diff --git a/GOALS.md b/GOALS.md index 1e4b2d13f..c70e89d09 100644 --- a/GOALS.md +++ b/GOALS.md @@ -7,8 +7,8 @@ - [X] Support configuration via a `modernuo.json` file ### Networking -- [X] Replace Packet classes with functions -- [X] Improve asynchronous socket handling using Pipes +- [ ] Replace Packet classes with functions +- [ ] Improve asynchronous socket handling using Pipes - [ ] Improve socket handling (2-5x) and event loop using libuv ### Administration diff --git a/ModernUO.sln b/ModernUO.sln index cdd102acb..deab80f56 100644 --- a/ModernUO.sln +++ b/ModernUO.sln @@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29102.190 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Projects\Server\Server.csproj", "{9514A3D3-5C0F-4EE0-B168-67C3F50DC225}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Projects\Server\Server.csproj", "{5E93BB35-3661-4822-9A8A-859726BAD87F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scripts", "Projects\Scripts\Scripts.csproj", "{BF29C43A-A539-448D-93DB-D7CBE13BACFE}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scripts", "Projects\Scripts\Scripts.csproj", "{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9514A3D3-5C0F-4EE0-B168-67C3F50DC225}.Debug|Any CPU.ActiveCfg = Release|Any CPU - {9514A3D3-5C0F-4EE0-B168-67C3F50DC225}.Debug|Any CPU.Build.0 = Release|Any CPU - {9514A3D3-5C0F-4EE0-B168-67C3F50DC225}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9514A3D3-5C0F-4EE0-B168-67C3F50DC225}.Release|Any CPU.Build.0 = Release|Any CPU - {BF29C43A-A539-448D-93DB-D7CBE13BACFE}.Debug|Any CPU.ActiveCfg = Release|Any CPU - {BF29C43A-A539-448D-93DB-D7CBE13BACFE}.Debug|Any CPU.Build.0 = Release|Any CPU - {BF29C43A-A539-448D-93DB-D7CBE13BACFE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BF29C43A-A539-448D-93DB-D7CBE13BACFE}.Release|Any CPU.Build.0 = Release|Any CPU + {5E93BB35-3661-4822-9A8A-859726BAD87F}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {5E93BB35-3661-4822-9A8A-859726BAD87F}.Debug|Any CPU.Build.0 = Release|Any CPU + {5E93BB35-3661-4822-9A8A-859726BAD87F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E93BB35-3661-4822-9A8A-859726BAD87F}.Release|Any CPU.Build.0 = Release|Any CPU + {83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Debug|Any CPU.Build.0 = Release|Any CPU + {83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Projects/Scripts/Accounting/Account.cs b/Projects/Scripts/Accounting/Account.cs index ced955f02..8ff0ab711 100644 --- a/Projects/Scripts/Accounting/Account.cs +++ b/Projects/Scripts/Accounting/Account.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Security.Cryptography; using System.Text; diff --git a/Projects/Scripts/Accounting/AccountAttackLimiter.cs b/Projects/Scripts/Accounting/AccountAttackLimiter.cs index a5b797bca..f302c22f3 100644 --- a/Projects/Scripts/Accounting/AccountAttackLimiter.cs +++ b/Projects/Scripts/Accounting/AccountAttackLimiter.cs @@ -61,7 +61,8 @@ namespace Server.Accounting InvalidAccountAccessLog accessLog = FindAccessLog(ns); - m_List.Add(accessLog ??= new InvalidAccountAccessLog(ns.Address)); + if (accessLog == null) + m_List.Add(accessLog = new InvalidAccountAccessLog(ns.Address)); accessLog.Counts += 1; accessLog.RefreshAccessTime(); diff --git a/Projects/Scripts/Accounting/AccountHandler.cs b/Projects/Scripts/Accounting/AccountHandler.cs index 459b173bd..31c131b6a 100644 --- a/Projects/Scripts/Accounting/AccountHandler.cs +++ b/Projects/Scripts/Accounting/AccountHandler.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Net; using Server.Accounting; using Server.Engines.Help; @@ -177,8 +176,8 @@ namespace Server.Misc from.SendLocalizedMessage(501234, "", 0x35); /* The next available Counselor/Game Master will respond as soon as possible. - * Please check your Journal for messages every few minutes. - */ + * Please check your Journal for messages every few minutes. + */ PageQueue.Enqueue(new PageEntry(from, $"[Automated: Change Password]
Desired password: {pass}
Current IP address: {ipAddress}
Account IP address: {accessList[0]}", @@ -200,27 +199,38 @@ namespace Server.Misc if (!(state.Account is Account acct)) { state.Dispose(); - return; } - - DeleteResultType deleteType; - - if (index < 0 || index >= acct.Length) - deleteType = DeleteResultType.BadRequest; + else if (index < 0 || index >= acct.Length) + { + state.Send(new DeleteResult(DeleteResultType.BadRequest)); + state.Send(new CharacterListUpdate(acct)); + } else { Mobile m = acct[index]; if (m == null) - deleteType = DeleteResultType.CharNotExist; + { + state.Send(new DeleteResult(DeleteResultType.CharNotExist)); + state.Send(new CharacterListUpdate(acct)); + } else if (m.NetState != null) - deleteType = DeleteResultType.CharBeingPlayed; + { + state.Send(new DeleteResult(DeleteResultType.CharBeingPlayed)); + state.Send(new CharacterListUpdate(acct)); + } else if (RestrictDeletion && DateTime.UtcNow < m.CreationTime + DeleteDelay) - deleteType = DeleteResultType.CharTooYoung; + { + state.Send(new DeleteResult(DeleteResultType.CharTooYoung)); + state.Send(new CharacterListUpdate(acct)); + } else if (m.AccessLevel == AccessLevel.Player && Region.Find(m.LogoutLocation, m.LogoutMap).IsPartOf() ) //Don't need to check current location, if netstate is null, they're logged out - deleteType = DeleteResultType.BadRequest; + { + state.Send(new DeleteResult(DeleteResultType.BadRequest)); + state.Send(new CharacterListUpdate(acct)); + } else { Console.WriteLine("Client: {0}: Deleting character {1} (0x{2:X})", state, index, m.Serial.Value); @@ -228,18 +238,27 @@ namespace Server.Misc acct.Comments.Add(new AccountComment("System", $"Character #{index + 1} {m} deleted by {state}")); m.Delete(); - Packets.SendCharacterListUpdate(state, acct); - return; + state.Send(new CharacterListUpdate(acct)); } } - - Packets.SendDeleteResult(state, deleteType); - Packets.SendCharacterListUpdate(state, acct); } - public static bool CanCreate(IPAddress ip) => !IPTable.ContainsKey(ip) || IPTable[ip] < MaxAccountsPerIP; + public static bool CanCreate(IPAddress ip) + { + if (!IPTable.ContainsKey(ip)) + return true; - private static bool IsForbiddenChar(char c) => m_ForbiddenChars.Any(t => c == t); + return IPTable[ip] < MaxAccountsPerIP; + } + + private static bool IsForbiddenChar(char c) + { + for (int i = 0; i < m_ForbiddenChars.Length; ++i) + if (c == m_ForbiddenChars[i]) + return true; + + return false; + } private static Account CreateAccount(NetState state, string un, string pw) { @@ -358,7 +377,9 @@ namespace Server.Misc string pw = e.Password; if (!(Accounts.GetAccount(un) is Account acct)) + { e.Accepted = false; + } else if (!acct.HasAccess(e.State)) { Console.WriteLine("Login: {0}: Access denied for '{1}'", e.State, un); diff --git a/Projects/Scripts/Accounting/Accounts.cs b/Projects/Scripts/Accounting/Accounts.cs index d5d01b165..8bf7e5446 100644 --- a/Projects/Scripts/Accounting/Accounts.cs +++ b/Projects/Scripts/Accounting/Accounts.cs @@ -90,4 +90,4 @@ namespace Server.Accounting xml.Close(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Accounting/Firewall.cs b/Projects/Scripts/Accounting/Firewall.cs index d7de42822..4946ff9c6 100644 --- a/Projects/Scripts/Accounting/Firewall.cs +++ b/Projects/Scripts/Accounting/Firewall.cs @@ -191,7 +191,9 @@ namespace Server return otherAddress.Equals(m_Address); } else if (obj is IPFirewallEntry entry) + { return m_Address.Equals(entry.m_Address); + } return false; } @@ -244,7 +246,7 @@ namespace Server public WildcardIPFirewallEntry(string entry) => m_Entry = entry; - bool IFirewallEntry.IsBlocked(IPAddress address) + public bool IsBlocked(IPAddress address) { if (!m_Valid) return false; //Why process if it's invalid? it'll return false anyway after processing it. diff --git a/Projects/Scripts/Commands/Add.cs b/Projects/Scripts/Commands/Add.cs index 9948d1c39..60e144037 100644 --- a/Projects/Scripts/Commands/Add.cs +++ b/Projects/Scripts/Commands/Add.cs @@ -7,7 +7,7 @@ using CPA = Server.CommandPropertyAttribute; namespace Server.Commands { - public static class Add + public class Add { private static Type m_EntityType = typeof(IEntity); diff --git a/Projects/Scripts/Commands/Batch.cs b/Projects/Scripts/Commands/Batch.cs index 9abef7a59..89e703c5e 100644 --- a/Projects/Scripts/Commands/Batch.cs +++ b/Projects/Scripts/Commands/Batch.cs @@ -120,7 +120,8 @@ namespace Server.Commands command.ExecuteList(eventArgs[i], usedList); - CommandLogging.Enabled |= list.Count > 20; + if (list.Count > 20) + CommandLogging.Enabled = true; command.Flush(e.Mobile, list.Count > 20); } diff --git a/Projects/Scripts/Commands/BoundingBoxPicker.cs b/Projects/Scripts/Commands/BoundingBoxPicker.cs index 29b0913bd..d95156919 100644 --- a/Projects/Scripts/Commands/BoundingBoxPicker.cs +++ b/Projects/Scripts/Commands/BoundingBoxPicker.cs @@ -1,6 +1,6 @@ using Server.Targeting; -namespace Server.Commands +namespace Server { public delegate void BoundingBoxCallback(Map map, Point3D start, Point3D end); @@ -60,4 +60,4 @@ namespace Server.Commands } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/ConvertPlayers.cs b/Projects/Scripts/Commands/ConvertPlayers.cs index c37c971cb..5dacd925e 100644 --- a/Projects/Scripts/Commands/ConvertPlayers.cs +++ b/Projects/Scripts/Commands/ConvertPlayers.cs @@ -7,7 +7,7 @@ using Server.Network; namespace Server.Commands { - public static class ConvertPlayers + public class ConvertPlayers { public static void Initialize() { diff --git a/Projects/Scripts/Commands/Decorate.cs b/Projects/Scripts/Commands/Decorate.cs index 4debc22a7..5475fb6eb 100644 --- a/Projects/Scripts/Commands/Decorate.cs +++ b/Projects/Scripts/Commands/Decorate.cs @@ -9,7 +9,7 @@ using Server.Mobiles; namespace Server.Commands { - public static class Decorate + public class Decorate { private static Mobile m_Mobile; private static int m_Count; @@ -878,7 +878,9 @@ namespace Server.Commands res = true; } else if ((item.ItemData.Flags & TileFlag.LightSource) != 0 && item.ItemData.Name == srcName) + { m_DeleteQueue.Enqueue(item); + } } } else if (srcItem is Teleporter || srcItem is FillableContainer || srcItem is BaseBook) diff --git a/Projects/Scripts/Commands/DecorateMag.cs b/Projects/Scripts/Commands/DecorateMag.cs index 4f0ba1386..38997aaad 100644 --- a/Projects/Scripts/Commands/DecorateMag.cs +++ b/Projects/Scripts/Commands/DecorateMag.cs @@ -10,7 +10,7 @@ using Server.Mobiles; namespace Server.Commands { - public static class DecorateMag + public class DecorateMag { private static Mobile m_Mobile; private static int m_Count; diff --git a/Projects/Scripts/Commands/Docs.cs b/Projects/Scripts/Commands/Docs.cs index 152b1f31e..c0e1fd763 100644 --- a/Projects/Scripts/Commands/Docs.cs +++ b/Projects/Scripts/Commands/Docs.cs @@ -82,7 +82,9 @@ namespace Server.Commands if (baseInfo == null) m_Types[baseType] = baseInfo = new TypeInfo(baseType); - baseInfo.m_Derived ??= new List(); + if (baseInfo.m_Derived == null) + baseInfo.m_Derived = new List(); + baseInfo.m_Derived.Add(info); } @@ -95,7 +97,9 @@ namespace Server.Commands if (decInfo == null) m_Types[decType] = decInfo = new TypeInfo(decType); - decInfo.m_Nested ??= new List(); + if (decInfo.m_Nested == null) + decInfo.m_Nested = new List(); + decInfo.m_Nested.Add(info); } @@ -111,7 +115,9 @@ namespace Server.Commands if (ifaceInfo == null) m_Types[iface] = ifaceInfo = new TypeInfo(iface); - ifaceInfo.m_Derived ??= new List(); + if (ifaceInfo.m_Derived == null) + ifaceInfo.m_Derived = new List(); + ifaceInfo.m_Derived.Add(info); } } @@ -638,7 +644,6 @@ namespace Server.Commands m_Namespaces = new Dictionary>(); List assemblies = new List { Core.Assembly }; - assemblies.AddRange(AssemblyHandler.Assemblies); foreach (Assembly asm in AssemblyHandler.Assemblies) @@ -1158,21 +1163,37 @@ namespace Server.Commands Item item = items[i].Construct(); if (item is Sandals) + { rewards[5] = true; + } else if (item is SmallStretchedHideEastDeed || item is SmallStretchedHideSouthDeed) + { rewards[10] = rewards[11] = true; + } else if (item is MediumStretchedHideEastDeed || item is MediumStretchedHideSouthDeed) + { rewards[10] = rewards[11] = true; + } else if (item is LightFlowerTapestryEastDeed || item is LightFlowerTapestrySouthDeed) + { rewards[12] = rewards[13] = true; + } else if (item is DarkFlowerTapestryEastDeed || item is DarkFlowerTapestrySouthDeed) + { rewards[12] = rewards[13] = true; + } else if (item is BrownBearRugEastDeed || item is BrownBearRugSouthDeed) + { rewards[14] = rewards[15] = true; + } else if (item is PolarBearRugEastDeed || item is PolarBearRugSouthDeed) + { rewards[14] = rewards[15] = true; + } else if (item is ClothingBlessDeed) + { rewards[16] = true; + } else if (item is PowerScroll ps) { if (ps.Value == 105.0) @@ -1197,7 +1218,10 @@ namespace Server.Commands else rewards[4] = true; } - else if (item is RunicSewingKit rkit) rewards[16 + CraftResources.GetIndex(rkit.Resource)] = true; + else if (item is RunicSewingKit rkit) + { + rewards[16 + CraftResources.GetIndex(rkit.Resource)] = true; + } item.Delete(); } @@ -1415,21 +1439,37 @@ namespace Server.Commands Item item = items[i].Construct(); if (item is SturdyPickaxe || item is SturdyShovel) + { rewards[0] = true; + } else if (item is LeatherGlovesOfMining) + { rewards[1] = true; + } else if (item is StuddedGlovesOfMining) + { rewards[2] = true; + } else if (item is RingmailGlovesOfMining) + { rewards[3] = true; + } else if (item is GargoylesPickaxe) + { rewards[4] = true; + } else if (item is ProspectorsTool) + { rewards[5] = true; + } else if (item is PowderOfTemperament) + { rewards[6] = true; + } else if (item is ColoredAnvil) + { rewards[7] = true; + } else if (item is PowerScroll ps) { if (ps.Value == 105.0) @@ -1442,7 +1482,9 @@ namespace Server.Commands rewards[11] = true; } else if (item is RunicHammer rh) + { rewards[11 + CraftResources.GetIndex(rh.Resource)] = true; + } else if (item is AncientSmithyHammer ash) { if (ash.Bonus == 10) diff --git a/Projects/Scripts/Commands/GenTeleporter.cs b/Projects/Scripts/Commands/GenTeleporter.cs index a9e5e4497..1c42392d7 100644 --- a/Projects/Scripts/Commands/GenTeleporter.cs +++ b/Projects/Scripts/Commands/GenTeleporter.cs @@ -3,7 +3,7 @@ using Server.Items; namespace Server.Commands { - public static class GenTeleporter + public class GenTeleporter { public static void Initialize() { @@ -282,7 +282,7 @@ namespace Server.Commands CreateTeleporter(2758, 2092, -20, 2756, 2097, 38, map, false); CreateTeleporter(2759, 2092, -20, 2756, 2097, 38, map, false); CreateTeleporter(2685, 2063, 39, 2685, 2063, -20, map, - false); // that should not be a teleporter: on OSI you simply fall under the ground + false); // that should not be a teleporter: on OSI you simply fall under the ground // Misc CreateTeleporter(5217, 18, 15, 5204, 74, 17, map, false); @@ -597,7 +597,7 @@ namespace Server.Commands CreateTeleporter(11, 1519, -27, 11, 873, -28, map, false); CreateTeleporter(12, 1519, -27, 12, 873, -27, map, false); - // Ratman Lair + // Ratman Lair CreateTeleporter(636, 813, -62, 164, 743, -28, map, false); CreateTeleporter(164, 746, -16, 636, 815, -52, map, false); @@ -775,47 +775,47 @@ namespace Server.Commands CreateTeleporter(548, 455, -40, 428, 113, -28, map, true); CreateTeleporter(429, 113, -28, 548, 455, -40, map, false); - CreateTeleporter(242, 27, -16, 372, 31, -31, map, false); // stairs - 0x754 - CreateTeleporter(242, 26, -16, 372, 30, -31, map, false); // stairs - 0x754 - CreateTeleporter(242, 25, -16, 372, 29, -31, map, false); // stairs - 0x754 - CreateTeleporter(371, 31, -36, 241, 27, -18, map, false); // stairs - 0x754 - CreateTeleporter(371, 30, -36, 241, 26, -18, map, false); // stairs - 0x754 + CreateTeleporter(242, 27, -16, 372, 31, -31, map, false); // stairs - 0x754 + CreateTeleporter(242, 26, -16, 372, 30, -31, map, false); // stairs - 0x754 + CreateTeleporter(242, 25, -16, 372, 29, -31, map, false); // stairs - 0x754 + CreateTeleporter(371, 31, -36, 241, 27, -18, map, false); // stairs - 0x754 + CreateTeleporter(371, 30, -36, 241, 26, -18, map, false); // stairs - 0x754 DestroyTeleporter(371, 29, -36, map); //To remove old erroneous teleporter CreateTeleporter(371, 29, -36, 241, 25, -18, map, false); // stairs - 0x754 - CreateTeleporter(272, 141, -16, 555, 427, -1, map, false); // stairs - 1st 0x753 - CreateTeleporter(273, 141, -16, 556, 427, -1, map, false); // stairs - 1st 0x753 - CreateTeleporter(274, 141, -16, 557, 427, -1, map, false); // stairs - 1st 0x753 - CreateTeleporter(555, 426, -6, 272, 140, -21, map, false); // stairs - 1st 0x753 - CreateTeleporter(556, 426, -6, 273, 140, -21, map, false); // stairs - 1st 0x753 - CreateTeleporter(557, 426, -6, 274, 140, -21, map, false); // stairs - 1st 0x753 + CreateTeleporter(272, 141, -16, 555, 427, -1, map, false); // stairs - 1st 0x753 + CreateTeleporter(273, 141, -16, 556, 427, -1, map, false); // stairs - 1st 0x753 + CreateTeleporter(274, 141, -16, 557, 427, -1, map, false); // stairs - 1st 0x753 + CreateTeleporter(555, 426, -6, 272, 140, -21, map, false); // stairs - 1st 0x753 + CreateTeleporter(556, 426, -6, 273, 140, -21, map, false); // stairs - 1st 0x753 + CreateTeleporter(557, 426, -6, 274, 140, -21, map, false); // stairs - 1st 0x753 - CreateTeleporter(265, 130, -31, 284, 72, -21, map, false); // stairs - 0x753 - CreateTeleporter(266, 130, -31, 285, 72, -21, map, false); // stairs - 0x753 - CreateTeleporter(267, 130, -31, 286, 72, -21, map, false); // stairs - 0x753 - CreateTeleporter(268, 130, -31, 287, 72, -21, map, false); // stairs - 0x753 - CreateTeleporter(284, 73, -16, 265, 131, -28, map, false); // stairs - 0x753 - CreateTeleporter(285, 73, -16, 266, 131, -28, map, false); // stairs - 0x753 - CreateTeleporter(286, 73, -16, 267, 131, -28, map, false); // stairs - 0x753 - CreateTeleporter(287, 73, -16, 268, 131, -28, map, false); // stairs - 0x753 + CreateTeleporter(265, 130, -31, 284, 72, -21, map, false); // stairs - 0x753 + CreateTeleporter(266, 130, -31, 285, 72, -21, map, false); // stairs - 0x753 + CreateTeleporter(267, 130, -31, 286, 72, -21, map, false); // stairs - 0x753 + CreateTeleporter(268, 130, -31, 287, 72, -21, map, false); // stairs - 0x753 + CreateTeleporter(284, 73, -16, 265, 131, -28, map, false); // stairs - 0x753 + CreateTeleporter(285, 73, -16, 266, 131, -28, map, false); // stairs - 0x753 + CreateTeleporter(286, 73, -16, 267, 131, -28, map, false); // stairs - 0x753 + CreateTeleporter(287, 73, -16, 268, 131, -28, map, false); // stairs - 0x753 - CreateTeleporter(284, 67, -30, 131, 128, -21, map, false); // stairs - 0x753 - CreateTeleporter(285, 67, -30, 132, 128, -21, map, false); // stairs - 0x753 - CreateTeleporter(286, 67, -30, 133, 128, -21, map, false); // stairs - 0x753 - CreateTeleporter(287, 67, -30, 134, 128, -21, map, false); // stairs - 0x753 - CreateTeleporter(131, 129, -16, 284, 68, -28, map, false); // stairs - 0x753 - CreateTeleporter(132, 129, -16, 285, 68, -28, map, false); // stairs - 0x753 - CreateTeleporter(133, 129, -16, 286, 68, -28, map, false); // stairs - 0x753 - CreateTeleporter(134, 129, -16, 287, 68, -28, map, false); // stairs - 0x753 + CreateTeleporter(284, 67, -30, 131, 128, -21, map, false); // stairs - 0x753 + CreateTeleporter(285, 67, -30, 132, 128, -21, map, false); // stairs - 0x753 + CreateTeleporter(286, 67, -30, 133, 128, -21, map, false); // stairs - 0x753 + CreateTeleporter(287, 67, -30, 134, 128, -21, map, false); // stairs - 0x753 + CreateTeleporter(131, 129, -16, 284, 68, -28, map, false); // stairs - 0x753 + CreateTeleporter(132, 129, -16, 285, 68, -28, map, false); // stairs - 0x753 + CreateTeleporter(133, 129, -16, 286, 68, -28, map, false); // stairs - 0x753 + CreateTeleporter(134, 129, -16, 287, 68, -28, map, false); // stairs - 0x753 - CreateTeleporter(358, 40, -36, 156, 88, -18, map, false); // stairs - 0x73A - CreateTeleporter(358, 41, -36, 156, 89, -18, map, false); // stairs - 0x73A - CreateTeleporter(358, 42, -36, 156, 90, -18, map, false); // stairs - 0x73A - CreateTeleporter(155, 88, -16, 357, 40, -31, map, false); // stairs - 0x73A - CreateTeleporter(155, 89, -16, 357, 41, -31, map, false); // stairs - 0x73A - CreateTeleporter(155, 90, -16, 357, 42, -31, map, false); // stairs - 0x73A + CreateTeleporter(358, 40, -36, 156, 88, -18, map, false); // stairs - 0x73A + CreateTeleporter(358, 41, -36, 156, 89, -18, map, false); // stairs - 0x73A + CreateTeleporter(358, 42, -36, 156, 90, -18, map, false); // stairs - 0x73A + CreateTeleporter(155, 88, -16, 357, 40, -31, map, false); // stairs - 0x73A + CreateTeleporter(155, 89, -16, 357, 41, -31, map, false); // stairs - 0x73A + CreateTeleporter(155, 90, -16, 357, 42, -31, map, false); // stairs - 0x73A CreateTeleporter(259, 90, -28, 236, 113, -28, map, true); @@ -923,7 +923,7 @@ namespace Server.Commands public void CreateTeleportersMap3(Map map) { - // CreateTeleporter( 408, 254, 2, 428, 319, 2, map, false ); // for doom quest; use blockers to avoid players teleporting into the ship! + // CreateTeleporter( 408, 254, 2, 428, 319, 2, map, false ); // for doom quest; use blockers to avoid players teleporting into the ship! // CreateTeleporter( 428, 321, 2, 422, 328, -1, map, false ); // for doom quest; use blockers to avoid players teleporting into the ship! // Doom Dungeon @@ -1040,4 +1040,4 @@ namespace Server.Commands } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/Generic/Commands/Commands.cs b/Projects/Scripts/Commands/Generic/Commands/Commands.cs index c0718109c..95e7de3f7 100644 --- a/Projects/Scripts/Commands/Generic/Commands/Commands.cs +++ b/Projects/Scripts/Commands/Generic/Commands/Commands.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Accounting; using Server.Engines.Help; using Server.Factions; @@ -13,7 +12,7 @@ using Server.Spells; namespace Server.Commands.Generic { - public static class TargetCommands + public class TargetCommands { public static List AllCommands{ get; } = new List(); @@ -186,7 +185,10 @@ namespace Server.Commands.Generic public override void ExecuteList(CommandEventArgs e, List list) { - AddResponse(list.Count == 1 ? "There is one matching object." : $"There are {list.Count} matching objects."); + if (list.Count == 1) + AddResponse("There is one matching object."); + else + AddResponse($"There are {list.Count} matching objects."); } } @@ -232,7 +234,9 @@ namespace Server.Commands.Generic NetState ns = mob.NetState; if (ns == null) + { LogFailure("That player is not online."); + } else { string url = e.GetString(0); @@ -240,7 +244,10 @@ namespace Server.Commands.Generic CommandLogging.WriteLine(from, "{0} {1} requesting to open web browser of {2} to {3}", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(mob), url); - AddResponse(echo ? "Awaiting user confirmation..." : "Open web browser request sent."); + if (echo) + AddResponse("Awaiting user confirmation..."); + else + AddResponse("Open web browser request sent."); mob.SendGump(new WarningGump(1060637, 30720, $"A game master is requesting to open your web browser to the following URL:
{url}", 0xFFC000, @@ -248,10 +255,14 @@ namespace Server.Commands.Generic } } else + { LogFailure("That is not a player."); + } } else + { LogFailure("Format: OpenBrowser "); + } } public override void Execute(CommandEventArgs e, object obj) @@ -325,7 +336,7 @@ namespace Server.Commands.Generic CommandLogging.WriteLine(from, "{0} {1} playing sound {2} for {3}", from.AccessLevel, CommandLogging.Format(from), index, CommandLogging.Format(mob)); - Packets.SendPlaySound(mob.NetState, index, mob.Location); + mob.Send(new PlaySound(index, mob.Location)); } else { @@ -447,10 +458,14 @@ namespace Server.Commands.Generic e.Mobile.SendGump(new AddGump(e.Mobile, match, 0, Type.EmptyTypes, false)); } else + { e.Mobile.SendGump(new AddGump(e.Mobile, match, 0, AddGump.Match(match).ToArray(), true)); + } } else + { return true; + } } else { @@ -619,9 +634,19 @@ namespace Server.Commands.Generic public override void Execute(CommandEventArgs e, object obj) { - AddResponse(obj == null ? - "The object is null." : - $"The type of that object is {obj.GetType().FullName}."); + if (obj == null) + { + AddResponse("The object is null."); + } + else + { + Type type = obj.GetType(); + + if (type.DeclaringType == null) + AddResponse($"The type of that object is {type.Name}."); + else + AddResponse($"The type of that object is {type.FullName}."); + } } } @@ -835,9 +860,13 @@ namespace Server.Commands.Generic if (m_Value) { if (!mob.Alive) + { LogFailure("They are already dead."); + } else if (!mob.CanBeDamaged()) + { LogFailure("They cannot be harmed."); + } else { CommandLogging.WriteLine(from, "{0} {1} killing {2}", from.AccessLevel, CommandLogging.Format(from), @@ -931,7 +960,10 @@ namespace Server.Commands.Generic m.PlaySound(0x228); m.Hidden = m_Value; - AddResponse(m_Value ? "They have been hidden." : "They have been revealed."); + if (m_Value) + AddResponse("They have been hidden."); + else + AddResponse("They have been revealed."); } } @@ -970,7 +1002,9 @@ namespace Server.Commands.Generic } } else + { LogFailure("They are not online."); + } } } @@ -1064,11 +1098,12 @@ namespace Server.Commands.Generic return; } - foreach (BaseHouse house in BaseHouse.AllHouses.Where(house => house.HasSecureItem(item) || house.HasLockedDownItem(item))) - { - e.Mobile.SendGump(new PropertiesGump(e.Mobile, house)); - return; - } + foreach (BaseHouse house in BaseHouse.AllHouses) + if (house.HasSecureItem(item) || house.HasLockedDownItem(item)) + { + e.Mobile.SendGump(new PropertiesGump(e.Mobile, house)); + return; + } LogFailure("No house was found."); } diff --git a/Projects/Scripts/Commands/Generic/Commands/DesignInsert.cs b/Projects/Scripts/Commands/Generic/Commands/DesignInsert.cs index 541f4959c..cae91d825 100644 --- a/Projects/Scripts/Commands/Generic/Commands/DesignInsert.cs +++ b/Projects/Scripts/Commands/Generic/Commands/DesignInsert.cs @@ -149,7 +149,7 @@ namespace Server.Commands.Generic AddResponse("Awaiting confirmation..."); } - private void OnConfirmCallback(Mobile from, bool okay, IReadOnlyList list, bool staticsOnly) + private void OnConfirmCallback(Mobile from, bool okay, List list, bool staticsOnly) { bool flushToLog = false; @@ -191,11 +191,13 @@ namespace Server.Commands.Generic house.Delta(ItemDelta.Update); } else + { AddResponse("Command aborted."); + } Flush(from, flushToLog); } #endregion } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs b/Projects/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs index 9b9ecf962..6db1c7a08 100644 --- a/Projects/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs +++ b/Projects/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs @@ -160,6 +160,10 @@ namespace Server.Commands.Generic FieldAttributes.Private | FieldAttributes.InitOnly ); +// parseMethod.Invoke(null, +// parseArgs.Length == 2 ? new object[] {toParse, (int) parseArgs[1]} : new object[] {toParse}); + + il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, toParse); @@ -230,17 +234,36 @@ namespace Server.Commands.Generic public override void Compile(MethodEmitter emitter) { - bool inverse = m_Operator == StringOperator.NotEqual; + bool inverse = false; - string methodName = m_Operator switch + string methodName; + + switch (m_Operator) { - StringOperator.Equal => "Equals", - StringOperator.NotEqual => "Equals", - StringOperator.Contains => "Contains", - StringOperator.StartsWith => "StartsWith", - StringOperator.EndsWith => "EndsWith", - _ => throw new InvalidOperationException("Invalid string comparison operator.") - }; + case StringOperator.Equal: + methodName = "Equals"; + break; + + case StringOperator.NotEqual: + methodName = "Equals"; + inverse = true; + break; + + case StringOperator.Contains: + methodName = "Contains"; + break; + + case StringOperator.StartsWith: + methodName = "StartsWith"; + break; + + case StringOperator.EndsWith: + methodName = "EndsWith"; + break; + + default: + throw new InvalidOperationException("Invalid string comparison operator."); + } if (m_IgnoreCase || methodName == "Equals") { diff --git a/Projects/Scripts/Commands/Generic/Extensions/DistinctExtension.cs b/Projects/Scripts/Commands/Generic/Extensions/DistinctExtension.cs index cc3fcf846..682f4681c 100644 --- a/Projects/Scripts/Commands/Generic/Extensions/DistinctExtension.cs +++ b/Projects/Scripts/Commands/Generic/Extensions/DistinctExtension.cs @@ -32,7 +32,8 @@ namespace Server.Commands.Generic prop.CheckAccess(from); } - assembly ??= new AssemblyEmitter("__dynamic"); + if (assembly == null) + assembly = new AssemblyEmitter("__dynamic"); m_Comparer = DistinctCompiler.Compile(assembly, baseType, m_Properties.ToArray()); } diff --git a/Projects/Scripts/Commands/Generic/Extensions/SortExtension.cs b/Projects/Scripts/Commands/Generic/Extensions/SortExtension.cs index cd1f757e1..5f2684cdb 100644 --- a/Projects/Scripts/Commands/Generic/Extensions/SortExtension.cs +++ b/Projects/Scripts/Commands/Generic/Extensions/SortExtension.cs @@ -31,7 +31,8 @@ namespace Server.Commands.Generic order.Property.CheckAccess(from); } - assembly ??= new AssemblyEmitter("__dynamic"); + if (assembly == null) + assembly = new AssemblyEmitter("__dynamic"); m_Comparer = SortCompiler.Compile(assembly, baseType, m_Orders.ToArray()); } @@ -68,6 +69,7 @@ namespace Server.Commands.Generic case "up": case "asc": case "ascending": + isAscending = true; ++offset; break; diff --git a/Projects/Scripts/Commands/Generic/Implementors/BaseCommandImplementor.cs b/Projects/Scripts/Commands/Generic/Implementors/BaseCommandImplementor.cs index ab37d795c..23edf03ea 100644 --- a/Projects/Scripts/Commands/Generic/Implementors/BaseCommandImplementor.cs +++ b/Projects/Scripts/Commands/Generic/Implementors/BaseCommandImplementor.cs @@ -111,15 +111,20 @@ namespace Server.Commands.Generic case ObjectTypes.All: case ObjectTypes.Both: { - items |= condIsItem; - mobiles |= condIsMobile; + if (condIsItem) + items = true; + + if (condIsMobile) + mobiles = true; break; } case ObjectTypes.Items: { if (condIsItem) + { items = true; + } else if (condIsMobile) { from.SendMessage("You may not use a mobile type condition for this command."); @@ -131,7 +136,9 @@ namespace Server.Commands.Generic case ObjectTypes.Mobiles: { if (condIsMobile) + { mobiles = true; + } else if (condIsItem) { from.SendMessage("You may not use an item type condition for this command."); diff --git a/Projects/Scripts/Commands/Generic/Implementors/ContainedCommandImplementor.cs b/Projects/Scripts/Commands/Generic/Implementors/ContainedCommandImplementor.cs index f68ff1e2c..2425840fe 100644 --- a/Projects/Scripts/Commands/Generic/Implementors/ContainedCommandImplementor.cs +++ b/Projects/Scripts/Commands/Generic/Implementors/ContainedCommandImplementor.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Items; using Server.Targeting; @@ -41,7 +40,7 @@ namespace Server.Commands.Generic from.SendMessage("That is not a container."); return; } - + try { Extensions ext = Extensions.Parse(from, ref args); @@ -71,4 +70,4 @@ namespace Server.Commands.Generic } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/Generic/Implementors/GlobalCommandImplementor.cs b/Projects/Scripts/Commands/Generic/Implementors/GlobalCommandImplementor.cs index 85d4d7b7f..e68726237 100644 --- a/Projects/Scripts/Commands/Generic/Implementors/GlobalCommandImplementor.cs +++ b/Projects/Scripts/Commands/Generic/Implementors/GlobalCommandImplementor.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace Server.Commands.Generic { @@ -29,10 +28,14 @@ namespace Server.Commands.Generic List list = new List(); if (items) - list.AddRange(World.Items.Values.Where(item => ext.IsValid(item))); + foreach (Item item in World.Items.Values) + if (ext.IsValid(item)) + list.Add(item); if (mobiles) - list.AddRange(World.Mobiles.Values.Where(mob => ext.IsValid(mob))); + foreach (Mobile mob in World.Mobiles.Values) + if (ext.IsValid(mob)) + list.Add(mob); ext.Filter(list); @@ -44,4 +47,4 @@ namespace Server.Commands.Generic } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/Generic/Implementors/ObjectConditional.cs b/Projects/Scripts/Commands/Generic/Implementors/ObjectConditional.cs index 6124e0e34..72519c9c5 100644 --- a/Projects/Scripts/Commands/Generic/Implementors/ObjectConditional.cs +++ b/Projects/Scripts/Commands/Generic/Implementors/ObjectConditional.cs @@ -30,7 +30,8 @@ namespace Server.Commands.Generic public void Compile(ref AssemblyEmitter emitter) { - emitter ??= new AssemblyEmitter("__dynamic"); + if (emitter == null) + emitter = new AssemblyEmitter("__dynamic"); m_Conditionals = new IConditional[m_Conditions.Length]; diff --git a/Projects/Scripts/Commands/Generic/Implementors/RegionCommandImplementor.cs b/Projects/Scripts/Commands/Generic/Implementors/RegionCommandImplementor.cs index edf65f7d4..5739236f9 100644 --- a/Projects/Scripts/Commands/Generic/Implementors/RegionCommandImplementor.cs +++ b/Projects/Scripts/Commands/Generic/Implementors/RegionCommandImplementor.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace Server.Commands.Generic { @@ -31,7 +30,16 @@ namespace Server.Commands.Generic List list = new List(); if (mobiles) - list.AddRange(reg.GetMobiles().Where(mob => BaseCommand.IsAccessible(from, mob)).Where(mob => ext.IsValid(mob))); + { + foreach (Mobile mob in reg.GetMobiles()) + { + if (!BaseCommand.IsAccessible(from, mob)) + continue; + + if (ext.IsValid(mob)) + list.Add(mob); + } + } else { command.LogFailure("This command does not support items."); @@ -48,4 +56,4 @@ namespace Server.Commands.Generic } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/Generic/Implementors/SerialCommandImplementor.cs b/Projects/Scripts/Commands/Generic/Implementors/SerialCommandImplementor.cs index 57873a2d1..5996b1466 100644 --- a/Projects/Scripts/Commands/Generic/Implementors/SerialCommandImplementor.cs +++ b/Projects/Scripts/Commands/Generic/Implementors/SerialCommandImplementor.cs @@ -17,7 +17,7 @@ namespace Server.Commands.Generic { Serial serial = e.GetUInt32(0); - IEntity obj = null; + object obj = null; if (serial.IsItem) obj = World.FindItem(serial); @@ -25,16 +25,22 @@ namespace Server.Commands.Generic obj = World.FindMobile(serial); if (obj == null) + { e.Mobile.SendMessage("That is not a valid serial."); + } else { Commands.TryGetValue(e.GetString(1), out BaseCommand command); if (command == null) + { e.Mobile.SendMessage( "That is either an invalid command name or one that does not support this modifier."); + } else if (e.Mobile.AccessLevel < command.AccessLevel) + { e.Mobile.SendMessage("You do not have access to that command."); + } else { switch (command.ObjectTypes) diff --git a/Projects/Scripts/Commands/Handlers.cs b/Projects/Scripts/Commands/Handlers.cs index f1015888f..723dfb2eb 100644 --- a/Projects/Scripts/Commands/Handlers.cs +++ b/Projects/Scripts/Commands/Handlers.cs @@ -1,11 +1,10 @@ using System.Collections.Generic; -using System.Linq; using System.Text; using Server.Commands.Generic; using Server.Engines.Help; using Server.Gumps; using Server.Items; -using Server.Menus; +using Server.Menus.ItemLists; using Server.Menus.Questions; using Server.Misc; using Server.Mobiles; @@ -17,7 +16,7 @@ using Server.Targets; namespace Server.Commands { - public static class CommandHandlers + public class CommandHandlers { public static void Initialize() { @@ -89,17 +88,19 @@ namespace Server.Commands { if (e.Length == 1 && !e.GetBoolean(0)) { - Packets.SendSpeedControlDisabled(from.NetState); + from.Send(SpeedControl.Disable); from.SendMessage("Speed boost has been disabled."); } else { - Packets.SendSpeedControlMount(from.NetState); + from.Send(SpeedControl.MountSpeed); from.SendMessage("Speed boost has been enabled."); } } else + { from.SendMessage("Format: SpeedBoost [true|false]"); + } } [Usage("Where")] @@ -158,16 +159,18 @@ namespace Server.Commands { PageEntry pe = PageQueue.GetEntry(targ); - from.SendMessage(pe?.Handler == from - ? "You may only use this command if you are handling their help page." - : "You may only use this command on someone who has paged you."); + if (pe?.Handler == from) + from.SendMessage("You may only use this command if you are handling their help page."); + else + from.SendMessage("You may only use this command on someone who has paged you."); return; } - from.SendMessage(targ.AddToBackpack(held) - ? "The item they were holding has been placed into their backpack." - : "The item they were holding has been placed at their feet."); + if (targ.AddToBackpack(held)) + from.SendMessage("The item they were holding has been placed into their backpack."); + else + from.SendMessage("The item they were holding has been placed at their feet."); held.ClearBounce(); @@ -217,8 +220,14 @@ namespace Server.Commands } List list = new List(); - list.AddRange(World.Items.Values.Where(item => item.Map == map && item.Parent == null)); - list.AddRange(World.Mobiles.Values.Where(m => m.Map == map && !m.Player)); + + foreach (Item item in World.Items.Values) + if (item.Map == map && item.Parent == null) + list.Add(item); + + foreach (Mobile m in World.Mobiles.Values) + if (m.Map == map && !m.Player) + list.Add(m); if (list.Count > 0) { @@ -268,7 +277,9 @@ namespace Server.Commands } } else + { from.SendMessage("There were no pets found for that player."); + } } else if (obj is Mobile master && master.Player) { @@ -297,7 +308,9 @@ namespace Server.Commands } } else + { from.SendMessage("There were no pets found for that player."); + } } else { @@ -336,9 +349,15 @@ namespace Server.Commands CommandLogging.WriteLine(m, "{0} {1} playing sound {2} (toAll={3})", m.AccessLevel, CommandLogging.Format(m), index, toAll); + Packet p = new PlaySound(index, m.Location); + + p.Acquire(); + foreach (NetState state in m.GetClientsInRange(12)) if (toAll || state.Mobile.CanSee(m)) - Packets.SendPlaySound(state, index, m.Location); + state.Send(p); + + p.Release(); } [Usage("Echo ")] @@ -347,7 +366,10 @@ namespace Server.Commands { string toEcho = e.ArgString.Trim(); - e.Mobile.SendMessage(toEcho.Length > 0 ? toEcho : "Format: Echo \"\""); + if (toEcho.Length > 0) + e.Mobile.SendMessage(toEcho); + else + e.Mobile.SendMessage("Format: Echo \"\""); } [Usage("Bank")] @@ -506,12 +528,16 @@ namespace Server.Commands Dictionary list = from.Map.Regions; - foreach (var (_, r) in list) + foreach (KeyValuePair kvp in list) + { + Region r = kvp.Value; + if (Insensitive.Equals(r.Name, name)) { from.Location = new Point3D(r.GoLocation); return; } + } for (int i = 0; i < Map.AllMaps.Count; ++i) { @@ -592,7 +618,11 @@ namespace Server.Commands { Mobile m = e.Mobile; - List list = CommandSystem.Entries.Values.Where(entry => m.AccessLevel >= entry.AccessLevel).ToList(); + List list = new List(); + + foreach (CommandEntry entry in CommandSystem.Entries.Values) + if (m.AccessLevel >= entry.AccessLevel) + list.Add(entry); list.Sort(); @@ -641,8 +671,13 @@ namespace Server.Commands public static void BroadcastMessage(AccessLevel ac, int hue, string message) { - foreach (Mobile m in NetState.Instances.Select(state => state.Mobile).Where(m => m?.AccessLevel >= ac)) - m.SendMessage(hue, message); + foreach (NetState state in NetState.Instances) + { + Mobile m = state.Mobile; + + if (m?.AccessLevel >= ac) + m.SendMessage(hue, message); + } } [Usage("AutoPageNotify")] diff --git a/Projects/Scripts/Commands/HelpInfo.cs b/Projects/Scripts/Commands/HelpInfo.cs index 8f1dc7946..a868edf7e 100644 --- a/Projects/Scripts/Commands/HelpInfo.cs +++ b/Projects/Scripts/Commands/HelpInfo.cs @@ -9,7 +9,7 @@ using CommandInfoSorter = Server.Commands.Docs.CommandEntrySorter; namespace Server.Commands { - public static class HelpInfo + public class HelpInfo { public static Dictionary HelpInfos{ get; } = new Dictionary(); diff --git a/Projects/Scripts/Commands/Logging.cs b/Projects/Scripts/Commands/Logging.cs index 0bc629775..8c4f09b86 100644 --- a/Projects/Scripts/Commands/Logging.cs +++ b/Projects/Scripts/Commands/Logging.cs @@ -5,7 +5,7 @@ using Server.Accounting; namespace Server.Commands { - public static class CommandLogging + public class CommandLogging { private static char[] m_NotSafe = { '\\', '/', ':', '*', '?', '"', '<', '>', '|' }; public static bool Enabled{ get; set; } = true; diff --git a/Projects/Scripts/Commands/Properties.cs b/Projects/Scripts/Commands/Properties.cs index c95ece9eb..60ed30a2f 100644 --- a/Projects/Scripts/Commands/Properties.cs +++ b/Projects/Scripts/Commands/Properties.cs @@ -196,7 +196,7 @@ namespace Server.Commands } } - return chain[^1]; + return chain[chain.Length - 1]; } public static string GetValue(Mobile from, object o, string name) @@ -328,7 +328,7 @@ namespace Server.Commands concat[i * 2 + 1] = i < chain.Length - 1 ? "." : " = "; } - concat[^1] = toString; + concat[concat.Length - 1] = toString; return string.Concat(concat); } @@ -382,7 +382,7 @@ namespace Server.Commands if (IsEnum(type)) try { - toSet = Enum.Parse(type, value ?? "", true); + toSet = Enum.Parse(type, value, true); } catch { @@ -654,7 +654,7 @@ namespace Server if (!IsBound) throw new NotYetBoundException(this); - return m_Chain[^1].PropertyType; + return m_Chain[m_Chain.Length - 1].PropertyType; } } diff --git a/Projects/Scripts/Commands/ShardTime.cs b/Projects/Scripts/Commands/ShardTime.cs index 33e7ea882..af91bba37 100644 --- a/Projects/Scripts/Commands/ShardTime.cs +++ b/Projects/Scripts/Commands/ShardTime.cs @@ -2,7 +2,7 @@ namespace Server.Commands { - public static class ShardTime + public class ShardTime { public static void Initialize() { @@ -16,4 +16,4 @@ namespace Server.Commands e.Mobile.SendMessage(DateTime.UtcNow.ToString()); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/SignParser.cs b/Projects/Scripts/Commands/SignParser.cs index d8133da8e..66176541b 100644 --- a/Projects/Scripts/Commands/SignParser.cs +++ b/Projects/Scripts/Commands/SignParser.cs @@ -4,7 +4,7 @@ using Server.Items; namespace Server.Commands { - public static class SignParser + public class SignParser { private static Queue m_ToDelete = new Queue(); @@ -76,7 +76,9 @@ namespace Server.Commands from.SendMessage("Sign generating complete."); } else + { from.SendMessage("{0} not found!", cfg); + } } public static void Add_Static(int itemID, Point3D location, Map map, string name) @@ -92,8 +94,17 @@ namespace Server.Commands while (m_ToDelete.Count > 0) m_ToDelete.Dequeue().Delete(); - Item sign = name.StartsWith("#") ? new LocalizedSign(itemID, Utility.ToInt32(name.Substring(1))) : - new Sign(itemID) {Name = name}; + Item sign; + + if (name.StartsWith("#")) + { + sign = new LocalizedSign(itemID, Utility.ToInt32(name.Substring(1))); + } + else + { + sign = new Sign(itemID); + sign.Name = name; + } if (map == Map.Malas) { diff --git a/Projects/Scripts/Commands/Skills.cs b/Projects/Scripts/Commands/Skills.cs index 11ba065da..7decdfc6f 100644 --- a/Projects/Scripts/Commands/Skills.cs +++ b/Projects/Scripts/Commands/Skills.cs @@ -3,7 +3,7 @@ using Server.Targeting; namespace Server.Commands { - public static class SkillsCommand + public class SkillsCommand { public static void Initialize() { @@ -123,4 +123,4 @@ namespace Server.Commands } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/SkillsMenu.cs b/Projects/Scripts/Commands/SkillsMenu.cs index c97486d03..6b4e617ab 100644 --- a/Projects/Scripts/Commands/SkillsMenu.cs +++ b/Projects/Scripts/Commands/SkillsMenu.cs @@ -3,7 +3,7 @@ using Server.Targeting; namespace Server.Commands { - public static class Skills + public class Skills { public static void Initialize() { @@ -35,4 +35,4 @@ namespace Server.Commands } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/Statics.cs b/Projects/Scripts/Commands/Statics.cs index 48f9acc38..476f96790 100644 --- a/Projects/Scripts/Commands/Statics.cs +++ b/Projects/Scripts/Commands/Statics.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using System.IO; +using Server.Commands; using Server.Gumps; using Server.Items; -namespace Server.Commands +namespace Server { - public static class Statics + public class Statics { private const string BaseFreezeWarning = "{0} " + "Those items will be removed from the world and placed into the server data files. " + @@ -179,8 +180,11 @@ namespace Server.Commands int totalFrozen = 0; - foreach (var (map, table) in mapTable) + foreach (KeyValuePair> de in mapTable) { + Map map = de.Key; + Dictionary table = de.Value; + TileMatrix matrix = map.Tiles; using FileStream idxStream = OpenWrite(matrix.IndexStream); diff --git a/Projects/Scripts/Commands/VisibilityList.cs b/Projects/Scripts/Commands/VisibilityList.cs index 0dfd9415f..6e7afd9ec 100644 --- a/Projects/Scripts/Commands/VisibilityList.cs +++ b/Projects/Scripts/Commands/VisibilityList.cs @@ -49,7 +49,9 @@ namespace Server.Commands pm.SendMessage("#{0}: {1}", i + 1, list[i].Name); } else + { pm.SendMessage("Your visibility list is empty."); + } } } @@ -69,7 +71,7 @@ namespace Server.Commands Mobile m = list[i]; if (!m.CanSee(pm) && Utility.InUpdateRange(m, pm)) - Packets.SendRemoveEntity(m.NetState, pm.Serial); + m.Send(pm.RemovePacket); } } } @@ -82,54 +84,58 @@ namespace Server.Commands protected override void OnTarget(Mobile from, object targeted) { - if (!(from is PlayerMobile pm) || !(targeted is Mobile targ)) + if (from is PlayerMobile pm && targeted is Mobile targ) { - from.SendMessage("Add only mobiles to your visibility list."); - return; - } + if (targ.AccessLevel <= pm.AccessLevel) + { + List list = pm.VisibilityList; - if (targ.AccessLevel > pm.AccessLevel) - { - pm.SendMessage("They can already see you!"); - return; - } + if (list.Contains(targ)) + { + list.Remove(targ); + pm.SendMessage("{0} has been removed from your visibility list.", targ.Name); + } + else + { + list.Add(targ); + pm.SendMessage("{0} has been added to your visibility list.", targ.Name); + } - List list = pm.VisibilityList; + if (Utility.InUpdateRange(targ, from)) + { + NetState ns = targ.NetState; - if (list.Contains(targ)) - { - list.Remove(targ); - pm.SendMessage("{0} has been removed from your visibility list.", targ.Name); + if (ns != null) + { + if (targ.CanSee(pm)) + { + ns.Send(MobileIncoming.Create(ns, targ, pm)); + + if (ObjectPropertyList.Enabled) + { + ns.Send(pm.OPLPacket); + + foreach (Item item in pm.Items) + ns.Send(item.OPLPacket); + } + } + else + { + ns.Send(pm.RemovePacket); + } + } + } + } + else + { + pm.SendMessage("They can already see you!"); + } } else { - list.Add(targ); - pm.SendMessage("{0} has been added to your visibility list.", targ.Name); - } - - if (Utility.InUpdateRange(targ, from)) - { - NetState ns = targ.NetState; - - if (ns != null) - { - if (targ.CanSee(pm)) - { - Packets.SendMobileIncoming(ns, targ, pm); - - if (ObjectPropertyList.Enabled) - { - pm.PropertyList.Send(ns); - - foreach (Item item in pm.Items) - item.PropertyList.SendOPLInfo(ns); - } - } - else - Packets.SendRemoveEntity(ns, pm.Serial); - } + from.SendMessage("Add only mobiles to your visibility list."); } } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Commands/Wipe.cs b/Projects/Scripts/Commands/Wipe.cs index a8e4921f8..eec17443b 100644 --- a/Projects/Scripts/Commands/Wipe.cs +++ b/Projects/Scripts/Commands/Wipe.cs @@ -5,7 +5,7 @@ using Server.Multis; namespace Server.Commands { - public static class Wipe + public class Wipe { [Flags] public enum WipeType @@ -74,7 +74,7 @@ namespace Server.Commands if (!items && !multis || !mobiles) return; - + eable = map.GetObjectsInBounds(rect); foreach (IEntity obj in eable) @@ -91,4 +91,4 @@ namespace Server.Commands toDelete[i].Delete(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Context Menus/AddToSpellbookEntry.cs b/Projects/Scripts/Context Menus/AddToSpellbookEntry.cs index 48cc030bc..18d1e0b35 100644 --- a/Projects/Scripts/Context Menus/AddToSpellbookEntry.cs +++ b/Projects/Scripts/Context Menus/AddToSpellbookEntry.cs @@ -34,7 +34,9 @@ namespace Server.ContextMenus { } else if (book.HasSpell(m_Scroll.SpellID)) + { from.SendLocalizedMessage(500179); // That spell is already present in that spellbook. + } else { int val = m_Scroll.SpellID - book.BookOffset; @@ -45,11 +47,11 @@ namespace Server.ContextMenus m_Scroll.Consume(); - Packets.SendPlaySound(from.NetState, 0x249, book.GetWorldLocation()); + from.Send(new PlaySound(0x249, book.GetWorldLocation())); } } } } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/BulkOrders/Books/BOBGump.cs b/Projects/Scripts/Engines/BulkOrders/Books/BOBGump.cs index a7c6e37f3..4cbab8357 100644 --- a/Projects/Scripts/Engines/BulkOrders/Books/BOBGump.cs +++ b/Projects/Scripts/Engines/BulkOrders/Books/BOBGump.cs @@ -4,6 +4,7 @@ using Server.Gumps; using Server.Items; using Server.Mobiles; using Server.Network; +using Server.Prompts; namespace Server.Engines.BulkOrders { diff --git a/Projects/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs b/Projects/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs index 8e6470dfb..e73315712 100644 --- a/Projects/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs +++ b/Projects/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Server.Gumps; using Server.Multis; +using Server.Prompts; using Server.Mobiles; using Server.ContextMenus; using Server.Items; diff --git a/Projects/Scripts/Engines/BulkOrders/LargeBOD.cs b/Projects/Scripts/Engines/BulkOrders/LargeBOD.cs index e711755e8..cafddf4e8 100644 --- a/Projects/Scripts/Engines/BulkOrders/LargeBOD.cs +++ b/Projects/Scripts/Engines/BulkOrders/LargeBOD.cs @@ -1,4 +1,3 @@ -using System.Linq; using Server.Mobiles; namespace Server.Engines.BulkOrders diff --git a/Projects/Scripts/Engines/BulkOrders/LargeTailorBOD.cs b/Projects/Scripts/Engines/BulkOrders/LargeTailorBOD.cs index 8f109ac99..8cb608427 100644 --- a/Projects/Scripts/Engines/BulkOrders/LargeTailorBOD.cs +++ b/Projects/Scripts/Engines/BulkOrders/LargeTailorBOD.cs @@ -2,7 +2,7 @@ namespace Server.Engines.BulkOrders { public class LargeTailorBOD : LargeBOD { - public static readonly double[] m_TailoringMaterialChances = + public static double[] m_TailoringMaterialChances = { 0.857421875, // None 0.125000000, // Spined @@ -19,6 +19,7 @@ namespace Server.Engines.BulkOrders switch (Utility.Random(14)) { default: + case 0: entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.Farmer); break; case 1: diff --git a/Projects/Scripts/Engines/BulkOrders/Rewards.cs b/Projects/Scripts/Engines/BulkOrders/Rewards.cs index 7de897822..c427bb54f 100644 --- a/Projects/Scripts/Engines/BulkOrders/Rewards.cs +++ b/Projects/Scripts/Engines/BulkOrders/Rewards.cs @@ -357,14 +357,7 @@ namespace Server.Engines.BulkOrders int[][][] goldTable = m_GoldTable; int typeIndex = ComputeType(type, itemCount); - - int quanIndex = quantity switch - { - 20 => 2, - 15 => 1, - _ => 0 - }; - + int quanIndex = quantity == 20 ? 2 : quantity == 15 ? 1 : 0; int mtrlIndex = material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite ? 1 + (material - BulkMaterialType.DullCopper) : 0; @@ -606,28 +599,11 @@ namespace Server.Engines.BulkOrders { int[][][] goldTable = Core.AOS ? m_AosGoldTable : m_OldGoldTable; - int typeIndex = itemCount switch - { - 6 => 3, - 5 => 2, - 4 => 1, - _ => 0 - } * 2 + (exceptional ? 1 : 0); - - int quanIndex = quantity switch - { - 20 => 2, - 15 => 1, - _ => 0 - }; - - int mtrlIndex = material switch - { - BulkMaterialType.Barbed => 3, - BulkMaterialType.Horned => 2, - BulkMaterialType.Spined => 1, - _ => 0 - }; + int typeIndex = (itemCount == 6 ? 3 : itemCount == 5 ? 2 : itemCount == 4 ? 1 : 0) * 2 + (exceptional ? 1 : 0); + int quanIndex = quantity == 20 ? 2 : quantity == 15 ? 1 : 0; + int mtrlIndex = material == BulkMaterialType.Barbed ? 3 : + material == BulkMaterialType.Horned ? 2 : + material == BulkMaterialType.Spined ? 1 : 0; int gold = goldTable[typeIndex][quanIndex][mtrlIndex]; @@ -639,7 +615,7 @@ namespace Server.Engines.BulkOrders #region Constructors - private static readonly int[][] m_ClothHues = + private static int[][] m_ClothHues = { new[] { 0x483, 0x48C, 0x488, 0x48A }, new[] { 0x495, 0x48B, 0x486, 0x485 }, @@ -702,15 +678,13 @@ namespace Server.Engines.BulkOrders }; } - private static Item CreateRunicKit(int type) => - type >= 1 && type <= 3 - ? new RunicSewingKit(CraftResource.RegularLeather + type, 60 - type * 15) - : throw new InvalidOperationException(); + private static Item CreateRunicKit(int type) + { + if (type >= 1 && type <= 3) + return new RunicSewingKit(CraftResource.RegularLeather + type, 60 - type * 15); - private static Item CreatePowerScroll(int type) => - type == 5 || type == 10 || type == 15 || type == 20 - ? new PowerScroll(SkillName.Tailoring, 100 + type) - : throw new InvalidOperationException(); + throw new InvalidOperationException(); + } private static Item CreatePowerScroll(int type) { diff --git a/Projects/Scripts/Engines/CannedEvil/ChampionSkullBrazier.cs b/Projects/Scripts/Engines/CannedEvil/ChampionSkullBrazier.cs index 3cb1b14f1..6991ac13e 100644 --- a/Projects/Scripts/Engines/CannedEvil/ChampionSkullBrazier.cs +++ b/Projects/Scripts/Engines/CannedEvil/ChampionSkullBrazier.cs @@ -65,16 +65,22 @@ namespace Server.Engines.CannedEvil Skull = null; if (from.Map != Map || !from.InRange(GetWorldLocation(), 3)) + { from.SendLocalizedMessage(500446); // That is too far away. + } else if (!Harrower.CanSpawn) + { from.SendMessage("The harrower has already been spawned."); + } else if (m_Skull == null) { from.SendLocalizedMessage(1049485); // What would you like to sacrifice? from.Target = new SacrificeTarget(this); } else - SendLocalizedMessageTo(from, 1049487); // I already have my champions awakening skull! + { + SendLocalizedMessageTo(from, 1049487, ""); // I already have my champions awakening skull! + } } public void EndSacrifice(Mobile from, ChampionSkull skull) @@ -86,15 +92,25 @@ namespace Server.Engines.CannedEvil Skull = null; if (from.Map != Map || !from.InRange(GetWorldLocation(), 3)) + { from.SendLocalizedMessage(500446); // That is too far away. + } else if (!Harrower.CanSpawn) + { from.SendMessage("The harrower has already been spawned."); + } else if (skull == null) - SendLocalizedMessageTo(from, 1049488); // That is not my champions awakening skull! + { + SendLocalizedMessageTo(from, 1049488, ""); // That is not my champions awakening skull! + } else if (m_Skull != null) - SendLocalizedMessageTo(from, 1049487); // I already have my champions awakening skull! + { + SendLocalizedMessageTo(from, 1049487, ""); // I already have my champions awakening skull! + } else if (!skull.IsChildOf(from.Backpack)) + { from.SendLocalizedMessage(1049486); // You can only sacrifice items that are in your backpack! + } else { if (skull.Type == Type) @@ -105,7 +121,9 @@ namespace Server.Engines.CannedEvil Skull = skull; } else - SendLocalizedMessageTo(from, 1049488); // That is not my champions awakening skull! + { + SendLocalizedMessageTo(from, 1049488, ""); // That is not my champions awakening skull! + } } } diff --git a/Projects/Scripts/Engines/CannedEvil/ChampionSpawn.cs b/Projects/Scripts/Engines/CannedEvil/ChampionSpawn.cs index 0ee5a3caf..2cdbe0c67 100644 --- a/Projects/Scripts/Engines/CannedEvil/ChampionSpawn.cs +++ b/Projects/Scripts/Engines/CannedEvil/ChampionSpawn.cs @@ -950,24 +950,24 @@ namespace Server.Engines.CannedEvil Dictionary validEntries = new Dictionary(); - foreach (var (key, value) in m_DamageEntries) - if (IsEligible(key, artifact)) + foreach (KeyValuePair kvp in m_DamageEntries) + if (IsEligible(kvp.Key, artifact)) { - validEntries.Add(key, value); - totalDamage += value; + validEntries.Add(kvp.Key, kvp.Value); + totalDamage += kvp.Value; } int randomDamage = Utility.RandomMinMax(1, totalDamage); totalDamage = 0; - foreach (var (key, value) in validEntries) + foreach (KeyValuePair kvp in validEntries) { - totalDamage += value; + totalDamage += kvp.Value; if (totalDamage >= randomDamage) { - GiveArtifact(key, artifact); + GiveArtifact(kvp.Key, artifact); return; } } @@ -1001,10 +1001,10 @@ namespace Server.Engines.CannedEvil writer.Write(m_SPawnSzMod); writer.Write(m_DamageEntries.Count); - foreach (var (key, value) in m_DamageEntries) + foreach (KeyValuePair kvp in m_DamageEntries) { - writer.Write(key); - writer.Write(value); + writer.Write(kvp.Key); + writer.Write(kvp.Value); } writer.Write(ConfinedRoaming); diff --git a/Projects/Scripts/Engines/Chat/Channel.cs b/Projects/Scripts/Engines/Chat/Channel.cs index 127c560bb..bc1a54ba8 100644 --- a/Projects/Scripts/Engines/Chat/Channel.cs +++ b/Projects/Scripts/Engines/Chat/Channel.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; namespace Server.Engines.Chat { @@ -402,7 +401,18 @@ namespace Server.Engines.Chat } } - public static Channel FindChannelByName(string name) => Channels.FirstOrDefault(channel => channel.m_Name == name); + public static Channel FindChannelByName(string name) + { + for (int i = 0; i < Channels.Count; ++i) + { + Channel channel = Channels[i]; + + if (channel.m_Name == name) + return channel; + } + + return null; + } public static void Initialize() { diff --git a/Projects/Scripts/Engines/Chat/Chat.cs b/Projects/Scripts/Engines/Chat/Chat.cs index 0c673dba2..705463ec5 100644 --- a/Projects/Scripts/Engines/Chat/Chat.cs +++ b/Projects/Scripts/Engines/Chat/Chat.cs @@ -1,13 +1,12 @@ using System; using System.IO; -using System.Linq; using Server.Accounting; using Server.Misc; using Server.Network; namespace Server.Engines.Chat { - public static class ChatSystem + public class ChatSystem { public static bool Enabled{ get; set; } = true; @@ -19,7 +18,7 @@ namespace Server.Engines.Chat public static void SendCommandTo(Mobile to, ChatCommand type, string param1 = null, string param2 = null) { - ChatPackets.SendChatMessage(to?.NetState, null, (int)type + 20, param1, param2); + to?.Send(new ChatMessagePacket(null, (int)type + 20, param1, param2)); } public static void OpenChatWindowRequest(NetState state, PacketReader pvSrc) @@ -62,11 +61,21 @@ namespace Server.Engines.Chat { // TODO: Optimize this search - if (Accounts.GetAccounts().Cast().Any(checkAccount => Insensitive.Equals(checkAccount.GetTag("ChatName")?.Trim(), chatName))) + foreach (Account checkAccount in Accounts.GetAccounts()) { - from.SendMessage("Nickname already in use."); - SendCommandTo(from, ChatCommand.AskNewNickname); - return; + string existingName = checkAccount.GetTag("ChatName"); + + if (existingName != null) + { + existingName = existingName.Trim(); + + if (Insensitive.Equals(existingName, chatName)) + { + from.SendMessage("Nickname already in use."); + SendCommandTo(from, ChatCommand.AskNewNickname); + return; + } + } } accountChatName = chatName; @@ -120,15 +129,17 @@ namespace Server.Engines.Chat if (handler.RequireConference && channel == null) user.SendMessage(31); /* You must be in a conference to do this. - * To join a conference, select one from the Conference menu. - */ + * To join a conference, select one from the Conference menu. + */ else if (handler.RequireModerator && !user.IsModerator) user.SendMessage(29); // You must have operator status to do this. else handler.Callback(user, channel, param); } else + { Console.WriteLine("Client: {0}: Unknown chat action 0x{1:X}: {2}", state, actionID, param); + } } catch (Exception e) { @@ -136,4 +147,4 @@ namespace Server.Engines.Chat } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Chat/ChatActionHandlers.cs b/Projects/Scripts/Engines/Chat/ChatActionHandlers.cs index 5cf3b95c4..b6ad6c2df 100644 --- a/Projects/Scripts/Engines/Chat/ChatActionHandlers.cs +++ b/Projects/Scripts/Engines/Chat/ChatActionHandlers.cs @@ -1,6 +1,6 @@ namespace Server.Engines.Chat { - public static class ChatActionHandlers + public class ChatActionHandlers { private static ChatActionHandler[] m_Handlers; @@ -112,8 +112,8 @@ namespace Server.Engines.Chat { from.IgnorePrivateMessage = true; from.SendMessage(38); /* You will no longer receive private messages. - * Those who send you a message will be notified that you are blocking incoming messages. - */ + * Those who send you a message will be notified that you are blocking incoming messages. + */ } public static void TogglePrivateMessages(ChatUser from, Channel channel, string param) diff --git a/Projects/Scripts/Engines/Chat/ChatUser.cs b/Projects/Scripts/Engines/Chat/ChatUser.cs index d2d802da8..a24ee7508 100644 --- a/Projects/Scripts/Engines/Chat/ChatUser.cs +++ b/Projects/Scripts/Engines/Chat/ChatUser.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using Server.Accounting; namespace Server.Engines.Chat @@ -65,14 +64,16 @@ namespace Server.Engines.Chat return false; } - public void SendMessage(int number, string param1 = "", string param2 = "") + public void SendMessage(int number, string param1 = null, string param2 = null) { - ChatPackets.SendChatMessage(Mobile.NetState, Mobile, number, param1, param2); + if (Mobile.NetState != null) + Mobile.Send(new ChatMessagePacket(Mobile, number, param1, param2)); } - public void SendMessage(int number, Mobile from, string param1 = "", string param2 = "") + public void SendMessage(int number, Mobile from, string param1, string param2) { - ChatPackets.SendChatMessage(Mobile.NetState, from, number, param1, param2); + if (Mobile.NetState != null) + Mobile.Send(new ChatMessagePacket(from, number, param1, param2)); } public bool IsIgnored(ChatUser check) => Ignored.Contains(check); @@ -80,7 +81,9 @@ namespace Server.Engines.Chat public void AddIgnored(ChatUser user) { if (IsIgnored(user)) + { SendMessage(22, user.Username); // You are already ignoring %1. + } else { Ignored.Add(user); @@ -103,7 +106,9 @@ namespace Server.Engines.Chat SendMessage(26); // You are no longer ignoring anyone. } else + { SendMessage(25, user.Username); // You are not ignoring %1. + } } public static ChatUser AddChatUser(Mobile from) @@ -167,7 +172,18 @@ namespace Server.Engines.Chat return c; } - public static ChatUser GetChatUser(string username) => m_Users.FirstOrDefault(user => user.Username == username); + public static ChatUser GetChatUser(string username) + { + for (int i = 0; i < m_Users.Count; ++i) + { + ChatUser user = m_Users[i]; + + if (user.Username == username) + return user; + } + + return null; + } public static void GlobalSendCommand(ChatCommand command, string param1, string param2 = null) { diff --git a/Projects/Scripts/Engines/Chat/Chatold.cs b/Projects/Scripts/Engines/Chat/Chatold.cs index 2ae2c4f35..0f3626116 100644 --- a/Projects/Scripts/Engines/Chat/Chatold.cs +++ b/Projects/Scripts/Engines/Chat/Chatold.cs @@ -1,6 +1,6 @@ namespace Server.Chat { - public static class ChatSystem + public class ChatSystem { public static void Initialize() { @@ -12,4 +12,4 @@ namespace Server.Chat e.Mobile.SendMessage("Chat is not currently supported."); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Chat/Packets.cs b/Projects/Scripts/Engines/Chat/Packets.cs index ce41aa740..3d8bfd563 100644 --- a/Projects/Scripts/Engines/Chat/Packets.cs +++ b/Projects/Scripts/Engines/Chat/Packets.cs @@ -1,36 +1,28 @@ -using Server.Buffers; using Server.Network; namespace Server.Engines.Chat { - public static class ChatPackets + public sealed class ChatMessagePacket : Packet { - public static void SendChatMessage(NetState ns, Mobile who, int number, string param1, string param2) + public ChatMessagePacket(Mobile who, int number, string param1, string param2) : base(0xB2) { - if (ns == null) - return; + if (param1 == null) + param1 = string.Empty; - param1 ??= ""; - param2 ??= ""; + if (param2 == null) + param2 = string.Empty; - int length = 13 + (param1.Length + param2.Length) * 2; - //base(0xB2) + EnsureCapacity(13 + (param1.Length + param2.Length) * 2); - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xB2); // Packet ID - writer.Write((ushort)length); // Dynamic Length - - writer.Write((ushort)(number - 20)); + m_Stream.Write((ushort)(number - 20)); if (who != null) - writer.WriteAsciiFixed(who.Language, 4); + m_Stream.WriteAsciiFixed(who.Language, 4); else - writer.Position += 4; + m_Stream.Write(0); - writer.WriteBigUniNull(param1); - writer.WriteBigUniNull(param2); - - ns.Send(writer.Span); + m_Stream.WriteBigUniNull(param1); + m_Stream.WriteBigUniNull(param2); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/ConPVP/Arena.cs b/Projects/Scripts/Engines/ConPVP/Arena.cs index c8a907a64..12703d633 100644 --- a/Projects/Scripts/Engines/ConPVP/Arena.cs +++ b/Projects/Scripts/Engines/ConPVP/Arena.cs @@ -512,7 +512,7 @@ namespace Server.Engines.ConPVP if (offset < offsets.Length) p = offsets[offset++]; else - p = offsets[^1]; + p = offsets[offsets.Length - 1]; p.X = p.X * matrix[0, 0] + p.Y * matrix[0, 1]; p.Y = p.X * matrix[1, 0] + p.Y * matrix[1, 1]; @@ -574,15 +574,12 @@ namespace Server.Engines.ConPVP if (hasBounds) { List pets = new List(); - IPooledEnumerable eable = facet.GetMobilesInBounds(m_Bounds); - foreach (Mobile mob in eable) + foreach (Mobile mob in facet.GetMobilesInBounds(m_Bounds)) if (mob is BaseCreature pet && pet.Controlled && pet.ControlMaster != null && Players.Contains(pet.ControlMaster)) pets.Add(pet); - eable.Free(); - foreach (Mobile pet in pets) { pet.Combatant = null; @@ -752,7 +749,7 @@ namespace Server.Engines.ConPVP #region Offsets & Rotation - private static readonly Point2D[] m_EdgeOffsets = + private static Point2D[] m_EdgeOffsets = { /* * /\ @@ -775,7 +772,7 @@ namespace Server.Engines.ConPVP }; // nw corner - private static readonly Point2D[] m_CornerOffsets = + private static Point2D[] m_CornerOffsets = { /* * /\ @@ -796,7 +793,7 @@ namespace Server.Engines.ConPVP new Point2D(3, 0) }; - private static readonly int[][,] m_Rotate = + private static int[][,] m_Rotate = { new[,] { { +1, 0 }, { 0, +1 } }, // west new[,] { { -1, 0 }, { 0, -1 } }, // east diff --git a/Projects/Scripts/Engines/ConPVP/DuelContext.cs b/Projects/Scripts/Engines/ConPVP/DuelContext.cs index 1d6a546b9..d4d2c388f 100644 --- a/Projects/Scripts/Engines/ConPVP/DuelContext.cs +++ b/Projects/Scripts/Engines/ConPVP/DuelContext.cs @@ -160,7 +160,7 @@ namespace Server.Engines.ConPVP if (spell is RecallSpell) from.SendMessage("You may not cast this spell."); - string title; + string title = null; string option; if (spell is ArcanistSpell) @@ -854,9 +854,16 @@ namespace Server.Engines.ConPVP Participant p = Participants[i]; if (p.Eliminated) - hasWinner |= ++eliminated == Participants.Count - 1; + { + ++eliminated; + + if (eliminated == Participants.Count - 1) + hasWinner = true; + } else + { winner = p; + } } return hasWinner ? winner ?? Participants[0] : null; @@ -1623,7 +1630,16 @@ namespace Server.Engines.ConPVP int rx = dx - dy; int ry = dx + dy; - bool eastToWest = (rx < 0 || ry < 0) && (rx >= 0 || ry >= 0); + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; Effects.PlaySound(wall, Arena.Facet, 0x1F6); @@ -1801,7 +1817,9 @@ namespace Server.Engines.ConPVP } } else + { defs = basedef.Options; + } int changes = 0; @@ -1981,7 +1999,9 @@ namespace Server.Engines.ConPVP if (!Registered) return; - StartedReadyCountdown |= count != -1; + if (count != -1) + StartedReadyCountdown = true; + ReadyCount = count; if (count == 0) diff --git a/Projects/Scripts/Engines/ConPVP/Games/BombingRun.cs b/Projects/Scripts/Engines/ConPVP/Games/BombingRun.cs index 406d1121e..76318ee08 100644 --- a/Projects/Scripts/Engines/ConPVP/Games/BombingRun.cs +++ b/Projects/Scripts/Engines/ConPVP/Games/BombingRun.cs @@ -293,7 +293,7 @@ namespace Server.Engines.ConPVP if (list.Count > 0) { - Point3D p = list[^1]; + Point3D p = list[list.Count - 1]; if (p.X != ix || p.Y != iy || p.Z != iz) list.Add(new Point3D(ix, iy, iz)); @@ -308,7 +308,7 @@ namespace Server.Engines.ConPVP z += zslp; } - if (list.Count > 0 && list[^1] != dest) + if (list.Count > 0 && list[list.Count - 1] != dest) list.Add(dest); /*if ( dist3d > 4 && ( dest.X != org.X || dest.Y != org.Y ) ) @@ -429,7 +429,10 @@ namespace Server.Engines.ConPVP if (t.Z <= point.Z && t.Z + height >= point.Z && (id.Flags & (TileFlag.Impassable | TileFlag.Wall | TileFlag.NoShoot)) != 0) { - point = i > m_PathIdx ? m_Path[i - 1] : GetWorldLocation(); + if (i > m_PathIdx) + point = m_Path[i - 1]; + else + point = GetWorldLocation(); HitObject(point, t.Z, height); return; } @@ -445,9 +448,13 @@ namespace Server.Engines.ConPVP continue; if (i is BRGoal) + { height = 17; + } else if (i is Blocker) + { height = 20; + } else { ItemData id = i.ItemData; @@ -466,7 +473,10 @@ namespace Server.Engines.ConPVP (i is Blocker || loc.Z <= point.Z && loc.Z + height >= point.Z)) { found = true; - point = j > m_PathIdx ? m_Path[j - 1] : GetWorldLocation(); + if (j > m_PathIdx) + point = m_Path[j - 1]; + else + point = GetWorldLocation(); break; } } @@ -484,7 +494,9 @@ namespace Server.Engines.ConPVP HitObject(point, loc.Z, height); } else + { HitObject(point, loc.Z, height); + } return; } @@ -499,11 +511,12 @@ namespace Server.Engines.ConPVP if (m == null || m == Thrower) continue; + Point3D point; Point3D loc = m.Location; for (int j = m_PathIdx; j < pathCheckEnd && !found; j++) { - Point3D point = m_Path[j]; + point = m_Path[j]; if (loc.X == point.X && loc.Y == point.Y && loc.Z <= point.Z && loc.Z + 16 >= point.Z) @@ -537,10 +550,9 @@ namespace Server.Engines.ConPVP else if (m_Path.Count > 0) MoveToWorld(m_Path.Last); - int myZ = Map?.GetAverageZ(X, Y) ?? 0; - - StaticTile[] statics = Map?.Tiles?.GetStaticTiles(X, Y, true) ?? new StaticTile[0]; + int myZ = Map.GetAverageZ(X, Y); + StaticTile[] statics = Map.Tiles.GetStaticTiles(X, Y, true); for (int j = 0; j < statics.Length; j++) { StaticTile t = statics[j]; @@ -664,7 +676,7 @@ namespace Server.Engines.ConPVP if (m_Bomb.Parent == null && m_Bomb.m_Game?.Controller != null) { if (!m_Bomb.m_Flying && m_Bomb.Map != Map.Internal) - Effects.SendLocationEffect(m_Bomb.GetWorldLocation(), m_Bomb.Map, 0x377A, 16, 10, m_Bomb.Hue); + Effects.SendLocationEffect(m_Bomb.GetWorldLocation(), m_Bomb.Map, 0x377A, 16, 10, m_Bomb.Hue, 0); if (m_Bomb.Location != m_Bomb.m_Game.Controller.BombHome) { @@ -971,7 +983,9 @@ namespace Server.Engines.ConPVP total = entries.Count; } else - total += section.Players.Values.Count(player => player.Score > 0); + foreach (BRPlayerInfo player in section.Players.Values) + if (player.Score > 0) + total++; entries.Sort(); @@ -1708,13 +1722,12 @@ namespace Server.Engines.ConPVP for (int i = 0; i < m_Context.Participants.Count; ++i) { - DuelPlayer[] players = m_Context.Participants[i]?.Players; - if (players == null) + if (!(m_Context.Participants[i] is Participant p) || p.Players == null) continue; - for (int j = 0; j < players.Length; ++j) + for (int j = 0; j < p.Players.Length; ++j) { - DuelPlayer dp = players[j]; + DuelPlayer dp = p.Players[j]; if (dp?.Mobile != null) { @@ -1723,16 +1736,16 @@ namespace Server.Engines.ConPVP } } - if (i == winner?.TeamID) + if (i == winner.TeamID) continue; - for (int j = 0; j < players.Length; ++j) - if (players[j] != null) - players[j].Eliminated = true; + if (p.Players != null) + for (int j = 0; j < p.Players.Length; ++j) + if (p.Players[j] != null) + p.Players[j].Eliminated = true; } - if (winner != null) - m_Context.Finish(m_Context.Participants[winner.TeamID]); + m_Context.Finish(m_Context.Participants[winner.TeamID]); } public override void OnStop() diff --git a/Projects/Scripts/Engines/ConPVP/Games/CTF.cs b/Projects/Scripts/Engines/ConPVP/Games/CTF.cs index 9d631f312..608e1543c 100644 --- a/Projects/Scripts/Engines/ConPVP/Games/CTF.cs +++ b/Projects/Scripts/Engines/ConPVP/Games/CTF.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using Server.Gumps; using Server.Items; @@ -71,13 +70,17 @@ namespace Server.Engines.ConPVP { CTFTeamInfo teamInfo = game.Controller.TeamInfo[i % 8]; - if (teamInfo?.Flag != null) - entries.Add(teamInfo); + if (teamInfo?.Flag == null) + continue; + + entries.Add(teamInfo); } else - entries.AddRange(section.Players.Values.Where(player => player.Score > 0)); + foreach (CTFPlayerInfo player in section.Players.Values) + if (player.Score > 0) + entries.Add(player); - entries.Sort((a, b) => b.Score - a.Score); + entries.Sort(delegate(IRankedCTF a, IRankedCTF b) { return b.Score - a.Score; }); int height = 0; @@ -108,8 +111,7 @@ namespace Server.Engines.ConPVP if (section == null) for (int i = 0; i < entries.Count; ++i) { - if (!(entries[i] is CTFTeamInfo teamInfo)) - continue; + CTFTeamInfo teamInfo = entries[i] as CTFTeamInfo; AddImage(30, 70 + i * 75, 10152); AddImage(30, 85 + i * 75, 10151); @@ -192,7 +194,10 @@ namespace Server.Engines.ConPVP private void AddColoredText(int x, int y, int width, int height, string text, int color) { - AddHtml(x, y, width, height, color == 0 ? text : Color(text, color)); + if (color == 0) + AddHtml(x, y, width, height, text); + else + AddHtml(x, y, width, height, Color(text, color)); } } @@ -241,8 +246,10 @@ namespace Server.Engines.ConPVP else if (ourTeam == useTeam) { if (Location == m_TeamInfo.Origin && Map == m_TeamInfo.Game.Facet) - Packets.SendUnicodeMessage(from.NetState, Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", Name, - "Touch me not for I am chaste."); + { + from.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", Name, + "Touch me not for I am chaste.")); + } else { CTFPlayerInfo playerInfo = useTeam[from]; @@ -299,7 +306,9 @@ namespace Server.Engines.ConPVP m_ReturnCount = Math.Min(m_ReturnCount, 10); } else + { SendHome(); + } } private void StopCountdown() @@ -408,7 +417,9 @@ namespace Server.Engines.ConPVP } } else + { from.LocalOverheadMessage(MessageType.Regular, 0x26, false, "Those are not my cookies."); + } } else if (obj is Mobile passTo) { @@ -932,8 +943,15 @@ namespace Server.Engines.ConPVP if (ourFlagCarrier != null && GetTeamInfo(ourFlagCarrier) == teamInfo) { - if (ourFlagCarrier.Aggressors.Any(t => t.Defender == ourFlagCarrier && t.Attacker == mob)) + for (int j = 0; j < ourFlagCarrier.Aggressors.Count; ++j) + { + if (!(ourFlagCarrier.Aggressors[j] is AggressorInfo aggr) || + aggr.Defender != ourFlagCarrier || aggr.Attacker != mob) + continue; + playerInfo.Score += 2; // helped defend guy capturing enemy flag + break; + } if (mob.Map == ourFlagCarrier.Map && ourFlagCarrier.InRange(mob, 12)) playerInfo.Score += 1; // helped defend guy capturing enemy flag diff --git a/Projects/Scripts/Engines/ConPVP/Games/DoubleDom.cs b/Projects/Scripts/Engines/ConPVP/Games/DoubleDom.cs index d516600cf..48080203b 100644 --- a/Projects/Scripts/Engines/ConPVP/Games/DoubleDom.cs +++ b/Projects/Scripts/Engines/ConPVP/Games/DoubleDom.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using Server.Gumps; using Server.Items; @@ -73,9 +72,11 @@ namespace Server.Engines.ConPVP entries.Add(teamInfo); } else - entries.AddRange(section.Players.Values.Where(player => player.Score > 0)); + foreach (DDPlayerInfo player in section.Players.Values) + if (player.Score > 0) + entries.Add(player); - entries.Sort((a, b) => b.Score - a.Score); + entries.Sort(delegate(IRankedCTF a, IRankedCTF b) { return b.Score - a.Score; }); int height = 0; @@ -106,8 +107,7 @@ namespace Server.Engines.ConPVP if (section == null) for (int i = 0; i < entries.Count; ++i) { - if (!(entries[i] is DDTeamInfo teamInfo)) - continue; + DDTeamInfo teamInfo = entries[i] as DDTeamInfo; AddImage(30, 70 + i * 75, 10152); AddImage(30, 85 + i * 75, 10151); diff --git a/Projects/Scripts/Engines/ConPVP/Games/KingOfTheHill.cs b/Projects/Scripts/Engines/ConPVP/Games/KingOfTheHill.cs index 188ea8670..5beded8eb 100644 --- a/Projects/Scripts/Engines/ConPVP/Games/KingOfTheHill.cs +++ b/Projects/Scripts/Engines/ConPVP/Games/KingOfTheHill.cs @@ -171,7 +171,8 @@ namespace Server.Engines.ConPVP King = m; - m_KingTimer ??= new KingTimer(this); + if (m_KingTimer == null) + m_KingTimer = new KingTimer(this); m_KingTimer.Stop(); m_KingTimer.StartHillTicker(); @@ -1112,13 +1113,12 @@ namespace Server.Engines.ConPVP for (int i = 0; i < m_Context.Participants.Count; ++i) { - DuelPlayer[] players = m_Context.Participants[i]?.Players; - if (players == null) + if (!(m_Context.Participants[i] is Participant p) || p.Players == null) continue; - for (int j = 0; j < players.Length; ++j) + for (int j = 0; j < p.Players.Length; ++j) { - DuelPlayer dp = players[j]; + DuelPlayer dp = p.Players[j]; if (dp?.Mobile != null) { @@ -1130,9 +1130,10 @@ namespace Server.Engines.ConPVP if (i == winner?.TeamID) continue; - for (int j = 0; j < players.Length; ++j) - if (players[j] != null) - players[j].Eliminated = true; + if (p.Players != null) + for (int j = 0; j < p.Players.Length; ++j) + if (p.Players[j] != null) + p.Players[j].Eliminated = true; } if (winner != null) @@ -1148,7 +1149,7 @@ namespace Server.Engines.ConPVP if (Controller.Hills[i] != null) Controller.Hills[i].Game = null; - foreach (var board in Controller.Boards) + foreach (KHBoard board in Controller.Boards) if (board != null) board.m_Game = null; diff --git a/Projects/Scripts/Engines/ConPVP/Games/TourneyMatch.cs b/Projects/Scripts/Engines/ConPVP/Games/TourneyMatch.cs index e14e4840e..1642a504f 100644 --- a/Projects/Scripts/Engines/ConPVP/Games/TourneyMatch.cs +++ b/Projects/Scripts/Engines/ConPVP/Games/TourneyMatch.cs @@ -106,7 +106,7 @@ namespace Server.Engines.ConPVP foreach (Mobile view in mob.GetMobilesInRange(18)) if (!mob.CanSee(view)) - Packets.SendRemoveEntity(mob.NetState, view.Serial); + mob.Send(view.RemovePacket); mob.LocalOverheadMessage(MessageType.Emote, 0x3B2, false, "* Your mind focuses intently on the fight and all other distractions fade away *"); diff --git a/Projects/Scripts/Engines/ConPVP/Gumps/RulesetGump.cs b/Projects/Scripts/Engines/ConPVP/Gumps/RulesetGump.cs index fe6842107..f1359bae4 100644 --- a/Projects/Scripts/Engines/ConPVP/Gumps/RulesetGump.cs +++ b/Projects/Scripts/Engines/ConPVP/Gumps/RulesetGump.cs @@ -93,7 +93,9 @@ namespace Server.Engines.ConPVP for (int i = 0; i < info.Switches.Length; ++i) { int sid = info.Switches[i]; - opts[sid] |= sid >= 0 && sid < m_Page.Options.Length; + + if (sid >= 0 && sid < m_Page.Options.Length) + opts[sid] = true; } for (int i = 0; i < opts.Length; ++i) diff --git a/Projects/Scripts/Engines/ConPVP/Participant.cs b/Projects/Scripts/Engines/ConPVP/Participant.cs index 9c5f8fbe1..2f83d7fbe 100644 --- a/Projects/Scripts/Engines/ConPVP/Participant.cs +++ b/Projects/Scripts/Engines/ConPVP/Participant.cs @@ -173,7 +173,7 @@ namespace Server.Engines.ConPVP } Resize(Players.Length + 1); - Players[^1] = new DuelPlayer(player, this); + Players[Players.Length - 1] = new DuelPlayer(player, this); } public void Resize(int count) diff --git a/Projects/Scripts/Engines/ConPVP/Tournament.cs b/Projects/Scripts/Engines/ConPVP/Tournament.cs index 355498447..bd2e9c569 100644 --- a/Projects/Scripts/Engines/ConPVP/Tournament.cs +++ b/Projects/Scripts/Engines/ConPVP/Tournament.cs @@ -433,7 +433,7 @@ namespace Server.Engines.ConPVP if (Pyramid.Levels.Count < 1) break; - PyramidLevel top = Pyramid.Levels[^1]; + PyramidLevel top = Pyramid.Levels[Pyramid.Levels.Count - 1]; if (top.FreeAdvance != null || top.Matches.Count != 1) break; @@ -451,7 +451,7 @@ namespace Server.Engines.ConPVP if (Pyramid.Levels.Count < 2) break; - PyramidLevel top = Pyramid.Levels[^1]; + PyramidLevel top = Pyramid.Levels[Pyramid.Levels.Count - 1]; if (top.FreeAdvance != null || top.Matches.Count != 1) break; @@ -471,7 +471,7 @@ namespace Server.Engines.ConPVP GiveAwards(part.Players, TrophyRank.Silver, cash / 2); } - PyramidLevel next = Pyramid.Levels[^2]; + PyramidLevel next = Pyramid.Levels[Pyramid.Levels.Count - 2]; if (next.Matches.Count > 2) break; @@ -495,7 +495,7 @@ namespace Server.Engines.ConPVP } } - private void GiveAwards(IReadOnlyList players, TrophyRank rank, int cash) + private void GiveAwards(List players, TrophyRank rank, int cash) { if (players.Count == 0) return; @@ -663,39 +663,69 @@ namespace Server.Engines.ConPVP try { if (EventController != null) + { Alert("The tournament has completed!", $"Team {EventController.GetTeamName(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner))} has won!"); + } else if (TourneyType == TourneyType.RandomTeam) + { Alert("The tournament has completed!", $"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!"); + } else if (TourneyType == TourneyType.Faction) { if (m_ParticipantsPerMatch == 4) { - string name = Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) switch + string name = "(null)"; + + switch (Pyramid.Levels[0].Matches[0].Participants.IndexOf( + winner)) { - 0 => "Minax", - 1 => "Council of Mages", - 2 => "True Britannians", - 3 => "Shadowlords", - _ => "(null)" - }; + case 0: + { + name = "Minax"; + break; + } + case 1: + { + name = "Council of Mages"; + break; + } + case 2: + { + name = "True Britannians"; + break; + } + case 3: + { + name = "Shadowlords"; + break; + } + } Alert("The tournament has completed!", $"The {name} team has won!"); } else if (m_ParticipantsPerMatch == 2) + { Alert("The tournament has completed!", $"The {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Evil" : "Hero")} team has won!"); + } else + { Alert("The tournament has completed!", $"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!"); + } } else if (TourneyType == TourneyType.RedVsBlue) + { Alert("The tournament has completed!", $"Team {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Red" : "Blue")} has won!"); + } else + { Alert("The tournament has completed!", $"{winner.NameList} {(winner.Players.Count > 1 ? "are" : "is")} the champion{(winner.Players.Count == 1 ? "" : "s")}."); + } } catch { @@ -709,7 +739,7 @@ namespace Server.Engines.ConPVP } else if (Pyramid.Levels.Count > 0) { - PyramidLevel activeLevel = Pyramid.Levels[^1]; + PyramidLevel activeLevel = Pyramid.Levels[Pyramid.Levels.Count - 1]; bool stillGoing = false; for (int i = 0; i < activeLevel.Matches.Count; ++i) @@ -816,6 +846,7 @@ namespace Server.Engines.ConPVP $"The {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Evil" : "Hero")} team has won!"); } else + { Alert("The tournament has completed!", $"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!"); } diff --git a/Projects/Scripts/Engines/Craft/Core/CraftItem.cs b/Projects/Scripts/Engines/Craft/Core/CraftItem.cs index c53651f36..23611a3ed 100644 --- a/Projects/Scripts/Engines/Craft/Core/CraftItem.cs +++ b/Projects/Scripts/Engines/Craft/Core/CraftItem.cs @@ -484,7 +484,8 @@ namespace Server.Engines.Craft if (m_TypesTable[j][0] == baseType) types[i] = m_TypesTable[j]; - types[i] ??= new[] { baseType }; + if (types[i] == null) + types[i] = new[] { baseType }; amounts[i] = craftRes.Amount; @@ -909,7 +910,8 @@ namespace Server.Engines.Craft hammer.Delete(); } - toolBroken |= tool.UsesRemaining < 1 && tool.BreakOnDepletion; + if (tool.UsesRemaining < 1 && tool.BreakOnDepletion) + toolBroken = true; if (toolBroken) tool.Delete(); @@ -1031,7 +1033,8 @@ namespace Server.Engines.Craft tool.UsesRemaining--; - toolBroken |= tool.UsesRemaining < 1 && tool.BreakOnDepletion; + if (tool.UsesRemaining < 1 && tool.BreakOnDepletion) + toolBroken = true; if (toolBroken) tool.Delete(); diff --git a/Projects/Scripts/Engines/Craft/Core/Recipes.cs b/Projects/Scripts/Engines/Craft/Core/Recipes.cs index 74e5179d1..a2b3578c3 100644 --- a/Projects/Scripts/Engines/Craft/Core/Recipes.cs +++ b/Projects/Scripts/Engines/Craft/Core/Recipes.cs @@ -33,7 +33,7 @@ namespace Server.Engines.Craft public int ID{ get; } - public TextDefinition TextDefinition => m_TD ??= new TextDefinition(CraftItem.NameNumber, CraftItem.NameString); + public TextDefinition TextDefinition => m_TD ?? (m_TD = new TextDefinition(CraftItem.NameNumber, CraftItem.NameString)); public static void Initialize() { @@ -52,13 +52,15 @@ namespace Server.Engines.Craft { if (targeted is PlayerMobile mobile) { - foreach (var (key, _) in Recipes) - mobile.AcquireRecipe(key); + foreach (KeyValuePair kvp in Recipes) + mobile.AcquireRecipe(kvp.Key); m.SendMessage("You teach them all of the recipes."); } else + { m.SendMessage("That is not a player!"); + } }); } @@ -84,4 +86,4 @@ namespace Server.Engines.Craft }); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Craft/Core/Repair.cs b/Projects/Scripts/Engines/Craft/Core/Repair.cs index 2fff2c4cb..2d74fc499 100644 --- a/Projects/Scripts/Engines/Craft/Core/Repair.cs +++ b/Projects/Scripts/Engines/Craft/Core/Repair.cs @@ -491,7 +491,7 @@ namespace Server.Engines.Craft if (!usingDeed) { - m_CraftSystem.GetContext(from); + CraftContext context = m_CraftSystem.GetContext(from); from.SendGump(new CraftGump(from, m_CraftSystem, m_Tool, number)); } else @@ -504,4 +504,4 @@ namespace Server.Engines.Craft } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Craft/DefAlchemy.cs b/Projects/Scripts/Engines/Craft/DefAlchemy.cs index bfdeef6c8..85746fc1f 100644 --- a/Projects/Scripts/Engines/Craft/DefAlchemy.cs +++ b/Projects/Scripts/Engines/Craft/DefAlchemy.cs @@ -17,7 +17,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044001; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefAlchemy(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefAlchemy()); public override double GetChanceAtMin(CraftItem item) => 0.0; diff --git a/Projects/Scripts/Engines/Craft/DefBlacksmithy.cs b/Projects/Scripts/Engines/Craft/DefBlacksmithy.cs index a5f98f5b4..c68c961ab 100644 --- a/Projects/Scripts/Engines/Craft/DefBlacksmithy.cs +++ b/Projects/Scripts/Engines/Craft/DefBlacksmithy.cs @@ -30,7 +30,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044002; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefBlacksmithy(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefBlacksmithy()); public override CraftECA ECA => CraftECA.ChanceMinusSixtyToFourtyFive; diff --git a/Projects/Scripts/Engines/Craft/DefBowFletching.cs b/Projects/Scripts/Engines/Craft/DefBowFletching.cs index c5a676fb8..1af14ebf7 100644 --- a/Projects/Scripts/Engines/Craft/DefBowFletching.cs +++ b/Projects/Scripts/Engines/Craft/DefBowFletching.cs @@ -15,7 +15,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044006; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefBowFletching(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefBowFletching()); public override CraftECA ECA => CraftECA.FiftyPercentChanceMinusTenPercent; diff --git a/Projects/Scripts/Engines/Craft/DefCarpentry.cs b/Projects/Scripts/Engines/Craft/DefCarpentry.cs index 3d2427ce9..4e965a2f0 100644 --- a/Projects/Scripts/Engines/Craft/DefCarpentry.cs +++ b/Projects/Scripts/Engines/Craft/DefCarpentry.cs @@ -15,7 +15,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044004; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefCarpentry(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefCarpentry()); public override double GetChanceAtMin(CraftItem item) => 0.5; diff --git a/Projects/Scripts/Engines/Craft/DefCartography.cs b/Projects/Scripts/Engines/Craft/DefCartography.cs index 3da613c7a..370664838 100644 --- a/Projects/Scripts/Engines/Craft/DefCartography.cs +++ b/Projects/Scripts/Engines/Craft/DefCartography.cs @@ -15,7 +15,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044008; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefCartography(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefCartography()); public override double GetChanceAtMin(CraftItem item) => 0.0; diff --git a/Projects/Scripts/Engines/Craft/DefCooking.cs b/Projects/Scripts/Engines/Craft/DefCooking.cs index 242cae9f8..b37f7d4af 100644 --- a/Projects/Scripts/Engines/Craft/DefCooking.cs +++ b/Projects/Scripts/Engines/Craft/DefCooking.cs @@ -15,7 +15,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044003; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefCooking(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefCooking()); public override CraftECA ECA => CraftECA.ChanceMinusSixtyToFourtyFive; diff --git a/Projects/Scripts/Engines/Craft/DefGlassblowing.cs b/Projects/Scripts/Engines/Craft/DefGlassblowing.cs index edfe0a8b4..4daf3d40f 100644 --- a/Projects/Scripts/Engines/Craft/DefGlassblowing.cs +++ b/Projects/Scripts/Engines/Craft/DefGlassblowing.cs @@ -16,7 +16,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044622; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefGlassblowing(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefGlassblowing()); public override double GetChanceAtMin(CraftItem item) => item.ItemType == typeof(HollowPrism) ? 0.5 : 0.0; diff --git a/Projects/Scripts/Engines/Craft/DefInscription.cs b/Projects/Scripts/Engines/Craft/DefInscription.cs index 42a884656..d8a5892eb 100644 --- a/Projects/Scripts/Engines/Craft/DefInscription.cs +++ b/Projects/Scripts/Engines/Craft/DefInscription.cs @@ -36,7 +36,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044009; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefInscription(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefInscription()); public override double GetChanceAtMin(CraftItem item) => 0.0; diff --git a/Projects/Scripts/Engines/Craft/DefMasonry.cs b/Projects/Scripts/Engines/Craft/DefMasonry.cs index a4aefbb5c..66b193e29 100644 --- a/Projects/Scripts/Engines/Craft/DefMasonry.cs +++ b/Projects/Scripts/Engines/Craft/DefMasonry.cs @@ -16,7 +16,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044500; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefMasonry(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefMasonry()); public override double GetChanceAtMin(CraftItem item) => 0.0; diff --git a/Projects/Scripts/Engines/Craft/DefTailoring.cs b/Projects/Scripts/Engines/Craft/DefTailoring.cs index 826b3fc21..cc4185fb8 100644 --- a/Projects/Scripts/Engines/Craft/DefTailoring.cs +++ b/Projects/Scripts/Engines/Craft/DefTailoring.cs @@ -23,7 +23,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044005; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefTailoring(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefTailoring()); public override CraftECA ECA => CraftECA.ChanceMinusSixtyToFourtyFive; diff --git a/Projects/Scripts/Engines/Craft/DefTinkering.cs b/Projects/Scripts/Engines/Craft/DefTinkering.cs index f38af4961..e2cd7f346 100644 --- a/Projects/Scripts/Engines/Craft/DefTinkering.cs +++ b/Projects/Scripts/Engines/Craft/DefTinkering.cs @@ -31,7 +31,7 @@ namespace Server.Engines.Craft public override int GumpTitleNumber => 1044007; - public static CraftSystem CraftSystem => m_CraftSystem ??= new DefTinkering(); + public static CraftSystem CraftSystem => m_CraftSystem ?? (m_CraftSystem = new DefTinkering()); public override double GetChanceAtMin(CraftItem item) { diff --git a/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs b/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs index de6aca895..4dbad8c90 100644 --- a/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs +++ b/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs @@ -5,6 +5,11 @@ using Server.Mobiles; using Server.Network; using Server.Spells; +/* + this is From me to you, Under no terms, Conditions... K? to apply you + just simply Unpatch/delete, Stick these in, Same location.. Restart + */ + namespace Server.Engines.Doom { public class LeverPuzzleController : Item @@ -321,7 +326,7 @@ namespace Server.Engines.Doom SendLocationEffect(lp_Center, 0x1153, 0, 60, 1); PlaySounds(lp_Center, cs1); - Effects.SendBoltEffect(player); + Effects.SendBoltEffect(player, true); player.MoveToWorld(lr_Enter, Map.Malas); m_Timer = new LampRoomTimer(this); @@ -412,24 +417,25 @@ namespace Server.Engines.Doom public static void SendLocationEffect(IPoint3D p, int itemID, int speed, int duration, int hue) { - Effects.SendLocationEffect(p, Map.Malas, itemID, speed, duration, hue); + Effects.SendPacket(p, Map.Malas, new LocationEffect(p, itemID, speed, duration, hue, 0)); } public static void PlayerSendASCII(Mobile player, int index) { - Packets.SendAsciiMessage(player.NetState, Serial.MinusOne, 0xFFFF, MessageType.Label, MsgParams[index][0], - MsgParams[index][1], null, Msgs[index]); + player.Send(new AsciiMessage(Serial.MinusOne, 0xFFFF, MessageType.Label, MsgParams[index][0], + MsgParams[index][1], null, Msgs[index])); } /* I cant find any better way to send "speech" using fonts other than default */ public static void POHMessage(Mobile from, int index) { - IPooledEnumerable eable = from.Map.GetClientsInRange(from.Location); - foreach (NetState state in eable) - Packets.SendAsciiMessage(state, from.Serial, from.Body, MessageType.Regular, MsgParams[index][0], + Packet p = new AsciiMessage(from.Serial, from.Body, MessageType.Regular, MsgParams[index][0], MsgParams[index][1], from.Name, Msgs[index]); + p.Acquire(); + foreach (NetState state in from.Map.GetClientsInRange(from.Location)) + state.Send(p); - eable.Free(); + Packet.Release(p); } public override void Serialize(GenericWriter writer) diff --git a/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleItems.cs b/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleItems.cs index 322b3ea97..967aaa563 100644 --- a/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleItems.cs +++ b/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleItems.cs @@ -39,7 +39,7 @@ namespace Server.Engines.Doom public void CallBackMessage() { - PublicOverheadMessage(MessageType.Regular, 0x3B2, 1060003); // You try to pry the box open... + PublicOverheadMessage(MessageType.Regular, 0x3B2, 1060003, ""); // You try to pry the box open... } public override void OnAfterDelete() diff --git a/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs b/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs index 443285803..193961bae 100644 --- a/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs +++ b/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs @@ -77,15 +77,17 @@ namespace Server.Engines.Doom public Mobile m_Occupant; public LeverPuzzleRegion(LeverPuzzleController controller, int[] loc) - : base(null, Map.Malas, Find(LeverPuzzleController.lr_Enter, Map.Malas), new Rectangle2D(loc[0], loc[1], 1, 1)) => + : base(null, Map.Malas, Find(LeverPuzzleController.lr_Enter, Map.Malas), new Rectangle2D(loc[0], loc[1], 1, 1)) + { Register(); + } [CommandProperty(AccessLevel.GameMaster)] public Mobile Occupant => m_Occupant?.Alive == true ? m_Occupant : null; public override void OnEnter(Mobile m) { - if (m_Occupant == null && m is PlayerMobile && m.Alive) + if (m != null && m_Occupant == null && m is PlayerMobile && m.Alive) m_Occupant = m; } diff --git a/Projects/Scripts/Engines/Ethics/Core/Ethic.cs b/Projects/Scripts/Engines/Ethics/Core/Ethic.cs index 7cf6bbb93..555add67a 100644 --- a/Projects/Scripts/Engines/Ethics/Core/Ethic.cs +++ b/Projects/Scripts/Engines/Ethics/Core/Ethic.cs @@ -93,8 +93,8 @@ namespace Server.Ethics if (IsImbued(child, true)) return true; - public static bool IsImbued(Item item, bool recurse) => - Find(item) != null || recurse && item.Items.Any(child => IsImbued(child, true)); + return false; + } public static void Initialize() { diff --git a/Projects/Scripts/Engines/Ethics/Evil/Powers/Blight.cs b/Projects/Scripts/Engines/Ethics/Evil/Powers/Blight.cs index 3d1d981cd..59a4216e4 100644 --- a/Projects/Scripts/Engines/Ethics/Evil/Powers/Blight.cs +++ b/Projects/Scripts/Engines/Ethics/Evil/Powers/Blight.cs @@ -33,9 +33,7 @@ namespace Server.Ethics.Evil SpellHelper.GetSurfaceTop(ref p); - IPooledEnumerable eable = from.Mobile.GetMobilesInRange(6); - - foreach (Mobile mob in eable) + foreach (Mobile mob in from.Mobile.GetMobilesInRange(6)) { if (mob == from.Mobile || !SpellHelper.ValidIndirectTarget(from.Mobile, mob)) continue; @@ -56,8 +54,6 @@ namespace Server.Ethics.Evil powerFunctioned = true; } - eable.Free(); - if (powerFunctioned) { SpellHelper.Turn(from.Mobile, p); @@ -75,4 +71,4 @@ namespace Server.Ethics.Evil } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Ethics/Evil/Powers/UnholySense.cs b/Projects/Scripts/Engines/Ethics/Evil/Powers/UnholySense.cs index d62d6ea36..faf336aad 100644 --- a/Projects/Scripts/Engines/Ethics/Evil/Powers/UnholySense.cs +++ b/Projects/Scripts/Engines/Ethics/Evil/Powers/UnholySense.cs @@ -80,11 +80,13 @@ namespace Server.Ethics.Evil } } else + { sb.Append('.'); + } from.Mobile.LocalOverheadMessage(MessageType.Regular, 0x59, false, sb.ToString()); FinishInvoke(from); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Ethics/Hero/Powers/Bless.cs b/Projects/Scripts/Engines/Ethics/Hero/Powers/Bless.cs index b08df7afe..f6ecfc8a6 100644 --- a/Projects/Scripts/Engines/Ethics/Hero/Powers/Bless.cs +++ b/Projects/Scripts/Engines/Ethics/Hero/Powers/Bless.cs @@ -33,9 +33,7 @@ namespace Server.Ethics.Hero SpellHelper.GetSurfaceTop(ref p); - IPooledEnumerable eable = from.Mobile.GetMobilesInRange(6); - - foreach (Mobile mob in eable) + foreach (Mobile mob in from.Mobile.GetMobilesInRange(6)) { if (mob != from.Mobile && SpellHelper.ValidIndirectTarget(from.Mobile, mob)) continue; @@ -56,8 +54,6 @@ namespace Server.Ethics.Hero powerFunctioned = true; } - eable.Free(); - if (powerFunctioned) { SpellHelper.Turn(from.Mobile, p); @@ -75,4 +71,4 @@ namespace Server.Ethics.Hero } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Ethics/Hero/Powers/HolySense.cs b/Projects/Scripts/Engines/Ethics/Hero/Powers/HolySense.cs index 9a625cc2b..dff3df97c 100644 --- a/Projects/Scripts/Engines/Ethics/Hero/Powers/HolySense.cs +++ b/Projects/Scripts/Engines/Ethics/Hero/Powers/HolySense.cs @@ -80,11 +80,13 @@ namespace Server.Ethics.Hero } } else + { sb.Append('.'); + } from.Mobile.LocalOverheadMessage(MessageType.Regular, 0x59, false, sb.ToString()); FinishInvoke(from); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Factions/Core/Faction.cs b/Projects/Scripts/Engines/Factions/Core/Faction.cs index 39861a99a..4f9e0c0a4 100644 --- a/Projects/Scripts/Engines/Factions/Core/Faction.cs +++ b/Projects/Scripts/Engines/Factions/Core/Faction.cs @@ -8,6 +8,7 @@ using Server.Ethics; using Server.Guilds; using Server.Items; using Server.Mobiles; +using Server.Prompts; using Server.Targeting; namespace Server.Factions @@ -132,12 +133,21 @@ namespace Server.Factions public static void HandleAtrophy() { - if (Factions.Any(f => !f.State.IsAtrophyReady)) - return; + foreach (Faction f in Factions) + if (!f.State.IsAtrophyReady) + return; - List activePlayers = (from f in Factions from ps in f.Members where ps.KillPoints > 0 && ps.IsActive select ps).ToList(); + List activePlayers = new List(); - int distrib = Factions.Sum(f => f.State.CheckAtrophy()); + foreach (Faction f in Factions) + foreach (PlayerState ps in f.Members) + if (ps.KillPoints > 0 && ps.IsActive) + activePlayers.Add(ps); + + int distrib = 0; + + foreach (Faction f in Factions) + distrib += f.State.CheckAtrophy(); if (activePlayers.Count == 0) return; @@ -148,7 +158,12 @@ namespace Server.Factions public static void DistributePoints(int distrib) { - List activePlayers = (from f in Factions from ps in f.Members where ps.KillPoints > 0 && ps.IsActive select ps).ToList(); + List activePlayers = new List(); + + foreach (Faction f in Factions) + foreach (PlayerState ps in f.Members) + if (ps.KillPoints > 0 && ps.IsActive) + activePlayers.Add(ps); if (activePlayers.Count > 0) for (int i = 0; i < distrib; ++i) @@ -172,9 +187,13 @@ namespace Server.Factions return; if (recvState == null || recvState.Faction != giveState.Faction) + { from.SendLocalizedMessage(1042497); // Only faction mates can be honored this way. + } else if (giveState.KillPoints < 5) + { from.SendLocalizedMessage(1042499); // You must have at least five kill points to honor them. + } else { recvState.LastHonorTime = DateTime.UtcNow; @@ -186,7 +205,9 @@ namespace Server.Factions } } else + { from.SendLocalizedMessage(1042496); // You may only honor another player. + } } public virtual void AddMember(Mobile mob) @@ -628,7 +649,11 @@ namespace Server.Factions public static void FactionItemReset_OnCommand(CommandEventArgs e) { - List items = World.Items.Values.Where(item => item is IFactionItem && !(item is HoodedShroudOfShadows)).ToList(); + List items = new List(); + + foreach (Item item in World.Items.Values) + if (item is IFactionItem && !(item is HoodedShroudOfShadows)) + items.Add(item); int[] hues = new int[Factions.Count * 2]; @@ -648,7 +673,16 @@ namespace Server.Factions if (fci.FactionItemState != null || item.LootType != LootType.Blessed) continue; - if (hues.Any(t => item.Hue == t)) + bool isHued = false; + + for (int j = 0; j < hues.Length; ++j) + if (item.Hue == hues[j]) + { + isHued = true; + break; + } + + if (isHued) { fci.FactionItemState = null; ++count; @@ -807,7 +841,7 @@ namespace Server.Factions Silver += tithed; - silver -= tithed; + silver = silver - tithed; if (silver > 0) mob.AddToBackpack(new Silver(silver)); @@ -853,12 +887,19 @@ namespace Server.Factions Faction smallest = FindSmallestFaction(); - return smallest == null || (Members.Count + influx) * 100 / StabilityFactor <= smallest.Members.Count; + if (smallest == null) + return true; // sanity + + if ((Members.Count + influx) * 100 / StabilityFactor > smallest.Members.Count) + return false; + + return true; } public static void HandleDeath(Mobile victim, Mobile killer) { - killer ??= victim.FindMostRecentDamager(true); + if (killer == null) + killer = victim.FindMostRecentDamager(true); PlayerState killerState = PlayerState.Find(killer); Container killerPack = killer?.Backpack; @@ -900,7 +941,7 @@ namespace Server.Factions int silver = killerState.Faction.AwardSilver(killer, bc.FactionSilverWorth); if (silver > 0) - killer?.SendLocalizedMessage(1042748, + killer.SendLocalizedMessage(1042748, silver.ToString("N0")); // Thou hast earned ~1_AMOUNT~ silver for vanquishing the vile creature. } @@ -941,7 +982,7 @@ namespace Server.Factions { if (victimState.KillPoints <= -6) { - killer?.SendLocalizedMessage(501693); // This victim is not worth enough to get kill points from. + killer.SendLocalizedMessage(501693); // This victim is not worth enough to get kill points from. #region Ethics @@ -983,12 +1024,13 @@ namespace Server.Factions { victimState.IsActive = true; - killerState.IsActive |= 1 > Utility.Random(3); + if (1 > Utility.Random(3)) + killerState.IsActive = true; int silver = killerState.Faction.AwardSilver(killer, award * 40); if (silver > 0) - killer?.SendLocalizedMessage(1042736, + killer.SendLocalizedMessage(1042736, $"{silver:N0} silver\t{victim.Name}"); // You have earned ~1_SILVER_AMOUNT~ pieces for vanquishing ~2_PLAYER_NAME~! } @@ -997,9 +1039,9 @@ namespace Server.Factions int offset = award != 1 ? 0 : 2; // for pluralization - string args = $"{award}\t{victim.Name}\t{killer?.Name ?? ""}"; + string args = $"{award}\t{victim.Name}\t{killer.Name}"; - killer?.SendLocalizedMessage(1042737 + offset, + killer.SendLocalizedMessage(1042737 + offset, args); // Thou hast been honored with ~1_KILL_POINTS~ kill point(s) for vanquishing ~2_DEAD_PLAYER~! victim.SendLocalizedMessage(1042738 + offset, args); // Thou has lost ~1_KILL_POINTS~ kill point(s) to ~3_ATTACKER_NAME~ for being vanquished! @@ -1031,7 +1073,7 @@ namespace Server.Factions } else { - killer?.SendLocalizedMessage( + killer.SendLocalizedMessage( 1042231); // You have recently defeated this enemy and thus their death brings you no honor. } } @@ -1242,7 +1284,9 @@ namespace Server.Factions AddResponse("They have been kicked from their faction."); } else + { LogFailure("They are not in a faction."); + } break; } @@ -1256,7 +1300,9 @@ namespace Server.Factions AddResponse("The account has been banned from joining factions."); } else + { AddResponse("The account is already banned from joining factions."); + } for (int i = 0; i < acct.Length; ++i) { @@ -1276,7 +1322,9 @@ namespace Server.Factions } } else + { LogFailure("They have no assigned account."); + } break; } @@ -1285,7 +1333,9 @@ namespace Server.Factions if (mob.Account is Account acct) { if (acct.GetTag("FactionBanned") == null) + { AddResponse("The account is not already banned from joining factions."); + } else { acct.RemoveTag("FactionBanned"); @@ -1293,7 +1343,9 @@ namespace Server.Factions } } else + { LogFailure("They have no assigned account."); + } break; } diff --git a/Projects/Scripts/Engines/Factions/Core/PlayerState.cs b/Projects/Scripts/Engines/Factions/Core/PlayerState.cs index 2425ba99f..121b8a7fe 100644 --- a/Projects/Scripts/Engines/Factions/Core/PlayerState.cs +++ b/Projects/Scripts/Engines/Factions/Core/PlayerState.cs @@ -260,7 +260,9 @@ namespace Server.Factions public void OnGivenSilverTo(Mobile mob) { - SilverGiven ??= new List(); + if (SilverGiven == null) + SilverGiven = new List(); + SilverGiven.Add(new SilverGivenEntry(mob)); } diff --git a/Projects/Scripts/Engines/Factions/Items/Power Faction Items/PowerFactionItem.cs b/Projects/Scripts/Engines/Factions/Items/Power Faction Items/PowerFactionItem.cs index 1039a98ad..77e3baa4b 100644 --- a/Projects/Scripts/Engines/Factions/Items/Power Faction Items/PowerFactionItem.cs +++ b/Projects/Scripts/Engines/Factions/Items/Power Faction Items/PowerFactionItem.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using Server.Factions; using Server.Mobiles; using Server.Network; @@ -42,7 +41,9 @@ namespace Server if (chance > Utility.Random(100)) { - int weight = _items.Sum(item => item.Weight); + int weight = 0; + + foreach (WeightedItem item in _items) weight += item.Weight; weight = Utility.Random(weight); @@ -176,4 +177,4 @@ namespace Server public Item Construct() => Activator.CreateInstance(Type) as Item; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Factions/Items/Power Faction Items/UrnOfAscension.cs b/Projects/Scripts/Engines/Factions/Items/Power Faction Items/UrnOfAscension.cs index b03886141..08b088de7 100644 --- a/Projects/Scripts/Engines/Factions/Items/Power Faction Items/UrnOfAscension.cs +++ b/Projects/Scripts/Engines/Factions/Items/Power Faction Items/UrnOfAscension.cs @@ -25,9 +25,7 @@ namespace Server bool used = false; - IPooledEnumerable eable = from.GetMobilesInRange(8); - - foreach (Mobile mob in eable) + foreach (Mobile mob in from.GetMobilesInRange(8)) if (mob.Player && !mob.Alive && from.InLOS(mob)) { if (Faction.Find(mob) != ourFaction) continue; @@ -43,8 +41,6 @@ namespace Server } } - eable.Free(); - if (used) { from.LocalOverheadMessage(MessageType.Regular, 2219, false, "The urn shatters as you invoke its power."); diff --git a/Projects/Scripts/Engines/Factions/Items/Traps/BaseFactionTrap.cs b/Projects/Scripts/Engines/Factions/Items/Traps/BaseFactionTrap.cs index f54142a40..898f40b5f 100644 --- a/Projects/Scripts/Engines/Factions/Items/Traps/BaseFactionTrap.cs +++ b/Projects/Scripts/Engines/Factions/Items/Traps/BaseFactionTrap.cs @@ -113,15 +113,10 @@ namespace Server.Factions return 502956; // You cannot place a trap on that. if (Core.ML) - { - IPooledEnumerable eable = m.GetItemsInRange(p, 0); - foreach (Item item in eable) + foreach (Item item in m.GetItemsInRange(p, 0)) if (item is BaseFactionTrap trap && trap.Faction == Faction) return 1075263; // There is already a trap belonging to your faction at this location.; - eable.Free(); - } - switch (AllowedPlacing) { case AllowedPlacing.FactionStronghold: @@ -134,12 +129,22 @@ namespace Server.Factions return 1010355; // This trap can only be placed in your stronghold } case AllowedPlacing.AnyFactionTown: - return Town.FromRegion(Region.Find(p, m)) != null ? 0 : 1010356; + { + Town town = Town.FromRegion(Region.Find(p, m)); + + if (town != null) + return 0; + + return 1010356; // This trap can only be placed in a faction town + } case AllowedPlacing.ControlledFactionTown: { Town town = Town.FromRegion(Region.Find(p, m)); - return town != null && town.Owner == Faction ? 0 : 1010357; + if (town != null && town.Owner == Faction) + return 0; + + return 1010357; // This trap can only be placed in a town your faction controls } } @@ -150,16 +155,17 @@ namespace Server.Factions { base.OnMovement(m, oldLocation); - if (!CheckDecay() && CheckRange(m.Location, oldLocation, 6) && - Faction.Find(m) != null && (m.Skills.DetectHidden.Value - 80.0) / 20.0 > Utility.RandomDouble()) - PrivateOverheadLocalizedMessage(m, 1010154, MessageHue, "", ""); // [Faction Trap] + if (!CheckDecay() && CheckRange(m.Location, oldLocation, 6)) + if (Faction.Find(m) != null && + (m.Skills.DetectHidden.Value - 80.0) / 20.0 > Utility.RandomDouble()) + PrivateOverheadLocalizedMessage(m, 1010154, MessageHue, "", ""); // [Faction Trap] } public void PrivateOverheadLocalizedMessage(Mobile to, int number, int hue, string name, string args) { NetState ns = to?.NetState; - Packets.SendMessageLocalized(ns, Serial, ItemID, MessageType.Regular, hue, 3, number, name, args); + ns?.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, hue, 3, number, name, args)); } public virtual bool CheckDecay() @@ -246,7 +252,10 @@ namespace Server.Factions if (faction == null && mob is BaseFactionGuard guard) faction = guard.Faction; - return faction != null && faction != Faction; + if (faction == null) + return false; + + return faction != Faction; } } } diff --git a/Projects/Scripts/Engines/Factions/Items/Traps/FactionExplosionTrap.cs b/Projects/Scripts/Engines/Factions/Items/Traps/FactionExplosionTrap.cs index 8954ac22d..920e5fa72 100644 --- a/Projects/Scripts/Engines/Factions/Items/Traps/FactionExplosionTrap.cs +++ b/Projects/Scripts/Engines/Factions/Items/Traps/FactionExplosionTrap.cs @@ -23,7 +23,7 @@ namespace Server.Factions public override void DoVisibleEffect() { - Effects.SendLocationEffect(GetWorldLocation(), Map, 0x36BD, 15); + Effects.SendLocationEffect(GetWorldLocation(), Map, 0x36BD, 15, 10); } public override void DoAttackEffect(Mobile m) diff --git a/Projects/Scripts/Engines/Factions/Items/Traps/FactionSawTrap.cs b/Projects/Scripts/Engines/Factions/Items/Traps/FactionSawTrap.cs index acc3780e9..6432656ff 100644 --- a/Projects/Scripts/Engines/Factions/Items/Traps/FactionSawTrap.cs +++ b/Projects/Scripts/Engines/Factions/Items/Traps/FactionSawTrap.cs @@ -8,10 +8,6 @@ namespace Server.Factions { } - public FactionSawTrap(Serial serial) : base(serial) - { - } - public override int LabelNumber => 1041047; // faction saw trap public override int AttackMessage => 1010544; // The blade cuts deep into your skin! @@ -23,7 +19,7 @@ namespace Server.Factions public override void DoVisibleEffect() { - Effects.SendLocationEffect(Location, Map, 0x11AD, 25); + Effects.SendLocationEffect(Location, Map, 0x11AD, 25, 10); } public override void DoAttackEffect(Mobile m) diff --git a/Projects/Scripts/Engines/Factions/Mobiles/Guards/GuardAI.cs b/Projects/Scripts/Engines/Factions/Mobiles/Guards/GuardAI.cs index 2e4d01f6f..e31baae4a 100644 --- a/Projects/Scripts/Engines/Factions/Mobiles/Guards/GuardAI.cs +++ b/Projects/Scripts/Engines/Factions/Mobiles/Guards/GuardAI.cs @@ -313,9 +313,7 @@ namespace Server.Factions actPrio = inactPrio = m_Mobile.GetDistanceToSqrt(comb); } - IPooledEnumerable eable = m_Mobile.GetMobilesInRange(12); - - foreach (Mobile m in eable) + foreach (Mobile m in m_Mobile.GetMobilesInRange(12)) if (m != m_Mobile && CanDispel(m)) { double prio = m_Mobile.GetDistanceToSqrt(m); @@ -333,8 +331,6 @@ namespace Server.Factions } } - eable.Free(); - return active ?? inactive; } diff --git a/Projects/Scripts/Engines/Harvest/Fishing.cs b/Projects/Scripts/Engines/Harvest/Fishing.cs index 33bdbd705..79064a01d 100644 --- a/Projects/Scripts/Engines/Harvest/Fishing.cs +++ b/Projects/Scripts/Engines/Harvest/Fishing.cs @@ -23,7 +23,7 @@ namespace Server.Engines.Harvest new MutateEntry(0.0, 125.0, -2375.0, false, typeof(PrizedFish), typeof(WondrousFish), typeof(TrulyRareFish), typeof(PeculiarFish)), new MutateEntry(0.0, 105.0, -420.0, false, typeof(Boots), typeof(Shoes), typeof(Sandals), typeof(ThighBoots)), - new MutateEntry(0.0, 200.0, -200.0, false, new Type[] { null }) + new MutateEntry(0.0, 200.0, -200.0, false, new Type[1] { null }) }; private static int[] m_WaterTiles = @@ -87,7 +87,7 @@ namespace Server.Engines.Harvest Definitions.Add(fish); } - public static Fishing System => m_System ??= new Fishing(); + public static Fishing System => m_System ?? (m_System = new Fishing()); public HarvestDefinition Definition{ get; } diff --git a/Projects/Scripts/Engines/Harvest/Lumberjacking.cs b/Projects/Scripts/Engines/Harvest/Lumberjacking.cs index e5b5b8ffa..c66eead6c 100644 --- a/Projects/Scripts/Engines/Harvest/Lumberjacking.cs +++ b/Projects/Scripts/Engines/Harvest/Lumberjacking.cs @@ -126,7 +126,7 @@ namespace Server.Engines.Harvest Definitions.Add(lumber); } - public static Lumberjacking System => m_System ??= new Lumberjacking(); + public static Lumberjacking System => m_System ?? (m_System = new Lumberjacking()); public HarvestDefinition Definition{ get; } diff --git a/Projects/Scripts/Engines/Harvest/Mining.cs b/Projects/Scripts/Engines/Harvest/Mining.cs index a4091cceb..043ebbc52 100644 --- a/Projects/Scripts/Engines/Harvest/Mining.cs +++ b/Projects/Scripts/Engines/Harvest/Mining.cs @@ -153,7 +153,7 @@ namespace Server.Engines.Harvest #endregion } - public static Mining System => m_System ??= new Mining(); + public static Mining System => m_System ?? (m_System = new Mining()); public HarvestDefinition OreAndStone{ get; } diff --git a/Projects/Scripts/Engines/Help/HelpGump.cs b/Projects/Scripts/Engines/Help/HelpGump.cs index 305dc5c35..f99b5c308 100644 --- a/Projects/Scripts/Engines/Help/HelpGump.cs +++ b/Projects/Scripts/Engines/Help/HelpGump.cs @@ -1,9 +1,7 @@ using System; -using System.Linq; using Server.Engines.ConPVP; using Server.Factions; using Server.Gumps; -using Server.Menus; using Server.Menus.Questions; using Server.Mobiles; using Server.Multis; @@ -29,7 +27,9 @@ namespace Server.Engines.Help public override void OnResponse(NetState state, int index) { if (index == 0) + { m_From.SendLocalizedMessage(1005306, "", 0x35); // Help request unchanged. + } else if (index == 1) { PageEntry entry = PageQueue.GetEntry(m_From); @@ -141,49 +141,49 @@ namespace Server.Engines.Help AddButton(80, 90, 5540, 5541, 7); AddHtmlLocalized(110, 90, 450, 145, 1062572, true, - true); /*
Another player is harassing me (or Exploiting).

- * VERBAL HARASSMENT
- * Use this option when another player is verbally harassing your character. - * Verbal harassment behaviors include but are not limited to, using bad language, threats etc.. - * Before you submit a complaint be sure you understand what constitutes harassment - * � what is verbal harassment? - - * and that you have followed these steps:
- * 1. You have asked the player to stop and they have continued.
- * 2. You have tried to remove yourself from the situation.
- * 3. You have done nothing to instigate or further encourage the harassment.
- * 4. You have added the player to your ignore list. - * - How do I ignore a player?
- * 5. You have read and understand Origin�s definition of harassment.
- * 6. Your account information is up to date. (Including a current email address)
- * *If these steps have not been taken, GMs may be unable to take action against the offending player.
- * **A chat log will be review by a GM to assess the validity of this complaint. - * Abuse of this system is a violation of the Rules of Conduct.
- * EXPLOITING
- * Use this option to report someone who may be exploiting or cheating. - * � What constitutes an exploit? - */ + true); /*
Another player is harassing me (or Exploiting).

+ * VERBAL HARASSMENT
+ * Use this option when another player is verbally harassing your character. + * Verbal harassment behaviors include but are not limited to, using bad language, threats etc.. + * Before you submit a complaint be sure you understand what constitutes harassment + * � what is verbal harassment? - + * and that you have followed these steps:
+ * 1. You have asked the player to stop and they have continued.
+ * 2. You have tried to remove yourself from the situation.
+ * 3. You have done nothing to instigate or further encourage the harassment.
+ * 4. You have added the player to your ignore list. + * - How do I ignore a player?
+ * 5. You have read and understand Origin�s definition of harassment.
+ * 6. Your account information is up to date. (Including a current email address)
+ * *If these steps have not been taken, GMs may be unable to take action against the offending player.
+ * **A chat log will be review by a GM to assess the validity of this complaint. + * Abuse of this system is a violation of the Rules of Conduct.
+ * EXPLOITING
+ * Use this option to report someone who may be exploiting or cheating. + * � What constitutes an exploit? + */ AddButton(80, 240, 5540, 5541, 8); AddHtmlLocalized(110, 240, 450, 145, 1062573, true, - true); /*
Another player is harassing me using game mechanics.

- *
- * PHYSICAL HARASSMENT
- * Use this option when another player is harassing your character using game mechanics. - * Physical harassment includes but is not limited to luring, Kill Stealing, and any act that causes a players death in Trammel. - * Before you submit a complaint be sure you understand what constitutes harassment - * � what is physical harassment? - * and that you have followed these steps:
- * 1. You have asked the player to stop and they have continued.
- * 2. You have tried to remove yourself from the situation.
- * 3. You have done nothing to instigate or further encourage the harassment.
- * 4. You have added the player to your ignore list. - * - how do I ignore a player?
- * 5. You have read and understand Origin�s definition of harassment.
- * 6. Your account information is up to date. (Including a current email address)
- * *If these steps have not been taken, GMs may be unable to take action against the offending player.
- * **This issue will be reviewed by a GM to assess the validity of this complaint. - * Abuse of this system is a violation of the Rules of Conduct. - */ + true); /*
Another player is harassing me using game mechanics.

+ *
+ * PHYSICAL HARASSMENT
+ * Use this option when another player is harassing your character using game mechanics. + * Physical harassment includes but is not limited to luring, Kill Stealing, and any act that causes a players death in Trammel. + * Before you submit a complaint be sure you understand what constitutes harassment + * � what is physical harassment? + * and that you have followed these steps:
+ * 1. You have asked the player to stop and they have continued.
+ * 2. You have tried to remove yourself from the situation.
+ * 3. You have done nothing to instigate or further encourage the harassment.
+ * 4. You have added the player to your ignore list. + * - how do I ignore a player?
+ * 5. You have read and understand Origin�s definition of harassment.
+ * 6. Your account information is up to date. (Including a current email address)
+ * *If these steps have not been taken, GMs may be unable to take action against the offending player.
+ * **This issue will be reviewed by a GM to assess the validity of this complaint. + * Abuse of this system is a violation of the Rules of Conduct. + */ AddButton(150, 390, 5540, 5541, 0, GumpButtonType.Page, 1); AddHtmlLocalized(180, 390, 335, 40, 1001015); // NO - I meant to ask for help with another matter. @@ -196,8 +196,9 @@ namespace Server.Engines.Help private static void EventSink_HelpRequest(HelpRequestEventArgs e) { - if (e.Mobile.NetState.Gumps.OfType().Any()) - return; + foreach (Gump g in e.Mobile.NetState.Gumps) + if (g is HelpGump) + return; if (!PageQueue.CheckAllowedToPage(e.Mobile)) return; @@ -223,9 +224,9 @@ namespace Server.Engines.Help return false; } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { - Mobile from = sender.Mobile; + Mobile from = state.Mobile; PageType type = (PageType)(-1); diff --git a/Projects/Scripts/Engines/Help/PagePrompt.cs b/Projects/Scripts/Engines/Help/PagePrompt.cs index 612819b36..4ab9e3a79 100644 --- a/Projects/Scripts/Engines/Help/PagePrompt.cs +++ b/Projects/Scripts/Engines/Help/PagePrompt.cs @@ -1,3 +1,5 @@ +using Server.Prompts; + namespace Server.Engines.Help { public class PagePrompt : Prompt @@ -14,11 +16,11 @@ namespace Server.Engines.Help public override void OnResponse(Mobile from, string text) { from.SendLocalizedMessage(501234, "", - 0x35); /* The next available Counselor/Game Master will respond as soon as possible. - * Please check your Journal for messages every few minutes. - */ + 0x35); /* The next available Counselor/Game Master will respond as soon as possible. + * Please check your Journal for messages every few minutes. + */ PageQueue.Enqueue(new PageEntry(from, text, m_Type)); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Help/PagePromptGump.cs b/Projects/Scripts/Engines/Help/PagePromptGump.cs index 7987e690a..982991a35 100644 --- a/Projects/Scripts/Engines/Help/PagePromptGump.cs +++ b/Projects/Scripts/Engines/Help/PagePromptGump.cs @@ -48,9 +48,9 @@ namespace Server.Engines.Help else { m_From.SendLocalizedMessage(501234, "", - 0x35); /* The next available Counselor/Game Master will respond as soon as possible. - * Please check your Journal for messages every few minutes. - */ + 0x35); /* The next available Counselor/Game Master will respond as soon as possible. + * Please check your Journal for messages every few minutes. + */ PageQueue.Enqueue(new PageEntry(m_From, text, m_Type)); } diff --git a/Projects/Scripts/Engines/Help/PageQueue.cs b/Projects/Scripts/Engines/Help/PageQueue.cs index 2062702a7..f719ddea8 100644 --- a/Projects/Scripts/Engines/Help/PageQueue.cs +++ b/Projects/Scripts/Engines/Help/PageQueue.cs @@ -82,6 +82,8 @@ namespace Server.Engines.Help private class InternalTimer : Timer { + private static TimeSpan StatusDelay = TimeSpan.FromMinutes(2.0); + private PageEntry m_Entry; public InternalTimer(PageEntry entry) : base(TimeSpan.FromSeconds(1.0), StatusDelay) => m_Entry = entry; diff --git a/Projects/Scripts/Engines/Help/PageQueueGump.cs b/Projects/Scripts/Engines/Help/PageQueueGump.cs index 124697ca9..a87f3d40e 100644 --- a/Projects/Scripts/Engines/Help/PageQueueGump.cs +++ b/Projects/Scripts/Engines/Help/PageQueueGump.cs @@ -32,7 +32,7 @@ namespace Server.Engines.Help AddHtmlLocalized(34, 28, 65, 24, 3001002, 0xFFFFFF); // Message } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { m_Mobile.SendGump(new PageResponseGump(m_Mobile, m_Name, m_Text)); @@ -100,20 +100,20 @@ namespace Server.Engines.Help } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID >= 1 && info.ButtonID <= m_List.Length) { if (PageQueue.List.IndexOf(m_List[info.ButtonID - 1]) >= 0) { - PageEntryGump g = new PageEntryGump(sender.Mobile, m_List[info.ButtonID - 1]); + PageEntryGump g = new PageEntryGump(state.Mobile, m_List[info.ButtonID - 1]); - g.SendTo(sender); + g.SendTo(state); } else { - sender.Mobile.SendGump(new PageQueueGump()); - sender.Mobile.SendMessage("That page has been removed."); + state.Mobile.SendGump(new PageQueueGump()); + state.Mobile.SendMessage("That page has been removed."); } } } @@ -553,12 +553,12 @@ namespace Server.Engines.Help g.SendTo(state); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID != 0 && PageQueue.List.IndexOf(m_Entry) < 0) { - sender.Mobile.SendGump(new PageQueueGump()); - sender.Mobile.SendMessage("That page has been removed."); + state.Mobile.SendGump(new PageQueueGump()); + state.Mobile.SendMessage("That page has been removed."); return; } @@ -566,18 +566,18 @@ namespace Server.Engines.Help { case 0: // close { - if (m_Entry.Handler != sender.Mobile) + if (m_Entry.Handler != state.Mobile) { PageQueueGump g = new PageQueueGump(); - g.SendTo(sender); + g.SendTo(state); } break; } case 1: // go to sender { - Mobile m = sender.Mobile; + Mobile m = state.Mobile; if (m_Entry.Sender.Deleted) { @@ -594,14 +594,14 @@ namespace Server.Engines.Help m.SendMessage("You have been teleported to that page's sender."); - Resend(sender); + Resend(state); } break; } case 2: // go to handler { - Mobile m = sender.Mobile; + Mobile m = state.Mobile; Mobile h = m_Entry.Handler; if (h != null) @@ -620,20 +620,20 @@ namespace Server.Engines.Help m.MoveToWorld(h.Location, h.Map); m.SendMessage("You have been teleported to that page's handler."); - Resend(sender); + Resend(state); } } else { m.SendMessage("Nobody is handling that page."); - Resend(sender); + Resend(state); } break; } case 3: // go to page location { - Mobile m = sender.Mobile; + Mobile m = state.Mobile; if (m_Entry.PageMap == null || m_Entry.PageMap == Map.Internal) { @@ -644,9 +644,9 @@ namespace Server.Engines.Help // m_Entry.AddResponse(state.Mobile, "[Go PageLoc]"); m.MoveToWorld(m_Entry.PageLocation, m_Entry.PageMap); - sender.Mobile.SendMessage("You have been teleported to the original page location."); + state.Mobile.SendMessage("You have been teleported to the original page location."); - Resend(sender); + Resend(state); } break; @@ -656,14 +656,16 @@ namespace Server.Engines.Help if (m_Entry.Handler == null) { // m_Entry.AddResponse(state.Mobile, "[Handling]"); - m_Entry.Handler = sender.Mobile; + m_Entry.Handler = state.Mobile; - sender.Mobile.SendMessage("You are now handling the page."); + state.Mobile.SendMessage("You are now handling the page."); } else - sender.Mobile.SendMessage("Someone is already handling that page."); + { + state.Mobile.SendMessage("Someone is already handling that page."); + } - Resend(sender); + Resend(state); break; } @@ -674,57 +676,59 @@ namespace Server.Engines.Help // m_Entry.AddResponse(state.Mobile, "[Deleting]"); PageQueue.Remove(m_Entry); - sender.Mobile.SendMessage("You delete the page."); + state.Mobile.SendMessage("You delete the page."); PageQueueGump g = new PageQueueGump(); - g.SendTo(sender); + g.SendTo(state); } else { - sender.Mobile.SendMessage("Someone is handling that page, it can not be deleted."); + state.Mobile.SendMessage("Someone is handling that page, it can not be deleted."); - Resend(sender); + Resend(state); } break; } case 6: // abandon page { - if (m_Entry.Handler == sender.Mobile) + if (m_Entry.Handler == state.Mobile) { // m_Entry.AddResponse(state.Mobile, "[Abandoning]"); - sender.Mobile.SendMessage("You abandon the page."); + state.Mobile.SendMessage("You abandon the page."); m_Entry.Handler = null; } else - sender.Mobile.SendMessage("You are not handling that page."); + { + state.Mobile.SendMessage("You are not handling that page."); + } - Resend(sender); + Resend(state); break; } case 7: // page handled { - if (m_Entry.Handler == sender.Mobile) + if (m_Entry.Handler == state.Mobile) { // m_Entry.AddResponse(state.Mobile, "[Handled]"); PageQueue.Remove(m_Entry); m_Entry.Handler = null; - sender.Mobile.SendMessage("You mark the page as handled, and remove it from the queue."); + state.Mobile.SendMessage("You mark the page as handled, and remove it from the queue."); PageQueueGump g = new PageQueueGump(); - g.SendTo(sender); + g.SendTo(state); } else { - sender.Mobile.SendMessage("You are not handling that page."); + state.Mobile.SendMessage("You are not handling that page."); - Resend(sender); + Resend(state); } break; @@ -739,20 +743,20 @@ namespace Server.Engines.Help //m_Entry.Sender.SendMessage( 0x482, "{0} tells you:", state.Mobile.Name ); //m_Entry.Sender.SendMessage( 0x482, text.Text ); - Resend(sender); + Resend(state); break; } case 9: // predef overview { - Resend(sender); - sender.Mobile.SendGump(new PredefGump(sender.Mobile, null)); + Resend(state); + state.Mobile.SendGump(new PredefGump(state.Mobile, null)); break; } case 10: // View Speech Log { - Resend(sender); + Resend(state); if (m_Entry.SpeechLog != null) state.Mobile.SendGump(new SpeechLogGump(m_Entry.Sender, m_Entry.SpeechLog)); @@ -768,7 +772,7 @@ namespace Server.Engines.Help m_Entry.Sender.SendGump(new MessageSentGump(m_Entry.Sender, state.Mobile.Name, preresp[index].Message)); - Resend(sender); + Resend(state); break; } diff --git a/Projects/Scripts/Engines/Help/SpeechLogGump.cs b/Projects/Scripts/Engines/Help/SpeechLogGump.cs index 1afb7aea3..7996e18f7 100644 --- a/Projects/Scripts/Engines/Help/SpeechLogGump.cs +++ b/Projects/Scripts/Engines/Help/SpeechLogGump.cs @@ -46,7 +46,9 @@ namespace Server.Engines.Help string sLog; if (page < 0 || page > lastPage) + { sLog = ""; + } else { int max = log.Count - (lastPage - page) * MaxEntriesPerPage; diff --git a/Projects/Scripts/Engines/Help/StuckMenu.cs b/Projects/Scripts/Engines/Help/StuckMenu.cs index 313b82c73..9c6519417 100644 --- a/Projects/Scripts/Engines/Help/StuckMenu.cs +++ b/Projects/Scripts/Engines/Help/StuckMenu.cs @@ -14,9 +14,9 @@ namespace Server.Menus.Questions Locations = locations; } - public int Name { get; } + public int Name{ get; } - public Point3D[] Locations { get; } + public Point3D[] Locations{ get; } } public class StuckMenu : Gump @@ -162,7 +162,7 @@ namespace Server.Menus.Questions m_Mobile.Frozen = false; } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { StopClose(); diff --git a/Projects/Scripts/Engines/Khaldun/PuzzleChest.cs b/Projects/Scripts/Engines/Khaldun/PuzzleChest.cs index 6263a9b4d..271a06410 100644 --- a/Projects/Scripts/Engines/Khaldun/PuzzleChest.cs +++ b/Projects/Scripts/Engines/Khaldun/PuzzleChest.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Gumps; using Server.Network; @@ -48,9 +47,22 @@ namespace Server.Items int version = reader.ReadEncodedInt(); int length = reader.ReadEncodedInt(); + for (int i = 0;; i++) + if (i < length) + { + PuzzleChestCylinder cylinder = (PuzzleChestCylinder)reader.ReadInt(); - for (int i = 0; i < Cylinders.Length; i++) - Cylinders[i] = i < length ? (PuzzleChestCylinder)reader.ReadInt() : RandomCylinder(); + if (i < Cylinders.Length) + Cylinders[i] = cylinder; + } + else if (i < Cylinders.Length) + { + Cylinders[i] = RandomCylinder(); + } + else + { + break; + } } public PuzzleChestCylinder[] Cylinders{ get; } = new PuzzleChestCylinder[Length]; @@ -284,7 +296,7 @@ namespace Server.Items { case 0: { - Effects.SendLocationEffect(to, to.Map, 0x113A, 20); + Effects.SendLocationEffect(to, to.Map, 0x113A, 20, 10); to.PlaySound(0x231); to.LocalOverheadMessage(MessageType.Regular, 0x44, 1010523); // A toxic vapor envelops thee. @@ -314,7 +326,7 @@ namespace Server.Items } default: { - to.BoltEffect(); + to.BoltEffect(0); to.LocalOverheadMessage(MessageType.Regular, 0xDA, 1010526); // Lightning arcs through thy body. AOS.Damage(to, to, Utility.RandomMinMax(10, 40), 0, 0, 0, 0, 100); @@ -397,8 +409,12 @@ namespace Server.Items for (int i = 0; i < 2; i++) { - Item item = Core.AOS ? - Loot.RandomArmorOrShieldOrWeaponOrJewelry() : Loot.RandomArmorOrShieldOrWeapon(); + Item item; + + if (Core.AOS) + item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(); + else + item = Loot.RandomArmorOrShieldOrWeapon(); if (item is BaseWeapon weapon) { @@ -459,7 +475,13 @@ namespace Server.Items public void CleanupGuesses() { - foreach (Mobile m in from kvp in m_Guesses where DateTime.UtcNow - kvp.Value.When > CleanupTime select kvp.Key) + List toDelete = new List(); + + foreach (KeyValuePair kvp in m_Guesses) + if (DateTime.UtcNow - kvp.Value.When > CleanupTime) + toDelete.Add(kvp.Key); + + foreach (Mobile m in toDelete) m_Guesses.Remove(m); } @@ -477,10 +499,10 @@ namespace Server.Items for (int i = 0; i < Hints.Length; i++) writer.Write((int)Hints[i]); writer.WriteEncodedInt(m_Guesses.Count); - foreach (var (key, value) in m_Guesses) + foreach (KeyValuePair kvp in m_Guesses) { - writer.Write(key); - value.Serialize(writer); + writer.Write(kvp.Key); + kvp.Value.Serialize(writer); } } @@ -658,7 +680,9 @@ namespace Server.Items } if (info.ButtonID == 1) + { m_Chest.SubmitSolution(m_From, m_Solution); + } else { if (info.Switches.Length == 0) diff --git a/Projects/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs b/Projects/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs index 9ae4c9238..4292a91dd 100644 --- a/Projects/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs +++ b/Projects/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using Server.Buffers; using Server.Gumps; using Server.Items; using Server.Mobiles; @@ -89,7 +87,7 @@ namespace Server.Engines.MLQuests.Gumps CloseCurrent(ns); m_Pending[ns] = new RaceChangeState(owner, ns, targetRace); - SendRaceChanger(ns, from.Female, targetRace); + ns.Send(new RaceChanger(from.Female, targetRace)); } private static void CloseCurrent(NetState ns) @@ -100,7 +98,7 @@ namespace Server.Engines.MLQuests.Gumps m_Pending.Remove(ns); } - SendCloseRaceChanger(ns); + ns.Send(CloseRaceChanger.Instance); } private static void Timeout(NetState ns) @@ -108,21 +106,30 @@ namespace Server.Engines.MLQuests.Gumps if (IsPending(ns)) { m_Pending.Remove(ns); - SendCloseRaceChanger(ns); + ns.Send(CloseRaceChanger.Instance); } } public static bool IsWearingEquipment(Mobile from) { - return from.Items.Select(item => item.Layer switch + foreach (Item item in from.Items) + switch (item.Layer) { - Layer.Hair => false, - Layer.FacialHair => false, - Layer.Backpack => false, - Layer.Mount => false, - Layer.Bank => false, - _ => true - }).FirstOrDefault(); + case Layer.Hair: + case Layer.FacialHair: + case Layer.Backpack: + case Layer.Mount: + case Layer.Bank: + { + continue; // ignore + } + default: + { + return true; + } + } + + return false; } private static bool CanChange(PlayerMobile from, Race targetRace) @@ -231,34 +238,38 @@ namespace Server.Engines.MLQuests.Gumps m_Timeout = Timer.DelayCall(m_TimeoutDelay, Timeout, ns); } } + } - public static void SendRaceChanger(NetState ns, bool female, Race targetRace) + public sealed class RaceChanger : Packet + { + public RaceChanger(bool female, Race targetRace) + : base(0xBF) { - if (ns == null) - return; + EnsureCapacity(7); - SpanWriter writer = new SpanWriter(stackalloc byte[7]); - writer.Write((byte)0xBF); // Packet ID - writer.Write((ushort)0x07); // Dynamic Length - - writer.Write((short)0x2A); - writer.Write(female); - writer.Write((byte)(targetRace.RaceID + 1)); - - ns.Send(writer.Span); - } - - private static void SendCloseRaceChanger(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0xBF, // Packet ID - 0x07, // Dynamic Length - 0x00, - 0xFF - }); + m_Stream.Write((short)0x2A); + m_Stream.Write((byte)(female ? 1 : 0)); + m_Stream.Write((byte)(targetRace.RaceID + 1)); } } + + public sealed class CloseRaceChanger : Packet + { + public static readonly Packet Instance = SetStatic(new CloseRaceChanger()); + + private CloseRaceChanger() + : base(0xBF) + { + EnsureCapacity(7); + + m_Stream.Write((short)0x2A); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0xFF); + } + } + + #region For testing + public class RaceChangeDeed : Item, IRaceChanger { [Constructible] @@ -319,4 +330,6 @@ namespace Server.Engines.MLQuests.Gumps int version = reader.ReadInt(); } } + + #endregion } diff --git a/Projects/Scripts/Engines/MLQuests/MLQuest.cs b/Projects/Scripts/Engines/MLQuests/MLQuest.cs index 599f6f86a..4231451b5 100644 --- a/Projects/Scripts/Engines/MLQuests/MLQuest.cs +++ b/Projects/Scripts/Engines/MLQuests/MLQuest.cs @@ -86,7 +86,14 @@ namespace Server.Engines.MLQuests public virtual int Version => 0; - public bool HasObjective() where T : BaseObjective => Objectives.OfType().Any(); + public bool HasObjective() where T : BaseObjective + { + foreach (BaseObjective obj in Objectives) + if (obj is T) + return true; + + return false; + } public virtual void Generate() { @@ -144,7 +151,11 @@ namespace Server.Engines.MLQuests } } - return Objectives.All(obj => obj.CanOffer(quester, pm, message)); + foreach (BaseObjective obj in Objectives) + if (!obj.CanOffer(quester, pm, message)) + return false; + + return true; } public virtual void SendOffer(IQuestGiver quester, PlayerMobile pm) diff --git a/Projects/Scripts/Engines/MLQuests/MLQuestContext.cs b/Projects/Scripts/Engines/MLQuests/MLQuestContext.cs index 17b886604..052f04544 100644 --- a/Projects/Scripts/Engines/MLQuests/MLQuestContext.cs +++ b/Projects/Scripts/Engines/MLQuests/MLQuestContext.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Mobiles; namespace Server.Engines.MLQuests @@ -114,7 +113,14 @@ namespace Server.Engines.MLQuests return quest != null && HasDoneQuest(quest); } - public bool HasDoneQuest(MLQuest quest) => m_DoneQuests.Any(info => info.m_Quest == quest); + public bool HasDoneQuest(MLQuest quest) + { + foreach (MLDoneQuestInfo info in m_DoneQuests) + if (info.m_Quest == quest) + return true; + + return false; + } public bool HasDoneQuest(MLQuest quest, out DateTime nextAvailable) { @@ -174,10 +180,20 @@ namespace Server.Engines.MLQuests { MLQuest quest = MLQuestSystem.FindQuest(questType); - return quest == null ? null : FindInstance(quest); + if (quest == null) + return null; + + return FindInstance(quest); } - public MLQuestInstance FindInstance(MLQuest quest) => QuestInstances.FirstOrDefault(instance => instance.Quest == quest); + public MLQuestInstance FindInstance(MLQuest quest) + { + foreach (MLQuestInstance instance in QuestInstances) + if (instance.Quest == quest) + return instance; + + return null; + } public bool IsDoingQuest(Type questType) { diff --git a/Projects/Scripts/Engines/MLQuests/MLQuestEntry.cs b/Projects/Scripts/Engines/MLQuests/MLQuestEntry.cs index 095802ca8..84e28db5a 100644 --- a/Projects/Scripts/Engines/MLQuests/MLQuestEntry.cs +++ b/Projects/Scripts/Engines/MLQuests/MLQuestEntry.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Engines.MLQuests.Gumps; using Server.Engines.MLQuests.Objectives; using Server.Engines.MLQuests.Rewards; @@ -37,7 +36,16 @@ namespace Server.Engines.MLQuests Objectives = new BaseObjectiveInstance[quest.Objectives.Count]; - bool timed = quest.Objectives.Aggregate(false, (current, t) => current | t.CreateInstance(this).IsTimed); + BaseObjectiveInstance obj; + bool timed = false; + + for (int i = 0; i < quest.Objectives.Count; ++i) + { + Objectives[i] = obj = quest.Objectives[i].CreateInstance(this); + + if (obj.IsTimed) + timed = true; + } Register(); @@ -105,8 +113,14 @@ namespace Server.Engines.MLQuests Removed = true; } - public bool AllowsQuestItem(Item item, Type type) => - Objectives.Any(objective => !objective.Expired && objective.AllowsQuestItem(item, type)); + public bool AllowsQuestItem(Item item, Type type) + { + foreach (BaseObjectiveInstance objective in Objectives) + if (!objective.Expired && objective.AllowsQuestItem(item, type)) + return true; + + return false; + } public bool IsCompleted() { @@ -238,11 +252,13 @@ namespace Server.Engines.MLQuests if (Quest.ObjectiveType == ObjectiveType.All) { // TODO: 1115877 - You no longer have the required items to complete this quest. - if (Objectives.Any(objective => !objective.IsCompleted())) - return; + foreach (BaseObjectiveInstance objective in Objectives) + if (!objective.IsCompleted()) + return; - if (Objectives.Any(objective => !objective.OnBeforeClaimReward())) - return; + foreach (BaseObjectiveInstance objective in Objectives) + if (!objective.OnBeforeClaimReward()) + return; foreach (BaseObjectiveInstance objective in Objectives) objective.OnClaimReward(); @@ -298,7 +314,14 @@ namespace Server.Engines.MLQuests { // On OSI a more naive method of checking is used. // For containers, only the actual container item counts. - bool canFit = rewards.All(rewardItem => Player.AddToBackpack(rewardItem)); + bool canFit = true; + + foreach (Item rewardItem in rewards) + if (!Player.AddToBackpack(rewardItem)) + { + canFit = false; + break; + } if (!canFit) { diff --git a/Projects/Scripts/Engines/MLQuests/MLQuestPersistence.cs b/Projects/Scripts/Engines/MLQuests/MLQuestPersistence.cs index 66c861788..87f3cfa5c 100644 --- a/Projects/Scripts/Engines/MLQuests/MLQuestPersistence.cs +++ b/Projects/Scripts/Engines/MLQuests/MLQuestPersistence.cs @@ -14,7 +14,8 @@ namespace Server.Engines.MLQuests public static void EnsureExistence() { - m_Instance ??= new MLQuestPersistence(); + if (m_Instance == null) + m_Instance = new MLQuestPersistence(); } public override void Serialize(GenericWriter writer) @@ -54,4 +55,4 @@ namespace Server.Engines.MLQuests MLQuest.Deserialize(reader, version); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/MLQuests/MLQuestSystem.cs b/Projects/Scripts/Engines/MLQuests/MLQuestSystem.cs index c65dd5640..32ec0c488 100644 --- a/Projects/Scripts/Engines/MLQuests/MLQuestSystem.cs +++ b/Projects/Scripts/Engines/MLQuests/MLQuestSystem.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using Server.Commands; using Server.Commands.Generic; using Server.Engines.MLQuests.Gumps; @@ -214,7 +213,7 @@ namespace Server.Engines.MLQuests return; } - bool enable = e.Length != 1 || e.GetBoolean(0); + bool enable = e.Length == 1 ? e.GetBoolean(0) : true; foreach (MLQuest quest in Quests.Values) quest.SaveEnabled = enable; @@ -330,8 +329,17 @@ namespace Server.Engines.MLQuests } } - public static bool CanMarkQuestItem(PlayerMobile pm, Item item, Type type) => - GetContext(pm)?.QuestInstances.Any(quest => !quest.ClaimReward && quest.AllowsQuestItem(item, type)) == true; + public static bool CanMarkQuestItem(PlayerMobile pm, Item item, Type type) + { + MLQuestContext context = GetContext(pm); + + if (context != null) + foreach (MLQuestInstance quest in context.QuestInstances) + if (!quest.ClaimReward && quest.AllowsQuestItem(item, type)) + return true; + + return false; + } private static void OnMarkQuestItem(PlayerMobile pm, Item item, Type type) { @@ -555,7 +563,8 @@ namespace Server.Engines.MLQuests * Save first quest that reaches the CanOffer call. * If no quests are valid at all, return this quest for displaying the CanOffer error message. */ - fallback ??= quest; + if (fallback == null) + fallback = quest; if (quest.CanOffer(quester, pm, context, false)) m_EligiblePool.Add(quest); @@ -634,7 +643,7 @@ namespace Server.Engines.MLQuests if (questType == null) return null; // no longer a type - return questType == null ? null : FindQuest(questType); + return FindQuest(questType); } public static MLQuest FindQuest(Type questType) diff --git a/Projects/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs b/Projects/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs index 303bed91c..0ba0dff6d 100644 --- a/Projects/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs +++ b/Projects/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Engines.MLQuests.Definitions; using Server.Engines.MLQuests.Gumps; using Server.Items; @@ -136,7 +135,20 @@ namespace Server.Engines.MLQuests.Mobiles { MLQuestContext context = MLQuestSystem.GetContext(pm); - return context == null ? 0 : Needed.Select(MLQuestSystem.FindQuest).Count(quest => quest == null || context.HasDoneQuest(quest)); + if (context == null) + return 0; + + int result = 0; + + foreach (Type type in Needed) + { + MLQuest quest = MLQuestSystem.FindQuest(type); + + if (quest == null || context.HasDoneQuest(quest)) + ++result; + } + + return result; } public virtual void OnComplete(PlayerMobile pm) diff --git a/Projects/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs b/Projects/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs index b92f56b41..ac70f3b68 100644 --- a/Projects/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs +++ b/Projects/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs @@ -42,7 +42,9 @@ namespace Server.Engines.MLQuests.Mobiles public override bool GetGender() => false; - public override bool CheckMorph() => true; + public override void CheckMorph() + { + } public override void InitOutfit() { @@ -51,9 +53,22 @@ namespace Server.Engines.MLQuests.Mobiles HairHue = FacialHairHue = 0x8A7; AddItem(new Sandals()); - AddItem(new Cloak{ ItemID = 0x26AD, Hue = 0x455}); - AddItem(new Robe {ItemID = 0x26AE, Hue = 0x4AB}); - AddItem(new Backpack {Movable = false}); + + Item item; + + item = new Cloak(); + item.ItemID = 0x26AD; + item.Hue = 0x455; + AddItem(item); + + item = new Robe(); + item.ItemID = 0x26AE; + item.Hue = 0x4AB; + AddItem(item); + + item = new Backpack(); + item.Movable = false; + AddItem(item); } public override void OnDoubleClick(Mobile from) @@ -77,23 +92,32 @@ namespace Server.Engines.MLQuests.Mobiles if (m_NextShout <= DateTime.UtcNow) { - IPooledEnumerable eable = GetClientsInRange(12); - foreach (NetState state in eable) + Packet shoutPacket = null; + + foreach (NetState state in GetClientsInRange(12)) { Mobile m = state.Mobile; if (m.CanSee(this) && m.InLOS(this) && m.CanBeginAction(this)) - Packets.SendMessageLocalized(state, Serial, Body, MessageType.Regular, 946, 3, - 1078099, Name); // Double Click On Me For Help! + { + if (shoutPacket == null) + shoutPacket = Packet.Acquire(new MessageLocalized(Serial, Body, MessageType.Regular, 946, 3, + 1078099, Name, "")); // Double Click On Me For Help! + + state.Send(shoutPacket); + } } - eable.Free(); + Packet.Release(shoutPacket); m_NextShout = DateTime.UtcNow + m_ShoutDelay; } } - private void EndLock(Mobile m) => m.EndAction(this); + private void EndLock(Mobile m) + { + m.EndAction(this); + } public override void Serialize(GenericWriter writer) { @@ -111,4 +135,4 @@ namespace Server.Engines.MLQuests.Mobiles Frozen = true; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs b/Projects/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs index d21af44a0..a81783ed4 100644 --- a/Projects/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs +++ b/Projects/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Server.Gumps; using Server.Misc; using Server.Mobiles; @@ -21,13 +20,14 @@ namespace Server.Engines.MLQuests.Objectives MLQuestContext context = MLQuestSystem.GetContext(pm); if (context != null) - if (context.QuestInstances.Any(instance => instance.Quest.IsEscort)) - { - if (message) - MLQuestSystem.Tell(quester, pm, 500896); // I see you already have an escort. + foreach (MLQuestInstance instance in context.QuestInstances) + if (instance.Quest.IsEscort) + { + if (message) + MLQuestSystem.Tell(quester, pm, 500896); // I see you already have an escort. - return false; - } + return false; + } DateTime nextEscort = pm.LastEscortTime + BaseEscortable.EscortDelay; diff --git a/Projects/Scripts/Engines/MLQuests/Objectives/KillObjective.cs b/Projects/Scripts/Engines/MLQuests/Objectives/KillObjective.cs index 0f35da79a..89f47f269 100644 --- a/Projects/Scripts/Engines/MLQuests/Objectives/KillObjective.cs +++ b/Projects/Scripts/Engines/MLQuests/Objectives/KillObjective.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Server.Gumps; using Server.Mobiles; @@ -92,21 +91,22 @@ namespace Server.Engines.MLQuests.Objectives { int desired = Objective.DesiredAmount; - if (Objective.AcceptedTypes.Any(acceptedType => acceptedType.IsAssignableFrom(type))) - { - if (Objective.Area?.Contains(mob) == false) - return false; + foreach (Type acceptedType in Objective.AcceptedTypes) + if (acceptedType.IsAssignableFrom(type)) + { + if (Objective.Area?.Contains(mob) == false) + return false; - PlayerMobile pm = Instance.Player; + PlayerMobile pm = Instance.Player; - if (++Slain >= desired) - pm.SendLocalizedMessage(1075050); // You have killed all the required quest creatures of this type. - else - pm.SendLocalizedMessage(1075051, - (desired - Slain).ToString()); // You have killed a quest creature. ~1_val~ more left. + if (++Slain >= desired) + pm.SendLocalizedMessage(1075050); // You have killed all the required quest creatures of this type. + else + pm.SendLocalizedMessage(1075051, + (desired - Slain).ToString()); // You have killed a quest creature. ~1_val~ more left. - return true; - } + return true; + } return false; } diff --git a/Projects/Scripts/Engines/MLQuests/QuestArea.cs b/Projects/Scripts/Engines/MLQuests/QuestArea.cs index 74f2c3ef9..92e2986a4 100644 --- a/Projects/Scripts/Engines/MLQuests/QuestArea.cs +++ b/Projects/Scripts/Engines/MLQuests/QuestArea.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; namespace Server.Engines.MLQuests { @@ -35,7 +34,14 @@ namespace Server.Engines.MLQuests // Debug method public void Validate() { - bool found = Region.Regions.Any(r => r.Name == RegionName && (ForceMap == null || r.Map == ForceMap)); + bool found = false; + + foreach (Region r in Region.Regions) + if (r.Name == RegionName && (ForceMap == null || r.Map == ForceMap)) + { + found = true; + break; + } if (!found) Console.WriteLine("Warning: QuestArea region '{0}' does not exist (ForceMap = {1})", RegionName, diff --git a/Projects/Scripts/Engines/MyRunUO/LayerComparer.cs b/Projects/Scripts/Engines/MyRunUO/LayerComparer.cs deleted file mode 100644 index cf00d5b67..000000000 --- a/Projects/Scripts/Engines/MyRunUO/LayerComparer.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Collections.Generic; - -namespace Server.Engines.MyRunUO -{ - public class LayerComparer : IComparer - { - private static Layer PlateArms = (Layer)255; - private static Layer ChainTunic = (Layer)254; - private static Layer LeatherShorts = (Layer)253; - - private static Layer[] m_DesiredLayerOrder = - { - Layer.Cloak, - Layer.Bracelet, - Layer.Ring, - Layer.Shirt, - Layer.Pants, - Layer.InnerLegs, - Layer.Shoes, - LeatherShorts, - Layer.Arms, - Layer.InnerTorso, - LeatherShorts, - PlateArms, - Layer.MiddleTorso, - Layer.OuterLegs, - Layer.Neck, - Layer.Waist, - Layer.Gloves, - Layer.OuterTorso, - Layer.OneHanded, - Layer.TwoHanded, - Layer.FacialHair, - Layer.Hair, - Layer.Helm, - Layer.Talisman - }; - - public static readonly IComparer Instance = new LayerComparer(); - - static LayerComparer() - { - TranslationTable = new int[256]; - - for (int i = 0; i < m_DesiredLayerOrder.Length; ++i) - TranslationTable[(int)m_DesiredLayerOrder[i]] = m_DesiredLayerOrder.Length - i; - } - - public static int[] TranslationTable{ get; } - - public int Compare(Item a, Item b) - { - if (a == null) - return b == null ? 0 : 1; - - if (b == null) - return -1; - - Layer aLayer = Fix(a.ItemID, a.Layer); - Layer bLayer = Fix(b.ItemID, b.Layer); - - return TranslationTable[(int)bLayer] - TranslationTable[(int)aLayer]; - } - - public static bool IsValid(Item item) => TranslationTable[(int)item.Layer] > 0; - - public Layer Fix(int itemID, Layer oldLayer) - { - if (itemID == 0x1410 || itemID == 0x1417) // platemail arms - return PlateArms; - - if (itemID == 0x13BF || itemID == 0x13C4) // chainmail tunic - return ChainTunic; - - if (itemID == 0x1C08 || itemID == 0x1C09 || itemID == 0x1C00 || itemID == 0x1C01) // leather skirt/shorts - return LeatherShorts; - - return oldLayer; - } - } -} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Party/Packets.cs b/Projects/Scripts/Engines/Party/Packets.cs index cabd86171..e417d0b3c 100644 --- a/Projects/Scripts/Engines/Party/Packets.cs +++ b/Projects/Scripts/Engines/Party/Packets.cs @@ -1,175 +1,77 @@ -using Server.Buffers; using Server.Network; namespace Server.Engines.PartySystem { - public static class PartyPackets + public sealed class PartyEmptyList : Packet { - public static void SendPartyEmptyList(NetState ns, Mobile m) + public PartyEmptyList(Mobile m) : base(0xBF) { - if (ns == null) - return; + EnsureCapacity(7); - SpanWriter writer = new SpanWriter(stackalloc byte[11]); - writer.Write((byte)0xBF); // Packet ID - writer.Write((short)11); // Dynamic Length - - writer.Write((short)0x06); - writer.Write((byte)0x02); - writer.Position++; // Writer(0); // Number of members - writer.Write(m.Serial); - - ns.Send(writer.Span); - } - - public static void SendPartyMemberList(NetState ns, Party p) - { - if (ns == null) - return; - - ushort length = (ushort)(7 + p.Count * 4); - - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xBF); // Packet ID - writer.Write(length); // Dynamic Length - - writer.Write((short)0x06); - writer.Write((byte)0x01); - writer.Write((byte)p.Count); - - for (int i = 0; i < p.Count; ++i) - writer.Write(p[i].Mobile.Serial); - - ns.Send(writer.Span); - } - - public static void SendPartyRemoveMember(NetState ns, Mobile removed, Party p) - { - if (ns == null) - return; - - ushort length = (ushort)(11 + p.Count * 4); - - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xBF); // Packet ID - writer.Write(length); // Dynamic Length - - writer.Write((short)0x06); - writer.Write((byte)0x02); - writer.Write((byte)p.Count); - writer.Write(removed.Serial); - - for (int i = 0; i < p.Count; ++i) - writer.Write(p[i].Mobile.Serial); - - ns.Send(writer.Span); - } - - public static void SendPartyRemoveMemberToAll(Mobile removed, Party p) - { - for (int i = 0; i < p.Members.Count; i++) - SendPartyRemoveMember(p[i].Mobile.NetState, removed, p); - } - - public static void SendPartyTextMessage(NetState ns, bool toAll, Mobile from, string text) - { - if (ns == null) - return; - - ushort length = (ushort)(12 + text.Length * 2); - - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xBF); // Packet ID - writer.Write(length); // Dynamic Length - - writer.Write((short)0x06); - writer.Write((byte)(toAll ? 0x04 : 0x03)); - writer.Write(from.Serial); - - writer.WriteBigUniNull(text); - - ns.Send(writer.Span); - } - - public static void SendPartyTextMessageToAll(Party p, bool toAll, Mobile from, string text) - { - for (int i = 0; i < p.Members.Count; ++i) - SendPartyTextMessage(p.Members[i].Mobile.NetState, toAll, from, text); - } - - public static void SendPartyInvitation(NetState ns, Mobile leader) - { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[10]); - writer.Write((byte)0xBF); // Packet ID - writer.Write((short)10); // Dynamic Length - - writer.Write((short)0x06); - writer.Write((byte)0x07); - writer.Write(leader.Serial); - - ns.Send(writer.Span); - } - - public static void SendPartyMessageLocalizedToAll(Party p, Serial serial, int graphic, MessageType type, int hue, int font, int number, string name = "", - string args = "") - { - for (int i = 0; i < p.Members.Count; ++i) - Packets.SendMessageLocalized(p.Members[i].Mobile.NetState, serial, graphic, type, hue, font, number, name, args); - - for (int i = 0; i < p.Listeners.Count; ++i) - { - Mobile mob = p.Listeners[i]; - - if (mob.Party != p) - Packets.SendMessageLocalized(mob.NetState, serial, graphic, type, hue, font, number, name, args); - } - } - - public static void SendPartyMessageLocalizedAffixToAll(Party p, Serial serial, int graphic, MessageType type, int hue, int font, int number, - string name = "", AffixType affixType = AffixType.System, string affix = "", string args = "") - { - for (int i = 0; i < p.Members.Count; ++i) - Packets.SendMessageLocalizedAffix(p.Members[i].Mobile.NetState, serial, graphic, type, hue, font, number, name, affixType, affix, args); - - for (int i = 0; i < p.Listeners.Count; ++i) - { - Mobile mob = p.Listeners[i]; - - if (mob.Party != p) - Packets.SendMessageLocalizedAffix(mob.NetState, serial, graphic, type, hue, font, number, name, affixType, affix, args); - } - } - - public static void SendPartyUnicodeMessageToAll(Party p, Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name, - string text) - { - for (int i = 0; i < p.Members.Count; ++i) - Packets.SendUnicodeMessage(p.Members[i].Mobile.NetState, serial, graphic, type, hue, font, lang, name, text); - - for (int i = 0; i < p.Listeners.Count; ++i) - { - Mobile mob = p.Listeners[i]; - - if (mob.Party != p) - Packets.SendUnicodeMessage(p.Members[i].Mobile.NetState, serial, graphic, type, hue, font, lang, name, text); - } - } - - public static void SendPartyAsciiMessageToAll(Party p, Serial serial, int graphic, MessageType type, int hue, int font, string name, string text) - { - for (int i = 0; i < p.Members.Count; ++i) - Packets.SendAsciiMessage(p.Members[i].Mobile.NetState, serial, graphic, type, hue, font, name, text); - - for (int i = 0; i < p.Listeners.Count; ++i) - { - Mobile mob = p.Listeners[i]; - - if (mob.Party != p) - Packets.SendAsciiMessage(p.Members[i].Mobile.NetState, serial, graphic, type, hue, font, name, text); - } + m_Stream.Write((short)0x0006); + m_Stream.Write((byte)0x02); + m_Stream.Write((byte)0); + m_Stream.Write(m.Serial); } } -} + + public sealed class PartyMemberList : Packet + { + public PartyMemberList(Party p) : base(0xBF) + { + EnsureCapacity(7 + p.Count * 4); + + m_Stream.Write((short)0x0006); + m_Stream.Write((byte)0x01); + m_Stream.Write((byte)p.Count); + + for (int i = 0; i < p.Count; ++i) + m_Stream.Write(p[i].Mobile.Serial); + } + } + + public sealed class PartyRemoveMember : Packet + { + public PartyRemoveMember(Mobile removed, Party p) : base(0xBF) + { + EnsureCapacity(11 + p.Count * 4); + + m_Stream.Write((short)0x0006); + m_Stream.Write((byte)0x02); + m_Stream.Write((byte)p.Count); + + m_Stream.Write(removed.Serial); + + for (int i = 0; i < p.Count; ++i) + m_Stream.Write(p[i].Mobile.Serial); + } + } + + public sealed class PartyTextMessage : Packet + { + public PartyTextMessage(bool toAll, Mobile from, string text) : base(0xBF) + { + if (text == null) + text = ""; + + EnsureCapacity(12 + text.Length * 2); + + m_Stream.Write((short)0x0006); + m_Stream.Write((byte)(toAll ? 0x04 : 0x03)); + m_Stream.Write(from.Serial); + m_Stream.WriteBigUniNull(text); + } + } + + public sealed class PartyInvitation : Packet + { + public PartyInvitation(Mobile leader) : base(0xBF) + { + EnsureCapacity(10); + + m_Stream.Write((short)0x0006); + m_Stream.Write((byte)0x07); + m_Stream.Write(leader.Serial); + } + } +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Party/Party.cs b/Projects/Scripts/Engines/Party/Party.cs index 037376b12..015ccbea4 100644 --- a/Projects/Scripts/Engines/Party/Party.cs +++ b/Projects/Scripts/Engines/Party/Party.cs @@ -9,6 +9,7 @@ namespace Server.Engines.PartySystem public class Party : IParty { public const int Capacity = 10; + private List m_Listeners; // staff listening public Party(Mobile leader) { @@ -16,7 +17,7 @@ namespace Server.Engines.PartySystem Members = new List(); Candidates = new List(); - Listeners = new List(); + m_Listeners = new List(); Members.Add(new PartyMemberInfo(leader)); } @@ -29,32 +30,58 @@ namespace Server.Engines.PartySystem public List Candidates{ get; } - public List Listeners { get; } // staff listening - public PartyMemberInfo this[int index] => Members[index]; - public PartyMemberInfo this[Mobile m] => Members.FirstOrDefault(t => t.Mobile == m); + public PartyMemberInfo this[Mobile m] + { + get + { + for (int i = 0; i < Members.Count; ++i) + if (Members[i].Mobile == m) + return Members[i]; + + return null; + } + } public void OnStamChanged(Mobile m) { + Packet p = null; + for (int i = 0; i < Members.Count; ++i) { Mobile c = Members[i].Mobile; if (c != m && m.Map == c.Map && Utility.InUpdateRange(c, m) && c.CanSee(m)) - Packets.SendNormalizedMobileStam(c.NetState, c); + { + if (p == null) + p = Packet.Acquire(new MobileStamN(m)); + + c.Send(p); + } } + + Packet.Release(p); } public void OnManaChanged(Mobile m) { + Packet p = null; + for (int i = 0; i < Members.Count; ++i) { Mobile c = Members[i].Mobile; if (c != m && m.Map == c.Map && Utility.InUpdateRange(c, m) && c.CanSee(m)) - Packets.SendNormalizedMobileMana(c.NetState, c); + { + if (p == null) + p = Packet.Acquire(new MobileManaN(m)); + + c.Send(p); + } } + + Packet.Release(p); } public void OnStatsQuery(Mobile beholder, Mobile beheld) @@ -63,9 +90,9 @@ namespace Server.Engines.PartySystem Utility.InUpdateRange(beholder, beheld)) { if (!beholder.CanSee(beheld)) - Packets.SendMobileStatusCompact(beholder.NetState, beheld, beheld.CanBeRenamedBy(beholder)); + beholder.Send(new MobileStatusCompact(beheld.CanBeRenamedBy(beholder), beheld)); - Packets.SendNormalizedMobileAttributes(beholder.NetState, beheld); + beholder.Send(new MobileAttributesN(beheld)); } } @@ -94,14 +121,14 @@ namespace Server.Engines.PartySystem { from.SendMessage("They are not in a party."); } - else if (p.Listeners.Contains(from)) + else if (p.m_Listeners.Contains(from)) { - p.Listeners.Remove(from); + p.m_Listeners.Remove(from); from.SendMessage("You are no longer listening to that party."); } else { - p.Listeners.Add(from); + p.m_Listeners.Add(from); from.SendMessage("You are now listening to that party."); } } @@ -157,25 +184,35 @@ namespace Server.Engines.PartySystem Members.Add(new PartyMemberInfo(m)); m.Party = this; + Packet memberList = Packet.Acquire(new PartyMemberList(this)); + Packet attrs = Packet.Acquire(new MobileAttributesN(m)); + for (int i = 0; i < Members.Count; ++i) { Mobile f = Members[i].Mobile; - NetState ns = f.NetState; - PartyPackets.SendPartyMemberList(ns, this); + f.Send(memberList); if (f != m) { - Packets.SendMobileStatusCompact(ns, m, m.CanBeRenamedBy(f)); - Packets.SendNormalizedMobileAttributes(ns, m); - Packets.SendMobileStatusCompact(ns, f, f.CanBeRenamedBy(m)); - Packets.SendNormalizedMobileAttributes(ns, f); + f.Send(new MobileStatusCompact(m.CanBeRenamedBy(f), m)); + f.Send(attrs); + m.Send(new MobileStatusCompact(f.CanBeRenamedBy(m), f)); + m.Send(new MobileAttributesN(f)); } } + + Packet.Release(memberList); + Packet.Release(attrs); } } - public void OnAccept(Mobile from, bool force = false) + public void OnAccept(Mobile from) + { + OnAccept(from, false); + } + + public void OnAccept(Mobile from, bool force) { Faction ourFaction = Faction.Find(Leader); Faction theirFaction = Faction.Find(from); @@ -184,8 +221,8 @@ namespace Server.Engines.PartySystem return; // : joined the party. - PartyPackets.SendPartyMessageLocalizedAffixToAll(this, Serial.MinusOne, -1, MessageType.Label, - 0x3B2, 3, 1008094, "",AffixType.Prepend | AffixType.System, from.Name); + SendToAll(new MessageLocalizedAffix(Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008094, "", + AffixType.Prepend | AffixType.System, from.Name, "")); from.SendLocalizedMessage(1005445); // You have been added to the party. @@ -201,15 +238,14 @@ namespace Server.Engines.PartySystem from.SendLocalizedMessage(1008092); // You notify them that you do not wish to join the party. Candidates.Remove(from); - PartyPackets.SendPartyEmptyList(from.NetState, from); + from.Send(new PartyEmptyList(from)); if (Candidates.Count == 0 && Members.Count <= 1) { for (int i = 0; i < Members.Count; ++i) { - Mobile m = this[i].Mobile; - PartyPackets.SendPartyEmptyList(m.NetState, m); - m.Party = null; + this[i].Mobile.Send(new PartyEmptyList(this[i].Mobile)); + this[i].Mobile.Party = null; } Members.Clear(); @@ -219,7 +255,9 @@ namespace Server.Engines.PartySystem public void Remove(Mobile m) { if (m == Leader) + { Disband(); + } else { for (int i = 0; i < Members.Count; ++i) @@ -228,21 +266,19 @@ namespace Server.Engines.PartySystem Members.RemoveAt(i); m.Party = null; - PartyPackets.SendPartyEmptyList(m.NetState, m); + m.Send(new PartyEmptyList(m)); m.SendLocalizedMessage(1005451); // You have been removed from the party. - PartyPackets.SendPartyRemoveMemberToAll(m, this); - // A player has been removed from your party. - PartyPackets.SendPartyMessageLocalizedToAll(this, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, 1005452, "System"); + SendToAll(new PartyRemoveMember(m, this)); + SendToAll(1005452); // A player has been removed from your party. break; } if (Members.Count == 1) { - // The last person has left the party... - PartyPackets.SendPartyMessageLocalizedToAll(this, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, 1005450, "System"); + SendToAll(1005450); // The last person has left the party... Disband(); } } @@ -252,14 +288,12 @@ namespace Server.Engines.PartySystem public void Disband() { - // Your party has disbanded. - PartyPackets.SendPartyMessageLocalizedToAll(this, Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, 1005449, "System"); + SendToAll(1005449); // Your party has disbanded. for (int i = 0; i < Members.Count; ++i) { - Mobile m = this[i].Mobile; - PartyPackets.SendPartyEmptyList(m.NetState, m); - m.Party = null; + this[i].Mobile.Send(new PartyEmptyList(this[i].Mobile)); + this[i].Mobile.Party = null; } Members.Clear(); @@ -286,57 +320,82 @@ namespace Server.Engines.PartySystem p.Candidates.Add(target); // : You are invited to join the party. Type /accept to join or /decline to decline the offer. - Packets.SendMessageLocalizedAffix(target.NetState, Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008089, "", - AffixType.Prepend | AffixType.System, from.Name); + target.Send(new MessageLocalizedAffix(Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008089, "", + AffixType.Prepend | AffixType.System, from.Name, "")); from.SendLocalizedMessage(1008090); // You have invited them to join the party. - PartyPackets.SendPartyInvitation(target.NetState, from); + target.Send(new PartyInvitation(from)); target.Party = from; DeclineTimer.Start(target, from); } + public void SendToAll(int number) + { + SendToAll(number, "", 0x3B2); + } + + public void SendToAll(int number, string args) + { + SendToAll(number, args, 0x3B2); + } + + public void SendToAll(int number, string args, int hue) + { + SendToAll(new MessageLocalized(Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args)); + } + public void SendPublicMessage(Mobile from, string text) { - PartyPackets.SendPartyTextMessageToAll(this, true, from, text); + SendToAll(new PartyTextMessage(true, from, text)); - for (int i = 0; i < Listeners.Count; ++i) + for (int i = 0; i < m_Listeners.Count; ++i) { - Mobile mob = Listeners[i]; + Mobile mob = m_Listeners[i]; if (mob.Party != this) - Listeners[i].SendMessage("[{0}]: {1}", from.Name, text); + m_Listeners[i].SendMessage("[{0}]: {1}", from.Name, text); } - SendToStaffMessage(from, $"[Party]: {text}"); + SendToStaffMessage(from, "[Party]: {0}", text); } public void SendPrivateMessage(Mobile from, Mobile to, string text) { - PartyPackets.SendPartyTextMessage(to.NetState, false, from, text); + to.Send(new PartyTextMessage(false, from, text)); - for (int i = 0; i < Listeners.Count; ++i) + for (int i = 0; i < m_Listeners.Count; ++i) { - Mobile mob = Listeners[i]; + Mobile mob = m_Listeners[i]; if (mob.Party != this) - Listeners[i].SendMessage("[{0}]->[{1}]: {2}", from.Name, to.Name, text); + m_Listeners[i].SendMessage("[{0}]->[{1}]: {2}", from.Name, to.Name, text); } - SendToStaffMessage(from, $"[Party]->[{to.Name}]: {text}"); + SendToStaffMessage(from, "[Party]->[{0}]: {1}", to.Name, text); } private void SendToStaffMessage(Mobile from, string text) { + Packet p = null; + foreach (NetState ns in from.GetClientsInRange(8)) { Mobile mob = ns.Mobile; if (mob?.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > from.AccessLevel && - mob.Party != this && !Listeners.Contains(mob)) - Packets.SendUnicodeMessage(ns, from.Serial, from.Body, MessageType.Regular, from.SpeechHue, 3, from.Language, from.Name, text); + mob.Party != this && !m_Listeners.Contains(mob)) + { + if (p == null) + p = Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Regular, from.SpeechHue, 3, + from.Language, from.Name, text)); + + ns.Send(p); + } } + + Packet.Release(p); } private void SendToStaffMessage(Mobile from, string format, params object[] args) @@ -344,6 +403,25 @@ namespace Server.Engines.PartySystem SendToStaffMessage(from, string.Format(format, args)); } + public void SendToAll(Packet p) + { + p.Acquire(); + + for (int i = 0; i < Members.Count; ++i) + Members[i].Mobile.Send(p); + + if (p is MessageLocalized || p is MessageLocalizedAffix || p is UnicodeMessage || p is AsciiMessage) + for (int i = 0; i < m_Listeners.Count; ++i) + { + Mobile mob = m_Listeners[i]; + + if (mob.Party != this) + mob.Send(p); + } + + p.Release(); + } + private class RejoinTimer : Timer { private Mobile m_Mobile; @@ -358,7 +436,11 @@ namespace Server.Engines.PartySystem return; m_Mobile.SendLocalizedMessage(1005437); // You have rejoined the party. - PartyPackets.SendPartyMemberList(m_Mobile.NetState, p); + m_Mobile.Send(new PartyMemberList(p)); + + Packet message = Packet.Acquire(new MessageLocalizedAffix(Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, + 1008087, "", AffixType.Prepend | AffixType.System, m_Mobile.Name, "")); + Packet attrs = Packet.Acquire(new MobileAttributesN(m_Mobile)); foreach (PartyMemberInfo mi in p.Members) { @@ -366,15 +448,16 @@ namespace Server.Engines.PartySystem if (m != m_Mobile) { - NetState ns = m.NetState; - Packets.SendMessageLocalizedAffix(ns, Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, - 1008087, "", AffixType.Prepend | AffixType.System, m_Mobile.Name); - Packets.SendMobileStatusCompact(ns, m_Mobile, m_Mobile.CanBeRenamedBy(m)); - Packets.SendNormalizedMobileAttributes(ns, m_Mobile); - Packets.SendMobileStatusCompact(ns, m, m.CanBeRenamedBy(m_Mobile)); - Packets.SendNormalizedMobileAttributes(ns, m); + m.Send(message); + m.Send(new MobileStatusCompact(m_Mobile.CanBeRenamedBy(m), m_Mobile)); + m.Send(attrs); + m_Mobile.Send(new MobileStatusCompact(m.CanBeRenamedBy(m_Mobile), m)); + m_Mobile.Send(new MobileAttributesN(m)); } } + + Packet.Release(message); + Packet.Release(attrs); } } } diff --git a/Projects/Scripts/Engines/Pathing/FastAStarAlgorithm.cs b/Projects/Scripts/Engines/Pathing/FastAStarAlgorithm.cs index 640b624bf..312e995c0 100644 --- a/Projects/Scripts/Engines/Pathing/FastAStarAlgorithm.cs +++ b/Projects/Scripts/Engines/Pathing/FastAStarAlgorithm.cs @@ -1,17 +1,19 @@ using System.Collections; using Server.Mobiles; +using CalcMoves = Server.Movement.Movement; +using MoveImpl = Server.Movement.MovementImpl; -namespace Server.PathAlgorithms +namespace Server.PathAlgorithms.FastAStar { + public struct PathNode + { + public int cost, total; + public int parent, next, prev; + public int z; + } + public class FastAStarAlgorithm : PathAlgorithm { - public struct PathNode - { - public int cost, total; - public int parent, next, prev; - public int z; - } - private const int MaxDepth = 300; private const int AreaSize = 38; @@ -132,18 +134,18 @@ namespace Server.PathAlgorithms if (bc != null) { - MovementImpl.AlwaysIgnoreDoors = bc.CanOpenDoors; - MovementImpl.IgnoreMovableImpassables = bc.CanMoveOverObstacles; + MoveImpl.AlwaysIgnoreDoors = bc.CanOpenDoors; + MoveImpl.IgnoreMovableImpassables = bc.CanMoveOverObstacles; } - MovementImpl.Goal = goal; + MoveImpl.Goal = goal; int[] vals = m_Successors; int count = GetSuccessors(bestNode, m, map); - MovementImpl.AlwaysIgnoreDoors = false; - MovementImpl.IgnoreMovableImpassables = false; - MovementImpl.Goal = Point3D.Zero; + MoveImpl.AlwaysIgnoreDoors = false; + MoveImpl.IgnoreMovableImpassables = false; + MoveImpl.Goal = Point3D.Zero; if (count == 0) break; @@ -156,26 +158,26 @@ namespace Server.PathAlgorithms if (wasTouched) continue; - + int newCost = m_Nodes[bestNode].cost + 1; int newTotal = newCost + Heuristic(newNode % AreaSize, newNode / AreaSize % AreaSize, m_Nodes[newNode].z); if (m_Nodes[newNode].total <= newTotal) continue; - + m_Nodes[newNode].parent = bestNode; m_Nodes[newNode].cost = newCost; m_Nodes[newNode].total = newTotal; if (m_OnOpen[newNode]) continue; - + AddToChain(newNode); if (newNode != destNode) continue; - + int pathCount = 0; int parent = m_Nodes[newNode].parent; @@ -294,7 +296,7 @@ namespace Server.PathAlgorithms if (x < 0 || x >= AreaSize || y < 0 || y >= AreaSize) continue; - if (Movement.CheckMovement(m, map, p3D, (Direction)i, out int z)) + if (CalcMoves.CheckMovement(m, map, p3D, (Direction)i, out int z)) { int idx = GetIndex(x + m_xOffset, y + m_yOffset, z); @@ -309,4 +311,4 @@ namespace Server.PathAlgorithms return count; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Pathing/FastMovement.cs b/Projects/Scripts/Engines/Pathing/FastMovement.cs index ae3fa8b67..d71530a80 100644 --- a/Projects/Scripts/Engines/Pathing/FastMovement.cs +++ b/Projects/Scripts/Engines/Pathing/FastMovement.cs @@ -8,7 +8,7 @@ using Server.Mobiles; #endregion -namespace Server +namespace Server.Movement { public class FastMovementImpl : IMovementImpl { @@ -179,7 +179,7 @@ namespace Server private static bool Check( Map map, Mobile m, - IReadOnlyCollection items, + List items, int x, int y, int startTop, diff --git a/Projects/Scripts/Engines/Pathing/Movement.cs b/Projects/Scripts/Engines/Pathing/Movement.cs index 6fbf02972..e04e7b1a8 100644 --- a/Projects/Scripts/Engines/Pathing/Movement.cs +++ b/Projects/Scripts/Engines/Pathing/Movement.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using Server.Items; using Server.Mobiles; -namespace Server +namespace Server.Movement { public class MovementImpl : IMovementImpl { @@ -316,7 +316,7 @@ namespace Server return true; } - private bool Check(Map map, Mobile m, List items, IReadOnlyList mobiles, int x, int y, int startTop, int startZ, + private bool Check(Map map, Mobile m, List items, List mobiles, int x, int y, int startTop, int startZ, bool canSwim, bool cantWalk, out int newZ) { newZ = 0; @@ -500,7 +500,7 @@ namespace Server !t.Alive || !m.Alive || t.IsDeadBondedPet || m.IsDeadBondedPet || t.Hidden && t.AccessLevel > AccessLevel.Player; - private void GetStartZ(Mobile m, Map map, Point3D loc, IReadOnlyList itemList, out int zLow, out int zTop) + private void GetStartZ(Mobile m, Map map, Point3D loc, List itemList, out int zLow, out int zTop) { int xCheck = loc.X, yCheck = loc.Y; diff --git a/Projects/Scripts/Engines/Pathing/MovementPath.cs b/Projects/Scripts/Engines/Pathing/MovementPath.cs index ef993e52e..17a7f7409 100644 --- a/Projects/Scripts/Engines/Pathing/MovementPath.cs +++ b/Projects/Scripts/Engines/Pathing/MovementPath.cs @@ -1,6 +1,8 @@ using System; using Server.Items; using Server.PathAlgorithms; +using Server.PathAlgorithms.FastAStar; +using Server.PathAlgorithms.SlowAStar; using Server.Spells; using Server.Targeting; @@ -82,7 +84,7 @@ namespace Server for (int i = 0; i < path.Directions.Length; ++i) { - Movement.Offset(path.Directions[i], ref x, ref y); + Movement.Movement.Offset(path.Directions[i], ref x, ref y); new RecallRune().MoveToWorld(new Point3D(x, y, z + zOffset), from.Map); } diff --git a/Projects/Scripts/Engines/Pathing/PathAlgorithm.cs b/Projects/Scripts/Engines/Pathing/PathAlgorithm.cs index 9d04dd9ac..07500b988 100644 --- a/Projects/Scripts/Engines/Pathing/PathAlgorithm.cs +++ b/Projects/Scripts/Engines/Pathing/PathAlgorithm.cs @@ -2,7 +2,7 @@ namespace Server.PathAlgorithms { public abstract class PathAlgorithm { - private static readonly Direction[] m_CalcDirections = { + private static Direction[] m_CalcDirections = { Direction.Up, Direction.North, Direction.Right, @@ -29,4 +29,4 @@ namespace Server.PathAlgorithms return m_CalcDirections[v]; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Pathing/PathFollower.cs b/Projects/Scripts/Engines/Pathing/PathFollower.cs index 43004f0b0..6780ba930 100644 --- a/Projects/Scripts/Engines/Pathing/PathFollower.cs +++ b/Projects/Scripts/Engines/Pathing/PathFollower.cs @@ -1,4 +1,5 @@ using System; +using CalcMoves = Server.Movement.Movement; namespace Server { @@ -51,7 +52,7 @@ namespace Server { int x = p.X, y = p.Y; - Movement.Offset(dirs[index], ref x, ref y); + CalcMoves.Offset(dirs[index], ref x, ref y); p.X = x; p.Y = y; diff --git a/Projects/Scripts/Engines/Pathing/SlowAStarAlgorithm.cs b/Projects/Scripts/Engines/Pathing/SlowAStarAlgorithm.cs index 3b36291ab..e09d23520 100644 --- a/Projects/Scripts/Engines/Pathing/SlowAStarAlgorithm.cs +++ b/Projects/Scripts/Engines/Pathing/SlowAStarAlgorithm.cs @@ -1,18 +1,20 @@ using System; using Server.Mobiles; +using CalcMoves = Server.Movement.Movement; +using MoveImpl = Server.Movement.MovementImpl; -namespace Server.PathAlgorithms +namespace Server.PathAlgorithms.SlowAStar { + public struct PathNode + { + public int x, y, z; + public int g, h; + public int px, py, pz; + public int dir; + } + public class SlowAStarAlgorithm : PathAlgorithm { - public struct PathNode - { - public int x, y, z; - public int g, h; - public int px, py, pz; - public int dir; - } - private const int MaxDepth = 300; private const int MaxNodes = MaxDepth * 16; public static PathAlgorithm Instance = new SlowAStarAlgorithm(); @@ -146,11 +148,11 @@ namespace Server.PathAlgorithms if (bc != null) { - MovementImpl.AlwaysIgnoreDoors = bc.CanOpenDoors; - MovementImpl.IgnoreMovableImpassables = bc.CanMoveOverObstacles; + MoveImpl.AlwaysIgnoreDoors = bc.CanOpenDoors; + MoveImpl.IgnoreMovableImpassables = bc.CanMoveOverObstacles; } - MovementImpl.Goal = goal; + MoveImpl.Goal = goal; int x; int y; @@ -160,6 +162,7 @@ namespace Server.PathAlgorithms switch (i) { default: + case 0: x = 0; y = -1; break; @@ -193,7 +196,7 @@ namespace Server.PathAlgorithms break; } - if (Movement.CheckMovement(m, map, new Point3D(curNode.x, curNode.y, curNode.z), (Direction)i, out z)) + if (CalcMoves.CheckMovement(m, map, new Point3D(curNode.x, curNode.y, curNode.z), (Direction)i, out z)) { successors[sucCount].x = x + curNode.x; successors[sucCount].y = y + curNode.y; @@ -201,9 +204,9 @@ namespace Server.PathAlgorithms } } - MovementImpl.AlwaysIgnoreDoors = false; - MovementImpl.IgnoreMovableImpassables = false; - MovementImpl.Goal = Point3D.Zero; + MoveImpl.AlwaysIgnoreDoors = false; + MoveImpl.IgnoreMovableImpassables = false; + MoveImpl.Goal = Point3D.Zero; if (sucCount == 0 || ++depth > MaxDepth) break; @@ -269,4 +272,4 @@ namespace Server.PathAlgorithms return null; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Plants/EmptyTheBowlGump.cs b/Projects/Scripts/Engines/Plants/EmptyTheBowlGump.cs index 5b98406c2..fdd97d00e 100644 --- a/Projects/Scripts/Engines/Plants/EmptyTheBowlGump.cs +++ b/Projects/Scripts/Engines/Plants/EmptyTheBowlGump.cs @@ -75,7 +75,7 @@ namespace Server.Engines.Plants } case 2: // Help { - ContentPackets.SendDisplayHelpTopic(from.NetState, 17, true); // EMPTYING THE BOWL + from.Send(new DisplayHelpTopic(71, true)); // EMPTYING THE BOWL from.SendGump(new EmptyTheBowlGump(m_Plant)); diff --git a/Projects/Scripts/Engines/Plants/MainPlantGump.cs b/Projects/Scripts/Engines/Plants/MainPlantGump.cs index ae5da309a..835b8ed10 100644 --- a/Projects/Scripts/Engines/Plants/MainPlantGump.cs +++ b/Projects/Scripts/Engines/Plants/MainPlantGump.cs @@ -264,7 +264,9 @@ namespace Server.Engines.Plants case 1: // Reproduction menu { if (m_Plant.PlantStatus > PlantStatus.BowlOfDirt) + { from.SendGump(new ReproductionGump(m_Plant)); + } else { from.SendLocalizedMessage(1061885); // You need to plant a seed in the bowl first. @@ -276,28 +278,32 @@ namespace Server.Engines.Plants } case 2: // Infestation { - ContentPackets.SendDisplayHelpTopic(from.NetState, 54, true); // INFESTATION LEVEL + from.Send(new DisplayHelpTopic(54, true)); // INFESTATION LEVEL + from.SendGump(new MainPlantGump(m_Plant)); break; } case 3: // Fungus { - ContentPackets.SendDisplayHelpTopic(from.NetState, 56, true); // FUNGUS LEVEL + from.Send(new DisplayHelpTopic(56, true)); // FUNGUS LEVEL + from.SendGump(new MainPlantGump(m_Plant)); break; } case 4: // Poison { - ContentPackets.SendDisplayHelpTopic(from.NetState, 58, true); // POISON LEVEL + from.Send(new DisplayHelpTopic(58, true)); // POISON LEVEL + from.SendGump(new MainPlantGump(m_Plant)); break; } case 5: // Disease { - ContentPackets.SendDisplayHelpTopic(from.NetState, 60, true); // DISEASE LEVEL + from.Send(new DisplayHelpTopic(60, true)); // DISEASE LEVEL + from.SendGump(new MainPlantGump(m_Plant)); break; @@ -314,7 +320,9 @@ namespace Server.Engines.Plants $"#{m_Plant.GetLocalizedPlantStatus()}"); // Target the container you wish to use to water the ~1_val~. } else + { m_Plant.Pour(from, bev); + } from.SendGump(new MainPlantGump(m_Plant)); @@ -346,7 +354,7 @@ namespace Server.Engines.Plants } case 11: // Help { - ContentPackets.SendDisplayHelpTopic(from.NetState, 48, true); // PLANT GROWING + from.Send(new DisplayHelpTopic(48, true)); // PLANT GROWING from.SendGump(new MainPlantGump(m_Plant)); @@ -366,7 +374,9 @@ namespace Server.Engines.Plants Item item = GetPotion(from, effects); if (item != null) + { m_Plant.Pour(from, item); + } else { if (m_Plant.ApplyPotion(effects[0], true, out int message)) diff --git a/Projects/Scripts/Engines/Plants/Network/DisplayHelpTopic.cs b/Projects/Scripts/Engines/Plants/Network/DisplayHelpTopic.cs new file mode 100644 index 000000000..e026d8a03 --- /dev/null +++ b/Projects/Scripts/Engines/Plants/Network/DisplayHelpTopic.cs @@ -0,0 +1,15 @@ +namespace Server.Network +{ + public class DisplayHelpTopic : Packet + { + public DisplayHelpTopic(int topicID, bool display) : base(0xBF) + { + EnsureCapacity(11); + + m_Stream.Write((short)0x17); + m_Stream.Write((byte)1); + m_Stream.Write(topicID); + m_Stream.Write(display); + } + } +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Plants/PlantItem.cs b/Projects/Scripts/Engines/Plants/PlantItem.cs index db0a0124c..6e825842b 100644 --- a/Projects/Scripts/Engines/Plants/PlantItem.cs +++ b/Projects/Scripts/Engines/Plants/PlantItem.cs @@ -84,7 +84,8 @@ namespace Server.Engines.Plants } else { - PlantSystem ??= new PlantSystem(this, false); + if (PlantSystem == null) + PlantSystem = new PlantSystem(this, false); int hits = (int)(PlantSystem.MaxHits * ratio); diff --git a/Projects/Scripts/Engines/Plants/PlantResources.cs b/Projects/Scripts/Engines/Plants/PlantResources.cs index 6059c5140..32eae6913 100644 --- a/Projects/Scripts/Engines/Plants/PlantResources.cs +++ b/Projects/Scripts/Engines/Plants/PlantResources.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Server.Items; namespace Server.Engines.Plants @@ -32,9 +31,15 @@ namespace Server.Engines.Plants public Type ResourceType{ get; } - public static PlantResourceInfo GetInfo(PlantType plantType, PlantHue plantHue) => - m_ResourceList.FirstOrDefault(info => info.PlantType == plantType && info.PlantHue == plantHue); + public static PlantResourceInfo GetInfo(PlantType plantType, PlantHue plantHue) + { + foreach (PlantResourceInfo info in m_ResourceList) + if (info.PlantType == plantType && info.PlantHue == plantHue) + return info; + + return null; + } public Item CreateResource() => (Item)Activator.CreateInstance(ResourceType); } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Plants/PlantSystem.cs b/Projects/Scripts/Engines/Plants/PlantSystem.cs index 832a63fd1..25539101c 100644 --- a/Projects/Scripts/Engines/Plants/PlantSystem.cs +++ b/Projects/Scripts/Engines/Plants/PlantSystem.cs @@ -383,7 +383,6 @@ namespace Server.Engines.Plants return 1060827; // soft if (Water <= 3) return 1060828; // squishy - return 1060829; // sopping wet } diff --git a/Projects/Scripts/Engines/Plants/PlantType.cs b/Projects/Scripts/Engines/Plants/PlantType.cs index 0010b253f..aaeb5ea27 100644 --- a/Projects/Scripts/Engines/Plants/PlantType.cs +++ b/Projects/Scripts/Engines/Plants/PlantType.cs @@ -261,13 +261,21 @@ namespace Server.Engines.Plants double rand = Utility.RandomDouble(); - return rand < 0.5 / exp4 ? PlantType.CommonGreenBonsai : - rand < 1.0 / exp4 ? PlantType.CommonPinkBonsai : - rand < (k1 * 0.5 + 1.0) / exp4 ? PlantType.UncommonGreenBonsai : - rand < exp1 / exp4 ? PlantType.UncommonPinkBonsai : - rand < (k2 * 0.5 + exp1) / exp4 ? PlantType.RareGreenBonsai : - rand < exp2 / exp4 ? PlantType.RarePinkBonsai : - rand < exp3 / exp4 ? PlantType.ExceptionalBonsai : PlantType.ExoticBonsai; + if (rand < 0.5 / exp4) + return PlantType.CommonGreenBonsai; + if (rand < 1.0 / exp4) + return PlantType.CommonPinkBonsai; + if (rand < (k1 * 0.5 + 1.0) / exp4) + return PlantType.UncommonGreenBonsai; + if (rand < exp1 / exp4) + return PlantType.UncommonPinkBonsai; + if (rand < (k2 * 0.5 + exp1) / exp4) + return PlantType.RareGreenBonsai; + if (rand < exp2 / exp4) + return PlantType.RarePinkBonsai; + if (rand < exp3 / exp4) + return PlantType.ExceptionalBonsai; + return PlantType.ExoticBonsai; } public static bool IsCrossable(PlantType plantType) => GetInfo(plantType).Crossable; @@ -348,4 +356,4 @@ namespace Server.Engines.Plants return hueInfo.IsBright() ? 1113493 : 1113492; // ~1_amount~ [bright] ~2_color~ ~3_type~ seeds } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Plants/PollinateTarget.cs b/Projects/Scripts/Engines/Plants/PollinateTarget.cs index 22b8e1cd9..f7d0ded40 100644 --- a/Projects/Scripts/Engines/Plants/PollinateTarget.cs +++ b/Projects/Scripts/Engines/Plants/PollinateTarget.cs @@ -14,30 +14,50 @@ namespace Server.Engines.Plants from.InRange(m_Plant.GetWorldLocation(), 3)) { if (!m_Plant.IsUsableBy(from)) + { m_Plant.LabelTo(from, 1061856); // You must have the item in your backpack or locked down in order to use it. + } else if (!m_Plant.IsCrossable) + { m_Plant.LabelTo(from, 1053050); // You cannot gather pollen from a mutated plant! + } else if (!m_Plant.PlantSystem.PollenProducing) + { m_Plant.LabelTo(from, 1053051); // You cannot gather pollen from a plant in this stage of development! + } else if (m_Plant.PlantSystem.Health < PlantHealth.Healthy) + { m_Plant.LabelTo(from, 1053052); // You cannot gather pollen from an unhealthy plant! + } else { if (!(targeted is PlantItem targ) || targ.PlantStatus >= PlantStatus.DecorativePlant || targ.PlantStatus <= PlantStatus.BowlOfDirt) + { m_Plant.LabelTo(from, 1053070); // You can only pollinate other specially grown plants! + } else if (!targ.IsUsableBy(from)) + { targ.LabelTo(from, 1061856); // You must have the item in your backpack or locked down in order to use it. + } else if (!targ.IsCrossable) + { targ.LabelTo(from, 1053073); // You cannot cross-pollinate with a mutated plant! + } else if (!targ.PlantSystem.PollenProducing) + { targ.LabelTo(from, 1053074); // This plant is not in the flowering stage. You cannot pollinate it! + } else if (targ.PlantSystem.Health < PlantHealth.Healthy) + { targ.LabelTo(from, 1053075); // You cannot pollinate an unhealthy plant! + } else if (targ.PlantSystem.Pollinated) + { targ.LabelTo(from, 1053072); // This plant has already been pollinated! + } else if (targ == m_Plant) { targ.PlantSystem.Pollinated = true; @@ -65,4 +85,4 @@ namespace Server.Engines.Plants m_Plant.IsUsableBy(from)) from.SendGump(new ReproductionGump(m_Plant)); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Plants/ReproductionGump.cs b/Projects/Scripts/Engines/Plants/ReproductionGump.cs index 5506bf512..ead5ca625 100644 --- a/Projects/Scripts/Engines/Plants/ReproductionGump.cs +++ b/Projects/Scripts/Engines/Plants/ReproductionGump.cs @@ -138,21 +138,24 @@ namespace Server.Engines.Plants } case 3: // Pollination { - ContentPackets.SendDisplayHelpTopic(from.NetState, 67, true); // POLLINATION STATE + from.Send(new DisplayHelpTopic(67, true)); // POLLINATION STATE + from.SendGump(new ReproductionGump(m_Plant)); break; } case 4: // Resources { - ContentPackets.SendDisplayHelpTopic(from.NetState, 69, true); // RESOURCE PRODUCTION + from.Send(new DisplayHelpTopic(69, true)); // RESOURCE PRODUCTION + from.SendGump(new ReproductionGump(m_Plant)); break; } case 5: // Seeds { - ContentPackets.SendDisplayHelpTopic(from.NetState, 68, true); // SEED PRODUCTION + from.Send(new DisplayHelpTopic(68, true)); // SEED PRODUCTION + from.SendGump(new ReproductionGump(m_Plant)); break; @@ -197,7 +200,9 @@ namespace Server.Engines.Plants m_Plant.LabelTo(from, 1053055); // Mutated plants do not produce resources! } else if (system.AvailableResources == 0) + { m_Plant.LabelTo(from, 1053056); // This plant has no resources to gather! + } else { Item resource = resInfo.CreateResource(); @@ -224,9 +229,13 @@ namespace Server.Engines.Plants PlantSystem system = m_Plant.PlantSystem; if (!m_Plant.Reproduces) + { m_Plant.LabelTo(from, 1053060); // Mutated plants do not produce seeds! + } else if (system.AvailableSeeds == 0) + { m_Plant.LabelTo(from, 1053061); // This plant has no seeds to gather! + } else { Seed seed = new Seed(system.SeedType, system.SeedHue, true); diff --git a/Projects/Scripts/Engines/Plants/SetToDecorativeGump.cs b/Projects/Scripts/Engines/Plants/SetToDecorativeGump.cs index 4e63c8166..5b3a60bce 100644 --- a/Projects/Scripts/Engines/Plants/SetToDecorativeGump.cs +++ b/Projects/Scripts/Engines/Plants/SetToDecorativeGump.cs @@ -64,7 +64,7 @@ namespace Server.Engines.Plants } case 2: // Help { - ContentPackets.SendDisplayHelpTopic(from.NetState, 70, true); // DECORATIVE MODE + from.Send(new DisplayHelpTopic(70, true)); // DECORATIVE MODE from.SendGump(new SetToDecorativeGump(m_Plant)); diff --git a/Projects/Scripts/Engines/Quests/Collector/Items/Obsidian.cs b/Projects/Scripts/Engines/Quests/Collector/Items/Obsidian.cs index a0e87b719..d48cd0da2 100644 --- a/Projects/Scripts/Engines/Quests/Collector/Items/Obsidian.cs +++ b/Projects/Scripts/Engines/Quests/Collector/Items/Obsidian.cs @@ -167,10 +167,11 @@ namespace Server.Engines.Quests.Collector { if (m_Quantity < m_Completed) { - if (IsChildOf(from.Backpack)) - from.Target = new InternalTarget(this); + if (!IsChildOf(from.Backpack)) + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x2C, 3, 500309, "", + "")); // Nothing Happens. else - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Regular, 0x2C, 3, 500309); // Nothing Happens. + from.Target = new InternalTarget(this); } } @@ -244,15 +245,15 @@ namespace Server.Engines.Quests.Collector if (targObsidian.Quantity >= m_Completed) targObsidian.StatueName = RandomName(from); - Packets.SendAsciiMessage(from.NetState, targObsidian.Serial, targObsidian.ItemID, MessageType.Regular, 0x59, 3, - m_Obsidian.Name, "Something Happened."); + from.Send(new AsciiMessage(targObsidian.Serial, targObsidian.ItemID, MessageType.Regular, 0x59, 3, + m_Obsidian.Name, "Something Happened.")); return; } - Packets.SendMessageLocalized(from.NetState, m_Obsidian.Serial, m_Obsidian.ItemID, MessageType.Regular, 0x2C, 3, 500309, - m_Obsidian.Name); // Nothing Happens. + from.Send(new MessageLocalized(m_Obsidian.Serial, m_Obsidian.ItemID, MessageType.Regular, 0x2C, 3, 500309, + m_Obsidian.Name, "")); // Nothing Happens. } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Quests/Collector/Objectives.cs b/Projects/Scripts/Engines/Quests/Collector/Objectives.cs index 9157eba14..c59bd2a2b 100644 --- a/Projects/Scripts/Engines/Quests/Collector/Objectives.cs +++ b/Projects/Scripts/Engines/Quests/Collector/Objectives.cs @@ -359,4 +359,4 @@ namespace Server.Engines.Quests.Collector { public override object Message => 1055136; } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Quests/Core/Items/EnchantedSextant.cs b/Projects/Scripts/Engines/Quests/Core/Items/EnchantedSextant.cs index 9282a47f1..2bb1b0fe0 100644 --- a/Projects/Scripts/Engines/Quests/Core/Items/EnchantedSextant.cs +++ b/Projects/Scripts/Engines/Quests/Core/Items/EnchantedSextant.cs @@ -99,10 +99,11 @@ namespace Server.Items else if (from.Map == Map.Ilshenar) { #if false - banks = m_IlshenarBanks; - moongates = PMList.Ilshenar; + banks = m_IlshenarBanks; + moongates = PMList.Ilshenar; #else - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, 0x482, 3, 1061684); // The magic of the sextant fails... + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, 0x482, 3, 1061684, "", + "")); // The magic of the sextant fails... return; #endif } @@ -153,7 +154,7 @@ namespace Server.Items else moonMsg = 1048018; // You are next to a Moongate at the moment. - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, 0x482, 3, moonMsg); + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, 0x482, 3, moonMsg, "", "")); int bankMsg; if (bankDistance == double.MaxValue) @@ -165,7 +166,7 @@ namespace Server.Items else bankMsg = 1048019; // You are next to a Bank at the moment. - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, 0x5AA, 3, bankMsg); + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, 0x5AA, 3, bankMsg, "", "")); } public override void Serialize(GenericWriter writer) @@ -182,4 +183,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Quests/Core/QuestSerializer.cs b/Projects/Scripts/Engines/Quests/Core/QuestSerializer.cs index e8aabf4aa..fcec07493 100644 --- a/Projects/Scripts/Engines/Quests/Core/QuestSerializer.cs +++ b/Projects/Scripts/Engines/Quests/Core/QuestSerializer.cs @@ -44,7 +44,9 @@ namespace Server.Engines.Quests switch (encoding) { default: + { return null; + } case 0x01: // indexed { int index = reader.ReadEncodedInt(); @@ -73,7 +75,9 @@ namespace Server.Engines.Quests switch (encoding) { default: + { return null; + } case 0x01: { Type type = ReadType(QuestSystem.QuestTypes, reader); @@ -90,7 +94,9 @@ namespace Server.Engines.Quests public static void Serialize(QuestSystem qs, GenericWriter writer) { if (qs == null) + { writer.WriteEncodedInt(0x00); + } else { writer.WriteEncodedInt(0x01); @@ -108,7 +114,9 @@ namespace Server.Engines.Quests switch (encoding) { default: + { return null; + } case 0x01: { Type type = ReadType(referenceTable, reader); @@ -125,7 +133,9 @@ namespace Server.Engines.Quests public static void Serialize(Type[] referenceTable, QuestObjective obj, GenericWriter writer) { if (obj == null) + { writer.WriteEncodedInt(0x00); + } else { writer.WriteEncodedInt(0x01); @@ -143,7 +153,9 @@ namespace Server.Engines.Quests switch (encoding) { default: + { return null; + } case 0x01: { Type type = ReadType(referenceTable, reader); @@ -160,7 +172,9 @@ namespace Server.Engines.Quests public static void Serialize(Type[] referenceTable, QuestConversation conv, GenericWriter writer) { if (conv == null) + { writer.WriteEncodedInt(0x00); + } else { writer.WriteEncodedInt(0x01); diff --git a/Projects/Scripts/Engines/Quests/Core/QuestSystem.cs b/Projects/Scripts/Engines/Quests/Core/QuestSystem.cs index 129093721..01397d2a0 100644 --- a/Projects/Scripts/Engines/Quests/Core/QuestSystem.cs +++ b/Projects/Scripts/Engines/Quests/Core/QuestSystem.cs @@ -259,7 +259,7 @@ namespace Server.Engines.Quests From.SendGump(new QuestObjectivesGump(Objectives)); - QuestObjective last = Objectives[^1]; + QuestObjective last = Objectives[Objectives.Count - 1]; if (last.Info != null) From.SendGump(new QuestItemInfoGump(last.Info)); @@ -276,7 +276,7 @@ namespace Server.Engines.Quests From.SendGump(new QuestConversationsGump(Conversations)); - QuestConversation last = Conversations[^1]; + QuestConversation last = Conversations[Conversations.Count - 1]; if (last.Info != null) From.SendGump(new QuestItemInfoGump(last.Info)); diff --git a/Projects/Scripts/Engines/Quests/Dark Tides/Items/KronusScroll.cs b/Projects/Scripts/Engines/Quests/Dark Tides/Items/KronusScroll.cs index 81912200d..b0cdb7038 100644 --- a/Projects/Scripts/Engines/Quests/Dark Tides/Items/KronusScroll.cs +++ b/Projects/Scripts/Engines/Quests/Dark Tides/Items/KronusScroll.cs @@ -1,12 +1,13 @@ using System; using Server.Items; using Server.Mobiles; +using Server.Network; namespace Server.Engines.Quests.Necro { public class KronusScroll : QuestItem { - private static Rectangle2D m_WellOfTearsArea = new Rectangle2D(2080, 1346, 10, 10); + private static readonly Rectangle2D m_WellOfTearsArea = new Rectangle2D(2080, 1346, 10, 10); private static readonly Map m_WellOfTearsMap = Map.Malas; [Constructible] @@ -133,7 +134,9 @@ namespace Server.Engines.Quests.Necro int hue = Utility.RandomList(0x481, 0x482, 0x489, 0x497, 0x66D); - Effects.SendMovingEffect(from, to, map, 0x36D4, 0, 0, false, true, hue); + Effects.SendPacket(from, map, + new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x36D4, from, to, 0, 0, false, true, + hue, 0)); } } @@ -152,4 +155,4 @@ namespace Server.Engines.Quests.Necro } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Quests/Dark Tides/Items/MaabusCoffin.cs b/Projects/Scripts/Engines/Quests/Dark Tides/Items/MaabusCoffin.cs index c6ce70243..d1e311a1d 100644 --- a/Projects/Scripts/Engines/Quests/Dark Tides/Items/MaabusCoffin.cs +++ b/Projects/Scripts/Engines/Quests/Dark Tides/Items/MaabusCoffin.cs @@ -65,8 +65,8 @@ namespace Server.Engines.Quests.Necro Maabus.Delete(); Maabus = null; - foreach (AddonComponent addonComponent in Components) - (addonComponent as MaabusCoffinComponent)?.TurnToFull(); + foreach (MaabusCoffinComponent c in Components) + c.TurnToFull(); } public override void Serialize(GenericWriter writer) @@ -151,4 +151,4 @@ namespace Server.Engines.Quests.Necro m_EmptyItemID = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Quests/Dark Tides/Objectives.cs b/Projects/Scripts/Engines/Quests/Dark Tides/Objectives.cs index f39afebba..4eb61cc39 100644 --- a/Projects/Scripts/Engines/Quests/Dark Tides/Objectives.cs +++ b/Projects/Scripts/Engines/Quests/Dark Tides/Objectives.cs @@ -258,7 +258,7 @@ namespace Server.Engines.Quests.Necro public class FindWellOfTearsObjective : QuestObjective { - private static Rectangle2D m_WellOfTearsArea = new Rectangle2D(2080, 1346, 10, 10); + private static readonly Rectangle2D m_WellOfTearsArea = new Rectangle2D(2080, 1346, 10, 10); private bool m_Inside; diff --git a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Conversations.cs b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Conversations.cs index c62b965ab..1ed974af4 100644 --- a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Conversations.cs +++ b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Conversations.cs @@ -36,29 +36,29 @@ namespace Server.Engines.Quests.Haven if (System.From.Profession == 2) // magician return 1049386; - /* Uzeraan nods at you with approval and begins to speak...

- * - * Now that you are ready, let me give you your first task.

- * - * As I mentioned earlier, we have been trying to fight back the wicked - * Horde Minions which have recently begun attacking our cities - * - but to no avail. Our need is great!

- * - * Your first task will be to assess the situation in the mountain pass, - * and help our troops defeat the Horde Minions there.

- * - * Take the road marked with glowing runes, that starts just outside of this mansion. - * Before you go into battle, it would be prudent to - * review combat techniques as well as - * information on healing yourself, - * using your Paladin ability 'Close Wounds'.

- * - * To aid you in your fight, you may also wish to - * purchase equipment from Frank the Blacksmith, - * who is standing just South of here.

- * - * Good luck young Paladin! - */ +/* Uzeraan nods at you with approval and begins to speak...

+ * + * Now that you are ready, let me give you your first task.

+ * + * As I mentioned earlier, we have been trying to fight back the wicked + * Horde Minions which have recently begun attacking our cities + * - but to no avail. Our need is great!

+ * + * Your first task will be to assess the situation in the mountain pass, + * and help our troops defeat the Horde Minions there.

+ * + * Take the road marked with glowing runes, that starts just outside of this mansion. + * Before you go into battle, it would be prudent to + * review combat techniques as well as + * information on healing yourself, + * using your Paladin ability 'Close Wounds'.

+ * + * To aid you in your fight, you may also wish to + * purchase equipment from Frank the Blacksmith, + * who is standing just South of here.

+ * + * Good luck young Paladin! + */ return 1060388; } } @@ -73,7 +73,7 @@ namespace Server.Engines.Quests.Haven public class UzeraanReportConversation : QuestConversation { - private static readonly QuestItemInfo[] m_Info = + private static QuestItemInfo[] m_Info = { new QuestItemInfo(1026153, 0x1822), // teleporter new QuestItemInfo(1048032, 0xE76) // a bag @@ -469,4 +469,4 @@ namespace Server.Engines.Quests.Haven public override bool Logged => false; } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs index 8847c6609..0f0904646 100644 --- a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs +++ b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs @@ -28,14 +28,15 @@ namespace Server.Engines.Quests.Haven { } - // TODO: Should be a better way than making/deleting a mob. + // TODO: What is this? Why are we creating and deleting a mobile? private static Mobile GetOwner() { - Mobile apprentice = new Mobile - { - Hue = Race.Human.RandomSkinHue(), Female = false, Body = 0x190, Name = NameList.RandomName("male") - }; + Mobile apprentice = new Mobile(); + apprentice.Hue = Race.Human.RandomSkinHue(); + apprentice.Female = false; + apprentice.Body = 0x190; + apprentice.Name = NameList.RandomName("male"); apprentice.Delete(); @@ -44,14 +45,12 @@ namespace Server.Engines.Quests.Haven private static List GetEquipment() { - List list = new List - { - new Robe(QuestSystem.RandomBrightHue()), - new WizardsHat(Utility.RandomNeutralHue()), - new Shoes(Utility.RandomNeutralHue()), - new Spellbook() - }; + List list = new List(); + list.Add(new Robe(QuestSystem.RandomBrightHue())); + list.Add(new WizardsHat(Utility.RandomNeutralHue())); + list.Add(new Shoes(Utility.RandomNeutralHue())); + list.Add(new Spellbook()); return list; } @@ -87,10 +86,11 @@ namespace Server.Engines.Quests.Haven int hue = Notoriety.GetHue(NotorietyHandlers.CorpseNotoriety(from, this)); if (ItemID == 0x2006) // Corpse form - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, hue, 3, 1049144, "", - Name); // the remains of ~1_NAME~ the apprentice + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1049144, "", + Name)); // the remains of ~1_NAME~ the apprentice else - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, hue, 3, 1049145); // the remains of a wizard's apprentice + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1049145, "", + "")); // the remains of a wizard's apprentice } public override void Open(Mobile from, bool checkSelfLoot) diff --git a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaFighter.cs b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaFighter.cs index 155c0a5a2..28a4e6619 100644 --- a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaFighter.cs +++ b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaFighter.cs @@ -118,10 +118,11 @@ namespace Server.Engines.Quests.Haven int hue = Notoriety.GetHue(NotorietyHandlers.CorpseNotoriety(from, this)); if (ItemID == 0x2006) // Corpse form - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, hue, 3, 1049318, "", - Name); // the remains of ~1_NAME~ the militia fighter + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1049318, "", + Name)); // the remains of ~1_NAME~ the militia fighter else - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, hue, 3, 1049318); // the remains of a militia fighters + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1049319, "", + "")); // the remains of a militia fighter } public override void Open(Mobile from, bool checkSelfLoot) @@ -145,4 +146,4 @@ namespace Server.Engines.Quests.Haven int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Objectives.cs b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Objectives.cs index a4e34843f..b023c610f 100644 --- a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Objectives.cs +++ b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/Objectives.cs @@ -72,8 +72,9 @@ namespace Server.Engines.Quests.Haven public KillHordeMinionsStep Step{ get; private set; } - public override object Message => - Step switch + public override object Message + { + get { return Step switch { @@ -107,7 +108,19 @@ namespace Server.Engines.Quests.Haven _ => 5 }; - public override bool Completed => Step == KillHordeMinionsStep.LearnKarma && HasBeenRead || base.Completed; + return 5; + } + } + + public override bool Completed + { + get + { + if (Step == KillHordeMinionsStep.LearnKarma && HasBeenRead) + return true; + return base.Completed; + } + } public override void RenderProgress(BaseQuestGump gump) { @@ -127,15 +140,23 @@ namespace Server.Engines.Quests.Haven CheckCompletionStatus(); } - public override bool IgnoreYoungProtection(Mobile from) => - from is HordeMinion && from.Map == Map.Trammel && TreasureMap.IsInHavenIsland(from); + public override bool IgnoreYoungProtection(Mobile from) + { + // This restriction continues until the quest is ended + if (from is HordeMinion && from.Map == Map.Trammel && from.X >= 3314 && from.X <= 3814 && from.Y >= 2345 && + from.Y <= 3095) // Haven island + return true; + + return false; + } public override void OnKill(BaseCreature creature, Container corpse) { - if (creature is HordeMinion && corpse.Map == Map.Trammel && TreasureMap.IsInHavenIsland(corpse)) + if (creature is HordeMinion && corpse.Map == Map.Trammel && corpse.X >= 3314 && corpse.X <= 3814 && + corpse.Y >= 2345 && corpse.Y <= 3095) // Haven island { if (CurProgress == 0) - ContentPackets.SendDisplayHelpTopic(System.From.NetState, 29, false); // HEALING + System.From.Send(new DisplayHelpTopic(29, false)); // HEALING CurProgress++; } @@ -319,26 +340,49 @@ namespace Server.Engines.Quests.Haven { public Container CorpseWithBone{ get; set; } - public override object Message => System.From.Profession == 5 ? 1060755 : 1049362; + public override object Message + { + get + { + if (System.From.Profession == 5) return 1060755; + + /* Use Uzeraan's teleporter to get to the Haunted graveyard.

+ * + * Slay the undead until you find a Daemon Bone. + */ + return 1049362; + } + } public override void OnComplete() { System.AddObjective(new ReturnDaemonBoneObjective()); } - private static bool IsInHavenGraveyard(IPoint2D p) => p.X >= 3391 && p.X <= 3424 && - p.Y >= 2639 && p.Y <= 2664; + public override bool IgnoreYoungProtection(Mobile from) + { + // This restriction continues until the end of the quest + if ((from is Zombie || from is Skeleton) && from.Map == Map.Trammel && from.X >= 3391 && from.X <= 3424 && + from.Y >= 2639 && from.Y <= 2664) // Haven graveyard + return true; - public override bool IgnoreYoungProtection(Mobile from) => - (from is Zombie || from is Skeleton) && from.Map == Map.Trammel && IsInHavenGraveyard(from); + return false; + } - public override bool GetKillEvent(BaseCreature creature, Container corpse) => - base.GetKillEvent(creature, corpse) || UzeraanTurmoilQuest.HasLostDaemonBone(System.From); + public override bool GetKillEvent(BaseCreature creature, Container corpse) + { + if (base.GetKillEvent(creature, corpse)) + return true; + + return UzeraanTurmoilQuest.HasLostDaemonBone(System.From); + } public override void OnKill(BaseCreature creature, Container corpse) { - if ((creature is Zombie || creature is Skeleton) && corpse.Map == Map.Trammel && IsInHavenGraveyard(corpse) && Utility.RandomDouble() < 0.25) - CorpseWithBone = corpse; + if ((creature is Zombie || creature is Skeleton) && corpse.Map == Map.Trammel && corpse.X >= 3391 && + corpse.X <= 3424 && corpse.Y >= 2639 && corpse.Y <= 2664) // Haven graveyard + if (Utility.RandomDouble() < 0.25) + CorpseWithBone = corpse; } public override void ChildDeserialize(GenericReader reader) diff --git a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/UzeraanTurmoilQuest.cs b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/UzeraanTurmoilQuest.cs index 55f19b5ea..e19696888 100644 --- a/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/UzeraanTurmoilQuest.cs +++ b/Projects/Scripts/Engines/Quests/Uzeraan Turmoil/UzeraanTurmoilQuest.cs @@ -62,8 +62,9 @@ namespace Server.Engines.Quests.Haven public override TimeSpan RestartDelay => TimeSpan.MaxValue; public override bool IsTutorial => true; - public override int Picture => - From.Profession switch + public override int Picture + { + get { return From.Profession switch { diff --git a/Projects/Scripts/Engines/Quests/Witch Apprentice/Ingredient.cs b/Projects/Scripts/Engines/Quests/Witch Apprentice/Ingredient.cs index 807b5d3ee..5589c845d 100644 --- a/Projects/Scripts/Engines/Quests/Witch Apprentice/Ingredient.cs +++ b/Projects/Scripts/Engines/Quests/Witch Apprentice/Ingredient.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Server.Mobiles; namespace Server.Engines.Quests.Hag @@ -90,7 +89,12 @@ namespace Server.Engines.Quests.Hag { Ingredient currIngredient = (Ingredient)i; - if (oldIngredients.All(ingredient => ingredient != currIngredient)) + bool found = false; + for (int j = 0; !found && j < oldIngredients.Length; j++) + if (oldIngredients[j] == currIngredient) + found = true; + + if (!found) ingredients[n++] = currIngredient; } @@ -99,4 +103,4 @@ namespace Server.Engines.Quests.Hag return ingredients[index]; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Quests/Witch Apprentice/Items/HagApprenticeCorpse.cs b/Projects/Scripts/Engines/Quests/Witch Apprentice/Items/HagApprenticeCorpse.cs index 39d9d29ad..66e7fba84 100644 --- a/Projects/Scripts/Engines/Quests/Witch Apprentice/Items/HagApprenticeCorpse.cs +++ b/Projects/Scripts/Engines/Quests/Witch Apprentice/Items/HagApprenticeCorpse.cs @@ -46,7 +46,7 @@ namespace Server.Engines.Quests.Hag { int hue = Notoriety.GetHue(NotorietyHandlers.CorpseNotoriety(from, this)); - Packets.SendAsciiMessage(from.NetState, Serial, ItemID, MessageType.Label, hue, 3, "", "a charred corpse"); + from.Send(new AsciiMessage(Serial, ItemID, MessageType.Label, hue, 3, "", "a charred corpse")); } public override void Open(Mobile from, bool checkSelfLoot) @@ -96,4 +96,4 @@ namespace Server.Engines.Quests.Hag int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/Quests/Witch Apprentice/Objectives.cs b/Projects/Scripts/Engines/Quests/Witch Apprentice/Objectives.cs index e715ac8b1..777ab0fa8 100644 --- a/Projects/Scripts/Engines/Quests/Witch Apprentice/Objectives.cs +++ b/Projects/Scripts/Engines/Quests/Witch Apprentice/Objectives.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Server.Items; using Server.Mobiles; @@ -51,7 +50,7 @@ namespace Server.Engines.Quests.Hag Corpse = new HagApprenticeCorpse(); Corpse.MoveToWorld(m_CorpseLocation, map); - Effects.SendLocationEffect(m_CorpseLocation, map, 0x3728, 10); + Effects.SendLocationEffect(m_CorpseLocation, map, 0x3728, 10, 10); Effects.PlaySound(m_CorpseLocation, map, 0x1FE); Mobile imp = new Zeefzorpul(); @@ -67,7 +66,7 @@ namespace Server.Engines.Quests.Hag { if (m?.Deleted == false) { - Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10); + Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10, 10); Effects.PlaySound(m.Location, m.Map, 0x1FE); m.Delete(); @@ -205,7 +204,7 @@ namespace Server.Engines.Quests.Hag Mobile from = System.From; Map map = from.Map; - Effects.SendLocationEffect(ImpLocation, map, 0x3728, 10); + Effects.SendLocationEffect(ImpLocation, map, 0x3728, 10, 10); Effects.PlaySound(ImpLocation, map, 0x1FE); Mobile imp = new Zeefzorpul(); @@ -220,7 +219,7 @@ namespace Server.Engines.Quests.Hag { if (imp is Mobile m && !m.Deleted) { - Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10); + Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10, 10); Effects.PlaySound(m.Location, m.Map, 0x1FE); m.Delete(); @@ -267,7 +266,7 @@ namespace Server.Engines.Quests.Hag for (int i = 0; i < oldIngredients.Length; i++) Ingredients[i] = oldIngredients[i]; - Ingredients[^1] = IngredientInfo.RandomIngredient(oldIngredients); + Ingredients[Ingredients.Length - 1] = IngredientInfo.RandomIngredient(oldIngredients); } else { @@ -280,8 +279,13 @@ namespace Server.Engines.Quests.Hag BlackheartMet = blackheartMet; } - public override object Message => - !BlackheartMet ? Step switch + public FindIngredientObjective() + { + } + + public override object Message + { + get { if (!BlackheartMet) return Step switch @@ -306,13 +310,21 @@ namespace Server.Engines.Quests.Hag */ return 1055055; } - : 1055055; + } - public override int MaxProgress => IngredientInfo.Get(Ingredient).Quantity; + public override int MaxProgress + { + get + { + IngredientInfo info = IngredientInfo.Get(Ingredient); + + return info.Quantity; + } + } public Ingredient[] Ingredients{ get; private set; } - public Ingredient Ingredient => Ingredients[^1]; + public Ingredient Ingredient => Ingredients[Ingredients.Length - 1]; public int Step => Ingredients.Length; public bool BlackheartMet{ get; private set; } @@ -333,14 +345,26 @@ namespace Server.Engines.Quests.Hag } } - public override bool IgnoreYoungProtection(Mobile from) => - !Completed && IngredientInfo.Get(Ingredient).Creatures.Any(t => from.GetType() == t); + public override bool IgnoreYoungProtection(Mobile from) + { + if (Completed) + return false; + + IngredientInfo info = IngredientInfo.Get(Ingredient); + Type fromType = from.GetType(); + + for (int i = 0; i < info.Creatures.Length; i++) + if (fromType == info.Creatures[i]) + return true; + + return false; + } public override void OnKill(BaseCreature creature, Container corpse) { IngredientInfo info = IngredientInfo.Get(Ingredient); - if (info.Creatures.Any(type => creature.GetType() == type)) + for (int i = 0; i < info.Creatures.Length; i++) { Type type = info.Creatures[i]; @@ -351,7 +375,8 @@ namespace Server.Engines.Quests.Hag CurProgress++; - CurProgress++; + break; + } } } diff --git a/Projects/Scripts/Engines/Spawner/Spawner.cs b/Projects/Scripts/Engines/Spawner/Spawner.cs index 2f2326944..e6c0d77e1 100644 --- a/Projects/Scripts/Engines/Spawner/Spawner.cs +++ b/Projects/Scripts/Engines/Spawner/Spawner.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; using Server.Commands; using Server.Items; @@ -23,24 +22,26 @@ namespace Server.Mobiles private InternalTimer m_Timer; private int m_WalkingRange = -1; - [Constructible(AccessLevel.Developer)] - public Spawner() : base(0x1f13) - { - InitSpawn(1, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10), 0, 4); - } - +// [Constructible] public Spawner(int amount, int minDelay, int maxDelay, int team, int homeRange, string spawnedNames) : base(0x1f13) { InitSpawn(amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), team, homeRange); AddEntry(spawnedNames, 100, amount, false); } +// [Constructible] public Spawner(string spawnedName) : base(0x1f13) { InitSpawn(1, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10), 0, 4); AddEntry(spawnedName, 100, 1, false); } + [Constructible(AccessLevel.Developer)] + public Spawner() : base(0x1f13) + { + InitSpawn(1, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10), 0, 4); + } + public Spawner(int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, params string[] spawnedNames) : base(0x1f13) { @@ -70,8 +71,9 @@ namespace Server.Mobiles { m_Count = value; - if (m_Timer != null && IsFull == m_Timer.Running) - DoTimer(); + if (m_Timer != null) + if (!IsFull && !m_Timer.Running || IsFull && m_Timer.Running) + DoTimer(); InvalidateProperties(); } @@ -264,16 +266,20 @@ namespace Server.Mobiles { base.OnSingleClick(from); - LabelTo(from, m_Running ? "[Running]" : "[Off]"); + if (m_Running) + LabelTo(from, "[Running]"); + else + LabelTo(from, "[Off]"); } public void Start() { - if (!m_Running && Entries.Count > 0) - { - m_Running = true; - DoTimer(); - } + if (!m_Running) + if (Entries.Count > 0) + { + m_Running = true; + DoTimer(); + } } public void Stop() @@ -287,7 +293,8 @@ namespace Server.Mobiles public void Defrag() { - Entries ??= new List(); + if (Entries == null) + Entries = new List(); for (int i = 0; i < Entries.Count; ++i) Entries[i].Defrag(this); @@ -295,6 +302,8 @@ namespace Server.Mobiles public void OnTick() { +// DoTimer( m_Spawned.Count >= m_Count ); + if (m_Group) { Defrag(); @@ -305,8 +314,19 @@ namespace Server.Mobiles Respawn(); } else + { Spawn(); + } +/* + if ( m_Running && m_Timer != null ) + { + if ( m_Spawned.Count >= m_Count && m_Timer.Running ) + DoTimer( true ); + else if ( m_Spawned.Count < m_Count && !m_Timer.Running ) + DoTimer( false ); + } +*/ DoTimer(); } @@ -327,7 +347,11 @@ namespace Server.Mobiles if (Entries.Count <= 0 || IsFull) return; - int probsum = Entries.Where(t => !t.IsFull).Sum(t => t.SpawnedProbability); + int probsum = 0; + + for (int i = 0; i < Entries.Count; i++) + if (!Entries[i].IsFull) + probsum += Entries[i].SpawnedProbability; if (probsum <= 0) return; @@ -370,7 +394,9 @@ namespace Server.Mobiles } } else + { props = new string[0, 0]; + } return props; } @@ -435,8 +461,13 @@ namespace Server.Mobiles try { object o = null; + string[] paramargs; + string[] propargs; - string[] propargs = string.IsNullOrEmpty(entry.Properties) ? new string[0] : CommandSystem.Split(entry.Properties.Trim()); + if (string.IsNullOrEmpty(entry.Properties)) + propargs = new string[0]; + else + propargs = CommandSystem.Split(entry.Properties.Trim()); string[,] props = FormatProperties(propargs); @@ -448,7 +479,10 @@ namespace Server.Mobiles return false; } - string[] paramargs = string.IsNullOrEmpty(entry.Parameters) ? new string[0] : entry.Parameters.Trim().Split(' '); + if (string.IsNullOrEmpty(entry.Parameters)) + paramargs = new string[0]; + else + paramargs = entry.Parameters.Trim().Split(' '); ConstructorInfo[] ctors = type.GetConstructors(); @@ -614,9 +648,21 @@ namespace Server.Mobiles LandTile landTile = map.Tiles.GetLandTile(x, y); - return landTile.Z == z && (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Wet) != 0 || - map.Tiles.GetStaticTiles(x, y, true).Any(staticTile => - staticTile.Z == z && (TileData.ItemTable[staticTile.ID & TileData.MaxItemValue].Flags & TileFlag.Wet) != 0); + if (landTile.Z == z && (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Wet) != 0) + return true; + + StaticTile[] staticTiles = map.Tiles.GetStaticTiles(x, y, true); + + for (int i = 0; i < staticTiles.Length; ++i) + { + StaticTile staticTile = staticTiles[i]; + + if (staticTile.Z == z && + (TileData.ItemTable[staticTile.ID & TileData.MaxItemValue].Flags & TileFlag.Wet) != 0) + return true; + } + + return false; } public virtual Map GetSpawnMap() => Map; @@ -931,7 +977,11 @@ namespace Server.Mobiles public InternalTimer(Spawner spawner, TimeSpan delay) : base(delay) { - Priority = spawner.IsFull ? TimerPriority.FiveSeconds : TimerPriority.OneSecond; + if (spawner.IsFull) + Priority = TimerPriority.FiveSeconds; + else + Priority = TimerPriority.OneSecond; + m_Spawner = spawner; } @@ -1100,11 +1150,41 @@ namespace Server.Mobiles bool remove = false; if (e is Item item) - remove |= item.Deleted || item.RootParent is Mobile || item.IsLockedDown || item.IsSecure || item.Spawner == null; + { + if (item.Deleted || item.RootParent is Mobile || item.IsLockedDown || item.IsSecure || + item.Spawner == null) + remove = true; + } else if (e is Mobile m) - remove |= m.Deleted || m.Spawner == null || m is BaseCreature c && (c.Controlled || c.IsStabled); + { + if (m.Deleted) + { + remove = true; + } + else if (m is BaseCreature c) + { + if (c.Controlled || c.IsStabled) + remove = true; +/* + else if ( c.Combatant == null && ( c.GetDistanceToSqrt( Location ) > (c.RangeHome * 4) ) ) + { + //m_Spawned[i].Delete(); + m_Spawned.RemoveAt( i ); + --i; + c.Delete(); + remove = true; + } +*/ + } + else if (m.Spawner == null) + { + remove = true; + } + } else + { remove = true; + } if (remove) { diff --git a/Projects/Scripts/Engines/Spawner/SpawnerGump.cs b/Projects/Scripts/Engines/Spawner/SpawnerGump.cs index 18852a81f..7be5f298d 100644 --- a/Projects/Scripts/Engines/Spawner/SpawnerGump.cs +++ b/Projects/Scripts/Engines/Spawner/SpawnerGump.cs @@ -203,7 +203,7 @@ namespace Server.Mobiles spawner.Start(); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (m_Spawner.Deleted) return; @@ -246,7 +246,7 @@ namespace Server.Mobiles } case 2: //Okay { - CreateArray(info, sender.Mobile, m_Spawner); + CreateArray(info, state.Mobile, m_Spawner); return; } case 3: @@ -261,7 +261,7 @@ namespace Server.Mobiles } case 5: { - CreateArray(info, sender.Mobile, m_Spawner); + CreateArray(info, state.Mobile, m_Spawner); break; } } @@ -282,15 +282,15 @@ namespace Server.Mobiles m_Spawner.RemoveSpawn(entryindex); } - CreateArray(info, sender.Mobile, m_Spawner); + CreateArray(info, state.Mobile, m_Spawner); break; } } if (m_Entry != null && m_Spawner.Entries?.Contains(m_Entry) == true) - sender.Mobile.SendGump(new SpawnerGump(m_Spawner, m_Entry, m_Page)); + state.Mobile.SendGump(new SpawnerGump(m_Spawner, m_Entry, m_Page)); else - sender.Mobile.SendGump(new SpawnerGump(m_Spawner, null, m_Page)); + state.Mobile.SendGump(new SpawnerGump(m_Spawner, null, m_Page)); } } } diff --git a/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatue.cs b/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatue.cs index 840eb354f..98650495c 100644 --- a/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatue.cs +++ b/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatue.cs @@ -185,7 +185,7 @@ namespace Server.Mobiles public void OnRequestedAnimation(Mobile from) { - StatuePackets.SendUpdateStatueAnimation(from.NetState, Serial, 1, m_Animation, m_Frames); + from.Send(new UpdateStatueAnimation(this, 1, m_Animation, m_Frames)); } public override void OnAosSingleClick(Mobile from) @@ -364,14 +364,22 @@ namespace Server.Mobiles { ProcessDelta(); + Packet p = null; + IPooledEnumerable eable = Map.GetClientsInRange(Location); foreach (NetState state in eable) { state.Mobile.ProcessDelta(); - StatuePackets.SendUpdateStatueAnimation(state, Serial, 1, m_Animation, m_Frames); + + if (p == null) + p = Packet.Acquire(new UpdateStatueAnimation(this, 1, m_Animation, m_Frames)); + + state.Send(p); } + Packet.Release(p); + eable.Free(); } } @@ -416,8 +424,9 @@ namespace Server.Mobiles { } - public override int LabelNumber => - (Statue?.StatueType ?? m_Type) switch + public override int LabelNumber + { + get { StatueType t = m_Type; @@ -439,7 +448,13 @@ namespace Server.Mobiles [CommandProperty(AccessLevel.GameMaster)] public StatueType StatueType { - get => Statue?.StatueType ?? m_Type; + get + { + if (Statue != null) + return Statue.StatueType; + + return m_Type; + } set => m_Type = value; } @@ -596,11 +611,18 @@ namespace Server.Mobiles from.SendGump(new CharacterStatueGump(m_Maker, statue, from)); } else if (result == AddonFitResult.Blocked) + { from.SendLocalizedMessage(500269); // You cannot build that there. + } else if (result == AddonFitResult.NotInHouse) + { from.SendLocalizedMessage( 1076192); // Statues can only be placed in houses where you are the owner or co-owner. - else if (result == AddonFitResult.DoorTooClose) from.SendLocalizedMessage(500271); // You cannot build near the door. + } + else if (result == AddonFitResult.DoorTooClose) + { + from.SendLocalizedMessage(500271); // You cannot build near the door. + } } else { @@ -608,9 +630,15 @@ namespace Server.Mobiles } } - public static AddonFitResult CouldFit(Point3D p, Map map, Mobile from, ref BaseHouse house) => - !map.CanFit(p.X, p.Y, p.Z, 20, true) ? AddonFitResult.Blocked : - !BaseAddon.CheckHouse(from, p, map, 20, ref house) ? AddonFitResult.NotInHouse : CheckDoors(p, 20, house); + public static AddonFitResult CouldFit(Point3D p, Map map, Mobile from, ref BaseHouse house) + { + if (!map.CanFit(p.X, p.Y, p.Z, 20, true)) + return AddonFitResult.Blocked; + if (!BaseAddon.CheckHouse(from, p, map, 20, ref house)) + return AddonFitResult.NotInHouse; + + return CheckDoors(p, 20, house); + } public static AddonFitResult CheckDoors(Point3D p, int height, BaseHouse house) { diff --git a/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/Gumps/CharacterStatueGump.cs b/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/Gumps/CharacterStatueGump.cs index 60459b340..48e429d14 100644 --- a/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/Gumps/CharacterStatueGump.cs +++ b/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/Gumps/CharacterStatueGump.cs @@ -66,8 +66,9 @@ namespace Server.Gumps } } - private int GetMaterialNumber(StatueType type, StatueMaterial material) => - material switch + private int GetMaterialNumber(StatueType type, StatueMaterial material) + { + switch (material) { case StatueMaterial.Antique: @@ -125,7 +126,7 @@ namespace Server.Gumps m_Maker?.Delete(); - m_Statue.Sculpt(sender.Mobile); + m_Statue.Sculpt(state.Mobile); } else if (info.ButtonID == (int)Buttons.PosePrev) { @@ -173,11 +174,11 @@ namespace Server.Gumps } else // Close { - sendGump = !m_Statue.Demolish(sender.Mobile); + sendGump = !m_Statue.Demolish(state.Mobile); } if (sendGump) - sender.Mobile.SendGump(new CharacterStatueGump(m_Maker, m_Statue, m_Owner)); + state.Mobile.SendGump(new CharacterStatueGump(m_Maker, m_Statue, m_Owner)); } private enum Buttons diff --git a/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/Packets.cs b/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/Packets.cs index af457b1d9..b13fd47b9 100644 --- a/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/Packets.cs +++ b/Projects/Scripts/Engines/VeteranRewards/Character Statue Maker/Packets.cs @@ -1,25 +1,20 @@ -using Server.Buffers; - namespace Server.Network { - public static class StatuePackets + public class UpdateStatueAnimation : Packet { - public static void SendUpdateStatueAnimation(NetState ns, Serial m, int status, int animation, int frame) + public UpdateStatueAnimation(Mobile m, int status, int animation, int frame) : base(0xBF, 17) { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[17]); - writer.Write((byte)0xBF); // Extended Packet ID - writer.Write((short)17); // Dynamic Length - - writer.Write((short)0x19); - writer.Write((byte)0x5); - writer.Write(m); - writer.Write((short)0xFF); - writer.Write((byte)status); - writer.Write((short)animation); - writer.Write((short)frame); + m_Stream.Write((short)0x11); + m_Stream.Write((short)0x19); + m_Stream.Write((byte)0x5); + m_Stream.Write(m.Serial); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0xFF); + m_Stream.Write((byte)status); + m_Stream.Write((byte)0); + m_Stream.Write((byte)animation); + m_Stream.Write((byte)0); + m_Stream.Write((byte)frame); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Engines/VeteranRewards/RewardOptionGump.cs b/Projects/Scripts/Engines/VeteranRewards/RewardOptionGump.cs index 7c10fd811..4bdd1b2c9 100644 --- a/Projects/Scripts/Engines/VeteranRewards/RewardOptionGump.cs +++ b/Projects/Scripts/Engines/VeteranRewards/RewardOptionGump.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using Server.Network; namespace Server.Gumps @@ -52,7 +51,17 @@ namespace Server.Gumps m_Option.OnOptionSelected(sender.Mobile, info.ButtonID); } - private bool Contains(int chosen) => m_Options?.Any(option => option.ID == chosen) == true; + private bool Contains(int chosen) + { + if (m_Options == null) + return false; + + foreach (RewardOption option in m_Options) + if (option.ID == chosen) + return true; + + return false; + } } public class RewardOption diff --git a/Projects/Scripts/Engines/Virtues/Honor.cs b/Projects/Scripts/Engines/Virtues/Honor.cs index b84c10510..576d0d42d 100644 --- a/Projects/Scripts/Engines/Virtues/Honor.cs +++ b/Projects/Scripts/Engines/Virtues/Honor.cs @@ -342,9 +342,9 @@ namespace Server targetFame / 100.0 * (m_HonorDamage / m_TotalDamage); //Initial honor gain is 100th of the monsters honor if (m_HonorDamage == m_TotalDamage && m_FirstHit == FirstHit.Granted) - dGain *= 1.5; //honor gain is increased alot more if the combat was fully honorable + dGain = dGain * 1.5; //honor gain is increased alot more if the combat was fully honorable else - dGain *= 0.9; + dGain = dGain * 0.9; int gain = Math.Min((int)dGain, 200); diff --git a/Projects/Scripts/Engines/Virtues/VirtueGump.cs b/Projects/Scripts/Engines/Virtues/VirtueGump.cs index 3338479cb..9f9780989 100644 --- a/Projects/Scripts/Engines/Virtues/VirtueGump.cs +++ b/Projects/Scripts/Engines/Virtues/VirtueGump.cs @@ -36,14 +36,14 @@ namespace Server AddPage(1); - Add(new GumpImage(61, 71, 108, GetHueFor(0), "VirtueGumpItem")); // Humility - Add(new GumpImage(123, 46, 112, GetHueFor(4), "VirtueGumpItem")); // Valor - Add(new GumpImage(187, 70, 107, GetHueFor(5), "VirtueGumpItem")); // Honor - Add(new GumpImage(35, 135, 110, GetHueFor(1), "VirtueGumpItem")); // Sacrifice - Add(new GumpImage(211, 133, 105, GetHueFor(2), "VirtueGumpItem")); // Compassion - Add(new GumpImage(61, 195, 111, GetHueFor(3), "VirtueGumpItem")); // Spiritulaity - Add(new GumpImage(186, 195, 109, GetHueFor(6), "VirtueGumpItem")); // Justice - Add(new GumpImage(121, 221, 106, GetHueFor(7), "VirtueGumpItem")); // Honesty + Add(new InternalEntry(61, 71, 108, GetHueFor(0))); // Humility + Add(new InternalEntry(123, 46, 112, GetHueFor(4))); // Valor + Add(new InternalEntry(187, 70, 107, GetHueFor(5))); // Honor + Add(new InternalEntry(35, 135, 110, GetHueFor(1))); // Sacrifice + Add(new InternalEntry(211, 133, 105, GetHueFor(2))); // Compassion + Add(new InternalEntry(61, 195, 111, GetHueFor(3))); // Spiritulaity + Add(new InternalEntry(186, 195, 109, GetHueFor(6))); // Justice + Add(new InternalEntry(121, 221, 106, GetHueFor(7))); // Honesty if (m_Beholder == m_Beheld) { @@ -147,7 +147,7 @@ namespace Server return m_Table[index * 3 + vl]; } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 1 && m_Beholder == m_Beheld) m_Beholder.SendGump(new VirtueStatusGump(m_Beholder)); diff --git a/Projects/Scripts/Engines/Virtues/VirtueInfoGump.cs b/Projects/Scripts/Engines/Virtues/VirtueInfoGump.cs index 71aa4e4ab..f642321a9 100644 --- a/Projects/Scripts/Engines/Virtues/VirtueInfoGump.cs +++ b/Projects/Scripts/Engines/Virtues/VirtueInfoGump.cs @@ -79,7 +79,7 @@ namespace Server AddHtmlLocalized(83, 275, 400, 40, webPage == null ? 1052055 : 1052052); // This virtue is not yet defined. OR -click to learn more (opens webpage) } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { switch (info.ButtonID) { @@ -88,7 +88,7 @@ namespace Server m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, m_Virtue, m_Desc, m_Page)); if (m_Page != null) - Packets.SendLaunchBrowser(sender, m_Page); + state.Send(new LaunchBrowser(m_Page)); //No message about web browser starting on OSI break; } case 2: diff --git a/Projects/Scripts/Engines/Virtues/VirtueStatusGump.cs b/Projects/Scripts/Engines/Virtues/VirtueStatusGump.cs index f1de0b00e..911cc7774 100644 --- a/Projects/Scripts/Engines/Virtues/VirtueStatusGump.cs +++ b/Projects/Scripts/Engines/Virtues/VirtueStatusGump.cs @@ -47,7 +47,7 @@ namespace Server AddButton(280, 43, 4014, 4014, 9); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { switch (info.ButtonID) { diff --git a/Projects/Scripts/Gumps/AdminGump.cs b/Projects/Scripts/Gumps/AdminGump.cs index 81deef6ad..fbc3db4b3 100644 --- a/Projects/Scripts/Gumps/AdminGump.cs +++ b/Projects/Scripts/Gumps/AdminGump.cs @@ -16,7 +16,7 @@ namespace Server.Gumps { public enum AdminGumpPage { - Information_General = 0, + Information_General, Information_Perf, Administer, Clients, @@ -39,8 +39,7 @@ namespace Server.Gumps AccountDetails_Tags, AccountDetails_ChangePassword, AccountDetails_ChangeAccess, - FirewallInfo, - Invalid = -1 + FirewallInfo } public class AdminGump : Gump @@ -588,7 +587,8 @@ namespace Server.Gumps } case AdminGumpPage.Accounts: { - m_List ??= new List(); + if (m_List == null) + m_List = new List(); List rads = state as List; @@ -1182,10 +1182,11 @@ namespace Server.Gumps if (totalBytes > 1000000) return $"{(double)totalBytes / 1048576:F1} MB"; - public static string FormatByteAmount(long totalBytes) => - totalBytes > 1000000000 ? $"{(double)totalBytes / 1073741824:F1} GB" : - totalBytes > 1000000 ? $"{(double)totalBytes / 1048576:F1} MB" : - totalBytes > 1000 ? $"{(double)totalBytes / 1024:F1} KB" : $"{totalBytes} Bytes"; + if (totalBytes > 1000) + return $"{(double)totalBytes / 1024:F1} KB"; + + return $"{totalBytes} Bytes"; + } public static void Initialize() { @@ -1524,7 +1525,7 @@ namespace Server.Gumps { IPAddress[] ips = a.LoginIPs; - if (ips.Length != 0 && ip.Equals(ips[0]) && AccountHandler.IPTable.ContainsKey(ips[0])) + if (ips.Length != 0 && ip == ips[0] && AccountHandler.IPTable.ContainsKey(ips[0])) --AccountHandler.IPTable[ip]; List newList = new List(ips); @@ -1607,19 +1608,30 @@ namespace Server.Gumps { case 0: { - AdminGumpPage page = index switch - { - 0 => AdminGumpPage.Information_General, - 1 => AdminGumpPage.Administer, - 2 => AdminGumpPage.Clients, - 3 => AdminGumpPage.Accounts, - 4 => AdminGumpPage.Firewall, - 5 => AdminGumpPage.Information_Perf, - _ => AdminGumpPage.Invalid, - }; + AdminGumpPage page; - if (page == AdminGumpPage.Invalid) - return; + switch (index) + { + case 0: + page = AdminGumpPage.Information_General; + break; + case 1: + page = AdminGumpPage.Administer; + break; + case 2: + page = AdminGumpPage.Clients; + break; + case 3: + page = AdminGumpPage.Accounts; + break; + case 4: + page = AdminGumpPage.Firewall; + break; + case 5: + page = AdminGumpPage.Information_Perf; + break; + default: return; + } from.SendGump(new AdminGump(from, page)); break; @@ -1939,7 +1951,12 @@ namespace Server.Gumps hasAccess = true; else for (int j = 0; !hasAccess && j < a.Length; ++j) - hasAccess |= a[j]?.AccessLevel >= level; + { + Mobile m = a[j]; + + if (m?.AccessLevel >= level) + hasAccess = true; + } if (!hasAccess) { @@ -2483,7 +2500,11 @@ namespace Server.Gumps } case 31: // View all inactive accounts { - List results = Accounts.GetAccounts().Cast().Where(acct => acct.Inactive).Cast().ToList(); + List results = new List(); + + foreach (Account acct in Accounts.GetAccounts()) + if (acct.Inactive) + results.Add(acct); if (results.Count == 1) from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, @@ -2496,7 +2517,11 @@ namespace Server.Gumps } case 32: // View all banned accounts { - List results = Accounts.GetAccounts().Cast().Where(acct => acct.Banned).Cast().ToList(); + List results = new List(); + + foreach (Account acct in Accounts.GetAccounts()) + if (acct.Banned) + results.Add(acct); if (results.Count == 1) from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, @@ -2527,7 +2552,8 @@ namespace Server.Gumps bool hasHouse = false; for (int i = 0; i < acct.Length && !hasHouse; ++i) - hasHouse |= acct[i] != null && BaseHouse.HasHouse(acct[i]); + if (acct[i] != null && BaseHouse.HasHouse(acct[i])) + hasHouse = true; if (!hasHouse) newRads.Add(acct); @@ -2946,7 +2972,8 @@ namespace Server.Gumps if (check.AccessLevel > accessLevel) accessLevel = check.AccessLevel; - online |= check.NetState != null; + if (check.NetState != null) + online = true; } } diff --git a/Projects/Scripts/Gumps/BaseConfirmGump.cs b/Projects/Scripts/Gumps/BaseConfirmGump.cs index f0825c745..eeb878c96 100644 --- a/Projects/Scripts/Gumps/BaseConfirmGump.cs +++ b/Projects/Scripts/Gumps/BaseConfirmGump.cs @@ -50,14 +50,14 @@ namespace Server.Gumps public virtual int LabelNumber // Are you sure you wish to select this? => 1074975; - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == (int)Buttons.Confirm) { if (info.IsSwitched((int)Buttons.Break)) - Confirm(sender.Mobile); + Confirm(state.Mobile); else - Refuse(sender.Mobile); + Refuse(state.Mobile); } } diff --git a/Projects/Scripts/Gumps/CategorizedAddGump.cs b/Projects/Scripts/Gumps/CategorizedAddGump.cs index cd796494c..f3e49ed66 100644 --- a/Projects/Scripts/Gumps/CategorizedAddGump.cs +++ b/Projects/Scripts/Gumps/CategorizedAddGump.cs @@ -110,7 +110,7 @@ namespace Server.Gumps public override string Caption => Title; - public static CAGCategory Root => m_Root ??= Load("Data/objects.xml"); + public static CAGCategory Root => m_Root ?? (m_Root = Load("Data/objects.xml")); public override void OnClick(Mobile from, int page) { @@ -184,8 +184,7 @@ namespace Server.Gumps public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; - private static bool PrevLabel = false; - private static bool NextLabel = false; + private static bool PrevLabel = false, NextLabel = false; private static readonly int PrevLabelOffsetX = PrevWidth + 1; private static readonly int PrevLabelOffsetY = 0; @@ -334,7 +333,7 @@ namespace Server.Gumps } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { Mobile from = m_Owner; diff --git a/Projects/Scripts/Gumps/ClientGump.cs b/Projects/Scripts/Gumps/ClientGump.cs index df05ab3b9..357851480 100644 --- a/Projects/Scripts/Gumps/ClientGump.cs +++ b/Projects/Scripts/Gumps/ClientGump.cs @@ -128,13 +128,13 @@ namespace Server.Gumps to.SendGump(new ClientGump(to, m_State, te == null ? "" : te.Text)); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (m_State == null) return; Mobile focus = m_State.Mobile; - Mobile from = sender.Mobile; + Mobile from = state.Mobile; if (focus == null) { diff --git a/Projects/Scripts/Gumps/CommentsGump.cs b/Projects/Scripts/Gumps/CommentsGump.cs index 3c7928d89..f884de9b6 100644 --- a/Projects/Scripts/Gumps/CommentsGump.cs +++ b/Projects/Scripts/Gumps/CommentsGump.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Server.Accounting; using Server.Network; +using Server.Prompts; using Server.Targeting; namespace Server.Gumps @@ -77,12 +78,12 @@ namespace Server.Gumps from.SendGump(new CommentsGump((Account)m.Account)); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 0x7F) { - sender.Mobile.SendMessage("Enter the text for the account comment (or press [Esc] to cancel):"); - sender.Mobile.Prompt = new CommentPrompt(m_Acct); + state.Mobile.SendMessage("Enter the text for the account comment (or press [Esc] to cancel):"); + state.Mobile.Prompt = new CommentPrompt(m_Acct); } } diff --git a/Projects/Scripts/Gumps/ConfirmHouseResize.cs b/Projects/Scripts/Gumps/ConfirmHouseResize.cs index a3fc0fd20..c572e08e6 100644 --- a/Projects/Scripts/Gumps/ConfirmHouseResize.cs +++ b/Projects/Scripts/Gumps/ConfirmHouseResize.cs @@ -46,7 +46,7 @@ namespace Server.Gumps AddHtmlLocalized(240, 250, 170, 20, 1011012, 0x7FFF); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 1 && !m_House.Deleted) { @@ -100,7 +100,7 @@ namespace Server.Gumps } else { - Item toGive; + Item toGive = null; if (m_House.IsAosRules) { diff --git a/Projects/Scripts/Gumps/Go/GoGump.cs b/Projects/Scripts/Gumps/Go/GoGump.cs index 3ef2fff1f..ec26774c9 100644 --- a/Projects/Scripts/Gumps/Go/GoGump.cs +++ b/Projects/Scripts/Gumps/Go/GoGump.cs @@ -187,9 +187,9 @@ namespace Server.Gumps from.SendGump(new GoGump(0, from, tree, branch)); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { - Mobile from = sender.Mobile; + Mobile from = state.Mobile; switch (info.ButtonID) { diff --git a/Projects/Scripts/Gumps/Guilds/DeclareFealtyGump.cs b/Projects/Scripts/Gumps/Guilds/DeclareFealtyGump.cs index f20bc3225..b6ade1cfa 100644 --- a/Projects/Scripts/Gumps/Guilds/DeclareFealtyGump.cs +++ b/Projects/Scripts/Gumps/Guilds/DeclareFealtyGump.cs @@ -20,7 +20,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 400, 100, 35, 1011012); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadMember(m_Mobile, m_Guild)) return; @@ -38,7 +38,7 @@ namespace Server.Gumps Mobile m = m_List[index]; if (m?.Deleted == false) - sender.Mobile.GuildFealty = m; + state.Mobile.GuildFealty = m; } } } diff --git a/Projects/Scripts/Gumps/Guilds/GrantGuildTitleGump.cs b/Projects/Scripts/Gumps/Guilds/GrantGuildTitleGump.cs index c49d5123a..1af757d3b 100644 --- a/Projects/Scripts/Gumps/Guilds/GrantGuildTitleGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GrantGuildTitleGump.cs @@ -20,7 +20,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 400, 100, 35, 1011012); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildAbbrvPrompt.cs b/Projects/Scripts/Gumps/Guilds/GuildAbbrvPrompt.cs index 24c5cdda1..f0f94a1c0 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildAbbrvPrompt.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildAbbrvPrompt.cs @@ -1,4 +1,5 @@ using Server.Guilds; +using Server.Prompts; namespace Server.Gumps { diff --git a/Projects/Scripts/Gumps/Guilds/GuildAcceptWarGump.cs b/Projects/Scripts/Gumps/Guilds/GuildAcceptWarGump.cs index 61a26ce31..021acd651 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildAcceptWarGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildAcceptWarGump.cs @@ -20,7 +20,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 400, 100, 35, 1011012); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildAdminCandidatesGump.cs b/Projects/Scripts/Gumps/Guilds/GuildAdminCandidatesGump.cs index 402f4b0fc..018f390ef 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildAdminCandidatesGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildAdminCandidatesGump.cs @@ -21,7 +21,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 400, 100, 35, 1013077); // Refuse } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildCandidatesGump.cs b/Projects/Scripts/Gumps/Guilds/GuildCandidatesGump.cs index f5a032390..60ce45109 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildCandidatesGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildCandidatesGump.cs @@ -17,7 +17,7 @@ namespace Server.Gumps AddHtmlLocalized(55, 400, 300, 35, 1011120); // Return to the main menu. } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadMember(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildChangeTypeGump.cs b/Projects/Scripts/Gumps/Guilds/GuildChangeTypeGump.cs index 54d5df27b..c5eb72a9a 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildChangeTypeGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildChangeTypeGump.cs @@ -41,7 +41,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 360, 150, 30, 1011012); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (Guild.NewGuildSystem && !BaseGuildGump.IsLeader(m_Mobile, m_Guild) || !Guild.NewGuildSystem && GuildGump.BadLeader(m_Mobile, m_Guild)) diff --git a/Projects/Scripts/Gumps/Guilds/GuildCharterGump.cs b/Projects/Scripts/Gumps/Guilds/GuildCharterGump.cs index a5fe1e55c..16662a04f 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildCharterGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildCharterGump.cs @@ -41,7 +41,7 @@ namespace Server.Gumps AddHtml(55, 220, 300, 20, website); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadMember(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildCharterPrompt.cs b/Projects/Scripts/Gumps/Guilds/GuildCharterPrompt.cs index e158e8b60..e3f265ba1 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildCharterPrompt.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildCharterPrompt.cs @@ -1,4 +1,5 @@ using Server.Guilds; +using Server.Prompts; namespace Server.Gumps { diff --git a/Projects/Scripts/Gumps/Guilds/GuildDeclarePeaceGump.cs b/Projects/Scripts/Gumps/Guilds/GuildDeclarePeaceGump.cs index fc18d39ac..00370e69d 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildDeclarePeaceGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildDeclarePeaceGump.cs @@ -20,7 +20,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 400, 100, 35, 1011012); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildDeclareWarGump.cs b/Projects/Scripts/Gumps/Guilds/GuildDeclareWarGump.cs index 3bb53678a..c60b6096c 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildDeclareWarGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildDeclareWarGump.cs @@ -23,7 +23,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 400, 100, 35, 1011012); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildDeclareWarPrompt.cs b/Projects/Scripts/Gumps/Guilds/GuildDeclareWarPrompt.cs index 8a18d46c6..9b17dbaa0 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildDeclareWarPrompt.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildDeclareWarPrompt.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Server.Guilds; +using Server.Prompts; namespace Server.Gumps { diff --git a/Projects/Scripts/Gumps/Guilds/GuildDismissGump.cs b/Projects/Scripts/Gumps/Guilds/GuildDismissGump.cs index 5ff961a47..f86a03209 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildDismissGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildDismissGump.cs @@ -20,7 +20,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 400, 100, 35, 1011012); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildNamePrompt.cs b/Projects/Scripts/Gumps/Guilds/GuildNamePrompt.cs index 59a5ddddd..292a23b72 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildNamePrompt.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildNamePrompt.cs @@ -1,4 +1,5 @@ using Server.Guilds; +using Server.Prompts; namespace Server.Gumps { diff --git a/Projects/Scripts/Gumps/Guilds/GuildRejectWarGump.cs b/Projects/Scripts/Gumps/Guilds/GuildRejectWarGump.cs index 5a15e9c85..16761e975 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildRejectWarGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildRejectWarGump.cs @@ -20,7 +20,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 400, 100, 35, 1011012); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildRescindDeclarationGump.cs b/Projects/Scripts/Gumps/Guilds/GuildRescindDeclarationGump.cs index 866cb889e..2a648b5d4 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildRescindDeclarationGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildRescindDeclarationGump.cs @@ -20,7 +20,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 400, 100, 35, 1011012); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildRosterGump.cs b/Projects/Scripts/Gumps/Guilds/GuildRosterGump.cs index 36aa21b66..5588678a3 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildRosterGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildRosterGump.cs @@ -17,7 +17,7 @@ namespace Server.Gumps AddHtmlLocalized(55, 400, 300, 35, 1011120); // Return to the main menu. } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadMember(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildTitlePrompt.cs b/Projects/Scripts/Gumps/Guilds/GuildTitlePrompt.cs index a098d9eeb..35e4655d0 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildTitlePrompt.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildTitlePrompt.cs @@ -1,4 +1,5 @@ using Server.Guilds; +using Server.Prompts; namespace Server.Gumps { diff --git a/Projects/Scripts/Gumps/Guilds/GuildWarAdminGump.cs b/Projects/Scripts/Gumps/Guilds/GuildWarAdminGump.cs index 9b0dcba48..64d284013 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildWarAdminGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildWarAdminGump.cs @@ -63,7 +63,7 @@ namespace Server.Gumps AddHtmlLocalized(55, 400, 400, 35, 1011104); // Return to the previous menu. } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildWarGump.cs b/Projects/Scripts/Gumps/Guilds/GuildWarGump.cs index a56f1f1aa..d2304dc45 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildWarGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildWarGump.cs @@ -86,7 +86,7 @@ namespace Server.Gumps } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadMember(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/GuildWebsitePrompt.cs b/Projects/Scripts/Gumps/Guilds/GuildWebsitePrompt.cs index 487901fc9..16aae7a12 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildWebsitePrompt.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildWebsitePrompt.cs @@ -1,4 +1,5 @@ using Server.Guilds; +using Server.Prompts; namespace Server.Gumps { diff --git a/Projects/Scripts/Gumps/Guilds/GuildmasterGump.cs b/Projects/Scripts/Gumps/Guilds/GuildmasterGump.cs index ff183da60..29a7be63a 100644 --- a/Projects/Scripts/Gumps/Guilds/GuildmasterGump.cs +++ b/Projects/Scripts/Gumps/Guilds/GuildmasterGump.cs @@ -82,7 +82,7 @@ namespace Server.Gumps AddHtmlLocalized(335, 360, 100, 30, 1011441); // EXIT } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (GuildGump.BadLeader(m_Mobile, m_Guild)) return; diff --git a/Projects/Scripts/Gumps/Guilds/New Guild System/BaseGuildGump.cs b/Projects/Scripts/Gumps/Guilds/New Guild System/BaseGuildGump.cs index 408630817..bab0308bf 100644 --- a/Projects/Scripts/Gumps/Guilds/New Guild System/BaseGuildGump.cs +++ b/Projects/Scripts/Gumps/Guilds/New Guild System/BaseGuildGump.cs @@ -1,4 +1,3 @@ -using System.Linq; using Server.Gumps; using Server.Misc; using Server.Mobiles; @@ -41,7 +40,9 @@ namespace Server.Guilds public override void OnResponse(NetState sender, RelayInfo info) { - if (!(sender.Mobile is PlayerMobile pm &&IsMember(pm, guild))) + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if (!IsMember(pm, guild)) return; switch (info.ButtonID) @@ -84,12 +85,30 @@ namespace Server.Guilds s = s.ToLower(); - if (s.Any(c => (c < 'a' || c > 'z') && (c < '0' || c > '9') && exceptions.All(exception => exception != c))) - return false; + for (int i = 0; i < s.Length; ++i) + { + char c = s[i]; + + if ((c < 'a' || c > 'z') && (c < '0' || c > '9')) + { + bool except = false; + + for (int j = 0; !except && j < exceptions.Length; j++) + if (c == exceptions[j]) + except = true; + + if (!except) + return false; + } + } string[] disallowed = ProfanityProtection.Disallowed; - return disallowed.All(t => s.IndexOf(t) == -1); + for (int i = 0; i < disallowed.Length; i++) + if (s.IndexOf(disallowed[i]) != -1) + return false; + + return true; } public void AddHtmlText(int x, int y, int width, int height, TextDefinition text, bool back, bool scroll) diff --git a/Projects/Scripts/Gumps/Guilds/New Guild System/OtherGuildInfo.cs b/Projects/Scripts/Gumps/Guilds/New Guild System/OtherGuildInfo.cs index 1bea09ecc..6ae8e735d 100644 --- a/Projects/Scripts/Gumps/Guilds/New Guild System/OtherGuildInfo.cs +++ b/Projects/Scripts/Gumps/Guilds/New Guild System/OtherGuildInfo.cs @@ -108,7 +108,9 @@ namespace Server.Guilds if (PendingWar) { if (war.WarRequester) + { number = 1063027; //
You have challenged this guild to war!
+ } else { number = 1062969; //
This guild has challenged you to war!
@@ -209,7 +211,9 @@ namespace Server.Guilds if (war?.WarRequester == false && activeWar == null) { if (!playerRank.GetFlag(RankFlags.ControlWarStatus)) + { pm.SendLocalizedMessage(1063440); // You don't have permission to negotiate wars. + } else if (alliance != null && alliance.Leader != guild) { pm.SendLocalizedMessage(1063239, @@ -272,7 +276,9 @@ namespace Server.Guilds if (war?.WarRequester == false && activeWar == null) { if (!playerRank.GetFlag(RankFlags.ControlWarStatus)) + { pm.SendLocalizedMessage(1063440); // You don't have permission to negotiate wars. + } else if (alliance != null && alliance.Leader != guild) { pm.SendLocalizedMessage(1063239, @@ -281,7 +287,9 @@ namespace Server.Guilds alliance.Leader.Name); // You need to negotiate via ~1_val~ instead. } else + { pm.SendGump(new WarDeclarationGump(pm, guild, otherGuild)); + } } break; @@ -291,7 +299,9 @@ namespace Server.Guilds if (war != null) { if (!playerRank.GetFlag(RankFlags.ControlWarStatus)) + { pm.SendLocalizedMessage(1063440); // You don't have permission to negotiate wars. + } else if (alliance != null && alliance.Leader != guild) { pm.SendLocalizedMessage(1063239, @@ -314,7 +324,9 @@ namespace Server.Guilds case 8: //Surrender { if (!playerRank.GetFlag(RankFlags.ControlWarStatus)) + { pm.SendLocalizedMessage(1063440); // You don't have permission to negotiate wars. + } else if (alliance != null && alliance.Leader != guild) { pm.SendLocalizedMessage(1063239, @@ -372,7 +384,9 @@ namespace Server.Guilds if (war == null && activeWar == null) { if (!playerRank.GetFlag(RankFlags.ControlWarStatus)) + { pm.SendLocalizedMessage(1063440); // You don't have permission to negotiate wars. + } else if (alliance != null && alliance.Leader != guild) { pm.SendLocalizedMessage(1063239, @@ -388,7 +402,9 @@ namespace Server.Guilds otherAlliance.Leader.Name); // You need to negotiate via ~1_val~ instead. } else + { pm.SendGump(new WarDeclarationGump(pm, guild, m_Other)); + } } break; @@ -403,10 +419,14 @@ namespace Server.Guilds if (alliance == null) { if (!playerRank.GetFlag(RankFlags.AllianceControl)) + { pm.SendLocalizedMessage(1070747); // You don't have permission to create an alliance. + } else if (Faction.Find(guild.Leader) != Faction.Find(m_Other.Leader)) + { pm.SendLocalizedMessage( 1070758); // You cannot propose an alliance to a guild with a different faction allegiance. + } else if (otherAlliance != null) { if (otherAlliance.IsPendingMember(m_Other)) @@ -416,9 +436,13 @@ namespace Server.Guilds pm.SendLocalizedMessage(1063426, m_Other.Name); // ~1_val~ already belongs to an alliance. } else if (m_Other.AcceptedWars.Count > 0 || m_Other.PendingWars.Count > 0) + { pm.SendLocalizedMessage(1063427, m_Other.Name); // ~1_val~ is currently involved in a guild war. + } else if (guild.AcceptedWars.Count > 0 || guild.PendingWars.Count > 0) + { pm.SendLocalizedMessage(1063427, guild.Name); // ~1_val~ is currently involved in a guild war. + } else { pm.SendLocalizedMessage(1063439); // Enter a name for the new alliance: @@ -433,10 +457,14 @@ namespace Server.Guilds else { if (!playerRank.GetFlag(RankFlags.AllianceControl)) + { pm.SendLocalizedMessage(1063436); // You don't have permission to negotiate an alliance. + } else if (alliance.Leader != guild) + { pm.SendLocalizedMessage(1063239, $"{guild.Name}\t{alliance.Name}"); // ~1_val~ is not the leader of the ~2_val~ alliance. + } else if (otherAlliance != null) { if (otherAlliance.IsPendingMember(m_Other)) @@ -446,15 +474,23 @@ namespace Server.Guilds pm.SendLocalizedMessage(1063426, m_Other.Name); // ~1_val~ already belongs to an alliance. } else if (alliance.IsPendingMember(guild)) + { pm.SendLocalizedMessage(1063416, guild.Name); // ~1_val~ is currently considering another alliance proposal. + } else if (m_Other.AcceptedWars.Count > 0 || m_Other.PendingWars.Count > 0) + { pm.SendLocalizedMessage(1063427, m_Other.Name); // ~1_val~ is currently involved in a guild war. + } else if (guild.AcceptedWars.Count > 0 || guild.PendingWars.Count > 0) + { pm.SendLocalizedMessage(1063427, guild.Name); // ~1_val~ is currently involved in a guild war. + } else if (Faction.Find(guild.Leader) != Faction.Find(m_Other.Leader)) + { pm.SendLocalizedMessage( 1070758); // You cannot propose an alliance to a guild with a different faction allegiance. + } else { pm.SendLocalizedMessage(1070750, @@ -481,7 +517,9 @@ namespace Server.Guilds case 11: //Leave Alliance { if (!playerRank.GetFlag(RankFlags.AllianceControl)) + { pm.SendLocalizedMessage(1063436); // You don't have permission to negotiate an alliance. + } else if (alliance?.IsMember(guild) == true) { guild.Alliance = null; //Calls alliance.Removeguild @@ -497,10 +535,14 @@ namespace Server.Guilds case 12: //Remove Guild from alliance { if (!playerRank.GetFlag(RankFlags.AllianceControl)) + { pm.SendLocalizedMessage(1063436); // You don't have permission to negotiate an alliance. + } else if (alliance != null && alliance.Leader != guild) + { pm.SendLocalizedMessage(1063239, $"{guild.Name}\t{alliance.Name}"); // ~1_val~ is not the leader of the ~2_val~ alliance. + } else if (alliance?.IsMember(guild) == true && alliance.IsMember(m_Other)) { m_Other.Alliance = null; @@ -515,10 +557,14 @@ namespace Server.Guilds case 13: //Promote to Alliance leader { if (!playerRank.GetFlag(RankFlags.AllianceControl)) + { pm.SendLocalizedMessage(1063436); // You don't have permission to negotiate an alliance. + } else if (alliance != null && alliance.Leader != guild) + { pm.SendLocalizedMessage(1063239, $"{guild.Name}\t{alliance.Name}"); // ~1_val~ is not the leader of the ~2_val~ alliance. + } else if (alliance?.IsMember(guild) == true && alliance.IsMember(m_Other)) { pm.SendLocalizedMessage(1063434, @@ -532,7 +578,9 @@ namespace Server.Guilds case 14: //Withdraw Request { if (!playerRank.GetFlag(RankFlags.AllianceControl)) + { pm.SendLocalizedMessage(1063436); // You don't have permission to negotiate an alliance. + } else if (alliance != null && alliance.Leader == guild && alliance.IsPendingMember(m_Other)) { m_Other.Alliance = null; @@ -544,7 +592,9 @@ namespace Server.Guilds case 15: //Deny Alliance Request { if (!playerRank.GetFlag(RankFlags.AllianceControl)) + { pm.SendLocalizedMessage(1063436); // You don't have permission to negotiate an alliance. + } else if (alliance != null && otherAlliance != null && alliance.Leader == m_Other && otherAlliance.IsPendingMember(guild)) { @@ -559,7 +609,9 @@ namespace Server.Guilds case 16: //Accept Alliance Request { if (!playerRank.GetFlag(RankFlags.AllianceControl)) + { pm.SendLocalizedMessage(1063436); // You don't have permission to negotiate an alliance. + } else if (otherAlliance != null && otherAlliance.Leader == m_Other && otherAlliance.IsPendingMember(guild)) { @@ -588,15 +640,20 @@ namespace Server.Guilds if (!IsMember(from, guild) || alliance != null) return; + RankDefinition playerRank = pm.GuildRank; if (!playerRank.GetFlag(RankFlags.AllianceControl)) + { pm.SendLocalizedMessage(1070747); // You don't have permission to create an alliance. + } else if (Faction.Find(guild.Leader) != Faction.Find(m_Other.Leader)) + { //Notes about this: OSI only cares/checks when proposing, you can change your faction all you want later. pm.SendLocalizedMessage( 1070758); // You cannot propose an alliance to a guild with a different faction allegiance. + } else if (otherAlliance != null) { if (otherAlliance.IsPendingMember(m_Other)) @@ -606,20 +663,30 @@ namespace Server.Guilds pm.SendLocalizedMessage(1063426, m_Other.Name); // ~1_val~ already belongs to an alliance. } else if (m_Other.AcceptedWars.Count > 0 || m_Other.PendingWars.Count > 0) + { pm.SendLocalizedMessage(1063427, m_Other.Name); // ~1_val~ is currently involved in a guild war. + } else if (guild.AcceptedWars.Count > 0 || guild.PendingWars.Count > 0) + { pm.SendLocalizedMessage(1063427, guild.Name); // ~1_val~ is currently involved in a guild war. + } else { string name = Utility.FixHtml(text.Trim()); if (!CheckProfanity(name)) + { pm.SendLocalizedMessage(1070886); // That alliance name is not allowed. + } else if (name.Length > Guild.NameLimit) + { pm.SendLocalizedMessage(1070887, Guild.NameLimit.ToString()); // An alliance name cannot exceed ~1_val~ characters in length. + } else if (AllianceInfo.Alliances.ContainsKey(name.ToLower())) + { pm.SendLocalizedMessage(1063428); // That alliance name is not available. + } else { pm.SendLocalizedMessage(1070750, diff --git a/Projects/Scripts/Gumps/HouseDemolishGump.cs b/Projects/Scripts/Gumps/HouseDemolishGump.cs index 5a2e11f5a..1ec189cff 100644 --- a/Projects/Scripts/Gumps/HouseDemolishGump.cs +++ b/Projects/Scripts/Gumps/HouseDemolishGump.cs @@ -1,3 +1,4 @@ +using Server.Accounting; using Server.Guilds; using Server.Items; using Server.Multis; @@ -31,14 +32,13 @@ namespace Server.Gumps AddImageTiled(10, 40, 400, 200, 2624); AddAlphaRegion(10, 40, 400, 200); - AddHtmlLocalized(10, 40, 400, 200, 1061795, 32512, false, true); - /* You are about to demolish your house. - * You will be refunded the house's value directly to your bank box. - * All items in the house will remain behind and can be freely picked up by anyone. - * Once the house is demolished, anyone can attempt to place a new house on the vacant land. - * This action will not un-condemn any other houses on your account, nor will it end your 7-day waiting period (if it applies to you). - * Are you sure you wish to continue? - */ + AddHtmlLocalized(10, 40, 400, 200, 1061795, 32512, false, true); /* You are about to demolish your house. + * You will be refunded the house's value directly to your bank box. + * All items in the house will remain behind and can be freely picked up by anyone. + * Once the house is demolished, anyone can attempt to place a new house on the vacant land. + * This action will not un-condemn any other houses on your account, nor will it end your 7-day waiting period (if it applies to you). + * Are you sure you wish to continue? + */ AddImageTiled(10, 250, 400, 20, 2624); AddAlphaRegion(10, 250, 400, 20); @@ -50,7 +50,7 @@ namespace Server.Gumps AddHtmlLocalized(240, 250, 170, 20, 1011012, 32767); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 1 && !m_House.Deleted) { diff --git a/Projects/Scripts/Gumps/HouseGump.cs b/Projects/Scripts/Gumps/HouseGump.cs index c940627bd..c3a65e70a 100644 --- a/Projects/Scripts/Gumps/HouseGump.cs +++ b/Projects/Scripts/Gumps/HouseGump.cs @@ -54,12 +54,12 @@ namespace Server.Gumps } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (m_House.Deleted) return; - Mobile from = sender.Mobile; + Mobile from = state.Mobile; from.SendGump(new HouseGump(from, m_House)); } @@ -125,12 +125,12 @@ namespace Server.Gumps } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (m_House.Deleted) return; - Mobile from = sender.Mobile; + Mobile from = state.Mobile; if (m_List != null && info.ButtonID == 1) // Remove now { diff --git a/Projects/Scripts/Gumps/HouseGumpAOS.cs b/Projects/Scripts/Gumps/HouseGumpAOS.cs index 22800fd7f..a29c9454e 100644 --- a/Projects/Scripts/Gumps/HouseGumpAOS.cs +++ b/Projects/Scripts/Gumps/HouseGumpAOS.cs @@ -672,92 +672,92 @@ namespace Server.Gumps if (e == null) return; - int cost = e.Cost - house.Price; + int cost = e.Cost - house.Price; - if (cost > 0) - { - if (Banker.Withdraw(from, cost)) + if (cost > 0) { - from.SendLocalizedMessage(1060398, - cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + if (Banker.Withdraw(from, cost)) + { + from.SendLocalizedMessage(1060398, + cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } + else + { + from.SendLocalizedMessage( + 1061624); // You do not have enough funds in your bank to cover the difference between your old house and your new one. + return; + } } - else + else if (cost < 0) { - from.SendLocalizedMessage( - 1061624); // You do not have enough funds in your bank to cover the difference between your old house and your new one. + if (Banker.Deposit(from, -cost)) + from.SendLocalizedMessage(1060397, + (-cost).ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. + else + return; + } + + BaseHouse newHouse = e.ConstructHouse(from); + + if (newHouse != null) + { + newHouse.Price = e.Cost; + + house.MoveAllToCrate(); + + newHouse.Friends = new List(house.Friends); + newHouse.CoOwners = new List(house.CoOwners); + newHouse.Bans = new List(house.Bans); + newHouse.Access = new List(house.Access); + newHouse.BuiltOn = house.BuiltOn; + newHouse.LastTraded = house.LastTraded; + newHouse.Public = house.Public; + + newHouse.VendorInventories.AddRange(house.VendorInventories); + house.VendorInventories.Clear(); + + foreach (VendorInventory inventory in newHouse.VendorInventories) inventory.House = newHouse; + + newHouse.InternalizedVendors.AddRange(house.InternalizedVendors); + house.InternalizedVendors.Clear(); + + foreach (Mobile mobile in newHouse.InternalizedVendors) + if (mobile is PlayerVendor vendor) + vendor.House = newHouse; + else if (mobile is PlayerBarkeeper barkeeper) + barkeeper.House = newHouse; + + if (house.MovingCrate != null) + { + newHouse.MovingCrate = house.MovingCrate; + newHouse.MovingCrate.House = newHouse; + house.MovingCrate = null; + } + + List items = house.GetItems(); + List mobiles = house.GetMobiles(); + + newHouse.MoveToWorld( + new Point3D(house.X + house.ConvertOffsetX, house.Y + house.ConvertOffsetY, + house.Z + house.ConvertOffsetZ), house.Map); + house.Delete(); + + foreach (Item item in items) item.Location = newHouse.BanLocation; + + foreach (Mobile mobile in mobiles) mobile.Location = newHouse.BanLocation; + + /* You have successfully replaced your original house with a new house. + * The value of the replaced house has been deposited into your bank box. + * All of the items in your original house have been relocated to a Moving Crate in the new house. + * Any deed-based house add-ons have been converted back into deeds. + * Vendors and barkeeps in the house, if any, have been stored in the Moving Crate as well. + * Use the Get Vendor context-sensitive menu option on your character to retrieve them. + * These containers can be used to re-create the vendor in a new location. + * Any barkeepers have been converted into deeds. + */ + from.SendGump(new NoticeGump(1060637, 30720, 1060012, 32512, 420, 280)); return; } - } - else if (cost < 0) - { - if (Banker.Deposit(from, -cost)) - from.SendLocalizedMessage(1060397, - (-cost).ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. - else - return; - } - - BaseHouse newHouse = e.ConstructHouse(from); - - if (newHouse != null) - { - newHouse.Price = e.Cost; - - house.MoveAllToCrate(); - - newHouse.Friends = new List(house.Friends); - newHouse.CoOwners = new List(house.CoOwners); - newHouse.Bans = new List(house.Bans); - newHouse.Access = new List(house.Access); - newHouse.BuiltOn = house.BuiltOn; - newHouse.LastTraded = house.LastTraded; - newHouse.Public = house.Public; - - newHouse.VendorInventories.AddRange(house.VendorInventories); - house.VendorInventories.Clear(); - - foreach (VendorInventory inventory in newHouse.VendorInventories) inventory.House = newHouse; - - newHouse.InternalizedVendors.AddRange(house.InternalizedVendors); - house.InternalizedVendors.Clear(); - - foreach (Mobile mobile in newHouse.InternalizedVendors) - if (mobile is PlayerVendor vendor) - vendor.House = newHouse; - else if (mobile is PlayerBarkeeper barkeeper) - barkeeper.House = newHouse; - - if (house.MovingCrate != null) - { - newHouse.MovingCrate = house.MovingCrate; - newHouse.MovingCrate.House = newHouse; - house.MovingCrate = null; - } - - List items = house.GetItems(); - List mobiles = house.GetMobiles(); - - newHouse.MoveToWorld( - new Point3D(house.X + house.ConvertOffsetX, house.Y + house.ConvertOffsetY, - house.Z + house.ConvertOffsetZ), house.Map); - house.Delete(); - - foreach (Item item in items) item.Location = newHouse.BanLocation; - - foreach (Mobile mobile in mobiles) mobile.Location = newHouse.BanLocation; - - /* You have successfully replaced your original house with a new house. - * The value of the replaced house has been deposited into your bank box. - * All of the items in your original house have been relocated to a Moving Crate in the new house. - * Any deed-based house add-ons have been converted back into deeds. - * Vendors and barkeeps in the house, if any, have been stored in the Moving Crate as well. - * Use the Get Vendor context-sensitive menu option on your character to retrieve them. - * These containers can be used to re-create the vendor in a new location. - * Any barkeepers have been converted into deeds. - */ - from.SendGump(new NoticeGump(1060637, 30720, 1060012, 32512, 420, 280)); - return; - } } from.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Security, from, house)); diff --git a/Projects/Scripts/Gumps/HouseTransferGump.cs b/Projects/Scripts/Gumps/HouseTransferGump.cs index 4dce5b90d..fc3926804 100644 --- a/Projects/Scripts/Gumps/HouseTransferGump.cs +++ b/Projects/Scripts/Gumps/HouseTransferGump.cs @@ -53,7 +53,7 @@ namespace Server.Gumps AddHtmlLocalized(240, 250, 170, 20, 1011012, 32767); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 1 && !m_House.Deleted) m_House.EndConfirmTransfer(m_From, m_To); diff --git a/Projects/Scripts/Gumps/PetResurrectGump.cs b/Projects/Scripts/Gumps/PetResurrectGump.cs index 87e53b6df..494505e9e 100644 --- a/Projects/Scripts/Gumps/PetResurrectGump.cs +++ b/Projects/Scripts/Gumps/PetResurrectGump.cs @@ -33,12 +33,12 @@ namespace Server.Gumps AddButton(110, 105, 0x819, 0x818, 0x2); // Cancel } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (m_Pet.Deleted || !m_Pet.IsBonded || !m_Pet.IsDeadPet) return; - Mobile from = sender.Mobile; + Mobile from = state.Mobile; if (info.ButtonID == 1) { diff --git a/Projects/Scripts/Gumps/PlayerVendorGumps.cs b/Projects/Scripts/Gumps/PlayerVendorGumps.cs index 86ce1c962..93c2e375b 100644 --- a/Projects/Scripts/Gumps/PlayerVendorGumps.cs +++ b/Projects/Scripts/Gumps/PlayerVendorGumps.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using Server.HuePickers; using Server.Items; using Server.Mobiles; using Server.Network; @@ -36,9 +37,9 @@ namespace Server.Gumps AddHtmlLocalized(152, 130, 100, 24, 1011036); // OKAY } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { - Mobile from = sender.Mobile; + Mobile from = state.Mobile; if (!m_Vendor.CanInteractWith(from, false)) return; @@ -134,9 +135,9 @@ namespace Server.Gumps AddLabel(300, 48, 0, ((int)(days / 12.0)).ToString()); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { - Mobile from = sender.Mobile; + Mobile from = state.Mobile; if (!m_Vendor.CanInteractWith(from, true)) return; @@ -475,12 +476,12 @@ namespace Server.Gumps } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (m_Vendor.Deleted) return; - Mobile from = sender.Mobile; + Mobile from = state.Mobile; if (m_Vendor is PlayerVendor vendor && !vendor.CanInteractWith(from, true)) return; @@ -580,11 +581,11 @@ namespace Server.Gumps if (category.Layer == Layer.Hair) { - new PVHairHuePicker(false, m_Vendor, from).SendTo(sender); + new PVHairHuePicker(false, m_Vendor, from).SendTo(state); } else if (category.Layer == Layer.FacialHair) { - new PVHairHuePicker(true, m_Vendor, from).SendTo(sender); + new PVHairHuePicker(true, m_Vendor, from).SendTo(state); } else { @@ -603,7 +604,7 @@ namespace Server.Gumps } if (item != null) - new PVHuePicker(item, m_Vendor, from).SendTo(sender); + new PVHuePicker(item, m_Vendor, from).SendTo(state); } } } diff --git a/Projects/Scripts/Gumps/PolymorphGump.cs b/Projects/Scripts/Gumps/PolymorphGump.cs index 11a2e88d8..4d6717b53 100644 --- a/Projects/Scripts/Gumps/PolymorphGump.cs +++ b/Projects/Scripts/Gumps/PolymorphGump.cs @@ -120,7 +120,7 @@ namespace Server.Gumps } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 1 && info.Switches.Length > 0) { diff --git a/Projects/Scripts/Gumps/Props/PropsGump.cs b/Projects/Scripts/Gumps/Props/PropsGump.cs index e0f2baaf5..57b9acb48 100644 --- a/Projects/Scripts/Gumps/Props/PropsGump.cs +++ b/Projects/Scripts/Gumps/Props/PropsGump.cs @@ -153,7 +153,9 @@ namespace Server.Gumps if (parent != null) { - m_Stack ??= new Stack(); + if (m_Stack == null) + m_Stack = new Stack(); + m_Stack.Push(parent); } @@ -279,9 +281,9 @@ namespace Server.Gumps } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { - Mobile from = sender.Mobile; + Mobile from = state.Mobile; if (!BaseCommand.IsAccessible(from, m_Object)) { diff --git a/Projects/Scripts/Gumps/Props/SetBodyGump.cs b/Projects/Scripts/Gumps/Props/SetBodyGump.cs index dedc3082a..43f1ee237 100644 --- a/Projects/Scripts/Gumps/Props/SetBodyGump.cs +++ b/Projects/Scripts/Gumps/Props/SetBodyGump.cs @@ -127,6 +127,7 @@ namespace Server.Gumps switch (index) { default: + case 0: type = ModelBodyType.Monsters; list = m_Monster; break; @@ -203,17 +204,24 @@ namespace Server.Gumps if (((Body)bodyID).IsEmpty) continue; - List list = oldEntry.BodyType switch - { - ModelBodyType.Monsters => m_Monster, - ModelBodyType.Animals => m_Animal, - ModelBodyType.Sea => m_Sea, - ModelBodyType.Human => m_Human, - _ => null - }; + List list; - if (list == null) - return; + switch (oldEntry.BodyType) + { + default: continue; + case ModelBodyType.Monsters: + list = m_Monster; + break; + case ModelBodyType.Animals: + list = m_Animal; + break; + case ModelBodyType.Sea: + list = m_Sea; + break; + case ModelBodyType.Human: + list = m_Human; + break; + } int itemID = ShrinkTable.Lookup(bodyID, -1); @@ -279,7 +287,7 @@ namespace Server.Gumps int v = Name.CompareTo(comp.Name); if (v == 0) - v = Body.CompareTo(comp.Body); + Body.CompareTo(comp.Body); return v; } diff --git a/Projects/Scripts/Gumps/Props/SetGump.cs b/Projects/Scripts/Gumps/Props/SetGump.cs index 4d0b11904..918eab063 100644 --- a/Projects/Scripts/Gumps/Props/SetGump.cs +++ b/Projects/Scripts/Gumps/Props/SetGump.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Reflection; using Server.Commands; +using Server.HuePickers; using Server.Network; namespace Server.Gumps diff --git a/Projects/Scripts/Gumps/Props/SetObjectGump.cs b/Projects/Scripts/Gumps/Props/SetObjectGump.cs index ef3895bbd..30d79a680 100644 --- a/Projects/Scripts/Gumps/Props/SetObjectGump.cs +++ b/Projects/Scripts/Gumps/Props/SetObjectGump.cs @@ -4,6 +4,7 @@ using System.Reflection; using Server.Commands; using Server.Commands.Generic; using Server.Network; +using Server.Prompts; namespace Server.Gumps { diff --git a/Projects/Scripts/Gumps/RunebookGump.cs b/Projects/Scripts/Gumps/RunebookGump.cs index 9f259ff9c..845ed5628 100644 --- a/Projects/Scripts/Gumps/RunebookGump.cs +++ b/Projects/Scripts/Gumps/RunebookGump.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Server.Items; using Server.Multis; using Server.Network; +using Server.Prompts; using Server.Spells.Chivalry; using Server.Spells.Fourth; using Server.Spells.Seventh; @@ -202,9 +203,9 @@ namespace Server.Gumps public static bool HasSpell(Mobile from, int spellID) => Spellbook.Find(from, spellID)?.HasSpell(spellID) == true; - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { - Mobile from = sender.Mobile; + Mobile from = state.Mobile; if (Book.Deleted || !from.InRange(Book.GetWorldLocation(), Core.ML ? 3 : 1) || !DesignContext.Check(from)) { diff --git a/Projects/Scripts/Gumps/SetSecureLevelGump.cs b/Projects/Scripts/Gumps/SetSecureLevelGump.cs index a52c8667e..149491e73 100644 --- a/Projects/Scripts/Gumps/SetSecureLevelGump.cs +++ b/Projects/Scripts/Gumps/SetSecureLevelGump.cs @@ -60,7 +60,7 @@ namespace Server.Gumps public int GetFirstID(SecureLevel level) => m_Info.Level == level ? 4006 : 4005; - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { var level = info.ButtonID switch { @@ -74,12 +74,12 @@ namespace Server.Gumps if (m_Info.Level == level) { - sender.Mobile.SendLocalizedMessage(1061281); // Access level unchanged. + state.Mobile.SendLocalizedMessage(1061281); // Access level unchanged. } else { m_Info.Level = level; - sender.Mobile.SendLocalizedMessage(1061280); // New access level set. + state.Mobile.SendLocalizedMessage(1061280); // New access level set. } } } diff --git a/Projects/Scripts/Gumps/SkillsGump.cs b/Projects/Scripts/Gumps/SkillsGump.cs index 2d3543009..31a4c881d 100644 --- a/Projects/Scripts/Gumps/SkillsGump.cs +++ b/Projects/Scripts/Gumps/SkillsGump.cs @@ -306,6 +306,7 @@ namespace Server.Gumps switch (sk.Lock) { default: + case SkillLock.Up: buttonID1 = 0x983; buttonID2 = 0x983; xOffset = 6; diff --git a/Projects/Scripts/Gumps/VendorRentalGumps.cs b/Projects/Scripts/Gumps/VendorRentalGumps.cs index 4a80fa64e..01c140d51 100644 --- a/Projects/Scripts/Gumps/VendorRentalGumps.cs +++ b/Projects/Scripts/Gumps/VendorRentalGumps.cs @@ -1,5 +1,6 @@ using Server.Items; using Server.Network; +using Server.Prompts; using Server.Mobiles; using Server.Targeting; using Server.Multis; diff --git a/Projects/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs b/Projects/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs index 39281307d..e93873910 100644 --- a/Projects/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs +++ b/Projects/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Events.Halloween; using Server.Items; using Server.Mobiles; @@ -70,7 +69,9 @@ namespace Server.Engines.Events if (twin.Deleted) return; - m_Items.AddRange(m_From.Items.Where(item => item.Layer != Layer.Backpack && item.Layer != Layer.Mount && item.Layer != Layer.Bank)); + foreach (Item item in m_From.Items) + if (item.Layer != Layer.Backpack && item.Layer != Layer.Mount && item.Layer != Layer.Bank) + m_Items.Add(item); if (m_Items.Count > 0) { diff --git a/Projects/Scripts/Items/Addons/BallotBox.cs b/Projects/Scripts/Items/Addons/BallotBox.cs index 8888d0e93..941e8037f 100644 --- a/Projects/Scripts/Items/Addons/BallotBox.cs +++ b/Projects/Scripts/Items/Addons/BallotBox.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Server.Gumps; using Server.Multis; using Server.Network; +using Server.Prompts; namespace Server.Items { diff --git a/Projects/Scripts/Items/Addons/ElvenSpinningwheelEastAddon.cs b/Projects/Scripts/Items/Addons/ElvenSpinningwheelEastAddon.cs index 4cbc53e4e..69945e6d2 100644 --- a/Projects/Scripts/Items/Addons/ElvenSpinningwheelEastAddon.cs +++ b/Projects/Scripts/Items/Addons/ElvenSpinningwheelEastAddon.cs @@ -26,8 +26,14 @@ namespace Server.Items m_Timer.Start(); foreach (AddonComponent c in Components) - if (c.ItemID == 0x2DD9 || c.ItemID == 0x101C || c.ItemID == 0x10A4) - ++c.ItemID; + switch (c.ItemID) + { + case 0x2DD9: + case 0x101C: + case 0x10A4: + ++c.ItemID; + break; + } } public override void Serialize(GenericWriter writer) @@ -63,8 +69,15 @@ namespace Server.Items m_Timer = null; foreach (AddonComponent c in Components) - if (c.ItemID == 0x1016 || c.ItemID == 0x101A || c.ItemID == 0x101D || c.ItemID == 0x10A5) - --c.ItemID; + switch (c.ItemID) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: + --c.ItemID; + break; + } callback?.Invoke(this, from, hue); } @@ -121,4 +134,4 @@ namespace Server.Items int version = reader.ReadEncodedInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Addons/ElvenSpinningwheelSouthAddon.cs b/Projects/Scripts/Items/Addons/ElvenSpinningwheelSouthAddon.cs index 8d5d5f2cb..39bd60ec8 100644 --- a/Projects/Scripts/Items/Addons/ElvenSpinningwheelSouthAddon.cs +++ b/Projects/Scripts/Items/Addons/ElvenSpinningwheelSouthAddon.cs @@ -26,8 +26,15 @@ namespace Server.Items m_Timer.Start(); foreach (AddonComponent c in Components) - if (c.ItemID == 0x1015 || c.ItemID == 0x1019 || c.ItemID == 0x101C || c.ItemID == 0x10A4) - ++c.ItemID; + switch (c.ItemID) + { + case 0x1015: + case 0x1019: + case 0x101C: + case 0x10A4: + ++c.ItemID; + break; + } } public override void Serialize(GenericWriter writer) @@ -64,8 +71,15 @@ namespace Server.Items m_Timer = null; foreach (AddonComponent c in Components) - if (c.ItemID == 0x1016 || c.ItemID == 0x101A || c.ItemID == 0x101D || c.ItemID == 0x10A5) - --c.ItemID; + switch (c.ItemID) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: + --c.ItemID; + break; + } callback?.Invoke(this, from, hue); } @@ -122,4 +136,4 @@ namespace Server.Items int version = reader.ReadEncodedInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Addons/FlourMillEastAddon.cs b/Projects/Scripts/Items/Addons/FlourMillEastAddon.cs index 2f9071dfc..e5c597386 100644 --- a/Projects/Scripts/Items/Addons/FlourMillEastAddon.cs +++ b/Projects/Scripts/Items/Addons/FlourMillEastAddon.cs @@ -130,10 +130,11 @@ namespace Server.Items { List components = Components; + int[][] stageTable = m_StageTable; + for (int i = 0; i < components.Count; ++i) { - AddonComponent component = components[i]; - if (component == null) + if (!(components[i] is AddonComponent component)) continue; int[] itemTable = FindItemTable(component.ItemID); @@ -209,4 +210,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Addons/FlourMillSouthAddon.cs b/Projects/Scripts/Items/Addons/FlourMillSouthAddon.cs index e3602112a..a158ec628 100644 --- a/Projects/Scripts/Items/Addons/FlourMillSouthAddon.cs +++ b/Projects/Scripts/Items/Addons/FlourMillSouthAddon.cs @@ -118,10 +118,11 @@ namespace Server.Items { List components = Components; + int[][] stageTable = m_StageTable; + for (int i = 0; i < components.Count; ++i) { - AddonComponent component = components[i]; - if (component == null) + if (!(components[i] is AddonComponent component)) continue; int[] itemTable = FindItemTable(component.ItemID); @@ -197,4 +198,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Addons/JackOLantern.cs b/Projects/Scripts/Items/Addons/JackOLantern.cs index 80d34f308..d72b6383e 100644 --- a/Projects/Scripts/Items/Addons/JackOLantern.cs +++ b/Projects/Scripts/Items/Addons/JackOLantern.cs @@ -39,7 +39,15 @@ namespace Server.Items public override bool ShareHue => false; - private AddonComponent GetComponent(int itemID, int hue) => new AddonComponent(itemID) {Hue = hue, Name = "jack-o-lantern"}; + private AddonComponent GetComponent(int itemID, int hue) + { + AddonComponent ac = new AddonComponent(itemID); + + ac.Hue = hue; + ac.Name = "jack-o-lantern"; + + return ac; + } public override void Serialize(GenericWriter writer) { @@ -58,23 +66,17 @@ namespace Server.Items Timer.DelayCall(TimeSpan.Zero, delegate { for (int i = 0; i < Components.Count; ++i) - { - AddonComponent ac = Components[i]; - if (ac?.Hue == 2118) + if (Components[i] is AddonComponent ac && ac.Hue == 2118) ac.Hue = 1161; - } }); if (version <= 1) Timer.DelayCall(TimeSpan.Zero, delegate { for (int i = 0; i < Components.Count; ++i) - { - AddonComponent ac = Components[i]; - if (ac != null) + if (Components[i] is AddonComponent ac) ac.Name = "jack-o-lantern"; - } }); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Addons/SpinningwheelEastAddon.cs b/Projects/Scripts/Items/Addons/SpinningwheelEastAddon.cs index e1dff197f..d85c4fd9b 100644 --- a/Projects/Scripts/Items/Addons/SpinningwheelEastAddon.cs +++ b/Projects/Scripts/Items/Addons/SpinningwheelEastAddon.cs @@ -34,8 +34,15 @@ namespace Server.Items m_Timer.Start(); foreach (AddonComponent c in Components) - if (c.ItemID == 0x1015 || c.ItemID == 0x1019 || c.ItemID == 0x101C || c.ItemID == 0x10A4) - ++c.ItemID; + switch (c.ItemID) + { + case 0x1015: + case 0x1019: + case 0x101C: + case 0x10A4: + ++c.ItemID; + break; + } } public override void Serialize(GenericWriter writer) @@ -72,8 +79,15 @@ namespace Server.Items m_Timer = null; foreach (AddonComponent c in Components) - if (c.ItemID == 0x1016 || c.ItemID == 0x101A || c.ItemID == 0x101D || c.ItemID == 0x10A5) - --c.ItemID; + switch (c.ItemID) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: + --c.ItemID; + break; + } callback?.Invoke(this, from, hue); } @@ -130,4 +144,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Addons/SpinningwheelSouthAddon.cs b/Projects/Scripts/Items/Addons/SpinningwheelSouthAddon.cs index 1123fea2f..a79769d39 100644 --- a/Projects/Scripts/Items/Addons/SpinningwheelSouthAddon.cs +++ b/Projects/Scripts/Items/Addons/SpinningwheelSouthAddon.cs @@ -26,8 +26,15 @@ namespace Server.Items m_Timer.Start(); foreach (AddonComponent c in Components) - if (c.ItemID == 0x1015 || c.ItemID == 0x1019 || c.ItemID == 0x101C || c.ItemID == 0x10A4) - ++c.ItemID; + switch (c.ItemID) + { + case 0x1015: + case 0x1019: + case 0x101C: + case 0x10A4: + ++c.ItemID; + break; + } } public override void Serialize(GenericWriter writer) @@ -64,8 +71,15 @@ namespace Server.Items m_Timer = null; foreach (AddonComponent c in Components) - if (c.ItemID == 0x1016 || c.ItemID == 0x101A || c.ItemID == 0x101D || c.ItemID == 0x10A5) - --c.ItemID; + switch (c.ItemID) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: + --c.ItemID; + break; + } callback?.Invoke(this, from, hue); } @@ -122,4 +136,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Aquarium/Aquarium.cs b/Projects/Scripts/Items/Aquarium/Aquarium.cs index 09e7fa1a7..c7247e0da 100644 --- a/Projects/Scripts/Items/Aquarium/Aquarium.cs +++ b/Projects/Scripts/Items/Aquarium/Aquarium.cs @@ -597,7 +597,8 @@ namespace Server.Items UpdateWaterState(); // reward - m_RewardAvailable |= LiveCreatures > 0; + if (LiveCreatures > 0) + m_RewardAvailable = true; } else { @@ -605,12 +606,12 @@ namespace Server.Items if (OptimalState && LiveCreatures < MaxLiveCreatures) if (Utility.RandomDouble() < 0.005 * LiveCreatures) { - BaseFish fish; - int message; + BaseFish fish = null; + int message = 0; switch (Utility.Random(6)) { - default: + case 0: { message = 1074371; // Brine shrimp have hatched overnight in the tank. fish = new BrineShrimp(); diff --git a/Projects/Scripts/Items/Armor/BaseArmor.cs b/Projects/Scripts/Items/Armor/BaseArmor.cs index 81a69037c..59fd460df 100644 --- a/Projects/Scripts/Items/Armor/BaseArmor.cs +++ b/Projects/Scripts/Items/Armor/BaseArmor.cs @@ -436,8 +436,9 @@ namespace Server.Items BaseEnergyResistance + GetProtOffset() + GetResourceAttrs().ArmorEnergyResist + m_EnergyBonus; [CommandProperty(AccessLevel.GameMaster)] - public ArmorBodyType BodyPosition => - Layer switch + public ArmorBodyType BodyPosition + { + get { return Layer switch { @@ -1143,7 +1144,8 @@ namespace Server.Items if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) SkillBonuses = new AosSkillBonuses(this, reader); - PlayerConstructed |= GetSaveFlag(flags, SaveFlag.PlayerConstructed); + if (GetSaveFlag(flags, SaveFlag.PlayerConstructed)) + PlayerConstructed = true; break; } @@ -1269,7 +1271,8 @@ namespace Server.Items } } - SkillBonuses ??= new AosSkillBonuses(this); + if (SkillBonuses == null) + SkillBonuses = new AosSkillBonuses(this); Mobile m = Parent as Mobile; @@ -1296,11 +1299,17 @@ namespace Server.Items m?.CheckStatTimers(); - PlayerConstructed |= version < 7; // we don't know, so, assume it's crafted + if (version < 7) + PlayerConstructed = true; // we don't know, so, assume it's crafted } - public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) => - Ethic.CheckTrade(@from, to, newOwner, this) && base.AllowSecureTrade(@from, to, newOwner, accepted); + public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) + { + if (!Ethic.CheckTrade(from, to, newOwner, this)) + return false; + + return base.AllowSecureTrade(from, to, newOwner, accepted); + } public override bool CanEquip(Mobile from) { @@ -1365,10 +1374,19 @@ namespace Server.Items return base.CanEquip(from); } - public override bool CheckPropertyConfliction(Mobile m) => - base.CheckPropertyConfliction(m) || (Layer == Layer.Pants - ? m.FindItemOnLayer(Layer.InnerLegs) != null - : Layer == Layer.Shirt && m.FindItemOnLayer(Layer.InnerTorso) != null); + public override bool CheckPropertyConfliction(Mobile m) + { + if (base.CheckPropertyConfliction(m)) + return true; + + if (Layer == Layer.Pants) + return m.FindItemOnLayer(Layer.InnerLegs) != null; + + if (Layer == Layer.Shirt) + return m.FindItemOnLayer(Layer.InnerTorso) != null; + + return false; + } public override bool OnEquip(Mobile from) { @@ -1459,9 +1477,25 @@ namespace Server.Items } } - public override bool AllowEquippedCast(Mobile from) => base.AllowEquippedCast(@from) || Attributes.SpellChanneling != 0; + public override bool AllowEquippedCast(Mobile from) + { + if (base.AllowEquippedCast(from)) + return true; - public virtual int GetLuckBonus() => CraftResources.GetInfo(m_Resource)?.AttributeInfo?.ArmorLuck ?? 0; + return Attributes.SpellChanneling != 0; + } + + public virtual int GetLuckBonus() + { + CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); + + CraftAttributeInfo attrInfo = resInfo?.AttributeInfo; + + if (attrInfo == null) + return 0; + + return attrInfo.ArmorLuck; + } public override void GetProperties(ObjectPropertyList list) { @@ -1631,7 +1665,9 @@ namespace Server.Items if (attrs.Count == 0 && Crafter == null && Name != null) return; - EquipmentPackets.SendDisplayEquipmentInfo(from.NetState, this, number, m_Crafter, false, attrs); + EquipmentInfo eqInfo = new EquipmentInfo(number, m_Crafter, false, attrs.ToArray()); + + from.Send(new DisplayEquipmentInfo(this, eqInfo)); } [Flags] diff --git a/Projects/Scripts/Items/Armor/Glasses/ElvenGlasses.cs b/Projects/Scripts/Items/Armor/Glasses/ElvenGlasses.cs index d16ce0287..9f51f6393 100644 --- a/Projects/Scripts/Items/Armor/Glasses/ElvenGlasses.cs +++ b/Projects/Scripts/Items/Armor/Glasses/ElvenGlasses.cs @@ -1,5 +1,3 @@ -using System; - namespace Server.Items { public class ElvenGlasses : BaseArmor @@ -122,14 +120,16 @@ namespace Server.Items SaveFlag flags = (SaveFlag)reader.ReadInt(); - WeaponAttributes = GetSaveFlag(flags, SaveFlag.WeaponAttributes) ? new AosWeaponAttributes(this, reader) : new AosWeaponAttributes(this); + if (GetSaveFlag(flags, SaveFlag.WeaponAttributes)) + WeaponAttributes = new AosWeaponAttributes(this, reader); + else + WeaponAttributes = new AosWeaponAttributes(this); } - [Flags] private enum SaveFlag { None = 0x00000000, WeaponAttributes = 0x00000001 } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Body Parts/Head.cs b/Projects/Scripts/Items/Body Parts/Head.cs index a8d26d885..96086f183 100644 --- a/Projects/Scripts/Items/Body Parts/Head.cs +++ b/Projects/Scripts/Items/Body Parts/Head.cs @@ -33,8 +33,9 @@ namespace Server.Items [CommandProperty(AccessLevel.GameMaster)] public HeadType HeadType{ get; set; } - public override string DefaultName => - PlayerName == null ? base.DefaultName : HeadType switch + public override string DefaultName + { + get { if (PlayerName == null) return base.DefaultName; diff --git a/Projects/Scripts/Items/Books/BaseBook.cs b/Projects/Scripts/Items/Books/BaseBook.cs index 67392e12d..754cabba2 100644 --- a/Projects/Scripts/Items/Books/BaseBook.cs +++ b/Projects/Scripts/Items/Books/BaseBook.cs @@ -57,17 +57,19 @@ namespace Server.Items if (content == null) { - Pages = new BookPageInfo[Math.Min(pageCount, 255)]; + Pages = new BookPageInfo[pageCount]; for (int i = 0; i < Pages.Length; ++i) Pages[i] = new BookPageInfo(); } else + { Pages = content.Copy(); + } } // Intended for defined books only - public BaseBook(int itemID, bool writable) : this(itemID, 0, writable) + public BaseBook(int itemID, bool writable) : this(itemID, 0) { } @@ -228,7 +230,12 @@ namespace Server.Items Pages[i] = new BookPageInfo(reader); } else - Pages = content?.Copy() ?? new BookPageInfo[0]; + { + if (content != null) + Pages = content.Copy(); + else + Pages = new BookPageInfo[0]; + } break; } @@ -247,7 +254,14 @@ namespace Server.Items Pages[i] = new BookPageInfo(reader); } else - Pages = DefaultContent?.Copy() ?? new BookPageInfo[0]; + { + BookContent content = DefaultContent; + + if (content != null) + Pages = content.Copy(); + else + Pages = new BookPageInfo[0]; + } break; } @@ -293,8 +307,8 @@ namespace Server.Items Author = from.Name; } - BookPackets.SendBookHeader(from.NetState, from, this); - BookPackets.SendBookPageDetails(from.NetState, this); + from.Send(new BookHeader(from, this)); + from.Send(new BookPageDetails(this)); } public static void Initialize() @@ -336,14 +350,14 @@ namespace Server.Items if (titleLength > 60) return; - string title = pvSrc.ReadStringSafe(titleLength); + string title = pvSrc.ReadUTF8StringSafe(titleLength); int authorLength = pvSrc.ReadUInt16(); if (authorLength > 30) return; - string author = pvSrc.ReadStringSafe(authorLength); + string author = pvSrc.ReadUTF8StringSafe(authorLength); book.Title = Utility.FixHtml(title); book.Author = Utility.FixHtml(author); @@ -366,23 +380,31 @@ namespace Server.Items { int index = pvSrc.ReadUInt16(); - if (index < 1 || index > book.PagesCount) - return; + if (index >= 1 && index <= book.PagesCount) + { + --index; - --index; + int lineCount = pvSrc.ReadUInt16(); - int lineCount = pvSrc.ReadUInt16(); + if (lineCount <= 8) + { + string[] lines = new string[lineCount]; - if (lineCount > 8) - return; + for (int j = 0; j < lineCount; ++j) + if ((lines[j] = pvSrc.ReadUTF8StringSafe()).Length >= 80) + return; - string[] lines = new string[lineCount]; - - for (int j = 0; j < lineCount; ++j) - if ((lines[j] = pvSrc.ReadUTF8StringSafe()).Length >= 80) + book.Pages[index].Lines = lines; + } + else + { return; - - book.Pages[index].Lines = lines; + } + } + else + { + return; + } } } @@ -396,4 +418,58 @@ namespace Server.Items Content = 0x08 } } + + public sealed class BookPageDetails : Packet + { + public BookPageDetails(BaseBook book) : base(0x66) + { + EnsureCapacity(256); + + m_Stream.Write(book.Serial); + m_Stream.Write((ushort)book.PagesCount); + + for (int i = 0; i < book.PagesCount; ++i) + { + BookPageInfo page = book.Pages[i]; + + m_Stream.Write((ushort)(i + 1)); + m_Stream.Write((ushort)page.Lines.Length); + + for (int j = 0; j < page.Lines.Length; ++j) + { + byte[] buffer = Utility.UTF8.GetBytes(page.Lines[j]); + + m_Stream.Write(buffer, 0, buffer.Length); + m_Stream.Write((byte)0); + } + } + } + } + + public sealed class BookHeader : Packet + { + public BookHeader(Mobile from, BaseBook book) : base(0xD4) + { + string title = book.Title ?? ""; + string author = book.Author ?? ""; + + byte[] titleBuffer = Utility.UTF8.GetBytes(title); + byte[] authorBuffer = Utility.UTF8.GetBytes(author); + + EnsureCapacity(15 + titleBuffer.Length + authorBuffer.Length); + + m_Stream.Write(book.Serial); + m_Stream.Write(true); + m_Stream.Write(book.Writable && from.InRange(book.GetWorldLocation(), 1)); + m_Stream.Write((ushort)book.PagesCount); + + m_Stream.Write((ushort)(titleBuffer.Length + 1)); + m_Stream.Write(titleBuffer, 0, titleBuffer.Length); + m_Stream.Write((byte)0); // terminate + + m_Stream.Write((ushort)(authorBuffer.Length + 1)); + m_Stream.Write(authorBuffer, 0, authorBuffer.Length); + m_Stream.Write((byte)0); // terminate + } + } } diff --git a/Projects/Scripts/Items/Books/BrownBook.cs b/Projects/Scripts/Items/Books/BrownBook.cs index 611c134ba..f6900edf3 100644 --- a/Projects/Scripts/Items/Books/BrownBook.cs +++ b/Projects/Scripts/Items/Books/BrownBook.cs @@ -13,8 +13,8 @@ namespace Server.Items } [Constructible] - public BrownBook(string title, string author, int pageCount, bool writable) : - base(0xFEF, title, author, pageCount, writable) + public BrownBook(string title, string author, int pageCount, bool writable) : base(0xFEF, title, author, pageCount, + writable) { } @@ -41,4 +41,4 @@ namespace Server.Items writer.Write(0); // version } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Books/Packets.cs b/Projects/Scripts/Items/Books/Packets.cs deleted file mode 100644 index 49a78fc2d..000000000 --- a/Projects/Scripts/Items/Books/Packets.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using Server.Buffers; -using Server.Items; - -namespace Server.Network -{ - public static class BookPackets - { - public static void SendBookPageDetails(NetState ns, BaseBook book) - { - if (ns == null) - return; - - // 80 chars per line (240 bytes) - // 8 lines per page - // Max: 77049 bytes - int length = 9; - - for (int i = 0; i < book.PagesCount; i++) - length += 1926 * book.Pages[i].Lines.Length; - - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0x66); // Packet ID - writer.Position += 2; // Dynamic Length - - writer.Write(book.Serial); - writer.Write((ushort)book.PagesCount); - - for (int i = 0; i < book.PagesCount; i++) - { - BookPageInfo page = book.Pages[i]; - length = Math.Min(page.Lines.Length, 8); - - writer.Write((ushort)(i + 1)); - writer.Write((ushort)length); - - for (int j = 0; j < length; j++) - { - string line = page.Lines[j]; - writer.WriteUTF8Null(line); - } - } - - writer.Position = 1; - writer.Write((ushort)writer.WrittenCount); - - ns.Send(writer.Span); - } - - public static void SendBookHeader(NetState ns, Mobile from, BaseBook book) - { - if (ns == null) - return; - - string title = book.Title ?? ""; - string author = book.Author ?? ""; - - int length = 17 + title.Length + author.Length; - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xD4); // Packet ID - writer.Position += 2; // Dynamic Length - - writer.Write(book.Serial); - writer.Write((byte)0x1); // true - writer.Write(book.Writable && from.InRange(book.GetWorldLocation(), 1)); - writer.Write((ushort)book.PagesCount); - - writer.Write((ushort)title.Length + 1); - writer.WriteAsciiNull(title); - - writer.Write((ushort)author.Length + 1); - writer.WriteAsciiNull(author); - - writer.Position = 1; - writer.Write((ushort)writer.WrittenCount); - - ns.Send(writer.Span); - } - } -} diff --git a/Projects/Scripts/Items/Books/RedBook.cs b/Projects/Scripts/Items/Books/RedBook.cs index d0ddb7bc7..2ee8b7d15 100644 --- a/Projects/Scripts/Items/Books/RedBook.cs +++ b/Projects/Scripts/Items/Books/RedBook.cs @@ -13,8 +13,8 @@ namespace Server.Items } [Constructible] - public RedBook(string title, string author, int pageCount, bool writable) : - base(0xFF1, title, author, pageCount, writable) + public RedBook(string title, string author, int pageCount, bool writable) : base(0xFF1, title, author, pageCount, + writable) { } @@ -41,4 +41,4 @@ namespace Server.Items writer.Write(0); // version } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Books/TanBook.cs b/Projects/Scripts/Items/Books/TanBook.cs index ef604c743..5be5297b0 100644 --- a/Projects/Scripts/Items/Books/TanBook.cs +++ b/Projects/Scripts/Items/Books/TanBook.cs @@ -13,8 +13,8 @@ namespace Server.Items } [Constructible] - public TanBook(string title, string author, int pageCount, bool writable) : - base(0xFF0, title, author, pageCount, writable) + public TanBook(string title, string author, int pageCount, bool writable) : base(0xFF0, title, author, pageCount, + writable) { } @@ -41,4 +41,4 @@ namespace Server.Items writer.Write(0); // version } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Clothing/BaseClothing.cs b/Projects/Scripts/Items/Clothing/BaseClothing.cs index ac7ddf454..06ee87907 100644 --- a/Projects/Scripts/Items/Clothing/BaseClothing.cs +++ b/Projects/Scripts/Items/Clothing/BaseClothing.cs @@ -724,7 +724,9 @@ namespace Server.Items int number; if (Name == null) + { number = LabelNumber; + } else { LabelTo(from, Name); @@ -734,7 +736,9 @@ namespace Server.Items if (attrs.Count == 0 && Crafter == null && Name != null) return; - EquipmentPackets.SendDisplayEquipmentInfo(from.NetState, this, number, m_Crafter, false, attrs); + EquipmentInfo eqInfo = new EquipmentInfo(number, m_Crafter, false, attrs.ToArray()); + + from.Send(new DisplayEquipmentInfo(this, eqInfo)); } public virtual void AddEquipInfoAttributes(Mobile from, List attrs) @@ -900,13 +904,25 @@ namespace Server.Items else m_Resource = DefaultResource; - Attributes = GetSaveFlag(flags, SaveFlag.Attributes) ? new AosAttributes(this, reader) : new AosAttributes(this); + if (GetSaveFlag(flags, SaveFlag.Attributes)) + Attributes = new AosAttributes(this, reader); + else + Attributes = new AosAttributes(this); - ClothingAttributes = GetSaveFlag(flags, SaveFlag.ClothingAttributes) ? new AosArmorAttributes(this, reader) : new AosArmorAttributes(this); + if (GetSaveFlag(flags, SaveFlag.ClothingAttributes)) + ClothingAttributes = new AosArmorAttributes(this, reader); + else + ClothingAttributes = new AosArmorAttributes(this); - SkillBonuses = GetSaveFlag(flags, SaveFlag.SkillBonuses) ? new AosSkillBonuses(this, reader) : new AosSkillBonuses(this); + if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) + SkillBonuses = new AosSkillBonuses(this, reader); + else + SkillBonuses = new AosSkillBonuses(this); - Resistances = GetSaveFlag(flags, SaveFlag.Resistances) ? new AosElementAttributes(this, reader) : new AosElementAttributes(this); + if (GetSaveFlag(flags, SaveFlag.Resistances)) + Resistances = new AosElementAttributes(this, reader); + else + Resistances = new AosElementAttributes(this); if (GetSaveFlag(flags, SaveFlag.MaxHitPoints)) m_MaxHitPoints = reader.ReadEncodedInt(); @@ -927,7 +943,8 @@ namespace Server.Items else m_StrReq = -1; - PlayerConstructed |= GetSaveFlag(flags, SaveFlag.PlayerConstructed); + if (GetSaveFlag(flags, SaveFlag.PlayerConstructed)) + PlayerConstructed = true; break; } @@ -965,7 +982,8 @@ namespace Server.Items } } - PlayerConstructed |= version < 2; // we don't know, so, assume it's crafted + if (version < 2) + PlayerConstructed = true; // we don't know, so, assume it's crafted if (version < 3) { diff --git a/Projects/Scripts/Items/Clothing/Hats.cs b/Projects/Scripts/Items/Clothing/Hats.cs index 45d17ad24..122a4c086 100644 --- a/Projects/Scripts/Items/Clothing/Hats.cs +++ b/Projects/Scripts/Items/Clothing/Hats.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Server.Engines.Craft; using Server.Misc; +using Server.Network; namespace Server.Items { diff --git a/Projects/Scripts/Items/Containers/Container.cs b/Projects/Scripts/Items/Containers/Container.cs index 1d0186189..5dec60a0c 100644 --- a/Projects/Scripts/Items/Containers/Container.cs +++ b/Projects/Scripts/Items/Containers/Container.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using Server.ContextMenus; using Server.Mobiles; using Server.Multis; @@ -17,17 +16,40 @@ namespace Server.Items { } - public override int DefaultMaxWeight => IsSecure ? 0 : base.DefaultMaxWeight; + public override int DefaultMaxWeight + { + get + { + if (IsSecure) + return 0; - public override bool IsAccessibleTo(Mobile m) => - BaseHouse.CheckAccessible(m, this) && base.IsAccessibleTo(m); + return base.DefaultMaxWeight; + } + } - public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) => - (!IsSecure || BaseHouse.CheckHold(m, this, item, message, checkItems, plusItems, plusWeight)) && - base.CheckHold(m, item, message, checkItems, plusItems, plusWeight); + public override bool IsAccessibleTo(Mobile m) + { + if (!BaseHouse.CheckAccessible(m, this)) + return false; - public override bool CheckItemUse(Mobile from, Item item) => - IsDecoContainer && item is BaseBook || base.CheckItemUse(from, item); + return base.IsAccessibleTo(m); + } + + public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) + { + if (IsSecure && !BaseHouse.CheckHold(m, this, item, message, checkItems, plusItems, plusWeight)) + return false; + + return base.CheckHold(m, item, message, checkItems, plusItems, plusWeight); + } + + public override bool CheckItemUse(Mobile from, Item item) + { + if (IsDecoContainer && item is BaseBook) + return true; + + return base.CheckItemUse(from, item); + } public override void GetContextMenuEntries(Mobile from, List list) { @@ -57,8 +79,13 @@ namespace Server.Items List list = Items; - if (list.Any(item => !(item is Container) && item.StackWith(from, dropped, false))) - return true; + for (int i = 0; i < list.Count; ++i) + { + Item item = list[i]; + + if (!(item is Container) && item.StackWith(from, dropped, false)) + return true; + } DropItem(dropped); @@ -909,4 +936,4 @@ namespace Server.Items Weight = -1; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Containers/FillableContainers.cs b/Projects/Scripts/Items/Containers/FillableContainers.cs index 986be77cf..13b08e542 100644 --- a/Projects/Scripts/Items/Containers/FillableContainers.cs +++ b/Projects/Scripts/Items/Containers/FillableContainers.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Mobiles; namespace Server.Items @@ -96,7 +95,14 @@ namespace Server.Items } } - public int GetItemsCount() => Items.Sum(item => item.Amount); + public int GetItemsCount() + { + int count = 0; + + foreach (Item item in Items) count += item.Amount; + + return count; + } public void CheckRespawn() { @@ -1501,9 +1507,7 @@ namespace Server.Items Mobile nearest = null; FillableContent content = null; - IPooledEnumerable eable = map.GetMobilesInRange(loc, 20); - - foreach (Mobile mob in eable) + foreach (Mobile mob in map.GetMobilesInRange(loc, 20)) { if (nearest != null && mob.GetDistanceToSqrt(loc) > nearest.GetDistanceToSqrt(loc) && !(nearest is Cobbler && mob is Provisioner)) @@ -1516,8 +1520,6 @@ namespace Server.Items } } - eable.Free(); - return content; } } diff --git a/Projects/Scripts/Items/Containers/LockableContainer.cs b/Projects/Scripts/Items/Containers/LockableContainer.cs index e6b89b306..783f90b0a 100644 --- a/Projects/Scripts/Items/Containers/LockableContainer.cs +++ b/Projects/Scripts/Items/Containers/LockableContainer.cs @@ -264,7 +264,7 @@ namespace Server.Items inaccessible = true; } - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Regular, 0x3B2, 3, number); + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", "")); } return inaccessible; @@ -323,4 +323,4 @@ namespace Server.Items LabelTo(from, 1041645); //recovered from a shipwreck } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Containers/SalvageBag.cs b/Projects/Scripts/Items/Containers/SalvageBag.cs index dad4c4ac7..cea584359 100644 --- a/Projects/Scripts/Items/Containers/SalvageBag.cs +++ b/Projects/Scripts/Items/Containers/SalvageBag.cs @@ -126,11 +126,16 @@ namespace Server.Items #region Checks - private bool Resmeltables() => //Where context menu checks for metal items and dragon barding deeds - Items.Select(i => i?.Deleted == false && - (i is BaseWeapon weapon && CraftResources.GetType(weapon.Resource) == CraftResourceType.Metal || - i is BaseArmor armor && CraftResources.GetType(armor.Resource) == CraftResourceType.Metal || - i is DragonBardingDeed)).FirstOrDefault(); + private bool Resmeltables() //Where context menu checks for metal items and dragon barding deeds + { + foreach (Item i in Items) + return i?.Deleted == false && ( + i is BaseWeapon weapon && CraftResources.GetType(weapon.Resource) == CraftResourceType.Metal || + i is BaseArmor armor && CraftResources.GetType(armor.Resource) == CraftResourceType.Metal || + i is DragonBardingDeed); + + return false; + } private bool Scissorables() //Where context menu checks for Leather items and cloth items { diff --git a/Projects/Scripts/Items/Containers/TrappableContainer.cs b/Projects/Scripts/Items/Containers/TrappableContainer.cs index 804519d26..c5de08e12 100644 --- a/Projects/Scripts/Items/Containers/TrappableContainer.cs +++ b/Projects/Scripts/Items/Containers/TrappableContainer.cs @@ -46,7 +46,7 @@ namespace Server.Items if (Deleted || !to.CanSee(this)) return; - Packets.SendMessageLocalized(to.NetState, Serial, ItemID, MessageType.Regular, hue, 3, number); + to.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, hue, 3, number, "", "")); } private void SendMessageTo(Mobile to, string text, int hue) @@ -54,7 +54,7 @@ namespace Server.Items if (Deleted || !to.CanSee(this)) return; - Packets.SendUnicodeMessage(to.NetState,Serial, ItemID, MessageType.Regular, hue, 3, "ENU", "", text); + to.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, hue, 3, "ENU", "", text)); } public virtual bool ExecuteTrap(Mobile from) @@ -91,7 +91,7 @@ namespace Server.Items from.LocalOverheadMessage(MessageType.Regular, 0x2A, 503000); } - Effects.SendLocationEffect(loc, facet, 0x36BD, 15); + Effects.SendLocationEffect(loc, facet, 0x36BD, 15, 10); Effects.PlaySound(loc, facet, 0x307); break; @@ -129,7 +129,7 @@ namespace Server.Items AOS.Damage(from, damage, 100, 0, 0, 0, 0); - // A dart embeds itself in your flesh! + // A dart imbeds itself in your flesh! from.LocalOverheadMessage(MessageType.Regular, 0x62, 502998); } @@ -221,4 +221,4 @@ namespace Server.Items } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Containers/TreasureMapChest.cs b/Projects/Scripts/Items/Containers/TreasureMapChest.cs index 8a4432c52..a0ccfcde4 100644 --- a/Projects/Scripts/Items/Containers/TreasureMapChest.cs +++ b/Projects/Scripts/Items/Containers/TreasureMapChest.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.ContextMenus; using Server.Engines.PartySystem; using Server.Gumps; @@ -40,7 +39,7 @@ namespace Server.Items public override int LabelNumber => 3000541; - public static Type[] Artifacts { get; } = + public static Type[] Artifacts{ get; } = { typeof(CandelabraOfSouls), typeof(GoldBricks), typeof(PhillipsWoodenSteed), typeof(ArcticDeathDealer), typeof(BlazeOfDeath), typeof(BurglarsBandana), @@ -52,18 +51,18 @@ namespace Server.Items }; [CommandProperty(AccessLevel.GameMaster)] - public int Level { get; set; } + public int Level{ get; set; } [CommandProperty(AccessLevel.GameMaster)] - public Mobile Owner { get; set; } + public Mobile Owner{ get; set; } [CommandProperty(AccessLevel.GameMaster)] - public DateTime DeleteTime { get; private set; } + public DateTime DeleteTime{ get; private set; } [CommandProperty(AccessLevel.GameMaster)] - public bool Temporary { get; set; } + public bool Temporary{ get; set; } - public List Guardians { get; private set; } + public List Guardians{ get; private set; } public override bool IsDecoContainer => false; @@ -197,11 +196,18 @@ namespace Server.Items }; } else + { numberItems = level * 6; + } for (int i = 0; i < numberItems; ++i) { - Item item = Core.AOS ? Loot.RandomArmorOrShieldOrWeaponOrJewelry() : Loot.RandomArmorOrShieldOrWeapon(); + Item item; + + if (Core.AOS) + item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(); + else + item = Loot.RandomArmorOrShieldOrWeapon(); if (item is BaseWeapon weapon) { @@ -290,12 +296,13 @@ namespace Server.Items if (Level == 0 && from.AccessLevel < AccessLevel.GameMaster) { - if (Guardians.Any(m => m.Alive)) - { - from.SendLocalizedMessage( - 1046448); // You must first kill the guardians before you may open this chest. - return true; - } + foreach (Mobile m in Guardians) + if (m.Alive) + { + from.SendLocalizedMessage( + 1046448); // You must first kill the guardians before you may open this chest. + return true; + } LockPick(from); return false; @@ -388,29 +395,29 @@ namespace Server.Items switch (version) { case 2: - { - Guardians = reader.ReadStrongMobileList(); - Temporary = reader.ReadBool(); + { + Guardians = reader.ReadStrongMobileList(); + Temporary = reader.ReadBool(); - goto case 1; - } + goto case 1; + } case 1: - { - Owner = reader.ReadMobile(); + { + Owner = reader.ReadMobile(); - goto case 0; - } + goto case 0; + } case 0: - { - Level = reader.ReadInt(); - DeleteTime = reader.ReadDeltaTime(); - m_Lifted = reader.ReadStrongItemList(); + { + Level = reader.ReadInt(); + DeleteTime = reader.ReadDeltaTime(); + m_Lifted = reader.ReadStrongItemList(); - if (version < 2) - Guardians = new List(); + if (version < 2) + Guardians = new List(); - break; - } + break; + } } if (!Temporary) diff --git a/Projects/Scripts/Items/Deeds/HairRestylingDeed.cs b/Projects/Scripts/Items/Deeds/HairRestylingDeed.cs index a7026917f..19eecb70c 100644 --- a/Projects/Scripts/Items/Deeds/HairRestylingDeed.cs +++ b/Projects/Scripts/Items/Deeds/HairRestylingDeed.cs @@ -56,7 +56,9 @@ namespace Server.Items new[] { 1074393, 1074390, 0x2fd0, 0x2fcd, 0xedde, 0xc6cb } // buns, long }; - // racial arrays are: cliloc_F, cliloc_M, ItemID_F, ItemID_M, gump_img_F, gump_img_M +/* + racial arrays are: cliloc_F, cliloc_M, ItemID_F, ItemID_M, gump_img_F, gump_img_M +*/ private int[][] HumanArray = /* why on earth cant these utilies be consistent with hex/dec */ { new[] { 0 }, @@ -71,8 +73,10 @@ namespace Server.Items new[] { 1011050, 1011050, 0x204A, 0x204A, 0xED29, 0xED29 }, // Topknot new[] { 1011396, 1011396, 0x2047, 0x2047, 0xed25, 0xc618 } // Curly }; +/* + gump data: bgX, bgY, htmlX, htmlY, imgX, imgY, butX, butY +*/ - // gump data: bgX, bgY, htmlX, htmlY, imgX, imgY, butX, butY private int[][] LayoutArray = { new[] { 0 }, /* padding: its more efficient than code to ++ the index/buttonid */ diff --git a/Projects/Scripts/Items/Deeds/HolidayTreeDeed.cs b/Projects/Scripts/Items/Deeds/HolidayTreeDeed.cs index 03ee8f05a..c56b3b341 100644 --- a/Projects/Scripts/Items/Deeds/HolidayTreeDeed.cs +++ b/Projects/Scripts/Items/Deeds/HolidayTreeDeed.cs @@ -91,11 +91,11 @@ namespace Server.Items Point3D loc = new Point3D(p); if (p is StaticTarget target) - loc.Z -= TileData.ItemTable[target.ItemID].CalcHeight; - /* NOTE: OSI does not properly normalize Z positioning here. - * A side affect is that you can only place on floors (due to the CanFit call). - * That functionality may be desired. And so, it's included in this script. - */ + loc.Z -= TileData.ItemTable[target.ItemID] + .CalcHeight; /* NOTE: OSI does not properly normalize Z positioning here. + * A side affect is that you can only place on floors (due to the CanFit call). + * That functionality may be desired. And so, it's included in this script. + */ if (ValidatePlacement(from, loc)) EndPlace(from, type, loc); diff --git a/Projects/Scripts/Items/Equipment/EquipmentInfoAttribute.cs b/Projects/Scripts/Items/Equipment/EquipmentInfoAttribute.cs deleted file mode 100644 index 6f8ac034c..000000000 --- a/Projects/Scripts/Items/Equipment/EquipmentInfoAttribute.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Server.Items -{ - public class EquipInfoAttribute - { - public EquipInfoAttribute(int number, int charges = -1) - { - Number = number; - Charges = charges; - } - - public int Number { get; } - - public int Charges { get; } - } -} diff --git a/Projects/Scripts/Items/Equipment/Packets.cs b/Projects/Scripts/Items/Equipment/Packets.cs deleted file mode 100644 index 607227df7..000000000 --- a/Projects/Scripts/Items/Equipment/Packets.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections.Generic; -using Server.Buffers; -using Server.Items; - -namespace Server.Network -{ - public static class EquipmentPackets - { - public static void SendDisplayEquipmentInfo(NetState ns, Item item, int number, Mobile crafter, bool unidentified, ICollection attrs) - { - int packetLength = 17 + - (crafter != null ? 6 + crafter.RawName?.Length ?? 0 : 0) + - (unidentified ? 4 : 0) + attrs.Count * 6; - - SpanWriter writer = new SpanWriter(stackalloc byte[packetLength]); - - writer.Write((byte)0xBF); // Extended Command Packet ID - writer.Write((ushort)packetLength); // Dynamic Length - - writer.Write((short)0x10); // Command - writer.Write(item.Serial); - writer.Write(number); - - if (crafter != null) - { - // TODO: We should not be referencing the crafter. - // They could have been deleted and the crafted by should still show up. - string name = crafter.RawName; - - writer.Write(-3); - - if (name == null) - writer.Write((ushort)0); - else - { - int length = name.Length; - writer.Write((ushort)length); - writer.WriteAsciiFixed(name, length); - } - } - - if (unidentified) - writer.Write(-4); - - foreach (EquipInfoAttribute attr in attrs) - { - writer.Write(attr.Number); - writer.Write((short)attr.Charges); - } - - writer.Write(-1); - - ns.Send(writer.Span); - } - } -} diff --git a/Projects/Scripts/Items/Food/CookableFood.cs b/Projects/Scripts/Items/Food/CookableFood.cs index 66d3e86a6..cb03e9e15 100644 --- a/Projects/Scripts/Items/Food/CookableFood.cs +++ b/Projects/Scripts/Items/Food/CookableFood.cs @@ -43,13 +43,13 @@ namespace Server.Items } #if false - public override void OnDoubleClick( Mobile from ) - { - if ( !Movable ) - return; + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; - from.Target = new InternalTarget( this ); - } + from.Target = new InternalTarget( this ); + } #endif public static bool IsHeatSource(object targeted) @@ -63,13 +63,22 @@ namespace Server.Items else return false; - return itemID == 0xFAC || - itemID >= 0xDE3 && itemID <= 0xDE9 || - itemID >= 0x461 && itemID <= 0x48E || - itemID >= 0x92B && itemID <= 0x96C || - itemID >= 0x184A && itemID <= 0x184C || - itemID >= 0x184E && itemID <= 0x1850 || - itemID >= 0x398C && itemID <= 0x399F; + if (itemID >= 0xDE3 && itemID <= 0xDE9) + return true; // Campfire + if (itemID >= 0x461 && itemID <= 0x48E) + return true; // Sandstone oven/fireplace + if (itemID >= 0x92B && itemID <= 0x96C) + return true; // Stone oven/fireplace + if (itemID == 0xFAC) + return true; // Firepit + if (itemID >= 0x184A && itemID <= 0x184C) + return true; // Heating stand (left) + if (itemID >= 0x184E && itemID <= 0x1850) + return true; // Heating stand (right) + if (itemID >= 0x398C && itemID <= 0x399F) + return true; // Fire field + + return false; } private class InternalTarget : Target @@ -94,7 +103,9 @@ namespace Server.Items t.Start(); } else + { from.SendLocalizedMessage(500119); // You must wait to perform another action + } } } @@ -132,7 +143,9 @@ namespace Server.Items m_From.PlaySound(0x57); } else + { m_From.SendLocalizedMessage(500686); // You burn the food to a crisp! It's ruined. + } } } } diff --git a/Projects/Scripts/Items/Food/Cooking.cs b/Projects/Scripts/Items/Food/Cooking.cs index aa68f6c75..ca8a09e2a 100644 --- a/Projects/Scripts/Items/Food/Cooking.cs +++ b/Projects/Scripts/Items/Food/Cooking.cs @@ -47,13 +47,13 @@ namespace Server.Items } #if false - public override void OnDoubleClick( Mobile from ) - { - if ( !Movable ) - return; + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; - from.Target = new InternalTarget( this ); - } + from.Target = new InternalTarget( this ); + } #endif private class InternalTarget : Target @@ -135,13 +135,13 @@ namespace Server.Items } #if false - public override void OnDoubleClick( Mobile from ) - { - if ( !Movable ) - return; + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; - from.Target = new InternalTarget( this ); - } + from.Target = new InternalTarget( this ); + } #endif private class InternalTarget : Target @@ -454,9 +454,9 @@ namespace Server.Items ++ItemID; #if false - this.Delete(); + this.Delete(); - from.AddToBackpack( new SackFlourOpen() ); + from.AddToBackpack( new SackFlourOpen() ); #endif } } diff --git a/Projects/Scripts/Items/Games/BaseBoard.cs b/Projects/Scripts/Items/Games/BaseBoard.cs index d7ecddcd4..fd292b550 100644 --- a/Projects/Scripts/Items/Games/BaseBoard.cs +++ b/Projects/Scripts/Items/Games/BaseBoard.cs @@ -72,13 +72,17 @@ namespace Server.Items { if (dropped is BasePiece piece && piece.Board == this && base.OnDragDropInto(from, dropped, point)) { - Point3D loc = GetWorldLocation(); + Packet p = new PlaySound(0x127, GetWorldLocation()); + + p.Acquire(); if (RootParent == from) - Packets.SendPlaySound(from.NetState, 0x127, loc); + from.Send(p); else foreach (NetState state in GetClientsInRange(2)) - Packets.SendPlaySound(state, 0x127, loc); + state.Send(p); + + p.Release(); return true; } diff --git a/Projects/Scripts/Items/Games/Dices.cs b/Projects/Scripts/Items/Games/Dices.cs index 29bc2d7bf..d065caaed 100644 --- a/Projects/Scripts/Items/Games/Dices.cs +++ b/Projects/Scripts/Items/Games/Dices.cs @@ -21,8 +21,10 @@ namespace Server.Items public override void OnDoubleClick(Mobile from) { - if (from.InRange(GetWorldLocation(), 2)) - Roll(from); + if (!from.InRange(GetWorldLocation(), 2)) + return; + + Roll(from); } public void Roll(Mobile from) @@ -43,4 +45,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Games/Mahjong/MahjongGame.cs b/Projects/Scripts/Items/Games/Mahjong/MahjongGame.cs index ac0d77495..cefbd322a 100644 --- a/Projects/Scripts/Items/Games/Mahjong/MahjongGame.cs +++ b/Projects/Scripts/Items/Games/Mahjong/MahjongGame.cs @@ -76,7 +76,7 @@ namespace Server.Engines.Mahjong m_SpectatorVision = value; if (Players.IsInGamePlayer(Players.DealerPosition)) - MahjongPackets.SendMahjongGeneralInfo(Players.Dealer.NetState, this); + Players.Dealer.Send(new MahjongGeneralInfo(this)); Players.SendTilesPacket(false, true); @@ -292,4 +292,4 @@ namespace Server.Engines.Mahjong } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Games/Mahjong/MahjongPacketHandlers.cs b/Projects/Scripts/Items/Games/Mahjong/MahjongPacketHandlers.cs index d3a69f0cd..9683f3363 100644 --- a/Projects/Scripts/Items/Games/Mahjong/MahjongPacketHandlers.cs +++ b/Projects/Scripts/Items/Games/Mahjong/MahjongPacketHandlers.cs @@ -6,7 +6,7 @@ namespace Server.Engines.Mahjong public sealed class MahjongPacketHandlers { - private static readonly OnMahjongPacketReceive[] m_SubCommandDelegates = new OnMahjongPacketReceive[0x100]; + private static OnMahjongPacketReceive[] m_SubCommandDelegates = new OnMahjongPacketReceive[0x100]; public static void RegisterSubCommand(int subCmd, OnMahjongPacketReceive onReceive) { @@ -80,7 +80,12 @@ namespace Server.Engines.Mahjong public static void ExitGame(MahjongGame game, NetState state, PacketReader pvSrc) { - game?.Players.LeaveGame(state.Mobile); + if (game == null) + return; + + Mobile from = state.Mobile; + + game.Players.LeaveGame(from); } public static void GivePoints(MahjongGame game, NetState state, PacketReader pvSrc) @@ -225,4 +230,4 @@ namespace Server.Engines.Mahjong game.DealerIndicator.Move(new Point2D(x, y), direction, wind); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Games/Mahjong/MahjongPlayers.cs b/Projects/Scripts/Items/Games/Mahjong/MahjongPlayers.cs index 0bd9501c7..dfb2f99bc 100644 --- a/Projects/Scripts/Items/Games/Mahjong/MahjongPlayers.cs +++ b/Projects/Scripts/Items/Games/Mahjong/MahjongPlayers.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; namespace Server.Engines.Mahjong { @@ -83,13 +82,28 @@ namespace Server.Engines.Mahjong return m_InGame[index]; } - public bool IsInGamePlayer(Mobile mobile) => IsInGamePlayer(GetPlayerIndex(mobile)); + public bool IsInGamePlayer(Mobile mobile) + { + int index = GetPlayerIndex(mobile); + + return IsInGamePlayer(index); + } public bool IsSpectator(Mobile mobile) => m_Spectators.Contains(mobile); - public bool IsSpectator(Mobile mobile) => m_Spectators.Contains(mobile); + public int GetScore(int index) + { + if (index < 0 || index >= m_Scores.Length) + return 0; + return m_Scores[index]; + } - public bool IsPublic(int index) => index >= 0 && index < m_PublicHand.Length && m_PublicHand[index]; + public bool IsPublic(int index) + { + if (index < 0 || index >= m_PublicHand.Length) + return false; + return m_PublicHand[index]; + } public void SetPublic(int index, bool value) { @@ -108,7 +122,10 @@ namespace Server.Engines.Mahjong { List list = new List(); - if (players) list.AddRange(m_Players.Where((t, i) => IsInGamePlayer(i))); + if (players) + for (int i = 0; i < m_Players.Length; i++) + if (IsInGamePlayer(i)) + list.Add(m_Players[i]); if (spectators) list.AddRange(m_Spectators); @@ -152,7 +169,7 @@ namespace Server.Engines.Mahjong { m_InGame[i] = false; - MahjongPackets.SendMahjongRelieve(player.NetState, Game); + player.Send(new MahjongRelieve(Game)); SendPlayerExitMessage(player); UpdateDealer(true); @@ -167,16 +184,20 @@ namespace Server.Engines.Mahjong Mobile mobile = m_Spectators[i]; if (mobile.NetState == null || mobile.Deleted) + { m_Spectators.RemoveAt(i); + } else if (!Game.IsAccessibleTo(mobile) || mobile.Map != Game.Map || !mobile.InRange(Game.GetWorldLocation(), 5)) { m_Spectators.RemoveAt(i); - MahjongPackets.SendMahjongRelieve(mobile.NetState, Game); + mobile.Send(new MahjongRelieve(Game)); } else + { i++; + } } if (removed && !UpdateSpectators()) @@ -255,12 +276,12 @@ namespace Server.Engines.Mahjong UpdateDealer(false); if (sendJoinGame) - MahjongPackets.SendMahjongJoinGame(player.NetState, Game); + player.Send(new MahjongJoinGame(Game)); SendPlayersPacket(true, true); - MahjongPackets.SendMahjongGeneralInfo(player.NetState, Game); - MahjongPackets.SendMahjongTilesInfo(player.NetState, Game, player); + player.Send(new MahjongGeneralInfo(Game)); + player.Send(new MahjongTilesInfo(Game, player)); if (DealerPosition == index) SendLocalizedMessage(1062773, player.Name); // ~1_name~ has entered the game as the dealer. @@ -268,14 +289,14 @@ namespace Server.Engines.Mahjong SendLocalizedMessage(1062772, player.Name); // ~1_name~ has entered the game as a player. } - private void AddSpectator(Mobile m) + private void AddSpectator(Mobile mobile) { - if (!IsSpectator(m)) m_Spectators.Add(m); + if (!IsSpectator(mobile)) m_Spectators.Add(mobile); - MahjongPackets.SendMahjongJoinGame(m.NetState, Game); - MahjongPackets.SendMahjongPlayersInfo(m.NetState, Game, m); - MahjongPackets.SendMahjongGeneralInfo(m.NetState, Game); - MahjongPackets.SendMahjongTilesInfo(m.NetState, Game, m); + mobile.Send(new MahjongJoinGame(Game)); + mobile.Send(new MahjongPlayersInfo(Game, mobile)); + mobile.Send(new MahjongGeneralInfo(Game)); + mobile.Send(new MahjongTilesInfo(Game, mobile)); } public void Join(Mobile mobile) @@ -283,7 +304,9 @@ namespace Server.Engines.Mahjong int index = GetPlayerIndex(mobile); if (index >= 0) + { AddPlayer(mobile, index, true); + } else { int nextSeat = GetNextSeat(); @@ -308,7 +331,9 @@ namespace Server.Engines.Mahjong SendPlayersPacket(true, true); } else + { m_Spectators.Remove(player); + } } public void ResetScores(int value) @@ -332,11 +357,13 @@ namespace Server.Engines.Mahjong m_Scores[toPosition] += amount; if (Game.ShowScores) + { SendPlayersPacket(true, true); + } else { - MahjongPackets.SendMahjongPlayersInfo(from.NetState, Game, from); - MahjongPackets.SendMahjongPlayersInfo(to.NetState, Game, to); + from.Send(new MahjongPlayersInfo(Game, from)); + to.Send(new MahjongPlayersInfo(Game, to)); } SendLocalizedMessage(1062774, @@ -350,7 +377,7 @@ namespace Server.Engines.Mahjong return; if (m_InGame[index]) - MahjongPackets.SendMahjongRelieve(player.NetState, Game); + player.Send(new MahjongRelieve(Game)); m_Players[index] = null; @@ -374,9 +401,9 @@ namespace Server.Engines.Mahjong DealerPosition = index; if (IsInGamePlayer(oldDealer)) - MahjongPackets.SendMahjongPlayersInfo(m_Players[oldDealer].NetState, Game, m_Players[oldDealer]); + m_Players[oldDealer].Send(new MahjongPlayersInfo(Game, m_Players[oldDealer])); - MahjongPackets.SendMahjongPlayersInfo(to.NetState, Game, to); + to.Send(new MahjongPlayersInfo(Game, to)); SendDealerChangedMessage(); } @@ -395,25 +422,36 @@ namespace Server.Engines.Mahjong public void SendPlayersPacket(bool players, bool spectators) { foreach (Mobile mobile in GetInGameMobiles(players, spectators)) - MahjongPackets.SendMahjongPlayersInfo(mobile.NetState, Game, mobile); + mobile.Send(new MahjongPlayersInfo(Game, mobile)); } public void SendGeneralPacket(bool players, bool spectators) { - foreach (Mobile mobile in GetInGameMobiles(players, spectators)) - MahjongPackets.SendMahjongGeneralInfo(mobile.NetState, Game); + List mobiles = GetInGameMobiles(players, spectators); + + if (mobiles.Count == 0) + return; + + MahjongGeneralInfo generalInfo = new MahjongGeneralInfo(Game); + + generalInfo.Acquire(); + + foreach (Mobile mobile in mobiles) + mobile.Send(generalInfo); + + generalInfo.Release(); } public void SendTilesPacket(bool players, bool spectators) { foreach (Mobile mobile in GetInGameMobiles(players, spectators)) - MahjongPackets.SendMahjongTilesInfo(mobile.NetState, Game, mobile); + mobile.Send(new MahjongTilesInfo(Game, mobile)); } public void SendTilePacket(MahjongTile tile, bool players, bool spectators) { foreach (Mobile mobile in GetInGameMobiles(players, spectators)) - MahjongPackets.SendMahjongTileInfo(mobile.NetState, tile, mobile); + mobile.Send(new MahjongTileInfo(tile, mobile)); } public void SendRelievePacket(bool players, bool spectators) @@ -423,8 +461,14 @@ namespace Server.Engines.Mahjong if (mobiles.Count == 0) return; + MahjongRelieve relieve = new MahjongRelieve(Game); + + relieve.Acquire(); + foreach (Mobile mobile in mobiles) - MahjongPackets.SendMahjongRelieve(mobile.NetState, Game); + mobile.Send(relieve); + + relieve.Release(); } public void SendLocalizedMessage(int number) diff --git a/Projects/Scripts/Items/Games/Mahjong/Packets.cs b/Projects/Scripts/Items/Games/Mahjong/Packets.cs index 235083757..39be5ea77 100644 --- a/Projects/Scripts/Items/Games/Mahjong/Packets.cs +++ b/Projects/Scripts/Items/Games/Mahjong/Packets.cs @@ -1,78 +1,76 @@ -using Server.Buffers; +using System.IO; using Server.Network; namespace Server.Engines.Mahjong { - public static class MahjongPackets + public sealed class MahjongJoinGame : Packet { - public static void SendMahjongJoinGame(NetState ns, MahjongGame game) + public MahjongJoinGame(MahjongGame game) : base(0xDA) { - if (ns == null) - return; + EnsureCapacity(9); - SpanWriter writer = new SpanWriter(stackalloc byte[9]); - writer.Write((byte)0xDA); // Packet ID - writer.Write((ushort)0x09); // Dynamic Length - - writer.Write(game.Serial); - writer.Write((short)0x19); - - ns.Send(writer.Span); + m_Stream.Write(game.Serial); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0x19); } + } - public static void SendMahjongPlayersInfo(NetState ns, MahjongGame game, Mobile to) + public sealed class MahjongPlayersInfo : Packet + { + public MahjongPlayersInfo(MahjongGame game, Mobile to) : base(0xDA) { - if (ns == null) - return; - MahjongPlayers players = game.Players; - SpanWriter writer = new SpanWriter(stackalloc byte[11 + 45 * players.Seats]); - writer.Write((byte)0xDA); // Packet ID - writer.Position += 2; // Dynamic Length - writer.Write(game.Serial); - writer.Write((short)0x02); - writer.Write((short)players.Seats); + EnsureCapacity(11 + 45 * players.Seats); - short n = 0; + m_Stream.Write(game.Serial); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0x2); + + m_Stream.Write((byte)0); + m_Stream.Write((byte)players.Seats); + + int n = 0; for (int i = 0; i < players.Seats; i++) { Mobile mobile = players.GetPlayer(i); if (mobile != null) { - writer.Write(mobile.Serial); - writer.Write(players.DealerPosition == i ? (byte)0x1 : (byte)0x2); - writer.Write((byte)i); + m_Stream.Write(mobile.Serial); + m_Stream.Write(players.DealerPosition == i ? (byte)0x1 : (byte)0x2); + m_Stream.Write((byte)i); if (game.ShowScores || mobile == to) - writer.Write(players.GetScore(i)); + m_Stream.Write(players.GetScore(i)); else - writer.Position++; // writer.Write(0); + m_Stream.Write(0); - writer.Position += 3; + m_Stream.Write((short)0); + m_Stream.Write((byte)0); - writer.Write(players.IsPublic(i)); + m_Stream.Write(players.IsPublic(i)); - writer.WriteAsciiFixed(mobile.Name, 30); - writer.Write(!players.IsInGamePlayer(i)); + m_Stream.WriteAsciiFixed(mobile.Name, 30); + m_Stream.Write(!players.IsInGamePlayer(i)); n++; } else if (game.ShowScores) { - writer.Position++; // writer.Write(0); - writer.Write((byte)0x2); - writer.Write((byte)i); + m_Stream.Write(0); + m_Stream.Write((byte)0x2); + m_Stream.Write((byte)i); - writer.Write(players.GetScore(i)); + m_Stream.Write(players.GetScore(i)); - writer.Position += 3; + m_Stream.Write((short)0); + m_Stream.Write((byte)0); - writer.Write(players.IsPublic(i)); + m_Stream.Write(players.IsPublic(i)); - writer.Position += 30; //writer.WriteAsciiFixed("", 30); - writer.Write((byte)0x1); // true + m_Stream.WriteAsciiFixed("", 30); + m_Stream.Write(true); n++; } @@ -80,66 +78,58 @@ namespace Server.Engines.Mahjong if (n != players.Seats) { - writer.Position = 9; - writer.Write(n); + m_Stream.Seek(10, SeekOrigin.Begin); + m_Stream.Write((byte)n); } - - writer.Position = 1; - writer.Write((short)writer.WrittenCount); - ns.Send(writer.Span); } + } - public static void SendMahjongGeneralInfo(NetState ns, MahjongGame game) + public sealed class MahjongGeneralInfo : Packet + { + public MahjongGeneralInfo(MahjongGame game) : base(0xDA) { - if (ns == null) - return; + EnsureCapacity(13); - SpanWriter writer = new SpanWriter(stackalloc byte[25]); - writer.Write((byte)0xDA); // Packet ID - writer.Write((ushort)25); // Dynamic Length + m_Stream.Write(game.Serial); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0x5); - writer.Write(game.Serial); - writer.Write((short)0x05); + m_Stream.Write((short)0); + m_Stream.Write((byte)0); - writer.Position += 3; + m_Stream.Write((byte)((game.ShowScores ? 0x1 : 0x0) | (game.SpectatorVision ? 0x2 : 0x0))); - writer.Write((byte)((game.ShowScores ? 0x1 : 0x0) | (game.SpectatorVision ? 0x2 : 0x0))); + m_Stream.Write((byte)game.Dices.First); + m_Stream.Write((byte)game.Dices.Second); - writer.Write((byte)game.Dices.First); - writer.Write((byte)game.Dices.Second); + m_Stream.Write((byte)game.DealerIndicator.Wind); + m_Stream.Write((short)game.DealerIndicator.Position.Y); + m_Stream.Write((short)game.DealerIndicator.Position.X); + m_Stream.Write((byte)game.DealerIndicator.Direction); - writer.Write((byte)game.DealerIndicator.Wind); - writer.Write((short)game.DealerIndicator.Position.Y); - writer.Write((short)game.DealerIndicator.Position.X); - writer.Write((byte)game.DealerIndicator.Direction); - - writer.Write((short)game.WallBreakIndicator.Position.Y); - writer.Write((short)game.WallBreakIndicator.Position.X); - - ns.Send(writer.Span); + m_Stream.Write((short)game.WallBreakIndicator.Position.Y); + m_Stream.Write((short)game.WallBreakIndicator.Position.X); } + } - public static void SendMahjongTilesInfo(NetState ns, MahjongGame game, Mobile to) + public sealed class MahjongTilesInfo : Packet + { + public MahjongTilesInfo(MahjongGame game, Mobile to) : base(0xDA) { - if (ns == null) - return; - MahjongTile[] tiles = game.Tiles; MahjongPlayers players = game.Players; - int length = 11 + 9 * tiles.Length; - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xDA); // Packet ID - writer.Write((short)length); // Dynamic Length + EnsureCapacity(11 + 9 * tiles.Length); - writer.Write(game.Serial); - writer.Write((short)0x4); + m_Stream.Write(game.Serial); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0x4); - writer.Write((short)tiles.Length); + m_Stream.Write((short)tiles.Length); foreach (MahjongTile tile in tiles) { - writer.Write((byte)tile.Number); + m_Stream.Write((byte)tile.Number); if (tile.Flipped) { @@ -147,40 +137,39 @@ namespace Server.Engines.Mahjong if (hand < 0 || players.IsPublic(hand) || players.GetPlayer(hand) == to || game.SpectatorVision && players.IsSpectator(to)) - writer.Write((byte)tile.Value); + m_Stream.Write((byte)tile.Value); else - writer.Position++; + m_Stream.Write((byte)0); } else - writer.Position++; + { + m_Stream.Write((byte)0); + } - writer.Write((short)tile.Position.Y); - writer.Write((short)tile.Position.X); - writer.Write((byte)tile.StackLevel); - writer.Write((byte)tile.Direction); + m_Stream.Write((short)tile.Position.Y); + m_Stream.Write((short)tile.Position.X); + m_Stream.Write((byte)tile.StackLevel); + m_Stream.Write((byte)tile.Direction); - writer.Write(tile.Flipped ? (byte)0x10 : (byte)0x0); + m_Stream.Write(tile.Flipped ? (byte)0x10 : (byte)0x0); } - - ns.Send(writer.Span); } + } - public static void SendMahjongTileInfo(NetState ns, MahjongTile tile, Mobile to) + public sealed class MahjongTileInfo : Packet + { + public MahjongTileInfo(MahjongTile tile, Mobile to) : base(0xDA) { - if (ns == null) - return; - MahjongGame game = tile.Game; MahjongPlayers players = game.Players; - SpanWriter writer = new SpanWriter(stackalloc byte[18]); - writer.Write((byte)0xDA); // Packet ID - writer.Write((short)18); // Dynamic Length + EnsureCapacity(18); - writer.Write(game.Serial); - writer.Write((short)0x3); + m_Stream.Write(tile.Game.Serial); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0x3); - writer.Write((byte)tile.Number); + m_Stream.Write((byte)tile.Number); if (tile.Flipped) { @@ -188,36 +177,33 @@ namespace Server.Engines.Mahjong if (hand < 0 || players.IsPublic(hand) || players.GetPlayer(hand) == to || game.SpectatorVision && players.IsSpectator(to)) - writer.Write((byte)tile.Value); + m_Stream.Write((byte)tile.Value); else - writer.Position++; + m_Stream.Write((byte)0); } else - writer.Position++; + { + m_Stream.Write((byte)0); + } - writer.Write((short)tile.Position.Y); - writer.Write((short)tile.Position.X); - writer.Write((byte)tile.StackLevel); - writer.Write((byte)tile.Direction); + m_Stream.Write((short)tile.Position.Y); + m_Stream.Write((short)tile.Position.X); + m_Stream.Write((byte)tile.StackLevel); + m_Stream.Write((byte)tile.Direction); - writer.Write(tile.Flipped ? (byte)0x10 : (byte)0x0); - - ns.Send(writer.Span); - } - - public static void SendMahjongRelieve(NetState ns, MahjongGame game) - { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[18]); - writer.Write((byte)0xDA); // Packet ID - writer.Write((short)18); // Dynamic Length - - writer.Write(game.Serial); - writer.Write((short)0x1A); - - ns.Send(writer.Span); + m_Stream.Write(tile.Flipped ? (byte)0x10 : (byte)0x0); } } -} + + public sealed class MahjongRelieve : Packet + { + public MahjongRelieve(MahjongGame game) : base(0xDA) + { + EnsureCapacity(9); + + m_Stream.Write(game.Serial); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0x1A); + } + } +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Guilds/GuildDeed.cs b/Projects/Scripts/Items/Guilds/GuildDeed.cs index 139077068..ea4197781 100644 --- a/Projects/Scripts/Items/Guilds/GuildDeed.cs +++ b/Projects/Scripts/Items/Guilds/GuildDeed.cs @@ -1,5 +1,6 @@ using Server.Guilds; using Server.Multis; +using Server.Prompts; namespace Server.Items { diff --git a/Projects/Scripts/Items/Guilds/Guildstone.cs b/Projects/Scripts/Items/Guilds/Guildstone.cs index 3a34fdb7f..c02b0cca4 100644 --- a/Projects/Scripts/Items/Guilds/Guildstone.cs +++ b/Projects/Scripts/Items/Guilds/Guildstone.cs @@ -143,7 +143,8 @@ namespace Server.Items if (Guild.NewGuildSystem && ItemID == 0xED4) ItemID = 0xED6; - m_BeforeChangeover |= version <= 2; + if (version <= 2) + m_BeforeChangeover = true; if (Guild.NewGuildSystem && m_BeforeChangeover) Timer.DelayCall(TimeSpan.Zero, AddToHouse); @@ -250,8 +251,10 @@ namespace Server.Items from.SendGump(new GuildGump(from, Guild)); } else if (from.AccessLevel < AccessLevel.GameMaster && !Guild.IsMember(from)) - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Regular, 0x3B2, 3, - 501158); // You are not a member ... + { + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, 501158, "", + "")); // You are not a member ... + } else { GuildGump.EnsureClosed(from); @@ -259,6 +262,8 @@ namespace Server.Items } } + #region IAddon Members + public Item Deed => new GuildstoneDeed(Guild, m_GuildName, m_GuildAbbrev); public bool CouldFit(IPoint3D p, Map map) => map.CanFit(p.X, p.Y, p.Z, ItemData.Height); @@ -371,7 +376,9 @@ namespace Server.Items list.Add(1060802, $"{Utility.FixHtml(name)} [{Utility.FixHtml(abbr)}]"); } else if (m_GuildName != null && m_GuildAbbrev != null) + { list.Add(1060802, $"{Utility.FixHtml(m_GuildName)} [{Utility.FixHtml(m_GuildAbbrev)}]"); + } } public override void OnDoubleClick(Mobile from) @@ -386,10 +393,14 @@ namespace Server.Items from.BeginTarget(-1, true, TargetFlags.None, Placement_OnTarget); } else + { from.SendLocalizedMessage(502092); // You must be in your house to do this. + } } else + { from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } } public void Placement_OnTarget(Mobile from, object targeted) @@ -413,10 +424,14 @@ namespace Server.Items Delete(); } else + { from.SendLocalizedMessage(1042036); // That location is not in your house. + } } else + { from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } } } } diff --git a/Projects/Scripts/Items/Maps/IndecipherableMap.cs b/Projects/Scripts/Items/Maps/IndecipherableMap.cs index 051e14fcb..9cc9dfe9d 100644 --- a/Projects/Scripts/Items/Maps/IndecipherableMap.cs +++ b/Projects/Scripts/Items/Maps/IndecipherableMap.cs @@ -3,7 +3,13 @@ namespace Server.Items public class IndecipherableMap : MapItem { [Constructible] - public IndecipherableMap() => Hue = Utility.RandomDouble() < 0.2 ? 0x965 : 0x961; + public IndecipherableMap() + { + if (Utility.RandomDouble() < 0.2) + Hue = 0x965; + else + Hue = 0x961; + } public IndecipherableMap(Serial serial) : base(serial) { @@ -30,4 +36,4 @@ namespace Server.Items int version = reader.ReadEncodedInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Maps/MapItem.cs b/Projects/Scripts/Items/Maps/MapItem.cs index 106f50e15..d60d321cd 100644 --- a/Projects/Scripts/Items/Maps/MapItem.cs +++ b/Projects/Scripts/Items/Maps/MapItem.cs @@ -10,16 +10,14 @@ namespace Server.Items { private const int MaxUserPins = 50; private bool m_Editable; - private Map m_Facet; [Constructible] - public MapItem(Map facet = null) : base(0x14EC) + public MapItem() : base(0x14EC) { Weight = 1.0; Width = 200; Height = 200; - m_Facet = facet; } public MapItem(Serial serial) : base(serial) @@ -40,13 +38,6 @@ namespace Server.Items public List Pins{ get; } = new List(); - [CommandProperty(AccessLevel.GameMaster)] - public virtual Map Facet - { - get => m_Facet; - set => m_Facet = value; - } - #region ICraftable Members public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, @@ -92,24 +83,13 @@ namespace Server.Items public virtual void DisplayTo(Mobile from) { - NetState ns = from.NetState; - - if (ns.NewCharacterList) // 7.0.13.0+ supports maps on all facets - MapItemPackets.SendMapDetailsNew(ns, this); - else if (Facet != null && Facet != Map.Felucca && Facet != Map.Trammel) // Is it Felucca and Trammel, or just Felucca? - { - from.SendMessage("You must have client 7.0.13.0 or higher to display this map."); - return; - } - else - MapItemPackets.SendMapDetailsOld(ns, this); - - MapItemPackets.SendMapDisplay(from.NetState, this); + from.Send(new MapDetails(this)); + from.Send(new MapDisplay(this)); for (int i = 0; i < Pins.Count; ++i) - MapItemPackets.SendMapAddPin(from.NetState, this, Pins[i]); + from.Send(new MapAddPin(this, Pins[i])); - MapItemPackets.SendMapSetEditable(from.NetState, this, ValidateEdit(from)); + from.Send(new MapSetEditable(this, ValidateEdit(from))); } public virtual void OnAddPin(Mobile from, int x, int y) @@ -164,7 +144,7 @@ namespace Server.Items if (Validate(from)) m_Editable = !m_Editable; - MapItemPackets.SendMapSetEditable(from.NetState, this, m_Editable && ValidateEdit(from)); + from.Send(new MapSetEditable(this, Validate(from) && m_Editable)); } public virtual void Validate(ref int x, ref int y) @@ -246,9 +226,7 @@ namespace Server.Items { base.Serialize(writer); - writer.Write(1); - - writer.Write(m_Facet); + writer.Write(0); writer.Write(Bounds); @@ -270,9 +248,6 @@ namespace Server.Items switch (version) { - case 1: - m_Facet = reader.ReadMap(); - goto case 0; case 0: { Bounds = reader.ReadRect2D(); @@ -331,5 +306,71 @@ namespace Server.Items break; } } + + private sealed class MapDetails : Packet + { + public MapDetails(MapItem map) : base(0x90, 19) + { + m_Stream.Write(map.Serial); + m_Stream.Write((short)0x139D); + m_Stream.Write((short)map.Bounds.Start.X); + m_Stream.Write((short)map.Bounds.Start.Y); + m_Stream.Write((short)map.Bounds.End.X); + m_Stream.Write((short)map.Bounds.End.Y); + m_Stream.Write((short)map.Width); + m_Stream.Write((short)map.Height); + } + } + + /* + private sealed class MapDetailsNew : Packet + { + public MapDetailsNew( MapItem map ) : base ( 0xF5, 21 ) + { + m_Stream.Write( (int) map.Serial ); + m_Stream.Write( (short) 0x139D ); + m_Stream.Write( (short) map.Bounds.Start.X ); + m_Stream.Write( (short) map.Bounds.Start.Y ); + m_Stream.Write( (short) map.Bounds.End.X ); + m_Stream.Write( (short) map.Bounds.End.Y ); + m_Stream.Write( (short) map.Width ); + m_Stream.Write( (short) map.Height ); + m_Stream.Write( (short) ( map.Facet == null ? 0 : map.Facet.MapID ) ); + } + } + */ + + private abstract class MapCommand : Packet + { + public MapCommand(MapItem map, int command, int number, int x, int y) : base(0x56, 11) + { + m_Stream.Write(map.Serial); + m_Stream.Write((byte)command); + m_Stream.Write((byte)number); + m_Stream.Write((short)x); + m_Stream.Write((short)y); + } + } + + private sealed class MapDisplay : MapCommand + { + public MapDisplay(MapItem map) : base(map, 5, 0, 0, 0) + { + } + } + + private sealed class MapAddPin : MapCommand + { + public MapAddPin(MapItem map, Point2D point) : base(map, 1, 0, point.X, point.Y) + { + } + } + + private sealed class MapSetEditable : MapCommand + { + public MapSetEditable(MapItem map, bool editable) : base(map, 7, editable ? 1 : 0, 0, 0) + { + } + } } } diff --git a/Projects/Scripts/Items/Maps/Packets.cs b/Projects/Scripts/Items/Maps/Packets.cs deleted file mode 100644 index 77d0805f4..000000000 --- a/Projects/Scripts/Items/Maps/Packets.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Server.Buffers; -using Server.Items; - -namespace Server.Network -{ - public static class MapItemPackets - { - public static void SendMapDetailsOld(NetState ns, MapItem map) - { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[19]); - writer.Write((byte)0x90); // Packet ID - - writer.Write(map.Serial); - writer.Write((short)0x139D); - writer.Write((short)map.Bounds.Start.X); - writer.Write((short)map.Bounds.Start.Y); - writer.Write((short)map.Bounds.End.X); - writer.Write((short)map.Bounds.End.Y); - writer.Write((short)map.Width); - writer.Write((short)map.Height); - - ns.Send(writer.Span); - } - - public static void SendMapDetailsNew(NetState ns, MapItem map) - { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[21]); - writer.Write((byte)0xF5); // Packet ID - - writer.Write(map.Serial); - writer.Write((short)0x139D); - writer.Write((short)map.Bounds.Start.X); - writer.Write((short)map.Bounds.Start.Y); - writer.Write((short)map.Bounds.End.X); - writer.Write((short)map.Bounds.End.Y); - writer.Write((short)map.Width); - writer.Write((short)map.Height); - writer.Write( (short)(map.Facet?.MapID ?? 0) ); - - ns.Send(writer.Span); - } - - public static void SendMapDisplay(NetState ns, MapItem map) - { - SendMapCommand(ns, map, 5); - } - - public static void SendMapAddPin(NetState ns, MapItem map, Point2D p) - { - SendMapCommand(ns, map, 1, 0, p.X, p.Y); - } - - public static void SendMapSetEditable(NetState ns, MapItem map, bool editable) - { - SendMapCommand(ns, map, 7, editable ? 1 : 0); - } - - public static void SendMapCommand(NetState ns, MapItem map, int command, int number = 0, int x = 0, int y = 0) - { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[11]); - writer.Write((byte)0x56); // Packet ID - - writer.Write(map.Serial); - writer.Write((byte)command); - writer.Write((byte)number); - writer.Write((short)x); - writer.Write((short)y); - - ns.Send(writer.Span); - } - } -} diff --git a/Projects/Scripts/Items/Maps/PresetMap.cs b/Projects/Scripts/Items/Maps/PresetMap.cs index 5039220e3..9f79db312 100644 --- a/Projects/Scripts/Items/Maps/PresetMap.cs +++ b/Projects/Scripts/Items/Maps/PresetMap.cs @@ -78,7 +78,7 @@ namespace Server.Items public Rectangle2D Bounds{ get; } - public static readonly PresetMapEntry[] Table = + public static PresetMapEntry[] Table{ get; } = { new PresetMapEntry(1041189, 200, 200, 1092, 1396, 1736, 1924), // map of Britain new PresetMapEntry(1041203, 200, 200, 0256, 1792, 1736, 2560), // map of Britain to Skara Brae @@ -142,4 +142,4 @@ namespace Server.Items Yew, YewToBritain } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Maps/TreasureMap.cs b/Projects/Scripts/Items/Maps/TreasureMap.cs index de2815a90..066f240eb 100644 --- a/Projects/Scripts/Items/Maps/TreasureMap.cs +++ b/Projects/Scripts/Items/Maps/TreasureMap.cs @@ -17,7 +17,7 @@ namespace Server.Items private static Point2D[] m_Locations; private static Point2D[] m_HavenLocations; - private static readonly Type[][] m_SpawnTypes = + private static Type[][] m_SpawnTypes = { new[] { typeof(HeadlessOne), typeof(Skeleton) }, new[] { typeof(Mongbat), typeof(Ratman), typeof(HeadlessOne), typeof(Skeleton), typeof(Zombie) }, @@ -32,13 +32,18 @@ namespace Server.Items private Mobile m_CompletedBy; private Mobile m_Decoder; private int m_Level; + private Map m_Map; [Constructible] - public TreasureMap(int level, Map facet = null) : base(facet) + public TreasureMap(int level, Map map) { m_Level = level; + m_Map = map; - ChestLocation = level == 0 ? GetRandomHavenLocation() : GetRandomLocation(); + if (level == 0) + ChestLocation = GetRandomHavenLocation(); + else + ChestLocation = GetRandomLocation(); Width = 300; Height = 300; @@ -122,12 +127,12 @@ namespace Server.Items } [CommandProperty(AccessLevel.GameMaster)] - public override Map Facet + public Map ChestMap { - get => base.Facet; + get => m_Map; set { - base.Facet = value; + m_Map = value; InvalidateProperties(); } } @@ -140,9 +145,15 @@ namespace Server.Items get { if (m_Decoder != null) - return m_Level == 6 ? 1063453 : 1041516 + m_Level; + { + if (m_Level == 6) + return 1063453; + return 1041516 + m_Level; + } - return m_Level == 6 ? 1063452 : 1041510 + m_Level; + if (m_Level == 6) + return 1063452; + return 1041510 + m_Level; } } @@ -151,8 +162,10 @@ namespace Server.Items if (m_Locations == null) LoadLocations(); - // ReSharper disable once PossibleNullReferenceException - return m_Locations.Length > 0 ? m_Locations[Utility.Random(m_Locations.Length)] : Point2D.Zero; + if (m_Locations.Length > 0) + return m_Locations[Utility.Random(m_Locations.Length)]; + + return Point2D.Zero; } public static Point2D GetRandomHavenLocation() @@ -160,8 +173,10 @@ namespace Server.Items if (m_HavenLocations == null) LoadLocations(); - // ReSharper disable once PossibleNullReferenceException - return m_HavenLocations.Length > 0 ? m_HavenLocations[Utility.Random(m_HavenLocations.Length)] : Point2D.Zero; + if (m_HavenLocations.Length > 0) + return m_HavenLocations[Utility.Random(m_HavenLocations.Length)]; + + return Point2D.Zero; } private static void LoadLocations() @@ -310,7 +325,7 @@ namespace Server.Items { from.SendLocalizedMessage(503020); // You are already digging treasure. } - else if (from.Map != Facet) + else if (from.Map != m_Map) { from.SendLocalizedMessage(1010479); // You seem to be in the right place, but may be on the wrong facet! } @@ -458,7 +473,7 @@ namespace Server.Items { base.GetProperties(list); - list.Add(Facet == Map.Felucca ? 1041502 : 1041503); // for somewhere in Felucca : for somewhere in Trammel + list.Add(m_Map == Map.Felucca ? 1041502 : 1041503); // for somewhere in Felucca : for somewhere in Trammel if (m_Completed) list.Add(1041507, m_CompletedBy == null ? "someone" : m_CompletedBy.Name); // completed by ~1_val~ @@ -468,8 +483,9 @@ namespace Server.Items { if (m_Completed) { - Packets.SendMessageLocalizedAffix(from.NetState, Serial, ItemID, MessageType.Label, 0x3B2, 3, 1048030, "", - AffixType.Append, $" completed by {m_CompletedBy?.Name ?? "someone"}"); + from.Send(new MessageLocalizedAffix(Serial, ItemID, MessageType.Label, 0x3B2, 3, 1048030, "", + AffixType.Append, + $" completed by {(m_CompletedBy == null ? "someone" : m_CompletedBy.Name)}", "")); } else if (m_Decoder != null) { @@ -480,10 +496,10 @@ namespace Server.Items } else { - LabelTo(from, 1041522, - m_Level == 6 - ? $"#{1063452}\t \t#{(Facet == Map.Felucca ? 1041502 : 1041503)}" - : $"#{1041510 + m_Level}\t \t#{(Facet == Map.Felucca ? 1041502 : 1041503)}"); + if (m_Level == 6) + LabelTo(from, 1041522, $"#{1063452}\t \t#{(m_Map == Map.Felucca ? 1041502 : 1041503)}"); + else + LabelTo(from, 1041522, $"#{1041510 + m_Level}\t \t#{(m_Map == Map.Felucca ? 1041502 : 1041503)}"); } } @@ -491,13 +507,14 @@ namespace Server.Items { base.Serialize(writer); - writer.Write(2); + writer.Write(1); writer.Write(m_CompletedBy); writer.Write(m_Level); writer.Write(m_Completed); writer.Write(m_Decoder); + writer.Write(m_Map); writer.Write(ChestLocation); } @@ -520,8 +537,7 @@ namespace Server.Items m_Level = reader.ReadInt(); m_Completed = reader.ReadBool(); m_Decoder = reader.ReadMobile(); - if (version < 2) - Facet = reader.ReadMap(); + m_Map = reader.ReadMap(); ChestLocation = reader.ReadPoint2D(); if (version == 0 && m_Completed) @@ -546,10 +562,12 @@ namespace Server.Items if (m_Map.Deleted) return; - Map facet = m_Map.Facet; + Map map = m_Map.m_Map; if (m_Map.m_Completed) + { from.SendLocalizedMessage(503028); // The treasure for this map has already been found. + } /* else if ( from != m_Map.m_Decoder ) { @@ -557,14 +575,22 @@ namespace Server.Items } */ else if (m_Map.m_Decoder != from && !m_Map.HasRequiredSkill(from)) + { from.SendLocalizedMessage( 503031); // You did not decode this map and have no clue where to look for the treasure. + } else if (!from.CanBeginAction()) + { from.SendLocalizedMessage(503020); // You are already digging treasure. + } else if (!HasDiggingTool(from)) - from.SendLocalizedMessage(1114416); // You must have a digging tool to dig for treasure. - else if (from.Map != facet) + { + from.SendMessage("You must have a digging tool to dig for treasure."); + } + else if (from.Map != map) + { from.SendLocalizedMessage(1010479); // You seem to be in the right place, but may be on the wrong facet! + } else { IPoint3D p = targeted as IPoint3D; @@ -591,17 +617,19 @@ namespace Server.Items if (Utility.InRange(targ3D, chest3D0, maxRange)) { if (from.Location.X == x && from.Location.Y == y) + { from.SendLocalizedMessage( 503030); // The chest can't be dug up because you are standing on top of it. - else if (facet != null) + } + else if (map != null) { - int z = facet.GetAverageZ(x, y); + int z = map.GetAverageZ(x, y); - if (!facet.CanFit(x, y, z, 16, true)) + if (!map.CanFit(x, y, z, 16, true)) from.SendLocalizedMessage( 503021); // You have found the treasure chest but something is keeping it from being dug up. else if (from.BeginAction()) - new DigTimer(from, m_Map, new Point3D(x, y, z), facet).Start(); + new DigTimer(from, m_Map, new Point3D(x, y, z), map).Start(); else from.SendLocalizedMessage(503020); // You are already digging treasure. } @@ -616,7 +644,9 @@ namespace Server.Items else { if (Utility.InRange(targ3D, chest3D0, 8)) // We're close, but not quite - from.SendLocalizedMessage(1080030, "", 0x44); // The treasure chest is very close! + { + from.SendAsciiMessage(0x44, "The treasure chest is very close!"); + } else { Direction dir = Utility.GetDirection(targ3D, chest3D0); diff --git a/Projects/Scripts/Items/Misc/BankCheck.cs b/Projects/Scripts/Items/Misc/BankCheck.cs index 161c06380..a07a360dd 100644 --- a/Projects/Scripts/Items/Misc/BankCheck.cs +++ b/Projects/Scripts/Items/Misc/BankCheck.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using Server.Accounting; using Server.Engines.Quests; using Server.Engines.Quests.Haven; using Server.Engines.Quests.Necro; diff --git a/Projects/Scripts/Items/Misc/Blocker.cs b/Projects/Scripts/Items/Misc/Blocker.cs index 87cfcce25..b5baf8be0 100644 --- a/Projects/Scripts/Items/Misc/Blocker.cs +++ b/Projects/Scripts/Items/Misc/Blocker.cs @@ -1,4 +1,3 @@ -using Server.Buffers; using Server.Network; namespace Server.Items @@ -14,21 +13,14 @@ namespace Server.Items public override int LabelNumber => 503057; // Impassable! - protected override void SendWorldPacketFor(NetState state) + protected override Packet GetWorldPacketFor(NetState state) { Mobile mob = state.Mobile; if (mob?.AccessLevel >= AccessLevel.GameMaster) - { - if (state.HighSeas) - SendGMItemHS(state); - else if (state.StygianAbyss) - SendGMItemSA(state); - else - SendGMItem(state); - } + return new GMItemPacket(this); - base.SendWorldPacketFor(state); + return base.GetWorldPacketFor(state); } public override void Serialize(GenericWriter writer) @@ -45,138 +37,66 @@ namespace Server.Items int version = reader.ReadInt(); } - private void SendGMItem(NetState ns) + public sealed class GMItemPacket : Packet { - if (ns == null) - return; + public GMItemPacket(Item item) : base(0x1A) + { + EnsureCapacity(20); - SpanWriter w = new SpanWriter(stackalloc byte[20]); - w.Write((byte)0x1A); // Packet ID - w.Position += 2; // Dynamic Length + // 14 base length + // +2 - Amount + // +2 - Hue + // +1 - Flags - uint serial = Serial.Value; - int itemId = 0x1183; - int amount = Amount; - Point3D loc = Location; - int x = loc.X; - int y = loc.Y; - int hue = Hue; - int flags = GetPacketFlags(); - int direction = (int)Direction; + uint serial = item.Serial.Value; + int itemID = 0x1183; + int amount = item.Amount; + Point3D loc = item.Location; + int x = loc.X; + int y = loc.Y; + int hue = item.Hue; + int flags = item.GetPacketFlags(); + int direction = (int)item.Direction; - if (amount != 0) - serial |= 0x80000000; - else - serial &= 0x7FFFFFFF; + if (amount != 0) + serial |= 0x80000000; + else + serial &= 0x7FFFFFFF; - w.Write(serial); + m_Stream.Write(serial); + m_Stream.Write((short)(itemID & 0x7FFF)); - w.Write((short)itemId); + if (amount != 0) + m_Stream.Write((short)amount); - if (amount != 0) - w.Write((short)amount); + x &= 0x7FFF; - x &= 0x7FFF; + if (direction != 0) + x |= 0x8000; - if (direction != 0) x |= 0x8000; + m_Stream.Write((short)x); - w.Write((short)x); + y &= 0x3FFF; - y &= 0x3FFF; + if (hue != 0) + y |= 0x8000; - if (hue != 0) y |= 0x8000; + if (flags != 0) + y |= 0x4000; - if (flags != 0) y |= 0x4000; + m_Stream.Write((short)y); - w.Write((short)y); + if (direction != 0) + m_Stream.Write((byte)direction); - if (direction != 0) - w.Write((byte)direction); + m_Stream.Write((sbyte)loc.Z); - w.Write((sbyte)loc.Z); + if (hue != 0) + m_Stream.Write((ushort)hue); - if (hue != 0) - w.Write((ushort)hue); - - if (flags != 0) - w.Write((byte)flags); - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - - public void SendGMItemSA(NetState ns) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[24]); - w.Write((byte)0xF3); // Packet ID - - w.Write((short)0x01); - - int itemId = 0x1183; - - w.Position++; // w.Write((byte)0); - - w.Write(Serial); - - w.Write((short)itemId); - - w.Write((byte)Direction); - - short amount = (short)Amount; - w.Write(amount); - w.Write(amount); - - Point3D loc = Location; - w.Write((short)(loc.X & 0x7FFF)); - w.Write((short)(loc.Y & 0x3FFF)); - w.Write((sbyte)loc.Z); - - w.Write((byte)Light); - w.Write((short)Hue); - w.Write((byte)GetPacketFlags()); - - ns.Send(w.RawSpan); - } - - public void SendGMItemHS(NetState ns) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[26]); - w.Write((byte)0xF3); // Packet ID - - w.Write((short)0x01); - - int itemId = 0x1183; - - w.Position++; // w.Write((byte)0); - - w.Write(Serial); - - w.Write((short)itemId); - - w.Write((byte)Direction); - - short amount = (short)Amount; - w.Write(amount); - w.Write(amount); - - Point3D loc = Location; - w.Write((short)(loc.X & 0x7FFF)); - w.Write((short)(loc.Y & 0x3FFF)); - w.Write((sbyte)loc.Z); - - w.Write((byte)Light); - w.Write((short)Hue); - w.Write((byte)GetPacketFlags()); - - ns.Send(w.RawSpan); + if (flags != 0) + m_Stream.Write((byte)flags); + } } } } diff --git a/Projects/Scripts/Items/Misc/BulletinBoards.cs b/Projects/Scripts/Items/Misc/BulletinBoards.cs index 7e17e5874..69ec0b014 100644 --- a/Projects/Scripts/Items/Misc/BulletinBoards.cs +++ b/Projects/Scripts/Items/Misc/BulletinBoards.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Server.Buffers; using Server.Network; using Server.Targeting; @@ -55,7 +54,7 @@ namespace Server.Items } [CommandProperty(AccessLevel.GameMaster)] - public string BoardName { get; set; } + public string BoardName{ get; set; } public static bool CheckTime(DateTime time, TimeSpan range) => time + range < DateTime.UtcNow; @@ -67,10 +66,8 @@ namespace Server.Items if (minutes != 0 && seconds != 0) return $"{minutes} minute{(minutes == 1 ? "" : "s")} and {seconds} second{(seconds == 1 ? "" : "s")}"; - if (minutes != 0) return $"{minutes} minute{(minutes == 1 ? "" : "s")}"; - return $"{seconds} second{(seconds == 1 ? "" : "s")}"; } @@ -149,8 +146,11 @@ namespace Server.Items NetState state = from.NetState; - BBPackets.SendBBDisplayBoard(state, this); - Packets.SendContainerContent(state, from, this); + state.Send(new BBDisplayBoard(this)); + if (state.ContainerGridLines) + state.Send(new ContainerContent6017(from, this)); + else + state.Send(new ContainerContent(from, this)); } else { @@ -232,14 +232,18 @@ namespace Server.Items public static void BBRequestContent(Mobile from, BaseBulletinBoard board, PacketReader pvSrc) { - if (World.FindItem(pvSrc.ReadUInt32()) is BulletinMessage msg && msg.Parent == board) - BBPackets.SendBBMessageContent(from.NetState, board, msg); + if (!(World.FindItem(pvSrc.ReadUInt32()) is BulletinMessage msg) || msg.Parent != board) + return; + + from.Send(new BBMessageContent(board, msg)); } public static void BBRequestHeader(Mobile from, BaseBulletinBoard board, PacketReader pvSrc) { - if (World.FindItem(pvSrc.ReadUInt32()) is BulletinMessage msg && msg.Parent == board) - BBPackets.SendBBMessageHeader(from.NetState, board, msg); + if (!(World.FindItem(pvSrc.ReadUInt32()) is BulletinMessage msg) || msg.Parent != board) + return; + + from.Send(new BBMessageHeader(board, msg)); } public static void BBPostMessage(Mobile from, BaseBulletinBoard board, PacketReader pvSrc) @@ -267,7 +271,7 @@ namespace Server.Items return; } - string subject = pvSrc.ReadStringSafe(pvSrc.ReadByte()); + string subject = pvSrc.ReadUTF8StringSafe(pvSrc.ReadByte()); if (subject.Length == 0) return; @@ -278,7 +282,7 @@ namespace Server.Items return; for (int i = 0; i < lines.Length; ++i) - lines[i] = pvSrc.ReadStringSafe(pvSrc.ReadByte()); + lines[i] = pvSrc.ReadUTF8StringSafe(pvSrc.ReadByte()); board.PostMessage(from, thread, subject, lines); } @@ -340,25 +344,25 @@ namespace Server.Items { } - public Mobile Poster { get; private set; } + public Mobile Poster{ get; private set; } - public BulletinMessage Thread { get; private set; } + public BulletinMessage Thread{ get; private set; } - public string Subject { get; private set; } + public string Subject{ get; private set; } - public DateTime Time { get; private set; } + public DateTime Time{ get; private set; } - public DateTime LastPostTime { get; set; } + public DateTime LastPostTime{ get; set; } - public string PostedName { get; private set; } + public string PostedName{ get; private set; } - public int PostedBody { get; private set; } + public int PostedBody{ get; private set; } - public int PostedHue { get; private set; } + public int PostedHue{ get; private set; } - public BulletinEquip[] PostedEquip { get; private set; } + public BulletinEquip[] PostedEquip{ get; private set; } - public string[] Lines { get; private set; } + public string[] Lines{ get; private set; } public string GetTimeAsString() => Time.ToString("MMM dd, yyyy"); @@ -448,64 +452,70 @@ namespace Server.Items } } - public static class BBPackets + public class BBDisplayBoard : Packet { - public static void SendBBDisplayBoard(NetState ns, BaseBulletinBoard board) + public BBDisplayBoard(BaseBulletinBoard board) : base(0x71) { - SpanWriter writer = new SpanWriter(stackalloc byte[38]); - writer.Write((byte)0x71); // Packet ID - writer.Write((ushort)38); // Dynamic Length + EnsureCapacity(38); - writer.Position++; // writer.Write((byte)0); // Command - writer.Write(board.Serial); - writer.WriteAsciiNull(board.BoardName ?? "", 29); + byte[] buffer = Utility.UTF8.GetBytes(board.BoardName ?? ""); - ns.Send(writer.Span); + m_Stream.Write((byte)0x00); // PacketID + m_Stream.Write(board.Serial); // Bulletin board serial + + // Bulletin board name + if (buffer.Length >= 29) + { + m_Stream.Write(buffer, 0, 29); + m_Stream.Write((byte)0); + } + else + { + m_Stream.Write(buffer, 0, buffer.Length); + m_Stream.Fill(30 - buffer.Length); + } + } + } + + public class BBMessageHeader : Packet + { + public BBMessageHeader(BaseBulletinBoard board, BulletinMessage msg) : base(0x71) + { + string poster = SafeString(msg.PostedName); + string subject = SafeString(msg.Subject); + string time = SafeString(msg.GetTimeAsString()); + + EnsureCapacity(22 + poster.Length + subject.Length + time.Length); + + m_Stream.Write((byte)0x01); // PacketID + m_Stream.Write(board.Serial); // Bulletin board serial + m_Stream.Write(msg.Serial); // Message serial + + BulletinMessage thread = msg.Thread; + + if (thread == null) + m_Stream.Write(0); // Thread serial--root + else + m_Stream.Write(thread.Serial); // Thread serial--parent + + WriteString(poster); + WriteString(subject); + WriteString(time); } - public static void SendBBMessageHeader(NetState ns, BaseBulletinBoard board, BulletinMessage msg) + public void WriteString(string v) { - string poster = msg.PostedName ?? ""; - string subject = msg.Subject ?? ""; - string time = msg.GetTimeAsString() ?? ""; + byte[] buffer = Utility.UTF8.GetBytes(v); + int len = buffer.Length + 1; - byte posterLength = Math.Min((byte)poster.Length, (byte)254); - byte subjectLength = Math.Min((byte)subject.Length, (byte)254); - byte timeLength = Math.Min((byte)time.Length, (byte)254); + if (len > 255) + len = 255; - int length = 22 + posterLength + subjectLength + timeLength; - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0x71); // Packet ID - writer.Write((ushort)length); // Dynamic Length - - writer.Write((byte)0x01); // Command - writer.Write(board.Serial); // Bulletin board serial - writer.Write(msg.Serial); // Message serial - writer.Write(msg.Thread?.Serial ?? 0); - - writer.Write(posterLength); - writer.WriteAsciiNull(poster, posterLength + 1); - writer.Write(subjectLength); - writer.WriteAsciiNull(subject, subjectLength + 1); - writer.Write(timeLength); - writer.WriteAsciiNull(time, timeLength + 1); - - ns.Send(writer.Span); + m_Stream.Write((byte)len); + m_Stream.Write(buffer, 0, len - 1); + m_Stream.Write((byte)0); } - public static void SendBBMessageContent(NetState ns, BaseBulletinBoard board, BulletinMessage msg) - { - string poster = msg.PostedName ?? ""; - string subject = msg.Subject ?? ""; - string time = msg.GetTimeAsString() ?? ""; - - byte posterLength = Math.Min((byte)poster.Length, (byte)254); - byte subjectLength = Math.Min((byte)subject.Length, (byte)254); - byte timeLength = Math.Min((byte)time.Length, (byte)254); - - int equipLength = Math.Min(msg.PostedEquip.Length, 255); - int msgLength = Math.Min(msg.Lines.Length, 255); - public string SafeString(string v) => v ?? string.Empty; } @@ -519,43 +529,72 @@ namespace Server.Items EnsureCapacity(22 + poster.Length + subject.Length + time.Length); - writer.Write((byte)0x02); // Command - writer.Write(board.Serial); // Bulletin board serial - writer.Write(msg.Serial); // Message serial + m_Stream.Write((byte)0x02); // PacketID + m_Stream.Write(board.Serial); // Bulletin board serial + m_Stream.Write(msg.Serial); // Message serial - writer.Write(posterLength); - writer.WriteAsciiNull(poster, posterLength + 1); - writer.Write(subjectLength); - writer.WriteAsciiNull(subject, subjectLength + 1); - writer.Write(timeLength); - writer.WriteAsciiNull(time, timeLength + 1); + WriteString(poster); + WriteString(subject); + WriteString(time); - writer.Write((short)msg.PostedBody); - writer.Write((short)msg.PostedHue); + m_Stream.Write((short)msg.PostedBody); + m_Stream.Write((short)msg.PostedHue); - writer.Write((byte)equipLength); + int len = msg.PostedEquip.Length; - for (int i = 0; i < equipLength; ++i) + if (len > 255) + len = 255; + + m_Stream.Write((byte)len); + + for (int i = 0; i < len; ++i) { BulletinEquip eq = msg.PostedEquip[i]; - writer.Write((short)eq.itemID); - writer.Write((short)eq.hue); + m_Stream.Write((short)eq.itemID); + m_Stream.Write((short)eq.hue); } - writer.Write((byte)msgLength); + len = msg.Lines.Length; - for (int i = 0; i < msgLength; ++i) - { - string line = msg.Lines[i]; - byte len = Math.Min((byte)line.Length, (byte)254); - writer.WriteAsciiNull(line, len); - } + if (len > 255) + len = 255; - writer.Position = 1; - writer.Write((ushort)writer.WrittenCount); + m_Stream.Write((byte)len); - ns.Send(writer.Span); + for (int i = 0; i < len; ++i) + WriteString(msg.Lines[i], true); + } + + public void WriteString(string v) + { + WriteString(v, false); + } + + public void WriteString(string v, bool padding) + { + byte[] buffer = Utility.UTF8.GetBytes(v); + int tail = padding ? 2 : 1; + int len = buffer.Length + tail; + + if (len > 255) + len = 255; + + m_Stream.Write((byte)len); + m_Stream.Write(buffer, 0, len - tail); + + if (padding) + m_Stream.Write((short)0); // padding compensates for a client bug + else + m_Stream.Write((byte)0); + } + + public string SafeString(string v) + { + if (v == null) + return string.Empty; + + return v; } } } diff --git a/Projects/Scripts/Items/Misc/CommunicationCrystals.cs b/Projects/Scripts/Items/Misc/CommunicationCrystals.cs index 1cd235d19..d660b678f 100644 --- a/Projects/Scripts/Items/Misc/CommunicationCrystals.cs +++ b/Projects/Scripts/Items/Misc/CommunicationCrystals.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Network; using Server.Targeting; @@ -30,7 +29,14 @@ namespace Server.Items public int Amount{ get; } - public static CrystalRechargeInfo Get(Type type) => Table.FirstOrDefault(info => info.Type == type); + public static CrystalRechargeInfo Get(Type type) + { + foreach (CrystalRechargeInfo info in Table) + if (info.Type == type) + return info; + + return null; + } } public class BroadcastCrystal : Item diff --git a/Projects/Scripts/Items/Misc/Corpses/Corpse.cs b/Projects/Scripts/Items/Misc/Corpses/Corpse.cs index dd37973f3..5aaa1f3fc 100644 --- a/Projects/Scripts/Items/Misc/Corpses/Corpse.cs +++ b/Projects/Scripts/Items/Misc/Corpses/Corpse.cs @@ -100,7 +100,7 @@ namespace Server.Items public Corpse(Mobile owner, HairInfo hair, FacialHairInfo facialhair, List equipItems) : base(0x2006) { - // To suppress console warnings, stackable must be true + // To supress console warnings, stackable must be true Stackable = true; Amount = owner.Body; // protocol defines that for itemid 0x2006, amount=body Stackable = false; @@ -193,7 +193,16 @@ namespace Server.Items } [CommandProperty(AccessLevel.GameMaster)] - public virtual bool InstancedCorpse => Core.SE && DateTime.UtcNow < TimeOfDeath + InstancedCorpseTime; + public virtual bool InstancedCorpse + { + get + { + if (!Core.SE) + return false; + + return DateTime.UtcNow < TimeOfDeath + InstancedCorpseTime; + } + } public override bool IsDecoContainer => false; @@ -293,7 +302,9 @@ namespace Server.Items Mobile dead = Owner; if (GetFlag(CorpseFlag.Carved) || dead == null) + { from.SendLocalizedMessage(500485); // You see nothing useful to carve from the corpse. + } else if (((Body)Amount).IsHuman && ItemID == 0x2006) { new Blood(0x122D).MoveToWorld(Location, Map); @@ -317,9 +328,13 @@ namespace Server.Items from.CriminalAction(true); } else if (dead is BaseCreature creature) + { creature.OnCarve(from, this, item); + } else + { from.SendLocalizedMessage(500485); // You see nothing useful to carve from the corpse. + } } public override bool IsChildVisibleTo(Mobile m, Item child) => @@ -332,7 +347,8 @@ namespace Server.Items if (Aggressors.Count == 0 || Items.Count == 0) return; - m_InstancedItems ??= new Dictionary(); + if (m_InstancedItems == null) + m_InstancedItems = new Dictionary(); List m_Stackables = new List(); List m_Unstackables = new List(); @@ -385,7 +401,7 @@ namespace Server.Items } if (remainder == 0) - m_InstancedItems.Add(item, new InstancedItemInfo(item, attackers[^1])); + m_InstancedItems.Add(item, new InstancedItemInfo(item, attackers[attackers.Count - 1])); else m_Unstackables.Add(item); } @@ -411,7 +427,9 @@ namespace Server.Items if (InstancedCorpse) { - m_InstancedItems ??= new Dictionary(); + if (m_InstancedItems == null) + m_InstancedItems = new Dictionary(); + m_InstancedItems.Add(carved, new InstancedItemInfo(carved, carver)); } } @@ -446,6 +464,7 @@ namespace Server.Items public override void OnAfterDelete() { m_DecayTimer?.Stop(); + m_DecayTimer = null; } @@ -524,23 +543,29 @@ namespace Server.Items writer.WriteDeltaTime(TimeOfDeath); - if (m_RestoreTable == null) - writer.Write(0); - else + List> list = m_RestoreTable == null + ? null + : new List>(m_RestoreTable); + int count = list?.Count ?? 0; + + writer.Write(count); + + for (int i = 0; i < count; ++i) { - writer.Write(m_RestoreTable.Count); + KeyValuePair kvp = list[i]; + Item item = kvp.Key; + Point3D loc = kvp.Value; - foreach (var (item, loc) in m_RestoreTable) + writer.Write(item); + + if (item.Location == loc) { - writer.Write(item); - - if (item.Location == loc) - writer.Write(false); - else - { - writer.Write(true); - writer.Write(loc); - } + writer.Write(false); + } + else + { + writer.Write(true); + writer.Write(loc); } } @@ -732,8 +757,12 @@ namespace Server.Items if (!(((Body)Amount).IsHuman && ItemID == 0x2006)) return; - CorpsePackets.SendCorpseContent(state, state.Mobile, this); - CorpsePackets.SendCorpseEquip(state, state.Mobile, this); + if (state.ContainerGridLines) + state.Send(new CorpseContent6017(state.Mobile, this)); + else + state.Send(new CorpseContent(state.Mobile, this)); + + state.Send(new CorpseEquip(state.Mobile, this)); } public bool IsCriminalAction(Mobile from) @@ -807,7 +836,8 @@ namespace Server.Items if (item == null) return; - m_RestoreTable ??= new Dictionary(); + if (m_RestoreTable == null) + m_RestoreTable = new Dictionary(); m_RestoreTable[item] = loc; } @@ -1035,7 +1065,7 @@ namespace Server.Items ObjectPropertyList opl = PropertyList; if (opl.Header > 0) - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, hue, 3, opl.Header, Name, opl.HeaderArgs); + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, opl.Header, Name, opl.HeaderArgs)); } public override void OnSingleClick(Mobile from) @@ -1045,12 +1075,14 @@ namespace Server.Items if (ItemID == 0x2006) // Corpse form { if (m_CorpseName != null) - Packets.SendAsciiMessage(from.NetState, Serial, ItemID, MessageType.Label, hue, 3, "", m_CorpseName); + from.Send(new AsciiMessage(Serial, ItemID, MessageType.Label, hue, 3, "", m_CorpseName)); else - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, hue, 3, 1046414, "", Name); + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1046414, "", Name)); } else // Bone form - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, hue, 3, 1046414, "", Name); + { + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1046414, "", Name)); + } } private class InstancedItemInfo diff --git a/Projects/Scripts/Items/Misc/Corpses/Packets.cs b/Projects/Scripts/Items/Misc/Corpses/Packets.cs index 7040d5060..cb4cb10d9 100644 --- a/Projects/Scripts/Items/Misc/Corpses/Packets.cs +++ b/Projects/Scripts/Items/Misc/Corpses/Packets.cs @@ -1,29 +1,24 @@ using System.Collections.Generic; -using Server.Buffers; +using System.IO; using Server.Items; namespace Server.Network { - public static class CorpsePackets + public sealed class CorpseEquip : Packet { - public static void SendCorpseEquip(NetState ns, Mobile beholder, Corpse beheld) + public CorpseEquip(Mobile beholder, Corpse beheld) : base(0x89) { - if (ns == null) - return; - List list = beheld.EquipItems; - int length = 8 + list.Count * 5; - if (beheld.Hair?.ItemID > 0) - length += 5; - if (beheld.FacialHair?.ItemID > 0) - length += 5; + int count = list.Count; + if (beheld.Hair != null && beheld.Hair.ItemID > 0) + count++; + if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0) + count++; - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0x89); // Packet ID - writer.Write((ushort)length); // Dynamic Length + EnsureCapacity(8 + count * 5); - writer.Write(beheld.Serial); + m_Stream.Write(beheld.Serial); for (int i = 0; i < list.Count; ++i) { @@ -31,180 +26,173 @@ namespace Server.Network if (!item.Deleted && beholder.CanSee(item) && item.Parent == beheld) { - writer.Write((byte)(item.Layer + 1)); - writer.Write(item.Serial); + m_Stream.Write((byte)(item.Layer + 1)); + m_Stream.Write(item.Serial); } } - if (beheld.Hair?.ItemID > 0) + if (beheld.Hair != null && beheld.Hair.ItemID > 0) { - writer.Write((byte)(Layer.Hair + 1)); - writer.Write(HairInfo.FakeSerial(beheld.Owner.Serial) - 2); + m_Stream.Write((byte)(Layer.Hair + 1)); + m_Stream.Write(HairInfo.FakeSerial(beheld.Owner) - 2); } - if (beheld.FacialHair?.ItemID > 0) + if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0) { - writer.Write((byte)(Layer.FacialHair + 1)); - writer.Write(FacialHairInfo.FakeSerial(beheld.Owner.Serial) - 2); + m_Stream.Write((byte)(Layer.FacialHair + 1)); + m_Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner) - 2); } - writer.Position++; // writer.Write((byte)Layer.Invalid); - - ns.Send(writer.Span); - } - - public static void SendCorpseContent(NetState ns, Mobile beholder, Corpse corpse) - { - if (ns == null) - return; - - if (ns.ContainerGridLines) - SendCorpseContentNew(ns, beholder, corpse); - else - SendCorpseContentOld(ns, beholder, corpse); - } - - public static void SendCorpseContentOld(NetState ns, Mobile beholder, Corpse corpse) - { - if (ns == null) - return; - - List items = corpse.EquipItems; - int length = 5 + items.Count * 19; - - if (corpse.Hair?.ItemID > 0) - length += 19; - if (corpse.FacialHair?.ItemID > 0) - length += 19; - - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0x3C); // Packet ID - writer.Write((ushort)length); // Dynamic Length - writer.Position += 2; - - ushort written = 0; - - for (int i = 0; i < items.Count; ++i) - { - Item child = items[i]; - - if (!child.Deleted && child.Parent == corpse && beholder.CanSee(child)) - { - writer.Write(child.Serial); - writer.Write((ushort)child.ItemID); - writer.Position++; // signed, itemID offset - writer.Write((ushort)child.Amount); - writer.Write((short)child.X); - writer.Write((short)child.Y); - writer.Write(corpse.Serial); - writer.Write((ushort)child.Hue); - - ++written; - } - } - - if (corpse.Hair?.ItemID > 0) - { - writer.Write(HairInfo.FakeSerial(corpse.Owner.Serial) - 2); - writer.Write((ushort)corpse.Hair.ItemID); - writer.Position++; // signed, itemID offset - writer.Write((ushort)1); - writer.Position += 4; - writer.Write(corpse.Serial); - writer.Write((ushort)corpse.Hair.Hue); - - ++written; - } - - if (corpse.FacialHair?.ItemID > 0) - { - writer.Write(FacialHairInfo.FakeSerial(corpse.Owner.Serial) - 2); - writer.Write((ushort)corpse.FacialHair.ItemID); - writer.Position++; // signed, itemID offset - writer.Write((ushort)1); - writer.Position += 4; - writer.Write(corpse.Serial); - writer.Write((ushort)corpse.FacialHair.Hue); - - ++written; - } - - writer.Position = 3; - writer.Write(written); - - ns.Send(writer.Span); - } - - public static void SendCorpseContentNew(NetState ns, Mobile beholder, Corpse corpse) - { - if (ns == null) - return; - - List items = corpse.EquipItems; - int length = 5 + items.Count * 20; - - if (corpse.Hair?.ItemID > 0) - length += 20; - if (corpse.FacialHair?.ItemID > 0) - length += 20; - - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0x3C); // Packet ID - writer.Write((ushort)length); // Dynamic Length - writer.Position += 2; - - ushort written = 0; - - for (int i = 0; i < items.Count; ++i) - { - Item child = items[i]; - - if (!child.Deleted && child.Parent == corpse && beholder.CanSee(child)) - { - writer.Write(child.Serial); - writer.Write((ushort)child.ItemID); - writer.Position++; // signed, itemID offset - writer.Write((ushort)child.Amount); - writer.Write((short)child.X); - writer.Write((short)child.Y); - writer.Position++; // grid location - writer.Write(corpse.Serial); - writer.Write((ushort)child.Hue); - - ++written; - } - } - - if (corpse.Hair?.ItemID > 0) - { - writer.Write(HairInfo.FakeSerial(corpse.Owner.Serial) - 2); - writer.Write((ushort)corpse.Hair.ItemID); - writer.Position++; // signed, itemID offset - writer.Write((ushort)1); - writer.Position += 5; - writer.Write(corpse.Serial); - writer.Write((ushort)corpse.Hair.Hue); - - ++written; - } - - if (corpse.FacialHair?.ItemID > 0) - { - writer.Write(FacialHairInfo.FakeSerial(corpse.Owner.Serial) - 2); - writer.Write((ushort)corpse.FacialHair.ItemID); - writer.Position++; // signed, itemID offset - writer.Write((ushort)1); - writer.Position += 5; - writer.Write(corpse.Serial); - writer.Write((ushort)corpse.FacialHair.Hue); - - ++written; - } - - writer.Position = 3; - writer.Write(written); - - ns.Send(writer.Span); + m_Stream.Write((byte)Layer.Invalid); } } -} + + public sealed class CorpseContent : Packet + { + public CorpseContent(Mobile beholder, Corpse beheld) + : base(0x3C) + { + List items = beheld.EquipItems; + int count = items.Count; + + if (beheld.Hair != null && beheld.Hair.ItemID > 0) + count++; + if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0) + count++; + + EnsureCapacity(5 + count * 19); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write((ushort)0); + + for (int i = 0; i < items.Count; ++i) + { + Item child = items[i]; + + if (!child.Deleted && child.Parent == beheld && beholder.CanSee(child)) + { + m_Stream.Write(child.Serial); + m_Stream.Write((ushort)child.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)child.Amount); + m_Stream.Write((short)child.X); + m_Stream.Write((short)child.Y); + m_Stream.Write(beheld.Serial); + m_Stream.Write((ushort)child.Hue); + + ++written; + } + } + + if (beheld.Hair != null && beheld.Hair.ItemID > 0) + { + m_Stream.Write(HairInfo.FakeSerial(beheld.Owner) - 2); + m_Stream.Write((ushort)beheld.Hair.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)1); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write(beheld.Serial); + m_Stream.Write((ushort)beheld.Hair.Hue); + + ++written; + } + + if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0) + { + m_Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner) - 2); + m_Stream.Write((ushort)beheld.FacialHair.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)1); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write(beheld.Serial); + m_Stream.Write((ushort)beheld.FacialHair.Hue); + + ++written; + } + + m_Stream.Seek(pos, SeekOrigin.Begin); + m_Stream.Write((ushort)written); + } + } + + public sealed class CorpseContent6017 : Packet + { + public CorpseContent6017(Mobile beholder, Corpse beheld) + : base(0x3C) + { + List items = beheld.EquipItems; + int count = items.Count; + + if (beheld.Hair != null && beheld.Hair.ItemID > 0) + count++; + if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0) + count++; + + EnsureCapacity(5 + count * 20); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write((ushort)0); + + for (int i = 0; i < items.Count; ++i) + { + Item child = items[i]; + + if (!child.Deleted && child.Parent == beheld && beholder.CanSee(child)) + { + m_Stream.Write(child.Serial); + m_Stream.Write((ushort)child.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)child.Amount); + m_Stream.Write((short)child.X); + m_Stream.Write((short)child.Y); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write(beheld.Serial); + m_Stream.Write((ushort)child.Hue); + + ++written; + } + } + + if (beheld.Hair != null && beheld.Hair.ItemID > 0) + { + m_Stream.Write(HairInfo.FakeSerial(beheld.Owner) - 2); + m_Stream.Write((ushort)beheld.Hair.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)1); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write(beheld.Serial); + m_Stream.Write((ushort)beheld.Hair.Hue); + + ++written; + } + + if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0) + { + m_Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner) - 2); + m_Stream.Write((ushort)beheld.FacialHair.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)1); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write(beheld.Serial); + m_Stream.Write((ushort)beheld.FacialHair.Hue); + + ++written; + } + + m_Stream.Seek(pos, SeekOrigin.Begin); + m_Stream.Write((ushort)written); + } + } +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Misc/EffectController.cs b/Projects/Scripts/Items/Misc/EffectController.cs index ecf776620..16f94d462 100644 --- a/Projects/Scripts/Items/Misc/EffectController.cs +++ b/Projects/Scripts/Items/Misc/EffectController.cs @@ -304,7 +304,7 @@ namespace Server.Items { case ECEffectType.Lightning: { - Effects.SendBoltEffect(from, false); + Effects.SendBoltEffect(from, false, EffectHue); break; } case ECEffectType.Location: @@ -334,4 +334,4 @@ namespace Server.Items } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Misc/EffectItem.cs b/Projects/Scripts/Items/Misc/EffectItem.cs index ebd8c9992..dcddd3b74 100644 --- a/Projects/Scripts/Items/Misc/EffectItem.cs +++ b/Projects/Scripts/Items/Misc/EffectItem.cs @@ -83,4 +83,4 @@ namespace Server.Items } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Misc/Firebomb.cs b/Projects/Scripts/Items/Misc/Firebomb.cs index 0bc4553bf..6ab46e1a2 100644 --- a/Projects/Scripts/Items/Misc/Firebomb.cs +++ b/Projects/Scripts/Items/Misc/Firebomb.cs @@ -66,7 +66,8 @@ namespace Server.Items from.SendLocalizedMessage(1060581); // You've already lit it! Better throw it now! } - m_Users ??= new List(); + if (m_Users == null) + m_Users = new List(); if (!m_Users.Contains(from)) m_Users.Add(from); diff --git a/Projects/Scripts/Items/Misc/Gold.cs b/Projects/Scripts/Items/Misc/Gold.cs index bacb07ef1..4a8553f01 100644 --- a/Projects/Scripts/Items/Misc/Gold.cs +++ b/Projects/Scripts/Items/Misc/Gold.cs @@ -1,4 +1,5 @@ using System; +using Server.Accounting; namespace Server.Items { diff --git a/Projects/Scripts/Items/Misc/InteriorDecorator.cs b/Projects/Scripts/Items/Misc/InteriorDecorator.cs index c9012b72e..8e01befe1 100644 --- a/Projects/Scripts/Items/Misc/InteriorDecorator.cs +++ b/Projects/Scripts/Items/Misc/InteriorDecorator.cs @@ -182,7 +182,8 @@ namespace Server.Items if (addon != null) { - isDecorableComponent |= count == 1 && Core.SE; + if (count == 1 && Core.SE) + isDecorableComponent = true; if (m_Decorator.Command == DecorateCommand.Turn) { @@ -190,7 +191,8 @@ namespace Server.Items (FlippableAddonAttribute[])addon.GetType() .GetCustomAttributes(typeof(FlippableAddonAttribute), false); - isDecorableComponent = attributes.Length > 0; + if (attributes.Length > 0) + isDecorableComponent = true; } } diff --git a/Projects/Scripts/Items/Misc/Key.cs b/Projects/Scripts/Items/Misc/Key.cs index 60a99de75..475b3492b 100644 --- a/Projects/Scripts/Items/Misc/Key.cs +++ b/Projects/Scripts/Items/Misc/Key.cs @@ -1,4 +1,5 @@ using Server.Network; +using Server.Prompts; using Server.Targeting; namespace Server.Items @@ -203,9 +204,14 @@ namespace Server.Items { base.GetProperties(list); - string desc = m_KeyVal == 0 ? "(blank)" : m_Description?.Trim() ?? ""; + string desc; - if (desc != "") + if (m_KeyVal == 0) + desc = "(blank)"; + else if ((desc = m_Description) == null || (desc = desc.Trim()).Length <= 0) + desc = null; + + if (desc != null) list.Add(desc); } @@ -213,10 +219,15 @@ namespace Server.Items { base.OnSingleClick(from); - string desc = m_KeyVal == 0 ? "(blank)" : m_Description?.Trim() ?? ""; + string desc; + + if (m_KeyVal == 0) + desc = "(blank)"; + else if ((desc = m_Description) == null || (desc = desc.Trim()).Length <= 0) + desc = ""; if (desc.Length > 0) - Packets.SendUnicodeMessage(from.NetState, Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", "", desc); + from.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", "", desc)); } public bool UseOn(Mobile from, ILockable o) diff --git a/Projects/Scripts/Items/Misc/KeyRing.cs b/Projects/Scripts/Items/Misc/KeyRing.cs index 40480d8a7..4965f6827 100644 --- a/Projects/Scripts/Items/Misc/KeyRing.cs +++ b/Projects/Scripts/Items/Misc/KeyRing.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using Server.Targeting; namespace Server.Items @@ -110,7 +109,14 @@ namespace Server.Items UpdateItemID(); } - public bool ContainsKey(uint keyValue) => Keys.Any(key => key.KeyValue == keyValue); + public bool ContainsKey(uint keyValue) + { + foreach (Key key in Keys) + if (key.KeyValue == keyValue) + return true; + + return false; + } private void UpdateItemID() { @@ -163,7 +169,9 @@ namespace Server.Items } else if (targeted is ILockable o) { - if (m_KeyRing.Keys.Any(key => key.UseOn(from, o))) return; + foreach (Key key in m_KeyRing.Keys) + if (key.UseOn(from, o)) + return; from.SendLocalizedMessage(1008140); // You do not have a key for that. } @@ -174,4 +182,4 @@ namespace Server.Items } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Misc/LOSBlocker.cs b/Projects/Scripts/Items/Misc/LOSBlocker.cs index ca21df5a3..2d44cef77 100644 --- a/Projects/Scripts/Items/Misc/LOSBlocker.cs +++ b/Projects/Scripts/Items/Misc/LOSBlocker.cs @@ -1,4 +1,3 @@ -using Server.Buffers; using Server.Network; namespace Server.Items @@ -20,21 +19,13 @@ namespace Server.Items TileData.ItemTable[0x21A2].Height = 20; } - protected override void SendWorldPacketFor(NetState state) + protected override Packet GetWorldPacketFor(NetState state) { Mobile mob = state.Mobile; - if (mob?.AccessLevel >= AccessLevel.GameMaster) - { - if (state.HighSeas) - SendGMItemHS(state); - else if (state.StygianAbyss) - SendGMItemSA(state); - else - SendGMItem(state); - } + if (mob?.AccessLevel >= AccessLevel.GameMaster) return new GMItemPacket(this); - base.SendWorldPacketFor(state); + return base.GetWorldPacketFor(state); } public override void Serialize(GenericWriter writer) @@ -54,138 +45,66 @@ namespace Server.Items ItemID = 0x21A2; } - private void SendGMItem(NetState ns) + public sealed class GMItemPacket : Packet { - if (ns == null) - return; + public GMItemPacket(Item item) : base(0x1A) + { + EnsureCapacity(20); - SpanWriter w = new SpanWriter(stackalloc byte[20]); - w.Write((byte)0x1A); // Packet ID - w.Position += 2; // Dynamic Length + // 14 base length + // +2 - Amount + // +2 - Hue + // +1 - Flags - uint serial = Serial.Value; - int itemId = 0x36FF; - int amount = Amount; - Point3D loc = Location; - int x = loc.X; - int y = loc.Y; - int hue = Hue; - int flags = GetPacketFlags(); - int direction = (int)Direction; + uint serial = item.Serial.Value; + int itemID = 0x36FF; + int amount = item.Amount; + Point3D loc = item.Location; + int x = loc.X; + int y = loc.Y; + int hue = item.Hue; + int flags = item.GetPacketFlags(); + int direction = (int)item.Direction; - if (amount != 0) - serial |= 0x80000000; - else - serial &= 0x7FFFFFFF; + if (amount != 0) + serial |= 0x80000000; + else + serial &= 0x7FFFFFFF; - w.Write(serial); + m_Stream.Write(serial); + m_Stream.Write((short)(itemID & 0x7FFF)); - w.Write((short)itemId); + if (amount != 0) + m_Stream.Write((short)amount); - if (amount != 0) - w.Write((short)amount); + x &= 0x7FFF; - x &= 0x7FFF; + if (direction != 0) + x |= 0x8000; - if (direction != 0) x |= 0x8000; + m_Stream.Write((short)x); - w.Write((short)x); + y &= 0x3FFF; - y &= 0x3FFF; + if (hue != 0) + y |= 0x8000; - if (hue != 0) y |= 0x8000; + if (flags != 0) + y |= 0x4000; - if (flags != 0) y |= 0x4000; + m_Stream.Write((short)y); - w.Write((short)y); + if (direction != 0) + m_Stream.Write((byte)direction); - if (direction != 0) - w.Write((byte)direction); + m_Stream.Write((sbyte)loc.Z); - w.Write((sbyte)loc.Z); + if (hue != 0) + m_Stream.Write((ushort)hue); - if (hue != 0) - w.Write((ushort)hue); - - if (flags != 0) - w.Write((byte)flags); - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - - public void SendGMItemSA(NetState ns) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[24]); - w.Write((byte)0xF3); // Packet ID - - w.Write((short)0x01); - - int itemId = 0x36FF; - - w.Position++; // w.Write((byte)0); - - w.Write(Serial); - - w.Write((short)itemId); - - w.Write((byte)Direction); - - short amount = (short)Amount; - w.Write(amount); - w.Write(amount); - - Point3D loc = Location; - w.Write((short)(loc.X & 0x7FFF)); - w.Write((short)(loc.Y & 0x3FFF)); - w.Write((sbyte)loc.Z); - - w.Write((byte)Light); - w.Write((short)Hue); - w.Write((byte)GetPacketFlags()); - - ns.Send(w.RawSpan); - } - - public void SendGMItemHS(NetState ns) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[26]); - w.Write((byte)0xF3); // Packet ID - - w.Write((short)0x01); - - int itemId = 0x36FF; - - w.Position++; // w.Write((byte)0); - - w.Write(Serial); - - w.Write((short)itemId); - - w.Write((byte)Direction); - - short amount = (short)Amount; - w.Write(amount); - w.Write(amount); - - Point3D loc = Location; - w.Write((short)(loc.X & 0x7FFF)); - w.Write((short)(loc.Y & 0x3FFF)); - w.Write((sbyte)loc.Z); - - w.Write((byte)Light); - w.Write((short)Hue); - w.Write((byte)GetPacketFlags()); - - ns.Send(w.RawSpan); + if (flags != 0) + m_Stream.Write((byte)flags); + } } } } diff --git a/Projects/Scripts/Items/Misc/PlayerBulletinBoards.cs b/Projects/Scripts/Items/Misc/PlayerBulletinBoards.cs index 7d5259e7d..2789f301d 100644 --- a/Projects/Scripts/Items/Misc/PlayerBulletinBoards.cs +++ b/Projects/Scripts/Items/Misc/PlayerBulletinBoards.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Server.Gumps; using Server.Multis; +using Server.Prompts; using Server.Mobiles; using Server.Network; using Server.ContextMenus; diff --git a/Projects/Scripts/Items/Misc/PowerGenerator.cs b/Projects/Scripts/Items/Misc/PowerGenerator.cs index 00da04a2c..db1d950c4 100644 --- a/Projects/Scripts/Items/Misc/PowerGenerator.cs +++ b/Projects/Scripts/Items/Misc/PowerGenerator.cs @@ -31,7 +31,11 @@ namespace Server.Items private void AddGeneratorComponent(int itemID, int x, int y, int z) { - AddComponent(new AddonComponent(itemID){ Name = "a power generator", Hue = 0x451 }, x, y, z); + AddonComponent component = new AddonComponent(itemID); + component.Name = "a power generator"; + component.Hue = 0x451; + + AddComponent(component, x, y, z); } public override void Serialize(GenericWriter writer) @@ -144,7 +148,9 @@ namespace Server.Items visited[current.X, current.Y] = true; } else + { current = stack[--stackSize - 1]; + } } Path = new Node[stackSize]; @@ -191,8 +197,9 @@ namespace Server.Items public void DoDamage(Mobile to) { - Packets.SendMessageLocalized(to.NetState, Serial, ItemID, MessageType.Regular, 0x3B2, 3, 1152372); // The Nexus shoots an arc of energy at you! - to.BoltEffect(); + to.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "", "", + "The generator shoots an arc of electricity at you!")); + to.BoltEffect(0); to.LocalOverheadMessage(MessageType.Regular, 0xC9, true, "* Your body convulses from electric shock *"); to.NonlocalOverheadMessage(MessageType.Regular, 0xC9, true, $"* {to.Name} spasms from electric shock *"); @@ -351,7 +358,7 @@ namespace Server.Items hues[n.X, n.Y] = NodeHue.Blue; } - Node lastNode = path[^1]; + Node lastNode = path[path.Length - 1]; hues[lastNode.X, lastNode.Y] = NodeHue.Red; for (int i = 0; i < sideLength; i++) diff --git a/Projects/Scripts/Items/Misc/PublicMoongate.cs b/Projects/Scripts/Items/Misc/PublicMoongate.cs index d3dc1e9fc..c0af37445 100644 --- a/Projects/Scripts/Items/Misc/PublicMoongate.cs +++ b/Projects/Scripts/Items/Misc/PublicMoongate.cs @@ -119,7 +119,11 @@ namespace Server.Items private static void DeleteAll() { - List list = World.Items.Values.OfType().Cast().ToList(); + List list = new List(); + + foreach (Item item in World.Items.Values) + if (item is PublicMoongate) + list.Add(item); foreach (Item item in list) item.Delete(); @@ -345,7 +349,7 @@ namespace Server.Items } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 0) // Cancel return; diff --git a/Projects/Scripts/Items/Misc/Teleporter.cs b/Projects/Scripts/Items/Misc/Teleporter.cs index 74db4bc7b..bf922bff7 100644 --- a/Projects/Scripts/Items/Misc/Teleporter.cs +++ b/Projects/Scripts/Items/Misc/Teleporter.cs @@ -157,7 +157,10 @@ namespace Server.Items { base.GetProperties(list); - list.Add(m_Active ? 1060742 : 1060743); + if (m_Active) + list.Add(1060742); // active + else + list.Add(1060743); // inactive if (m_MapDest != null) list.Add(1060658, "Map\t{0}", m_MapDest); @@ -231,12 +234,12 @@ namespace Server.Items bool sendEffect = !m.Hidden || m.AccessLevel == AccessLevel.Player; if (m_SourceEffect && sendEffect) - Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10); + Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10, 10); m.MoveToWorld(p, map); if (m_DestEffect && sendEffect) - Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10); + Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10, 10); if (m_SoundID > 0 && sendEffect) Effects.PlaySound(m.Location, m.Map, m_SoundID); @@ -392,10 +395,11 @@ namespace Server.Items if (m.BeginAction(this)) { if (m_MessageString != null) - Packets.SendUnicodeMessage(m.NetState, Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", "", - m_MessageString); + m.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", null, + m_MessageString)); else if (m_MessageNumber != 0) - Packets.SendMessageLocalized(m.NetState, Serial, ItemID, MessageType.Regular, 0x3B2, 3, m_MessageNumber); + m.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, m_MessageNumber, null, + "")); Timer.DelayCall(TimeSpan.FromSeconds(5.0), () => m.EndAction(this)); } @@ -521,7 +525,12 @@ namespace Server.Items if (!m.InRange(GetWorldLocation(), m_Range)) return; - bool isMatch = m_Keyword >= 0 && e.HasKeyword(m_Keyword) || m_Substring != null && e.Speech.ToLower().IndexOf(m_Substring.ToLower()) >= 0; + bool isMatch = false; + + if (m_Keyword >= 0 && e.HasKeyword(m_Keyword)) + isMatch = true; + else if (m_Substring != null && e.Speech.ToLower().IndexOf(m_Substring.ToLower()) >= 0) + isMatch = true; if (!isMatch || !CanTeleport(m)) return; @@ -811,10 +820,10 @@ namespace Server.Items writer.Write(TimeoutDelay); writer.Write(m_Teleporting.Count); - foreach (var (key, value) in m_Teleporting) + foreach (KeyValuePair kvp in m_Teleporting) { - writer.Write(key); - writer.Write(value.Next); + writer.Write(kvp.Key); + writer.Write(kvp.Value.Next); } } @@ -1054,7 +1063,9 @@ namespace Server.Items case Layer.Backpack: case Layer.Mount: case Layer.Bank: + { continue; // ignore + } default: { m.SendMessage("You must remove all of your equipment before proceeding."); diff --git a/Projects/Scripts/Items/Misc/TrashBarrel.cs b/Projects/Scripts/Items/Misc/TrashBarrel.cs index fc578e383..da67c25df 100644 --- a/Projects/Scripts/Items/Misc/TrashBarrel.cs +++ b/Projects/Scripts/Items/Misc/TrashBarrel.cs @@ -112,7 +112,7 @@ namespace Server.Items if (items.Count > 0) { - PublicOverheadMessage(MessageType.Regular, 0x3B2, message); + PublicOverheadMessage(MessageType.Regular, 0x3B2, message, ""); for (int i = items.Count - 1; i >= 0; --i) { diff --git a/Projects/Scripts/Items/Misc/UnholyBone.cs b/Projects/Scripts/Items/Misc/UnholyBone.cs index 4f34ecc50..236a41a1e 100644 --- a/Projects/Scripts/Items/Misc/UnholyBone.cs +++ b/Projects/Scripts/Items/Misc/UnholyBone.cs @@ -26,7 +26,7 @@ namespace Server.Items public void Carve(Mobile from, Item item) { Effects.PlaySound(GetWorldLocation(), Map, 0x48F); - Effects.SendLocationEffect(GetWorldLocation(), Map, 0x3728, 10); + Effects.SendLocationEffect(GetWorldLocation(), Map, 0x3728, 10, 10, 0, 0); if (0.3 > Utility.RandomDouble()) { diff --git a/Projects/Scripts/Items/Quivers/BaseQuiver.cs b/Projects/Scripts/Items/Quivers/BaseQuiver.cs index def02a29d..f38f31d44 100644 --- a/Projects/Scripts/Items/Quivers/BaseQuiver.cs +++ b/Projects/Scripts/Items/Quivers/BaseQuiver.cs @@ -302,7 +302,7 @@ namespace Server.Items if ((prop = Attributes.RegenMana) != 0) list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ - if (Attributes.NightSight != 0) + if ((prop = Attributes.NightSight) != 0) list.Add(1060441); // night sight if ((prop = Attributes.ReflectPhysical) != 0) diff --git a/Projects/Scripts/Items/Resources/Tailor/BoltOfCloth.cs b/Projects/Scripts/Items/Resources/Tailor/BoltOfCloth.cs index 3e97a980e..d57728a15 100644 --- a/Projects/Scripts/Items/Resources/Tailor/BoltOfCloth.cs +++ b/Projects/Scripts/Items/Resources/Tailor/BoltOfCloth.cs @@ -54,8 +54,10 @@ namespace Server.Items public override void OnSingleClick(Mobile from) { - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, 0x3B2, 3, - Amount == 1 ? 1049122 : 1049121, "", (Amount * 50).ToString()); + int number = Amount == 1 ? 1049122 : 1049121; + + from.Send( + new MessageLocalized(Serial, ItemID, MessageType.Label, 0x3B2, 3, number, "", (Amount * 50).ToString())); } } } diff --git a/Projects/Scripts/Items/Resources/Tailor/Cloth.cs b/Projects/Scripts/Items/Resources/Tailor/Cloth.cs index 4f5705daa..9c98be700 100644 --- a/Projects/Scripts/Items/Resources/Tailor/Cloth.cs +++ b/Projects/Scripts/Items/Resources/Tailor/Cloth.cs @@ -55,8 +55,9 @@ namespace Server.Items public override void OnSingleClick(Mobile from) { - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, 0x3B2, 3, - Amount == 1 ? 1049124 : 1049123, "", Amount.ToString()); + int number = Amount == 1 ? 1049124 : 1049123; + + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", Amount.ToString())); } } } diff --git a/Projects/Scripts/Items/Resources/Tailor/Leathers.cs b/Projects/Scripts/Items/Resources/Tailor/Leathers.cs index 8661bfcee..a8568f553 100644 --- a/Projects/Scripts/Items/Resources/Tailor/Leathers.cs +++ b/Projects/Scripts/Items/Resources/Tailor/Leathers.cs @@ -29,10 +29,16 @@ namespace Server.Items } } - public override int LabelNumber => - m_Resource >= CraftResource.SpinedLeather && m_Resource <= CraftResource.BarbedLeather - ? 1049684 + (m_Resource - CraftResource.SpinedLeather) - : 1047022; + public override int LabelNumber + { + get + { + if (m_Resource >= CraftResource.SpinedLeather && m_Resource <= CraftResource.BarbedLeather) + return 1049684 + (m_Resource - CraftResource.SpinedLeather); + + return 1047022; + } + } int ICommodity.DescriptionNumber => LabelNumber; bool ICommodity.IsDeedable => true; diff --git a/Projects/Scripts/Items/Resources/Tailor/UncutCloth.cs b/Projects/Scripts/Items/Resources/Tailor/UncutCloth.cs index eda2b6400..676283400 100644 --- a/Projects/Scripts/Items/Resources/Tailor/UncutCloth.cs +++ b/Projects/Scripts/Items/Resources/Tailor/UncutCloth.cs @@ -55,8 +55,9 @@ namespace Server.Items public override void OnSingleClick(Mobile from) { - Packets.SendMessageLocalized(from.NetState, Serial, ItemID, MessageType.Label, 0x3B2, 3, - Amount == 1 ? 1049124 : 1049123, "", Amount.ToString()); + int number = Amount == 1 ? 1049124 : 1049123; + + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", Amount.ToString())); } } } diff --git a/Projects/Scripts/Items/Skill Items/Camping/Campfire.cs b/Projects/Scripts/Items/Skill Items/Camping/Campfire.cs index 8f9a35130..cbe187746 100644 --- a/Projects/Scripts/Items/Skill Items/Camping/Campfire.cs +++ b/Projects/Scripts/Items/Skill Items/Camping/Campfire.cs @@ -44,7 +44,7 @@ namespace Server.Items [CommandProperty(AccessLevel.GameMaster)] public CampfireStatus Status { - get => ItemID switch + get { return ItemID switch { diff --git a/Projects/Scripts/Items/Skill Items/Fishing/Misc/SOS.cs b/Projects/Scripts/Items/Skill Items/Fishing/Misc/SOS.cs index dc4f20bae..2b3639fc9 100644 --- a/Projects/Scripts/Items/Skill Items/Fishing/Misc/SOS.cs +++ b/Projects/Scripts/Items/Skill Items/Fishing/Misc/SOS.cs @@ -233,19 +233,21 @@ namespace Server.Items bool xEast = false, ySouth = false; string fmt; - fmt = Sextant.Format(loc, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth) ? - $"{yLat}°{yMins}'{(ySouth ? "S" : "N")},{xLong}°{xMins}'{(xEast ? "E" : "W")}" : "?????"; + if (Sextant.Format(loc, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth)) + fmt = $"{yLat}°{yMins}'{(ySouth ? "S" : "N")},{xLong}°{xMins}'{(xEast ? "E" : "W")}"; + else + fmt = "?????"; AddPage(0); AddBackground(0, 40, 350, 300, 2520); - AddHtmlLocalized(30, 80, 285, 160, 1018326, true, true); - /* This is a message hastily scribbled by a passenger aboard a sinking ship. - * While it is probably too late to save the passengers and crew, - * perhaps some treasure went down with the ship! - * The message gives the ship's last known sextant co-ordinates.= - */ + AddHtmlLocalized(30, 80, 285, 160, 1018326, true, + true); /* This is a message hastily scribbled by a passenger aboard a sinking ship. + * While it is probably too late to save the passengers and crew, + * perhaps some treasure went down with the ship! + * The message gives the ship's last known sextant co-ordinates. + */ AddHtml(35, 240, 230, 20, fmt); diff --git a/Projects/Scripts/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs b/Projects/Scripts/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs index e82ef9e7d..db5d8c74d 100644 --- a/Projects/Scripts/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs +++ b/Projects/Scripts/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs @@ -200,6 +200,7 @@ namespace Server.Items switch (Utility.Random(8)) { default: + case 0: x = -1; y = -1; break; @@ -404,4 +405,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs b/Projects/Scripts/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs index abf96ad14..26bbbabf4 100644 --- a/Projects/Scripts/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs +++ b/Projects/Scripts/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs @@ -159,7 +159,9 @@ namespace Server.Items if (!(from is PlayerMobile pm)) return; - list.Add(new ContextMenuEntry(pm.ToggleMiningStone ? 6179 : 6178) {Color = 0x421F}); + ContextMenuEntry miningEntry = new ContextMenuEntry(pm.ToggleMiningStone ? 6179 : 6178); + miningEntry.Color = 0x421F; + list.Add(miningEntry); list.Add(new ToggleMiningStoneEntry(pm, false, 6176)); list.Add(new ToggleMiningStoneEntry(pm, true, 6177)); diff --git a/Projects/Scripts/Items/Skill Items/Magical/Misc/Moongate.cs b/Projects/Scripts/Items/Skill Items/Magical/Misc/Moongate.cs index 672019d2d..b0e17a24e 100644 --- a/Projects/Scripts/Items/Skill Items/Magical/Misc/Moongate.cs +++ b/Projects/Scripts/Items/Skill Items/Magical/Misc/Moongate.cs @@ -167,7 +167,7 @@ namespace Server.Items from.Map != Map.Felucca && TargetMap == Map.Felucca && ShowFeluccaWarning) { if (from.AccessLevel == AccessLevel.Player || !from.Hidden) - Packets.SendPlaySound(from.NetState, 0x20E, from.Location); + from.Send(new PlaySound(0x20E, from.Location)); from.CloseGump(); from.SendGump(new MoongateConfirmGump(from, this)); } @@ -381,7 +381,7 @@ namespace Server.Items } } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 1) m_Gate.EndConfirmation(m_From); diff --git a/Projects/Scripts/Items/Skill Items/Magical/Misc/RecallRune.cs b/Projects/Scripts/Items/Skill Items/Magical/Misc/RecallRune.cs index f78663b1a..af4e695b7 100644 --- a/Projects/Scripts/Items/Skill Items/Magical/Misc/RecallRune.cs +++ b/Projects/Scripts/Items/Skill Items/Magical/Misc/RecallRune.cs @@ -1,4 +1,5 @@ using Server.Multis; +using Server.Prompts; using Server.Regions; namespace Server.Items diff --git a/Projects/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs b/Projects/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs index fcb582922..84957e0fb 100644 --- a/Projects/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs +++ b/Projects/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs @@ -76,7 +76,8 @@ namespace Server.Items from.RevealingAction(); - Users ??= new List(); + if (Users == null) + Users = new List(); if (!Users.Contains(from)) Users.Add(from); @@ -168,7 +169,7 @@ namespace Server.Items Effects.PlaySound(loc, map, 0x307); - Effects.SendLocationEffect(loc, map, 0x36B0, 9); + Effects.SendLocationEffect(loc, map, 0x36B0, 9, 10, 0, 0); int alchemyBonus = 0; if (direct) diff --git a/Projects/Scripts/Items/Skill Items/Magical/Potions/NightSight.cs b/Projects/Scripts/Items/Skill Items/Magical/Potions/NightSight.cs index d5256e9aa..c4bc72042 100644 --- a/Projects/Scripts/Items/Skill Items/Magical/Potions/NightSight.cs +++ b/Projects/Scripts/Items/Skill Items/Magical/Potions/NightSight.cs @@ -29,7 +29,7 @@ namespace Server.Items public override void Drink(Mobile from) { - if (from.BeginAction()) + if (from.BeginAction()) { new LightCycle.NightSightTimer(from).Start(); from.LightLevel = LightCycle.DungeonLevel / 2; @@ -43,7 +43,9 @@ namespace Server.Items Consume(); } else + { from.SendMessage("You already have nightsight."); + } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Skill Items/Magical/Runebook.cs b/Projects/Scripts/Items/Skill Items/Magical/Runebook.cs index fe054f07e..2bc7d5692 100644 --- a/Projects/Scripts/Items/Skill Items/Magical/Runebook.cs +++ b/Projects/Scripts/Items/Skill Items/Magical/Runebook.cs @@ -355,9 +355,13 @@ namespace Server.Items if (dropped is RecallRune rune) { if (IsLockedDown && from.AccessLevel < AccessLevel.GameMaster) + { from.SendLocalizedMessage(502413, null, 0x35); // That cannot be done while the book is locked down. + } else if (IsOpen(from)) + { from.SendLocalizedMessage(1005571); // You cannot place objects in the book while viewing the contents. + } else if (Entries.Count < 16) { if (rune.Marked && rune.TargetMap != null) @@ -366,12 +370,12 @@ namespace Server.Items rune.Delete(); - Packets.SendPlaySound(from.NetState, 0x42, GetWorldLocation()); + from.Send(new PlaySound(0x42, GetWorldLocation())); string desc = rune.Description; if (desc == null || (desc = desc.Trim()).Length == 0) - desc = "(nondescript)"; + desc = "(indescript)"; from.SendMessage(desc); @@ -381,13 +385,15 @@ namespace Server.Items from.SendLocalizedMessage(502409); // This rune does not have a marked location. } else + { from.SendLocalizedMessage(502401); // This runebook is full. + } } else if (dropped is RecallScroll) { if (CurCharges < MaxCharges) { - Packets.SendPlaySound(from.NetState, 0x259, GetWorldLocation()); + from.Send(new PlaySound(0x249, GetWorldLocation())); int amount = dropped.Amount; @@ -405,7 +411,9 @@ namespace Server.Items } } else + { from.SendLocalizedMessage(502410); // This book already has the maximum amount of charges. + } } return false; diff --git a/Projects/Scripts/Items/Skill Items/Magical/Spellbook.cs b/Projects/Scripts/Items/Skill Items/Magical/Spellbook.cs index b97d2ebca..ca99ee343 100644 --- a/Projects/Scripts/Items/Skill Items/Magical/Spellbook.cs +++ b/Projects/Scripts/Items/Skill Items/Magical/Spellbook.cs @@ -491,7 +491,7 @@ namespace Server.Items scroll.Delete(); - Packets.SendPlaySound(from.NetState, 0x249, GetWorldLocation()); + from.Send(new PlaySound(0x249, GetWorldLocation())); return true; } } @@ -569,16 +569,49 @@ namespace Server.Items return; if (Parent == null) - SendWorldPacketFor(ns); + { + to.Send(WorldPacket); + } else if (Parent is Item) + { // What will happen if the client doesn't know about our parent? - Packets.SendContainerContentUpdate(ns, this); + if (ns.ContainerGridLines) + to.Send(new ContainerContentUpdate6017(this)); + else + to.Send(new ContainerContentUpdate(this)); + } else if (Parent is Mobile) + { // What will happen if the client doesn't know about our parent? - Packets.SendEquipUpdate(ns, this); + to.Send(new EquipUpdate(this)); + } - Packets.SendDisplayContainer(ns, Serial); - Packets.SendSpellbookContent(ns, Serial, ItemID, BookOffset + 1, m_Content); + if (ns.HighSeas) + to.Send(new DisplaySpellbookHS(this)); + else + to.Send(new DisplaySpellbook(this)); + + if (ObjectPropertyList.Enabled) + { + if (ns.NewSpellbook) + { + to.Send(new NewSpellbookContent(this, ItemID, BookOffset + 1, m_Content)); + } + else + { + if (ns.ContainerGridLines) + to.Send(new SpellbookContent6017(SpellCount, BookOffset + 1, m_Content, this)); + else + to.Send(new SpellbookContent(SpellCount, BookOffset + 1, m_Content, this)); + } + } + else + { + if (ns.ContainerGridLines) + to.Send(new SpellbookContent6017(SpellCount, BookOffset + 1, m_Content, this)); + else + to.Send(new SpellbookContent(SpellCount, BookOffset + 1, m_Content, this)); + } } public override void GetProperties(ObjectPropertyList list) @@ -777,9 +810,11 @@ namespace Server.Items } } - Attributes ??= new AosAttributes(this); + if (Attributes == null) + Attributes = new AosAttributes(this); - SkillBonuses ??= new AosSkillBonuses(this); + if (SkillBonuses == null) + SkillBonuses = new AosSkillBonuses(this); if (Core.AOS && Parent is Mobile mobile) SkillBonuses.AddTo(mobile); diff --git a/Projects/Scripts/Items/Skill Items/Misc/Bandage.cs b/Projects/Scripts/Items/Skill Items/Misc/Bandage.cs index f842d091d..752c68f87 100644 --- a/Projects/Scripts/Items/Skill Items/Misc/Bandage.cs +++ b/Projects/Scripts/Items/Skill Items/Misc/Bandage.cs @@ -387,7 +387,7 @@ namespace Server.Items double toHeal = min + Utility.RandomDouble() * (max - min); if (Patient.Body.IsMonster || Patient.Body.IsAnimal) - toHeal += Patient.HitsMax / 100.0; + toHeal += Patient.HitsMax / 100; if (Core.AOS) toHeal -= toHeal * Slips * 0.35; // TODO: Verify algorithm diff --git a/Projects/Scripts/Items/Skill Items/Misc/FireHorn.cs b/Projects/Scripts/Items/Skill Items/Misc/FireHorn.cs index 127cde348..5e0d9c5d0 100644 --- a/Projects/Scripts/Items/Skill Items/Misc/FireHorn.cs +++ b/Projects/Scripts/Items/Skill Items/Misc/FireHorn.cs @@ -79,8 +79,9 @@ namespace Server.Items from.Backpack.ConsumeUpTo(typeof(SulfurousAsh), sulfAsh); from.PlaySound(0x15F); - - Effects.SendMovingEffect(from, loc, from.Map, 0x36D4, 5, 0, false, true); + Effects.SendPacket(from, from.Map, + new HuedEffect(EffectType.Moving, from.Serial, Serial.Zero, 0x36D4, from.Location, loc, 5, 0, false, true, 0, + 0)); IPooledEnumerable eable = from.Map.GetMobilesInRange(new Point3D(loc), 2); @@ -91,9 +92,11 @@ namespace Server.Items || Core.AOS && !from.InLOS(m)) return false; - playerVsPlayer |= m.Player; + if (m.Player) + playerVsPlayer = true; return true; + }).ToList(); eable.Free(); diff --git a/Projects/Scripts/Items/Skill Items/Musical Instruments/BaseInstrument.cs b/Projects/Scripts/Items/Skill Items/Musical Instruments/BaseInstrument.cs index 462ba6d62..b1e840c8b 100644 --- a/Projects/Scripts/Items/Skill Items/Musical Instruments/BaseInstrument.cs +++ b/Projects/Scripts/Items/Skill Items/Musical Instruments/BaseInstrument.cs @@ -406,8 +406,13 @@ namespace Server.Items number = 1041000; } - if (attrs.Count > 0 || Crafter != null || Name == null) - EquipmentPackets.SendDisplayEquipmentInfo(from.NetState, this, number, m_Crafter, false, attrs); + if (attrs.Count == 0 && Crafter == null && Name != null) + return; + + EquipmentInfo eqInfo = new EquipmentInfo(number, m_Crafter, false, + attrs.ToArray()); + + from.Send(new DisplayEquipmentInfo(this, eqInfo)); } public override void Serialize(GenericWriter writer) diff --git a/Projects/Scripts/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs b/Projects/Scripts/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs index 35773aa8c..2c77e45ea 100644 --- a/Projects/Scripts/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs +++ b/Projects/Scripts/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs @@ -6,7 +6,7 @@ using Server.Mobiles; namespace Server.Items { [Flippable(0x2790, 0x27DB)] - public class LeatherNinjaBelt : BaseWaist, INinjaWeapon + public class LeatherNinjaBelt : BaseWaist, IDyable, INinjaWeapon { private Poison m_Poison; private int m_PoisonCharges; @@ -27,18 +27,18 @@ namespace Server.Items public override CraftResource DefaultResource => CraftResource.RegularLeather; - public int WrongAmmoMessage => 1063301; //You can only place shuriken in a ninja belt. - public int NoFreeHandMessage => 1063299; //You must have a free hand to throw shuriken. - public int EmptyWeaponMessage => 1063297; //You have no shuriken in your ninja belt! - public int RecentlyUsedMessage => 1063298; //You cannot throw another shuriken yet. - public int FullWeaponMessage => 1063302; //You cannot add any more shuriken. + public virtual int WrongAmmoMessage => 1063301; //You can only place shuriken in a ninja belt. + public virtual int NoFreeHandMessage => 1063299; //You must have a free hand to throw shuriken. + public virtual int EmptyWeaponMessage => 1063297; //You have no shuriken in your ninja belt! + public virtual int RecentlyUsedMessage => 1063298; //You cannot throw another shuriken yet. + public virtual int FullWeaponMessage => 1063302; //You cannot add any more shuriken. - public int WeaponMinRange => 2; - public int WeaponMaxRange => 10; + public virtual int WeaponMinRange => 2; + public virtual int WeaponMaxRange => 10; - public int WeaponDamage => Utility.RandomMinMax(3, 5); + public virtual int WeaponDamage => Utility.RandomMinMax(3, 5); - public Type AmmoType => typeof(Shuriken); + public virtual Type AmmoType => typeof(Shuriken); [CommandProperty(AccessLevel.GameMaster)] public int UsesRemaining @@ -81,8 +81,7 @@ namespace Server.Items public void AttackAnimation(Mobile from, Mobile to) { - if (from.Body.IsHuman) - from.Animate(from.Mounted ? 26 : 9, 7, 1, true, false, 0); + if (from.Body.IsHuman) from.Animate(from.Mounted ? 26 : 9, 7, 1, true, false, 0); from.PlaySound(0x23A); from.MovingEffect(to, 0x27AC, 1, 0, false, false); @@ -157,4 +156,4 @@ namespace Server.Items } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Skill Items/Tailor Items/Misc/Dyes.cs b/Projects/Scripts/Items/Skill Items/Tailor Items/Misc/Dyes.cs index ff72147f8..8a86ab078 100644 --- a/Projects/Scripts/Items/Skill Items/Tailor Items/Misc/Dyes.cs +++ b/Projects/Scripts/Items/Skill Items/Tailor Items/Misc/Dyes.cs @@ -1,3 +1,4 @@ +using Server.HuePickers; using Server.Targeting; namespace Server.Items diff --git a/Projects/Scripts/Items/Skill Items/Thief/DisguisePersistance.cs b/Projects/Scripts/Items/Skill Items/Thief/DisguisePersistance.cs index f41182141..50d3b0ccf 100644 --- a/Projects/Scripts/Items/Skill Items/Thief/DisguisePersistance.cs +++ b/Projects/Scripts/Items/Skill Items/Thief/DisguisePersistance.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace Server.Items { @@ -30,10 +31,12 @@ namespace Server.Items writer.Write(timerCount); - foreach (var (m, value) in DisguiseTimers.Timers) + foreach (KeyValuePair entry in DisguiseTimers.Timers) { + Mobile m = entry.Key; + writer.Write(m); - writer.Write(value.Next - DateTime.UtcNow); + writer.Write(entry.Value.Next - DateTime.UtcNow); writer.Write(m.NameMod); } } diff --git a/Projects/Scripts/Items/Skill Items/Tinkering/Spyglass.cs b/Projects/Scripts/Items/Skill Items/Tinkering/Spyglass.cs index 711d7b173..2dae504f3 100644 --- a/Projects/Scripts/Items/Skill Items/Tinkering/Spyglass.cs +++ b/Projects/Scripts/Items/Skill Items/Tinkering/Spyglass.cs @@ -20,10 +20,10 @@ namespace Server.Items from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1008155); // You peer into the heavens, seeking the moons... - Packets.SendMessageLocalizedAffix(from.NetState, from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, - 1008146 + (int)Clock.GetMoonPhase(Map.Trammel, from.X, from.Y), "", AffixType.Prepend, "Trammel : "); - Packets.SendMessageLocalizedAffix(from.NetState, from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, - 1008146 + (int)Clock.GetMoonPhase(Map.Felucca, from.X, from.Y), "", AffixType.Prepend, "Felucca : "); + from.Send(new MessageLocalizedAffix(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, + 1008146 + (int)Clock.GetMoonPhase(Map.Trammel, from.X, from.Y), "", AffixType.Prepend, "Trammel : ", "")); + from.Send(new MessageLocalizedAffix(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, + 1008146 + (int)Clock.GetMoonPhase(Map.Felucca, from.X, from.Y), "", AffixType.Prepend, "Felucca : ", "")); if (from is PlayerMobile player) { @@ -33,7 +33,7 @@ namespace Server.Items return; FindIngredientObjective obj = qs.FindObjective(); - + if (obj?.Completed == false && obj.Ingredient == Ingredient.StarChart) { Clock.GetTime(from.Map, from.X, from.Y, out int hours, out int _); @@ -68,4 +68,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs b/Projects/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs index 3216bf7d0..e5d2fcfb0 100644 --- a/Projects/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs +++ b/Projects/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs @@ -7,6 +7,16 @@ using Server.Network; namespace Server.Items { + public sealed class StopMusic : Packet + { + public static readonly Packet Instance = SetStatic(new StopMusic()); + + public StopMusic() : base(0x6D, 3) + { + m_Stream.Write((short)0x1FFF); + } + } + [Flippable(0x2AF9, 0x2AFD)] public class DawnsMusicBox : Item, ISecurable { @@ -148,7 +158,7 @@ namespace Server.Items else m_ItemID = ItemID; - Packets.SendPlayMusic(m.NetState, music); + m.Send(new PlayMusic(music)); m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 4, Animate); } @@ -157,7 +167,7 @@ namespace Server.Items if (m_Timer?.Running == true) m_Timer.Stop(); - Packets.SendStopMusic(m.NetState); + m.Send(StopMusic.Instance); if (m_Count > 0) ItemID = m_ItemID; diff --git a/Projects/Scripts/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs b/Projects/Scripts/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs index faa446550..c8dfa3341 100644 --- a/Projects/Scripts/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs +++ b/Projects/Scripts/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs @@ -108,7 +108,7 @@ namespace Server.Items Point3D location = Location; location.Z += 10; - Effects.SendLocationEffect(location, Map, 0x3709, 10, 10, 0x356); + Effects.SendLocationEffect(location, Map, 0x3709, 10, 10, 0x356, 0); Effects.PlaySound(location, Map, 0x32E); if (Items.Count > 0) diff --git a/Projects/Scripts/Items/Special/House Raffle/HouseRaffleStone.cs b/Projects/Scripts/Items/Special/House Raffle/HouseRaffleStone.cs index a23ff661a..9186c5dc1 100644 --- a/Projects/Scripts/Items/Special/House Raffle/HouseRaffleStone.cs +++ b/Projects/Scripts/Items/Special/House Raffle/HouseRaffleStone.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Text; using Server.Accounting; @@ -291,9 +290,22 @@ namespace Server.Items } } - private bool HasEntered(Mobile from) => - from.Account is Account acc && - (from entry in Entries select entry.From?.Account as Account).Any(entryAcc => entryAcc == acc); + private bool HasEntered(Mobile from) + { + if (!(from.Account is Account acc)) + return false; + + foreach (RaffleEntry entry in Entries) + if (entry.From != null) + { + Account entryAcc = entry.From.Account as Account; + + if (entryAcc == acc) + return true; + } + + return false; + } private bool IsAtIPLimit(Mobile from) { @@ -303,7 +315,12 @@ namespace Server.Items IPAddress address = from.NetState.Address; int tickets = 0; - return Entries.Where(entry => Utility.IPMatchClassC(entry.Address, address)).Any(entry => ++tickets >= EntryLimitPerIP); + foreach (RaffleEntry entry in Entries) + if (Utility.IPMatchClassC(entry.Address, address)) + if (++tickets >= EntryLimitPerIP) + return true; + + return false; } public static string FormatLocation(Point3D loc, Map map, bool displayMap) diff --git a/Projects/Scripts/Items/Special/Solen Items/BagOfSending.cs b/Projects/Scripts/Items/Special/Solen Items/BagOfSending.cs index a186285ba..33832fb3d 100644 --- a/Projects/Scripts/Items/Special/Solen Items/BagOfSending.cs +++ b/Projects/Scripts/Items/Special/Solen Items/BagOfSending.cs @@ -219,34 +219,54 @@ namespace Server.Items return; if (from.Region.IsPartOf()) + { from.SendMessage("You may not do that in jail."); + } else if (!m_Bag.IsChildOf(from.Backpack)) - MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054107, - 0x59); // This item must be in your backpack. + { + MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1062334, + 0x59); // The bag of sending must be in your backpack. 1054107 is gone from client, using generic response + } else if (m_Bag.Charges == 0) + { MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1042544, 0x59); // This item is out of charges. + } else if (targeted is Item item) { int reqCharges = (int)Math.Max(1, Math.Ceiling(item.TotalWeight / 10.0)); if (!item.IsChildOf(from.Backpack)) + { MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054152, 0x59); // You may only send items from your backpack to your bank box. + } else if (item is BagOfSending || item is Container) - Packets.SendAsciiMessage(from.NetState, m_Bag.Serial, m_Bag.ItemID, MessageType.Regular, 0x3B2, 3, "", - "You cannot send a container through the bag of sending." ); + { + from.Send(new AsciiMessage(m_Bag.Serial, m_Bag.ItemID, MessageType.Regular, 0x3B2, 3, "", + "You cannot send a container through the bag of sending.")); + } else if (item.LootType == LootType.Cursed) + { MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054108, 0x59); // The bag of sending rejects the cursed item. + } else if (!item.VerifyMove(from) || item is QuestItem || item.Nontransferable) + { MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054109, 0x59); // The bag of sending rejects that item. + } else if (SpellHelper.IsDoomGauntlet(from.Map, from.Location)) + { from.SendLocalizedMessage(1062089); // You cannot use that here. + } else if (!from.BankBox.TryDropItem(from, item, false)) + { MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054110, 0x59); // Your bank box is full. + } else if (Core.ML && reqCharges > m_Bag.Charges) + { from.SendLocalizedMessage(1079932); //You don't have enough charges to send that much weight + } else { m_Bag.Charges -= Core.ML ? reqCharges : 1; @@ -258,4 +278,4 @@ namespace Server.Items } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Special/Solen Items/BallOfSummoning.cs b/Projects/Scripts/Items/Special/Solen Items/BallOfSummoning.cs index 27e16780b..24a0bee0e 100644 --- a/Projects/Scripts/Items/Special/Solen Items/BallOfSummoning.cs +++ b/Projects/Scripts/Items/Special/Solen Items/BallOfSummoning.cs @@ -177,27 +177,41 @@ namespace Server.Items return; if (Charges == 0) + { SendLocalizedMessageTo(from, 1054122); // The Crystal Ball darkens. It must be charged before it can be used again. + } else if (pet is BaseMount mount && mount.Rider == from) + { MessageHelper.SendLocalizedMessageTo(this, from, 1054124, 0x36); // The Crystal Ball fills with a yellow mist. Why would you summon your pet while riding it? + } else if (pet.Map == Map.Internal && (!pet.IsStabled || from.Followers + pet.ControlSlots > from.FollowersMax)) + { MessageHelper.SendLocalizedMessageTo(this, from, 1054125, 0x5); // The Crystal Ball fills with a blue mist. Your pet is not responding to the summons. + } else if ((!pet.Controlled || pet.ControlMaster != from) && !from.Stabled.Contains(pet)) + { MessageHelper.SendLocalizedMessageTo(this, from, 1054126, 0x8FD); // The Crystal Ball fills with a grey mist. You are not the owner of the pet you are attempting to summon. + } else if (!pet.IsBonded) + { MessageHelper.SendLocalizedMessageTo(this, from, 1054127, 0x22); // The Crystal Ball fills with a red mist. You appear to have let your bond to your pet deteriorate. + } else if (from.Map == Map.Ilshenar || from.Region.IsPartOf() || from.Region.IsPartOf() || from.Region.IsPartOf()) - Packets.SendAsciiMessage(from.NetState, Serial, ItemID, MessageType.Regular, 0x22, 3, "", - "You cannot summon your pet to this location."); + { + from.Send(new AsciiMessage(Serial, ItemID, MessageType.Regular, 0x22, 3, "", + "You cannot summon your pet to this location.")); + } else if (Core.ML && from is PlayerMobile mobile && DateTime.UtcNow < mobile.LastPetBallTime.AddSeconds(15.0)) + { MessageHelper.SendLocalizedMessageTo(this, mobile, 1080072, 0x22); // You must wait a few seconds before you can summon your pet. + } else { if (Core.ML) diff --git a/Projects/Scripts/Items/Special/Solen Items/BraceletOfBinding.cs b/Projects/Scripts/Items/Special/Solen Items/BraceletOfBinding.cs index 9e4478191..4417b9b8e 100644 --- a/Projects/Scripts/Items/Special/Solen Items/BraceletOfBinding.cs +++ b/Projects/Scripts/Items/Special/Solen Items/BraceletOfBinding.cs @@ -5,6 +5,7 @@ using Server.Factions; using Server.Misc; using Server.Mobiles; using Server.Network; +using Server.Prompts; using Server.Regions; using Server.Spells; using Server.Targeting; diff --git a/Projects/Scripts/Misc/MessageHelper.cs b/Projects/Scripts/Items/Special/Solen Items/MessageHelper.cs similarity index 58% rename from Projects/Scripts/Misc/MessageHelper.cs rename to Projects/Scripts/Items/Special/Solen Items/MessageHelper.cs index 6bf6b001d..09f79bf9d 100644 --- a/Projects/Scripts/Misc/MessageHelper.cs +++ b/Projects/Scripts/Items/Special/Solen Items/MessageHelper.cs @@ -2,7 +2,7 @@ using Server.Network; namespace Server { - public static class MessageHelper + public class MessageHelper { public static void SendLocalizedMessageTo(Item from, Mobile to, int number, int hue) { @@ -11,12 +11,12 @@ namespace Server public static void SendLocalizedMessageTo(Item from, Mobile to, int number, string args, int hue) { - Packets.SendMessageLocalized(to.NetState, from.Serial, from.ItemID, MessageType.Regular, hue, 3, number, "", args); + to.Send(new MessageLocalized(from.Serial, from.ItemID, MessageType.Regular, hue, 3, number, "", args)); } public static void SendMessageTo(Item from, Mobile to, string text, int hue) { - Packets.SendUnicodeMessage(to.NetState, from.Serial, from.ItemID, MessageType.Regular, hue, 3, "ENU", "", text); + to.Send(new UnicodeMessage(from.Serial, from.ItemID, MessageType.Regular, hue, 3, "ENU", "", text)); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Special/SoulStone.cs b/Projects/Scripts/Items/Special/SoulStone.cs index aee2dd8ed..ea64d856e 100644 --- a/Projects/Scripts/Items/Special/SoulStone.cs +++ b/Projects/Scripts/Items/Special/SoulStone.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Server.Accounting; using Server.Engines.VeteranRewards; using Server.Factions; @@ -580,6 +579,7 @@ namespace Server.Items return; } + SkillName skill = m_Stone.Skill; double skillValue = m_Stone.SkillValue; Skill fromSkill = from.Skills[m_Stone.Skill]; @@ -589,8 +589,27 @@ namespace Server.Items */ int requiredAmount = (int)(skillValue * 10) - fromSkill.BaseFixedPoint - (from.SkillsCap - from.SkillsTotal); - bool cannotAbsorb = fromSkill.Lock != SkillLock.Up || requiredAmount > 0 && - requiredAmount > from.Skills.Where(t => t.Lock == SkillLock.Down).Sum(t => t.BaseFixedPoint); + bool cannotAbsorb = false; + + if (fromSkill.Lock != SkillLock.Up) + { + cannotAbsorb = true; + } + else if (requiredAmount > 0) + { + int available = 0; + + for (int i = 0; i < from.Skills.Length; ++i) + { + if (from.Skills[i].Lock != SkillLock.Down) + continue; + + available += from.Skills[i].BaseFixedPoint; + } + + if (requiredAmount > available) + cannotAbsorb = true; + } if (cannotAbsorb) { diff --git a/Projects/Scripts/Items/Special/Special Scrolls/PowerScroll.cs b/Projects/Scripts/Items/Special/Special Scrolls/PowerScroll.cs index c5de04d58..1e567af7b 100644 --- a/Projects/Scripts/Items/Special/Special Scrolls/PowerScroll.cs +++ b/Projects/Scripts/Items/Special/Special Scrolls/PowerScroll.cs @@ -81,12 +81,10 @@ namespace Server.Items } public override int Message => - 1049469; - /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. - * When used, the effect is not immediately seen without a gain of points with that skill or statistics. - * You can view your maximum skill values in your skills window. - * You can view your maximum statistic value in your statistics window. - */ + 1049469; /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. + * When used, the effect is not immediately seen without a gain of points with that skill or statistics. + * You can view your maximum skill values in your skills window. + * You can view your maximum statistic value in your statistics window. */ public override int Title { @@ -95,12 +93,10 @@ namespace Server.Items double level = (Value - 105.0) / 5.0; if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0) - return 1049635 + (int)level; - /* Wonderous Scroll (105 Skill): OR - * Exalted Scroll (110 Skill): OR - * Mythical Scroll (115 Skill): OR - * Legendary Scroll (120 Skill): - */ + return 1049635 + (int)level; /* Wonderous Scroll (105 Skill): OR + * Exalted Scroll (110 Skill): OR + * Mythical Scroll (115 Skill): OR + * Legendary Scroll (120 Skill): */ return 0; } @@ -158,12 +154,10 @@ namespace Server.Items double level = (Value - 105.0) / 5.0; if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0) - list.Add(1049639 + (int)level, GetNameLocalized()); - /* a wonderous scroll of ~1_type~ (105 Skill) OR - * an exalted scroll of ~1_type~ (110 Skill) OR - * a mythical scroll of ~1_type~ (115 Skill) OR - * a legendary scroll of ~1_type~ (120 Skill) - */ + list.Add(1049639 + (int)level, GetNameLocalized()); /* a wonderous scroll of ~1_type~ (105 Skill) OR + * an exalted scroll of ~1_type~ (110 Skill) OR + * a mythical scroll of ~1_type~ (115 Skill) OR + * a legendary scroll of ~1_type~ (120 Skill) */ else list.Add("a power scroll of {0} ({1} Skill)", GetName(), Value); } diff --git a/Projects/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs b/Projects/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs index aa4921f2f..1728e261d 100644 --- a/Projects/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs +++ b/Projects/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Server.Engines.MLQuests; using Server.Engines.MLQuests.Objectives; using Server.Mobiles; @@ -22,11 +21,9 @@ namespace Server.Items public override int LabelNumber => 1078604; // Scroll of Alacrity public override int Message => - 1078602; - /* Using a Scroll of Transcendence for a given skill will permanently increase your current - * level in that skill by the amount of points displayed on the scroll. - * As you may not gain skills beyond your maximum skill cap, any excess points will be lost. - */ + 1078602; /*Using a Scroll of Transcendence for a given skill will permanently increase your current + *level in that skill by the amount of points displayed on the scroll. + *As you may not gain skills beyond your maximum skill cap, any excess points will be lost.*/ public override string DefaultTitle => "Scroll of Alacrity:"; @@ -77,10 +74,8 @@ namespace Server.Items if (tskill >= tcap || from.Skills[Skill].Lock != SkillLock.Up) { from.SendLocalizedMessage( - 1094935); - /* You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. - * If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap. - */ + 1094935); /*You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. + *If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap.*/ return; } diff --git a/Projects/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs b/Projects/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs index d1d1c66a0..3eeefe93c 100644 --- a/Projects/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs +++ b/Projects/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Server.Engines.MLQuests; using Server.Engines.MLQuests.Objectives; using Server.Mobiles; @@ -22,11 +21,9 @@ namespace Server.Items public override int LabelNumber => 1094934; // Scroll of Transcendence public override int Message => - 1094933; - /* Using a Scroll of Transcendence for a given skill will permanently increase your current - * level in that skill by the amount of points displayed on the scroll. - * As you may not gain skills beyond your maximum skill cap, any excess points will be lost. - */ + 1094933; /*Using a Scroll of Transcendence for a given skill will permanently increase your current + *level in that skill by the amount of points displayed on the scroll. + *As you may not gain skills beyond your maximum skill cap, any excess points will be lost.*/ public override string DefaultTitle => $"Scroll of Transcendence ({Value} Skill):"; @@ -115,10 +112,8 @@ namespace Server.Items if (!canGain) { from.SendLocalizedMessage( - 1094935); - /* You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. - * If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap. - */ + 1094935); /*You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. + *If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap.*/ return; } diff --git a/Projects/Scripts/Items/Special/Special Scrolls/SpecialScroll.cs b/Projects/Scripts/Items/Special/Special Scrolls/SpecialScroll.cs index 9090b11c5..40fefa434 100644 --- a/Projects/Scripts/Items/Special/Special Scrolls/SpecialScroll.cs +++ b/Projects/Scripts/Items/Special/Special Scrolls/SpecialScroll.cs @@ -158,7 +158,7 @@ namespace Server.Items AddHtmlLocalized(310, 20, 120, 20, AosSkillBonuses.GetLabel(m_Scroll.Skill), 0xFFFFFF); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 1) m_Scroll.Use(m_Mobile); diff --git a/Projects/Scripts/Items/Special/Special Scrolls/StatScroll.cs b/Projects/Scripts/Items/Special/Special Scrolls/StatScroll.cs index c3de85fcb..4ebb96f5c 100644 --- a/Projects/Scripts/Items/Special/Special Scrolls/StatScroll.cs +++ b/Projects/Scripts/Items/Special/Special Scrolls/StatScroll.cs @@ -12,12 +12,10 @@ namespace Server.Items } public override int Message => - 1049469; - /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. - * When used, the effect is not immediately seen without a gain of points with that skill or statistics. - * You can view your maximum skill values in your skills window. - * You can view your maximum statistic value in your statistics window. - */ + 1049469; /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. + * When used, the effect is not immediately seen without a gain of points with that skill or statistics. + * You can view your maximum skill values in your skills window. + * You can view your maximum statistic value in your statistics window. */ public override int Title { @@ -26,13 +24,11 @@ namespace Server.Items int level = ((int)Value - 230) / 5; if (level >= 0 && level <= 4 && Value % 5 == 0) - return 1049458 + level; - /* Wonderous Scroll (+5 Maximum Stats): OR - * Exalted Scroll (+10 Maximum Stats): OR - * Mythical Scroll (+15 Maximum Stats): OR - * Legendary Scroll (+20 Maximum Stats): OR - * Ultimate Scroll (+25 Maximum Stats): - */ + return 1049458 + level; /* Wonderous Scroll (+5 Maximum Stats): OR + * Exalted Scroll (+10 Maximum Stats): OR + * Mythical Scroll (+15 Maximum Stats): OR + * Legendary Scroll (+20 Maximum Stats): OR + * Ultimate Scroll (+25 Maximum Stats): */ return 0; } @@ -46,13 +42,11 @@ namespace Server.Items int level = ((int)Value - 230) / 5; if (level >= 0 && level <= 4 && (int)Value % 5 == 0) - list.Add(1049463 + level, "#1049476"); - /* a wonderous scroll of ~1_type~ (+5 Maximum Stats) OR - * an exalted scroll of ~1_type~ (+10 Maximum Stats) OR - * a mythical scroll of ~1_type~ (+15 Maximum Stats) OR - * a legendary scroll of ~1_type~ (+20 Maximum Stats) OR - * an ultimate scroll of ~1_type~ (+25 Maximum Stats) - */ + list.Add(1049463 + level, "#1049476"); /* a wonderous scroll of ~1_type~ (+5 Maximum Stats) OR + * an exalted scroll of ~1_type~ (+10 Maximum Stats) OR + * a mythical scroll of ~1_type~ (+15 Maximum Stats) OR + * a legendary scroll of ~1_type~ (+20 Maximum Stats) OR + * an ultimate scroll of ~1_type~ (+25 Maximum Stats) */ else list.Add("a scroll of power ({0}{1} Maximum Stats)", Value - 225 >= 0 ? "+" : "", Value - 225); } diff --git a/Projects/Scripts/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs b/Projects/Scripts/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs index cbdb6164a..4d81265d3 100644 --- a/Projects/Scripts/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs +++ b/Projects/Scripts/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs @@ -135,9 +135,9 @@ namespace Server.Items { } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { - Mobile from = sender.Mobile; + Mobile from = state.Mobile; if (info.ButtonID == 1 || info.ButtonID == 2) { @@ -147,10 +147,9 @@ namespace Server.Items return; } - if (from is PlayerMobile mobile) - mobile.AnkhNextUse = DateTime.UtcNow + TimeSpan.FromHours(1); + if (from is PlayerMobile mobile) mobile.AnkhNextUse = DateTime.UtcNow + TimeSpan.FromHours(1); - base.OnResponse(sender, info); + base.OnResponse(state, info); } } } diff --git a/Projects/Scripts/Items/Special/Veteran Rewards/Brazier.cs b/Projects/Scripts/Items/Special/Veteran Rewards/Brazier.cs index 724723140..7f43e8011 100644 --- a/Projects/Scripts/Items/Special/Veteran Rewards/Brazier.cs +++ b/Projects/Scripts/Items/Special/Veteran Rewards/Brazier.cs @@ -63,7 +63,8 @@ namespace Server.Items public void TurnOn() { - m_Fire ??= new Item(); + if (m_Fire == null) + m_Fire = new Item(); m_Fire.ItemID = 0x19AB; m_Fire.Movable = false; diff --git a/Projects/Scripts/Items/Special/Veteran Rewards/Cannon.cs b/Projects/Scripts/Items/Special/Veteran Rewards/Cannon.cs index a16a27f78..3c7c68035 100644 --- a/Projects/Scripts/Items/Special/Veteran Rewards/Cannon.cs +++ b/Projects/Scripts/Items/Special/Veteran Rewards/Cannon.cs @@ -63,37 +63,37 @@ namespace Server.Items switch (direction) { case CannonDirection.North: - { - AddComponent(new CannonAddonComponent(0xE8D), 0, 0, 0); - AddComponent(new CannonAddonComponent(0xE8C), 0, 1, 0); - AddComponent(new CannonAddonComponent(0xE8B), 0, 2, 0); + { + AddComponent(new CannonAddonComponent(0xE8D), 0, 0, 0); + AddComponent(new CannonAddonComponent(0xE8C), 0, 1, 0); + AddComponent(new CannonAddonComponent(0xE8B), 0, 2, 0); - break; - } + break; + } case CannonDirection.East: - { - AddComponent(new CannonAddonComponent(0xE96), 0, 0, 0); - AddComponent(new CannonAddonComponent(0xE95), -1, 0, 0); - AddComponent(new CannonAddonComponent(0xE94), -2, 0, 0); + { + AddComponent(new CannonAddonComponent(0xE96), 0, 0, 0); + AddComponent(new CannonAddonComponent(0xE95), -1, 0, 0); + AddComponent(new CannonAddonComponent(0xE94), -2, 0, 0); - break; - } + break; + } case CannonDirection.South: - { - AddComponent(new CannonAddonComponent(0xE91), 0, 0, 0); - AddComponent(new CannonAddonComponent(0xE92), 0, -1, 0); - AddComponent(new CannonAddonComponent(0xE93), 0, -2, 0); + { + AddComponent(new CannonAddonComponent(0xE91), 0, 0, 0); + AddComponent(new CannonAddonComponent(0xE92), 0, -1, 0); + AddComponent(new CannonAddonComponent(0xE93), 0, -2, 0); - break; - } + break; + } default: - { - AddComponent(new CannonAddonComponent(0xE8E), 0, 0, 0); - AddComponent(new CannonAddonComponent(0xE8F), 1, 0, 0); - AddComponent(new CannonAddonComponent(0xE90), 2, 0, 0); + { + AddComponent(new CannonAddonComponent(0xE8E), 0, 0, 0); + AddComponent(new CannonAddonComponent(0xE8F), 1, 0, 0); + AddComponent(new CannonAddonComponent(0xE90), 2, 0, 0); - break; - } + break; + } } } @@ -114,7 +114,7 @@ namespace Server.Items } [CommandProperty(AccessLevel.GameMaster)] - public CannonDirection CannonDirection { get; private set; } + public CannonDirection CannonDirection{ get; private set; } [CommandProperty(AccessLevel.GameMaster)] public int Charges @@ -261,19 +261,34 @@ namespace Server.Items { if (!Utility.InRange(new Point3D(p), m_Cannon.Location, 2)) { + bool allow = false; int x = p.X - m_Cannon.X; int y = p.Y - m_Cannon.Y; - bool allow = m_Cannon.CannonDirection switch + switch (m_Cannon.CannonDirection) { + case CannonDirection.North: + if (y < 0 && Math.Abs(x) <= -y / 3) + allow = true; - CannonDirection.North => y < 0 && Math.Abs(x) <= -y / 3, - CannonDirection.East => x > 0 && Math.Abs(y) <= x / 3, - CannonDirection.South => y > 0 && Math.Abs(x) <= y / 3, - CannonDirection.West => x < 0 && Math.Abs(y) <= -x / 3, - _ => false, - }; + break; + case CannonDirection.East: + if (x > 0 && Math.Abs(y) <= x / 3) + allow = true; + + break; + case CannonDirection.South: + if (y > 0 && Math.Abs(x) <= y / 3) + allow = true; + + break; + case CannonDirection.West: + if (x < 0 && Math.Abs(y) <= -x / 3) + allow = true; + + break; + } if (allow && Utility.InRange(new Point3D(p), m_Cannon.Location, 14)) m_Cannon.DoFireEffect(p); @@ -286,7 +301,9 @@ namespace Server.Items } } else + { from.SendLocalizedMessage(1049630); // You cannot see that target! + } } protected override void OnTargetOutOfRange(Mobile from, object targeted) @@ -324,10 +341,10 @@ namespace Server.Items AddHtmlLocalized(195, 109, 120, 20, 1076197, 0x7FFF); // Recharge } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (m_Cannon?.Deleted == false && info.ButtonID == (int)Buttons.Recharge) - m_Cannon.Fill(sender.Mobile, m_Keg); + m_Cannon.Fill(state.Mobile, m_Keg); } private enum Buttons @@ -356,8 +373,7 @@ namespace Server.Items public override BaseAddon Addon => new CannonAddon(m_Direction) { - Charges = m_Charges, - IsRewardItem = m_IsRewardItem + Charges = m_Charges, IsRewardItem = m_IsRewardItem }; [CommandProperty(AccessLevel.GameMaster)] diff --git a/Projects/Scripts/Items/Special/Veteran Rewards/WeaponEngravingTool.cs b/Projects/Scripts/Items/Special/Veteran Rewards/WeaponEngravingTool.cs index 9090a7077..481b6c4c5 100644 --- a/Projects/Scripts/Items/Special/Veteran Rewards/WeaponEngravingTool.cs +++ b/Projects/Scripts/Items/Special/Veteran Rewards/WeaponEngravingTool.cs @@ -243,7 +243,7 @@ namespace Server.Items AddTextEntry(75, 245, 350, 40, 0x0, (int)Buttons.Text, ""); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (m_Tool?.Deleted != false || m_Target?.Deleted != false) return; @@ -319,12 +319,12 @@ namespace Server.Items AddHtmlLocalized(40, 109, 100, 20, 1060051, 0x7FFF); // CANCEL } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (m_Engraver?.Deleted != false || info.ButtonID != (int)Buttons.Confirm) return; - m_Engraver.Recharge(sender.Mobile, m_Guildmaster); + m_Engraver.Recharge(state.Mobile, m_Guildmaster); } private enum Buttons diff --git a/Projects/Scripts/Items/Talismans/TalismanSlayer.cs b/Projects/Scripts/Items/Talismans/TalismanSlayer.cs index 71966f898..15b84549a 100644 --- a/Projects/Scripts/Items/Talismans/TalismanSlayer.cs +++ b/Projects/Scripts/Items/Talismans/TalismanSlayer.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Mobiles; namespace Server.Items @@ -74,7 +73,9 @@ namespace Server.Items }, [TalismanSlayerName.Bovine] = new[] { - typeof(Cow), typeof(Bull), typeof(Gaman), typeof(TormentedMinotaur) + typeof(Cow), typeof(Bull), typeof(Gaman) /*, typeof( MinotaurCaptain ), + typeof( MinotaurScout ), typeof( Minotaur )*/ + // TODO TormentedMinotaur } }; } @@ -82,11 +83,15 @@ namespace Server.Items public static bool Slays(TalismanSlayerName name, Mobile m) { if (m == null || !m_Table.TryGetValue(name, out Type[] types) || types == null) - return false; + return false;; Type type = m.GetType(); - return types.Any(t => t.IsAssignableFrom(type)); + for (int i = 0; i < types.Length; i++) + if (types[i].IsAssignableFrom(type)) + return true; + + return false; } } } diff --git a/Projects/Scripts/Items/Talismans/TalismanSummons.cs b/Projects/Scripts/Items/Talismans/TalismanSummons.cs index 6863a4c5a..e2e4e933f 100644 --- a/Projects/Scripts/Items/Talismans/TalismanSummons.cs +++ b/Projects/Scripts/Items/Talismans/TalismanSummons.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using Server.ContextMenus; using Server.Items; -using Server.Regions; namespace Server.Mobiles { @@ -397,6 +396,9 @@ namespace Server.Mobiles int version = reader.ReadEncodedInt(); } + /* + // An area attack that only damages staff, wtf? + private DateTime m_NextWave; public void AreaHeatDamage() @@ -406,20 +408,29 @@ namespace Server.Mobiles if ( mob != null ) { if ( mob.InRange( Location, 2 ) ) - if ( mob.AccessLevel == AccessLevel.Player ) + { + if ( mob.AccessLevel != AccessLevel.Player ) { AOS.Damage( mob, Utility.Random( 2, 3 ), 0, 100, 0, 0, 0 ); mob.SendLocalizedMessage( 1008112 ); // The intense heat is damaging you! } + } - if ( Region is GuardedRegion && mob.Alive ) + GuardedRegion r = Region as GuardedRegion; + + if ( r != null && mob.Alive ) + { foreach ( Mobile m in GetMobilesInRange( 2 ) ) + { if ( !mob.CanBeHarmful( m ) ) mob.CriminalAction( false ); + } + } } m_NextWave = DateTime.UtcNow + TimeSpan.FromSeconds( 3 ); } + */ } public class SummonedOrcBrute : BaseTalismanSummon @@ -620,4 +631,4 @@ namespace Server.Mobiles int version = reader.ReadEncodedInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Traps/GasTrap.cs b/Projects/Scripts/Items/Traps/GasTrap.cs index 9bd0efdef..a6950be9c 100644 --- a/Projects/Scripts/Items/Traps/GasTrap.cs +++ b/Projects/Scripts/Items/Traps/GasTrap.cs @@ -35,7 +35,7 @@ namespace Server.Items [CommandProperty(AccessLevel.GameMaster)] public GasTrapType Type { - get => ItemID switch + get { return ItemID switch { @@ -69,7 +69,7 @@ namespace Server.Items if (Poison == null || !from.Player || !from.Alive || from.AccessLevel > AccessLevel.Player) return; - Effects.SendLocationEffect(Location, Map, GetBaseID(Type) - 2, 16, 3, GetEffectHue()); + Effects.SendLocationEffect(Location, Map, GetBaseID(Type) - 2, 16, 3, GetEffectHue(), 0); Effects.PlaySound(Location, Map, 0x231); from.ApplyPoison(from, Poison); diff --git a/Projects/Scripts/Items/Traps/GiantSpikeTrap.cs b/Projects/Scripts/Items/Traps/GiantSpikeTrap.cs index 121d9a38e..f5425d39e 100644 --- a/Projects/Scripts/Items/Traps/GiantSpikeTrap.cs +++ b/Projects/Scripts/Items/Traps/GiantSpikeTrap.cs @@ -24,7 +24,7 @@ namespace Server.Items if (from.AccessLevel > AccessLevel.Player) return; - Effects.SendLocationEffect(Location, Map, 0x1D99, 48, 2, GetEffectHue()); + Effects.SendLocationEffect(Location, Map, 0x1D99, 48, 2, GetEffectHue(), 0); if (from.Alive && CheckRange(from.Location, 0)) SpellHelper.Damage(TimeSpan.FromTicks(1), from, from, Utility.Dice(10, 7, 0)); diff --git a/Projects/Scripts/Items/Traps/SawTrap.cs b/Projects/Scripts/Items/Traps/SawTrap.cs index 8b28281d1..7b1de8d2c 100644 --- a/Projects/Scripts/Items/Traps/SawTrap.cs +++ b/Projects/Scripts/Items/Traps/SawTrap.cs @@ -26,7 +26,7 @@ namespace Server.Items [CommandProperty(AccessLevel.GameMaster)] public SawTrapType Type { - get => ItemID switch + get { return ItemID switch { @@ -62,7 +62,7 @@ namespace Server.Items if (!from.Alive || from.AccessLevel > AccessLevel.Player) return; - Effects.SendLocationEffect(Location, Map, GetBaseID(Type) + 1, 6, 3, GetEffectHue()); + Effects.SendLocationEffect(Location, Map, GetBaseID(Type) + 1, 6, 3, GetEffectHue(), 0); Effects.PlaySound(Location, Map, 0x21C); SpellHelper.Damage(TimeSpan.FromTicks(1), from, from, Utility.RandomMinMax(5, 15)); diff --git a/Projects/Scripts/Items/Traps/SpikeTrap.cs b/Projects/Scripts/Items/Traps/SpikeTrap.cs index 843b02e07..0a4a636df 100644 --- a/Projects/Scripts/Items/Traps/SpikeTrap.cs +++ b/Projects/Scripts/Items/Traps/SpikeTrap.cs @@ -26,7 +26,7 @@ namespace Server.Items [CommandProperty(AccessLevel.GameMaster)] public SpikeTrapType Type { - get => ItemID switch + get { return ItemID switch { @@ -56,7 +56,13 @@ namespace Server.Items public bool Extended { get => ItemID == GetExtendedID(Type); - set => ItemID = value ? GetExtendedID(Type) : GetBaseID(Type); + set + { + if (value) + ItemID = GetExtendedID(Type); + else + ItemID = GetBaseID(Type); + } } public override bool PassivelyTriggered => false; @@ -95,7 +101,7 @@ namespace Server.Items if (!from.Alive || from.AccessLevel > AccessLevel.Player) return; - Effects.SendLocationEffect(Location, Map, GetBaseID(Type) + 1, 18, 3, GetEffectHue()); + Effects.SendLocationEffect(Location, Map, GetBaseID(Type) + 1, 18, 3, GetEffectHue(), 0); Effects.PlaySound(Location, Map, 0x22C); foreach (Mobile mob in GetMobilesInRange(0)) @@ -116,7 +122,7 @@ namespace Server.Items public virtual void OnSpikeRetracted() { Extended = false; - Effects.SendLocationEffect(Location, Map, GetExtendedID(Type) - 1, 6, 3, GetEffectHue()); + Effects.SendLocationEffect(Location, Map, GetExtendedID(Type) - 1, 6, 3, GetEffectHue(), 0); } public override void Serialize(GenericWriter writer) diff --git a/Projects/Scripts/Items/Traps/StoneFaceTrap.cs b/Projects/Scripts/Items/Traps/StoneFaceTrap.cs index f9a320d74..2aab141f8 100644 --- a/Projects/Scripts/Items/Traps/StoneFaceTrap.cs +++ b/Projects/Scripts/Items/Traps/StoneFaceTrap.cs @@ -40,24 +40,22 @@ namespace Server.Items } set { - 0x10F5 => StoneFaceTrapType.NorthWestWall, - 0x10F6 => StoneFaceTrapType.NorthWestWall, - 0x10F7 => StoneFaceTrapType.NorthWestWall, - 0x10FC => StoneFaceTrapType.NorthWall, - 0x10FD => StoneFaceTrapType.NorthWall, - 0x10FE => StoneFaceTrapType.NorthWall, - 0x110F => StoneFaceTrapType.WestWall, - 0x1110 => StoneFaceTrapType.WestWall, - 0x1111 => StoneFaceTrapType.WestWall, - _ => StoneFaceTrapType.NorthWestWall - }; - set => ItemID = Breathing ? GetFireID(value) : GetBaseID(value); + bool breathing = Breathing; + + ItemID = breathing ? GetFireID(value) : GetBaseID(value); + } } public bool Breathing { get => ItemID == GetFireID(Type); - set => ItemID = value ? GetFireID(Type) : GetBaseID(Type); + set + { + if (value) + ItemID = GetFireID(Type); + else + ItemID = GetBaseID(Type); + } } public override bool PassivelyTriggered => true; @@ -159,4 +157,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Wands/BaseWand.cs b/Projects/Scripts/Items/Wands/BaseWand.cs index 97819c442..656850536 100644 --- a/Projects/Scripts/Items/Wands/BaseWand.cs +++ b/Projects/Scripts/Items/Wands/BaseWand.cs @@ -236,15 +236,22 @@ namespace Server.Items int number; if (Name == null) + { number = 1017085; + } else { LabelTo(from, Name); number = 1041000; } - if (attrs.Count > 0 || Crafter != null || Name == null) - EquipmentPackets.SendDisplayEquipmentInfo(from.NetState, this, number, Crafter, false, attrs); + if (attrs.Count == 0 && Crafter == null && Name != null) + return; + + EquipmentInfo eqInfo = new EquipmentInfo(number, Crafter, false, + attrs.ToArray()); + + from.Send(new DisplayEquipmentInfo(this, eqInfo)); } public void Cast(Spell spell) @@ -272,4 +279,4 @@ namespace Server.Items public virtual bool OnWandTarget(Mobile from, object o) => true; } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Items/Weapons/Abilities/WeaponAbility.cs b/Projects/Scripts/Items/Weapons/Abilities/WeaponAbility.cs index 50b2d774f..dff3bf72e 100644 --- a/Projects/Scripts/Items/Weapons/Abilities/WeaponAbility.cs +++ b/Projects/Scripts/Items/Weapons/Abilities/WeaponAbility.cs @@ -125,13 +125,13 @@ namespace Server.Items { int mana = BaseMana; - double skillTotal = GetSkill(from, SkillName.Swords) + GetSkill(from, SkillName.Macing) + - GetSkill(from, SkillName.Fencing) + + double 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.Parry) + + GetSkill(from, SkillName.Lumberjacking) + + GetSkill(from, SkillName.Stealth) + + GetSkill(from, SkillName.Poisoning) + GetSkill(from, SkillName.Bushido) + GetSkill(from, SkillName.Ninjitsu); @@ -256,33 +256,55 @@ namespace Server.Items #region Dueling - string option = this switch - { - ArmorIgnore _ => "Armor Ignore", - BleedAttack _ => "Bleed Attack", - ConcussionBlow _ => "Concussion Blow", - CrushingBlow _ => "Crushing Blow", - Disarm _ => "Disarm", - Dismount _ => "Dismount", - DoubleStrike _ => "Double Strike", - InfectiousStrike _ => "Infectious Strike", - MortalStrike _ => "Mortal Strike", - MovingShot _ => "Moving Shot", - ParalyzingBlow _ => "Paralyzing Blow", - ShadowStrike _ => "Shadow Strike", - WhirlwindAttack _ => "Whirlwind Attack", - RidingSwipe _ => "Riding Swipe", - FrenziedWhirlwind _ => "Frenzied Whirlwind", - Block _ => "Block", - DefenseMastery _ => "Defense Mastery", - NerveStrike _ => "Nerve Strike", - TalonStrike _ => "Talon Strike", - Feint _ => "Feint", - DualWield _ => "Dual Wield", - DoubleShot _ => "Double Shot", - ArmorPierce _ => "Armor Pierce", - _ => null - }; + string option = null; + + if (this is ArmorIgnore) + option = "Armor Ignore"; + else if (this is BleedAttack) + option = "Bleed Attack"; + else if (this is ConcussionBlow) + option = "Concussion Blow"; + else if (this is CrushingBlow) + option = "Crushing Blow"; + else if (this is Disarm) + option = "Disarm"; + else if (this is Dismount) + option = "Dismount"; + else if (this is DoubleStrike) + option = "Double Strike"; + else if (this is InfectiousStrike) + option = "Infectious Strike"; + else if (this is MortalStrike) + option = "Mortal Strike"; + else if (this is MovingShot) + option = "Moving Shot"; + else if (this is ParalyzingBlow) + option = "Paralyzing Blow"; + else if (this is ShadowStrike) + option = "Shadow Strike"; + else if (this is WhirlwindAttack) + option = "Whirlwind Attack"; + else if (this is RidingSwipe) + option = "Riding Swipe"; + else if (this is FrenziedWhirlwind) + option = "Frenzied Whirlwind"; + else if (this is Block) + option = "Block"; + else if (this is DefenseMastery) + option = "Defense Mastery"; + else if (this is NerveStrike) + option = "Nerve Strike"; + else if (this is TalonStrike) + option = "Talon Strike"; + else if (this is Feint) + option = "Feint"; + else if (this is DualWield) + option = "Dual Wield"; + else if (this is DoubleShot) + option = "Double Shot"; + else if (this is ArmorPierce) + option = "Armor Pierce"; + if (option != null && !DuelContext.AllowSpecialAbility(from, option, true)) return false; @@ -359,7 +381,7 @@ namespace Server.Items Table.Remove(m); if (Core.AOS && m.NetState != null) - Packets.SendClearWeaponAbility(m.NetState); + m.Send(ClearWeaponAbility.Instance); } public static void Initialize() diff --git a/Projects/Scripts/Items/Weapons/BaseWeapon.cs b/Projects/Scripts/Items/Weapons/BaseWeapon.cs index 2d686d4dc..c3a156618 100644 --- a/Projects/Scripts/Items/Weapons/BaseWeapon.cs +++ b/Projects/Scripts/Items/Weapons/BaseWeapon.cs @@ -291,16 +291,24 @@ namespace Server.Items if (m_Quality == WeaponQuality.Exceptional) bonus += 20; - - bonus += m_DurabilityLevel switch + switch (m_DurabilityLevel) { - WeaponDurabilityLevel.Durable => 20, - WeaponDurabilityLevel.Substantial => 50, - WeaponDurabilityLevel.Massive => 70, - WeaponDurabilityLevel.Fortified => 100, - WeaponDurabilityLevel.Indestructible => 120, - _ => 0 - }; + case WeaponDurabilityLevel.Durable: + bonus += 20; + break; + case WeaponDurabilityLevel.Substantial: + bonus += 50; + break; + case WeaponDurabilityLevel.Massive: + bonus += 70; + break; + case WeaponDurabilityLevel.Fortified: + bonus += 100; + break; + case WeaponDurabilityLevel.Indestructible: + bonus += 120; + break; + } if (Core.AOS) { @@ -508,9 +516,10 @@ namespace Server.Items double swrd = m.Skills.Swords.Value; double fenc = m.Skills.Fencing.Value; double mcng = m.Skills.Macing.Value; + double val; sk = SkillName.Swords; - double val = swrd; + val = swrd; if (fenc > val) { @@ -521,7 +530,12 @@ namespace Server.Items if (mcng > val) sk = SkillName.Macing; } else if (WeaponAttributes.MageWeapon != 0) - sk = m.Skills.Magery.Value > m.Skills[Skill].Value ? SkillName.Magery : Skill; + { + if (m.Skills.Magery.Value > m.Skills[Skill].Value) + sk = SkillName.Magery; + else + sk = Skill; + } else { sk = Skill; @@ -778,7 +792,9 @@ namespace Server.Items if (canSwing && attacker.HarmfulCheck(defender)) { attacker.DisruptiveAction(); - Packets.SendSwing(attacker.NetState, attacker.Serial, defender.Serial); + + if (attacker.NetState != null) + attacker.Send(new Swing(0, attacker, defender)); if (attacker is BaseCreature bc) { @@ -1433,7 +1449,7 @@ namespace Server.Items damage = AOS.Scale(damage, 100 + damageBonus); - return damage / 100.0; + return damage / 100; } public virtual CheckSlayerResult CheckSlayers(Mobile attacker, Mobile defender) @@ -1625,32 +1641,65 @@ namespace Server.Items if (!Core.AOS) return 0; - return m_AccuracyLevel switch + int bonus = 0; + + switch (m_AccuracyLevel) { - WeaponAccuracyLevel.Accurate => 2, - WeaponAccuracyLevel.Surpassingly => 4, - WeaponAccuracyLevel.Eminently => 6, - WeaponAccuracyLevel.Exceedingly => 8, - WeaponAccuracyLevel.Supremely => 10, - _ => 0 - }; + case WeaponAccuracyLevel.Accurate: + bonus += 02; + break; + case WeaponAccuracyLevel.Surpassingly: + bonus += 04; + break; + case WeaponAccuracyLevel.Eminently: + bonus += 06; + break; + case WeaponAccuracyLevel.Exceedingly: + bonus += 08; + break; + case WeaponAccuracyLevel.Supremely: + bonus += 10; + break; + } + + return bonus; } - public virtual int GetDamageBonus() => - VirtualDamageBonus + m_Quality switch + public virtual int GetDamageBonus() + { + int bonus = VirtualDamageBonus; + + switch (m_Quality) { - WeaponQuality.Low => -20, - WeaponQuality.Exceptional => 20, - _ => 0, - } + m_DamageLevel switch + case WeaponQuality.Low: + bonus -= 20; + break; + case WeaponQuality.Exceptional: + bonus += 20; + break; + } + + switch (m_DamageLevel) { - WeaponDamageLevel.Ruin => 15, - WeaponDamageLevel.Might => 20, - WeaponDamageLevel.Force => 25, - WeaponDamageLevel.Power => 30, - WeaponDamageLevel.Vanq => 35, - _ => 0, - }; + case WeaponDamageLevel.Ruin: + bonus += 15; + break; + case WeaponDamageLevel.Might: + bonus += 20; + break; + case WeaponDamageLevel.Force: + bonus += 25; + break; + case WeaponDamageLevel.Power: + bonus += 30; + break; + case WeaponDamageLevel.Vanq: + bonus += 35; + break; + } + + return bonus; + } public virtual double ScaleDamageAOS(Mobile attacker, double damage, bool checkSkills) { @@ -2304,7 +2353,10 @@ namespace Server.Items } else if (m_Slayer != SlayerName.None || m_Slayer2 != SlayerName.None || m_DurabilityLevel != WeaponDurabilityLevel.Regular || m_DamageLevel != WeaponDamageLevel.Regular || - m_AccuracyLevel != WeaponAccuracyLevel.Regular) attrs.Add(new EquipInfoAttribute(1038000)); // Unidentified + m_AccuracyLevel != WeaponAccuracyLevel.Regular) + { + attrs.Add(new EquipInfoAttribute(1038000)); // Unidentified + } if (m_Poison != null && m_PoisonCharges > 0) attrs.Add(new EquipInfoAttribute(1017383, m_PoisonCharges)); @@ -2312,15 +2364,21 @@ namespace Server.Items int number; if (Name == null) + { number = LabelNumber; + } else { LabelTo(from, Name); number = 1041000; } - if (attrs.Count > 0 || Crafter != null || Name == null) - EquipmentPackets.SendDisplayEquipmentInfo(from.NetState, this, number, m_Crafter, false, attrs); + if (attrs.Count == 0 && Crafter == null && Name != null) + return; + + EquipmentInfo eqInfo = new EquipmentInfo(number, m_Crafter, false, attrs.ToArray()); + + from.Send(new DisplayEquipmentInfo(this, eqInfo)); } private class ResetEquipTimer : Timer @@ -2860,7 +2918,7 @@ namespace Server.Items double damage = GetAosDamage(attacker, 23, 1, 4); - defender.BoltEffect(); + defender.BoltEffect(0); SpellHelper.Damage(TimeSpan.Zero, defender, attacker, damage, 0, 0, 0, 0, 100); } @@ -3297,7 +3355,8 @@ namespace Server.Items parentMobile.AddSkillMod(m_MageMod); } - PlayerConstructed |= GetSaveFlag(flags, SaveFlag.PlayerConstructed); + if (GetSaveFlag(flags, SaveFlag.PlayerConstructed)) + PlayerConstructed = true; if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) SkillBonuses = new AosSkillBonuses(this, reader); @@ -3449,7 +3508,8 @@ namespace Server.Items if (m_Hits <= 0 && m_MaxHits <= 0) m_Hits = m_MaxHits = Utility.RandomMinMax(InitMinHits, InitMaxHits); - PlayerConstructed |= version < 6; // we don't know, so, assume it's crafted + if (version < 6) + PlayerConstructed = true; // we don't know, so, assume it's crafted } #endregion diff --git a/Projects/Scripts/Items/Weapons/Maces/FireworksWand.cs b/Projects/Scripts/Items/Weapons/Maces/FireworksWand.cs index 40f243fee..37389667e 100644 --- a/Projects/Scripts/Items/Weapons/Maces/FireworksWand.cs +++ b/Projects/Scripts/Items/Weapons/Maces/FireworksWand.cs @@ -71,7 +71,7 @@ namespace Server.Items startLoc.Z + 32); Effects.SendMovingEffect(new Entity(Serial.Zero, startLoc, map), new Entity(Serial.Zero, endLoc, map), - 0x36E4, 5, 0); + 0x36E4, 5, 0, false, false); Timer.DelayCall(TimeSpan.FromSeconds(1.0), () => FinishLaunch(endLoc, map)); } diff --git a/Projects/Scripts/Items/Weapons/Ranged/BaseRanged.cs b/Projects/Scripts/Items/Weapons/Ranged/BaseRanged.cs index c9a1283d5..7c87a4199 100644 --- a/Projects/Scripts/Items/Weapons/Ranged/BaseRanged.cs +++ b/Projects/Scripts/Items/Weapons/Ranged/BaseRanged.cs @@ -81,7 +81,7 @@ namespace Server.Items if (canSwing && attacker.HarmfulCheck(defender)) { attacker.DisruptiveAction(); - Packets.SendSwing(attacker.NetState, attacker.Serial, defender.Serial); + attacker.Send(new Swing(0, attacker, defender)); if (OnFired(attacker, defender)) { diff --git a/Projects/Scripts/Items/Weapons/Staves/ShepherdsCrook.cs b/Projects/Scripts/Items/Weapons/Staves/ShepherdsCrook.cs index 1a17ad5ff..dab5c1bb5 100644 --- a/Projects/Scripts/Items/Weapons/Staves/ShepherdsCrook.cs +++ b/Projects/Scripts/Items/Weapons/Staves/ShepherdsCrook.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Server.Engines.CannedEvil; using Server.Mobiles; using Server.Network; @@ -118,7 +117,9 @@ namespace Server.Items { Type t = bc.GetType(); - return m_ChampTamables.Any(type => type == t); + foreach (Type type in m_ChampTamables) + if (type == t) + return true; } } @@ -144,7 +145,7 @@ namespace Server.Items if (from.CheckTargetSkill(SkillName.Herding, m_Creature, min, max)) { - if (!ReferenceEquals(p, from)) + if (p != from) p = new Point2D(p.X, p.Y); m_Creature.TargetLocation = p; diff --git a/Projects/Scripts/Misc/AOS.cs b/Projects/Scripts/Misc/AOS.cs index 2d9fac575..cbf8d4487 100644 --- a/Projects/Scripts/Misc/AOS.cs +++ b/Projects/Scripts/Misc/AOS.cs @@ -9,7 +9,7 @@ using Server.Spells.Seventh; namespace Server { - public static class AOS + public class AOS { public static void DisableStatInfluences() { @@ -1019,7 +1019,8 @@ namespace Server if (!GetValues(i, out SkillName skill, out double bonus)) continue; - m_Mods ??= new List(); + if (m_Mods == null) + m_Mods = new List(); SkillMod sk = new DefaultSkillMod(skill, true, bonus); sk.ObeyCap = true; diff --git a/Projects/Scripts/Misc/AccountPrompt.cs b/Projects/Scripts/Misc/AccountPrompt.cs index 274e5bd9e..1c5df4dab 100644 --- a/Projects/Scripts/Misc/AccountPrompt.cs +++ b/Projects/Scripts/Misc/AccountPrompt.cs @@ -3,7 +3,7 @@ using Server.Accounting; namespace Server.Misc { - public static class AccountPrompt + public class AccountPrompt { public static void Initialize() { @@ -22,7 +22,8 @@ namespace Server.Misc Console.Write("Password: "); string password = Console.ReadLine(); - Account a = new Account(username, password) {AccessLevel = AccessLevel.Owner}; + Account a = new Account(username, password); + a.AccessLevel = AccessLevel.Owner; Console.WriteLine("Account created."); } @@ -35,4 +36,4 @@ namespace Server.Misc } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/Animations.cs b/Projects/Scripts/Misc/Animations.cs index 67de3a56b..d4515e671 100644 --- a/Projects/Scripts/Misc/Animations.cs +++ b/Projects/Scripts/Misc/Animations.cs @@ -1,6 +1,6 @@ namespace Server.Misc { - public static class Animations + public class Animations { public static void Initialize() { @@ -28,4 +28,4 @@ namespace Server.Misc from.Animate(action, 5, 1, true, false, 0); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/AttackMessage.cs b/Projects/Scripts/Misc/AttackMessage.cs index a58ccf38a..0687281f7 100644 --- a/Projects/Scripts/Misc/AttackMessage.cs +++ b/Projects/Scripts/Misc/AttackMessage.cs @@ -4,7 +4,7 @@ using Server.Network; namespace Server.Misc { - public static class AttackMessage + public class AttackMessage { private const string AggressorFormat = "You are attacking {0}!"; private const string AggressedFormat = "{0} is attacking you!"; @@ -59,4 +59,4 @@ namespace Server.Misc return false; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/AutoSave.cs b/Projects/Scripts/Misc/AutoSave.cs index 6b538ce56..1d206f72b 100644 --- a/Projects/Scripts/Misc/AutoSave.cs +++ b/Projects/Scripts/Misc/AutoSave.cs @@ -141,7 +141,7 @@ namespace Server.Misc string saves = Path.Combine(Core.BaseDirectory, "Saves"); if (Directory.Exists(saves)) - Directory.Move(saves, FormatDirectory(root, m_Backups[^1], GetTimeStamp())); + Directory.Move(saves, FormatDirectory(root, m_Backups[m_Backups.Length - 1], GetTimeStamp())); } private static DirectoryInfo Match(string[] paths, string match) @@ -181,4 +181,4 @@ namespace Server.Misc return $"{now.Day}-{now.Month}-{now.Year} {now.Hour}-{now.Minute:D2}-{now.Second:D2}"; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/Broadcasts.cs b/Projects/Scripts/Misc/Broadcasts.cs index 4e4e6b117..65d5f79a3 100644 --- a/Projects/Scripts/Misc/Broadcasts.cs +++ b/Projects/Scripts/Misc/Broadcasts.cs @@ -1,6 +1,6 @@ namespace Server.Misc { - public static class Broadcasts + public class Broadcasts { public static void Initialize() { diff --git a/Projects/Scripts/Misc/BuffIcons.cs b/Projects/Scripts/Misc/BuffIcons.cs index 1a4bf64fa..6884f63c9 100644 --- a/Projects/Scripts/Misc/BuffIcons.cs +++ b/Projects/Scripts/Misc/BuffIcons.cs @@ -1,5 +1,4 @@ using System; -using Server.Buffers; using Server.Mobiles; using Server.Network; @@ -19,11 +18,13 @@ namespace Server }; } + #region Properties + public BuffIcon ID{ get; } - public int Title{ get; } + public int TitleCliloc{ get; } - public TextDefinition Description{ get; } + public int SecondaryCliloc{ get; } public TimeSpan TimeLength{ get; } @@ -31,30 +32,50 @@ namespace Server public Timer Timer{ get; } - public bool RetainThroughDeath { get; } + public bool RetainThroughDeath{ get; } - public BuffInfo(BuffIcon iconId, int title, TimeSpan time = default, Mobile m = null) : - this(iconId, title, title + 1, time, m) + public TextDefinition Args{ get; } + + #endregion + + #region Constructors + + public BuffInfo(BuffIcon iconID, int titleCliloc) + : this(iconID, titleCliloc, titleCliloc + 1) { } - public BuffInfo(BuffIcon iconId, int title, string args, TimeSpan time = default, Mobile m = null) : - this(iconId, title, title + 1, args, time, m) + public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc) + { + ID = iconID; + TitleCliloc = titleCliloc; + SecondaryCliloc = secondaryCliloc; + } + + public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m) + : this(iconID, titleCliloc, titleCliloc + 1, length, m) { } - public BuffInfo(BuffIcon iconId, int title, int desc, TimeSpan time = default, Mobile m = null) : - this(iconId, title, desc, null, time, m) + //Only the timed one needs to Mobile to know when to automagically remove it. + public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m) + : this(iconID, titleCliloc, secondaryCliloc) { + TimeLength = length; + TimeStart = DateTime.UtcNow; + + Timer = Timer.DelayCall(length, delegate + { + if (!(m is PlayerMobile pm)) + return; + + pm.RemoveBuff(this); + }); } - public BuffInfo(BuffIcon iconId, int title, string args, bool retain, Mobile m = null) : - this(iconId, title, title + 1, args, DateTime.UtcNow, default, retain, m) - { - } - public BuffInfo(BuffIcon iconId, int title, int desc, string args, TimeSpan time, Mobile m = null) : - this(iconId, title, new TextDefinition(desc, args), DateTime.UtcNow, time, false, m) + public BuffInfo(BuffIcon iconID, int titleCliloc, TextDefinition args) + : this(iconID, titleCliloc, titleCliloc + 1, args) { } @@ -62,8 +83,8 @@ namespace Server : this(iconID, titleCliloc, secondaryCliloc) => Args = args; - public BuffInfo(BuffIcon iconId, int title, int desc, string args, TimeSpan time = default, bool retain = false, - Mobile m = null) : this(iconId, title, new TextDefinition(desc, args), DateTime.UtcNow, time, retain, m) + public BuffInfo(BuffIcon iconID, int titleCliloc, bool retainThroughDeath) + : this(iconID, titleCliloc, titleCliloc + 1, retainThroughDeath) { } @@ -71,17 +92,9 @@ namespace Server : this(iconID, titleCliloc, secondaryCliloc) => RetainThroughDeath = retainThroughDeath; - public BuffInfo(BuffIcon iconId, int title, TextDefinition desc, DateTime start = default, TimeSpan time = default, bool retain = false, - Mobile m = null) + public BuffInfo(BuffIcon iconID, int titleCliloc, TextDefinition args, bool retainThroughDeath) + : this(iconID, titleCliloc, titleCliloc + 1, args, retainThroughDeath) { - ID = iconId; - Title = title; - Description = desc; - TimeLength = time; - TimeStart = start; - RetainThroughDeath = retain; - if (m is PlayerMobile pm) - Timer = Timer.DelayCall(time, playermobile => playermobile.RemoveBuff(this), pm); } public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, bool retainThroughDeath) @@ -118,17 +131,20 @@ namespace Server public static void AddBuff(Mobile m, BuffInfo b) { - (m as PlayerMobile)?.AddBuff(b); + if (m is PlayerMobile pm) + pm.AddBuff(b); } public static void RemoveBuff(Mobile m, BuffInfo b) { - (m as PlayerMobile)?.RemoveBuff(b); + if (m is PlayerMobile pm) + pm.RemoveBuff(b); } public static void RemoveBuff(Mobile m, BuffIcon b) { - (m as PlayerMobile)?.RemoveBuff(b); + if (m is PlayerMobile pm) + pm.RemoveBuff(b); } #endregion @@ -192,68 +208,80 @@ namespace Server Fly } - public static class BuffPackets + public sealed class AddBuffPacket : Packet { - public static void SendAddBuff(Mobile m, BuffInfo info) + public AddBuffPacket(Mobile m, BuffInfo info) + : this(m, info.ID, info.TitleCliloc, info.SecondaryCliloc, info.Args, + info.TimeStart != DateTime.MinValue ? info.TimeStart + info.TimeLength - DateTime.UtcNow : TimeSpan.Zero) { - SendAddBuff(m.NetState, m.Serial, info.ID, info.Title, info.Description, - info.TimeStart != DateTime.MinValue ? info.TimeStart + info.TimeLength - DateTime.UtcNow : TimeSpan.Zero); - } - public static void SendAddBuff(NetState ns, Serial m, BuffIcon iconID, int title, TextDefinition desc, TimeSpan time) - { - if (ns == null) - return; - - string args = desc?.String ?? ""; - - int length = 44 + args.Length * 2; - - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xDF); // Packet ID - writer.Write((ushort)length); // Dynamic Length - - writer.Write(m); - - writer.Write((short)iconID); //ID - writer.Write((short)0x1); //Type 0 for removal. 1 for add 2 for Data - - writer.Position += 4; - - writer.Write((short)iconID); //ID - writer.Write((short)0x01); //Type 0 for removal. 1 for add 2 for Data - - writer.Position += 4; - - writer.Write((short)Math.Max(time.TotalSeconds, 0)); //Time in seconds - - writer.Position += 3; - - writer.Write(title); - writer.Write(desc?.Number ?? 0); - - writer.Position += 5; - writer.Write((byte)0x1); // Start indicator? - writer.Position += 2; - - writer.WriteLittleUniNull(args); - - ns.Send(writer.Span); } - public static void SendRemoveBuffPacket(NetState ns, Serial m, int icon) + public AddBuffPacket(Mobile mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, + TimeSpan length) + : base(0xDF) { - SpanWriter writer = new SpanWriter(stackalloc byte[13]); - writer.Write((byte)0xDF); // Packet ID - writer.Write((ushort)13); // Dynamic Length + bool hasArgs = args != null; - writer.Write(m); + EnsureCapacity(hasArgs ? 48 + args.ToString().Length * 2 : 44); + m_Stream.Write(mob.Serial); - writer.Write((short)icon); //ID - writer.Write((short)0x0); //Type 0 for removal. 1 for add 2 for Data - writer.Position += 4; + m_Stream.Write((short)iconID); //ID + m_Stream.Write((short)0x1); //Type 0 for removal. 1 for add 2 for Data - ns.Send(writer.Span); + m_Stream.Fill(4); + + m_Stream.Write((short)iconID); //ID + m_Stream.Write((short)0x01); //Type 0 for removal. 1 for add 2 for Data + + m_Stream.Fill(4); + + if (length < TimeSpan.Zero) + length = TimeSpan.Zero; + + m_Stream.Write((short)length.TotalSeconds); //Time in seconds + + m_Stream.Fill(3); + m_Stream.Write(titleCliloc); + m_Stream.Write(secondaryCliloc); + + if (!hasArgs) + { + //m_Stream.Fill( 2 ); + m_Stream.Fill(10); + } + else + { + m_Stream.Fill(4); + m_Stream.Write((short)0x1); //Unknown -> Possibly something saying 'hey, I have more data!'? + m_Stream.Fill(2); + + //m_Stream.WriteLittleUniNull( "\t#1018280" ); + m_Stream.WriteLittleUniNull($"\t{args}"); + + m_Stream.Write((short)0x1); //Even more Unknown -> Possibly something saying 'hey, I have more data!'? + m_Stream.Fill(2); + } } } -} + + public sealed class RemoveBuffPacket : Packet + { + public RemoveBuffPacket(Mobile mob, BuffInfo info) + : this(mob, info.ID) + { + } + + public RemoveBuffPacket(Mobile mob, BuffIcon iconID) + : base(0xDF) + { + EnsureCapacity(13); + m_Stream.Write(mob.Serial); + + m_Stream.Write((short)iconID); //ID + m_Stream.Write((short)0x0); //Type 0 for removal. 1 for add 2 for Data + + m_Stream.Fill(4); + } + } +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/CharacterCreation.cs b/Projects/Scripts/Misc/CharacterCreation.cs index a234f5e6c..64fcdd999 100644 --- a/Projects/Scripts/Misc/CharacterCreation.cs +++ b/Projects/Scripts/Misc/CharacterCreation.cs @@ -7,7 +7,7 @@ using Server.Network; namespace Server.Misc { - public static class CharacterCreation + public class CharacterCreation { private static readonly CityInfo m_NewHavenInfo = new CityInfo("New Haven", "The Bountiful Harvest Inn", 3503, 2574, 14, Map.Trammel); @@ -22,8 +22,15 @@ namespace Server.Misc private static void AddBackpack(Mobile m) { - if (m.Backpack == null) - m.AddItem(new Backpack {Movable = false}); + Container pack = m.Backpack; + + if (pack == null) + { + pack = new Backpack(); + pack.Movable = false; + + m.AddItem(pack); + } PackItem(new RedBook("a book", m.Name, 20, true)); PackItem(new Gold(1000)); // Starting gold can be customized here @@ -45,8 +52,16 @@ namespace Server.Misc item.Location = new Point3D(x, y, 0); } - private static Item MakePotionKeg(PotionEffect type, int hue) => - MakeNewbie(new PotionKeg {Held = 100, Type = type, Hue = hue}); + private static Item MakePotionKeg(PotionEffect type, int hue) + { + PotionKeg keg = new PotionKeg(); + + keg.Held = 100; + keg.Type = type; + keg.Hue = hue; + + return MakeNewbie(keg); + } private static void FillBankAOS(Mobile m) { @@ -60,8 +75,11 @@ namespace Server.Misc m.StatCap = 250; + Container cont; + + // Begin box of money - Container cont = new WoodenBox(); + cont = new WoodenBox(); cont.ItemID = 0xE7D; cont.Hue = 0x489; @@ -79,7 +97,8 @@ namespace Server.Misc // Begin bag of potion kegs - cont = new Backpack {Name = "Various Potion Kegs"}; + cont = new Backpack(); + cont.Name = "Various Potion Kegs"; PlaceItemIn(cont, 45, 149, MakePotionKeg(PotionEffect.CureGreater, 0x2D)); PlaceItemIn(cont, 69, 149, MakePotionKeg(PotionEffect.HealGreater, 0x499)); @@ -94,7 +113,8 @@ namespace Server.Misc // Begin bag of tools - cont = new Bag {Name = "Tool Bag"}; + cont = new Bag(); + cont.Name = "Tool Bag"; PlaceItemIn(cont, 30, 35, new TinkerTools(1000)); PlaceItemIn(cont, 60, 35, new HousePlacementTool()); @@ -125,7 +145,8 @@ namespace Server.Misc // Begin bag of archery ammo - cont = new Bag {Name = "Bag Of Archery Ammo"}; + cont = new Bag(); + cont.Name = "Bag Of Archery Ammo"; PlaceItemIn(cont, 48, 76, new Arrow(5000)); PlaceItemIn(cont, 72, 76, new Bolt(5000)); @@ -135,7 +156,8 @@ namespace Server.Misc // Begin bag of treasure maps - cont = new Bag {Name = "Bag Of Treasure Maps"}; + cont = new Bag(); + cont.Name = "Bag Of Treasure Maps"; PlaceItemIn(cont, 30, 35, new TreasureMap(1, Map.Trammel)); PlaceItemIn(cont, 45, 35, new TreasureMap(2, Map.Trammel)); @@ -159,7 +181,9 @@ namespace Server.Misc // Begin bag of raw materials - cont = new Bag {Hue = 0x835, Name = "Raw Materials Bag"}; + cont = new Bag(); + cont.Hue = 0x835; + cont.Name = "Raw Materials Bag"; PlaceItemIn(cont, 92, 60, new BarbedLeather(5000)); PlaceItemIn(cont, 92, 68, new HornedLeather(5000)); @@ -192,7 +216,9 @@ namespace Server.Misc // Begin bag of spell casting stuff - cont = new Backpack {Hue = 0x480, Name = "Spell Casting Stuff"}; + cont = new Backpack(); + cont.Hue = 0x480; + cont.Name = "Spell Casting Stuff"; PlaceItemIn(cont, 45, 105, new Spellbook(ulong.MaxValue)); PlaceItemIn(cont, 65, 105, new NecromancerSpellbook((ulong)0xFFFF)); @@ -208,7 +234,8 @@ namespace Server.Misc toHue.Hue = 0x2D; PlaceItemIn(cont, 45, 150, toHue); - toHue = new BagOfNecroReagents(150) {Hue = 0x488}; + toHue = new BagOfNecroReagents(150); + toHue.Hue = 0x488; PlaceItemIn(cont, 65, 150, toHue); PlaceItemIn(cont, 140, 150, new BagOfAllReagents(500)); @@ -223,7 +250,9 @@ namespace Server.Misc // Begin bag of ethereals - cont = new Backpack {Hue = 0x490, Name = "Bag Of Ethy's!"}; + cont = new Backpack(); + cont.Hue = 0x490; + cont.Name = "Bag Of Ethy's!"; PlaceItemIn(cont, 45, 66, new EtherealHorse()); PlaceItemIn(cont, 69, 82, new EtherealOstard()); @@ -239,7 +268,9 @@ namespace Server.Misc // Begin first bag of artifacts - cont = new Backpack {Hue = 0x48F, Name = "Bag of Artifacts"}; + cont = new Backpack(); + cont.Hue = 0x48F; + cont.Name = "Bag of Artifacts"; PlaceItemIn(cont, 45, 66, new TitansHammer()); PlaceItemIn(cont, 69, 82, new InquisitorsResolution()); @@ -251,7 +282,9 @@ namespace Server.Misc // Begin second bag of artifacts - cont = new Backpack {Hue = 0x48F, Name = "Bag of Artifacts"}; + cont = new Backpack(); + cont.Hue = 0x48F; + cont.Name = "Bag of Artifacts"; PlaceItemIn(cont, 45, 66, new GauntletsOfNobility()); PlaceItemIn(cont, 69, 82, new MidnightBracers()); @@ -291,7 +324,10 @@ namespace Server.Misc // End second bag of artifacts // Begin bag of minor artifacts - cont = new Backpack {Hue = 0x48F, Name = "Bag of Minor Artifacts"}; + cont = new Backpack(); + cont.Hue = 0x48F; + cont.Name = "Bag of Minor Artifacts"; + PlaceItemIn(cont, 45, 66, new LunaLance()); PlaceItemIn(cont, 69, 82, new VioletCourage()); @@ -332,7 +368,9 @@ namespace Server.Misc if (Core.SE) { - cont = new Bag {Hue = 0x501, Name = "Tokuno Minor Artifacts"}; + cont = new Bag(); + cont.Hue = 0x501; + cont.Name = "Tokuno Minor Artifacts"; PlaceItemIn(cont, 42, 70, new Exiler()); PlaceItemIn(cont, 38, 53, new HanzosBow()); @@ -360,7 +398,8 @@ namespace Server.Misc if (Core.SE) //This bag came only after SE. { - cont = new Bag {Name = "Bag of Bows"}; + cont = new Bag(); + cont.Name = "Bag of Bows"; PlaceItemIn(cont, 31, 84, new Bow()); PlaceItemIn(cont, 78, 74, new CompositeBow()); @@ -393,7 +432,11 @@ namespace Server.Misc bank.DropItem(new BankCheck(1000000)); // Full spellbook - bank.DropItem(new Spellbook {Content = ulong.MaxValue}); + Spellbook book = new Spellbook(); + + book.Content = ulong.MaxValue; + + bank.DropItem(book); Bag bag = new Bag(); @@ -598,7 +641,10 @@ namespace Server.Misc newChar.Female = args.Female; //newChar.Body = newChar.Female ? 0x191 : 0x190; - newChar.Race = Core.Expansion >= args.Race.RequiredExpansion ? args.Race : Race.DefaultRace; + if (Core.Expansion >= args.Race.RequiredExpansion) + newChar.Race = args.Race; //Sets body + else + newChar.Race = Race.DefaultRace; //newChar.Hue = Utility.ClipSkinHue( args.Hue & 0x3FFF ) | 0x8000; newChar.Hue = newChar.Race.ClipSkinHue(args.Hue & 0x3FFF) | 0x8000; @@ -646,7 +692,12 @@ namespace Server.Misc if (TestCenter.Enabled) FillBankbox(newChar); - if (young) newChar.BankBox.DropItem(new NewPlayerTicket {Owner = newChar}); + if (young) + { + NewPlayerTicket ticket = new NewPlayerTicket(); + ticket.Owner = newChar; + newChar.BankBox.DropItem(ticket); + } CityInfo city = GetStartLocation(args, young); @@ -659,8 +710,19 @@ namespace Server.Misc new WelcomeTimer(newChar).Start(); } - public static bool VerifyProfession(int profession) => - profession >= 0 && (profession < 4 || Core.AOS && profession < 6 || Core.SE && profession < 8); + public static bool VerifyProfession(int profession) + { + if (profession < 0) + return false; + if (profession < 4) + return true; + if (Core.AOS && profession < 6) + return true; + if (Core.SE && profession < 8) + return true; + + return false; + } private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool isYoung) { @@ -692,7 +754,9 @@ namespace Server.Misc break; } case 5: //Paladin + { return m_NewHavenInfo; + } case 6: //Samurai { if ((flags & ClientFlags.Tokuno) != 0) @@ -731,7 +795,10 @@ namespace Server.Misc } } - return useHaven ? m_NewHavenInfo : args.City; + if (useHaven) + return m_NewHavenInfo; + + return args.City; } private static void FixStats(ref int str, ref int dex, ref int intel, int max) @@ -1097,7 +1164,7 @@ namespace Server.Misc if (m_Mobile?.EquipItem(item) == true) return; - Container pack = m_Mobile?.Backpack; + Container pack = m_Mobile.Backpack; if (!mustEquip && pack != null) pack.DropItem(item); @@ -1110,7 +1177,7 @@ namespace Server.Misc if (!Core.AOS) item.LootType = LootType.Newbied; - Container pack = m_Mobile?.Backpack; + Container pack = m_Mobile.Backpack; if (pack != null) pack.DropItem(item); @@ -1666,18 +1733,18 @@ namespace Server.Misc private class BadStartMessage : Timer { private int m_Message; - private Mobile m_From; + private Mobile m_Mobile; public BadStartMessage(Mobile m, int message) : base(TimeSpan.FromSeconds(3.5)) { - m_From = m; + m_Mobile = m; m_Message = message; Start(); } protected override void OnTick() { - m_From.SendLocalizedMessage(m_Message); + m_Mobile.SendLocalizedMessage(m_Message); } } } diff --git a/Projects/Scripts/Misc/Cleanup.cs b/Projects/Scripts/Misc/Cleanup.cs index 4b6f5f9f2..407f1d0a0 100644 --- a/Projects/Scripts/Misc/Cleanup.cs +++ b/Projects/Scripts/Misc/Cleanup.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Items; +using Server.Mobiles; using Server.Multis; namespace Server.Misc @@ -43,7 +43,9 @@ namespace Server.Misc if (relEntity.Entity is Item item1) validItems.Add(item1); - validItems.AddRange(house.VendorInventories.SelectMany(inventory => inventory.Items)); + foreach (VendorInventory inventory in house.VendorInventories) + foreach (Item subItem in inventory.Items) + validItems.Add(subItem); } else if (item is BankBox box) { diff --git a/Projects/Scripts/Misc/CurrentExpansion.cs b/Projects/Scripts/Misc/CurrentExpansion.cs index bde778496..3ff96d7ed 100644 --- a/Projects/Scripts/Misc/CurrentExpansion.cs +++ b/Projects/Scripts/Misc/CurrentExpansion.cs @@ -1,4 +1,4 @@ -using Server.Items; +using Server.Accounting; using Server.Network; namespace Server @@ -37,4 +37,4 @@ namespace Server } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/DoorGenerator.cs b/Projects/Scripts/Misc/DoorGenerator.cs index 2a1b3fe76..865160c48 100644 --- a/Projects/Scripts/Misc/DoorGenerator.cs +++ b/Projects/Scripts/Misc/DoorGenerator.cs @@ -390,7 +390,7 @@ namespace Server public static bool IsFrame(int id, int[] list) { - if (id > list[^1]) + if (id > list[list.Length - 1]) return false; for (int i = 0; i < list.Length; ++i) diff --git a/Projects/Scripts/Misc/Email.cs b/Projects/Scripts/Misc/Email.cs index 750515f03..43d1d99c9 100644 --- a/Projects/Scripts/Misc/Email.cs +++ b/Projects/Scripts/Misc/Email.cs @@ -6,17 +6,17 @@ using System.Threading; namespace Server.Misc { - public static class Email + public class Email { /* In order to support emailing, fill in EmailServer and FromAddress: * Example: * public static readonly string EmailServer = "mail.domain.com"; * public static readonly string FromAddress = "runuo@domain.com"; - * + * * If you want to add crash reporting emailing, fill in CrashAddresses: * Example: * public static readonly string CrashAddresses = "first@email.here,second@email.here,third@email.here"; - * + * * If you want to add speech log page emailing, fill in SpeechLogPageAddresses: * Example: * public static readonly string SpeechLogPageAddresses = "first@email.here,second@email.here,third@email.here"; @@ -62,7 +62,7 @@ namespace Server.Misc // .NET relies on the MTA to generate Message-ID header. Not all MTAs will add this header. DateTime now = DateTime.UtcNow; - string messageID = $"<{now:yyyyMMdd}.{now:HHmmssff}@{EmailServer}>"; + string messageID = $"<{now.ToString("yyyyMMdd")}.{now.ToString("HHmmssff")}@{EmailServer}>"; message.Headers.Add("Message-ID", messageID); message.Headers.Add("X-Mailer", "RunUO"); @@ -89,8 +89,10 @@ namespace Server.Misc { MailMessage message = (MailMessage)state; - Console.WriteLine(Send(message) ? "Sent e-mail '{0}' to '{1}'." : "Failure sending e-mail '{0}' to '{1}'.", - message.Subject, message.To); + if (Send(message)) + Console.WriteLine("Sent e-mail '{0}' to '{1}'.", message.Subject, message.To); + else + Console.WriteLine("Failure sending e-mail '{0}' to '{1}'.", message.Subject, message.To); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/Fastwalk.cs b/Projects/Scripts/Misc/Fastwalk.cs index a9861974c..232986b7a 100644 --- a/Projects/Scripts/Misc/Fastwalk.cs +++ b/Projects/Scripts/Misc/Fastwalk.cs @@ -4,7 +4,7 @@ namespace Server.Misc { // This fastwalk detection is no longer required // As of B36 PlayerMobile implements movement packet throttling which more reliably controls movement speeds - public static class Fastwalk + public class Fastwalk { private static int MaxSteps = 4; // Maximum number of queued steps until fastwalk is detected private static bool Enabled = false; // Is fastwalk detection enabled? @@ -30,4 +30,4 @@ namespace Server.Misc Console.WriteLine("Client: {0}: Fast movement detected (name={1})", e.NetState, e.NetState.Mobile.Name); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/Geometry.cs b/Projects/Scripts/Misc/Geometry.cs index 639d76896..ff3fccdde 100644 --- a/Projects/Scripts/Misc/Geometry.cs +++ b/Projects/Scripts/Misc/Geometry.cs @@ -19,19 +19,26 @@ namespace Server.Misc public static Point2D ArcPoint(Point3D loc, int radius, int angle) { + int sideA, sideB; + if (angle < 0) angle = 0; if (angle > 90) angle = 90; - int sideA = (int)Math.Round(radius * Math.Sin(DegreesToRadians(angle))); - int sideB = (int)Math.Round(radius * Math.Cos(DegreesToRadians(angle))); + sideA = (int)Math.Round(radius * Math.Sin(DegreesToRadians(angle))); + sideB = (int)Math.Round(radius * Math.Cos(DegreesToRadians(angle))); return new Point2D(loc.X - sideB, loc.Y - sideA); } - public static void Circle2D(Point3D loc, Map map, int radius, DoEffect_Callback effect, int angleStart = 0, int angleEnd = 360) + public static void Circle2D(Point3D loc, Map map, int radius, DoEffect_Callback effect) + { + Circle2D(loc, map, radius, effect, 0, 360); + } + + public static void Circle2D(Point3D loc, Map map, int radius, DoEffect_Callback effect, int angleStart, int angleEnd) { if (angleStart < 0 || angleStart > 360) angleStart = 0; @@ -140,9 +147,13 @@ namespace Server.Misc withinBounds = false; } else if (pointQuadrant == start.Quadrant && (x < startX || y > startY)) + { withinBounds = false; + } else if (pointQuadrant == end.Quadrant && (x > endX || y < endY)) + { withinBounds = false; + } return opposite ? !withinBounds : withinBounds; } @@ -207,4 +218,4 @@ namespace Server.Misc public int Quadrant{ get; } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs b/Projects/Scripts/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs index e56ff99e9..1c6a17a03 100644 --- a/Projects/Scripts/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs +++ b/Projects/Scripts/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs @@ -129,7 +129,9 @@ namespace Server.Items Effects.SendMovingEffect(from, targ, 0x36E4, 7, 0, false, true, 0x47F); } else + { from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying. + } } else { @@ -138,9 +140,11 @@ namespace Server.Items } } else + { from.SendLocalizedMessage( 1005577); // You can only throw a snowball at something that can throw one back. + } } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/Guild.cs b/Projects/Scripts/Misc/Guild.cs index 8b70338c6..9f6f2ec8c 100644 --- a/Projects/Scripts/Misc/Guild.cs +++ b/Projects/Scripts/Misc/Guild.cs @@ -32,7 +32,7 @@ namespace Server.Guilds public class RankDefinition { - public static readonly RankDefinition[] Ranks = + public static RankDefinition[] Ranks = { new RankDefinition(1062963, 0, RankFlags.None), //Ronin new RankDefinition(1062962, 1, RankFlags.Member), //Member @@ -78,8 +78,8 @@ namespace Server.Guilds public class AllianceInfo { private Guild m_Leader; - private readonly List m_Members; - private readonly List m_PendingMembers; + private List m_Members; + private List m_PendingMembers; public AllianceInfo(Guild leader, string name, Guild partner) { @@ -154,9 +154,21 @@ namespace Server.Guilds } } - public bool IsPendingMember(Guild g) => g.Alliance == this && m_PendingMembers.Contains(g); + public bool IsPendingMember(Guild g) + { + if (g.Alliance != this) + return false; - public bool IsMember(Guild g) => g.Alliance == this && m_Members.Contains(g); + return m_PendingMembers.Contains(g); + } + + public bool IsMember(Guild g) + { + if (g.Alliance != this) + return false; + + return m_Members.Contains(g); + } public void Serialize(GenericWriter writer) { @@ -320,18 +332,29 @@ namespace Server.Guilds public void AllianceChat(Mobile from, int hue, string text) { + Packet p = null; for (int i = 0; i < m_Members.Count; i++) { Guild g = m_Members[i]; for (int j = 0; j < g.Members.Count; j++) { - NetState ns = g.Members[j].NetState; + Mobile m = g.Members[j]; - if (ns != null) - Packets.SendUnicodeMessage(ns, from.Serial, from.Body, MessageType.Alliance, hue, 3, from.Language, from.Name, text); + NetState state = m.NetState; + + if (state != null) + { + if (p == null) + p = Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Alliance, hue, 3, + from.Language, from.Name, text)); + + state.Send(p); + } } } + + Packet.Release(p); } public void AllianceChat(Mobile from, string text) @@ -660,7 +683,9 @@ namespace Server.Guilds Mobile from = e.Mobile; if (arg.Length == 0) + { e.Mobile.Target = new GuildPropsTarget(); + } else { Guild g = uint.TryParse(arg, out uint id) @@ -695,7 +720,7 @@ namespace Server.Guilds if (o is Guildstone stone) { - if (stone.Guild.Disbanded) + if (stone?.Guild.Disbanded != false) { from.SendMessage("The guild associated with that Guildstone no longer exists"); return; @@ -704,7 +729,9 @@ namespace Server.Guilds g = stone.Guild; } else if (o is Mobile mobile) + { g = mobile.Guild as Guild; + } if (g == null) { @@ -746,7 +773,13 @@ namespace Server.Guilds public AllianceInfo Alliance { - get => m_AllianceInfo ?? m_AllianceLeader?.m_AllianceInfo; + get + { + if (m_AllianceInfo != null) + return m_AllianceInfo; + + return m_AllianceLeader?.m_AllianceInfo; + } set { AllianceInfo current = Alliance; @@ -789,7 +822,10 @@ namespace Server.Guilds { AllianceInfo alliance = g.Alliance; - return alliance?.Leader != null && alliance.IsMember(g) ? alliance.Leader : g; + if (alliance?.Leader != null && alliance.IsMember(g)) + return alliance.Leader; + + return g; } #endregion @@ -801,9 +837,31 @@ namespace Server.Guilds public List AcceptedWars{ get; private set; } - public WarDeclaration FindPendingWar(Guild g) => PendingWars.FirstOrDefault(w => w.Opponent == g); + public WarDeclaration FindPendingWar(Guild g) + { + for (int i = 0; i < PendingWars.Count; i++) + { + WarDeclaration w = PendingWars[i]; - public WarDeclaration FindActiveWar(Guild g) => AcceptedWars.FirstOrDefault(w => w.Opponent == g); + if (w.Opponent == g) + return w; + } + + return null; + } + + public WarDeclaration FindActiveWar(Guild g) + { + for (int i = 0; i < AcceptedWars.Count; i++) + { + WarDeclaration w = AcceptedWars[i]; + + if (w.Opponent == g) + return w; + } + + return null; + } public void CheckExpiredWars() { @@ -878,7 +936,8 @@ namespace Server.Guilds if (!NewGuildSystem) return; - killer ??= victim.FindMostRecentDamager(false); + if (killer == null) + killer = victim.FindMostRecentDamager(false); if (killer == null || victim.Guild == null || killer.Guild == null) return; @@ -1089,10 +1148,24 @@ namespace Server.Guilds } } - AllyDeclarations ??= new List(); - AllyInvitations ??= new List(); - AcceptedWars ??= new List(); - PendingWars ??= new List(); + if (AllyDeclarations == null) + AllyDeclarations = new List(); + + if (AllyInvitations == null) + AllyInvitations = new List(); + + + if (AcceptedWars == null) + AcceptedWars = new List(); + + if (PendingWars == null) + PendingWars = new List(); + + + /* + if ( ( !NewGuildSystem && m_Guildstone == null )|| m_Members.Count == 0 ) + Disband(); + */ Timer.DelayCall(TimeSpan.Zero, VerifyGuild_Callback); } @@ -1261,14 +1334,24 @@ namespace Server.Guilds public void GuildChat(Mobile from, int hue, string text) { + Packet p = null; for (int i = 0; i < Members.Count; i++) { - NetState ns = Members[i].NetState; + Mobile m = Members[i]; - if (ns != null) - Packets.SendUnicodeMessage(ns, from.Serial, from.Body, MessageType.Guild, hue, 3, - from.Language, from.Name, text); + NetState state = m.NetState; + + if (state != null) + { + if (p == null) + p = Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Guild, hue, 3, + from.Language, from.Name, text)); + + state.Send(p); + } } + + Packet.Release(p); } public void GuildChat(Mobile from, string text) @@ -1319,12 +1402,17 @@ namespace Server.Guilds Mobile winner = null; int highVotes = 0; - foreach ((Mobile m, int val) in votes) + foreach (KeyValuePair kvp in votes) + { + Mobile m = kvp.Key; + int val = kvp.Value; + if (winner == null || val > highVotes) { winner = m; highVotes = val; } + } if (NewGuildSystem && highVotes * 100 / Math.Max(votingMembers, 1) < MajorityPercentage && !Disbanded && winner != m_Leader && m_Leader.Guild == this) diff --git a/Projects/Scripts/Misc/Keywords.cs b/Projects/Scripts/Misc/Keywords.cs index 71e04ffc4..6c4ac05e6 100644 --- a/Projects/Scripts/Misc/Keywords.cs +++ b/Projects/Scripts/Misc/Keywords.cs @@ -4,7 +4,7 @@ using Server.Mobiles; namespace Server.Misc { - public static class Keywords + public class Keywords { public static void Initialize() { @@ -51,4 +51,4 @@ namespace Server.Misc } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/LanguageStatistics.cs b/Projects/Scripts/Misc/LanguageStatistics.cs index 9a4ce9402..f5cac3106 100644 --- a/Projects/Scripts/Misc/LanguageStatistics.cs +++ b/Projects/Scripts/Misc/LanguageStatistics.cs @@ -20,7 +20,7 @@ namespace Server.Misc * enable showing of unicode control chars **/ - public static class LanguageStatistics + public class LanguageStatistics { private static InternationalCode[] InternationalCodes = { @@ -317,10 +317,13 @@ namespace Server.Misc public int Compare(InternationalCodeCounter x, InternationalCodeCounter y) { - string a = x?.Code; - int ca = x?.Count ?? 0; - string b = y?.Code; - int cb = y?.Count ?? 0; + string a = null, b = null; + int ca = 0, cb = 0; + + a = x.Code; + ca = x.Count; + b = y.Code; + cb = y.Count; if (ca > cb) diff --git a/Projects/Scripts/Misc/LightCycle.cs b/Projects/Scripts/Misc/LightCycle.cs index 14c7b0204..90155d0fa 100644 --- a/Projects/Scripts/Misc/LightCycle.cs +++ b/Projects/Scripts/Misc/LightCycle.cs @@ -4,7 +4,7 @@ using Server.Network; namespace Server { - public static class LightCycle + public class LightCycle { public const int DayLevel = 0; public const int NightLevel = 12; @@ -69,12 +69,12 @@ namespace Server Clock.GetTime(from.Map, from.X, from.Y, out int hours, out int minutes); /* OSI times: - * + * * Midnight -> 3:59 AM : Night * 4:00 AM -> 11:59 PM : Day - * + * * RunUO times: - * + * * 10:00 PM -> 11:59 PM : Scale to night * Midnight -> 3:59 AM : Night * 4:00 AM -> 5:59 AM : Scale to day @@ -124,10 +124,10 @@ namespace Server protected override void OnTick() { - m_Owner.EndAction(); + m_Owner.EndAction(); m_Owner.LightLevel = 0; BuffInfo.RemoveBuff(m_Owner, BuffIcon.NightSight); } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/LoginStats.cs b/Projects/Scripts/Misc/LoginStats.cs index 54a2fd3de..69985c921 100644 --- a/Projects/Scripts/Misc/LoginStats.cs +++ b/Projects/Scripts/Misc/LoginStats.cs @@ -2,7 +2,7 @@ using Server.Network; namespace Server.Misc { - public static class LoginStats + public class LoginStats { public static void Initialize() { @@ -27,4 +27,4 @@ namespace Server.Misc mobileCount, mobileCount == 1 ? "" : "s"); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/MapDefinitions.cs b/Projects/Scripts/Misc/MapDefinitions.cs index 19d8a1006..f0558527a 100644 --- a/Projects/Scripts/Misc/MapDefinitions.cs +++ b/Projects/Scripts/Misc/MapDefinitions.cs @@ -1,16 +1,17 @@ namespace Server.Misc { - public static class MapDefinitions + public class MapDefinitions { public static void Configure() { /* Here we configure all maps. Some notes: - * + * * 1) The first 32 maps are reserved for core use. * 2) Map 0x7F is reserved for core use. * 3) Map 0xFF is reserved for core use. * 4) Changing or removing any predefined maps may cause server instability. */ + RegisterMap(0, 0, 0, 7168, 4096, 4, "Felucca", MapRules.FeluccaRules); RegisterMap(1, 1, 1, 7168, 4096, 0, "Trammel", MapRules.TrammelRules); RegisterMap(2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.TrammelRules); @@ -22,7 +23,7 @@ namespace Server.Misc /* Example of registering a custom map: * RegisterMap( 32, 0, 0, 6144, 4096, 3, "Iceland", MapRules.FeluccaRules ); - * + * * Defined: * RegisterMap( , , , , , , , ); * - : An unreserved unique index for this map @@ -39,7 +40,7 @@ namespace Server.Misc MultiComponentList.PostHSFormat = true; // OSI Client Patch 7.0.9.0 } - public static void RegisterMap(int mapIndex, int mapID, int fileIndex, int width, int height, byte season, + public static void RegisterMap(int mapIndex, int mapID, int fileIndex, int width, int height, int season, string name, MapRules rules) { Map newMap = new Map(mapID, mapIndex, fileIndex, width, height, season, name, rules); @@ -48,4 +49,4 @@ namespace Server.Misc Map.AllMaps.Add(newMap); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/MapUO.cs b/Projects/Scripts/Misc/MapUO.cs index 5ed36e88d..7263c6530 100644 --- a/Projects/Scripts/Misc/MapUO.cs +++ b/Projects/Scripts/Misc/MapUO.cs @@ -1,5 +1,4 @@ using System; -using Server.Buffers; using Server.Engines.PartySystem; using Server.Guilds; using Server.Network; @@ -19,12 +18,35 @@ namespace Server.Misc private static void OnPartyTrack(NetState state, PacketReader pvSrc) { - MapUOPackets.SendPartyTrack(state, Party.Get(state.Mobile)); + Mobile from = state.Mobile; + Party party = Party.Get(from); + + if (party != null) + { + Packets.PartyTrack packet = new Packets.PartyTrack(from, party); + + if (packet.UnderlyingStream.Length > 8) + state.Send(packet); + } } private static void OnGuildTrack(NetState state, PacketReader pvSrc) { - MapUOPackets.SendGuildTrack(state, state.Mobile.Guild as Guild, pvSrc.ReadBoolean()); + Mobile from = state.Mobile; + + if (from.Guild is Guild guild) + { + bool locations = pvSrc.ReadByte() != 0; + + Packets.GuildTrack packet = new Packets.GuildTrack(from, guild, locations); + + if (packet.UnderlyingStream.Length > (locations ? 9 : 5)) + state.Send(packet); + } + else + { + state.Send(new Packets.GuildTrack()); + } } private static class Settings @@ -34,97 +56,75 @@ namespace Server.Misc public const bool GuildHitsPercent = true; } - private static class MapUOPackets + private static class Packets { - public static void SendPartyTrack(NetState ns, Party party) + public sealed class PartyTrack : ProtocolExtension { - Mobile from = ns.Mobile; - int count = party?.Members.Count ?? 0; - if (count < 2) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[Math.Max(count - 1, 0) * 9 + 8]); - writer.Write((byte)0xF0); // Packet ID - writer.Position += 2; // Dynamic Length - - writer.Write((byte)0x01); // Command - - count = 0; - for (int i = 0; i < count; ++i) + public PartyTrack(Mobile from, Party party) : base(0x01, (party.Members.Count - 1) * 9 + 4) { - Mobile mob = party.Members[i]?.Mobile; // if count is greater than 0, then party is not null + for (int i = 0; i < party.Members.Count; ++i) + { + PartyMemberInfo pmi = party.Members[i]; - if (mob == from || mob?.NetState == null || Utility.InUpdateRange(from, mob) && from.CanSee(mob)) - continue; + if (pmi == null || pmi.Mobile == from) + continue; - count++; - writer.Write(mob.Serial); - writer.Write((short)mob.X); - writer.Write((short)mob.Y); - writer.Write((byte)(mob.Map?.MapID ?? 0)); + Mobile mob = pmi.Mobile; + + if (Utility.InUpdateRange(from, mob) && from.CanSee(mob)) + continue; + + m_Stream.Write(mob.Serial); + m_Stream.Write((short)mob.X); + m_Stream.Write((short)mob.Y); + m_Stream.Write((byte)(mob.Map?.MapID ?? 0)); + } + + m_Stream.Write(0); } - - if (count == 0) - return; - - writer.Position += 4; // Empty Serial - writer.Position = 1; - writer.Write((ushort)writer.WrittenCount); - - ns.Send(writer.Span); } - public static void SendGuildTrack(NetState ns, Guild guild = null, bool locations = false) + public sealed class GuildTrack : ProtocolExtension { - Mobile from = ns.Mobile; - - int count = guild?.Members.Count ?? 0; - - if (count < 2) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[Math.Max(count - 1, 0) * (locations ? 10 : 4) + 9]); - writer.Write((byte)0xF0); // Packet ID - writer.Position += 2; // Dynamic Length - - writer.Write((byte)0x02); // Command - - writer.Write(locations); - - count = 0; - for (int i = 0; i < count; ++i) + public GuildTrack() : base(0x02, 5) { - Mobile mob = guild.Members[i]; // If guild count is above 0, then guild is not null. - - if (mob == from || mob?.NetState == null || locations && Utility.InUpdateRange(from, mob) && from.CanSee(mob)) - continue; - - count++; - writer.Write(mob.Serial); - - if (locations) - { - writer.Write((short)mob.X); - writer.Write((short)mob.Y); - writer.Write((byte)(mob.Map?.MapID ?? 0)); - - if (Settings.GuildHitsPercent && mob.Alive) - writer.Write((byte)(mob.Hits / Math.Max(mob.HitsMax, 1.0) * 100)); - else - writer.Position++; // writer.Write((byte)0); - } + m_Stream.Write((byte)0); + m_Stream.Write(0); } - if (count == 0) - return; + public GuildTrack(Mobile from, Guild guild, bool locations) : base(0x02, + (guild.Members.Count - 1) * (locations ? 10 : 4) + 5) + { + m_Stream.Write((byte)(locations ? 1 : 0)); - writer.Position += 4; // Empty Serial + for (int i = 0; i < guild.Members.Count; ++i) + { + Mobile mob = guild.Members[i]; - writer.Position = 1; - writer.Write((ushort)writer.WrittenCount); + if (mob == null || mob == from || mob.NetState == null) + continue; - ns.Send(writer.Span); + if (locations && Utility.InUpdateRange(from, mob) && from.CanSee(mob)) + continue; + + m_Stream.Write(mob.Serial); + + if (locations) + { + m_Stream.Write((short)mob.X); + m_Stream.Write((short)mob.Y); + m_Stream.Write((byte)(mob.Map?.MapID ?? 0)); + + if (Settings.GuildHitsPercent && mob.Alive) + m_Stream.Write((byte)(mob.Hits / Math.Max(mob.HitsMax, 1.0) * 100)); + else + m_Stream.Write((byte)0); + } + } + + m_Stream.Write(0); + } } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/NameList.cs b/Projects/Scripts/Misc/NameList.cs index 95c8e89a0..36ba6a249 100644 --- a/Projects/Scripts/Misc/NameList.cs +++ b/Projects/Scripts/Misc/NameList.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Xml; namespace Server diff --git a/Projects/Scripts/Misc/NameVerification.cs b/Projects/Scripts/Misc/NameVerification.cs index 250b56913..44ef8f68e 100644 --- a/Projects/Scripts/Misc/NameVerification.cs +++ b/Projects/Scripts/Misc/NameVerification.cs @@ -1,6 +1,6 @@ namespace Server.Misc { - public static class NameVerification + public class NameVerification { public static readonly char[] SpaceDashPeriodQuote = { @@ -148,9 +148,20 @@ namespace Server.Misc exceptCount = 0; } - else if (exceptCount++ == maxExceptions || exceptions.All(exception => exception != c) || - i == 0 && noExceptionsAtStart) - return false; + else + { + bool except = false; + + for (int j = 0; !except && j < exceptions.Length; ++j) + if (c == exceptions[j]) + except = true; + + if (!except || i == 0 && noExceptionsAtStart) + return false; + + if (exceptCount++ == maxExceptions) + return false; + } } for (int i = 0; i < disallowed.Length; ++i) @@ -177,7 +188,11 @@ namespace Server.Misc return false; } - return startDisallowed.All(t => !name.StartsWith(t)); + for (int i = 0; i < startDisallowed.Length; ++i) + if (name.StartsWith(startDisallowed[i])) + return false; + + return true; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/Notoriety.cs b/Projects/Scripts/Misc/Notoriety.cs index 7b528858d..ea42bc887 100644 --- a/Projects/Scripts/Misc/Notoriety.cs +++ b/Projects/Scripts/Misc/Notoriety.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Engines.ConPVP; using Server.Engines.PartySystem; using Server.Factions; @@ -13,7 +12,7 @@ using Server.Spells.Seventh; namespace Server.Misc { - public static class NotorietyHandlers + public class NotorietyHandlers { public static void Initialize() { @@ -307,7 +306,7 @@ namespace Server.Misc } /* Must be thread-safe */ - public static byte MobileNotoriety(Mobile source, Mobile target) + public static int MobileNotoriety(Mobile source, Mobile target) { BaseCreature bcTarg = target as BaseCreature; @@ -430,12 +429,27 @@ namespace Server.Misc public static bool IsSummoned(BaseCreature c) => c?.Summoned == true; - public static bool IsSummoned(BaseCreature c) => c?.Summoned == true; + public static bool CheckAggressor(List list, Mobile target) + { + for (int i = 0; i < list.Count; ++i) + if (list[i].Attacker == target) + return true; - public static bool CheckAggressor(IEnumerable list, Mobile target) => list.Any(t => t.Attacker == target); + return false; + } - public static bool CheckAggressed(IEnumerable list, Mobile target) => - list.Any(info => !info.CriminalAggression && info.Defender == target); + public static bool CheckAggressed(List list, Mobile target) + { + for (int i = 0; i < list.Count; ++i) + { + AggressorInfo info = list[i]; + + if (!info.CriminalAggression && info.Defender == target) + return true; + } + + return false; + } private enum GuildStatus { diff --git a/Projects/Scripts/Misc/Paperdoll.cs b/Projects/Scripts/Misc/Paperdoll.cs index 8ad46e846..4ba425c74 100644 --- a/Projects/Scripts/Misc/Paperdoll.cs +++ b/Projects/Scripts/Misc/Paperdoll.cs @@ -3,7 +3,7 @@ using Server.Network; namespace Server.Misc { - public static class Paperdoll + public class Paperdoll { public static void Initialize() { @@ -13,22 +13,21 @@ namespace Server.Misc public static void EventSink_PaperdollRequest(PaperdollRequestEventArgs e) { Mobile beholder = e.Beholder; - NetState ns = beholder.NetState; Mobile beheld = e.Beheld; - Packets.SendDisplayPaperdoll(ns, beholder, Titles.ComputeTitle(beholder, beheld), - beheld.AllowEquipFrom(beholder)); + beholder.Send(new DisplayPaperdoll(beheld, Titles.ComputeTitle(beholder, beheld), + beheld.AllowEquipFrom(beholder))); if (ObjectPropertyList.Enabled) { List items = beheld.Items; for (int i = 0; i < items.Count; ++i) - items[i].PropertyList.SendOPLInfo(ns); + beholder.Send(items[i].OPLPacket); // NOTE: OSI sends MobileUpdate when opening your own paperdoll. // It has a very bad rubber-banding affect. What positive affects does it have? } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/ProfanityProtection.cs b/Projects/Scripts/Misc/ProfanityProtection.cs index 0f6ebb23e..514589214 100644 --- a/Projects/Scripts/Misc/ProfanityProtection.cs +++ b/Projects/Scripts/Misc/ProfanityProtection.cs @@ -99,7 +99,10 @@ namespace Server.Misc return false; } default: + case ProfanityAction.Other: // TODO: Provide custom implementation if this is chosen + { return true; + } } } @@ -115,4 +118,4 @@ namespace Server.Misc e.Blocked = !OnProfanityDetected(from, e.Speech); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/Profile.cs b/Projects/Scripts/Misc/Profile.cs index c87afd5eb..98731f549 100644 --- a/Projects/Scripts/Misc/Profile.cs +++ b/Projects/Scripts/Misc/Profile.cs @@ -4,7 +4,7 @@ using Server.Network; namespace Server.Misc { - public static class Profile + public class Profile { public static void Initialize() { @@ -48,9 +48,12 @@ namespace Server.Misc if (footer.Length == 0 && beholder == beheld) footer = GetAccountDuration(beheld); - string body = beheld.Profile ?? ""; + string body = beheld.Profile; - Packets.SendDisplayProfile(beholder.NetState, beholder != beheld || !beheld.ProfileLocked ? beheld.Serial : Serial.Zero, header, body, footer); + if (body == null || body.Length <= 0) + body = ""; + + beholder.Send(new DisplayProfile(beholder != beheld || !beheld.ProfileLocked, beheld, header, body, footer)); } private static string GetAccountDuration(Mobile m) @@ -69,7 +72,10 @@ namespace Server.Misc if (Format(ts.TotalMinutes, "This account is {0} minute{1} old.", out v)) return v; - return Format(ts.TotalSeconds, "This account is {0} second{1} old.", out v) ? v : ""; + if (Format(ts.TotalSeconds, "This account is {0} second{1} old.", out v)) + return v; + + return ""; } public static bool Format(double value, string format, out string op) @@ -84,4 +90,4 @@ namespace Server.Misc return false; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/ProtocolExtensions.cs b/Projects/Scripts/Misc/ProtocolExtensions.cs index 6b3e3290e..5aeee0a96 100644 --- a/Projects/Scripts/Misc/ProtocolExtensions.cs +++ b/Projects/Scripts/Misc/ProtocolExtensions.cs @@ -3,9 +3,9 @@ using Server.Network; namespace Server.Misc { - public static class ProtocolExtensions + public class ProtocolExtensions { - private static readonly PacketHandler[] m_Handlers = new PacketHandler[0x100]; + private static PacketHandler[] m_Handlers = new PacketHandler[0x100]; public static void Initialize() { @@ -17,34 +17,48 @@ namespace Server.Misc m_Handlers[packetID] = new PacketHandler(packetID, 0, ingame, onReceive); } - public static PacketHandler GetHandler(int packetID) => packetID >= 0 && packetID < m_Handlers.Length ? m_Handlers[packetID] : null; + public static PacketHandler GetHandler(int packetID) + { + if (packetID >= 0 && packetID < m_Handlers.Length) + return m_Handlers[packetID]; + + return null; + } public static void DecodeBundledPacket(NetState state, PacketReader pvSrc) { int packetID = pvSrc.ReadByte(); PacketHandler ph = GetHandler(packetID); - if (ph == null) - return; - if (ph.Ingame) + if (ph != null) { - if (state.Mobile == null) + if (ph.Ingame && state.Mobile == null) { Console.WriteLine( - "Client: {0}: Sent ingame packet (0xF0x{1:X2}) before having been attached to a mobile", state, packetID); + "Client: {0}: Sent ingame packet (0xF0x{1:X2}) before having been attached to a mobile", state, + packetID); state.Dispose(); - return; } - - if (state.Mobile.Deleted) + else if (ph.Ingame && state.Mobile.Deleted) { state.Dispose(); - return; + } + else + { + ph.OnReceive(state, pvSrc); } } - - ph.OnReceive(state, pvSrc); } } -} + + public abstract class ProtocolExtension : Packet + { + public ProtocolExtension(int packetID, int capacity) : base(0xF0) + { + EnsureCapacity(4 + capacity); + + m_Stream.Write((byte)packetID); + } + } +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/RaceDefinitions.cs b/Projects/Scripts/Misc/RaceDefinitions.cs index 7f3c4aaa6..eb9720308 100644 --- a/Projects/Scripts/Misc/RaceDefinitions.cs +++ b/Projects/Scripts/Misc/RaceDefinitions.cs @@ -1,5 +1,3 @@ -using System.Linq; - namespace Server.Misc { public class RaceDefinitions @@ -32,9 +30,22 @@ namespace Server.Misc { } - public override bool ValidateHair(bool female, int itemID) => - itemID == 0 || (!female || itemID != 0x2048) && (female || itemID != 0x2046) && - (itemID >= 0x203B && itemID <= 0x203D || itemID >= 0x2044 && itemID <= 0x204A); + public override bool ValidateHair(bool female, int itemID) + { + if (itemID == 0) + return true; + + if (female && itemID == 0x2048 || !female && itemID == 0x2046) + return false; //Buns & Receding Hair + + if (itemID >= 0x203B && itemID <= 0x203D) + return true; + + if (itemID >= 0x2044 && itemID <= 0x204A) + return true; + + return false; + } public override int RandomHair(bool female) //Random hair doesn't include baldness { @@ -79,18 +90,32 @@ namespace Server.Misc return (rand < 4 ? 0x203E : 0x2047) + rand; } - public override int ClipSkinHue(int hue) => hue < 1002 ? 1002 : hue > 1058 ? 1058 : hue; + public override int ClipSkinHue(int hue) + { + if (hue < 1002) + return 1002; + if (hue > 1058) + return 1058; + return hue; + } public override int RandomSkinHue() => Utility.Random(1002, 57) | 0x8000; - public override int ClipHairHue(int hue) => hue < 1102 ? 1102 : hue > 1149 ? 1149 : hue; + public override int ClipHairHue(int hue) + { + if (hue < 1102) + return 1102; + if (hue > 1149) + return 1149; + return hue; + } public override int RandomHairHue() => Utility.Random(1102, 48); } private class Elf : Race { - private static readonly int[] m_SkinHues = + private static int[] m_SkinHues = { 0x0BF, 0x24D, 0x24E, 0x24F, 0x353, 0x361, 0x367, 0x374, 0x375, 0x376, 0x381, 0x382, 0x383, 0x384, 0x385, 0x389, @@ -98,7 +123,7 @@ namespace Server.Misc 0x51D, 0x53F, 0x579, 0x76B, 0x76C, 0x76D, 0x835, 0x903 }; - private static readonly int[] m_HairHues = + private static int[] m_HairHues = { 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x058, 0x08E, 0x08F, 0x090, 0x091, 0x092, 0x101, 0x159, 0x15A, 0x15B, @@ -114,10 +139,10 @@ namespace Server.Misc { } - public override bool ValidateHair(bool female, int itemID) => - itemID == 0 || (!female || itemID != 0x2FCD && itemID != 0x2FBF) && - (female || itemID != 0x2FCC && itemID != 0x2FD0) && - (itemID >= 0x2FBF && itemID <= 0x2FC2 || itemID >= 0x2FCC && itemID <= 0x2FD1); + public override bool ValidateHair(bool female, int itemID) + { + if (itemID == 0) + return true; if (female && (itemID == 0x2FCD || itemID == 0x2FBF) || !female && (itemID == 0x2FCC || itemID == 0x2FD0)) return false; @@ -161,9 +186,14 @@ namespace Server.Misc public override int RandomSkinHue() => m_SkinHues[Utility.Random(m_SkinHues.Length)] | 0x8000; - public override int RandomSkinHue() => m_SkinHues[Utility.Random(m_SkinHues.Length)] | 0x8000; + public override int ClipHairHue(int hue) + { + for (int i = 0; i < m_HairHues.Length; i++) + if (m_HairHues[i] == hue) + return hue; - public override int ClipHairHue(int hue) => m_HairHues.Any(t => t == hue) ? hue : m_HairHues[0]; + return m_HairHues[0]; + } public override int RandomHairHue() => m_HairHues[Utility.Random(m_HairHues.Length)]; } @@ -195,11 +225,13 @@ namespace Server.Misc { } - public override bool ValidateHair(bool female, int itemID) => - female == false - ? itemID >= 0x4258 && itemID <= 0x425F - : itemID == 0x4261 || itemID == 0x4262 || itemID >= 0x4273 && itemID <= 0x4275 || itemID == 0x42B0 || - itemID == 0x42B1 || itemID == 0x42AA || itemID == 0x42AB; + public override bool ValidateHair(bool female, int itemID) + { + if (female == false) return itemID >= 0x4258 && itemID <= 0x425F; + + return itemID == 0x4261 || itemID == 0x4262 || itemID >= 0x4273 && itemID <= 0x4275 || itemID == 0x42B0 || + itemID == 0x42B1 || itemID == 0x42AA || itemID == 0x42AB; + } public override int RandomHair(bool female) { @@ -230,9 +262,14 @@ namespace Server.Misc public override int RandomSkinHue() => m_BodyHues[Utility.Random(m_BodyHues.Length)] | 0x8000; - public override int RandomSkinHue() => m_BodyHues[Utility.Random(m_BodyHues.Length)] | 0x8000; + public override int ClipHairHue(int hue) + { + for (int i = 0; i < m_HornHues.Length; i++) + if (m_HornHues[i] == hue) + return hue; - public override int ClipHairHue(int hue) => m_HornHues.Any(t => t == hue) ? hue : m_HornHues[0]; + return m_HornHues[0]; + } public override int RandomHairHue() => m_HornHues[Utility.Random(m_HornHues.Length)]; } diff --git a/Projects/Scripts/Misc/ServerList.cs b/Projects/Scripts/Misc/ServerList.cs index 885d3f8fb..469fc8d84 100644 --- a/Projects/Scripts/Misc/ServerList.cs +++ b/Projects/Scripts/Misc/ServerList.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; @@ -10,18 +9,18 @@ namespace Server.Misc { public class ServerList { - /* + /* * The default setting for Address, a value of 'null', will use your local IP address. If all of your local IP addresses * are private network addresses and AutoDetect is 'true' then RunUO will attempt to discover your public IP address * for you automatically. * * If you do not plan on allowing clients outside of your LAN to connect, you can set AutoDetect to 'false' and leave * Address set to 'null'. - * + * * If your public IP address cannot be determined, you must change the value of Address to your public IP address * manually to allow clients outside of your LAN to connect to your server. Address can be either an IP address or * a hostname that will be resolved when RunUO starts. - * + * * If you want players outside your LAN to be able to connect to your server and you are behind a router, you must also * forward TCP port 2593 to your private IP address. The procedure for doing this varies by manufacturer but generally * involves configuration of the router through your web browser. @@ -33,7 +32,7 @@ namespace Server.Misc * properly and fully supports listening on multiple ports. If a client with a public IP address is connecting to a * locally private address, the server will direct the client to either the AutoDetected IP address or the manually entered * IP address or hostname, whichever is applicable. Loopback clients will be directed to loopback. - * + * * If you would like to listen on additional ports (i.e. 22, 23, 80, for clients behind highly restrictive egress * firewalls) or specific IP adddresses you can do so by modifying the file SocketOptions.cs found in this directory. */ @@ -112,7 +111,7 @@ namespace Server.Misc IPHostEntry iphe = Dns.GetHostEntry(addr); if (iphe.AddressList.Length > 0) - outValue = iphe.AddressList[^1]; + outValue = iphe.AddressList[iphe.AddressList.Length - 1]; } catch { @@ -120,23 +119,65 @@ namespace Server.Misc } } - private static bool HasPublicIPAddress() => - NetworkInterface.GetAllNetworkInterfaces().Select(adapter => adapter.GetIPProperties()) - .Any(properties => properties.UnicastAddresses.Select(unicast => unicast.Address) - .Any(ip => !IPAddress.IsLoopback(ip) && ip.AddressFamily != AddressFamily.InterNetworkV6 && !IsPrivateNetwork(ip))); + private static bool HasPublicIPAddress() + { + NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces(); - // 10.0.0.0/8 - // 172.16.0.0/12 - // 192.168.0.0/16 - // 169.254.0.0/16 - // 100.64.0.0/10 RFC 6598 - private static bool IsPrivateNetwork(IPAddress ip) => - ip.AddressFamily != AddressFamily.InterNetworkV6 && - (Utility.IPMatch("192.168.*", ip) || - Utility.IPMatch("10.*", ip) || - Utility.IPMatch("172.16-31.*", ip) || - Utility.IPMatch("169.254.*", ip) || - Utility.IPMatch("100.64-127.*", ip)); + foreach (NetworkInterface adapter in adapters) + { + IPInterfaceProperties properties = adapter.GetIPProperties(); + + foreach (IPAddressInformation unicast in properties.UnicastAddresses) + { + IPAddress ip = unicast.Address; + + if (!IPAddress.IsLoopback(ip) && ip.AddressFamily != AddressFamily.InterNetworkV6 && + !IsPrivateNetwork(ip)) + return true; + } + } + + return false; + + + /* + IPHostEntry iphe = Dns.GetHostEntry( Dns.GetHostName() ); + + IPAddress[] ips = iphe.AddressList; + + for ( int i = 0; i < ips.Length; ++i ) + { + if ( ips[i].AddressFamily != AddressFamily.InterNetworkV6 && !IsPrivateNetwork( ips[i] ) ) + return true; + } + + return false; + */ + } + + private static bool IsPrivateNetwork(IPAddress ip) + { + // 10.0.0.0/8 + // 172.16.0.0/12 + // 192.168.0.0/16 + // 169.254.0.0/16 + // 100.64.0.0/10 RFC 6598 + + if (ip.AddressFamily == AddressFamily.InterNetworkV6) + return false; + + if (Utility.IPMatch("192.168.*", ip)) + return true; + if (Utility.IPMatch("10.*", ip)) + return true; + if (Utility.IPMatch("172.16-31.*", ip)) + return true; + if (Utility.IPMatch("169.254.*", ip)) + return true; + if (Utility.IPMatch("100.64-127.*", ip)) + return true; + return false; + } private static IPAddress FindPublicAddress() { @@ -152,7 +193,7 @@ namespace Server.Misc StreamReader sr = new StreamReader(s); - IPAddress ip = IPAddress.Parse(sr.ReadLine() ?? ""); + IPAddress ip = IPAddress.Parse(sr.ReadLine()); sr.Close(); s.Close(); diff --git a/Projects/Scripts/Misc/ShardPoller.cs b/Projects/Scripts/Misc/ShardPoller.cs index 484c60db9..2e94a58c2 100644 --- a/Projects/Scripts/Misc/ShardPoller.cs +++ b/Projects/Scripts/Misc/ShardPoller.cs @@ -4,6 +4,7 @@ using System.Net; using System.Text.RegularExpressions; using Server.Gumps; using Server.Network; +using Server.Prompts; namespace Server.Misc { @@ -464,7 +465,9 @@ namespace Server.Misc public void QueuePoll(ShardPoller poller) { - m_Polls ??= new Queue(4); + if (m_Polls == null) + m_Polls = new Queue(4); + m_Polls.Enqueue(poller); } diff --git a/Projects/Scripts/Misc/SkillCheck.cs b/Projects/Scripts/Misc/SkillCheck.cs index b1ca705b0..c0ead7ea3 100644 --- a/Projects/Scripts/Misc/SkillCheck.cs +++ b/Projects/Scripts/Misc/SkillCheck.cs @@ -224,7 +224,7 @@ namespace Server.Misc Skills skills = from.Skills; - if (from.Player && skills.Total / (double)skills.Cap >= Utility.RandomDouble()) //( skills.Total >= skills.Cap ) + if (from.Player && skills.Total / skills.Cap >= Utility.RandomDouble()) //( skills.Total >= skills.Cap ) for (int i = 0; i < skills.Length; ++i) { Skill toLower = skills[i]; diff --git a/Projects/Scripts/Misc/Titles.cs b/Projects/Scripts/Misc/Titles.cs index ee2d50860..2ff78569f 100644 --- a/Projects/Scripts/Misc/Titles.cs +++ b/Projects/Scripts/Misc/Titles.cs @@ -373,7 +373,8 @@ namespace Server.Misc { int fp = Math.Min(skill.BaseFixedPoint, 1200); - private static int GetTableIndex(Skill skill) => (Math.Min(skill.BaseFixedPoint, 1200) - 300) / 100; + return (fp - 300) / 100; + } } public class FameEntry diff --git a/Projects/Scripts/Misc/TreasureMapProtection.cs b/Projects/Scripts/Misc/TreasureMapProtection.cs index bdc79fdbb..16f3951bc 100644 --- a/Projects/Scripts/Misc/TreasureMapProtection.cs +++ b/Projects/Scripts/Misc/TreasureMapProtection.cs @@ -19,7 +19,7 @@ namespace Server public static void Initialize() { string filePath = Path.Combine(Core.BaseDirectory, "Data/treasure.cfg"); - int i = 0; + int i = 0, x = 0, y = 0; if (File.Exists(filePath)) { @@ -69,4 +69,4 @@ namespace Server m.SendMessage("You have left a protected treasure map area."); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Misc/VendorGenerator.cs b/Projects/Scripts/Misc/VendorGenerator.cs index 204f6a6da..40451ac82 100644 --- a/Projects/Scripts/Misc/VendorGenerator.cs +++ b/Projects/Scripts/Misc/VendorGenerator.cs @@ -347,6 +347,8 @@ namespace Server private static bool CanFit(Map map, int x, int y, int z) { + bool hasSurface = false; + LandTile lt = map.Tiles.GetLandTile(x, y); int lowZ = 0, avgZ = 0, topZ = 0; @@ -355,8 +357,8 @@ namespace Server if ((landFlags & TileFlag.Impassable) != 0 && topZ > z && z + 16 > lowZ) return false; - - bool hasSurface = (landFlags & TileFlag.Impassable) == 0 && z == avgZ && !lt.Ignored; + if ((landFlags & TileFlag.Impassable) == 0 && z == avgZ && !lt.Ignored) + hasSurface = true; StaticTile[] staticTiles = map.Tiles.GetStaticTiles(x, y); @@ -374,8 +376,8 @@ namespace Server if ((surface || impassable) && staticTiles[i].Z + id.CalcHeight > z && z + 16 > staticTiles[i].Z) return false; - - hasSurface |= surface && !impassable && z == staticTiles[i].Z + id.CalcHeight; + if (surface && !impassable && z == staticTiles[i].Z + id.CalcHeight) + hasSurface = true; } Sector sector = map.GetSector(x, y); @@ -393,8 +395,8 @@ namespace Server if ((surface || impassable) && item.Z + id.CalcHeight > z && z + 16 > item.Z) return false; - - hasSurface |= surface && !impassable && z == item.Z + id.CalcHeight; + if (surface && !impassable && z == item.Z + id.CalcHeight) + hasSurface = true; } } @@ -411,9 +413,9 @@ namespace Server floor.Add(p); for (int xo = -1; xo <= 1; ++xo) - for (int yo = -1; yo <= 1; ++yo) - if ((xo != 0 || yo != 0) && IsFloor(map, x + xo, y + yo, false)) - RecurseFindFloor(map, x + xo, y + yo, floor); + for (int yo = -1; yo <= 1; ++yo) + if ((xo != 0 || yo != 0) && IsFloor(map, x + xo, y + yo, false)) + RecurseFindFloor(map, x + xo, y + yo, floor); } [Flags] diff --git a/Projects/Scripts/Misc/Weather.cs b/Projects/Scripts/Misc/Weather.cs index c9ff68246..34d3aa2c4 100644 --- a/Projects/Scripts/Misc/Weather.cs +++ b/Projects/Scripts/Misc/Weather.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Items; using Server.Network; diff --git a/Projects/Scripts/Misc/WeightOverloading.cs b/Projects/Scripts/Misc/WeightOverloading.cs index b09a9e653..27704df0a 100644 --- a/Projects/Scripts/Misc/WeightOverloading.cs +++ b/Projects/Scripts/Misc/WeightOverloading.cs @@ -23,12 +23,21 @@ namespace Server.Misc public static void FatigueOnDamage(Mobile m, int damage) { - double fatigue = DFA switch + double fatigue = 0.0; + + switch (DFA) { - DFAlgorithm.Standard => damage * (100.0 / m.Hits) * ((double)m.Stam / 100) - 5.0, - DFAlgorithm.PainSpike => damage * (100.0 / m.Hits + (50.0 + m.Stam) / 100 - 1.0) - 5.0, - _ => 0.0, - }; + case DFAlgorithm.Standard: + { + fatigue = damage * (100.0 / m.Hits) * ((double)m.Stam / 100) - 5.0; + break; + } + case DFAlgorithm.PainSpike: + { + fatigue = damage * (100.0 / m.Hits + (50.0 + m.Stam) / 100 - 1.0) - 5.0; + break; + } + } if (fatigue > 0) m.Stam -= (int)fatigue; @@ -108,4 +117,4 @@ namespace Server.Misc return Mobile.BodyWeight + m.TotalWeight > GetMaxWeight(m) + OverloadAllowance; } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/AI/AnimalAI.cs b/Projects/Scripts/Mobiles/AI/AnimalAI.cs index 90ad332d5..9cc4585ea 100644 --- a/Projects/Scripts/Mobiles/AI/AnimalAI.cs +++ b/Projects/Scripts/Mobiles/AI/AnimalAI.cs @@ -1,5 +1,5 @@ // Ideas -// When you run on animals they panic +// When you run on animals the panic // When if ( distance < 8 && Utility.RandomDouble() * Math.Sqrt( (8 - distance) / 6 ) >= incoming.Skills.AnimalTaming.Value ) // More your close, the more it can panic /* diff --git a/Projects/Scripts/Mobiles/AI/BaseAI.cs b/Projects/Scripts/Mobiles/AI/BaseAI.cs index 5ecb9dafc..801a02665 100644 --- a/Projects/Scripts/Mobiles/AI/BaseAI.cs +++ b/Projects/Scripts/Mobiles/AI/BaseAI.cs @@ -12,6 +12,7 @@ using Server.Regions; using Server.Spells; using Server.Spells.Spellweaving; using Server.Targets; +using MoveImpl = Server.Movement.MovementImpl; namespace Server.Mobiles { @@ -110,7 +111,18 @@ namespace Server.Mobiles m_Timer = new AITimer(this); - if (!(m.PlayerRangeSensitive || World.Loading || m.Map == null || m.Map == Map.Internal || !m.Map.GetSector(m).Active)) + bool activate; + + if (!m.PlayerRangeSensitive) + activate = true; + else if (World.Loading) + activate = false; + else if (m.Map == null || m.Map == Map.Internal || !m.Map.GetSector(m).Active) + activate = false; + else + activate = true; + + if (activate) m_Timer.Start(); Action = ActionType.Wander; @@ -1677,17 +1689,20 @@ namespace Server.Mobiles bool isPassive = delay == m_Mobile.PassiveSpeed; bool isControlled = m_Mobile.Controlled || m_Mobile.Summoned; - delay = delay switch - { - 0.2 => 0.3, - 0.25 => 0.45, - 0.3 => 0.6, - 0.4 => 0.9, - 0.5 => 1.05, - 0.6 => 1.2, - 0.8 => 1.5, - _ => delay - }; + if (delay == 0.2) + delay = 0.3; + else if (delay == 0.25) + delay = 0.45; + else if (delay == 0.3) + delay = 0.6; + else if (delay == 0.4) + delay = 0.9; + else if (delay == 0.5) + delay = 1.05; + else if (delay == 0.6) + delay = 1.2; + else if (delay == 0.8) + delay = 1.5; if (isPassive) delay += 0.2; @@ -1767,13 +1782,13 @@ namespace Server.Mobiles m_Mobile.Pushing = false; - MovementImpl.IgnoreMovableImpassables = m_Mobile.CanMoveOverObstacles && !m_Mobile.CanDestroyObstacles; + MoveImpl.IgnoreMovableImpassables = m_Mobile.CanMoveOverObstacles && !m_Mobile.CanDestroyObstacles; if ((m_Mobile.Direction & Direction.Mask) != (d & Direction.Mask)) { bool v = m_Mobile.Move(d); - MovementImpl.IgnoreMovableImpassables = false; + MoveImpl.IgnoreMovableImpassables = false; return v ? MoveResult.Success : MoveResult.Blocked; } @@ -1795,7 +1810,7 @@ namespace Server.Mobiles if (map != null) { int x = m_Mobile.X, y = m_Mobile.Y; - Movement.Offset(d, ref x, ref y); + Movement.Movement.Offset(d, ref x, ref y); int destroyables = 0; @@ -1884,20 +1899,20 @@ namespace Server.Mobiles if (m_Mobile.Move(m_Mobile.Direction)) { - MovementImpl.IgnoreMovableImpassables = false; + MoveImpl.IgnoreMovableImpassables = false; return MoveResult.SuccessAutoTurn; } } - MovementImpl.IgnoreMovableImpassables = false; + MoveImpl.IgnoreMovableImpassables = false; return wasPushing ? MoveResult.BadState : MoveResult.Blocked; } - MovementImpl.IgnoreMovableImpassables = false; + MoveImpl.IgnoreMovableImpassables = false; return MoveResult.Success; } - MovementImpl.IgnoreMovableImpassables = false; + MoveImpl.IgnoreMovableImpassables = false; return MoveResult.Success; } @@ -2007,9 +2022,9 @@ namespace Server.Mobiles return true; } - if (ReferenceEquals(m_Path?.Goal, m)) + if (m_Path?.Goal == m) { - if (m_Path?.Follow(run, 1) == true) + if (m_Path.Follow(run, 1)) { m_Path = null; return true; @@ -2017,7 +2032,8 @@ namespace Server.Mobiles } else if (!DoMove(m_Mobile.GetDirectionTo(m), true)) { - m_Path = new PathFollower(m_Mobile, m) {Mover = DoMoveImpl}; + m_Path = new PathFollower(m_Mobile, m); + m_Path.Mover = DoMoveImpl; if (m_Path.Follow(run, 1)) { @@ -2059,23 +2075,30 @@ namespace Server.Mobiles if (iCurrDist < iWantDistMin || iCurrDist > iWantDistMax) { bool needCloser = iCurrDist > iWantDistMax; + bool needFurther = !needCloser; - if (needCloser && m_Path != null && ReferenceEquals(m_Path.Goal, m)) + if (needCloser && m_Path != null && m_Path.Goal == m) { if (m_Path.Follow(bRun, 1)) m_Path = null; } else { - Direction dirTo = iCurrDist > iWantDistMax ? m_Mobile.GetDirectionTo(m) : m.GetDirectionTo(m_Mobile); + Direction dirTo; + + if (iCurrDist > iWantDistMax) + dirTo = m_Mobile.GetDirectionTo(m); + else + dirTo = m.GetDirectionTo(m_Mobile); // Add the run flag if (bRun) - dirTo |= Direction.Running; + dirTo = dirTo | Direction.Running; if (!DoMove(dirTo, true) && needCloser) { - m_Path = new PathFollower(m_Mobile, m) {Mover = DoMoveImpl}; + m_Path = new PathFollower(m_Mobile, m); + m_Path.Mover = DoMoveImpl; if (m_Path.Follow(bRun, 1)) m_Path = null; @@ -2681,9 +2704,13 @@ namespace Server.Mobiles } if (m_Owner.m_Mobile.BardPacified) + { m_Owner.DoBardPacified(); + } else if (m_Owner.m_Mobile.BardProvoked) + { m_Owner.DoBardProvoked(); + } else { if (!m_Owner.m_Mobile.Controlled) diff --git a/Projects/Scripts/Mobiles/AI/HealerAI.cs b/Projects/Scripts/Mobiles/AI/HealerAI.cs index 68c51964a..f5fe4f341 100644 --- a/Projects/Scripts/Mobiles/AI/HealerAI.cs +++ b/Projects/Scripts/Mobiles/AI/HealerAI.cs @@ -1,4 +1,3 @@ -using System.Linq; using Server.Spells; using Server.Spells.First; using Server.Spells.Fourth; @@ -117,16 +116,19 @@ namespace Server.Mobiles if (!m_Mobile.CanSee(m) || !(m is BaseCreature) || ((BaseCreature)m).Team != m_Mobile.Team) continue; - if (funcs.Any(t => t(m))) - { - double val = -m_Mobile.GetDistanceToSqrt(m); - - if (found == null || val > prio) + for (int i = 0; i < funcs.Length; ++i) + if (funcs[i](m)) { - prio = val; - found = m; + double val = -m_Mobile.GetDistanceToSqrt(m); + + if (found == null || val > prio) + { + prio = val; + found = m; + } + + break; } - } } return found; diff --git a/Projects/Scripts/Mobiles/AI/MageAI.cs b/Projects/Scripts/Mobiles/AI/MageAI.cs index 0cc8875f6..e4f9e69a5 100644 --- a/Projects/Scripts/Mobiles/AI/MageAI.cs +++ b/Projects/Scripts/Mobiles/AI/MageAI.cs @@ -339,17 +339,18 @@ namespace Server.Mobiles if (m_Mobile.Skills.Magery.Value >= 80.0 && Utility.RandomBool()) return new ManaVampireSpell(m_Mobile); - public virtual Spell GetRandomManaDrainSpell() => - m_Mobile.Skills.Magery.Value >= 80.0 && Utility.RandomBool() - ? (Spell)new ManaVampireSpell(m_Mobile) - : new ManaDrainSpell(m_Mobile); + return new ManaDrainSpell(m_Mobile); + } public virtual Spell DoDispel(Mobile toDispel) { if (!SmartAI) - return ScaleBySkill(DispelChance, SkillName.Magery) > Utility.RandomDouble() - ? new DispelSpell(m_Mobile) - : ChooseSpell(toDispel); + { + if (ScaleBySkill(DispelChance, SkillName.Magery) > Utility.RandomDouble()) + return new DispelSpell(m_Mobile); + + return ChooseSpell(toDispel); + } Spell spell = CheckCastHealingSpell(); diff --git a/Projects/Scripts/Mobiles/Animals/Mounts/Ethereals.cs b/Projects/Scripts/Mobiles/Animals/Mounts/Ethereals.cs index 6478c7d68..b2e2a7995 100644 --- a/Projects/Scripts/Mobiles/Animals/Mounts/Ethereals.cs +++ b/Projects/Scripts/Mobiles/Animals/Mounts/Ethereals.cs @@ -364,8 +364,13 @@ namespace Server.Mobiles Disturb(DisturbType.Hurt, false); } - public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) => - type != DisturbType.EquipRequest && type != DisturbType.UseRequest; + public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) + { + if (type == DisturbType.EquipRequest || type == DisturbType.UseRequest /* || type == DisturbType.Hurt*/) + return false; + + return true; + } public override void DoHurtFizzle() { diff --git a/Projects/Scripts/Mobiles/Animals/Mounts/Kirin.cs b/Projects/Scripts/Mobiles/Animals/Mounts/Kirin.cs index 1e5d70fd5..650e1194a 100644 --- a/Projects/Scripts/Mobiles/Animals/Mounts/Kirin.cs +++ b/Projects/Scripts/Mobiles/Animals/Mounts/Kirin.cs @@ -78,7 +78,7 @@ namespace Server.Mobiles if (Rider.Hits - damage < 30 && Rider.Map == attacker.Map && Rider.InRange(attacker, 18) ) //Range and map checked here instead of other base fuction because of abiliites that don't need to check this { - attacker.BoltEffect(); + attacker.BoltEffect(0); // 35~100 damage, unresistable, by the Ki-rin. attacker.Damage(Utility.RandomMinMax(35, 100), this, false); //Don't inform mount about this damage, Still unsure wether or not it's flagged as the mount doing damage or the player. If changed to player, without the extra bool it'd be an infinite loop diff --git a/Projects/Scripts/Mobiles/BaseCreature.cs b/Projects/Scripts/Mobiles/BaseCreature.cs index 927e57603..26d7e716d 100644 --- a/Projects/Scripts/Mobiles/BaseCreature.cs +++ b/Projects/Scripts/Mobiles/BaseCreature.cs @@ -327,7 +327,6 @@ namespace Server.Mobiles { if (m_Paragon == value) return; - if (value) Paragon.Convert(this); else @@ -916,7 +915,7 @@ namespace Server.Mobiles return (double)chance / 1000; } - public override void Damage(int amount, Mobile from = null, bool informMount = true) + public override void Damage(int amount, Mobile from) { int oldHits = Hits; @@ -931,10 +930,10 @@ namespace Server.Mobiles if (oath == this) { amount = (int)(amount * 1.1); - from?.Damage(amount, from); + from.Damage(amount, from); } - base.Damage(amount, from, informMount); + base.Damage(amount, from); if (SubdueBeforeTame && !Controlled && oldHits > HitsMax / 10 && Hits <= HitsMax / 10) PublicOverheadMessage(MessageType.Regular, 0x3B2, false, @@ -2111,7 +2110,9 @@ namespace Server.Mobiles } } else if (ReacquireOnMovement) + { ForceReacquire(); + } InhumanSpeech speechType = SpeechType; @@ -2132,7 +2133,10 @@ namespace Server.Mobiles if (MLQuestSystem.Enabled && CanShout && m is PlayerMobile mobile) CheckShout(mobile, oldLocation); - if (m_NoDupeGuards == m || !Body.IsHuman || Kills >= 5 || AlwaysMurderer || AlwaysAttackable || m.Kills < 5 || + if (m_NoDupeGuards == m) + return; + + if (!Body.IsHuman || Kills >= 5 || AlwaysMurderer || AlwaysAttackable || m.Kills < 5 || !m.InRange(Location, 12) || !m.Alive) return; @@ -3052,12 +3056,7 @@ namespace Server.Mobiles IsDeadPet = false; - IPooledEnumerable eable = Map.GetClientsInRange(Location); - - foreach (NetState ns in eable) - Packets.SendBondStatus(ns, Serial, false); - - eable.Free(); + Effects.SendPacket(Location, Map, new BondedStatus(0, Serial, 0)); SendIncomingPacket(); SendIncomingPacket(); @@ -3101,7 +3100,10 @@ namespace Server.Mobiles m_ReturnQueued = true; } - else if (PlayerRangeSensitive) AIObject?.Deactivate(); + else if (PlayerRangeSensitive) + { + AIObject?.Deactivate(); + } base.OnSectorDeactivate(); } @@ -3235,11 +3237,15 @@ namespace Server.Mobiles { if (m_MLQuests == null) { - m_MLQuests = StaticMLQuester ? MLQuestSystem.FindQuestList(GetType()) : ConstructQuestList(); + if (StaticMLQuester) + m_MLQuests = MLQuestSystem.FindQuestList(GetType()); + else + m_MLQuests = ConstructQuestList(); - // return EmptyList, but don't cache it (run construction again next time) if (m_MLQuests == null) - return MLQuestSystem.EmptyList; + return + MLQuestSystem + .EmptyList; // return EmptyList, but don't cache it (run construction again next time) } return m_MLQuests; @@ -3263,7 +3269,9 @@ namespace Server.Mobiles if (m_MLNextShout > DateTime.UtcNow || pm.Hidden || !pm.Alive) return; - if (!InRange(pm.Location, ShoutRange) || InRange(oldLocation, ShoutRange) || !CanSee(pm) || !InLOS(pm)) + int shoutRange = ShoutRange; + + if (!InRange(pm.Location, shoutRange) || InRange(oldLocation, shoutRange) || !CanSee(pm) || !InLOS(pm)) return; MLQuestContext context = MLQuestSystem.GetContext(pm); @@ -3306,7 +3314,16 @@ namespace Server.Mobiles public Spawner MySpawner => Spawner as Spawner; [CommandProperty(AccessLevel.GameMaster)] - public Mobile LastOwner => Owners?.Count > 0 ? Owners[^1] : null; + public Mobile LastOwner + { + get + { + if (Owners == null || Owners.Count == 0) + return null; + + return Owners[Owners.Count - 1]; + } + } [CommandProperty(AccessLevel.GameMaster)] public bool IsBonded @@ -3715,7 +3732,9 @@ namespace Server.Mobiles public virtual void AddPetFriend(Mobile m) { - Friends ??= new List(); + if (Friends == null) + Friends = new List(); + Friends.Add(m); } @@ -3846,13 +3865,28 @@ namespace Server.Mobiles typeof(Gold) }; - public virtual bool CheckFoodPreference(Item f) => - CheckFoodPreference(f, FoodType.Eggs, m_Eggs) || - CheckFoodPreference(f, FoodType.Fish, m_Fish) || - CheckFoodPreference(f, FoodType.GrainsAndHay, m_GrainsAndHay) || - CheckFoodPreference(f, FoodType.Meat, m_Meat) || - CheckFoodPreference(f, FoodType.FruitsAndVegies, m_FruitsAndVegies) || - CheckFoodPreference(f, FoodType.Gold, m_Gold); + public virtual bool CheckFoodPreference(Item f) + { + if (CheckFoodPreference(f, FoodType.Eggs, m_Eggs)) + return true; + + if (CheckFoodPreference(f, FoodType.Fish, m_Fish)) + return true; + + if (CheckFoodPreference(f, FoodType.GrainsAndHay, m_GrainsAndHay)) + return true; + + if (CheckFoodPreference(f, FoodType.Meat, m_Meat)) + return true; + + if (CheckFoodPreference(f, FoodType.FruitsAndVegies, m_FruitsAndVegies)) + return true; + + if (CheckFoodPreference(f, FoodType.Gold, m_Gold)) + return true; + + return false; + } public virtual bool CheckFoodPreference(Item fed, FoodType type, Type[] types) { @@ -3870,79 +3904,82 @@ namespace Server.Mobiles public virtual bool CheckFeed(Mobile from, Item dropped) { - if (IsDeadPet || !Controlled || ControlMaster != from && !IsPetFriend(from)) - return false; - - Item f = dropped; - - if (!CheckFoodPreference(f)) - return false; - - int amount = f.Amount; - - if (amount <= 0) - return false; - - int stamGain; - - if (f is Gold) - stamGain = amount - 50; - else - stamGain = amount * 15 - 50; - - if (stamGain > 0) - Stam += stamGain; - - if (Core.SE) + if (!IsDeadPet && Controlled && (ControlMaster == from || IsPetFriend(from))) { - if (m_Loyalty < MaxLoyalty) - m_Loyalty = MaxLoyalty; - } - else - for (int i = 0; i < amount; ++i) - if (m_Loyalty < MaxLoyalty && 0.5 >= Utility.RandomDouble()) - m_Loyalty += 10; + Item f = dropped; - /* if ( happier )*/ - // looks like in OSI pets say they are happier even if they are at maximum loyalty - SayTo(from, 502060); // Your pet looks happier. - - if (Body.IsAnimal) - Animate(3, 5, 1, true, false, 0); - else if (Body.IsMonster) - Animate(17, 5, 1, true, false, 0); - - if (IsBondable && !IsBonded) - { - Mobile master = m_ControlMaster; - - if (master != null && master == from) //So friends can't start the bonding process + if (CheckFoodPreference(f)) { - if (MinTameSkill <= 29.1 || master.Skills.AnimalTaming.Base >= MinTameSkill || - OverrideBondingReqs() || - Core.ML && master.Skills.AnimalTaming.Value >= MinTameSkill) + int amount = f.Amount; + + if (amount > 0) { - if (BondingBegin == DateTime.MinValue) + int stamGain; + + if (f is Gold) + stamGain = amount - 50; + else + stamGain = amount * 15 - 50; + + if (stamGain > 0) + Stam += stamGain; + + if (Core.SE) { - BondingBegin = DateTime.UtcNow; + if (m_Loyalty < MaxLoyalty) m_Loyalty = MaxLoyalty; } - else if (BondingBegin + BondingDelay <= DateTime.UtcNow) + else { - IsBonded = true; - BondingBegin = DateTime.MinValue; - from.SendLocalizedMessage(1049666); // Your pet has bonded with you! + for (int i = 0; i < amount; ++i) + if (m_Loyalty < MaxLoyalty && 0.5 >= Utility.RandomDouble()) + m_Loyalty += 10; } - } - else if (Core.ML) - { - from.SendLocalizedMessage( - 1075268); // Your pet cannot form a bond with you until your animal taming ability has risen. + + /* if ( happier )*/ + // looks like in OSI pets say they are happier even if they are at maximum loyalty + SayTo(from, 502060); // Your pet looks happier. + + if (Body.IsAnimal) + Animate(3, 5, 1, true, false, 0); + else if (Body.IsMonster) + Animate(17, 5, 1, true, false, 0); + + if (IsBondable && !IsBonded) + { + Mobile master = m_ControlMaster; + + if (master != null && master == from) //So friends can't start the bonding process + { + if (MinTameSkill <= 29.1 || master.Skills.AnimalTaming.Base >= MinTameSkill || + OverrideBondingReqs() || + Core.ML && master.Skills.AnimalTaming.Value >= MinTameSkill) + { + if (BondingBegin == DateTime.MinValue) + { + BondingBegin = DateTime.UtcNow; + } + else if (BondingBegin + BondingDelay <= DateTime.UtcNow) + { + IsBonded = true; + BondingBegin = DateTime.MinValue; + from.SendLocalizedMessage(1049666); // Your pet has bonded with you! + } + } + else if (Core.ML) + { + from.SendLocalizedMessage( + 1075268); // Your pet cannot form a bond with you until your animal taming ability has risen. + } + } + } + + dropped.Delete(); + return true; } } } - dropped.Delete(); - return true; + return false; } #endregion @@ -3995,10 +4032,23 @@ namespace Server.Mobiles public virtual bool CanTeach => false; - public virtual bool CheckTeach(SkillName skill, Mobile from) => - CanTeach && (skill != SkillName.Stealth || !(from.Skills.Hiding.Base < Stealth.HidingRequirement)) && - (skill != SkillName.RemoveTrap || !(from.Skills.Lockpicking.Base < 50.0) && !(from.Skills.DetectHidden.Base < 50.0)) && - (Core.AOS || skill != SkillName.Focus && skill != SkillName.Chivalry && skill != SkillName.Necromancy); + public virtual bool CheckTeach(SkillName skill, Mobile from) + { + if (!CanTeach) + return false; + + if (skill == SkillName.Stealth && from.Skills.Hiding.Base < Stealth.HidingRequirement) + return false; + + if (skill == SkillName.RemoveTrap && (from.Skills.Lockpicking.Base < 50.0 || + from.Skills.DetectHidden.Base < 50.0)) + return false; + + if (!Core.AOS && (skill == SkillName.Focus || skill == SkillName.Chivalry || skill == SkillName.Necromancy)) + return false; + + return true; + } public enum TeachResult { @@ -4108,8 +4158,16 @@ namespace Server.Mobiles return TeachResult.Success; } - public virtual bool CheckTeachingMatch(Mobile m) => - m_Teaching != (SkillName)(-1) && (!(m is PlayerMobile mobile) || mobile.Learning == m_Teaching); + public virtual bool CheckTeachingMatch(Mobile m) + { + if (m_Teaching == (SkillName)(-1)) + return false; + + if (m is PlayerMobile mobile) + return mobile.Learning == m_Teaching; + + return true; + } private SkillName m_Teaching = (SkillName)(-1); @@ -5054,7 +5112,9 @@ namespace Server.Mobiles if (c.Loyalty <= 0) lock (toRelease) + { toRelease.Add(c); + } } } @@ -5062,12 +5122,18 @@ namespace Server.Mobiles if (!c.Controlled && !c.IsStabled && (c.Region.IsPartOf() && c.CanBeDamaged() || c.RemoveIfUntamed && c.Spawner == null)) { - if (c.RemoveStep++ >= 20) + c.RemoveStep++; + + if (c.RemoveStep >= 20) lock (toRemove) + { toRemove.Add(c); + } } else + { c.RemoveStep = 0; + } }); // TODO: Parallelize this diff --git a/Projects/Scripts/Mobiles/Familiars/HordeMinion.cs b/Projects/Scripts/Mobiles/Familiars/HordeMinion.cs index fb2205a74..8012f81be 100644 --- a/Projects/Scripts/Mobiles/Familiars/HordeMinion.cs +++ b/Projects/Scripts/Mobiles/Familiars/HordeMinion.cs @@ -73,11 +73,11 @@ namespace Server.Mobiles if (pack == null) return; - IPooledEnumerable eable = GetItemsInRange(2); + IEnumerable eable = GetItemsInRange(2).Where(item => item.Movable && item.Stackable); int pickedUp = 0; - foreach (Item item in eable.Where(item => item.Movable && item.Stackable)) + foreach (Item item in eable) { if (!pack.CheckHold(this, item, false, true)) return; @@ -94,8 +94,6 @@ namespace Server.Mobiles if (++pickedUp == 3) break; } - - eable.Free(); } private void ConfirmRelease_Callback(Mobile from, bool okay) diff --git a/Projects/Scripts/Mobiles/Guards/ArcherGuard.cs b/Projects/Scripts/Mobiles/Guards/ArcherGuard.cs index ac3f11045..6560b2652 100644 --- a/Projects/Scripts/Mobiles/Guards/ArcherGuard.cs +++ b/Projects/Scripts/Mobiles/Guards/ArcherGuard.cs @@ -261,7 +261,7 @@ namespace Server.Mobiles { // TeleportTo(target); - target.BoltEffect(); + target.BoltEffect(0); if (target is BaseCreature creature) creature.NoKillAwards = true; diff --git a/Projects/Scripts/Mobiles/Guards/BaseGuard.cs b/Projects/Scripts/Mobiles/Guards/BaseGuard.cs index 5d8a5c59e..187318cd8 100644 --- a/Projects/Scripts/Mobiles/Guards/BaseGuard.cs +++ b/Projects/Scripts/Mobiles/Guards/BaseGuard.cs @@ -27,9 +27,7 @@ namespace Server.Mobiles if (target?.Deleted != false) return; - IPooledEnumerable eable = target.GetMobilesInRange(15); - - foreach (Mobile m in eable) + foreach (Mobile m in target.GetMobilesInRange(15)) if (m is BaseGuard g) { if (g.Focus == null) // idling @@ -44,8 +42,6 @@ namespace Server.Mobiles } } - eable.Free(); - while (amount-- > 0) caller.Region.MakeGuard(target); } @@ -76,4 +72,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Guards/WarriorGuard.cs b/Projects/Scripts/Mobiles/Guards/WarriorGuard.cs index 909a8dd27..1cad91a09 100644 --- a/Projects/Scripts/Mobiles/Guards/WarriorGuard.cs +++ b/Projects/Scripts/Mobiles/Guards/WarriorGuard.cs @@ -292,7 +292,7 @@ namespace Server.Mobiles { // TeleportTo(target); - target.BoltEffect(); + target.BoltEffect(0); if (target is BaseCreature creature) creature.NoKillAwards = true; diff --git a/Projects/Scripts/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs b/Projects/Scripts/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs index c2df17252..63bf68194 100644 --- a/Projects/Scripts/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs +++ b/Projects/Scripts/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs @@ -151,7 +151,7 @@ namespace Server.Mobiles return; IPooledEnumerable eable = GetMobilesInRange(8); - + switch (Utility.Random(3)) { case 0: /* greater heal */ @@ -208,7 +208,7 @@ namespace Server.Mobiles damage = Utility.Random(12, 9); } - m.BoltEffect(); + m.BoltEffect(0); SpellHelper.Damage(TimeSpan.FromSeconds(0.25), m, this, damage, 0, 0, 0, 0, 100); } @@ -260,7 +260,7 @@ namespace Server.Mobiles break; } } - + eable.Free(); } @@ -276,4 +276,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs b/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs index b56c8a0a5..5bb6064aa 100644 --- a/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs +++ b/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Items; namespace Server.Mobiles @@ -80,9 +79,13 @@ namespace Server.Mobiles if (lastKiller is BaseCreature creature) lastKiller = creature.GetMaster(); - if (IsInsideKhaldun(m) && IsInsideKhaldun(lastKiller) && lastKiller.Player && - !m_Set.Contains(lastKiller) && m.Aggressors.Any(ai => ai.Attacker == lastKiller && ai.CanReportMurder)) - SummonRevenant(m, lastKiller); + if (IsInsideKhaldun(m) && IsInsideKhaldun(lastKiller) && lastKiller.Player && !m_Set.Contains(lastKiller)) + foreach (AggressorInfo ai in m.Aggressors) + if (ai.Attacker == lastKiller && ai.CanReportMurder) + { + SummonRevenant(m, lastKiller); + break; + } } public static void SummonRevenant(Mobile victim, Mobile killer) diff --git a/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs b/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs index 7829cb1ae..5eceebcba 100644 --- a/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs +++ b/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs @@ -104,7 +104,7 @@ namespace Server.Mobiles } Effects.PlaySound(this, Map, GetDeathSound()); - Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835); + Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835, 0); rm.MoveToWorld(Location, Map); Delete(); diff --git a/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs b/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs index 733d9df4f..b01f3900e 100644 --- a/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs +++ b/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs @@ -113,7 +113,7 @@ namespace Server.Mobiles } Effects.PlaySound(this, Map, GetDeathSound()); - Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835); + Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835, 0); rm.MoveToWorld(Location, Map); Delete(); diff --git a/Projects/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs b/Projects/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs index ede677bb7..0d05094af 100644 --- a/Projects/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs +++ b/Projects/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs @@ -217,7 +217,7 @@ namespace Server.Mobiles { if (to.Alive && to.Player && !UnderCacophonicAttack(to)) { - Packets.SendSpeedControlWalk(to.NetState); + to.Send(SpeedControl.WalkSpeed); to.SendLocalizedMessage(1072069); // A cacophonic sound lambastes you, suppressing your ability to move. to.PlaySound(0x584); @@ -229,7 +229,7 @@ namespace Server.Mobiles public virtual void CacophonicEnd(Mobile from) { m_Table.Remove(from); - Packets.SendSpeedControlDisabled(from.NetState); + from.Send(SpeedControl.Disable); } public static bool UnderCacophonicAttack(Mobile from) => m_Table.Contains(from); diff --git a/Projects/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs b/Projects/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs index d64a16c67..848713e48 100644 --- a/Projects/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs +++ b/Projects/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs @@ -76,7 +76,8 @@ namespace Server.Mobiles { OpenedBy = from; - m_Timer ??= new DecayTimer(this); + if (m_Timer == null) + m_Timer = new DecayTimer(this); if (!m_Timer.Running) m_Timer.Start(); diff --git a/Projects/Scripts/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs b/Projects/Scripts/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs index e479247af..40eeebf38 100644 --- a/Projects/Scripts/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs +++ b/Projects/Scripts/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs @@ -35,7 +35,8 @@ namespace Server.Mobiles Body = 0x15; BaseSoundID = 0xDB; break; - default: // slime + default: + case 5: // slime Body = 51; BaseSoundID = 456; break; diff --git a/Projects/Scripts/Mobiles/Monsters/SE/DeathWatchBeetle.cs b/Projects/Scripts/Mobiles/Monsters/SE/DeathWatchBeetle.cs index a3b7a0179..72b4bb73e 100644 --- a/Projects/Scripts/Mobiles/Monsters/SE/DeathWatchBeetle.cs +++ b/Projects/Scripts/Mobiles/Monsters/SE/DeathWatchBeetle.cs @@ -98,7 +98,7 @@ namespace Server.Mobiles { if (Utility.RandomBool() && Mana > 14 && to != null) { - damage += damage / 2; + damage = damage + damage / 2; to.SendLocalizedMessage(1060091); // You take extra damage from the crushing attack! to.PlaySound(0x1E1); to.FixedParticles(0x377A, 1, 32, 0x26da, 0, 0, 0); diff --git a/Projects/Scripts/Mobiles/Monsters/SE/FanDancer.cs b/Projects/Scripts/Mobiles/Monsters/SE/FanDancer.cs index 31ce55213..998623e31 100644 --- a/Projects/Scripts/Mobiles/Monsters/SE/FanDancer.cs +++ b/Projects/Scripts/Mobiles/Monsters/SE/FanDancer.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Server.Engines.Plants; using Server.Items; +using Server.Network; namespace Server.Mobiles { @@ -84,7 +85,9 @@ namespace Server.Mobiles * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" * Damage: 50-65 */ - Effects.SendMovingEffect(Location, attacker.Location, attacker.Map, 0x27A3, 10); + Effects.SendPacket(attacker, attacker.Map, + new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x27A3, Location, attacker.Location, 10, 0, + false, false, 0, 0)); AOS.Damage(attacker, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); } } @@ -99,7 +102,9 @@ namespace Server.Mobiles * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" * Damage: 50-65 */ - Effects.SendMovingEffect(Location, attacker.Location, attacker.Map, 0x27A3, 10); + Effects.SendPacket(attacker, attacker.Map, + new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x27A3, Location, attacker.Location, 10, 0, + false, false, 0, 0)); AOS.Damage(attacker, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); } } diff --git a/Projects/Scripts/Mobiles/PlayerMobile.cs b/Projects/Scripts/Mobiles/PlayerMobile.cs index 0e02156ee..b38ba71bb 100644 --- a/Projects/Scripts/Mobiles/PlayerMobile.cs +++ b/Projects/Scripts/Mobiles/PlayerMobile.cs @@ -18,6 +18,7 @@ using Server.Guilds; using Server.Gumps; using Server.Items; using Server.Misc; +using Server.Movement; using Server.Multis; using Server.Network; using Server.Regions; @@ -203,7 +204,16 @@ namespace Server.Mobiles SkillName.TasteID }; - public override double RacialSkillBonus => Core.ML && Race == Race.Human ? 20.0 : 0; + public override double RacialSkillBonus + { + get + { + if (Core.ML && Race == Race.Human) + return 20.0; + + return 0; + } + } public List EquipSnapshot{ get; private set; } @@ -292,7 +302,15 @@ namespace Server.Mobiles public DateTime SessionStart{ get; private set; } [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan GameTime => NetState != null ? m_GameTime + (DateTime.UtcNow - SessionStart) : m_GameTime; + public TimeSpan GameTime + { + get + { + if (NetState != null) + return m_GameTime + (DateTime.UtcNow - SessionStart); + return m_GameTime; + } + } public override bool NewGuildDisplay => Guilds.Guild.NewGuildSystem; @@ -347,9 +365,13 @@ namespace Server.Mobiles BlockMountType type = MountBlockReason; if (!Alive) + { SendLocalizedMessage(1113082); // You may not fly while dead. + } else if (IsBodyMod && !(BodyMod == 666 || BodyMod == 667)) + { SendLocalizedMessage(1112453); // You can't fly in your current form! + } else if (type != BlockMountType.None) { switch (type) @@ -526,9 +548,10 @@ namespace Server.Mobiles private static void CheckPets() { foreach (Mobile m in World.Mobiles.Values) - if (m is PlayerMobile pm && ((!pm.Mounted || pm.Mount is EtherealMount) && pm.AllFollowers.Count > pm.AutoStabled.Count || - pm.Mounted && pm.AllFollowers.Count > pm.AutoStabled.Count + 1)) - pm.AutoStablePets(); /* autostable checks summons, et al: no need here */ + if (m is PlayerMobile pm) + if ((!pm.Mounted || pm.Mount is EtherealMount) && pm.AllFollowers.Count > pm.AutoStabled.Count || + pm.Mounted && pm.AllFollowers.Count > pm.AutoStabled.Count + 1) + pm.AutoStablePets(); /* autostable checks summons, et al: no need here */ } private static bool CheckBlock(MountBlock block) => block?.m_Timer.Running == true; @@ -609,8 +632,8 @@ namespace Server.Mobiles m_LastGlobalLight = global; m_LastPersonalLight = personal; - Packets.SendGlobalLightLevel(ns, (sbyte)global); - Packets.SendPersonalLightLevel(ns, Serial, (sbyte)personal); + ns.Send(GlobalLightLevel.Instantiate(global)); + ns.Send(new PersonalLightLevel(this, personal)); } public override int GetMinResistance(ResistanceType type) @@ -654,17 +677,23 @@ namespace Server.Mobiles if (!(from.Account is Account acct) || !acct.HasAccess(from.NetState)) { - notice = from.AccessLevel == AccessLevel.Player ? - "The server is currently under lockdown. No players are allowed to log in at this time." : - "The server is currently under lockdown. You do not have sufficient access level to connect."; + if (from.AccessLevel == AccessLevel.Player) + notice = "The server is currently under lockdown. No players are allowed to log in at this time."; + else + notice = + "The server is currently under lockdown. You do not have sufficient access level to connect."; - Timer.DelayCall(TimeSpan.FromSeconds(1.0), ns => ns?.Dispose(), from.NetState); + Timer.DelayCall(TimeSpan.FromSeconds(1.0), () => from.NetState?.Dispose()); } else if (from.AccessLevel >= AccessLevel.Administrator) + { notice = "The server is currently under lockdown. As you are an administrator, you may change this from the [Admin gump."; + } else + { notice = "The server is currently under lockdown. You have sufficient access level to connect."; + } from.SendGump(new NoticeGump(1060637, 30720, notice, 0xFFC000, 300, 140)); return; @@ -1021,9 +1050,13 @@ namespace Server.Mobiles return base.CanBeHarmful(target, message, ignoreOurBlessedness); } - public override bool CanBeBeneficial(Mobile target, bool message, bool allowDead) => - DesignContext == null && (!(target is PlayerMobile mobile) || mobile.DesignContext == null) && - base.CanBeBeneficial(target, message, allowDead); + public override bool CanBeBeneficial(Mobile target, bool message, bool allowDead) + { + if (DesignContext != null || target is PlayerMobile mobile && mobile.DesignContext != null) + return false; + + return base.CanBeBeneficial(target, message, allowDead); + } public override bool CheckContextMenuDisplay(IEntity target) => DesignContext == null; @@ -1083,10 +1116,12 @@ namespace Server.Mobiles int speed = ComputeMovementSpeed(d); + bool res; + if (!Alive) MovementImpl.IgnoreMovableImpassables = true; - bool res = base.Move(d); + res = base.Move(d); MovementImpl.IgnoreMovableImpassables = false; @@ -1110,7 +1145,7 @@ namespace Server.Mobiles newZ = foundation.Z + HouseFoundation.GetLevelZ(context.Level, context.Foundation); int newX = X, newY = Y; - Movement.Offset(d, ref newX, ref newY); + Movement.Movement.Offset(d, ref newX, ref newY); int startX = foundation.X + foundation.Components.Min.X + 1; int startY = foundation.Y + foundation.Components.Min.Y + 1; @@ -1847,7 +1882,7 @@ namespace Server.Mobiles pointsToGain += (int)Math.Sqrt(GameTime.TotalSeconds * 4); pointsToGain *= 5; - pointsToGain += (int)Math.Pow(Skills.Total / 250.0, 2); + pointsToGain += (int)Math.Pow(Skills.Total / 250, 2); if (VirtueHelper.Award(m, VirtueName.Justice, pointsToGain, ref gainedPath)) { @@ -1859,7 +1894,7 @@ namespace Server.Mobiles m.FixedParticles(0x375A, 9, 20, 5027, EffectLayer.Waist); m.PlaySound(0x1F7); - m_NextJustAward = DateTime.UtcNow + TimeSpan.FromMinutes(pointsToGain / 3.0); + m_NextJustAward = DateTime.UtcNow + TimeSpan.FromMinutes(pointsToGain / 3); } } } @@ -1896,8 +1931,16 @@ namespace Server.Mobiles #endregion if (m_BuffTable != null) - foreach(var buff in m_BuffTable.Values.Where(buff => !buff.RetainThroughDeath)) - RemoveBuff(buff); + { + List list = new List(); + + foreach (BuffInfo buff in m_BuffTable.Values) + if (!buff.RetainThroughDeath) + list.Add(buff); + + for (int i = 0; i < list.Count; i++) + RemoveBuff(list[i]); + } } public override bool MutateSpeech(List hears, ref string text, ref object context) @@ -1908,8 +1951,14 @@ namespace Server.Mobiles if (Core.ML && Skills.SpiritSpeak.Value >= 100.0) return false; - if (Core.AOS && hears.Any(m => m != this && m.Skills.SpiritSpeak.Value >= 100.0)) - return false; + if (Core.AOS) + for (int i = 0; i < hears.Count; ++i) + { + Mobile m = hears[i]; + + if (m != this && m.Skills.SpiritSpeak.Value >= 100.0) + return false; + } return base.MutateSpeech(hears, ref text, ref context); } @@ -1919,48 +1968,65 @@ namespace Server.Mobiles if (Guilds.Guild.NewGuildSystem && (type == MessageType.Guild || type == MessageType.Alliance)) { if (!(Guild is Guild g)) + { SendLocalizedMessage(1063142); // You are not in a guild! + } else if (type == MessageType.Alliance) { if (g.Alliance?.IsMember(g) == true) { //g.Alliance.AllianceTextMessage( hue, "[Alliance][{0}]: {1}", this.Name, text ); g.Alliance.AllianceChat(this, text); - SendToStaffMessage(this, $"[Alliance]: {text}"); + SendToStaffMessage(this, "[Alliance]: {0}", text); AllianceMessageHue = hue; } else + { SendLocalizedMessage(1071020); // You are not in an alliance! + } } else //Type == MessageType.Guild { GuildMessageHue = hue; g.GuildChat(this, text); - SendToStaffMessage(this, $"[Guild]: {text}"); + SendToStaffMessage(this, "[Guild]: {0}", text); } } else + { base.DoSpeech(text, keywords, type, hue); + } } private static void SendToStaffMessage(Mobile from, string text) { - IPooledEnumerable eable = from.GetClientsInRange(8); - foreach (NetState ns in eable) + Packet p = null; + + foreach (NetState ns in from.GetClientsInRange(8)) { Mobile mob = ns.Mobile; if (mob?.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > from.AccessLevel) - Packets.SendUnicodeMessage(ns, from.Serial, from.Body, MessageType.Regular, from.SpeechHue, 3, - from.Language, from.Name, text); + { + if (p == null) + p = Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Regular, from.SpeechHue, 3, + from.Language, from.Name, text)); + + ns.Send(p); + } } - eable.Free(); + Packet.Release(p); } - public override void Damage(int amount, Mobile from = null, bool informMount = true) + private static void SendToStaffMessage(Mobile from, string format, params object[] args) + { + SendToStaffMessage(from, string.Format(format, args)); + } + + public override void Damage(int amount, Mobile from) { if (EvilOmenSpell.TryEndEffect(this)) amount = (int)(amount * 1.25); @@ -1983,15 +2049,16 @@ namespace Server.Mobiles from.Damage(amount, this); } - if (from != null && Talisman is BaseTalisman talisman && talisman.Protection != null && talisman.Protection.Type != null) - { - Type type = talisman.Protection.Type; + if (from != null && Talisman is BaseTalisman talisman) + if (talisman.Protection != null && talisman.Protection.Type != null) + { + Type type = talisman.Protection.Type; - if (type.IsInstanceOfType(from)) - amount = (int)(amount * (1 - (double)talisman.Protection.Amount / 100)); - } + if (type.IsInstanceOfType(from)) + amount = (int)(amount * (1 - (double)talisman.Protection.Amount / 100)); + } - base.Damage(amount, from, informMount); + base.Damage(amount, from); } public override bool IsHarmfulCriminal(Mobile target) @@ -2291,23 +2358,32 @@ namespace Server.Mobiles } } - RecentlyReported ??= new List(); + if (RecentlyReported == null) + RecentlyReported = new List(); // Professions weren't verified on 1.0 RC0 if (!CharacterCreation.VerifyProfession(Profession)) Profession = 0; - PermaFlags ??= new List(); - JusticeProtectors ??= new List(); - BOBFilter ??= new BOBFilter(); + if (PermaFlags == null) + PermaFlags = new List(); - //Default to member if going from older version to new version (only time it should be null) - m_GuildRank ??= RankDefinition.Member; + if (JusticeProtectors == null) + JusticeProtectors = new List(); + + if (BOBFilter == null) + BOBFilter = new BOBFilter(); + + if (m_GuildRank == null) + m_GuildRank = + RankDefinition + .Member; //Default to member if going from older version to new version (only time it should be null) if (LastOnline == DateTime.MinValue && Account != null) LastOnline = ((Account)Account).LastLogin; - ChampionTitles ??= new ChampionTitleInfo(); + if (ChampionTitles == null) + ChampionTitles = new ChampionTitleInfo(); if (AccessLevel > AccessLevel.Player) m_IgnoreMobiles = true; @@ -2721,10 +2797,9 @@ namespace Server.Mobiles for (int i = AutoStabled.Count - 1; i >= 0; --i) { - if (!(AutoStabled[i] is BaseCreature pet)) - return; + BaseCreature pet = AutoStabled[i] as BaseCreature; - if (pet.Deleted) + if (pet?.Deleted == true) { pet.IsStabled = false; pet.StabledBy = null; @@ -2756,8 +2831,10 @@ namespace Server.Mobiles Stabled.Remove(pet); } else + { SendLocalizedMessage(1049612, pet.Name); // ~1_NAME~ remained in the stables because you have too many followers. + } } AutoStabled.Clear(); @@ -2825,7 +2902,7 @@ namespace Server.Mobiles public bool NinjaWepCooldown{ get; set; } - public List AllFollowers => m_AllFollowers ??= new List(); + public List AllFollowers => m_AllFollowers ?? (m_AllFollowers = new List()); public RankDefinition GuildRank { @@ -3006,14 +3083,14 @@ namespace Server.Mobiles if (!Core.SE || !Alive) return; - foreach (var (key, value) in RecoverableAmmo) - if (value > 0) + foreach (KeyValuePair kvp in RecoverableAmmo) + if (kvp.Value > 0) { Item ammo = null; try { - ammo = Activator.CreateInstance(key) as Item; + ammo = Activator.CreateInstance(kvp.Key) as Item; } catch { @@ -3023,7 +3100,7 @@ namespace Server.Mobiles if (ammo == null) continue; string name = ammo.Name; - ammo.Amount = value; + ammo.Amount = kvp.Value; if (name == null) { @@ -3103,21 +3180,39 @@ namespace Server.Mobiles [CommandProperty(AccessLevel.GameMaster)] public override int Str { - get => Core.ML && AccessLevel == AccessLevel.Player ? Math.Min(base.Str, 150) : base.Str; + get + { + if (Core.ML && AccessLevel == AccessLevel.Player) + return Math.Min(base.Str, 150); + + return base.Str; + } set => base.Str = value; } [CommandProperty(AccessLevel.GameMaster)] public override int Int { - get => Core.ML && AccessLevel == AccessLevel.Player ? Math.Min(base.Int, 150) : base.Int; + get + { + if (Core.ML && AccessLevel == AccessLevel.Player) + return Math.Min(base.Int, 150); + + return base.Int; + } set => base.Int = value; } [CommandProperty(AccessLevel.GameMaster)] public override int Dex { - get => Core.ML && AccessLevel == AccessLevel.Player ? Math.Min(base.Dex, 150) : base.Dex; + get + { + if (Core.ML && AccessLevel == AccessLevel.Player) + return Math.Min(base.Dex, 150); + + return base.Dex; + } set => base.Dex = value; } @@ -3136,16 +3231,36 @@ namespace Server.Mobiles SendLocalizedMessage(1060868); // Target the item you wish to toggle insurance status on to cancel } - private bool CanInsure(Item item) => - (!(item is Container) || item is BaseQuiver) && !(item is BagOfSending) && !(item is KeyRing) && - !(item is PotionKeg) && !(item is Sigil) && !item.Stackable && item.LootType != LootType.Cursed && - item.ItemID != 0x204E && item.Layer != Layer.Mount && item.LootType != LootType.Blessed && - item.LootType != LootType.Newbied && item.BlessedFor != this; + private bool CanInsure(Item item) + { + if (item is Container && !(item is BaseQuiver) || item is BagOfSending || item is KeyRing || item is PotionKeg || + item is Sigil) + return false; + + if (item.Stackable) + return false; + + if (item.LootType == LootType.Cursed) + return false; + + if (item.ItemID == 0x204E) // death shroud + return false; + + if (item.Layer == Layer.Mount) + return false; + + if (item.LootType == LootType.Blessed || item.LootType == LootType.Newbied || item.BlessedFor == this) + return false; + + return true; + } private void ToggleItemInsurance_Callback(Mobile from, object obj) { - if (CheckAlive()) - ToggleItemInsurance_Callback(from, obj as Item, true); + if (!CheckAlive()) + return; + + ToggleItemInsurance_Callback(from, obj as Item, true); } private void ToggleItemInsurance_Callback(Mobile from, Item item, bool target) @@ -3275,7 +3390,9 @@ namespace Server.Mobiles m_Player.AutoRenewInsurance = false; } else + { m_Player.SendLocalizedMessage(1042021); // Cancelled. + } if (m_InsuranceGump != null) m_Player.SendGump(m_InsuranceGump.NewInstance()); @@ -3287,7 +3404,11 @@ namespace Server.Mobiles if (!CheckAlive()) return; - List items = Items.Where(DisplayInItemInsuranceGump).ToList(); + List items = new List(); + + foreach (Item item in Items) + if (DisplayInItemInsuranceGump(item)) + items.Add(item); Container pack = Backpack; @@ -3358,7 +3479,11 @@ namespace Server.Mobiles AddHtmlLocalized(400, 54, 70, 20, 1114311, 0x7FFF); // Insured int balance = Banker.GetBalance(from); - int cost = items.Where((t, i) => insure[i]).Sum(GetInsuranceCost); + int cost = 0; + + for (int i = 0; i < items.Length; ++i) + if (insure[i]) + cost += GetInsuranceCost(items[i]); AddHtmlLocalized(15, 420, 300, 20, 1114310, 0x7FFF); // GOLD AVAILABLE: AddLabel(215, 420, 0x481, balance.ToString()); @@ -3577,12 +3702,20 @@ namespace Server.Mobiles private DateTime[] m_StuckMenuUses; - public bool CanUseStuckMenu() => - m_StuckMenuUses?.Any(t => DateTime.UtcNow - t > TimeSpan.FromDays(1.0)) != false; + public bool CanUseStuckMenu() + { + if (m_StuckMenuUses == null) return true; + + for (int i = 0; i < m_StuckMenuUses.Length; ++i) + if (DateTime.UtcNow - m_StuckMenuUses[i] > TimeSpan.FromDays(1.0)) + return true; + + return false; + } public void UsedStuckMenu() { - m_StuckMenuUses ??= new DateTime[2]; + if (m_StuckMenuUses == null) m_StuckMenuUses = new DateTime[2]; for (int i = 0; i < m_StuckMenuUses.Length; ++i) if (DateTime.UtcNow - m_StuckMenuUses[i] > TimeSpan.FromDays(1.0)) @@ -3646,7 +3779,10 @@ namespace Server.Mobiles m_DuelPlayer = value; - DuelContext = m_DuelPlayer?.Participant.Context; + if (m_DuelPlayer == null) + DuelContext = null; + else + DuelContext = m_DuelPlayer.Participant.Context; bool isInTourney = DuelContext?.Finished == false && DuelContext.m_Tournament != null; @@ -3809,14 +3945,22 @@ namespace Server.Mobiles private void DeltaEnemies(Type oldType, Type newType) { - NetState ns = NetState; - foreach (Mobile m in GetMobilesInRange(18)) { Type t = m.GetType(); if (t == oldType || t == newType) - Packets.SendMobileMoving(NetState, m, Notoriety.Compute(this, m)); + { + NetState ns = NetState; + + if (ns != null) + { + if (ns.StygianAbyss) + ns.Send(new MobileMoving(m, Notoriety.Compute(this, m))); + else + ns.Send(new MobileMovingOld(m, Notoriety.Compute(this, m))); + } + } } } @@ -3976,8 +4120,13 @@ namespace Server.Mobiles return base.ApplyNameSuffix(suffix); } - public override TimeSpan GetLogoutDelay() => - Young || BedrollLogout || TestCenter.Enabled ? TimeSpan.Zero : base.GetLogoutDelay(); + public override TimeSpan GetLogoutDelay() + { + if (Young || BedrollLogout || TestCenter.Enabled) + return TimeSpan.Zero; + + return base.GetLogoutDelay(); + } private DateTime m_LastYoungMessage = DateTime.MinValue; @@ -4018,7 +4167,7 @@ namespace Server.Mobiles return false; } - private static readonly Point3D[] m_TrammelDeathDestinations = + private static Point3D[] m_TrammelDeathDestinations = { new Point3D(1481, 1612, 20), new Point3D(2708, 2153, 0), @@ -4037,7 +4186,7 @@ namespace Server.Mobiles new Point3D(3665, 2587, 0) }; - private static readonly Point3D[] m_IlshenarDeathDestinations = + private static Point3D[] m_IlshenarDeathDestinations = { new Point3D(1216, 468, -13), new Point3D(723, 1367, -60), @@ -4050,13 +4199,13 @@ namespace Server.Mobiles new Point3D(1722, 219, 96) }; - private static readonly Point3D[] m_MalasDeathDestinations = + private static Point3D[] m_MalasDeathDestinations = { new Point3D(2079, 1376, -70), new Point3D(944, 519, -71) }; - private static readonly Point3D[] m_TokunoDeathDestinations = + private static Point3D[] m_TokunoDeathDestinations = { new Point3D(1166, 801, 27), new Point3D(782, 1228, 25), @@ -4136,7 +4285,9 @@ namespace Server.Mobiles { if (SpeechLog.Enabled && NetState != null) { - SpeechLog ??= new SpeechLog(); + if (SpeechLog == null) + SpeechLog = new SpeechLog(); + SpeechLog.Add(e.Mobile, e.Speech); } } @@ -4284,7 +4435,8 @@ namespace Server.Mobiles if (m_Values == null || index < 0 || index >= m_Values.Length) return 0; - m_Values[index] ??= new TitleInfo(); + if (m_Values[index] == null) + m_Values[index] = new TitleInfo(); return m_Values[index].Value; } @@ -4294,14 +4446,16 @@ namespace Server.Mobiles if (m_Values == null || index < 0 || index >= m_Values.Length) return DateTime.MinValue; - m_Values[index] ??= new TitleInfo(); + if (m_Values[index] == null) + m_Values[index] = new TitleInfo(); return m_Values[index].LastDecay; } public void SetValue(int index, int value) { - m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; + if (m_Values == null) + m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; if (value < 0) value = 0; @@ -4309,31 +4463,36 @@ namespace Server.Mobiles if (index < 0 || index >= m_Values.Length) return; - m_Values[index] ??= new TitleInfo(); + if (m_Values[index] == null) + m_Values[index] = new TitleInfo(); m_Values[index].Value = value; } public void Award(int index, int value) { - m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; + if (m_Values == null) + m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; if (index < 0 || index >= m_Values.Length || value <= 0) return; - m_Values[index] ??= new TitleInfo(); + if (m_Values[index] == null) + m_Values[index] = new TitleInfo(); m_Values[index].Value += value; } public void Atrophy(int index, int value) { - m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; + if (m_Values == null) + m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; if (index < 0 || index >= m_Values.Length || value <= 0) return; - m_Values[index] ??= new TitleInfo(); + if (m_Values[index] == null) + m_Values[index] = new TitleInfo(); int before = m_Values[index].Value; @@ -4359,7 +4518,9 @@ namespace Server.Mobiles for (int i = 0; i < length; i++) { - titles.m_Values[i] ??= new TitleInfo(); + if (titles.m_Values[i] == null) + titles.m_Values[i] = new TitleInfo(); + TitleInfo.Serialize(writer, titles.m_Values[i]); } } @@ -4370,7 +4531,8 @@ namespace Server.Mobiles if (t == null) return; - t.m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; + if (t.m_Values == null) + t.m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; for (int i = 0; i < t.m_Values.Length; i++) if (t.GetLastDecay(i) + LossDelay < DateTime.UtcNow) @@ -4384,8 +4546,16 @@ namespace Server.Mobiles if (t == null) return; - t.m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; - t.Harrower = Math.Max(1 + t.m_Values.Count(t1 => t1.Value > 900), t.Harrower); //Harrower titles never decay. + if (t.m_Values == null) + t.m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; + + int count = 1; + + for (int i = 0; i < t.m_Values.Length; i++) + if (t.m_Values[i].Value > 900) + count++; + + t.Harrower = Math.Max(count, t.Harrower); //Harrower titles never decay. } private class TitleInfo @@ -4441,7 +4611,9 @@ namespace Server.Mobiles public virtual void AcquireRecipe(int recipeID) { - m_AcquiredRecipes ??= new Dictionary(); + if (m_AcquiredRecipes == null) + m_AcquiredRecipes = new Dictionary(); + m_AcquiredRecipes[recipeID] = true; } @@ -4459,11 +4631,12 @@ namespace Server.Mobiles public void ResendBuffs() { - if (!BuffInfo.Enabled || m_BuffTable == null || NetState?.BuffIcon != true) + if (!BuffInfo.Enabled || m_BuffTable == null) return; - foreach (BuffInfo info in m_BuffTable.Values) - BuffPackets.SendAddBuff(this, info); + if (NetState?.BuffIcon == true) + foreach (BuffInfo info in m_BuffTable.Values) + NetState.Send(new AddBuffPacket(this, info)); } private Dictionary m_BuffTable; @@ -4481,7 +4654,7 @@ namespace Server.Mobiles m_BuffTable.Add(b.ID, b); if (NetState?.BuffIcon == true) - BuffPackets.SendAddBuff(this, b); + NetState.Send(new AddBuffPacket(this, b)); } public void RemoveBuff(BuffInfo b) @@ -4505,7 +4678,7 @@ namespace Server.Mobiles m_BuffTable.Remove(b); if (NetState?.BuffIcon == true) - BuffPackets.SendRemoveBuffPacket(NetState, Serial, (int)b); + NetState.Send(new RemoveBuffPacket(this, b)); if (m_BuffTable.Count <= 0) m_BuffTable = null; diff --git a/Projects/Scripts/Mobiles/Special/ChaosGuard.cs b/Projects/Scripts/Mobiles/Special/ChaosGuard.cs index 0c96e9297..a7ad50117 100644 --- a/Projects/Scripts/Mobiles/Special/ChaosGuard.cs +++ b/Projects/Scripts/Mobiles/Special/ChaosGuard.cs @@ -1,3 +1,4 @@ +using Server.Guilds; using Server.Items; namespace Server.Mobiles diff --git a/Projects/Scripts/Mobiles/Special/Harrower.cs b/Projects/Scripts/Mobiles/Special/Harrower.cs index 863ed402c..59a0bf1a7 100644 --- a/Projects/Scripts/Mobiles/Special/Harrower.cs +++ b/Projects/Scripts/Mobiles/Special/Harrower.cs @@ -398,24 +398,24 @@ namespace Server.Mobiles Dictionary validEntries = new Dictionary(); - foreach (var (key, value) in m_DamageEntries) - if (IsEligible(key, artifact)) + foreach (KeyValuePair kvp in m_DamageEntries) + if (IsEligible(kvp.Key, artifact)) { - validEntries.Add(key, value); - totalDamage += value; + validEntries.Add(kvp.Key, kvp.Value); + totalDamage += kvp.Value; } int randomDamage = Utility.RandomMinMax(1, totalDamage); totalDamage = 0; - foreach (var (key, value) in validEntries) + foreach (KeyValuePair kvp in validEntries) { - totalDamage += value; + totalDamage += kvp.Value; if (totalDamage >= randomDamage) { - GiveArtifact(key, artifact); + GiveArtifact(kvp.Key, artifact); return; } } diff --git a/Projects/Scripts/Mobiles/Special/Mephitis.cs b/Projects/Scripts/Mobiles/Special/Mephitis.cs index 13fb0d633..2c80b0802 100644 --- a/Projects/Scripts/Mobiles/Special/Mephitis.cs +++ b/Projects/Scripts/Mobiles/Special/Mephitis.cs @@ -68,7 +68,12 @@ namespace Server.Mobiles AddLoot(LootPack.UltraRich, 4); } - // TODO: Web Ability + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + // TODO: Web ability + } public override void Serialize(GenericWriter writer) { @@ -84,4 +89,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Special/OrderGuard.cs b/Projects/Scripts/Mobiles/Special/OrderGuard.cs index b46e23ce0..e3db5a597 100644 --- a/Projects/Scripts/Mobiles/Special/OrderGuard.cs +++ b/Projects/Scripts/Mobiles/Special/OrderGuard.cs @@ -1,3 +1,4 @@ +using Server.Guilds; using Server.Items; namespace Server.Mobiles diff --git a/Projects/Scripts/Mobiles/Special/Semidar.cs b/Projects/Scripts/Mobiles/Special/Semidar.cs index c4f6dc568..4f01a0747 100644 --- a/Projects/Scripts/Mobiles/Special/Semidar.cs +++ b/Projects/Scripts/Mobiles/Special/Semidar.cs @@ -71,7 +71,8 @@ namespace Server.Mobiles public override void CheckReflect(Mobile caster, ref bool reflect) { - reflect |= caster.Body.IsMale; // Always reflect if caster isn't female + if (caster.Body.IsMale) + reflect = true; // Always reflect if caster isn't female } public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) diff --git a/Projects/Scripts/Mobiles/Townfolk/Banker.cs b/Projects/Scripts/Mobiles/Townfolk/Banker.cs index 84daa5cd0..1d7d3c6f8 100644 --- a/Projects/Scripts/Mobiles/Townfolk/Banker.cs +++ b/Projects/Scripts/Mobiles/Townfolk/Banker.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Server.Accounting; using Server.ContextMenus; using Server.Items; using Server.Network; @@ -283,16 +284,22 @@ namespace Server.Mobiles break; if (!Core.ML && amount > 5000 || Core.ML && amount > 60000) + { Say(500381); // Thou canst not withdraw so much at one time! + } else if (pack?.Deleted != false || !(pack.TotalWeight < pack.MaxWeight) || !(pack.TotalItems < pack.MaxItems)) + { Say(1048147); // Your backpack can't hold anything else. + } else if (amount > 0) { BankBox box = e.Mobile.FindBankNoCreate(); if (box == null || !Withdraw(e.Mobile, amount)) + { Say(500384); // Ah, art thou trying to fool me? Thou hast not so much gold! + } else { pack.DropItem(new Gold(amount)); @@ -358,9 +365,13 @@ namespace Server.Mobiles break; if (amount < 5000) + { Say(1010006); // We cannot create checks for such a paltry amount of gold! + } else if (amount > 1000000) + { Say(1010007); // Our policies prevent us from creating checks worth that much! + } else { BankCheck check = new BankCheck(amount); diff --git a/Projects/Scripts/Mobiles/Townfolk/BrideGroom.cs b/Projects/Scripts/Mobiles/Townfolk/BrideGroom.cs index 40f372cd4..027273089 100644 --- a/Projects/Scripts/Mobiles/Townfolk/BrideGroom.cs +++ b/Projects/Scripts/Mobiles/Townfolk/BrideGroom.cs @@ -50,7 +50,10 @@ namespace Server.Mobiles else AddItem(new Boots(lowHue)); - HairItemID = Utility.RandomBool() ? 0x203B : 0x203C; + if (Utility.RandomBool()) + HairItemID = 0x203B; + else + HairItemID = 0x203C; HairHue = Race.RandomHairHue(); @@ -71,4 +74,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Townfolk/EscortableMage.cs b/Projects/Scripts/Mobiles/Townfolk/EscortableMage.cs index 624dea558..b97d80c54 100644 --- a/Projects/Scripts/Mobiles/Townfolk/EscortableMage.cs +++ b/Projects/Scripts/Mobiles/Townfolk/EscortableMage.cs @@ -68,4 +68,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Townfolk/Merchant.cs b/Projects/Scripts/Mobiles/Townfolk/Merchant.cs index 159f6557c..e80c8faa6 100644 --- a/Projects/Scripts/Mobiles/Townfolk/Merchant.cs +++ b/Projects/Scripts/Mobiles/Townfolk/Merchant.cs @@ -77,4 +77,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Townfolk/Messenger.cs b/Projects/Scripts/Mobiles/Townfolk/Messenger.cs index 5c909af23..69a8e6908 100644 --- a/Projects/Scripts/Mobiles/Townfolk/Messenger.cs +++ b/Projects/Scripts/Mobiles/Townfolk/Messenger.cs @@ -66,4 +66,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Townfolk/Noble.cs b/Projects/Scripts/Mobiles/Townfolk/Noble.cs index b603bc051..994996a55 100644 --- a/Projects/Scripts/Mobiles/Townfolk/Noble.cs +++ b/Projects/Scripts/Mobiles/Townfolk/Noble.cs @@ -78,4 +78,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Townfolk/Peasant.cs b/Projects/Scripts/Mobiles/Townfolk/Peasant.cs index 4658c9c01..61619ac87 100644 --- a/Projects/Scripts/Mobiles/Townfolk/Peasant.cs +++ b/Projects/Scripts/Mobiles/Townfolk/Peasant.cs @@ -71,4 +71,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs b/Projects/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs index a8da80d46..2d34b17a7 100644 --- a/Projects/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs +++ b/Projects/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs @@ -26,7 +26,12 @@ namespace Server.Mobiles public override bool ClickTitle => false; // Do not display 'the seeker of adventure' when single-clicking - public override string[] GetPossibleDestinations() => Core.ML ? m_MLDestinations : m_Dungeons; + public override string[] GetPossibleDestinations() + { + if (Core.ML) + return m_MLDestinations; + return m_Dungeons; + } private static int GetRandomHue() { @@ -84,4 +89,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Townfolk/TownCrier.cs b/Projects/Scripts/Mobiles/Townfolk/TownCrier.cs index 41f9c7a1c..b151f5da7 100644 --- a/Projects/Scripts/Mobiles/Townfolk/TownCrier.cs +++ b/Projects/Scripts/Mobiles/Townfolk/TownCrier.cs @@ -4,6 +4,7 @@ using System.Text; using Server.Gumps; using Server.Items; using Server.Network; +using Server.Prompts; namespace Server.Mobiles { @@ -19,7 +20,7 @@ namespace Server.Mobiles { private static GlobalTownCrierEntryList m_Instance; - public static GlobalTownCrierEntryList Instance => m_Instance ??= new GlobalTownCrierEntryList(); + public static GlobalTownCrierEntryList Instance => m_Instance ?? (m_Instance = new GlobalTownCrierEntryList()); public bool IsEmpty => Entries == null || Entries.Count == 0; @@ -49,7 +50,8 @@ namespace Server.Mobiles public TownCrierEntry AddEntry(string[] lines, TimeSpan duration) { - Entries ??= new List(); + if (Entries == null) + Entries = new List(); TownCrierEntry tce = new TownCrierEntry(lines, duration); @@ -382,7 +384,8 @@ namespace Server.Mobiles public TownCrierEntry AddEntry(string[] lines, TimeSpan duration) { - Entries ??= new List(); + if (Entries == null) + Entries = new List(); TownCrierEntry tce = new TownCrierEntry(lines, duration); diff --git a/Projects/Scripts/Mobiles/Vendors/BaseVendor.cs b/Projects/Scripts/Mobiles/Vendors/BaseVendor.cs index ec3c64456..639565a01 100644 --- a/Projects/Scripts/Mobiles/Vendors/BaseVendor.cs +++ b/Projects/Scripts/Mobiles/Vendors/BaseVendor.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.ContextMenus; using Server.Engines.BulkOrders; using Server.Factions; @@ -25,10 +24,10 @@ namespace Server.Mobiles { private const int MaxSell = 500; - private static readonly TimeSpan InventoryDecayTime = TimeSpan.FromHours(1.0); + private static TimeSpan InventoryDecayTime = TimeSpan.FromHours(1.0); - private readonly List m_ArmorBuyInfo = new List(); - private readonly List m_ArmorSellInfo = new List(); + private List m_ArmorBuyInfo = new List(); + private List m_ArmorSellInfo = new List(); public BaseVendor(string title = null) : base(AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2) @@ -126,6 +125,7 @@ namespace Server.Mobiles IShopSellInfo[] info = GetSellInfo(); int totalCost = 0; List validBuy = new List(list.Count); + bool bought; bool fromBank = false; bool fullPurchase = true; int controlSlots = buyer.FollowersMax - buyer.Followers; @@ -188,7 +188,7 @@ namespace Server.Mobiles if (validBuy.Count == 0) return false; - bool bought = buyer.AccessLevel >= AccessLevel.GameMaster; + bought = buyer.AccessLevel >= AccessLevel.GameMaster; Container cont = buyer.Backpack; if (!bought && cont != null) @@ -259,9 +259,8 @@ namespace Server.Mobiles if (cont?.TryDropItem(buyer, buyItem, false) != true) buyItem.MoveToWorld(buyer.Location, buyer.Map); - if (cont?.TryDropItem(buyer, buyItem, false) != true) - buyItem.MoveToWorld(buyer.Location, buyer.Map); - } + break; + } } } else if (ser.IsMobile) @@ -310,7 +309,10 @@ namespace Server.Mobiles public virtual bool OnSellItems(Mobile seller, List list) { - if (!(IsActiveBuyer && seller.CheckAlive())) + if (!IsActiveBuyer) + return false; + + if (!seller.CheckAlive()) return false; if (!CheckVendorAccess(seller)) @@ -332,7 +334,12 @@ namespace Server.Mobiles !resp.Item.Movable || resp.Item is Container container && container.Items.Count != 0) continue; - if (info.Any(ssi => ssi.IsSellable(resp.Item))) Sold++; + foreach (IShopSellInfo ssi in info) + if (ssi.IsSellable(resp.Item)) + { + Sold++; + break; + } } if (Sold > MaxSell) @@ -361,11 +368,14 @@ namespace Server.Mobiles { bool found = false; - if (buyInfo.Any(bii => bii.Restock(resp.Item, amount))) - { - resp.Item.Consume(amount); - found = true; - } + foreach (IBuyItemInfo bii in buyInfo) + if (bii.Restock(resp.Item, amount)) + { + resp.Item.Consume(amount); + found = true; + + break; + } if (!found) { @@ -512,9 +522,11 @@ namespace Server.Mobiles if (CheckGargoyle()) return; - public virtual int GetShoeHue() => 0.1 > Utility.RandomDouble() ? 0 : Utility.RandomNeutralHue(); + if (CheckNecromancer()) + return; - public virtual bool CheckMorph() => CheckGargoyle() || CheckNecromancer() || CheckTokuno(); + CheckTokuno(); + } public virtual bool CheckTokuno() { @@ -536,7 +548,12 @@ namespace Server.Mobiles public virtual bool CheckGargoyle() { - if (!(Map == Map.Ilshenar && Region.IsPartOf("Gargoyle City"))) + Map map = Map; + + if (map != Map.Ilshenar) + return false; + + if (!Region.IsPartOf("Gargoyle City")) return false; if (Body != 0x2F6 || (Hue & 0x8000) == 0) @@ -547,7 +564,12 @@ namespace Server.Mobiles public virtual bool CheckNecromancer() { - if (!(Map == Map.Malas && Region.IsPartOf("Umbra"))) + Map map = Map; + + if (map != Map.Malas) + return false; + + if (!Region.IsPartOf("Umbra")) return false; if (Hue != 0x83E8) @@ -617,10 +639,12 @@ namespace Server.Mobiles public virtual void CapitalizeTitle() { - if (Title == null) + string title = Title; + + if (title == null) return; - string[] split = Title.Split(' '); + string[] split = title.Split(' '); for (int i = 0; i < split.Length; ++i) { @@ -706,7 +730,10 @@ namespace Server.Mobiles public virtual void VendorBuy(Mobile from) { - if (!(IsActiveSeller && from.CheckAlive())) + if (!IsActiveSeller) + return; + + if (!from.CheckAlive()) return; if (!CheckVendorAccess(from)) @@ -797,13 +824,25 @@ namespace Server.Mobiles NetState ns = from.NetState; - Packets.SendVendorBuyContent(ns, list); - Packets.SendVendorBuyList(ns, this, list); - Packets.SendDisplayBuyList(ns, this.Serial); - Packets.SendMobileStatusExtended(ns, from); //make sure their gold amount is sent + if (ns == null) + return; + + if (ns.ContainerGridLines) + from.Send(new VendorBuyContent6017(list)); + else + from.Send(new VendorBuyContent(list)); + + from.Send(new VendorBuyList(this, list)); + + if (ns.HighSeas) + from.Send(new DisplayBuyListHS(this)); + else + from.Send(new DisplayBuyList(this)); + + from.Send(new MobileStatusExtended(from)); //make sure their gold amount is sent for (int i = 0; i < opls.Count; ++i) - opls[i].Send(ns); + from.Send(opls[i]); SayTo(from, 500186); // Greetings. Have a look around. } @@ -818,14 +857,12 @@ namespace Server.Mobiles AddItem(pack); } - NetState ns = from.NetState; - - Packets.SendEquipUpdate(ns, pack); + from.Send(new EquipUpdate(pack)); pack = FindItemOnLayer(Layer.ShopSell); if (pack != null) - Packets.SendEquipUpdate(ns, pack); + from.Send(new EquipUpdate(pack)); pack = FindItemOnLayer(Layer.ShopResale); @@ -835,12 +872,15 @@ namespace Server.Mobiles AddItem(pack); } - Packets.SendEquipUpdate(ns, pack); + from.Send(new EquipUpdate(pack)); } public virtual void VendorSell(Mobile from) { - if (!(IsActiveBuyer && from.CheckAlive())) + if (!IsActiveBuyer) + return; + + if (!from.CheckAlive()) return; if (!CheckVendorAccess(from)) @@ -871,10 +911,13 @@ namespace Server.Mobiles if (list.Count > 0) { SendPacksTo(from); - Packets.SendVendorSellList(from.NetState, Serial, list); + + from.Send(new VendorSellList(this, list)); } else + { Say(true, "You have nothing I would be interested in."); + } } public override bool OnDragDrop(Mobile from, Item dropped) @@ -949,7 +992,7 @@ namespace Server.Mobiles return null; } - private void ProcessSinglePurchase(BuyItemResponse buy, IBuyItemInfo bii, ICollection validBuy, + private void ProcessSinglePurchase(BuyItemResponse buy, IBuyItemInfo bii, List validBuy, ref int controlSlots, ref bool fullPurchase, ref int totalCost) { int amount = buy.Amount; @@ -963,7 +1006,9 @@ namespace Server.Mobiles int slots = bii.ControlSlots * amount; if (controlSlots >= slots) + { controlSlots -= slots; + } else { fullPurchase = false; @@ -1140,9 +1185,10 @@ namespace Server.Mobiles } } - IsParagon = false; + if (IsParagon) + IsParagon = false; - Timer.DelayCall(TimeSpan.Zero, () => CheckMorph()); + Timer.DelayCall(TimeSpan.Zero, CheckMorph); } public override void AddCustomContextEntries(Mobile from, List list) @@ -1242,7 +1288,8 @@ namespace Server.ContextMenus { private BaseVendor m_Vendor; - public VendorBuyEntry(Mobile from, BaseVendor vendor) : base(6103, 8) + public VendorBuyEntry(Mobile from, BaseVendor vendor) + : base(6103, 8) { m_Vendor = vendor; Enabled = vendor.CheckVendorAccess(from); @@ -1258,7 +1305,8 @@ namespace Server.ContextMenus { private BaseVendor m_Vendor; - public VendorSellEntry(Mobile from, BaseVendor vendor) : base(6104, 8) + public VendorSellEntry(Mobile from, BaseVendor vendor) + : base(6104, 8) { m_Vendor = vendor; Enabled = vendor.CheckVendorAccess(from); diff --git a/Projects/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs b/Projects/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs index a909923b7..535d1cb4e 100644 --- a/Projects/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs +++ b/Projects/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs @@ -84,7 +84,10 @@ namespace Server.Mobiles return max; } - private void CloseClaimList(Mobile from) => from.CloseGump(); + private void CloseClaimList(Mobile from) + { + from.CloseGump(); + } public void BeginClaimList(Mobile from) { @@ -138,7 +141,9 @@ namespace Server.Mobiles (from as PlayerMobile)?.AutoStabled.Remove(pet); } else + { SayTo(from, 1049612, pet.Name); // ~1_NAME~ remained in the stables because you have too many followers. + } } public void BeginStable(Mobile from) @@ -171,25 +176,43 @@ namespace Server.Mobiles return; if (pet.Body.IsHuman) - SayTo(from, 502672); // HA HA HA! Sorry, I am not an inn. - else if (!pet.Controlled) - SayTo(from, 1048053); // You can't stable that! - else if (pet.ControlMaster != from) - SayTo(from, 1042562); // You do not own that pet! - else if (pet.IsDeadPet) - SayTo(from, 1049668); // Living pets only, please. - else if (pet.Summoned) - SayTo(from, 502673); // I can not stable summoned creatures. - /*else if ( pet.Allured ) { - SayTo( from, 1048053 ); // You can't stable that! - }*/ + SayTo(from, 502672); // HA HA HA! Sorry, I am not an inn. + } + else if (!pet.Controlled) + { + SayTo(from, 1048053); // You can't stable that! + } + else if (pet.ControlMaster != from) + { + SayTo(from, 1042562); // You do not own that pet! + } + else if (pet.IsDeadPet) + { + SayTo(from, 1049668); // Living pets only, please. + } + else if (pet.Summoned) + { + SayTo(from, 502673); // I can not stable summoned creatures. + } +/* + else if ( pet.Allured ) + { + SayTo( from, 1048053 ); // You can't stable that! + } +*/ else if ((pet is PackLlama || pet is PackHorse || pet is Beetle) && pet.Backpack?.Items.Count > 0) + { SayTo(from, 1042563); // You need to unload your pet. + } else if (pet.Combatant != null && pet.InRange(pet.Combatant, 12) && pet.Map == pet.Combatant.Map) + { SayTo(from, 1042564); // I'm sorry. Your pet seems to be busy. + } else if (from.Stabled.Count >= GetMaxStabled(from)) + { SayTo(from, 1042565); // You have too many pets in the stables! + } else { Container bank = from.FindBankNoCreate(); @@ -218,7 +241,9 @@ namespace Server.Mobiles : 502679); // [AOS: Your pet has been stabled.] Very well, thy pet is stabled. Thou mayst recover it by saying 'claim' to me. In one real world week, I shall sell it off if it is not claimed! } else + { SayTo(from, 502677); // But thou hast not the funds in thy bank account! + } } } @@ -238,11 +263,8 @@ namespace Server.Mobiles if (pet?.Deleted != false) { - if (pet != null) - { - pet.IsStabled = false; - pet.StabledBy = null; - } + pet.IsStabled = false; + pet.StabledBy = null; from.Stabled.RemoveAt(i); --i; continue; @@ -281,7 +303,7 @@ namespace Server.Mobiles public bool CanClaim(Mobile from, BaseCreature pet) => from.Followers + pet.ControlSlots <= from.FollowersMax; - private static void DoClaim(Mobile from, BaseCreature pet) + private void DoClaim(Mobile from, BaseCreature pet) { pet.SetControlMaster(from); diff --git a/Projects/Scripts/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs b/Projects/Scripts/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs index eab2fecb4..de015a30a 100644 --- a/Projects/Scripts/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs +++ b/Projects/Scripts/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs @@ -44,13 +44,24 @@ namespace Server.Mobiles public virtual void SayPriceTo(Mobile m) { - Packets.SendMessageLocalizedAffix(m.NetState, Serial, Body, MessageType.Regular, SpeechHue, 3, 1008052, Name, - AffixType.Append, JoinCost.ToString()); + m.Send(new MessageLocalizedAffix(Serial, Body, MessageType.Regular, SpeechHue, 3, 1008052, Name, + AffixType.Append, JoinCost.ToString(), "")); } - public virtual bool WasNamed(string speech) => Name != null && Insensitive.StartsWith(speech, Name); + public virtual bool WasNamed(string speech) + { + string name = Name; - public override bool HandlesOnSpeech(Mobile from) => from.InRange(Location, 2) || base.HandlesOnSpeech(from); + return name != null && Insensitive.StartsWith(speech, name); + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from.InRange(Location, 2)) + return true; + + return base.HandlesOnSpeech(from); + } public override void OnSpeech(SpeechEventArgs e) { @@ -74,10 +85,14 @@ namespace Server.Mobiles else if (e.HasKeyword(0x0005)) // *resign* | *quit* { if (pm.NpcGuild != NpcGuild) + { SayTo(pm, 501052); // Thou dost not belong to my guild! + } else if (pm.NpcGuildJoinTime + QuitAge > DateTime.UtcNow || pm.NpcGuildGameTime + QuitGameAge > pm.GameTime) + { SayTo(pm, 501053); // You just joined my guild! You must wait a week to resign. + } else { SayTo(pm, 501054); // I accept thy resignation. @@ -96,11 +111,17 @@ namespace Server.Mobiles if (from is PlayerMobile pm && dropped.Amount == JoinCost) { if (pm.NpcGuild == NpcGuild) + { SayTo(pm, 501047); // Thou art already a member of our guild. + } else if (pm.NpcGuild != NpcGuild.None) + { SayTo(pm, 501046); // Thou must resign from thy other guild first. + } else if (pm.GameTime < JoinGameAge || pm.CreationTime + JoinAge > DateTime.UtcNow) + { SayTo(pm, 501048); // You are too young to join my guild... + } else if (CheckCustomReqs(pm)) { SayWelcomeTo(pm); @@ -133,4 +154,4 @@ namespace Server.Mobiles int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs b/Projects/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs index f808e3a21..a11537460 100644 --- a/Projects/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs +++ b/Projects/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs @@ -5,6 +5,7 @@ using Server.Gumps; using Server.Items; using Server.Multis; using Server.Network; +using Server.Prompts; namespace Server.Mobiles { @@ -968,7 +969,7 @@ namespace Server.Mobiles AddItem(580, 44, 4033); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (!m_Barkeeper.IsOwner(m_From)) return; diff --git a/Projects/Scripts/Mobiles/Vendors/PlayerVendor.cs b/Projects/Scripts/Mobiles/Vendors/PlayerVendor.cs index 41d7dd9d8..a3f4e850d 100644 --- a/Projects/Scripts/Mobiles/Vendors/PlayerVendor.cs +++ b/Projects/Scripts/Mobiles/Vendors/PlayerVendor.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using Server.ContextMenus; using Server.Engines.BulkOrders; using Server.Ethics; @@ -9,6 +8,7 @@ using Server.Gumps; using Server.Items; using Server.Misc; using Server.Multis; +using Server.Prompts; using Server.Targeting; namespace Server.Mobiles @@ -326,7 +326,11 @@ namespace Server.Mobiles { if (BaseHouse.NewVendorSystem) return ChargePerRealWorldDay / 12; - long total = m_SellItems.Values.Aggregate(0, (current, vi) => current + vi.Price) - 500; + long total = 0; + foreach (VendorItem vi in m_SellItems.Values) + total += vi.Price; + + total -= 500; if (total < 0) total = 0; @@ -341,7 +345,9 @@ namespace Server.Mobiles { if (BaseHouse.NewVendorSystem) { - long total = m_SellItems.Values.Aggregate(0, (current, vi) => current + vi.Price); + long total = 0; + foreach (VendorItem vi in m_SellItems.Values) + total += vi.Price; return (int)(60 + total / 500 * 3); } @@ -538,7 +544,11 @@ namespace Server.Mobiles protected List GetItems() { - List list = Items.Where(item => item.Movable && item != Backpack && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair).ToList(); + List list = new List(); + + foreach (Item item in Items) + if (item.Movable && item != Backpack && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair) + list.Add(item); if (Backpack != null) list.AddRange(Backpack.Items); @@ -574,17 +584,18 @@ namespace Server.Mobiles { if (House.IsOwner(Owner)) // Move to moving crate { - House.MovingCrate ??= new MovingCrate(House); + if (House.MovingCrate == null) + House.MovingCrate = new MovingCrate(House); if (HoldGold > 0) Banker.Deposit(House.MovingCrate, HoldGold); - foreach (Item item in list) - House.MovingCrate.DropItem(item); + foreach (Item item in list) House.MovingCrate.DropItem(item); } else // Move to vendor inventory { - VendorInventory inventory = new VendorInventory(House, Owner, Name, ShopName) {Gold = HoldGold}; + VendorInventory inventory = new VendorInventory(House, Owner, Name, ShopName); + inventory.Gold = HoldGold; foreach (Item item in list) inventory.AddItem(item); diff --git a/Projects/Scripts/Mobiles/Vendors/RentedVendor.cs b/Projects/Scripts/Mobiles/Vendors/RentedVendor.cs index 9d73296d1..618076cfa 100644 --- a/Projects/Scripts/Mobiles/Vendors/RentedVendor.cs +++ b/Projects/Scripts/Mobiles/Vendors/RentedVendor.cs @@ -4,6 +4,7 @@ using Server.ContextMenus; using Server.Gumps; using Server.Misc; using Server.Multis; +using Server.Prompts; namespace Server.Mobiles { @@ -128,7 +129,8 @@ namespace Server.Mobiles { if (RentalGold > 0 && House?.IsAosRules == true) { - House.MovingCrate ??= new MovingCrate(House); + if (House.MovingCrate == null) + House.MovingCrate = new MovingCrate(House); Banker.Deposit(House.MovingCrate, RentalGold); RentalGold = 0; diff --git a/Projects/Scripts/Mobiles/Vendors/VendorInventory.cs b/Projects/Scripts/Mobiles/Vendors/VendorInventory.cs index 7b9323a6c..ad3104ae5 100644 --- a/Projects/Scripts/Mobiles/Vendors/VendorInventory.cs +++ b/Projects/Scripts/Mobiles/Vendors/VendorInventory.cs @@ -116,7 +116,8 @@ namespace Server.Mobiles { if (m_Inventory.Gold > 0) { - house.MovingCrate ??= new MovingCrate(house); + if (house.MovingCrate == null) + house.MovingCrate = new MovingCrate(house); Banker.Deposit(house.MovingCrate, m_Inventory.Gold); } @@ -133,4 +134,4 @@ namespace Server.Mobiles } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Multis/Houses/BaseHouse.cs b/Projects/Scripts/Multis/BaseHouse.cs similarity index 88% rename from Projects/Scripts/Multis/Houses/BaseHouse.cs rename to Projects/Scripts/Multis/BaseHouse.cs index 69a819c44..97c9e5829 100644 --- a/Projects/Scripts/Multis/Houses/BaseHouse.cs +++ b/Projects/Scripts/Multis/BaseHouse.cs @@ -24,7 +24,7 @@ namespace Server.Multis public const int MaximumBarkeepCount = 2; - private static readonly Dictionary> m_Table = new Dictionary>(); + private static Dictionary> m_Table = new Dictionary>(); private DecayLevel m_LastDecayLevel; @@ -148,7 +148,10 @@ namespace Server.Multis newest = check; } - return this == newest ? DecayType.AutoRefresh : DecayType.ManualRefresh; + if (this == newest) + return DecayType.AutoRefresh; + + return DecayType.ManualRefresh; } } @@ -215,13 +218,43 @@ namespace Server.Multis public virtual bool IsActive => true; - public bool HasPersonalVendors => PlayerVendors.Any(vendor => !(vendor is RentedVendor)); + public bool HasPersonalVendors + { + get + { + foreach (PlayerVendor vendor in PlayerVendors) + if (!(vendor is RentedVendor)) + return true; - public bool HasRentedVendors => PlayerVendors.OfType().Any(); + return false; + } + } + + public bool HasRentedVendors + { + get + { + foreach (PlayerVendor vendor in PlayerVendors) + if (vendor is RentedVendor) + return true; + + return false; + } + } #region Mondain's Legacy - public bool HasAddonContainers => Addons.OfType().Any(); + public bool HasAddonContainers + { + get + { + foreach (Item item in Addons) + if (item is BaseAddonContainer) + return true; + + return false; + } + } #endregion @@ -331,7 +364,9 @@ namespace Server.Multis { get { - int count = GetLockdowns(); + int count = 0; + + count += GetLockdowns(); if (Secures != null) for (int i = 0; i < Secures.Count; ++i) @@ -350,7 +385,26 @@ namespace Server.Multis } } - public int SecureCount => Secures?.Where(info => !info.Item.Deleted).Count(info => !(info.Item is StrongBox)) ?? 0; + public int SecureCount + { + get + { + int count = 0; + + if (Secures != null) + for (int i = 0; i < Secures.Count; i++) + { + SecureInfo info = Secures[i]; + + if (info.Item.Deleted) + continue; + if (!(info.Item is StrongBox)) + count += 1; + } + + return count; + } + } public List Addons{ get; set; } @@ -488,9 +542,11 @@ namespace Server.Multis { HousePlacementEntry hpe = GetAosEntry(); - public virtual int GetAosMaxSecures() => (int)(GetAosEntry()?.Storage ?? 0 * BonusStorageScalar); + if (hpe == null) + return 0; - public virtual int GetAosMaxLockdowns() => (int)(GetAosEntry()?.Lockdowns ?? 0 * BonusStorageScalar); + return (int)(hpe.Lockdowns * BonusStorageScalar); + } public virtual int GetAosCurSecures(out int fromSecures, out int fromVendors, out int fromLockdowns, out int fromMovingCrate) @@ -504,14 +560,22 @@ namespace Server.Multis if (list != null) { - fromSecures += list.Sum(si => si.Item.TotalItems); + for (int i = 0; i < list.Count; ++i) + { + SecureInfo si = list[i]; + + fromSecures += si.Item.TotalItems; + } + fromLockdowns += list.Count; } fromLockdowns += GetLockdowns(); if (!NewVendorSystem) - fromVendors += PlayerVendors.Where(vendor => vendor.Backpack != null).Sum(vendor => vendor.Backpack.TotalItems); + foreach (PlayerVendor vendor in PlayerVendors) + if (vendor.Backpack != null) + fromVendors += vendor.Backpack.TotalItems; if (MovingCrate != null) { @@ -525,17 +589,18 @@ namespace Server.Multis return fromSecures + fromVendors + fromLockdowns + fromMovingCrate; } - public bool InRange(IPoint2D from, int range) => - Region?.Area.Any(rect => - from.X >= rect.Start.X - range && from.Y >= rect.Start.Y - range && from.X < rect.End.X + range && from.Y < rect.End.Y + range) - == true; + public bool InRange(IPoint2D from, int range) + { + if (Region == null) + return false; - public virtual int GetNewVendorSystemMaxVendors() => - (int)(GetAosEntry()?.Vendors ?? 0 * BonusStorageScalar); + foreach (Rectangle3D rect in Region.Area) + if (from.X >= rect.Start.X - range && from.Y >= rect.Start.Y - range && from.X < rect.End.X + range && + from.Y < rect.End.Y + range) + return true; - public virtual bool CanPlaceNewVendor() => - !IsAosRules || (!NewVendorSystem ? CheckAosLockdowns(10) : - PlayerVendors.Count + VendorRentalContracts.Count < GetNewVendorSystemMaxVendors()); + return false; + } public virtual int GetNewVendorSystemMaxVendors() { @@ -586,11 +651,25 @@ namespace Server.Multis eable.Free(); } - public List AvailableVendorsFor(Mobile m) => - PlayerVendors.Where(vendor => vendor.CanInteractWith(m, false)).Cast().ToList(); + public List AvailableVendorsFor(Mobile m) + { + List list = new List(); - public bool AreThereAvailableVendorsFor(Mobile m) => - PlayerVendors.Any(vendor => vendor.CanInteractWith(m, false)); + foreach (PlayerVendor vendor in PlayerVendors) + if (vendor.CanInteractWith(m, false)) + list.Add(vendor); + + return list; + } + + public bool AreThereAvailableVendorsFor(Mobile m) + { + foreach (PlayerVendor vendor in PlayerVendors) + if (vendor.CanInteractWith(m, false)) + return true; + + return false; + } public void MoveAllToCrate() { @@ -617,7 +696,7 @@ namespace Server.Multis LockDowns.Clear(); - foreach (VendorRentalContract item in VendorRentalContracts) + foreach (Item item in VendorRentalContracts) if (!item.Deleted) { item.IsLockedDown = false; @@ -732,10 +811,25 @@ namespace Server.Multis if (m_Trash != null && m_Trash.Map != Map.Internal) list.Add(m_Trash); - list.AddRange(LockDowns.Where(item => item.Parent == null && item.Map != Map.Internal)); - list.AddRange(VendorRentalContracts.Cast().Where(item => item.Parent == null && item.Map != Map.Internal)); - list.AddRange(Secures.Select(info => info.Item).Where(item => item.Parent == null && item.Map != Map.Internal)); - list.AddRange(Addons.Where(item => item.Parent == null && item.Map != Map.Internal)); + foreach (Item item in LockDowns) + if (item.Parent == null && item.Map != Map.Internal) + list.Add(item); + + foreach (Item item in VendorRentalContracts) + if (item.Parent == null && item.Map != Map.Internal) + list.Add(item); + + foreach (SecureInfo info in Secures) + { + Item item = info.Item; + + if (item.Parent == null && item.Map != Map.Internal) + list.Add(item); + } + + foreach (Item item in Addons) + if (item.Parent == null && item.Map != Map.Internal) + list.Add(item); foreach (PlayerVendor mobile in PlayerVendors) { @@ -745,7 +839,9 @@ namespace Server.Multis list.Add(mobile); } - list.AddRange(PlayerBarkeepers.Cast().Where(mobile => mobile.Map != Map.Internal)); + foreach (Mobile mobile in PlayerBarkeepers) + if (mobile.Map != Map.Internal) + list.Add(mobile); return list; } @@ -812,7 +908,9 @@ namespace Server.Multis // The item can't fit if (item is TrashBarrel) + { item.Delete(); // Trash barrels don't go to the moving crate + } else { SetLockdown(item, false); @@ -897,7 +995,9 @@ namespace Server.Multis public void DropToMovingCrate(Item item) { - MovingCrate ??= new MovingCrate(this); + if (MovingCrate == null) + MovingCrate = new MovingCrate(this); + MovingCrate.DropItem(item); } @@ -918,11 +1018,12 @@ namespace Server.Multis return list; } - public List GetMobiles() => - Map == null || Map == Map.Internal ? new List() - : Region.GetMobiles().Where(IsInside).ToList(); + public List GetMobiles() + { + if (Map == null || Map == Map.Internal) + return new List(); - public virtual bool CheckAosLockdowns(int need) => GetAosCurLockdowns() + need <= GetAosMaxLockdowns(); + List list = new List(); foreach (Mobile mobile in Region.GetMobiles()) if (IsInside(mobile)) @@ -945,9 +1046,14 @@ namespace Server.Multis Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), Decay_OnTick); } - public virtual int GetAosCurLockdowns() => GetLockdowns() + Secures?.Count ?? 0 + (NewVendorSystem ? 0 : PlayerVendors.Count * 10); + public virtual int GetAosCurLockdowns() + { + int v = 0; - public static bool CheckLockedDown(Item item) => FindHouseAt(item)?.HasLockedDownItem(item) == true; + v += GetLockdowns(); + + if (Secures != null) + v += Secures.Count; if (!NewVendorSystem) v += PlayerVendors.Count * 10; @@ -1008,15 +1114,31 @@ namespace Server.Multis BaseHouse house = FindHouseAt(item); - return house == null || house.CheckSecureAccess(m, item) switch + if (house == null) + return true; + + SecureAccessResult res = house.CheckSecureAccess(m, item); + + switch (res) { - SecureAccessResult.Accessible => true, - SecureAccessResult.Inaccessible => false, - _ => (!house.HasLockedDownItem(item) || house.IsCoOwner(m) && item is Container) - }; + case SecureAccessResult.Insecure: break; + case SecureAccessResult.Accessible: return true; + case SecureAccessResult.Inaccessible: return false; + } + + if (house.HasLockedDownItem(item)) + return house.IsCoOwner(m) && item is Container; + + return true; } - public static BaseHouse FindHouseAt(Mobile m) => m?.Deleted != false ? null : FindHouseAt(m.Location, m.Map, 16); + public static BaseHouse FindHouseAt(Mobile m) + { + if (m?.Deleted != false) + return null; + + return FindHouseAt(m.Location, m.Map, 16); + } public static BaseHouse FindHouseAt(Item item) => item?.Deleted != false ? null : @@ -1046,7 +1168,7 @@ namespace Server.Multis switch (res) { - // case SecureAccessResult.Insecure: break; + case SecureAccessResult.Insecure: break; case SecureAccessResult.Accessible: return true; case SecureAccessResult.Inaccessible: return false; } @@ -1063,21 +1185,28 @@ namespace Server.Multis return IsCoOwner(from); if (item.Stackable) return true; + if (item is BaseLight) + return IsFriend(from); + if (item is PotionKeg) + return IsFriend(from); + if (item is Dices) + return true; + if (item is RecallRune) + return true; + if (item is TreasureMap) + return true; + if (item is Clock) + return true; + if (item is BaseInstrument) + return true; + if (item is Dyes) + return true; + if (item is VendorRentalContract) + return true; + if (item is RewardBrazier) + return true; - return item switch - { - BaseLight _ => IsFriend(from), - PotionKeg _ => IsFriend(from), - Dices _ => true, - RecallRune _ => true, - TreasureMap _ => true, - Clock _ => true, - BaseInstrument _ => true, - Dyes _ => true, - VendorRentalContract _ => true, - RewardBrazier _ => true, - _ => false - }; + return false; } public virtual bool IsInside(Point3D p, int height) @@ -1362,11 +1491,9 @@ namespace Server.Multis m_Trash = new TrashBarrel { Movable = false }; m_Trash.MoveToWorld(from.Location, from.Map); - from.SendLocalizedMessage(502121); - /* You have a new trash barrel. - * Three minutes after you put something in the barrel, the trash will be emptied. - * Be forewarned, this is permanent! - */ + from.SendLocalizedMessage(502121); /* You have a new trash barrel. + * Three minutes after you put something in the barrel, the trash will be emptied. + * Be forewarned, this is permanent! */ } else { @@ -1435,19 +1562,31 @@ namespace Server.Multis Item parentItem = item.Parent as Item; if (checkIsInside && item.RootParent is Mobile) + { m.SendLocalizedMessage(1005525); //That is not in your house + } else if (checkIsInside && !IsInside(item.GetWorldLocation(), item.ItemData.Height)) + { m.SendLocalizedMessage(1005525); //That is not in your house + } else if (Ethic.IsImbued(item)) + { m.SendLocalizedMessage(1005377); //You cannot lock that down + } else if (HasSecureItem(rootItem)) + { m.SendLocalizedMessage(501737); // You need not lock down items in a secure container. + } else if (parentItem != null && !HasLockedDownItem(parentItem)) + { m.SendLocalizedMessage(501736); // You must lockdown the container first! + } else if (!(item is VendorRentalContract) && (IsAosRules ? !CheckAosLockdowns(amt) || !CheckAosStorage(amt) : LockDownCount + amt > MaxLockDowns)) + { m.SendLocalizedMessage(1005379); //That would exceed the maximum lock down limit for this house + } else { SetLockdown(item, true); @@ -1460,9 +1599,13 @@ namespace Server.Multis return true; } else if (item is HouseSign || item is Static) + { m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1005526); // This is already locked down. + } else + { m.SendLocalizedMessage(1005377); //You cannot lock that down + } return false; } @@ -1501,17 +1644,25 @@ namespace Server.Multis return; if (NewVendorSystem && HasPersonalVendors) + { from.SendLocalizedMessage( 1062467); // You cannot trade this house while you still have personal vendors inside. + } else if (DecayLevel == DecayLevel.DemolitionPending) + { from.SendLocalizedMessage( 1005321); // This house has been marked for demolition, and it cannot be transferred. + } else if (from == to) + { from.SendLocalizedMessage(1005330); // You cannot transfer a house to yourself, silly. + } else if (to.Player) { if (HasAccountHouse(to)) + { from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner! + } else if (CheckTransferPosition(from, to)) { from.SendLocalizedMessage(1005326); // Please wait while the other player verifies the transfer. @@ -1558,17 +1709,25 @@ namespace Server.Multis return; if (NewVendorSystem && HasPersonalVendors) + { from.SendLocalizedMessage( 1062467); // You cannot trade this house while you still have personal vendors inside. + } else if (DecayLevel == DecayLevel.DemolitionPending) + { from.SendLocalizedMessage( 1005321); // This house has been marked for demolition, and it cannot be transferred. + } else if (from == to) + { from.SendLocalizedMessage(1005330); // You cannot transfer a house to yourself, silly. + } else if (to.Player) { if (HasAccountHouse(to)) + { from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner! + } else if (CheckTransferPosition(from, to)) { NetState fromState = from.NetState, toState = to.NetState; @@ -1576,14 +1735,20 @@ namespace Server.Multis if (fromState != null && toState != null) { if (from.HasTrade) + { from.SendLocalizedMessage( 1062071); // You cannot trade a house while you have other trades pending. + } else if (to.HasTrade) + { to.SendLocalizedMessage( 1062071); // You cannot trade a house while you have other trades pending. + } else if (!to.Alive) + { // TODO: Check if the message is correct. from.SendLocalizedMessage(1062069); // You cannot transfer this house to that person. + } else { Container c = fromState.AddTrade(toState); @@ -1594,7 +1759,9 @@ namespace Server.Multis } } else + { from.SendLocalizedMessage(501384); // Only a player can own a house! + } } public void Release(Mobile m, Item item) @@ -1611,9 +1778,13 @@ namespace Server.Multis (item as RewardBrazier)?.TurnOff(); } else if (HasSecureItem(item)) + { ReleaseSecure(m, item); + } else + { m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1010416); // This is not locked down or secured. + } } public void AddSecure(Mobile m, Item item) @@ -1622,11 +1793,17 @@ namespace Server.Multis return; if (!IsInside(item)) + { m.SendLocalizedMessage(1005525); // That is not in your house + } else if (HasLockedDownItem(item)) + { m.SendLocalizedMessage(1010550); // This is already locked down and cannot be secured. + } else if (!(item is Container)) + { LockDown(m, item); + } else { SecureInfo info = null; @@ -1641,17 +1818,27 @@ namespace Server.Multis m.SendGump(new SetSecureLevelGump(m_Owner, info, this)); } else if (item.Parent != null) + { m.SendLocalizedMessage(1010423); // You cannot secure this, place it on the ground first. + } // Mondain's Legacy mod else if (!(item is BaseAddonContainer) && !item.Movable) + { m.SendLocalizedMessage(1010424); // You cannot secure this. + } else if (!IsAosRules && SecureCount >= MaxSecures) + { // The maximum number of secure items has been reached : m.SendLocalizedMessage(1008142, true, MaxSecures.ToString()); + } else if (IsAosRules ? !CheckAosLockdowns(1) : LockDownCount + 125 >= MaxLockDowns) + { m.SendLocalizedMessage(1005379); // That would exceed the maximum lock down limit for this house + } else if (IsAosRules && !CheckAosStorage(item.TotalItems)) + { m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house. + } else { info = new SecureInfo((Container)item, SecureLevel.Owner); @@ -1721,7 +1908,15 @@ namespace Server.Multis item.IsLockedDown = false; item.IsSecure = false; - item.Movable = !(item is BaseAddonContainer); + #region Mondain's Legacy + + if (item is BaseAddonContainer) + item.Movable = false; + else + + #endregion + + item.Movable = true; item.SetLastMoved(); item.PublicOverheadMessage(MessageType.Label, 0x3B2, 501656); //[no longer secure] Secures.RemoveAt(i); @@ -1787,24 +1982,33 @@ namespace Server.Multis return; if (targ.AccessLevel > AccessLevel.Player && from.AccessLevel <= targ.AccessLevel) + { from.SendLocalizedMessage(501346); // Uh oh...a bigger boot may be required! + } else if (IsFriend(targ) && !Core.ML) + { from.SendLocalizedMessage(501348); // You cannot eject a friend of the house! + } else if (targ is PlayerVendor) + { from.SendLocalizedMessage(501351); // You cannot eject a vendor. + } else if (!IsInside(targ)) + { from.SendLocalizedMessage(501352); // You may not eject someone who is not in your house! + } else if (targ is BaseCreature creature && creature.NoHouseRestrictions) + { from.SendLocalizedMessage(501347); // You cannot eject that from the house! + } else { targ.MoveToWorld(BanLocation, Map); from.SendLocalizedMessage(1042840, targ.Name); // ~1_PLAYER NAME~ has been ejected from this house. - targ.SendLocalizedMessage(501341); - /* You have been ejected from this house. - * If you persist in entering, you may be banned from the house. - */ + targ.SendLocalizedMessage(501341); /* You have been ejected from this house. + * If you persist in entering, you may be banned from the house. + */ } } @@ -1846,22 +2050,38 @@ namespace Server.Multis return; if (targ.AccessLevel > AccessLevel.Player && from.AccessLevel <= targ.AccessLevel) + { from.SendLocalizedMessage(501354); // Uh oh...a bigger boot may be required. + } else if (IsFriend(targ)) + { from.SendLocalizedMessage(501348); // You cannot eject a friend of the house! + } else if (targ is PlayerVendor) + { from.SendLocalizedMessage(501351); // You cannot eject a vendor. + } else if (Bans.Count >= MaxBans) + { from.SendLocalizedMessage(501355); // The ban limit for this house has been reached! + } else if (IsBanned(targ)) + { from.SendLocalizedMessage(501356); // This person is already banned! + } else if (!IsInside(targ)) + { from.SendLocalizedMessage(501352); // You may not eject someone who is not in your house! + } else if (!Public && IsAosRules) + { from.SendLocalizedMessage( 1062521); // You cannot ban someone from a private house. Revoke their access instead. + } else if (targ is BaseCreature bc && bc.NoHouseRestrictions) + { from.SendLocalizedMessage(1062040); // You cannot ban that. + } else { Bans.Add(targ); @@ -1879,11 +2099,17 @@ namespace Server.Multis return; if (HasAccess(targ)) + { from.SendLocalizedMessage(1060729); // That person already has access to this house. + } else if (!targ.Player) + { from.SendLocalizedMessage(1060712); // That is not a player. + } else if (IsBanned(targ)) + { from.SendLocalizedMessage(501367); // This person is banned! Unban them first. + } else { Access.Add(targ); @@ -1898,19 +2124,33 @@ namespace Server.Multis return; if (IsOwner(targ)) + { from.SendLocalizedMessage(501360); // This person is already the house owner! + } else if (Friends.Contains(targ)) + { from.SendLocalizedMessage(501361); // This person is a friend of the house. Remove them first. + } else if (!targ.Player) + { from.SendLocalizedMessage(501362); // That can't be a co-owner of the house. + } else if (!Core.AOS && HasAccountHouse(targ)) + { from.SendLocalizedMessage(501364); // That person is already a house owner. + } else if (IsBanned(targ)) + { from.SendLocalizedMessage(501367); // This person is banned! Unban them first. + } else if (CoOwners.Count >= MaxCoOwners) + { from.SendLocalizedMessage(501368); // Your co-owner list is full! + } else if (CoOwners.Contains(targ)) + { from.SendLocalizedMessage(501369); // This person is already on your co-owner list! + } else { CoOwners.Add(targ); @@ -1956,17 +2196,29 @@ namespace Server.Multis return; if (IsOwner(targ)) + { from.SendLocalizedMessage(501370); // This person is already an owner of the house! + } else if (CoOwners.Contains(targ)) + { from.SendLocalizedMessage(501369); // This person is already on your co-owner list! + } else if (!targ.Player) + { from.SendLocalizedMessage(501371); // That can't be a friend of the house. + } else if (IsBanned(targ)) + { from.SendLocalizedMessage(501374); // This person is banned! Unban them first. + } else if (Friends.Count >= MaxFriends) + { from.SendLocalizedMessage(501375); // Your friends list is full! + } else if (Friends.Contains(targ)) + { from.SendLocalizedMessage(501376); // This person is already on your friends list! + } else { Friends.Add(targ); @@ -2549,7 +2801,21 @@ namespace Server.Multis AllHouses.Remove(this); } - public static bool HasHouse(Mobile m) => m != null && m_Table.TryGetValue(m, out List list) && list.Any(h => !h.Deleted); + public static bool HasHouse(Mobile m) + { + if (m == null || !m_Table.TryGetValue(m, out List list)) + return false; + + for (int i = 0; i < list.Count; ++i) + { + BaseHouse h = list[i]; + + if (!h.Deleted) + return true; + } + + return false; + } public static bool HasAccountHouse(Mobile m) { @@ -2563,15 +2829,35 @@ namespace Server.Multis return false; } - public bool IsOwner(Mobile m) => - m != null && (m == m_Owner || m.AccessLevel >= AccessLevel.GameMaster || - IsAosRules && AccountHandler.CheckAccount(m, m_Owner)); + public bool IsOwner(Mobile m) + { + if (m == null) + return false; - public bool IsCoOwner(Mobile m) => - m != null && (IsOwner(m) || CoOwners?.Contains(m) == true || - !IsAosRules && AccountHandler.CheckAccount(m, m_Owner)); + if (m == m_Owner || m.AccessLevel >= AccessLevel.GameMaster) + return true; - public bool IsGuildMember(Mobile m) => Owner?.Guild != null && m?.Guild == Owner.Guild; + return IsAosRules && AccountHandler.CheckAccount(m, m_Owner); + } + + public bool IsCoOwner(Mobile m) + { + if (m == null || CoOwners == null) + return false; + + if (IsOwner(m) || CoOwners.Contains(m)) + return true; + + return !IsAosRules && AccountHandler.CheckAccount(m, m_Owner); + } + + public bool IsGuildMember(Mobile m) + { + if (m == null || Owner?.Guild == null) + return false; + + return m.Guild == Owner.Guild; + } public void RemoveKeys(Mobile m) { @@ -2783,11 +3069,10 @@ namespace Server.Multis return; from.SendLocalizedMessage(501338); // You have transferred ownership of the house. - to.SendLocalizedMessage(501339); - /* You are now the owner of this house. - * The house's co-owner, friend, ban, and access lists have been cleared. - * You should double-check the security settings on any doors and teleporters in the house. - */ + to.SendLocalizedMessage(501339); /* You are now the owner of this house. + * The house's co-owner, friend, ban, and access lists have been cleared. + * You should double-check the security settings on any doors and teleporters in the house. + */ m_House.RemoveKeys(from); m_House.Owner = to; diff --git a/Projects/Scripts/Multis/Boats/BaseBoat.cs b/Projects/Scripts/Multis/Boats/BaseBoat.cs index 1d93e625e..b16405417 100644 --- a/Projects/Scripts/Multis/Boats/BaseBoat.cs +++ b/Projects/Scripts/Multis/Boats/BaseBoat.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using Server.Items; using Server.Network; @@ -258,7 +259,7 @@ namespace Server.Multis } int xOffset = 0, yOffset = 0; - Movement.Offset(m_Facing, ref xOffset, ref yOffset); + Movement.Movement.Offset(m_Facing, ref xOffset, ref yOffset); if (TillerMan != null) { @@ -1457,10 +1458,11 @@ namespace Server.Multis else { List toMove = GetMovingEntities(); - if (TillerMan != null) toMove.Add(TillerMan); - if (Hold != null) toMove.Add(Hold); - if (PPlank != null) toMove.Add(PPlank); - if (SPlank != null) toMove.Add(SPlank); + + SafeAdd(TillerMan, toMove); + SafeAdd(Hold, toMove); + SafeAdd(PPlank, toMove); + SafeAdd(SPlank, toMove); // Packet must be sent before actual locations are changed foreach (NetState ns in Map.GetClientsInRange(Location, GetMaxUpdateRange())) @@ -1468,7 +1470,7 @@ namespace Server.Multis Mobile m = ns.Mobile; if (ns.HighSeas && m.CanSee(this) && m.InRange(Location, GetUpdateRange(m))) - BoatPackets.SendMoveBoatHS(ns, m, this, d, clientSpeed, toMove, xOffset, yOffset); + ns.Send(new MoveBoatHS(m, this, d, clientSpeed, toMove, xOffset, yOffset)); } foreach (IEntity e in toMove) @@ -1500,6 +1502,12 @@ namespace Server.Multis return true; } + private static void SafeAdd(Item item, List toMove) + { + if (item != null) + toMove.Add(item); + } + public void Teleport(int xOffset, int yOffset, int zOffset) { List toMove = GetMovingEntities(); @@ -1526,9 +1534,9 @@ namespace Server.Multis return list; MultiComponentList mcl = Components; - IPooledEnumerable eable = map.GetObjectsInBounds(new Rectangle2D(X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height)); - foreach (IEntity o in eable) + foreach (IEntity o in map.GetObjectsInBounds(new Rectangle2D(X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height)) + ) { if (o == this || o is TillerMan || o is Hold || o is Plank) continue; @@ -1545,8 +1553,6 @@ namespace Server.Multis } } - eable.Free(); - return list; } @@ -1589,11 +1595,11 @@ namespace Server.Multis List toMove = GetMovingEntities(); - if (PPlank != null) toMove.Add(PPlank); - if (SPlank != null) toMove.Add(SPlank); + toMove.Add(PPlank); + toMove.Add(SPlank); int xOffset = 0, yOffset = 0; - Movement.Offset(facing, ref xOffset, ref yOffset); + Movement.Movement.Offset(facing, ref xOffset, ref yOffset); if (TillerMan != null) TillerMan.Location = new Point3D(X + xOffset * TillerManDistance + (facing == Direction.North ? 1 : 0), @@ -1610,7 +1616,9 @@ namespace Server.Multis IEntity e = toMove[i]; if (e is Item item) + { item.Location = Rotate(item.Location, count); + } else if (e is Mobile m) { m.Direction = m.Direction - old + facing & Direction.Mask; @@ -1726,6 +1734,8 @@ namespace Server.Multis } } + #region High Seas + public override bool AllowsRelativeDrop => true; /* @@ -1743,5 +1753,137 @@ namespace Server.Multis return base.GetWorldPacketFor( state ); } */ + + public sealed class MoveBoatHS : Packet + { + public MoveBoatHS(Mobile beholder, BaseBoat boat, Direction d, int speed, List ents, int xOffset, + int yOffset) + : base(0xF6) + { + EnsureCapacity(3 + 15 + ents.Count * 10); + + m_Stream.Write(boat.Serial); + m_Stream.Write((byte)speed); + m_Stream.Write((byte)d); + m_Stream.Write((byte)boat.Facing); + m_Stream.Write((short)(boat.X + xOffset)); + m_Stream.Write((short)(boat.Y + yOffset)); + m_Stream.Write((short)boat.Z); + m_Stream.Write((short)0); // count placeholder + + int count = 0; + + foreach (IEntity ent in ents) + { + if (!beholder.CanSee(ent)) + continue; + + m_Stream.Write(ent.Serial); + m_Stream.Write((short)(ent.X + xOffset)); + m_Stream.Write((short)(ent.Y + yOffset)); + m_Stream.Write((short)ent.Z); + ++count; + } + + m_Stream.Seek(16, SeekOrigin.Begin); + m_Stream.Write((short)count); + } + } + + public sealed class DisplayBoatHS : Packet + { + public DisplayBoatHS(Mobile beholder, BaseBoat boat) + : base(0xF7) + { + List ents = boat.GetMovingEntities(); + + SafeAdd(boat.TillerMan, ents); + SafeAdd(boat.Hold, ents); + SafeAdd(boat.PPlank, ents); + SafeAdd(boat.SPlank, ents); + + ents.Add(boat); + + EnsureCapacity(3 + 2 + ents.Count * 26); + + m_Stream.Write((short)0); // count placeholder + + int count = 0; + + foreach (IEntity ent in ents) + { + if (!beholder.CanSee(ent)) + continue; + + // Embedded WorldItemHS packets + m_Stream.Write((byte)0xF3); + m_Stream.Write((short)0x1); + + if (ent is BaseMulti bm) + { + m_Stream.Write((byte)0x02); + m_Stream.Write(bm.Serial); + // TODO: Mask no longer needed, merge with Item case? + m_Stream.Write((ushort)(bm.ItemID & 0x3FFF)); + m_Stream.Write((byte)0); + + m_Stream.Write((short)bm.Amount); + m_Stream.Write((short)bm.Amount); + + m_Stream.Write((short)(bm.X & 0x7FFF)); + m_Stream.Write((short)(bm.Y & 0x3FFF)); + m_Stream.Write((sbyte)bm.Z); + + m_Stream.Write((byte)bm.Light); + m_Stream.Write((short)bm.Hue); + m_Stream.Write((byte)bm.GetPacketFlags()); + } + else if (ent is Mobile m) + { + m_Stream.Write((byte)0x01); + m_Stream.Write(m.Serial); + m_Stream.Write((short)m.Body); + m_Stream.Write((byte)0); + + m_Stream.Write((short)1); + m_Stream.Write((short)1); + + m_Stream.Write((short)(m.X & 0x7FFF)); + m_Stream.Write((short)(m.Y & 0x3FFF)); + m_Stream.Write((sbyte)m.Z); + + m_Stream.Write((byte)m.Direction); + m_Stream.Write((short)m.Hue); + m_Stream.Write((byte)m.GetPacketFlags()); + } + else if (ent is Item item) + { + m_Stream.Write((byte)0x00); + m_Stream.Write(item.Serial); + m_Stream.Write((ushort)(item.ItemID & 0xFFFF)); + m_Stream.Write((byte)0); + + m_Stream.Write((short)item.Amount); + m_Stream.Write((short)item.Amount); + + m_Stream.Write((short)(item.X & 0x7FFF)); + m_Stream.Write((short)(item.Y & 0x3FFF)); + m_Stream.Write((sbyte)item.Z); + + m_Stream.Write((byte)item.Light); + m_Stream.Write((short)item.Hue); + m_Stream.Write((byte)item.GetPacketFlags()); + } + + m_Stream.Write((short)0x00); + ++count; + } + + m_Stream.Seek(3, SeekOrigin.Begin); + m_Stream.Write((short)count); + } + } + + #endregion } } diff --git a/Projects/Scripts/Multis/Boats/ConfirmDryDockGump.cs b/Projects/Scripts/Multis/Boats/ConfirmDryDockGump.cs index 4184103ae..920eecaa5 100644 --- a/Projects/Scripts/Multis/Boats/ConfirmDryDockGump.cs +++ b/Projects/Scripts/Multis/Boats/ConfirmDryDockGump.cs @@ -29,7 +29,7 @@ namespace Server.Multis AddButton(20, 125, 4005, 4007, 1); } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 2) m_Boat.EndDryDock(m_From); diff --git a/Projects/Scripts/Multis/Boats/Packets.cs b/Projects/Scripts/Multis/Boats/Packets.cs deleted file mode 100644 index e82d6fe22..000000000 --- a/Projects/Scripts/Multis/Boats/Packets.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.Collections.Generic; -using Server.Buffers; -using Server.Multis; - -namespace Server.Network -{ - public static class BoatPackets - { - public static void SendMoveBoatHS(NetState ns, Mobile beholder, BaseBoat boat, Direction d, int speed, - IReadOnlyCollection ents, int xOffset, - int yOffset) - { - if (ns == null) - return; - - int length = 18 + ents.Count * 10; - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xF6); // Packet ID - writer.Position += 2; // Dynamic Length - - writer.Write(boat.Serial); - writer.Write((byte)speed); - writer.Write((byte)d); - writer.Write((byte)boat.Facing); - writer.Write((short)(boat.X + xOffset)); - writer.Write((short)(boat.Y + yOffset)); - writer.Write((short)boat.Z); - writer.Position += 2; // count - - ushort count = 0; - foreach (IEntity ent in ents) - { - if (!beholder.CanSee(ent)) - continue; - - writer.Write(ent.Serial); - writer.Write((short)(ent.X + xOffset)); - writer.Write((short)(ent.Y + yOffset)); - writer.Write((short)ent.Z); - count++; - } - - writer.Position = 16; - writer.Write(count); - writer.Position = 1; - writer.Write((ushort)writer.WrittenCount); - - ns.Send(writer.Span); - } - - public static void SendDisplayBoatHS(NetState ns, Mobile beholder, BaseBoat boat) - { - if (ns == null) - return; - - List ents = boat.GetMovingEntities(); - if (boat.TillerMan != null) ents.Add(boat.TillerMan); - if (boat.Hold != null) ents.Add(boat.Hold); - if (boat.PPlank != null) ents.Add(boat.PPlank); - if (boat.SPlank != null) ents.Add(boat.SPlank); - ents.Add(boat); - - int length = 5 + ents.Count * 26; - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xF7); // Packet ID - writer.Position += 4; // Dynamic Length & Count - - ushort count = 0; - - foreach (IEntity ent in ents) - { - if (!beholder.CanSee(ent)) - continue; - - writer.Write((byte)0xF3); - writer.Write((short)0x1); - - if (ent is Mobile m) - { - writer.Write((byte)0x01); - writer.Write(m.Serial); - writer.Write((short)m.Body); - writer.Position++; - - writer.Write((short)1); - writer.Write((short)1); - - writer.Write((short)(m.X & 0x7FFF)); - writer.Write((short)(m.Y & 0x3FFF)); - writer.Write((sbyte)m.Z); - - writer.Write((byte)m.Direction); - writer.Write((short)m.Hue); - writer.Write((byte)m.GetPacketFlags()); - } - else if (ent is Item item) - { - writer.Position++; - writer.Write(item.Serial); - writer.Write((ushort)(item.ItemID & 0xFFFF)); - writer.Position++; - - writer.Write((short)item.Amount); - writer.Write((short)item.Amount); - - writer.Write((short)(item.X & 0x7FFF)); - writer.Write((short)(item.Y & 0x3FFF)); - writer.Write((sbyte)item.Z); - - writer.Write((byte)item.Light); - writer.Write((short)item.Hue); - writer.Write((byte)item.GetPacketFlags()); - } - - writer.Position += 2; - count++; - } - - writer.Position = 3; - writer.Write(count); - writer.Position = 1; - writer.Write((ushort)writer.WrittenCount); - - ns.Send(writer.Span); - } - } -} diff --git a/Projects/Scripts/Multis/Boats/RenameBoatPrompt.cs b/Projects/Scripts/Multis/Boats/RenameBoatPrompt.cs index 6afc8694b..4448bbed8 100644 --- a/Projects/Scripts/Multis/Boats/RenameBoatPrompt.cs +++ b/Projects/Scripts/Multis/Boats/RenameBoatPrompt.cs @@ -1,3 +1,5 @@ +using Server.Prompts; + namespace Server.Multis { public class RenameBoatPrompt : Prompt diff --git a/Projects/Scripts/Multis/Boats/Strandedness.cs b/Projects/Scripts/Multis/Boats/Strandedness.cs index 3a4c4bfe2..5f818ecee 100644 --- a/Projects/Scripts/Multis/Boats/Strandedness.cs +++ b/Projects/Scripts/Multis/Boats/Strandedness.cs @@ -95,7 +95,7 @@ namespace Server.Misc if (map == null) return false; - ITile surface = map.GetTopSurface(from.Location); + object surface = map.GetTopSurface(from.Location); if (surface is LandTile tile) { @@ -175,4 +175,4 @@ namespace Server.Misc from.Location = new Point3D(x, y, z); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Multis/Houses/Deeds.cs b/Projects/Scripts/Multis/Deeds.cs similarity index 94% rename from Projects/Scripts/Multis/Houses/Deeds.cs rename to Projects/Scripts/Multis/Deeds.cs index 5436302c3..81769384a 100644 --- a/Projects/Scripts/Multis/Houses/Deeds.cs +++ b/Projects/Scripts/Multis/Deeds.cs @@ -100,15 +100,18 @@ namespace Server.Multis.Deeds public override void OnDoubleClick(Mobile from) { if (!IsChildOf(from.Backpack)) + { from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } else if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + { from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } else { - from.SendLocalizedMessage(1010433); - /* House placement cancellation could result in a - * 60 second delay in the return of your deed. - */ + from.SendLocalizedMessage(1010433); /* House placement cancellation could result in a + * 60 second delay in the return of your deed. + */ from.Target = new HousePlacementTarget(this); } @@ -122,9 +125,13 @@ namespace Server.Multis.Deeds return; if (!IsChildOf(from.Backpack)) + { from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } else if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + { from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } else { Point3D center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); diff --git a/Projects/Scripts/Multis/DynamicDecay.cs b/Projects/Scripts/Multis/DynamicDecay.cs index 385862cb7..8976f294a 100644 --- a/Projects/Scripts/Multis/DynamicDecay.cs +++ b/Projects/Scripts/Multis/DynamicDecay.cs @@ -5,7 +5,7 @@ namespace Server.Multis { public class DynamicDecay { - private static readonly Dictionary m_Stages; + private static Dictionary m_Stages; static DynamicDecay() { diff --git a/Projects/Scripts/Multis/Houses/HouseFoundation.cs b/Projects/Scripts/Multis/HouseFoundation.cs similarity index 90% rename from Projects/Scripts/Multis/Houses/HouseFoundation.cs rename to Projects/Scripts/Multis/HouseFoundation.cs index 7e8ae0615..b77b75d87 100644 --- a/Projects/Scripts/Multis/Houses/HouseFoundation.cs +++ b/Projects/Scripts/Multis/HouseFoundation.cs @@ -3,8 +3,8 @@ using System.Buffers; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading; +using System.Threading.Tasks; using Server.Gumps; using Server.Items; using Server.Mobiles; @@ -123,7 +123,9 @@ namespace Server.Multis { get { - if (m_Current == null) SetInitialState(); + if (m_Current == null) + SetInitialState(); + return m_Current.Components; } } @@ -185,7 +187,7 @@ namespace Server.Multis } } - public static ComponentVerification Verification => m_Verification ??= new ComponentVerification(); + public static ComponentVerification Verification => m_Verification ?? (m_Verification = new ComponentVerification()); public bool IsFixture(Item item) => Fixtures.Contains(item); @@ -298,7 +300,8 @@ namespace Server.Multis public void AddFixtures(Mobile from, MultiTileEntry[] list) { - Fixtures ??= new List(); + if (Fixtures == null) + Fixtures = new List(); uint keyValue = 0; @@ -391,9 +394,13 @@ namespace Server.Multis door = new GenericHouseDoor(facing, 0x29F5 + 8 * ((itemID - 0x2A05) / 8), sound, sound); } else if (itemID == 0x2D46) + { door = new GenericHouseDoor(DoorFacing.NorthCW, 0x2D46, 0xEA, 0xF1, false); + } else if (itemID == 0x2D48 || itemID == 0x2FE2) + { door = new GenericHouseDoor(DoorFacing.SouthCCW, itemID, 0xEA, 0xF1, false); + } else if (itemID >= 0x2D63 && itemID < 0x2D70) { int mod = (itemID - 0x2D63) / 2 % 2; @@ -404,7 +411,9 @@ namespace Server.Multis door = new GenericHouseDoor(facing, 0x2D63 + 4 * type + mod * 2, 0xEA, 0xF1, false); } else if (itemID == 0x2FE4 || itemID == 0x31AE) + { door = new GenericHouseDoor(DoorFacing.WestCCW, itemID, 0xEA, 0xF1, false); + } else if (itemID >= 0x319C && itemID < 0x31AE) { //special case for 0x31aa <-> 0x31a8 (a9) @@ -437,13 +446,21 @@ namespace Server.Multis }; } else if (itemID >= 0x409B && itemID < 0x40A3) + { door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x409B), itemID, 0xEA, 0xF1, false); + } else if (itemID >= 0x410C && itemID < 0x4114) + { door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x410C), itemID, 0xEA, 0xF1, false); + } else if (itemID >= 0x41C2 && itemID < 0x41CA) + { door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41C2), itemID, 0xEA, 0xF1, false); + } else if (itemID >= 0x41CF && itemID < 0x41D7) + { door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41CF), itemID, 0xEA, 0xF1, false); + } else if (itemID >= 0x436E && itemID < 0x437E) { /* These ones had to be different... @@ -455,15 +472,25 @@ namespace Server.Multis door = new GenericHouseDoor(facing, itemID, 0xEA, 0xF1, false); } else if (itemID >= 0x46DD && itemID < 0x46E5) + { door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x46DD), itemID, 0xEB, 0xF2, false); + } else if (itemID >= 0x4D22 && itemID < 0x4D2A) + { door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x4D22), itemID, 0xEA, 0xF1, false); + } else if (itemID >= 0x50C8 && itemID < 0x50D0) + { door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50C8), itemID, 0xEA, 0xF1, false); + } else if (itemID >= 0x50D0 && itemID < 0x50D8) + { door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50D0), itemID, 0xEA, 0xF1, false); + } else if (itemID >= 0x5142 && itemID < 0x514A) + { door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x5142), itemID, 0xF0, 0xEF, false); + } if (door != null) { @@ -503,6 +530,7 @@ namespace Server.Multis switch (door.Facing) { default: + case DoorFacing.WestCW: linkFacing = DoorFacing.EastCCW; xOffset = 1; yOffset = 0; @@ -590,6 +618,7 @@ namespace Server.Multis switch (type) { default: + case FoundationType.DarkWood: corner = 0x0014; east = 0x0015; south = 0x0016; @@ -739,8 +768,20 @@ namespace Server.Multis x += mcl.Center.X; y += mcl.Center.Y; - return x >= 0 && x < mcl.Width && y >= 0 && y < mcl.Height && - mcl.Tiles[x][y].Any(tile => tile.Z == 7 && tile.Height == 20); + if (x >= 0 && x < mcl.Width && y >= 0 && y < mcl.Height) + { + StaticTile[] tiles = mcl.Tiles[x][y]; + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile tile = tiles[i]; + + if (tile.Z == 7 && tile.Height == 20) + return true; + } + } + + return false; } public void BeginCustomize(Mobile m) @@ -758,11 +799,12 @@ namespace Server.Multis foreach (Item item in GetItems()) item.Location = BanLocation; - foreach (Mobile mobile in GetMobiles().Where(mobile => mobile != m)) - mobile.Location = BanLocation; + foreach (Mobile mobile in GetMobiles()) + if (mobile != m) + mobile.Location = BanLocation; DesignContext.Add(m, this); - HouseFoundationPackets.SendBeginHouseCustomization(m.NetState, Serial); + m.Send(new BeginHouseCustomization(this)); NetState ns = m.NetState; if (ns != null) @@ -1031,15 +1073,19 @@ namespace Server.Multis { // Temporary Fix. We should be booting a client out of customization mode in the delete handler. if (from.AccessLevel >= AccessLevel.GameMaster && cost != 0) + { from.SendMessage("{0} gold would have been {1} your bank if you were not a GM.", cost.ToString(), cost > 0 ? "withdrawn from" : "deposited into"); + } else { if (cost > 0) { if (Banker.Withdraw(from, cost)) + { from.SendLocalizedMessage(1060398, cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } else { from.SendLocalizedMessage( @@ -1096,7 +1142,7 @@ namespace Server.Multis DesignContext.Remove(from); // Notify the client that customization has ended - HouseFoundationPackets.SendEndHouseCustomization(from.NetState, Serial); + from.Send(new EndHouseCustomization(this)); // Notify the core that the foundation has changed and should be resent to all clients Delta(ItemDelta.Update); @@ -1237,7 +1283,8 @@ namespace Server.Multis switch (dir) { - default: // North + default: + case 0: // North { xStart = x; yStart = y + height; @@ -1346,12 +1393,16 @@ namespace Server.Multis // Remove the component if (AllowStairSectioning) { - fixState |= DeleteStairs(mcl, itemID, x, y, z); // The client removes the entire set of stairs locally, resend state + if (DeleteStairs(mcl, itemID, x, y, z)) + fixState = true; // The client removes the entire set of stairs locally, resend state mcl.Remove(itemID, x, y, z); } - else if (!DeleteStairs(mcl, itemID, x, y, z)) - mcl.Remove(itemID, x, y, z); + else + { + if (!DeleteStairs(mcl, itemID, x, y, z)) + mcl.Remove(itemID, x, y, z); + } // If needed, replace removed component with a dirt tile if (ax >= 1 && ax < mcl.Width && ay >= 1 && ay < mcl.Height - 1) @@ -1508,8 +1559,7 @@ namespace Server.Multis DesignContext.Remove(from); // Notify the client that customization has ended - - HouseFoundationPackets.SendEndHouseCustomization(from.NetState, context.Foundation.Serial); + from.Send(new EndHouseCustomization(context.Foundation)); // Refresh client with current visible design state context.Foundation.SendInfoTo(state); @@ -1657,8 +1707,7 @@ namespace Server.Multis public class DesignState { - private int m_Revision; - private byte[] m_Packet; + private Packet m_PacketCache; public DesignState(HouseFoundation foundation, MultiComponentList components) { @@ -1710,23 +1759,27 @@ namespace Server.Multis } } + public Packet PacketCache + { + get => m_PacketCache; + set + { + if (m_PacketCache == value) + return; + + m_PacketCache?.Release(); + + m_PacketCache = value; + } + } + public HouseFoundation Foundation{ get; } public MultiComponentList Components{ get; } public MultiTileEntry[] Fixtures{ get; private set; } - public int Revision - { - get => m_Revision; - set => m_Revision = value; - } - - public byte[] Packet - { - get => m_Packet; - set => Interlocked.Exchange(ref m_Packet, value); - } + public int Revision{ get; set; } public void Serialize(GenericWriter writer) { @@ -1752,18 +1805,31 @@ namespace Server.Multis public void OnRevised() { - Interlocked.Exchange(ref m_Revision, ++Foundation.LastRevision); + lock (this) + { + Revision = ++Foundation.LastRevision; + + m_PacketCache?.Release(); + + m_PacketCache = null; + } } public void SendGeneralInfoTo(NetState state) { - HouseFoundationPackets.SendDesignStateGeneral(state, Foundation.Serial, Revision); + state?.Send(new DesignStateGeneral(Foundation, this)); } public void SendDetailedInfoTo(NetState state) { if (state != null) - HouseFoundationPackets.SendDesignDetails(state, Foundation, this); + lock (this) + { + if (m_PacketCache == null) + DesignStateDetailed.SendDetails(state, Foundation, this); + else + state.Send(m_PacketCache); + } } public void FreezeFixtures() @@ -1809,36 +1875,68 @@ namespace Server.Multis } } - public static bool IsFixture(int itemID) => - itemID >= 0x675 && itemID < 0x6F5 || - itemID >= 0x314 && itemID < 0x364 || - itemID >= 0x824 && itemID < 0x834 || - itemID >= 0x839 && itemID < 0x849 || - itemID >= 0x84C && itemID < 0x85C || - itemID >= 0x866 && itemID < 0x876 || - itemID >= 0x0E8 && itemID < 0x0F8 || - itemID >= 0x1FED && itemID < 0x1FFD || - itemID >= 0x181D && itemID < 0x1829 || - itemID >= 0x241F && itemID < 0x2421 || - itemID >= 0x2423 && itemID < 0x2425 || - itemID >= 0x2A05 && itemID < 0x2A1D || - itemID >= 0x319C && itemID < 0x31B0 || - itemID == 0x2D46 || itemID == 0x2D48 || - itemID == 0x2FE2 || itemID == 0x2FE4 || - itemID >= 0x2D63 && itemID < 0x2D70 || - itemID >= 0x319C && itemID < 0x31AF || - itemID >= 0x367B && itemID < 0x369B || - itemID >= 0x409B && itemID < 0x40A3 || - itemID >= 0x410C && itemID < 0x4114 || - itemID >= 0x41C2 && itemID < 0x41CA || - itemID >= 0x41CF && itemID < 0x41D7 || - itemID >= 0x436E && itemID < 0x437E || - itemID >= 0x46DD && itemID < 0x46E5 || - itemID >= 0x4D22 && itemID < 0x4D2A || - itemID >= 0x50C8 && itemID < 0x50D8 || - itemID >= 0x5142 && itemID < 0x514A || - itemID >= 0x9AD7 && itemID < 0x9AE7 || - itemID >= 0x9B3C && itemID < 0x9B4C; + public static bool IsFixture(int itemID) + { + if (itemID >= 0x675 && itemID < 0x6F5) + return true; + if (itemID >= 0x314 && itemID < 0x364) + return true; + if (itemID >= 0x824 && itemID < 0x834) + return true; + if (itemID >= 0x839 && itemID < 0x849) + return true; + if (itemID >= 0x84C && itemID < 0x85C) + return true; + if (itemID >= 0x866 && itemID < 0x876) + return true; + if (itemID >= 0x0E8 && itemID < 0x0F8) + return true; + if (itemID >= 0x1FED && itemID < 0x1FFD) + return true; + if (itemID >= 0x181D && itemID < 0x1829) + return true; + if (itemID >= 0x241F && itemID < 0x2421) + return true; + if (itemID >= 0x2423 && itemID < 0x2425) + return true; + if (itemID >= 0x2A05 && itemID < 0x2A1D) + return true; + if (itemID >= 0x319C && itemID < 0x31B0) + return true; + // ML doors + if (itemID == 0x2D46 || itemID == 0x2D48 || itemID == 0x2FE2 || itemID == 0x2FE4) + return true; + if (itemID >= 0x2D63 && itemID < 0x2D70) + return true; + if (itemID >= 0x319C && itemID < 0x31AF) + return true; + if (itemID >= 0x367B && itemID < 0x369B) + return true; + // SA doors + if (itemID >= 0x409B && itemID < 0x40A3) + return true; + if (itemID >= 0x410C && itemID < 0x4114) + return true; + if (itemID >= 0x41C2 && itemID < 0x41CA) + return true; + if (itemID >= 0x41CF && itemID < 0x41D7) + return true; + if (itemID >= 0x436E && itemID < 0x437E) + return true; + if (itemID >= 0x46DD && itemID < 0x46E5) + return true; + if (itemID >= 0x4D22 && itemID < 0x4D2A) + return true; + if (itemID >= 0x50C8 && itemID < 0x50D8) + return true; + if (itemID >= 0x5142 && itemID < 0x514A) + return true; + // TOL doors + if (itemID >= 0x9AD7 && itemID < 0x9AE7) + return true; + + return itemID >= 0x9B3C && itemID < 0x9B4C; + } } public class ConfirmCommitGump : Gump @@ -1962,17 +2060,17 @@ namespace Server.Multis { Item item = fixtures[i]; - Packets.SendRemoveEntity(state, item.Serial); + state.Send(item.RemovePacket); } if (foundation.Signpost != null) - Packets.SendRemoveEntity(state, foundation.Signpost.Serial); + state.Send(foundation.Signpost.RemovePacket); if (foundation.SignHanger != null) - Packets.SendRemoveEntity(state, foundation.SignHanger.Serial); + state.Send(foundation.SignHanger.RemovePacket); if (foundation.Sign != null) - Packets.SendRemoveEntity(state, foundation.Sign.Serial); + state.Send(foundation.Sign.RemovePacket); } public static void Remove(Mobile from) @@ -2004,7 +2102,9 @@ namespace Server.Multis } context.Foundation.Signpost?.SendInfoTo(state); + context.Foundation.SignHanger?.SendInfoTo(state); + context.Foundation.Sign?.SendInfoTo(state); } } diff --git a/Projects/Scripts/Multis/Houses/HousePlacement.cs b/Projects/Scripts/Multis/HousePlacement.cs similarity index 90% rename from Projects/Scripts/Multis/Houses/HousePlacement.cs rename to Projects/Scripts/Multis/HousePlacement.cs index 5f19d065b..a41b615f4 100644 --- a/Projects/Scripts/Multis/Houses/HousePlacement.cs +++ b/Projects/Scripts/Multis/HousePlacement.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using Server.Regions; using Server.Spells; @@ -158,7 +157,8 @@ namespace Server.Multis bool isFoundation = addTile.Z == 0 && (addTileFlags & TileFlag.Wall) != 0; bool hasSurface = false; - hasFoundation |= isFoundation; + if (isFoundation) + hasFoundation = true; int addTileZ = center.Z + addTile.Z; int addTileTop = addTileZ + addTile.Height; @@ -333,7 +333,29 @@ namespace Server.Multis } } - return yard.Any(t => _houses.Any(b => b.Contains(t))) ? HousePlacementResult.BadStatic : HousePlacementResult.Valid; + for (int i = 0; i < yard.Count; ++i) + foreach (BaseHouse b in _houses) + if (b.Contains(yard[i])) + return HousePlacementResult.BadStatic; // Broke rule #3 + /*Point2D yardPoint = yard[i]; + + IPooledEnumerable eable = map.GetMultiTilesAt( yardPoint.X, yardPoint.Y ); + + foreach ( StaticTile[] tile in eable ) + { + for ( int j = 0; j < tile.Length; ++j ) + { + if ( (TileData.ItemTable[tile[j].ID & TileData.MaxItemValue].Flags & (TileFlag.Impassable | TileFlag.Surface)) != 0 ) + { + eable.Free(); + return HousePlacementResult.BadStatic; // Broke rule #3 + } + } + } + + eable.Free();*/ + + return HousePlacementResult.Valid; } } } diff --git a/Projects/Scripts/Multis/Houses/HousePlacementTool.cs b/Projects/Scripts/Multis/HousePlacementTool.cs similarity index 96% rename from Projects/Scripts/Multis/Houses/HousePlacementTool.cs rename to Projects/Scripts/Multis/HousePlacementTool.cs index 691411efc..6c79e252b 100644 --- a/Projects/Scripts/Multis/Houses/HousePlacementTool.cs +++ b/Projects/Scripts/Multis/HousePlacementTool.cs @@ -611,7 +611,9 @@ namespace Server.Items case HousePlacementResult.Valid: { if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + { from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } else { BaseHouse house = ConstructHouse(from); @@ -622,13 +624,17 @@ namespace Server.Items house.Price = Cost; if (from.AccessLevel >= AccessLevel.GameMaster) + { from.SendMessage("{0} gold would have been withdrawn from your bank if you were not a GM.", Cost.ToString()); + } else { if (Banker.Withdraw(from, Cost)) + { from.SendLocalizedMessage(1060398, Cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } else { house.RemoveKeys(from); @@ -701,7 +707,9 @@ namespace Server.Items case HousePlacementResult.Valid: { if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + { from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } else { from.SendLocalizedMessage(1011576); // This is a valid location. @@ -796,13 +804,16 @@ namespace Server.Items { m_Table.TryGetValue(house.GetType(), out object obj); - return obj switch - { - HousePlacementEntry entry => entry, - List list => list.FirstOrDefault(e => e.MultiID == house.ItemID), - Dictionary table => table[house.ItemID], - _ => null - }; + if (obj is HousePlacementEntry entry) + return entry; + + if (obj is List list) + return list.FirstOrDefault(e => e.MultiID == house.ItemID); + + if (obj is Dictionary table) + return table[house.ItemID]; + + return null; } private static void FillTable(HousePlacementEntry[] entries) @@ -812,7 +823,9 @@ namespace Server.Items HousePlacementEntry e = entries[i]; if (!m_Table.TryGetValue(e.Type, out object obj)) + { m_Table[e.Type] = e; + } else if (obj is HousePlacementEntry entry) { List list = new List { entry, e }; @@ -835,7 +848,10 @@ namespace Server.Items else list.Add(e); } - else if (obj is Dictionary table) table[e.MultiID] = e; + else if (obj is Dictionary table) + { + table[e.MultiID] = e; + } } } } diff --git a/Projects/Scripts/Multis/Houses/HouseSign.cs b/Projects/Scripts/Multis/HouseSign.cs similarity index 100% rename from Projects/Scripts/Multis/Houses/HouseSign.cs rename to Projects/Scripts/Multis/HouseSign.cs diff --git a/Projects/Scripts/Multis/Houses/HouseTeleporter.cs b/Projects/Scripts/Multis/HouseTeleporter.cs similarity index 100% rename from Projects/Scripts/Multis/Houses/HouseTeleporter.cs rename to Projects/Scripts/Multis/HouseTeleporter.cs diff --git a/Projects/Scripts/Multis/Houses/Houses.cs b/Projects/Scripts/Multis/Houses.cs similarity index 96% rename from Projects/Scripts/Multis/Houses/Houses.cs rename to Projects/Scripts/Multis/Houses.cs index 084f93d67..15b1f9fd0 100644 --- a/Projects/Scripts/Multis/Houses/Houses.cs +++ b/Projects/Scripts/Multis/Houses.cs @@ -581,4 +581,4 @@ namespace Server.Multis int version = reader.ReadInt(); } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Multis/Houses/Packets.cs b/Projects/Scripts/Multis/Houses/Packets.cs deleted file mode 100644 index 797ee49f1..000000000 --- a/Projects/Scripts/Multis/Houses/Packets.cs +++ /dev/null @@ -1,366 +0,0 @@ -using System; -using System.Buffers; -using System.Collections.Concurrent; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Server.Buffers; -using Server.Multis; - -namespace Server.Network -{ - public static class HouseFoundationPackets - { - public static void SendBeginHouseCustomization(NetState ns, Serial house) - { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[17]); - writer.Write((byte)0xBF); // Packet ID - writer.Write((ushort)17); // Dynamic Length - - writer.Write((short)0x20); // House Customization - writer.Write(house); - writer.Write((byte)0x04); // Start customization - writer.Position += 2; - writer.Write(0xFFFFFFFF); - writer.Write((byte)0xFF); - - ns.Send(writer.Span); - } - - public static void SendEndHouseCustomization(NetState ns, Serial house) - { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[17]); - writer.Write((byte)0xBF); // Packet ID - writer.Write((ushort)17); // Dynamic Length - - writer.Write((short)0x20); // House Customization - writer.Write(house); - writer.Write((byte)0x05); // End customization - writer.Position += 2; - writer.Write(0xFFFFFFFF); - writer.Write((byte)0xFF); - - ns.Send(writer.Span); - } - - public static void SendDesignStateGeneral(NetState ns, Serial house, int revision) - { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[13]); - writer.Write((byte)0xBF); // Packet ID - writer.Write((ushort)13); // Dynamic Length - - writer.Write((short)0x1D); // Design - writer.Write(house); - writer.Write(revision); - - ns.Send(writer.Span); - } - - private const int MaxItemsPerStairBuffer = 750; - - private static ConcurrentQueue m_SendQueue; - private static AutoResetEvent m_Sync; - - static HouseFoundationPackets() - { - m_SendQueue = new ConcurrentQueue(); - m_Sync = new AutoResetEvent(false); - Task.Run(ProcessDesignStates); - } - - public static void ProcessDesignStates() - { - while (!Core.Closing) - { - m_Sync.WaitOne(); - - int count = m_SendQueue.Count; - - while (count > 0 && m_SendQueue.TryDequeue(out SendQueueEntry sqe)) - try - { - byte[] packet = sqe.m_DesignState.Packet; - - if (packet == null) - { - packet = CreateDesignDetailsPacket(sqe.m_Serial, sqe.m_Revision, sqe.m_xMin, sqe.m_yMin, sqe.m_xMax, - sqe.m_yMax, sqe.m_Tiles); - sqe.m_DesignState.Packet = packet; - return; - } - - sqe.m_NetState.Send(packet); - } - catch (Exception e) - { - Console.WriteLine(e); - - try - { - using StreamWriter op = new StreamWriter("dsd_exceptions.txt", true); - op.WriteLine(e); - } - catch - { - // ignored - } - } - finally - { - count = m_SendQueue.Count; - } - } - } - - public static byte[] CreateDesignDetailsPacket(Serial serial, int revision, int xMin, int yMin, int xMax, int yMax, - MultiTileEntry[] tiles) - { - ArrayBufferWriter bufferWriter = new ArrayBufferWriter(0x10000); - - SpanWriter headWriter = new SpanWriter(stackalloc byte[18]); - headWriter.Write((byte)0xD8); // Packet ID - headWriter.Position += 2; // Dynamic Length - - headWriter.Write((byte)0x03); // Compression Type - headWriter.Position++; - headWriter.Write(serial); - headWriter.Write(revision); - headWriter.Write((short)tiles.Length); - headWriter.Position += 3; // Buffer/Plane count - - int bufferLength = 1; // includes plane count - - int width = xMax - xMin + 1; - int height = yMax - yMin + 1; - - Span planeUsed = stackalloc bool[9]; - Span planeBuffers = stackalloc byte[9216]; - Span stairBuffers = stackalloc byte[MaxItemsPerStairBuffer * 30]; - - int totalStairsUsed = 0; - - for (int i = 0; i < tiles.Length; ++i) - { - MultiTileEntry mte = tiles[i]; - int x = mte.m_OffsetX - xMin; - int y = mte.m_OffsetY - yMin; - int z = mte.m_OffsetZ; - bool floor = TileData.ItemTable[mte.m_ItemID & TileData.MaxItemValue].Height <= 0; - int plane, size; - - switch (z) - { - case 0: - plane = 0; - break; - case 7: - plane = 1; - break; - case 27: - plane = 2; - break; - case 47: - plane = 3; - break; - case 67: - plane = 4; - break; - default: - { - int stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer; - Span stairBuffer = stairBuffers.Slice(stairBufferIndex, MaxItemsPerStairBuffer); - - int byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5; - - stairBuffer[byteIndex++] = (byte)(mte.m_ItemID >> 8); - stairBuffer[byteIndex++] = (byte)mte.m_ItemID; - - stairBuffer[byteIndex++] = (byte)mte.m_OffsetX; - stairBuffer[byteIndex++] = (byte)mte.m_OffsetY; - stairBuffer[byteIndex] = (byte)mte.m_OffsetZ; - - ++totalStairsUsed; - - continue; - } - } - - if (plane == 0) - size = height; - else if (floor) - { - size = height - 2; - x -= 1; - y -= 1; - } - else - { - size = height - 1; - plane += 4; - } - - int index = (x * size + y) * 2; - - if (x < 0 || y < 0 || y >= size || index + 1 >= 0x400) - { - int stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer; - Span stairBuffer = stairBuffers.Slice(stairBufferIndex, MaxItemsPerStairBuffer); - - int byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5; - - stairBuffer[byteIndex++] = (byte)(mte.m_ItemID >> 8); - stairBuffer[byteIndex++] = (byte)mte.m_ItemID; - - stairBuffer[byteIndex++] = (byte)mte.m_OffsetX; - stairBuffer[byteIndex++] = (byte)mte.m_OffsetY; - stairBuffer[byteIndex] = (byte)mte.m_OffsetZ; - - ++totalStairsUsed; - } - else - { - planeUsed[plane] = true; - planeBuffers[plane * 0x400 + index] = (byte)(mte.m_ItemID >> 8); - planeBuffers[plane * 0x400 + index + 1] = (byte)mte.m_ItemID; - } - } - - int planeCount = 0; - int bound = (int)Compression.Compressor.CompressBound(0x400); - - for (int i = 0; i < 9; ++i) - { - if (!planeUsed[i]) - continue; - - ++planeCount; - - int size; - - if (i == 0) - size = width * height * 2; - else if (i < 5) - size = (width - 1) * (height - 2) * 2; - else - size = width * (height - 1) * 2; - - Span inflatedBuffer = planeBuffers.Slice(i * 0x400, 0x400); - Span deflatedBuffer = bufferWriter.GetSpan(bound + 4); - - ulong deflatedLength = (ulong)bound; - ZLibError ce = Compression.Pack(deflatedBuffer.Slice(4), ref deflatedLength, inflatedBuffer, (ulong)size, ZLibQuality.Default); - - if (ce != ZLibError.Okay) - { - Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce); - size = 0; - } - - int length = (int)deflatedLength; - - deflatedBuffer[0] = (byte)(0x20 | i); - deflatedBuffer[1] = (byte)size; - deflatedBuffer[2] = (byte)length; - deflatedBuffer[3] = (byte)(((size >> 4) & 0xF0) | ((length >> 8) & 0xF)); - - bufferLength += 4 + length; - bufferWriter.Advance(length + 4); - } - - int totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer; - bound = (int)Compression.Compressor.CompressBound(MaxItemsPerStairBuffer); - - for (int i = 0; i < totalStairBuffersUsed; ++i) - { - ++planeCount; - - int count = totalStairsUsed - i * MaxItemsPerStairBuffer; - - if (count > MaxItemsPerStairBuffer) - count = MaxItemsPerStairBuffer; - - int size = count * 5; - - Span inflatedBuffer = stairBuffers.Slice(i * MaxItemsPerStairBuffer, MaxItemsPerStairBuffer); - Span deflatedBuffer = bufferWriter.GetSpan(bound + 4); - - ulong deflatedLength = (ulong)bound; - ZLibError ce = Compression.Pack(deflatedBuffer.Slice(4), ref deflatedLength, inflatedBuffer, (ulong)size, ZLibQuality.Default); - - if (ce != ZLibError.Okay) - { - Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce); - deflatedLength = 0; - size = 0; - } - - int length = (int)deflatedLength; - - deflatedBuffer[0] = (byte)(9 + i); - deflatedBuffer[1] = (byte)size; - deflatedBuffer[2] = (byte)length; - deflatedBuffer[3] = (byte)(((size >> 4) & 0xF0) | ((length >> 8) & 0xF)); - - bufferLength += 4 + length; - bufferWriter.Advance(length + 4); - } - - headWriter.Position = 15; - - headWriter.Write((short)bufferLength); // Buffer length - headWriter.Write((byte)planeCount); // Plane count - - headWriter.Position = 1; - int written = headWriter.WrittenCount + bufferWriter.WrittenCount; - headWriter.Write((ushort)written); - - byte[] packet = new byte[written]; - headWriter.CopyTo(packet); - bufferWriter.WrittenSpan.CopyTo(packet.AsSpan(headWriter.WrittenCount)); - - return packet; - } - - private class SendQueueEntry - { - public NetState m_NetState; - public DesignState m_DesignState; - public int m_Revision; - public uint m_Serial; - public MultiTileEntry[] m_Tiles; - public int m_xMin, m_yMin, m_xMax, m_yMax; - - public SendQueueEntry(NetState ns, HouseFoundation foundation, DesignState state) - { - m_NetState = ns; - m_Serial = foundation.Serial; - m_Revision = state.Revision; - m_DesignState = state; - - MultiComponentList mcl = state.Components; - - m_xMin = mcl.Min.X; - m_yMin = mcl.Min.Y; - m_xMax = mcl.Max.X; - m_yMax = mcl.Max.Y; - - m_Tiles = mcl.List; - } - } - - public static void SendDesignDetails(NetState ns, HouseFoundation house, DesignState state) - { - m_SendQueue.Enqueue(new SendQueueEntry(ns, house, state)); - m_Sync.Set(); - } - } -} diff --git a/Projects/Scripts/Multis/Houses/MovingCrate.cs b/Projects/Scripts/Multis/MovingCrate.cs similarity index 88% rename from Projects/Scripts/Multis/Houses/MovingCrate.cs rename to Projects/Scripts/Multis/MovingCrate.cs index 9087a8c96..a29857e71 100644 --- a/Projects/Scripts/Multis/Houses/MovingCrate.cs +++ b/Projects/Scripts/Multis/MovingCrate.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Items; using Server.Network; @@ -50,8 +49,19 @@ namespace Server.Multis public override void DropItem(Item dropped) { // 1. Try to stack the item - if (Items.Any(item => item is PackingBox && item.Items.Any(subItem => !(subItem is Container) && subItem.StackWith(null, dropped, false)))) - return; + foreach (Item item in Items) + if (item is PackingBox) + { + List subItems = item.Items; + + for (int i = 0; i < subItems.Count; i++) + { + Item subItem = subItems[i]; + + if (!(subItem is Container) && subItem.StackWith(null, dropped, false)) + return; + } + } // 2. Try to drop the item into an existing container foreach (Item item in Items) @@ -163,7 +173,12 @@ namespace Server.Multis m_InternalizeTimer = null; } - foreach (Item item in Items.Where(item => item is PackingBox && item.Items.Count == 0)) + List toRemove = new List(); + foreach (Item item in Items) + if (item is PackingBox && item.Items.Count == 0) + toRemove.Add(item); + + foreach (Item item in toRemove) item.Delete(); if (TotalItems == 0) diff --git a/Projects/Scripts/Multis/Houses/PreviewHouse.cs b/Projects/Scripts/Multis/PreviewHouse.cs similarity index 100% rename from Projects/Scripts/Multis/Houses/PreviewHouse.cs rename to Projects/Scripts/Multis/PreviewHouse.cs diff --git a/Projects/Scripts/Network/Packets.cs b/Projects/Scripts/Network/Packets.cs deleted file mode 100644 index 7bcbb06b7..000000000 --- a/Projects/Scripts/Network/Packets.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Server.Buffers; - -namespace Server.Network -{ - public static class ContentPackets - { - public static void SendDisplayHelpTopic(NetState ns, int topicID, bool display) - { - if (ns == null) - return; - - SpanWriter writer = new SpanWriter(stackalloc byte[11]); - writer.Write((byte)0xBF); // Packet ID - writer.Write((ushort)11); // Dynamic Length - - writer.Write((short)0x17); // Command - writer.Write((byte)1); - writer.Write(topicID); - writer.Write(display); - - ns.Send(writer.Span); - } - } -} diff --git a/Projects/Scripts/Regions/GuardedRegion.cs b/Projects/Scripts/Regions/GuardedRegion.cs index c12319f00..39a6df5d8 100644 --- a/Projects/Scripts/Regions/GuardedRegion.cs +++ b/Projects/Scripts/Regions/GuardedRegion.cs @@ -90,14 +90,17 @@ namespace Server.Regions GuardedRegion reg = from.Region.GetRegion(); if (reg == null) + { from.SendMessage("You are not in a guardable region."); + } else { reg.Disabled = !e.GetBoolean(0); - from.SendMessage(reg.Disabled - ? "The guards in this region have been disabled." - : "The guards in this region have been enabled."); + if (reg.Disabled) + from.SendMessage("The guards in this region have been disabled."); + else + from.SendMessage("The guards in this region have been enabled."); } } else @@ -190,6 +193,12 @@ namespace Server.Regions CheckGuardCandidate(m); } + public override void OnExit(Mobile m) + { +// if (IsDisabled()) + return; + } + public override void OnSpeech(SpeechEventArgs args) { base.OnSpeech(args); diff --git a/Projects/Scripts/Regions/Spawning/SpawnEntry.cs b/Projects/Scripts/Regions/Spawning/SpawnEntry.cs index 4ff99d1eb..471577845 100644 --- a/Projects/Scripts/Regions/Spawning/SpawnEntry.cs +++ b/Projects/Scripts/Regions/Spawning/SpawnEntry.cs @@ -264,7 +264,9 @@ namespace Server.Regions if (entity != null) { - m_RemoveList ??= new List(); + if (m_RemoveList == null) + m_RemoveList = new List(); + m_RemoveList.Add(entity); } } diff --git a/Projects/Scripts/Regions/Spawning/SpawnPersistence.cs b/Projects/Scripts/Regions/Spawning/SpawnPersistence.cs index 7999f8718..e4c827e68 100644 --- a/Projects/Scripts/Regions/Spawning/SpawnPersistence.cs +++ b/Projects/Scripts/Regions/Spawning/SpawnPersistence.cs @@ -15,7 +15,8 @@ namespace Server.Regions public static void EnsureExistence() { - m_Instance ??= new SpawnPersistence(); + if (m_Instance == null) + m_Instance = new SpawnPersistence(); } public override void Serialize(GenericWriter writer) @@ -53,4 +54,4 @@ namespace Server.Regions } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Scripts.csproj b/Projects/Scripts/Scripts.csproj index cf2ce83f4..f3b49987e 100644 --- a/Projects/Scripts/Scripts.csproj +++ b/Projects/Scripts/Scripts.csproj @@ -15,7 +15,6 @@ ..\..\Distribution\Assemblies ..\..\Distribution\Assemblies ..\..\Distribution\Assemblies - ..\..\Distribution\Assemblies TRACE;DEBUG diff --git a/Projects/Scripts/Skills/Anatomy.cs b/Projects/Scripts/Skills/Anatomy.cs index e6580f8be..e4ab479a5 100644 --- a/Projects/Scripts/Skills/Anatomy.cs +++ b/Projects/Scripts/Skills/Anatomy.cs @@ -83,7 +83,7 @@ namespace Server.SkillHandlers } else { - (targeted as Item)?.SendLocalizedMessageTo(from, 500323); // Only living things have anatomies! + (targeted as Item)?.SendLocalizedMessageTo(from, 500323, ""); // Only living things have anatomies! } } } diff --git a/Projects/Scripts/Skills/AnimalTaming.cs b/Projects/Scripts/Skills/AnimalTaming.cs index 040f55549..a24a80936 100644 --- a/Projects/Scripts/Skills/AnimalTaming.cs +++ b/Projects/Scripts/Skills/AnimalTaming.cs @@ -338,7 +338,8 @@ namespace Server.SkillHandlers if (!alreadyOwned) // Passively check animal lore for gain m_Tamer.CheckTargetSkill(SkillName.AnimalLore, m_Creature, 0.0, 120.0); - m_Paralyzed |= m_Creature.Paralyzed; + if (m_Creature.Paralyzed) + m_Paralyzed = true; } else { @@ -346,7 +347,8 @@ namespace Server.SkillHandlers m_Tamer.NextSkillTime = Core.TickCount; m_BeingTamed.Remove(m_Creature); - m_Paralyzed |= m_Creature.Paralyzed; + if (m_Creature.Paralyzed) + m_Paralyzed = true; if (!alreadyOwned) // Passively check animal lore for gain m_Tamer.CheckTargetSkill(SkillName.AnimalLore, m_Creature, 0.0, 120.0); diff --git a/Projects/Scripts/Skills/Discordance.cs b/Projects/Scripts/Skills/Discordance.cs index f003c124a..25ea05e79 100644 --- a/Projects/Scripts/Skills/Discordance.cs +++ b/Projects/Scripts/Skills/Discordance.cs @@ -50,13 +50,16 @@ namespace Server.SkillHandlers // According to uoherald bard must remain alive, visible, and // within range of the target or the effect ends in 15 seconds. if (!targ.Alive || targ.Deleted || !from.Alive || from.Hidden) + { ends = true; + } else { int range = (int)targ.GetDistanceToSqrt(from); int maxRange = BaseInstrument.GetBardRange(from, SkillName.Discordance); - ends |= from.Map != targ.Map || range > maxRange; + if (from.Map != targ.Map || range > maxRange) + ends = true; } if (ends && info.m_Ending && info.m_EndTime < DateTime.UtcNow) diff --git a/Projects/Scripts/Skills/EvalInt.cs b/Projects/Scripts/Skills/EvalInt.cs index 1e61bbc66..60524153f 100644 --- a/Projects/Scripts/Skills/EvalInt.cs +++ b/Projects/Scripts/Skills/EvalInt.cs @@ -84,7 +84,8 @@ namespace Server.SkillHandlers } else { - (targeted as Item)?.SendLocalizedMessageTo(from, 500908); // It looks smarter than a rock, but dumber than a piece of wood. + (targeted as Item)?.SendLocalizedMessageTo(from, 500908, + ""); // It looks smarter than a rock, but dumber than a piece of wood. } } } diff --git a/Projects/Scripts/Skills/Hiding.cs b/Projects/Scripts/Skills/Hiding.cs index 7143ffffd..c136c666e 100644 --- a/Projects/Scripts/Skills/Hiding.cs +++ b/Projects/Scripts/Skills/Hiding.cs @@ -30,10 +30,13 @@ namespace Server.SkillHandlers BaseHouse house = BaseHouse.FindHouseAt(m); if (house?.IsFriend(m) == true) + { bonus = 100.0; + } else if (!Core.AOS) { - house ??= BaseHouse.FindHouseAt(new Point3D(m.X - 1, m.Y, 127), m.Map, 16) ?? + if (house == null) + house = BaseHouse.FindHouseAt(new Point3D(m.X - 1, m.Y, 127), m.Map, 16) ?? BaseHouse.FindHouseAt(new Point3D(m.X + 1, m.Y, 127), m.Map, 16) ?? BaseHouse.FindHouseAt(new Point3D(m.X, m.Y - 1, 127), m.Map, 16) ?? BaseHouse.FindHouseAt(new Point3D(m.X, m.Y + 1, 127), m.Map, 16); @@ -77,6 +80,7 @@ namespace Server.SkillHandlers else { m.RevealingAction(); + m.LocalOverheadMessage(MessageType.Regular, 0x22, 501241); // You can't seem to hide here. } diff --git a/Projects/Scripts/Skills/ItemIdentification.cs b/Projects/Scripts/Skills/ItemIdentification.cs index bedc35364..e3a168a19 100644 --- a/Projects/Scripts/Skills/ItemIdentification.cs +++ b/Projects/Scripts/Skills/ItemIdentification.cs @@ -39,13 +39,19 @@ namespace Server.Items item.OnSingleClick(from); } else + { from.SendLocalizedMessage(500353); // You are not certain... + } } else if (o is Mobile mobile) + { mobile.OnSingleClick(from); + } else + { from.SendLocalizedMessage(500353); // You are not certain... + } } } } -} +} \ No newline at end of file diff --git a/Projects/Scripts/Skills/SpiritSpeak.cs b/Projects/Scripts/Skills/SpiritSpeak.cs index 94e184297..d24077635 100644 --- a/Projects/Scripts/Skills/SpiritSpeak.cs +++ b/Projects/Scripts/Skills/SpiritSpeak.cs @@ -127,7 +127,7 @@ namespace Server.SkillHandlers public override void OnCast() { IPooledEnumerable eable = Caster.GetItemsInRange(3); - Corpse toChannel = eable.FirstOrDefault(corpse => corpse?.Channeled == false); + Corpse toChannel = eable.FirstOrDefault(item => item is Corpse corpse && !corpse.Channeled); eable.Free(); int min = 1 + (int)(Caster.Skills.SpiritSpeak.Value * 0.25); diff --git a/Projects/Scripts/Skills/Tracking.cs b/Projects/Scripts/Skills/Tracking.cs index 5f071b20b..391c88e0b 100644 --- a/Projects/Scripts/Skills/Tracking.cs +++ b/Projects/Scripts/Skills/Tracking.cs @@ -106,7 +106,7 @@ namespace Server.SkillHandlers AddHtmlLocalized(320, 90, 100, 20, 1018090); // Players } - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID >= 1 && info.ButtonID <= 4) TrackWhoGump.DisplayTo(m_Success, m_From, info.ButtonID - 1); @@ -261,7 +261,7 @@ namespace Server.SkillHandlers private static bool IsPlayer(Mobile m) => m.Player; - public override void OnResponse(NetState sender, RelayInfo info) + public override void OnResponse(NetState state, RelayInfo info) { int index = info.ButtonID - 1; diff --git a/Projects/Scripts/SpecialSystems/Engines/TestCenter.cs b/Projects/Scripts/SpecialSystems/Engines/TestCenter.cs index b60d06ebd..5e8944f8a 100644 --- a/Projects/Scripts/SpecialSystems/Engines/TestCenter.cs +++ b/Projects/Scripts/SpecialSystems/Engines/TestCenter.cs @@ -59,7 +59,9 @@ namespace Server.Misc private static void ChangeStrength(Mobile from, int value) { if (value < 10 || value > 125) + { from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. + } else { if (value + from.RawDex + from.RawInt > from.StatCap) @@ -78,7 +80,9 @@ namespace Server.Misc private static void ChangeDexterity(Mobile from, int value) { if (value < 10 || value > 125) + { from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. + } else { if (from.RawStr + value + from.RawInt > from.StatCap) @@ -97,7 +101,9 @@ namespace Server.Misc private static void ChangeIntelligence(Mobile from, int value) { if (value < 10 || value > 125) + { from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. + } else { if (from.RawStr + from.RawDex + value > from.StatCap) @@ -126,7 +132,9 @@ namespace Server.Misc if (skill != null) { if (value < 0 || value > skill.Cap) + { from.SendMessage($"Your skill in {skill.Info.Name} is capped at {skill.Cap:F1}."); + } else { int newFixedPoint = (int)(value * 10.0); @@ -139,7 +147,9 @@ namespace Server.Misc } } else + { from.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. + } } @@ -189,8 +199,8 @@ namespace Server.Misc if (sb.Length + 1 + v.Length >= 256) { - Packets.SendAsciiMessage(sender, Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, - "System", sb.ToString()); + sender.Send(new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, + "System", sb.ToString())); sb = new StringBuilder(); sb.Append(v); } @@ -202,8 +212,8 @@ namespace Server.Misc } if (sb.Length > 0) - Packets.SendAsciiMessage(sender, Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, "System", - sb.ToString()); + sender.Send(new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, "System", + sb.ToString())); break; } diff --git a/Projects/Scripts/SpecialSystems/Items/Stones/GMStone.cs b/Projects/Scripts/SpecialSystems/Items/Stones/GMStone.cs new file mode 100644 index 000000000..4b7023151 --- /dev/null +++ b/Projects/Scripts/SpecialSystems/Items/Stones/GMStone.cs @@ -0,0 +1,56 @@ +#if false +using System; +using Server.Network; +using Server.Commands; + +namespace Server.Items +{ + public class GMStone : Item + { + public override string DefaultName + { + get { return "a GM stone"; } + } + + [Constructible] + public GMStone() : base( 0xED4 ) + { + Movable = false; + Hue = 0x489; + } + + public GMStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel < AccessLevel.GameMaster ) + { + from.AccessLevel = AccessLevel.GameMaster; + + from.SendAsciiMessage( 0x482, "The command prefix is \"{0}\"", CommandSystem.Prefix ); + CommandHandlers.Help_OnCommand( new CommandEventArgs( from, "help", "", new string[0] ) ); + } + else + { + from.SendMessage( "The stone has no effect." ); + } + } + } +} +#endif \ No newline at end of file diff --git a/Projects/Scripts/Spells/Base/SpecialMove.cs b/Projects/Scripts/Spells/Base/SpecialMove.cs index d42a7a5e1..c46f4b88f 100644 --- a/Projects/Scripts/Spells/Base/SpecialMove.cs +++ b/Projects/Scripts/Spells/Base/SpecialMove.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Engines.ConPVP; using Server.Items; using Server.Network; @@ -12,7 +11,7 @@ namespace Server.Spells { public abstract class SpecialMove { - private static readonly Dictionary m_PlayersTable = new Dictionary(); + private static Dictionary m_PlayersTable = new Dictionary(); public virtual int BaseMana => 0; @@ -182,8 +181,13 @@ namespace Server.Spells public static void ClearAllMoves(Mobile m) { - foreach (var (moveID, _) in SpellRegistry.SpecialMoves.Where(kvp => kvp.Key != -1)) - Packets.SendToggleSpecialAbility(m.NetState, (short)(moveID + 1), false); + foreach (KeyValuePair kvp in SpellRegistry.SpecialMoves) + { + int moveID = kvp.Key; + + if (moveID != -1) + m.Send(new ToggleSpecialAbility(moveID + 1, false)); + } } public static SpecialMove GetCurrentMove(Mobile m) @@ -238,7 +242,7 @@ namespace Server.Spells int moveID = SpellRegistry.GetRegistryNumber(move); if (moveID > 0) - Packets.SendToggleSpecialAbility(m.NetState, (short)(moveID + 1), true); + m.Send(new ToggleSpecialAbility(moveID + 1, true)); TextDefinition.SendMessageTo(m, move.AbilityMessage); } @@ -255,7 +259,7 @@ namespace Server.Spells int moveID = SpellRegistry.GetRegistryNumber(move); if (moveID > 0) - Packets.SendToggleSpecialAbility(m.NetState, (short)(moveID + 1), false); + m.Send(new ToggleSpecialAbility(moveID + 1, false)); } Table.Remove(m); diff --git a/Projects/Scripts/Spells/Base/SpellHelper.cs b/Projects/Scripts/Spells/Base/SpellHelper.cs index 6512ad3db..a197a62c8 100644 --- a/Projects/Scripts/Spells/Base/SpellHelper.cs +++ b/Projects/Scripts/Spells/Base/SpellHelper.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Server.Engines.CannedEvil; using Server.Engines.ConPVP; using Server.Engines.PartySystem; @@ -149,8 +148,13 @@ namespace Server.Spells public static bool DisableSkillCheck{ get; set; } - public static TimeSpan GetDamageDelayForSpell(Spell sp) => - !sp.DelayedDamage ? TimeSpan.Zero : Core.AOS ? AosDamageDelay : OldDamageDelay; + public static TimeSpan GetDamageDelayForSpell(Spell sp) + { + if (!sp.DelayedDamage) + return TimeSpan.Zero; + + return Core.AOS ? AosDamageDelay : OldDamageDelay; + } public static bool CheckMulti(Point3D p, Map map, bool houses = true, int housingrange = 0) { @@ -169,7 +173,9 @@ namespace Server.Spells return true; } else if (multi.Contains(p)) + { return true; + } } return false; @@ -185,15 +191,36 @@ namespace Server.Spells if (item.RootParent != from) from.Direction = from.GetDirectionTo(item.GetWorldLocation()); } - else if (!ReferenceEquals(from, target)) + else if (from != target) + { from.Direction = from.GetDirectionTo(target); + } } - public static bool CheckCombat(Mobile m) => - RestrictTravelCombat && - (m.Aggressed.Any(info => info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay) || - Core.Expansion == Expansion.AOS && m.Aggressors.Any(info => - info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay)); + public static bool CheckCombat(Mobile m) + { + if (!RestrictTravelCombat) + return false; + + for (int i = 0; i < m.Aggressed.Count; ++i) + { + AggressorInfo info = m.Aggressed[i]; + + if (info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay) + return true; + } + + if (Core.Expansion == Expansion.AOS) + for (int i = 0; i < m.Aggressors.Count; ++i) + { + AggressorInfo info = m.Aggressors[i]; + + if (info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay) + return true; + } + + return false; + } public static bool AdjustField(ref Point3D p, Map map, int height, bool mobsBlock) { @@ -219,7 +246,9 @@ namespace Server.Spells public static void GetSurfaceTop(ref IPoint3D p) { if (p is Item item) + { p = item.GetSurfaceTop(); + } else if (p is StaticTarget t) { int z = t.Z; @@ -231,10 +260,15 @@ namespace Server.Spells } } - public static bool AddStatOffset(Mobile m, StatType type, int offset, TimeSpan duration) => - offset > 0 - ? AddStatBonus(m, m, type, offset, duration) - : offset >= 0 || AddStatCurse(m, m, type, -offset, duration); + public static bool AddStatOffset(Mobile m, StatType type, int offset, TimeSpan duration) + { + if (offset > 0) + return AddStatBonus(m, m, type, offset, duration); + if (offset < 0) + return AddStatCurse(m, m, type, -offset, duration); + + return true; + } public static bool AddStatBonus(Mobile caster, Mobile target, StatType type) => AddStatBonus(caster, target, type, GetOffset(caster, target, type, false), GetDuration(caster, target)); @@ -570,7 +604,7 @@ namespace Server.Spells // Always allow monsters to teleport if (caster is BaseCreature bc && !bc.Controlled && !bc.Summoned && (type == TravelCheckType.TeleportTo || type == TravelCheckType.TeleportFrom)) - return true; + return true; m_TravelCaster = caster; m_TravelType = type; diff --git a/Projects/Scripts/Spells/Bushido/SamuraiSpell.cs b/Projects/Scripts/Spells/Bushido/SamuraiSpell.cs index 61fe27436..4af7c7ca7 100644 --- a/Projects/Scripts/Spells/Bushido/SamuraiSpell.cs +++ b/Projects/Scripts/Spells/Bushido/SamuraiSpell.cs @@ -106,7 +106,7 @@ namespace Server.Spells.Bushido int spellID = SpellRegistry.GetRegistryNumber(this); if (spellID > 0) - Packets.SendToggleSpecialAbility(caster.NetState, (short)(spellID + 1), true); + caster.Send(new ToggleSpecialAbility(spellID + 1, true)); } public static void OnEffectEnd(Mobile caster, Type type) @@ -114,7 +114,7 @@ namespace Server.Spells.Bushido int spellID = SpellRegistry.GetRegistryNumber(type); if (spellID > 0) - Packets.SendToggleSpecialAbility(caster.NetState, (short)(spellID + 1), false); + caster.Send(new ToggleSpecialAbility(spellID + 1, false)); } } } diff --git a/Projects/Scripts/Spells/Chivalry/DispelEvil.cs b/Projects/Scripts/Spells/Chivalry/DispelEvil.cs index 9677bb90c..d76a6bebc 100644 --- a/Projects/Scripts/Spells/Chivalry/DispelEvil.cs +++ b/Projects/Scripts/Spells/Chivalry/DispelEvil.cs @@ -74,7 +74,7 @@ namespace Server.Spells.Chivalry if (evil) { // TODO: Is this right? - double fleeChance = (100 - Math.Sqrt(m.Fame / 2.0)) * chiv * dispelSkill; + double fleeChance = (100 - Math.Sqrt(m.Fame / 2)) * chiv * dispelSkill; fleeChance /= 1000000; if (fleeChance > Utility.RandomDouble()) bc.BeginFlee(TimeSpan.FromSeconds(30.0)); diff --git a/Projects/Scripts/Spells/Chivalry/NobleSacrifice.cs b/Projects/Scripts/Spells/Chivalry/NobleSacrifice.cs index dc091a26a..1bb57d30a 100644 --- a/Projects/Scripts/Spells/Chivalry/NobleSacrifice.cs +++ b/Projects/Scripts/Spells/Chivalry/NobleSacrifice.cs @@ -135,10 +135,16 @@ namespace Server.Spells.Chivalry sendEffect = true; } + if (EvilOmenSpell.TryEndEffect(m)) + sendEffect = true; + + if (StrangleSpell.RemoveCurse(m)) + sendEffect = true; + + if (CorpseSkinSpell.RemoveCurse(m)) + sendEffect = true; + // TODO: Should this remove blood oath? Pain spike? - sendEffect |= EvilOmenSpell.TryEndEffect(m); - sendEffect |= StrangleSpell.RemoveCurse(m); - sendEffect |= CorpseSkinSpell.RemoveCurse(m); if (sendEffect) { diff --git a/Projects/Scripts/Spells/Chivalry/SacredJourney.cs b/Projects/Scripts/Spells/Chivalry/SacredJourney.cs index 58d14c605..5ca1a4152 100644 --- a/Projects/Scripts/Spells/Chivalry/SacredJourney.cs +++ b/Projects/Scripts/Spells/Chivalry/SacredJourney.cs @@ -76,9 +76,13 @@ namespace Server.Spells.Chivalry public void Effect(Point3D loc, Map map, bool checkMulti) { if (Sigil.ExistsOn(Caster)) + { Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } else if (map == null || !Core.AOS && Caster.Map != map) + { Caster.SendLocalizedMessage(1005569); // You can not recall to another facet. + } else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.RecallFrom)) { } @@ -86,21 +90,37 @@ namespace Server.Spells.Chivalry { } else if (map == Map.Felucca && Caster is PlayerMobile mobile && mobile.Young) + { mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. + } else if (Caster.Kills >= 5 && map != Map.Felucca) + { Caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. + } else if (Caster.Criminal) + { Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + } else if (SpellHelper.CheckCombat(Caster)) + { Caster.SendLocalizedMessage(1061282); // You cannot use the Sacred Journey ability to flee from combat. + } else if (WeightOverloading.IsOverloaded(Caster)) + { Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + } else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z)) + { Caster.SendLocalizedMessage(501942); // That location is blocked. + } else if (checkMulti && SpellHelper.CheckMulti(loc, map)) + { Caster.SendLocalizedMessage(501942); // That location is blocked. + } else if (m_Book != null && m_Book.CurCharges <= 0) + { Caster.SendLocalizedMessage(502412); // There are no charges left on that item. + } else if (CheckSequence()) { BaseCreature.TeleportPets(Caster, loc, map, true); diff --git a/Projects/Scripts/Spells/Eighth/AirElemental.cs b/Projects/Scripts/Spells/Eighth/AirElemental.cs index fb5c60b0f..0aec5b631 100644 --- a/Projects/Scripts/Spells/Eighth/AirElemental.cs +++ b/Projects/Scripts/Spells/Eighth/AirElemental.cs @@ -39,7 +39,7 @@ namespace Server.Spells.Eighth { if (CheckSequence()) { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); if (Core.AOS) SpellHelper.Summon(new SummonedAirElemental(), Caster, 0x217, duration, false, false); diff --git a/Projects/Scripts/Spells/Eighth/EarthElemental.cs b/Projects/Scripts/Spells/Eighth/EarthElemental.cs index 53c93a25b..18dfceb2a 100644 --- a/Projects/Scripts/Spells/Eighth/EarthElemental.cs +++ b/Projects/Scripts/Spells/Eighth/EarthElemental.cs @@ -39,7 +39,7 @@ namespace Server.Spells.Eighth { if (CheckSequence()) { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); if (Core.AOS) SpellHelper.Summon(new SummonedEarthElemental(), Caster, 0x217, duration, false, false); diff --git a/Projects/Scripts/Spells/Eighth/FireElemental.cs b/Projects/Scripts/Spells/Eighth/FireElemental.cs index 4c20faa05..62e37ff46 100644 --- a/Projects/Scripts/Spells/Eighth/FireElemental.cs +++ b/Projects/Scripts/Spells/Eighth/FireElemental.cs @@ -40,7 +40,7 @@ namespace Server.Spells.Eighth { if (CheckSequence()) { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); if (Core.AOS) SpellHelper.Summon(new SummonedFireElemental(), Caster, 0x217, duration, false, false); diff --git a/Projects/Scripts/Spells/Eighth/SummonDaemon.cs b/Projects/Scripts/Spells/Eighth/SummonDaemon.cs index eb97176f4..b5853ac02 100644 --- a/Projects/Scripts/Spells/Eighth/SummonDaemon.cs +++ b/Projects/Scripts/Spells/Eighth/SummonDaemon.cs @@ -40,7 +40,7 @@ namespace Server.Spells.Eighth { if (CheckSequence()) { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); if (Core.AOS) /* Why two diff daemons? TODO: solve this */ { diff --git a/Projects/Scripts/Spells/Eighth/WaterElemental.cs b/Projects/Scripts/Spells/Eighth/WaterElemental.cs index a0672ffce..122871ba5 100644 --- a/Projects/Scripts/Spells/Eighth/WaterElemental.cs +++ b/Projects/Scripts/Spells/Eighth/WaterElemental.cs @@ -39,7 +39,7 @@ namespace Server.Spells.Eighth { if (CheckSequence()) { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); if (Core.AOS) SpellHelper.Summon(new SummonedWaterElemental(), Caster, 0x217, duration, false, false); diff --git a/Projects/Scripts/Spells/Fifth/PoisonField.cs b/Projects/Scripts/Spells/Fifth/PoisonField.cs index 3d3eefff2..4eb0f9aae 100644 --- a/Projects/Scripts/Spells/Fifth/PoisonField.cs +++ b/Projects/Scripts/Spells/Fifth/PoisonField.cs @@ -47,7 +47,16 @@ namespace Server.Spells.Fifth int rx = (dx - dy) * 44; int ry = (dx + dy) * 44; - bool eastToWest = (rx < 0 || ry < 0) && (rx >= 0 || ry >= 0); + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; Effects.PlaySound(p, Caster.Map, 0x20B); diff --git a/Projects/Scripts/Spells/Fifth/SummonCreature.cs b/Projects/Scripts/Spells/Fifth/SummonCreature.cs index 2450b148b..4786ce796 100644 --- a/Projects/Scripts/Spells/Fifth/SummonCreature.cs +++ b/Projects/Scripts/Spells/Fifth/SummonCreature.cs @@ -70,7 +70,7 @@ namespace Server.Spells.Fifth TimeSpan duration; if (Core.AOS) - duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); + duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); else duration = TimeSpan.FromSeconds(4.0 * Caster.Skills.Magery.Value); diff --git a/Projects/Scripts/Spells/First/Clumsy.cs b/Projects/Scripts/Spells/First/Clumsy.cs index 7f1f952c0..e0d0e1e49 100644 --- a/Projects/Scripts/Spells/First/Clumsy.cs +++ b/Projects/Scripts/Spells/First/Clumsy.cs @@ -51,7 +51,7 @@ namespace Server.Spells.First int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); TimeSpan length = SpellHelper.GetDuration(Caster, m); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Clumsy, 1075831, percentage.ToString(), length, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Clumsy, 1075831, length, m, percentage.ToString())); HarmfulSpell(m); } diff --git a/Projects/Scripts/Spells/First/Feeblemind.cs b/Projects/Scripts/Spells/First/Feeblemind.cs index bb4d08dcb..37344a029 100644 --- a/Projects/Scripts/Spells/First/Feeblemind.cs +++ b/Projects/Scripts/Spells/First/Feeblemind.cs @@ -49,7 +49,7 @@ namespace Server.Spells.First int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); TimeSpan length = SpellHelper.GetDuration(Caster, m); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.FeebleMind, 1075833, percentage.ToString(), length, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.FeebleMind, 1075833, length, m, percentage.ToString())); HarmfulSpell(m); } diff --git a/Projects/Scripts/Spells/First/NightSight.cs b/Projects/Scripts/Spells/First/NightSight.cs index bc835d146..7de4cf18f 100644 --- a/Projects/Scripts/Spells/First/NightSight.cs +++ b/Projects/Scripts/Spells/First/NightSight.cs @@ -35,7 +35,7 @@ namespace Server.Spells.First { SpellHelper.Turn(m_Spell.Caster, targ); - if (targ.BeginAction()) + if (targ.BeginAction()) { new LightCycle.NightSightTimer(targ).Start(); int level = (int)(LightCycle.DungeonLevel * diff --git a/Projects/Scripts/Spells/First/ReactiveArmor.cs b/Projects/Scripts/Spells/First/ReactiveArmor.cs index 3184dd922..521b6397a 100644 --- a/Projects/Scripts/Spells/First/ReactiveArmor.cs +++ b/Projects/Scripts/Spells/First/ReactiveArmor.cs @@ -80,7 +80,7 @@ namespace Server.Spells.First int physresist = 15 + (int)(targ.Skills.Inscribe.Value / 20); string args = $"{physresist}\t{5}\t{5}\t{5}\t{5}"; - BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ReactiveArmor, 1075812, args)); + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ReactiveArmor, 1075812, 1075813, args)); } else { diff --git a/Projects/Scripts/Spells/First/Weaken.cs b/Projects/Scripts/Spells/First/Weaken.cs index abe97a0c7..8584877e0 100644 --- a/Projects/Scripts/Spells/First/Weaken.cs +++ b/Projects/Scripts/Spells/First/Weaken.cs @@ -49,7 +49,7 @@ namespace Server.Spells.First int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); TimeSpan length = SpellHelper.GetDuration(Caster, m); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Weaken, 1075837, percentage.ToString(), length, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Weaken, 1075837, length, m, percentage.ToString())); HarmfulSpell(m); } diff --git a/Projects/Scripts/Spells/Fourth/ArchCure.cs b/Projects/Scripts/Spells/Fourth/ArchCure.cs index 57e763ad6..7f9f0d27e 100644 --- a/Projects/Scripts/Spells/Fourth/ArchCure.cs +++ b/Projects/Scripts/Spells/Fourth/ArchCure.cs @@ -124,9 +124,23 @@ namespace Server.Spells.Fourth return true; } - private bool IsAggressor(Mobile m) => Caster.Aggressors.Any(info => m == info.Attacker && !info.Expired); + private bool IsAggressor(Mobile m) + { + foreach (AggressorInfo info in Caster.Aggressors) + if (m == info.Attacker && !info.Expired) + return true; - private bool IsAggressed(Mobile m) => Caster.Aggressed.Any(info => m == info.Defender && !info.Expired); + return false; + } + + private bool IsAggressed(Mobile m) + { + foreach (AggressorInfo info in Caster.Aggressed) + if (m == info.Defender && !info.Expired) + return true; + + return false; + } private static bool IsInnocentTo(Mobile from, Mobile to) => Notoriety.Compute(from, to) == Notoriety.Innocent; diff --git a/Projects/Scripts/Spells/Fourth/Curse.cs b/Projects/Scripts/Spells/Fourth/Curse.cs index 29209a4f4..59e66a42a 100644 --- a/Projects/Scripts/Spells/Fourth/Curse.cs +++ b/Projects/Scripts/Spells/Fourth/Curse.cs @@ -77,7 +77,7 @@ namespace Server.Spells.Fourth string args = $"{percentage}\t{percentage}\t{percentage}\t{10}\t{10}\t{10}\t{10}"; - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Curse, 1075835, args, length, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Curse, 1075835, 1075836, length, m, args)); HarmfulSpell(m); } diff --git a/Projects/Scripts/Spells/Fourth/FireField.cs b/Projects/Scripts/Spells/Fourth/FireField.cs index 6a603c400..376732848 100644 --- a/Projects/Scripts/Spells/Fourth/FireField.cs +++ b/Projects/Scripts/Spells/Fourth/FireField.cs @@ -47,7 +47,16 @@ namespace Server.Spells.Fourth int rx = (dx - dy) * 44; int ry = (dx + dy) * 44; - bool eastToWest = (rx < 0 || ry < 0) && (rx >= 0 || ry >= 0); + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; Effects.PlaySound(p, Caster.Map, 0x20C); @@ -56,7 +65,7 @@ namespace Server.Spells.Fourth TimeSpan duration; if (Core.AOS) - duration = TimeSpan.FromSeconds((15 + Caster.Skills.Magery.Fixed / 5.0) / 4.0); + duration = TimeSpan.FromSeconds((15 + Caster.Skills.Magery.Fixed / 5) / 4); else duration = TimeSpan.FromSeconds(4.0 + Caster.Skills.Magery.Value * 0.5); diff --git a/Projects/Scripts/Spells/Fourth/Lightning.cs b/Projects/Scripts/Spells/Fourth/Lightning.cs index 0ead57c77..151054b36 100644 --- a/Projects/Scripts/Spells/Fourth/Lightning.cs +++ b/Projects/Scripts/Spells/Fourth/Lightning.cs @@ -58,7 +58,7 @@ namespace Server.Spells.Fourth damage *= GetDamageScalar(m); } - m.BoltEffect(); + m.BoltEffect(0); SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 100); } diff --git a/Projects/Scripts/Spells/Mysticism/HailStormSpell.cs b/Projects/Scripts/Spells/Mysticism/HailStormSpell.cs index 338bbaaae..53c2b8fa4 100644 --- a/Projects/Scripts/Spells/Mysticism/HailStormSpell.cs +++ b/Projects/Scripts/Spells/Mysticism/HailStormSpell.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Server.Network; namespace Server.Spells.Mysticism { @@ -66,7 +67,8 @@ namespace Server.Spells.Mysticism targets.Add(m); - pvp |= m.Player; + if (m.Player) + pvp = true; } } } @@ -111,7 +113,9 @@ namespace Server.Spells.Mysticism private static void SendEffectPacket(IPoint3D p, Map map, Point3D orig, Point3D dest) { - Effects.SendMovingEffect(p, orig, dest, map, 0x36D4, 0, 0, false, false, 0x63, 4); + Effects.SendPacket(p, map, + new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x36D4, orig, dest, 0, 0, false, false, 0x63, + 0x4)); } } } diff --git a/Projects/Scripts/Spells/Mysticism/NetherCycloneSpell.cs b/Projects/Scripts/Spells/Mysticism/NetherCycloneSpell.cs index bc2bd0758..36ec20616 100644 --- a/Projects/Scripts/Spells/Mysticism/NetherCycloneSpell.cs +++ b/Projects/Scripts/Spells/Mysticism/NetherCycloneSpell.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Server.Network; namespace Server.Spells.Mysticism { @@ -69,7 +70,8 @@ namespace Server.Spells.Mysticism targets.Add(m); - pvp |= m.Player; + if (m.Player) + pvp = true; } } } @@ -120,7 +122,9 @@ namespace Server.Spells.Mysticism private static void SendEffectPacket(IPoint3D p, Map map, Point3D orig, Point3D dest) { - Effects.SendMovingEffect(p, orig, dest, map, 0x375A, 0, 0, false, false, 0x49A, 4); + Effects.SendPacket(p, map, + new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x375A, orig, dest, 0, 0, false, false, 0x49A, + 0x4)); } } } diff --git a/Projects/Scripts/Spells/Mysticism/StoneFormSpell.cs b/Projects/Scripts/Spells/Mysticism/StoneFormSpell.cs index ac5d5656b..d3ede2835 100644 --- a/Projects/Scripts/Spells/Mysticism/StoneFormSpell.cs +++ b/Projects/Scripts/Spells/Mysticism/StoneFormSpell.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Server.Factions; +using Server.Mobiles; using Server.Spells.Fifth; using Server.Spells.Ninjitsu; using Server.Spells.Seventh; @@ -117,7 +118,7 @@ namespace Server.Spells.Mysticism Caster.PlaySound(0x65A); Caster.Delta(MobileDelta.Resistances); - BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.StoneForm, 1080145, + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.StoneForm, 1080145, 1080146, $"-10\t-2\t{offset}\t{GetResistCapBonus(Caster)}\t{GetDIBonus(Caster)}", false)); } } diff --git a/Projects/Scripts/Spells/Necromancy/BloodOathSpell.cs b/Projects/Scripts/Spells/Necromancy/BloodOathSpell.cs index 58727cf9b..d30a5b2f6 100644 --- a/Projects/Scripts/Spells/Necromancy/BloodOathSpell.cs +++ b/Projects/Scripts/Spells/Necromancy/BloodOathSpell.cs @@ -81,8 +81,8 @@ namespace Server.Spells.Necromancy timer = new ExpireTimer(Caster, m, duration); timer.Start(); - BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.BloodOathCaster, 1075659, m.Name, duration, Caster)); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.BloodOathCurse, 1075661, Caster.Name, duration, m)); + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.BloodOathCurse, 1075661, duration, m, Caster.Name)); m_Table[m] = timer; HarmfulSpell(m); diff --git a/Projects/Scripts/Spells/Necromancy/Exorcism.cs b/Projects/Scripts/Spells/Necromancy/Exorcism.cs index efcb84ef3..9d7c8940d 100644 --- a/Projects/Scripts/Spells/Necromancy/Exorcism.cs +++ b/Projects/Scripts/Spells/Necromancy/Exorcism.cs @@ -87,7 +87,9 @@ namespace Server.Spells.Necromancy { ChampionSpawnRegion r = Caster.Region.GetRegion(); if (r == null || !Caster.InRange(r.ChampionSpawn, Range)) + { Caster.SendLocalizedMessage(1072111); // You are not in a valid exorcism region. + } else if (CheckSequence()) { Map map = Caster.Map; @@ -96,7 +98,6 @@ namespace Server.Spells.Necromancy { IEnumerable targets = r.ChampionSpawn.GetMobilesInRange(Range).Where(IsValidTarget); - //Surprisingly, no sparkle type effects foreach (Mobile m in targets) //Surprisingly, no sparkle type effects m.Location = GetNearestShrine(m); @@ -133,7 +134,7 @@ namespace Server.Spells.Necromancy Guild mGuild = m.Guild as Guild; Guild cGuild = Caster.Guild as Guild; - if (mGuild?.IsAlly(cGuild) == true) + if (mGuild.IsAlly(cGuild)) return false; if (mGuild == cGuild) diff --git a/Projects/Scripts/Spells/Necromancy/PainSpike.cs b/Projects/Scripts/Spells/Necromancy/PainSpike.cs index 5b48e06ac..79b03d0f0 100644 --- a/Projects/Scripts/Spells/Necromancy/PainSpike.cs +++ b/Projects/Scripts/Spells/Necromancy/PainSpike.cs @@ -73,7 +73,7 @@ namespace Server.Spells.Necromancy buffTime = timer.Next - DateTime.UtcNow; } - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.PainSpike, 1075667, ((int)damage).ToString(), buffTime, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.PainSpike, 1075667, buffTime, m, Convert.ToString((int)damage))); // TODO: Find a better way to do this WeightOverloading.DFA = DFAlgorithm.PainSpike; diff --git a/Projects/Scripts/Spells/Necromancy/Strangle.cs b/Projects/Scripts/Spells/Necromancy/Strangle.cs index f5f4ecc9b..5d02a6627 100644 --- a/Projects/Scripts/Spells/Necromancy/Strangle.cs +++ b/Projects/Scripts/Spells/Necromancy/Strangle.cs @@ -14,7 +14,7 @@ namespace Server.Spells.Necromancy Reagent.NoxCrystal ); - private static readonly Dictionary m_Table = new Dictionary(); + private static Dictionary m_Table = new Dictionary(); public StrangleSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) { @@ -104,7 +104,7 @@ namespace Server.Spells.Necromancy } TimeSpan t_Duration = TimeSpan.FromSeconds(i_Length); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, args, t_Duration, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, 1075795, t_Duration, m, args)); FinishSequence(); } diff --git a/Projects/Scripts/Spells/Ninjitsu/AnimalForm.cs b/Projects/Scripts/Spells/Ninjitsu/AnimalForm.cs index 5968c49aa..96711d893 100644 --- a/Projects/Scripts/Spells/Ninjitsu/AnimalForm.cs +++ b/Projects/Scripts/Spells/Ninjitsu/AnimalForm.cs @@ -70,7 +70,7 @@ namespace Server.Spells.Ninjitsu public static void OnLogin(LoginEventArgs e) { if (GetContext(e.Mobile)?.SpeedBoost == true) - Packets.SendSpeedControlMount(e.Mobile.NetState); + e.Mobile.Send(SpeedControl.MountSpeed); } public override bool CheckCast() @@ -228,7 +228,7 @@ namespace Server.Spells.Ninjitsu m.HueMod = hueMod; if (entry.SpeedBoost) - Packets.SendSpeedControlMount(m.NetState); + m.Send(SpeedControl.MountSpeed); SkillMod mod = null; @@ -275,7 +275,7 @@ namespace Server.Spells.Ninjitsu m_Table.Remove(m); if (context.SpeedBoost) - Packets.SendSpeedControlDisabled(m.NetState); + m.Send(SpeedControl.Disable); SkillMod mod = context.Mod; @@ -575,7 +575,7 @@ namespace Server.Spells.Ninjitsu { m_Mobile.RevealingAction(); m_Mobile.PlaySound(0x227); - Effects.SendMovingEffect(m_Mobile, target, 0x36D4, 5, 0); + Effects.SendMovingEffect(m_Mobile, target, 0x36D4, 5, 0, false, false); DelayCall(TimeSpan.FromSeconds(1), BreathDamage_Callback, target); } diff --git a/Projects/Scripts/Spells/Second/Agility.cs b/Projects/Scripts/Spells/Second/Agility.cs index 8520e4762..ce8b7e4c0 100644 --- a/Projects/Scripts/Spells/Second/Agility.cs +++ b/Projects/Scripts/Spells/Second/Agility.cs @@ -55,7 +55,7 @@ namespace Server.Spells.Second int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); TimeSpan length = SpellHelper.GetDuration(Caster, m); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Agility, 1075841, percentage.ToString(), length, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Agility, 1075841, length, m, percentage.ToString())); } FinishSequence(); diff --git a/Projects/Scripts/Spells/Second/Cunning.cs b/Projects/Scripts/Spells/Second/Cunning.cs index bc822edb6..fac065ce5 100644 --- a/Projects/Scripts/Spells/Second/Cunning.cs +++ b/Projects/Scripts/Spells/Second/Cunning.cs @@ -55,7 +55,7 @@ namespace Server.Spells.Second int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); TimeSpan length = SpellHelper.GetDuration(Caster, m); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Cunning, 1075843, percentage.ToString(), length, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Cunning, 1075843, length, m, percentage.ToString())); } FinishSequence(); diff --git a/Projects/Scripts/Spells/Second/Protection.cs b/Projects/Scripts/Spells/Second/Protection.cs index ac2ec16ac..f4587ed26 100644 --- a/Projects/Scripts/Spells/Second/Protection.cs +++ b/Projects/Scripts/Spells/Second/Protection.cs @@ -75,7 +75,7 @@ namespace Server.Spells.Second int physloss = -15 + (int)(caster.Skills.Inscribe.Value / 20); int resistloss = -35 + (int)(caster.Skills.Inscribe.Value / 20); string args = $"{physloss}\t{resistloss}"; - BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Protection, 1075814, args)); + BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Protection, 1075814, 1075815, args)); } else { diff --git a/Projects/Scripts/Spells/Second/Strength.cs b/Projects/Scripts/Spells/Second/Strength.cs index 8faf62cee..bc05a93ff 100644 --- a/Projects/Scripts/Spells/Second/Strength.cs +++ b/Projects/Scripts/Spells/Second/Strength.cs @@ -55,7 +55,7 @@ namespace Server.Spells.Second int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); TimeSpan length = SpellHelper.GetDuration(Caster, m); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strength, 1075845, percentage.ToString(), length, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strength, 1075845, length, m, percentage.ToString())); } FinishSequence(); diff --git a/Projects/Scripts/Spells/Seventh/ChainLightning.cs b/Projects/Scripts/Spells/Seventh/ChainLightning.cs index 9db5df46c..9609f56f3 100644 --- a/Projects/Scripts/Spells/Seventh/ChainLightning.cs +++ b/Projects/Scripts/Spells/Seventh/ChainLightning.cs @@ -59,7 +59,8 @@ namespace Server.Spells.Seventh !Caster.CanBeHarmful(m, false)) return false; - playerVsPlayer |= m.Player; + if (m.Player) + playerVsPlayer = true; return true; }).ToList()); @@ -67,7 +68,9 @@ namespace Server.Spells.Seventh eable.Free(); } - double damage = Core.AOS ? GetNewAosDamage(51, 1, 5, playerVsPlayer) + double damage; + + damage = Core.AOS ? GetNewAosDamage(51, 1, 5, playerVsPlayer) : Utility.Random(27, 22); if (targets.Count > 0) @@ -93,11 +96,13 @@ namespace Server.Spells.Seventh Caster.DoHarmful(m); SpellHelper.Damage(this, m, toDeal, 0, 0, 0, 0, 100); - m.BoltEffect(); + m.BoltEffect(0); } } else + { Caster.PlaySound(0x29); + } } FinishSequence(); diff --git a/Projects/Scripts/Spells/Seventh/EnergyField.cs b/Projects/Scripts/Spells/Seventh/EnergyField.cs index 802985ba0..f14dbe3c6 100644 --- a/Projects/Scripts/Spells/Seventh/EnergyField.cs +++ b/Projects/Scripts/Spells/Seventh/EnergyField.cs @@ -47,7 +47,16 @@ namespace Server.Spells.Seventh int rx = (dx - dy) * 44; int ry = (dx + dy) * 44; - bool eastToWest = (rx < 0 || ry < 0) && (rx >= 0 || ry >= 0); + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; Effects.PlaySound(p, Caster.Map, 0x20B); @@ -134,7 +143,7 @@ namespace Server.Spells.Seventh { if (!(m is PlayerMobile)) return base.OnMoveOver(m); - + int noto = Notoriety.Compute(m_Caster, m); return noto != Notoriety.Enemy && noto != Notoriety.Ally && base.OnMoveOver(m); } diff --git a/Projects/Scripts/Spells/Seventh/GateTravel.cs b/Projects/Scripts/Spells/Seventh/GateTravel.cs index 4770aea31..bca60d29c 100644 --- a/Projects/Scripts/Spells/Seventh/GateTravel.cs +++ b/Projects/Scripts/Spells/Seventh/GateTravel.cs @@ -67,9 +67,13 @@ namespace Server.Spells.Seventh public void Effect(Point3D loc, Map map, bool checkMulti) { if (Sigil.ExistsOn(Caster)) + { Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } else if (map == null || !Core.AOS && Caster.Map != map) + { Caster.SendLocalizedMessage(1005570); // You can not gate to another facet. + } else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.GateFrom)) { } @@ -77,19 +81,34 @@ namespace Server.Spells.Seventh { } else if (map == Map.Felucca && Caster is PlayerMobile mobile && mobile.Young) + { mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. + } else if (Caster.Kills >= 5 && map != Map.Felucca) + { Caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. + } else if (Caster.Criminal) + { Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + } else if (SpellHelper.CheckCombat(Caster)) + { Caster.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? + } else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z)) + { Caster.SendLocalizedMessage(501942); // That location is blocked. + } else if (checkMulti && SpellHelper.CheckMulti(loc, map)) + { Caster.SendLocalizedMessage(501942); // That location is blocked. - else if (Core.SE && (GateExistsAt(map, loc) || GateExistsAt(Caster.Map, Caster.Location))) // SE restricted stacking gates + } + else if (Core.SE && (GateExistsAt(map, loc) || GateExistsAt(Caster.Map, Caster.Location)) + ) // SE restricted stacking gates + { Caster.SendLocalizedMessage(1071242); // There is already a gate there. + } else if (CheckSequence()) { Caster.SendLocalizedMessage(501024); // You open a magical gate to another location diff --git a/Projects/Scripts/Spells/Seventh/MeteorSwarm.cs b/Projects/Scripts/Spells/Seventh/MeteorSwarm.cs index 0aa30c2c6..3acc34147 100644 --- a/Projects/Scripts/Spells/Seventh/MeteorSwarm.cs +++ b/Projects/Scripts/Spells/Seventh/MeteorSwarm.cs @@ -59,7 +59,8 @@ namespace Server.Spells.Seventh Core.AOS && !Caster.InLOS(m)) return false; - playerVsPlayer |= m.Player; + if (m.Player) + playerVsPlayer = true; return true; }).ToList(); @@ -71,7 +72,9 @@ namespace Server.Spells.Seventh targets = new List(); } - double damage = Core.AOS ? GetNewAosDamage(51, 1, 5, playerVsPlayer) + double damage; + + damage = Core.AOS ? GetNewAosDamage(51, 1, 5, playerVsPlayer) : Utility.Random(27, 22); if (targets.Count > 0) diff --git a/Projects/Scripts/Spells/Seventh/Polymorph.cs b/Projects/Scripts/Spells/Seventh/Polymorph.cs index 2031fbe95..b1842fbb2 100644 --- a/Projects/Scripts/Spells/Seventh/Polymorph.cs +++ b/Projects/Scripts/Spells/Seventh/Polymorph.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Server.Factions; using Server.Gumps; using Server.Items; +using Server.Mobiles; using Server.Spells.Fifth; namespace Server.Spells.Seventh diff --git a/Projects/Scripts/Spells/Sixth/Mark.cs b/Projects/Scripts/Spells/Sixth/Mark.cs index 1ffb89196..336e25172 100644 --- a/Projects/Scripts/Spells/Sixth/Mark.cs +++ b/Projects/Scripts/Spells/Sixth/Mark.cs @@ -31,8 +31,8 @@ namespace Server.Spells.Sixth public void Target(Item item) { if (!(item is RecallRune rune)) - Packets.SendMessageLocalized(Caster.NetState, Caster.Serial, Caster.Body, MessageType.Regular, - 0x3B2, 3, 501797, Caster.Name); // I cannot mark that object. + Caster.Send(new MessageLocalized(Caster.Serial, Caster.Body, MessageType.Regular, 0x3B2, 3, 501797, Caster.Name, + "")); // I cannot mark that object. else if (!Caster.CanSee(rune)) Caster.SendLocalizedMessage(500237); // Target can not be seen. else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.Mark)) diff --git a/Projects/Scripts/Spells/Sixth/ParalyzeField.cs b/Projects/Scripts/Spells/Sixth/ParalyzeField.cs index 78ad1a38b..4f16ac735 100644 --- a/Projects/Scripts/Spells/Sixth/ParalyzeField.cs +++ b/Projects/Scripts/Spells/Sixth/ParalyzeField.cs @@ -46,7 +46,16 @@ namespace Server.Spells.Sixth int rx = (dx - dy) * 44; int ry = (dx + dy) * 44; - bool eastToWest = (rx < 0 || ry < 0) && (rx >= 0 || ry >= 0); + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; Effects.PlaySound(p, Caster.Map, 0x20B); diff --git a/Projects/Scripts/Spells/Spellweaving/AttuneWeapon.cs b/Projects/Scripts/Spells/Spellweaving/AttuneWeapon.cs index 2376fc843..938cfdc44 100644 --- a/Projects/Scripts/Spells/Spellweaving/AttuneWeapon.cs +++ b/Projects/Scripts/Spells/Spellweaving/AttuneWeapon.cs @@ -61,7 +61,7 @@ namespace Server.Spells.Spellweaving Caster.BeginAction(); BuffInfo.AddBuff(Caster, - new BuffInfo(BuffIcon.AttuneWeapon, 1075798, damageAbsorb.ToString(), duration, Caster)); + new BuffInfo(BuffIcon.AttuneWeapon, 1075798, duration, Caster, damageAbsorb.ToString())); } FinishSequence(); diff --git a/Projects/Scripts/Spells/Spellweaving/EssenceOfWind.cs b/Projects/Scripts/Spells/Spellweaving/EssenceOfWind.cs index 70c04b7dc..11fc81d31 100644 --- a/Projects/Scripts/Spells/Spellweaving/EssenceOfWind.cs +++ b/Projects/Scripts/Spells/Spellweaving/EssenceOfWind.cs @@ -51,7 +51,8 @@ namespace Server.Spells.Spellweaving m_Table[m] = new EssenceOfWindInfo(m, fcMalus, ssiMalus, duration); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EssenceOfWind, 1075802, $"{fcMalus}\t{ssiMalus}", duration, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EssenceOfWind, 1075802, duration, m, + $"{fcMalus.ToString()}\t{ssiMalus.ToString()}")); } eable.Free(); diff --git a/Projects/Scripts/Spells/Spellweaving/GiftOfLife.cs b/Projects/Scripts/Spells/Spellweaving/GiftOfLife.cs index fe3425e57..f04154d49 100644 --- a/Projects/Scripts/Spells/Spellweaving/GiftOfLife.cs +++ b/Projects/Scripts/Spells/Spellweaving/GiftOfLife.cs @@ -77,7 +77,7 @@ namespace Server.Spells.Spellweaving m_Table[m] = t; - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.GiftOfLife, 1031615, 1075807, duration, true, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.GiftOfLife, 1031615, 1075807, duration, m, null, true)); } FinishSequence(); diff --git a/Projects/Scripts/Spells/Spellweaving/GiftOfRenewal.cs b/Projects/Scripts/Spells/Spellweaving/GiftOfRenewal.cs index 45fdea610..b1734b3dd 100644 --- a/Projects/Scripts/Spells/Spellweaving/GiftOfRenewal.cs +++ b/Projects/Scripts/Spells/Spellweaving/GiftOfRenewal.cs @@ -75,7 +75,7 @@ namespace Server.Spells.Spellweaving Caster.BeginAction(); BuffInfo.AddBuff(m, - new BuffInfo(BuffIcon.GiftOfRenewal, 1031602, 1075797, hitsPerRound.ToString(), duration, m)); + new BuffInfo(BuffIcon.GiftOfRenewal, 1031602, 1075797, duration, m, hitsPerRound.ToString())); } } diff --git a/Projects/Scripts/Spells/Spellweaving/ReaperForm.cs b/Projects/Scripts/Spells/Spellweaving/ReaperForm.cs index 80530393f..ff693ec24 100644 --- a/Projects/Scripts/Spells/Spellweaving/ReaperForm.cs +++ b/Projects/Scripts/Spells/Spellweaving/ReaperForm.cs @@ -37,19 +37,19 @@ namespace Server.Spells.Spellweaving TransformContext context = TransformationSpellHelper.GetContext(e.Mobile); if (context?.Type == typeof(ReaperFormSpell)) - Packets.SendSpeedControlWalk(e.Mobile.NetState); + e.Mobile.Send(SpeedControl.WalkSpeed); } public override void DoEffect(Mobile m) { m.PlaySound(0x1BA); - Packets.SendSpeedControlWalk(m.NetState); + m.Send(SpeedControl.WalkSpeed); } public override void RemoveEffect(Mobile m) { - Packets.SendSpeedControlDisabled(m.NetState); + m.Send(SpeedControl.Disable); } } } diff --git a/Projects/Scripts/Spells/Spellweaving/Thunderstorm.cs b/Projects/Scripts/Spells/Spellweaving/Thunderstorm.cs index 6fe73c0e1..f4d2c558c 100644 --- a/Projects/Scripts/Spells/Spellweaving/Thunderstorm.cs +++ b/Projects/Scripts/Spells/Spellweaving/Thunderstorm.cs @@ -66,7 +66,7 @@ namespace Server.Spells.Spellweaving m_Table[m] = Timer.DelayCall(duration, DoExpire, m); BuffInfo.AddBuff(m, - new BuffInfo(BuffIcon.Thunderstorm, 1075800, GetCastRecoveryMalus(m).ToString(), duration, m)); + new BuffInfo(BuffIcon.Thunderstorm, 1075800, duration, m, GetCastRecoveryMalus(m))); } eable.Free(); diff --git a/Projects/Scripts/Spells/Targeting/RecallSpellTarget.cs b/Projects/Scripts/Spells/Targeting/RecallSpellTarget.cs index f032f96ee..b74530dfb 100644 --- a/Projects/Scripts/Spells/Targeting/RecallSpellTarget.cs +++ b/Projects/Scripts/Spells/Targeting/RecallSpellTarget.cs @@ -40,13 +40,18 @@ namespace Server.Spells if (!boat.Deleted && boat.CheckKey(key.KeyValue)) m_Spell.Effect(boat.GetMarkedLocation(), boat.Map, false); else - Packets.SendMessageLocalized(from.NetState, from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, - from.Name); // I can not recall from that object. + from.Send(new MessageLocalized(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, + from.Name, "")); // I can not recall from that object. } else if (o is HouseRaffleDeed deed && deed.ValidLocation()) + { m_Spell.Effect(deed.PlotLocation, deed.PlotFacet, true); + } else - Packets.SendMessageLocalized(from.NetState, from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name); // I can not recall from that object. + { + from.Send(new MessageLocalized(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, + "")); // I can not recall from that object. + } } protected override void OnNonlocalTarget(Mobile from, object o) diff --git a/Projects/Scripts/Spells/Third/Bless.cs b/Projects/Scripts/Spells/Third/Bless.cs index f11c740dd..47e26354a 100644 --- a/Projects/Scripts/Spells/Third/Bless.cs +++ b/Projects/Scripts/Spells/Third/Bless.cs @@ -61,7 +61,7 @@ namespace Server.Spells.Third string args = $"{percentage}\t{percentage}\t{percentage}"; - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Bless, 1075847, 1075848, args, length, m)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Bless, 1075847, 1075848, length, m, args)); } FinishSequence(); diff --git a/Projects/Scripts/Spells/Third/WallOfStone.cs b/Projects/Scripts/Spells/Third/WallOfStone.cs index 6346344d0..430a37b69 100644 --- a/Projects/Scripts/Spells/Third/WallOfStone.cs +++ b/Projects/Scripts/Spells/Third/WallOfStone.cs @@ -44,7 +44,16 @@ namespace Server.Spells.Third int rx = (dx - dy) * 44; int ry = (dx + dy) * 44; - bool eastToWest = (rx < 0 || ry < 0) && (rx >= 0 || ry >= 0); + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; Effects.PlaySound(p, Caster.Map, 0x1F6); diff --git a/Projects/Server/Diagnostics/BaseProfile.cs b/Projects/Server/Diagnostics/BaseProfile.cs index 316cad869..bbc7804a5 100644 --- a/Projects/Server/Diagnostics/BaseProfile.cs +++ b/Projects/Server/Diagnostics/BaseProfile.cs @@ -50,7 +50,7 @@ namespace Server.Diagnostics { List list = new List(profiles); - list.Sort((a, b) => -a.TotalTime.CompareTo(b.TotalTime)); + list.Sort(delegate(T a, T b) { return -a.TotalTime.CompareTo(b.TotalTime); }); foreach (T prof in list) { @@ -85,4 +85,4 @@ namespace Server.Diagnostics PeakTime.TotalSeconds, TotalTime.TotalSeconds); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Effects.cs b/Projects/Server/Effects.cs index bbe7dd0f0..ead626d02 100644 --- a/Projects/Server/Effects.cs +++ b/Projects/Server/Effects.cs @@ -48,26 +48,44 @@ namespace Server ParticleSupportType == ParticleSupportType.Full || ParticleSupportType == ParticleSupportType.Detect && state.IsUOTDClient; - public static void PlaySound(IPoint3D p, Map map, int soundId) + public static void PlaySound(IPoint3D p, Map map, int soundID) { - if (soundId <= -1) + if (soundID <= -1) return; if (map != null) { - IPooledEnumerable eable = map.GetClientsInRange(p); + Packet playSound = null; + + IPooledEnumerable eable = map.GetClientsInRange(new Point3D(p)); foreach (NetState state in eable) { state.Mobile.ProcessDelta(); - Packets.SendPlaySound(state, soundId, p); + + if (playSound == null) + playSound = Packet.Acquire(new PlaySound(soundID, p)); + + state.Send(playSound); } + Packet.Release(playSound); + eable.Free(); } } - public static void SendBoltEffect(IEntity e, bool sound = true) + public static void SendBoltEffect(IEntity e) + { + SendBoltEffect(e, true, 0); + } + + public static void SendBoltEffect(IEntity e, bool sound) + { + SendBoltEffect(e, sound, 0); + } + + public static void SendBoltEffect(IEntity e, bool sound, int hue) { Map map = e.Map; @@ -76,35 +94,61 @@ namespace Server e.ProcessDelta(); + Packet preEffect = null, boltEffect = null, playSound = null; + IPooledEnumerable eable = map.GetClientsInRange(e.Location); foreach (NetState state in eable) if (state.Mobile.CanSee(e)) { if (SendParticlesTo(state)) - Packets.SendTargetParticleEffect(state, e, 0, 10, 5, 0, 0, 5031, 3, 0); + { + if (preEffect == null) + preEffect = Packet.Acquire(new TargetParticleEffect(e, 0, 10, 5, 0, 0, 5031, 3, 0)); - Packets.SendBoltEffect(state, e); + state.Send(preEffect); + } + + if (boltEffect == null) + boltEffect = Packet.Acquire(new BoltEffect(e, hue)); + + state.Send(boltEffect); if (sound) - Packets.SendPlaySound(state, 0x29, e); + { + if (playSound == null) + playSound = Packet.Acquire(new PlaySound(0x29, e)); + + state.Send(playSound); + } } + Packet.Release(preEffect); + Packet.Release(boltEffect); + Packet.Release(playSound); + eable.Free(); } - public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int speed = 10, int hue = 0, - int renderMode = 0) + public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration) { - IPooledEnumerable eable = map.GetClientsInRange(p); + SendLocationEffect(p, map, itemID, duration, 10, 0, 0); + } - foreach (NetState state in eable) - { - state.Mobile.ProcessDelta(); - Packets.SendLocationHuedEffect(state, p, itemID, speed, duration, hue, renderMode); - } + public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int speed) + { + SendLocationEffect(p, map, itemID, duration, speed, 0, 0); + } - eable.Free(); + public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int hue, int renderMode) + { + SendLocationEffect(p, map, itemID, duration, 10, hue, renderMode); + } + + public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int speed, int hue, + int renderMode) + { + SendPacket(p, map, new LocationEffect(p, itemID, speed, duration, hue, renderMode)); } public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect) @@ -122,39 +166,63 @@ namespace Server { Map map = e.Map; - if (map == null) - return; - - IPooledEnumerable eable = map.GetClientsInRange(e.Location); - - foreach (NetState state in eable) + if (map != null) { - state.Mobile.ProcessDelta(); + Packet particles = null, regular = null; - if (SendParticlesTo(state)) - Packets.SendLocationParticleEffect(state, e, itemID, speed, duration, hue, - renderMode, effect, unknown); - else if (itemID != 0) - Packets.SendLocationHuedEffect(state, e, itemID, speed, duration, hue, renderMode); + IPooledEnumerable eable = map.GetClientsInRange(e.Location); + + foreach (NetState state in eable) + { + state.Mobile.ProcessDelta(); + + if (SendParticlesTo(state)) + { + if (particles == null) + particles = Packet.Acquire(new LocationParticleEffect(e, itemID, speed, duration, hue, + renderMode, effect, unknown)); + + state.Send(particles); + } + else if (itemID != 0) + { + if (regular == null) + regular = Packet.Acquire(new LocationEffect(e, itemID, speed, duration, hue, renderMode)); + + state.Send(regular); + } + } + + Packet.Release(particles); + Packet.Release(regular); + + eable.Free(); } - eable.Free(); + //SendPacket( e.Location, e.Map, new LocationParticleEffect( e, itemID, speed, duration, hue, renderMode, effect, unknown ) ); } - public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration, int hue = 0, int renderMode = 0) + public static void SendTargetEffect(IEntity target, int itemID, int duration) + { + SendTargetEffect(target, itemID, duration, 0, 0); + } + + public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration) + { + SendTargetEffect(target, itemID, speed, duration, 0, 0); + } + + public static void SendTargetEffect(IEntity target, int itemID, int duration, int hue, int renderMode) + { + SendTargetEffect(target, itemID, 10, duration, hue, renderMode); + } + + public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration, int hue, int renderMode) { if (target is Mobile mobile) mobile.ProcessDelta(); - IPooledEnumerable eable = target.Map.GetClientsInRange(target.Location); - - foreach (NetState state in eable) - { - state.Mobile.ProcessDelta(); - Packets.SendTargetHuedEffect(state, target, itemID, speed, duration, hue, renderMode); - } - - eable.Free(); + SendPacket(target.Location, target.Map, new TargetEffect(target, itemID, speed, duration, hue, renderMode)); } public static void SendTargetParticles(IEntity target, int itemID, int speed, int duration, int effect, @@ -177,47 +245,44 @@ namespace Server Map map = target.Map; - if (map == null) - return; - - IPooledEnumerable eable = map.GetClientsInRange(target.Location); - - foreach (NetState state in eable) + if (map != null) { - state.Mobile.ProcessDelta(); + Packet particles = null, regular = null; - if (SendParticlesTo(state)) - Packets.SendTargetParticleEffect(state, target, itemID, speed, duration, hue, - renderMode, effect, (int)layer, unknown); - else if (itemID != 0) - Packets.SendTargetHuedEffect(state, target, itemID, speed, duration, hue, renderMode); + IPooledEnumerable eable = map.GetClientsInRange(target.Location); + + foreach (NetState state in eable) + { + state.Mobile.ProcessDelta(); + + if (SendParticlesTo(state)) + { + if (particles == null) + particles = Packet.Acquire(new TargetParticleEffect(target, itemID, speed, duration, hue, + renderMode, effect, (int)layer, unknown)); + + state.Send(particles); + } + else if (itemID != 0) + { + if (regular == null) + regular = Packet.Acquire(new TargetEffect(target, itemID, speed, duration, hue, renderMode)); + + state.Send(regular); + } + } + + Packet.Release(particles); + Packet.Release(regular); + + eable.Free(); } - eable.Free(); - } - - public static void SendMovingEffect(IPoint3D from, IPoint3D to, Map map, int itemID, int speed = 0, int duration = 0, - bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0) - { - SendMovingEffect(from, from, to, map, itemID, speed, duration, fixedDirection, explodes, hue, renderMode); - } - - public static void SendMovingEffect(IPoint3D range, IPoint3D from, IPoint3D to, Map map, int itemID, int speed = 0, int duration = 0, - bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0) - { - IPooledEnumerable eable = map.GetClientsInRange(range); - - foreach (NetState state in eable) - { - state.Mobile.ProcessDelta(); - Packets.SendMovingHuedEffect(state, from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode); - } - - eable.Free(); + //SendPacket( target.Location, target.Map, new TargetParticleEffect( target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown ) ); } public static void SendMovingEffect(IEntity from, IEntity to, int itemID, int speed, int duration, - bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0) + bool fixedDirection, bool explodes, int hue = 0, int renderMode = 0) { if (from is Mobile mobile) mobile.ProcessDelta(); @@ -225,15 +290,8 @@ namespace Server if (to is Mobile mobile1) mobile1.ProcessDelta(); - IPooledEnumerable eable = from.Map.GetClientsInRange(from.Location); - - foreach (NetState state in eable) - { - state.Mobile.ProcessDelta(); - Packets.SendMovingHuedEffect(state, from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode); - } - - eable.Free(); + SendPacket(from.Location, from.Map, + new MovingEffect(from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode)); } public static void SendMovingParticles(IEntity from, IEntity to, int itemID, int speed, int duration, @@ -270,25 +328,82 @@ namespace Server Map map = from.Map; + if (map != null) + { + Packet particles = null, regular = null; + + IPooledEnumerable eable = map.GetClientsInRange(from.Location); + + foreach (NetState state in eable) + { + state.Mobile.ProcessDelta(); + + if (SendParticlesTo(state)) + { + if (particles == null) + particles = Packet.Acquire(new MovingParticleEffect(from, to, itemID, speed, duration, + fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, layer, + unknown)); + + state.Send(particles); + } + else if (itemID > 1) + { + if (regular == null) + regular = Packet.Acquire(new MovingEffect(from, to, itemID, speed, duration, fixedDirection, + explodes, hue, renderMode)); + + state.Send(regular); + } + } + + Packet.Release(particles); + Packet.Release(regular); + + eable.Free(); + } + + //SendPacket( from.Location, from.Map, new MovingParticleEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, unknown ) ); + } + + public static void SendPacket(Point3D origin, Map map, Packet p) + { if (map == null) return; + + IPooledEnumerable eable = map.GetClientsInRange(origin); - IPooledEnumerable eable = map.GetClientsInRange(from.Location); + p.Acquire(); foreach (NetState state in eable) { state.Mobile.ProcessDelta(); - - if (SendParticlesTo(state)) - Packets.SendMovingParticleEffect(state, from, to, itemID, speed, duration, - fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, layer, - unknown); - else if (itemID > 1) - Packets.SendMovingHuedEffect(state, from, to, itemID, speed, duration, fixedDirection, - explodes, hue, renderMode); + state.Send(p); } + p.Release(); + + eable.Free(); + } + + public static void SendPacket(IPoint3D origin, Map map, Packet p) + { + if (map == null) + return; + + IPooledEnumerable eable = map.GetClientsInRange(new Point3D(origin)); + + p.Acquire(); + + foreach (NetState state in eable) + { + state.Mobile.ProcessDelta(); + state.Send(p); + } + + p.Release(); + eable.Free(); } } -} +} \ No newline at end of file diff --git a/Projects/Server/ExpansionInfo.cs b/Projects/Server/ExpansionInfo.cs index 39a17be40..d5770fd26 100644 --- a/Projects/Server/ExpansionInfo.cs +++ b/Projects/Server/ExpansionInfo.cs @@ -72,7 +72,6 @@ namespace Server RoleplayFaces = 0x00002000, TrialAccount = 0x00004000, LiveAccount = 0x00008000, - SA = 0x00010000, HS = 0x00020000, Gothic = 0x00040000, @@ -322,4 +321,4 @@ namespace Server public override string ToString() => Name; } -} +} \ No newline at end of file diff --git a/Projects/Server/Geometry.cs b/Projects/Server/Geometry.cs index fe703e488..a86248fff 100644 --- a/Projects/Server/Geometry.cs +++ b/Projects/Server/Geometry.cs @@ -134,11 +134,13 @@ namespace Server m_Z = z; } - public Point3D(IPoint3D p) : this(p.X, p.Y, p.Z) + public Point3D(IPoint3D p) + : this(p.X, p.Y, p.Z) { } - public Point3D(IPoint2D p, int z) : this(p.X, p.Y, z) + public Point3D(IPoint2D p, int z) + : this(p.X, p.Y, z) { } diff --git a/Projects/Server/Guild.cs b/Projects/Server/Guild.cs index 83d5b5803..76f892474 100644 --- a/Projects/Server/Guild.cs +++ b/Projects/Server/Guild.cs @@ -19,9 +19,8 @@ ***************************************************************************/ using System.Collections.Generic; -using System.Linq; -namespace Server +namespace Server.Guilds { public enum GuildType { @@ -73,9 +72,23 @@ namespace Server return g; } - public static BaseGuild FindByName(string name) => List.Values.FirstOrDefault(g => g.Name == name); + public static BaseGuild FindByName(string name) + { + foreach (BaseGuild g in List.Values) + if (g.Name == name) + return g; - public static BaseGuild FindByAbbrev(string abbr) => List.Values.FirstOrDefault(g => g.Abbreviation == abbr); + return null; + } + + public static BaseGuild FindByAbbrev(string abbr) + { + foreach (BaseGuild g in List.Values) + if (g.Abbreviation == abbr) + return g; + + return null; + } public static List Search(string find) { @@ -83,8 +96,19 @@ namespace Server List results = new List(); foreach (BaseGuild g in List.Values) - if (words.All(t => g.Name.ToLower().IndexOf(t) != -1)) + { + bool match = true; + string name = g.Name.ToLower(); + for (int i = 0; i < words.Length; i++) + if (name.IndexOf(words[i]) == -1) + { + match = false; + break; + } + + if (match) results.Add(g); + } return results; } diff --git a/Projects/Server/Gumps/Gump.cs b/Projects/Server/Gumps/Gump.cs index 8644d9cbd..0d5cc707a 100644 --- a/Projects/Server/Gumps/Gump.cs +++ b/Projects/Server/Gumps/Gump.cs @@ -19,13 +19,8 @@ ***************************************************************************/ using System; -using System.Buffers; using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; using System.Text; -using Server.Buffers; -using Server.Collections; using Server.Network; namespace Server.Gumps @@ -34,45 +29,135 @@ namespace Server.Gumps { private static uint m_NextSerial = 1; + private static byte[] m_BeginLayout = StringToBuffer("{ "); + private static byte[] m_EndLayout = StringToBuffer(" }"); + private static byte[] m_NoMove = StringToBuffer("{ nomove }"); private static byte[] m_NoClose = StringToBuffer("{ noclose }"); private static byte[] m_NoDispose = StringToBuffer("{ nodispose }"); private static byte[] m_NoResize = StringToBuffer("{ noresize }"); + private bool m_Closable = true; + private bool m_Disposable = true; + + private bool m_Draggable = true; + private bool m_Resizable = true; + + private uint m_Serial; + private List m_Strings; internal int m_TextEntries, m_Switches; + private int m_X, m_Y; public Gump(int x, int y) { do { - Serial = m_NextSerial++; - } while (Serial == 0); // standard client apparently doesn't send a gump response packet if serial == 0 + m_Serial = m_NextSerial++; + } while (m_Serial == 0); // standard client apparently doesn't send a gump response packet if serial == 0 - X = x; - Y = y; + m_X = x; + m_Y = y; TypeID = GetTypeID(GetType()); Entries = new List(); + m_Strings = new List(); } public int TypeID{ get; } public List Entries{ get; } - public uint Serial { get; set; } + public uint Serial + { + get => m_Serial; + set + { + if (m_Serial != value) + { + m_Serial = value; + Invalidate(); + } + } + } - public int X { get; set; } + public int X + { + get => m_X; + set + { + if (m_X != value) + { + m_X = value; + Invalidate(); + } + } + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set + { + if (m_Y != value) + { + m_Y = value; + Invalidate(); + } + } + } - public bool Disposable { get; set; } = true; + public bool Disposable + { + get => m_Disposable; + set + { + if (m_Disposable != value) + { + m_Disposable = value; + Invalidate(); + } + } + } - public bool Resizable { get; set; } = true; + public bool Resizable + { + get => m_Resizable; + set + { + if (m_Resizable != value) + { + m_Resizable = value; + Invalidate(); + } + } + } - public bool Draggable { get; set; } = true; + public bool Draggable + { + get => m_Draggable; + set + { + if (m_Draggable != value) + { + m_Draggable = value; + Invalidate(); + } + } + } - public bool Closable { get; set; } = true; + public bool Closable + { + get => m_Closable; + set + { + if (m_Closable != value) + { + m_Closable = value; + Invalidate(); + } + } + } public static int GetTypeID(Type type) => type?.FullName?.GetHashCode() ?? -1; @@ -177,12 +262,7 @@ namespace Server.Gumps Add(new GumpRadio(x, y, inactiveID, activeID, initialState, switchID)); } - public void AddTextEntry( int x, int y, int width, int height, int hue, int entryID, string initialText ) - { - Add( new GumpTextEntry( x, y, width, height, hue, entryID, initialText ) ); - } - - public void AddTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText, int size) + public void AddTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText, int size = 0) { Add(new GumpTextEntryLimited(x, y, width, height, hue, entryID, initialText, size)); } @@ -195,8 +275,14 @@ namespace Server.Gumps public void Add(GumpEntry g) { if (g.Parent != this) + { g.Parent = this; - else if (!Entries.Contains(g)) Entries.Add(g); + } + else if (!Entries.Contains(g)) + { + Invalidate(); + Entries.Add(g); + } } public void Remove(GumpEntry g) @@ -204,120 +290,70 @@ namespace Server.Gumps if (g == null || !Entries.Contains(g)) return; + Invalidate(); Entries.Remove(g); g.Parent = null; } - public static byte[] StringToBuffer(string str) => Encoding.ASCII.GetBytes(str); + public int Intern(string value) + { + int indexOf = m_Strings.IndexOf(value); + + if (indexOf >= 0) return indexOf; + + Invalidate(); + m_Strings.Add(value); + return m_Strings.Count - 1; + } public void SendTo(NetState state) { state.AddGump(this); - ArrayBufferWriter bufferWriter = new ArrayBufferWriter(0x10000); - m_TextEntries = 0; - m_Switches = 0; - if (state.Unpack) - CompilePacked(bufferWriter); - else - CompileFast(bufferWriter); - state.Send(bufferWriter.WrittenSpan); - } - - private void WriteLayout(ArrayBufferWriter layoutBuffer, ArraySet strings) - { - if (!Draggable) - layoutBuffer.Write(m_NoMove); - - if (!Closable) - layoutBuffer.Write(m_NoClose); - - if (!Disposable) - layoutBuffer.Write(m_NoDispose); - - if (!Resizable) - layoutBuffer.Write(m_NoResize); - - for (int i = 0; i < Entries.Count; ++i) - Entries[i].AppendTo(layoutBuffer, strings, ref m_TextEntries, ref m_Switches); - } - - private static void WriteStrings(IBufferWriter stringsBuffer, IList strings) - { - int stringLength = 2 * strings.Count + strings.Sum(t => t.Length * 2); - SpanWriter rawStringsWriter = new SpanWriter(stringsBuffer.GetSpan(stringLength)); - - for (int i = 0; i < strings.Count; ++i) - { - string v = strings[i] ?? ""; - - rawStringsWriter.Write((ushort)v.Length); - rawStringsWriter.WriteBigUni(v); - } - - stringsBuffer.Advance(stringLength); + state.Send(Compile(state)); } public static byte[] StringToBuffer(string str) => Encoding.ASCII.GetBytes(str); - private void CompileFast(IBufferWriter bufferWriter) + private Packet Compile(NetState ns = null) { - SpanWriter writer = new SpanWriter(bufferWriter.GetSpan(21)); - writer.Write((byte)0xB0); // Packed ID - writer.Position += 2; // Dynamic Length + IGumpWriter disp; - writer.Write(Serial); - writer.Write(TypeID); - writer.Write(X); - writer.Write(Y); + if (ns?.Unpack == true) + disp = new DisplayGumpPacked(this); + else + disp = new DisplayGumpFast(this); - ArraySet strings = new ArraySet(); - ArrayBufferWriter layoutBuffer = new ArrayBufferWriter(); - WriteLayout(layoutBuffer, strings); + if (!m_Draggable) + disp.AppendLayout(m_NoMove); - writer.Write((ushort)layoutBuffer.WrittenCount); + if (!m_Closable) + disp.AppendLayout(m_NoClose); - ArrayBufferWriter stringsBuffer = new ArrayBufferWriter(); - Span span = stringsBuffer.GetSpan(2); - span[0] = (byte)(strings.Count >> 8); - span[1] = (byte)strings.Count; - bufferWriter.Advance(2); - WriteStrings(stringsBuffer, strings); + if (!m_Disposable) + disp.AppendLayout(m_NoDispose); - writer.Position = 1; - writer.Write((ushort)(23 + layoutBuffer.WrittenCount + stringsBuffer.WrittenCount)); + if (!m_Resizable) + disp.AppendLayout(m_NoResize); - // Write the header - bufferWriter.Advance(21); + int count = Entries.Count; - // Write the layout - bufferWriter.Write(layoutBuffer.WrittenSpan); - - // Write strings - bufferWriter.Write(stringsBuffer.WrittenSpan); - } - - private static int GetMaxPackedSize(int sourceLength) => 8 + (int)Compression.MaxPackSize((ulong)sourceLength); - - private static int WritePacked(ReadOnlySpan source, Span dest) - { - int length = source.Length; - - if (length == 0) + for (int i = 0; i < count; ++i) { - dest.Clear(); - return 4; + GumpEntry e = Entries[i]; + + disp.AppendLayout(m_BeginLayout); + e.AppendTo(ns, disp); + disp.AppendLayout(m_EndLayout); } - ulong packLength = (ulong)dest.Length - 8; + disp.WriteStrings(m_Strings); - ZLibError ce = Compression.Pack(dest.Slice(8), ref packLength, source, ZLibQuality.Default); - if (ce != ZLibError.Okay) Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce); - SpanWriter writer = new SpanWriter(dest); - int packLengthInt = (int)packLength; - writer.Write(4 + packLengthInt); - writer.Write(length); + disp.Flush(); - return 8 + packLengthInt; + m_TextEntries = disp.TextEntries; + m_Switches = disp.Switches; + + return (Packet)disp; } public virtual void OnResponse(NetState sender, RelayInfo info) diff --git a/Projects/Server/Gumps/GumpAlphaRegion.cs b/Projects/Server/Gumps/GumpAlphaRegion.cs index a26304df0..20cfefe0d 100644 --- a/Projects/Server/Gumps/GumpAlphaRegion.cs +++ b/Projects/Server/Gumps/GumpAlphaRegion.cs @@ -18,46 +18,57 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpAlphaRegion : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("checkertrans"); + private int m_Width, m_Height; + private int m_X, m_Y; + public GumpAlphaRegion(int x, int y, int width, int height) { - X = x; - Y = y; - Width = width; - Height = height; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Width { get; set; } + public int Width + { + get => m_Width; + set => Delta(ref m_Width, value); + } - public int Height { get; set; } + public int Height + { + get => m_Height; + set => Delta(ref m_Height, value); + } public override string Compile(NetState ns) => $"{{ checkertrans {m_X} {m_Y} {m_Width} {m_Height} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(60)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpBackground.cs b/Projects/Server/Gumps/GumpBackground.cs index a6ea217b9..8016cfe1b 100644 --- a/Projects/Server/Gumps/GumpBackground.cs +++ b/Projects/Server/Gumps/GumpBackground.cs @@ -18,53 +18,66 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpBackground : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("resizepic"); private int m_GumpID; + private int m_Width, m_Height; + private int m_X, m_Y; public GumpBackground(int x, int y, int width, int height, int gumpID) { - X = x; - Y = y; - Width = width; - Height = height; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; m_GumpID = gumpID; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Width { get; set; } + public int Width + { + get => m_Width; + set => Delta(ref m_Width, value); + } - public int Height { get; set; } + public int Height + { + get => m_Height; + set => Delta(ref m_Height, value); + } - public override string Compile(ArraySet strings) => $"{{ resizepic {X} {Y} {m_GumpID} {Width} {Height} }}"; + public int GumpID + { + get => m_GumpID; + set => Delta(ref m_GumpID, value); + } public override string Compile(NetState ns) => $"{{ resizepic {m_X} {m_Y} {m_GumpID} {m_Width} {m_Height} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(68)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(m_GumpID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_GumpID); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpButton.cs b/Projects/Server/Gumps/GumpButton.cs index db6ccd84d..9186b8e37 100644 --- a/Projects/Server/Gumps/GumpButton.cs +++ b/Projects/Server/Gumps/GumpButton.cs @@ -18,9 +18,7 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { @@ -32,56 +30,89 @@ namespace Server.Gumps public class GumpButton : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("button"); + private int m_ButtonID; + private int m_ID1, m_ID2; + private int m_Param; + private GumpButtonType m_Type; + private int m_X, m_Y; + public GumpButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type = GumpButtonType.Reply, int param = 0) { - X = x; - Y = y; - NormalID = normalID; - PressedID = pressedID; - ButtonID = buttonID; - Type = type; - Param = param; + m_X = x; + m_Y = y; + m_ID1 = normalID; + m_ID2 = pressedID; + m_ButtonID = buttonID; + m_Type = type; + m_Param = param; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int NormalID { get; set; } + public int NormalID + { + get => m_ID1; + set => Delta(ref m_ID1, value); + } - public int PressedID { get; set; } + public int PressedID + { + get => m_ID2; + set => Delta(ref m_ID2, value); + } - public int ButtonID { get; set; } + public int ButtonID + { + get => m_ButtonID; + set => Delta(ref m_ButtonID, value); + } - public GumpButtonType Type { get; set; } + public GumpButtonType Type + { + get => m_Type; + set + { + if (m_Type != value) + { + m_Type = value; - public int Param { get; set; } + Gump parent = Parent; - public override string Compile(ArraySet strings) => $"{{ button {X} {Y} {NormalID} {PressedID} {(int)Type} {Param} {ButtonID} }}"; + parent?.Invalidate(); + } + } + } + + public int Param + { + get => m_Param; + set => Delta(ref m_Param, value); + } public override string Compile(NetState ns) => $"{{ button {m_X} {m_Y} {m_ID1} {m_ID2} {(int)m_Type} {m_Param} {m_ButtonID} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(68)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(NormalID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(PressedID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(((int)Type).ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Param.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(ButtonID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_ID1); + disp.AppendLayout(m_ID2); + disp.AppendLayout((int)m_Type); + disp.AppendLayout(m_Param); + disp.AppendLayout(m_ButtonID); } } } diff --git a/Projects/Server/Gumps/GumpCheck.cs b/Projects/Server/Gumps/GumpCheck.cs index a765337b7..afc3a54d0 100644 --- a/Projects/Server/Gumps/GumpCheck.cs +++ b/Projects/Server/Gumps/GumpCheck.cs @@ -18,58 +18,77 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpCheck : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("checkbox"); + private int m_ID1, m_ID2; + private bool m_InitialState; + private int m_SwitchID; + private int m_X, m_Y; + public GumpCheck(int x, int y, int inactiveID, int activeID, bool initialState, int switchID) { - X = x; - Y = y; - InactiveID = inactiveID; - ActiveID = activeID; - InitialState = initialState; - SwitchID = switchID; + m_X = x; + m_Y = y; + m_ID1 = inactiveID; + m_ID2 = activeID; + m_InitialState = initialState; + m_SwitchID = switchID; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int InactiveID { get; set; } + public int InactiveID + { + get => m_ID1; + set => Delta(ref m_ID1, value); + } - public int ActiveID { get; set; } + public int ActiveID + { + get => m_ID2; + set => Delta(ref m_ID2, value); + } - public bool InitialState { get; set; } + public bool InitialState + { + get => m_InitialState; + set => Delta(ref m_InitialState, value); + } - public int SwitchID { get; set; } + public int SwitchID + { + get => m_SwitchID; + set => Delta(ref m_SwitchID, value); + } public override string Compile(NetState ns) => $"{{ checkbox {m_X} {m_Y} {m_ID1} {m_ID2} {(m_InitialState ? 1 : 0)} {m_SwitchID} }}"; - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("{ checkbox "); - - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(69)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(InactiveID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(ActiveID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(InitialState ? "1" : "0"); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(SwitchID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_ID1); + disp.AppendLayout(m_ID2); + disp.AppendLayout(m_InitialState); + disp.AppendLayout(m_SwitchID); + + disp.Switches++; } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpEntry.cs b/Projects/Server/Gumps/GumpEntry.cs index e67726f82..732125b15 100644 --- a/Projects/Server/Gumps/GumpEntry.cs +++ b/Projects/Server/Gumps/GumpEntry.cs @@ -18,8 +18,7 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { @@ -43,7 +42,37 @@ namespace Server.Gumps } } - public abstract string Compile(ArraySet strings); - public abstract void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches); + protected void Delta(ref uint var, uint val) + { + if (var != val) + var = val; + } + + protected void Delta(ref int var, int val) + { + if (var != val) + var = val; + } + + protected void Delta(ref bool var, bool val) + { + if (var != val) + var = val; + } + + protected void Delta(ref string var, string val) + { + if (var != val) + var = val; + } + + protected void Delta(ref object[] var, object[] val) + { + if (var != val) + var = val; + } + + public abstract string Compile(NetState ns); + public abstract void AppendTo(NetState ns, IGumpWriter disp); } } diff --git a/Projects/Server/Gumps/GumpGroup.cs b/Projects/Server/Gumps/GumpGroup.cs index 3d32b9da9..93418d837 100644 --- a/Projects/Server/Gumps/GumpGroup.cs +++ b/Projects/Server/Gumps/GumpGroup.cs @@ -18,30 +18,29 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpGroup : GumpEntry { - public GumpGroup(int group) => Group = group; + private static byte[] m_LayoutName = Gump.StringToBuffer("group"); + private int m_Group; public GumpGroup(int group) => m_Group = group; - public override string Compile(ArraySet strings) => $"{{ group {Group} }}"; + public int Group + { + get => m_Group; + set => Delta(ref m_Group, value); + } public override string Compile(NetState ns) => $"{{ group {m_Group} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(20)); - writer.Write(m_LayoutName); - writer.WriteAscii(Group.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_Group); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpHtml.cs b/Projects/Server/Gumps/GumpHtml.cs index a9dde3634..12cd813e4 100644 --- a/Projects/Server/Gumps/GumpHtml.cs +++ b/Projects/Server/Gumps/GumpHtml.cs @@ -18,61 +18,83 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpHtml : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("htmlgump"); + private bool m_Background, m_Scrollbar; + private string m_Text; + private int m_Width, m_Height; + private int m_X, m_Y; + public GumpHtml(int x, int y, int width, int height, string text, bool background, bool scrollbar) { - X = x; - Y = y; - Width = width; - Height = height; - Text = text; - Background = background; - Scrollbar = scrollbar; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Text = text; + m_Background = background; + m_Scrollbar = scrollbar; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Width { get; set; } + public int Width + { + get => m_Width; + set => Delta(ref m_Width, value); + } - public int Height { get; set; } + public int Height + { + get => m_Height; + set => Delta(ref m_Height, value); + } - public string Text { get; set; } + public string Text + { + get => m_Text; + set => Delta(ref m_Text, value); + } - public bool Background { get; set; } + public bool Background + { + get => m_Background; + set => Delta(ref m_Background, value); + } - public bool Scrollbar { get; set; } + public bool Scrollbar + { + get => m_Scrollbar; + set => Delta(ref m_Scrollbar, value); + } public override string Compile(NetState ns) => $"{{ htmlgump {m_X} {m_Y} {m_Width} {m_Height} {Parent.Intern(m_Text)} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(71)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(strings.Add(Text).ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Background ? "1" : "0"); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Scrollbar ? "1" : "0"); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); + disp.AppendLayout(Parent.Intern(m_Text)); + disp.AppendLayout(m_Background); + disp.AppendLayout(m_Scrollbar); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpHtmlLocalized.cs b/Projects/Server/Gumps/GumpHtmlLocalized.cs index e87af43d0..ad8bf533e 100644 --- a/Projects/Server/Gumps/GumpHtmlLocalized.cs +++ b/Projects/Server/Gumps/GumpHtmlLocalized.cs @@ -18,9 +18,7 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { @@ -33,33 +31,45 @@ namespace Server.Gumps public class GumpHtmlLocalized : GumpEntry { + private static byte[] m_LayoutNamePlain = Gump.StringToBuffer("xmfhtmlgump"); + private static byte[] m_LayoutNameColor = Gump.StringToBuffer("xmfhtmlgumpcolor"); + private static byte[] m_LayoutNameArgs = Gump.StringToBuffer("xmfhtmltok"); + private string m_Args; + private bool m_Background, m_Scrollbar; + private int m_Color; + private int m_Number; + + private GumpHtmlLocalizedType m_Type; + private int m_Width, m_Height; + private int m_X, m_Y; + public GumpHtmlLocalized(int x, int y, int width, int height, int number, bool background = false, bool scrollbar = false) { - X = x; - Y = y; - Width = width; - Height = height; - Number = number; - Background = background; - Scrollbar = scrollbar; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Number = number; + m_Background = background; + m_Scrollbar = scrollbar; - Type = GumpHtmlLocalizedType.Plain; + m_Type = GumpHtmlLocalizedType.Plain; } public GumpHtmlLocalized(int x, int y, int width, int height, int number, int color, bool background = false, bool scrollbar = false) { - X = x; - Y = y; - Width = width; - Height = height; - Number = number; - Color = color; - Background = background; - Scrollbar = scrollbar; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Number = number; + m_Color = color; + m_Background = background; + m_Scrollbar = scrollbar; - Type = GumpHtmlLocalizedType.Color; + m_Type = GumpHtmlLocalizedType.Color; } public GumpHtmlLocalized(int x, int y, int width, int height, int number, string args, int color, @@ -67,38 +77,81 @@ namespace Server.Gumps { // Are multiple arguments unsupported? And what about non ASCII arguments? - X = x; - Y = y; - Width = width; - Height = height; - Number = number; - Args = args; - Color = color; - Background = background; - Scrollbar = scrollbar; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Number = number; + m_Args = args; + m_Color = color; + m_Background = background; + m_Scrollbar = scrollbar; - Type = GumpHtmlLocalizedType.Args; + m_Type = GumpHtmlLocalizedType.Args; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Width { get; set; } + public int Width + { + get => m_Width; + set => Delta(ref m_Width, value); + } - public int Height { get; set; } + public int Height + { + get => m_Height; + set => Delta(ref m_Height, value); + } - public int Number { get; set; } + public int Number + { + get => m_Number; + set => Delta(ref m_Number, value); + } - public string Args { get; set; } + public string Args + { + get => m_Args; + set => Delta(ref m_Args, value); + } - public int Color { get; set; } + public int Color + { + get => m_Color; + set => Delta(ref m_Color, value); + } - public bool Background { get; set; } + public bool Background + { + get => m_Background; + set => Delta(ref m_Background, value); + } - public bool Scrollbar { get; set; } + public bool Scrollbar + { + get => m_Scrollbar; + set => Delta(ref m_Scrollbar, value); + } - public GumpHtmlLocalizedType Type { get; set; } + public GumpHtmlLocalizedType Type + { + get => m_Type; + set + { + if (m_Type != value) + { + m_Type = value; Parent?.Invalidate(); } @@ -120,81 +173,56 @@ namespace Server.Gumps public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(90 + Args?.Length ?? 0)); - switch (Type) + switch (m_Type) { case GumpHtmlLocalizedType.Plain: { - writer.Write(m_LayoutNamePlain); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Number.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Background ? "1" : "0"); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Scrollbar ? "1" : "0"); + disp.AppendLayout(m_LayoutNamePlain); + + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); + disp.AppendLayout(m_Number); + disp.AppendLayout(m_Background); + disp.AppendLayout(m_Scrollbar); break; } case GumpHtmlLocalizedType.Color: { - writer.Write(m_LayoutNameColor); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Number.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Background ? "1" : "0"); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Scrollbar ? "1" : "0"); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Color.ToString()); + disp.AppendLayout(m_LayoutNameColor); + + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); + disp.AppendLayout(m_Number); + disp.AppendLayout(m_Background); + disp.AppendLayout(m_Scrollbar); + disp.AppendLayout(m_Color); break; } case GumpHtmlLocalizedType.Args: { - writer.Write(m_LayoutNameArgs); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Background ? "1" : "0"); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Scrollbar ? "1" : "0"); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Color.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Number.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x40); // '@' - writer.WriteAscii(Args ?? ""); - writer.Write((byte)0x40); // '@' + disp.AppendLayout(m_LayoutNameArgs); + + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); + disp.AppendLayout(m_Background); + disp.AppendLayout(m_Scrollbar); + disp.AppendLayout(m_Color); + disp.AppendLayout(m_Number); + disp.AppendLayout(m_Args); break; } } - - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); } } } diff --git a/Projects/Server/Gumps/GumpImage.cs b/Projects/Server/Gumps/GumpImage.cs index 401b90b35..26d013222 100644 --- a/Projects/Server/Gumps/GumpImage.cs +++ b/Projects/Server/Gumps/GumpImage.cs @@ -18,68 +18,66 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpImage : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("gumppic"); + private static byte[] m_HueEquals = Gump.StringToBuffer(" hue="); + private int m_GumpID; + private int m_Hue; + private int m_X, m_Y; + public GumpImage(int x, int y, int gumpID, int hue = 0) { - X = x; - Y = y; - GumpID = gumpID; - Hue = hue; + m_X = x; + m_Y = y; + m_GumpID = gumpID; + m_Hue = hue; } - public GumpImage(int x, int y, int gumpID, int hue = 0, string cls = null) + public int X { - X = x; - Y = y; - GumpID = gumpID; - Hue = hue; - Class = cls; + get => m_X; + set => Delta(ref m_X, value); } - public int X { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Y { get; set; } + public int GumpID + { + get => m_GumpID; + set => Delta(ref m_GumpID, value); + } - public int GumpID { get; set; } + public int Hue + { + get => m_Hue; + set => Delta(ref m_Hue, value); + } public override string Compile(NetState ns) => m_Hue == 0 ? $"{{ gumppic {m_X} {m_Y} {m_GumpID} }}" : $"{{ gumppic {m_X} {m_Y} {m_GumpID} hue={m_Hue} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(66 + Class?.Length ?? 0)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(GumpID.ToString()); - writer.Write((byte)0x20); // ' ' + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_GumpID); - if (Hue != 0) + if (m_Hue != 0) { - writer.Write(m_HueEquals); - writer.WriteAscii(Hue.ToString()); - writer.Write((byte)0x20); // ' ' + disp.AppendLayout(m_HueEquals); + disp.AppendLayoutNS(m_Hue); } - - if (!string.IsNullOrWhiteSpace(Class)) - { - writer.Write(m_ClassEquals); - writer.WriteAscii(Class); - writer.Write((byte)0x20); // ' ' - } - - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); } } } diff --git a/Projects/Server/Gumps/GumpImageTileButton.cs b/Projects/Server/Gumps/GumpImageTileButton.cs index 58417cc3b..a7fcfc4c0 100644 --- a/Projects/Server/Gumps/GumpImageTileButton.cs +++ b/Projects/Server/Gumps/GumpImageTileButton.cs @@ -18,101 +18,155 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpImageTileButton : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("buttontileart"); + private static byte[] m_LayoutTooltip = Gump.StringToBuffer(" }{ tooltip"); + private int m_ButtonID; + private int m_Height; + private int m_Hue; + private int m_ID1, m_ID2; + + private int m_ItemID; + private int m_Param; + private GumpButtonType m_Type; + + private int m_Width; + //Note, on OSI, The tooltip supports ONLY clilocs as far as I can figure out, and the tooltip ONLY works after the buttonTileArt (as far as I can tell from testing) + private int m_X, m_Y; public GumpImageTileButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param, int itemID, int hue, int width, int height, int localizedTooltip = -1) { - X = x; - Y = y; - NormalID = normalID; - PressedID = pressedID; - ButtonID = buttonID; - Type = type; - Param = param; + m_X = x; + m_Y = y; + m_ID1 = normalID; + m_ID2 = pressedID; + m_ButtonID = buttonID; + m_Type = type; + m_Param = param; - ItemID = itemID; - Hue = hue; - Width = width; - Height = height; + m_ItemID = itemID; + m_Hue = hue; + m_Width = width; + m_Height = height; LocalizedTooltip = localizedTooltip; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int NormalID { get; set; } + public int NormalID + { + get => m_ID1; + set => Delta(ref m_ID1, value); + } - public int PressedID { get; set; } + public int PressedID + { + get => m_ID2; + set => Delta(ref m_ID2, value); + } - public int ButtonID { get; set; } + public int ButtonID + { + get => m_ButtonID; + set => Delta(ref m_ButtonID, value); + } - public GumpButtonType Type { get; set; } + public GumpButtonType Type + { + get => m_Type; + set + { + if (m_Type != value) + { + m_Type = value; - public int Param { get; set; } + Gump parent = Parent; - public int ItemID { get; set; } + parent?.Invalidate(); + } + } + } - public int Hue { get; set; } + public int Param + { + get => m_Param; + set => Delta(ref m_Param, value); + } - public int Width { get; set; } + public int ItemID + { + get => m_ItemID; + set => Delta(ref m_ItemID, value); + } - public int Height { get; set; } + public int Hue + { + get => m_Hue; + set => Delta(ref m_Hue, value); + } + + public int Width + { + get => m_Width; + set => Delta(ref m_Width, value); + } + + public int Height + { + get => m_Height; + set => Delta(ref m_Height, value); + } public int LocalizedTooltip{ get; set; } - public override string Compile(ArraySet strings) => - $"{{ buttontileart {X} {Y} {NormalID} {PressedID} {(int)Type} {Param} {ButtonID} {ItemID} {Hue} {Width} {Height} }}{(LocalizedTooltip > 0 ? $"{{ tooltip {LocalizedTooltip} }}" : "")}"; - - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("{ buttontileart "); - private static readonly byte[] m_LayoutTooltip = Gump.StringToBuffer(" }{ tooltip "); - - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override string Compile(NetState ns) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(160)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(NormalID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(PressedID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(((int)Type).ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Param.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(ButtonID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(ItemID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Hue.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' + if (LocalizedTooltip > 0) + return + $"{{ buttontileart {m_X} {m_Y} {m_ID1} {m_ID2} {(int)m_Type} {m_Param} {m_ButtonID} {m_ItemID} {m_Hue} {m_Width} {m_Height} }}{{ tooltip {LocalizedTooltip} }}"; + return + $"{{ buttontileart {m_X} {m_Y} {m_ID1} {m_ID2} {(int)m_Type} {m_Param} {m_ButtonID} {m_ItemID} {m_Hue} {m_Width} {m_Height} }}"; + } + + public override void AppendTo(NetState ns, IGumpWriter disp) + { + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_ID1); + disp.AppendLayout(m_ID2); + disp.AppendLayout((int)m_Type); + disp.AppendLayout(m_Param); + disp.AppendLayout(m_ButtonID); + + disp.AppendLayout(m_ItemID); + disp.AppendLayout(m_Hue); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); if (LocalizedTooltip > 0) { - writer.Write(m_LayoutTooltip); - writer.WriteAscii(LocalizedTooltip.ToString()); - writer.Write((byte)0x20); // ' ' + disp.AppendLayout(m_LayoutTooltip); + disp.AppendLayout(LocalizedTooltip); } - - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); } } } diff --git a/Projects/Server/Gumps/GumpImageTiled.cs b/Projects/Server/Gumps/GumpImageTiled.cs index af8854d44..e090bdf3a 100644 --- a/Projects/Server/Gumps/GumpImageTiled.cs +++ b/Projects/Server/Gumps/GumpImageTiled.cs @@ -18,51 +18,66 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpImageTiled : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("gumppictiled"); + private int m_GumpID; + private int m_Width, m_Height; + private int m_X, m_Y; + public GumpImageTiled(int x, int y, int width, int height, int gumpID) { - X = x; - Y = y; - Width = width; - Height = height; - GumpID = gumpID; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_GumpID = gumpID; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Width { get; set; } + public int Width + { + get => m_Width; + set => Delta(ref m_Width, value); + } - public int Height { get; set; } + public int Height + { + get => m_Height; + set => Delta(ref m_Height, value); + } - public int GumpID { get; set; } + public int GumpID + { + get => m_GumpID; + set => Delta(ref m_GumpID, value); + } public override string Compile(NetState ns) => $"{{ gumppictiled {m_X} {m_Y} {m_Width} {m_Height} {m_GumpID} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(71)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(GumpID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); + disp.AppendLayout(m_GumpID); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpItem.cs b/Projects/Server/Gumps/GumpItem.cs index f2e08327f..8420886ea 100644 --- a/Projects/Server/Gumps/GumpItem.cs +++ b/Projects/Server/Gumps/GumpItem.cs @@ -18,58 +18,63 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpItem : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("tilepic"); + private static byte[] m_LayoutNameHue = Gump.StringToBuffer("tilepichue"); + private int m_Hue; + private int m_ItemID; + private int m_X, m_Y; + public GumpItem(int x, int y, int itemID, int hue = 0) { - X = x; - Y = y; - ItemID = itemID; - Hue = hue; + m_X = x; + m_Y = y; + m_ItemID = itemID; + m_Hue = hue; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int ItemID { get; set; } + public int ItemID + { + get => m_ItemID; + set => Delta(ref m_ItemID, value); + } - public int Hue { get; set; } + public int Hue + { + get => m_Hue; + set => Delta(ref m_Hue, value); + } public override string Compile(NetState ns) => m_Hue == 0 ? $"{{ tilepic {m_X} {m_Y} {m_ItemID} }}" : $"{{ tilepichue {m_X} {m_Y} {m_ItemID} {m_Hue} }}"; - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("{ tilepic "); - private static readonly byte[] m_LayoutNameHue = Gump.StringToBuffer("{ tilepichue "); - - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(57)); - writer.Write(Hue == 0 ? m_LayoutName : m_LayoutNameHue); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(ItemID.ToString()); - writer.Write((byte)0x20); // ' ' + disp.AppendLayout(m_Hue == 0 ? m_LayoutName : m_LayoutNameHue); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_ItemID); - if (Hue != 0) - { - writer.WriteAscii(Hue.ToString()); - writer.Write((byte)0x20); // ' ' - } - - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - - buffer.Advance(writer.WrittenCount); + if (m_Hue != 0) + disp.AppendLayout(m_Hue); } } } diff --git a/Projects/Server/Gumps/GumpItemProperty.cs b/Projects/Server/Gumps/GumpItemProperty.cs index b791cde3f..5ce65e19e 100644 --- a/Projects/Server/Gumps/GumpItemProperty.cs +++ b/Projects/Server/Gumps/GumpItemProperty.cs @@ -18,31 +18,29 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpItemProperty : GumpEntry { - public GumpItemProperty(uint serial) => Serial = serial; + private static byte[] m_LayoutName = Gump.StringToBuffer("itemproperty"); + private uint m_Serial; public GumpItemProperty(uint serial) => m_Serial = serial; - public override string Compile(ArraySet strings) => $"{{ itemproperty {Serial} }}"; + public uint Serial + { + get => m_Serial; + set => Delta(ref m_Serial, value); + } public override string Compile(NetState ns) => $"{{ itemproperty {m_Serial} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(27)); - writer.Write(m_LayoutName); - writer.WriteAscii(Serial.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_Serial); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpLabel.cs b/Projects/Server/Gumps/GumpLabel.cs index 52028d4e7..d8a0c3389 100644 --- a/Projects/Server/Gumps/GumpLabel.cs +++ b/Projects/Server/Gumps/GumpLabel.cs @@ -18,47 +18,58 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpLabel : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("text"); + private int m_Hue; + private string m_Text; + private int m_X, m_Y; + public GumpLabel(int x, int y, int hue, string text) { - X = x; - Y = y; - Hue = hue; - Text = text; + m_X = x; + m_Y = y; + m_Hue = hue; + m_Text = text; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Hue { get; set; } + public int Hue + { + get => m_Hue; + set => Delta(ref m_Hue, value); + } - public string Text { get; set; } + public string Text + { + get => m_Text; + set => Delta(ref m_Text, value); + } public override string Compile(NetState ns) => $"{{ text {m_X} {m_Y} {m_Hue} {Parent.Intern(m_Text)} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(52)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Hue.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(strings.Add(Text).ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Hue); + disp.AppendLayout(Parent.Intern(m_Text)); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpLabelCropped.cs b/Projects/Server/Gumps/GumpLabelCropped.cs index 62243a73d..462968311 100644 --- a/Projects/Server/Gumps/GumpLabelCropped.cs +++ b/Projects/Server/Gumps/GumpLabelCropped.cs @@ -18,59 +18,75 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpLabelCropped : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("croppedtext"); + private int m_Hue; + private string m_Text; + private int m_Width, m_Height; + private int m_X, m_Y; + public GumpLabelCropped(int x, int y, int width, int height, int hue, string text) { - X = x; - Y = y; - Width = width; - Height = height; - Hue = hue; - Text = text; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Hue = hue; + m_Text = text; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Width { get; set; } + public int Width + { + get => m_Width; + set => Delta(ref m_Width, value); + } - public int Height { get; set; } + public int Height + { + get => m_Height; + set => Delta(ref m_Height, value); + } - public int Hue { get; set; } + public int Hue + { + get => m_Hue; + set => Delta(ref m_Hue, value); + } - public string Text { get; set; } + public string Text + { + get => m_Text; + set => Delta(ref m_Text, value); + } public override string Compile(NetState ns) => $"{{ croppedtext {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {Parent.Intern(m_Text)} }}"; - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("{ croppedtext "); - - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(81)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Hue.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(strings.Add(Text).ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); + disp.AppendLayout(m_Hue); + disp.AppendLayout(Parent.Intern(m_Text)); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpPage.cs b/Projects/Server/Gumps/GumpPage.cs index 38b99e88d..8b5479512 100644 --- a/Projects/Server/Gumps/GumpPage.cs +++ b/Projects/Server/Gumps/GumpPage.cs @@ -18,31 +18,29 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpPage : GumpEntry { - public GumpPage(int page) => Page = page; + private static byte[] m_LayoutName = Gump.StringToBuffer("page"); + private int m_Page; public GumpPage(int page) => m_Page = page; - public override string Compile(ArraySet strings) => $"{{ page {Page} }}"; + public int Page + { + get => m_Page; + set => Delta(ref m_Page, value); + } public override string Compile(NetState ns) => $"{{ page {m_Page} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(19)); - writer.Write(m_LayoutName); - writer.WriteAscii(Page.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_Page); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpRadio.cs b/Projects/Server/Gumps/GumpRadio.cs index 011693c3a..740c3d9b1 100644 --- a/Projects/Server/Gumps/GumpRadio.cs +++ b/Projects/Server/Gumps/GumpRadio.cs @@ -18,61 +18,77 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpRadio : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("radio"); + private int m_ID1, m_ID2; + private bool m_InitialState; + private int m_SwitchID; + private int m_X, m_Y; + public GumpRadio(int x, int y, int inactiveID, int activeID, bool initialState, int switchID) { - X = x; - Y = y; - InactiveID = inactiveID; - ActiveID = activeID; - InitialState = initialState; - SwitchID = switchID; + m_X = x; + m_Y = y; + m_ID1 = inactiveID; + m_ID2 = activeID; + m_InitialState = initialState; + m_SwitchID = switchID; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int InactiveID { get; set; } + public int InactiveID + { + get => m_ID1; + set => Delta(ref m_ID1, value); + } - public int ActiveID { get; set; } + public int ActiveID + { + get => m_ID2; + set => Delta(ref m_ID2, value); + } - public bool InitialState { get; set; } + public bool InitialState + { + get => m_InitialState; + set => Delta(ref m_InitialState, value); + } - public int SwitchID { get; set; } + public int SwitchID + { + get => m_SwitchID; + set => Delta(ref m_SwitchID, value); + } public override string Compile(NetState ns) => $"{{ radio {m_X} {m_Y} {m_ID1} {m_ID2} {(m_InitialState ? 1 : 0)} {m_SwitchID} }}"; - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("{ radio "); - - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(66)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(InactiveID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(ActiveID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(InitialState ? "1" : "0"); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(SwitchID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_ID1); + disp.AppendLayout(m_ID2); + disp.AppendLayout(m_InitialState); + disp.AppendLayout(m_SwitchID); - buffer.Advance(writer.WrittenCount); - - switches++; + disp.Switches++; } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpTextEntry.cs b/Projects/Server/Gumps/GumpTextEntry.cs index 8f1702b8f..8ebd49f83 100644 --- a/Projects/Server/Gumps/GumpTextEntry.cs +++ b/Projects/Server/Gumps/GumpTextEntry.cs @@ -18,66 +18,86 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpTextEntry : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("textentry"); + private int m_EntryID; + private int m_Hue; + private string m_InitialText; + private int m_Width, m_Height; + private int m_X, m_Y; + public GumpTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText) { - X = x; - Y = y; - Width = width; - Height = height; - Hue = hue; - EntryID = entryID; - InitialText = initialText; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Hue = hue; + m_EntryID = entryID; + m_InitialText = initialText; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Width { get; set; } + public int Width + { + get => m_Width; + set => Delta(ref m_Width, value); + } - public int Height { get; set; } + public int Height + { + get => m_Height; + set => Delta(ref m_Height, value); + } - public int Hue { get; set; } + public int Hue + { + get => m_Hue; + set => Delta(ref m_Hue, value); + } - public int EntryID { get; set; } + public int EntryID + { + get => m_EntryID; + set => Delta(ref m_EntryID, value); + } - public string InitialText { get; set; } + public string InitialText + { + get => m_InitialText; + set => Delta(ref m_InitialText, value); + } public override string Compile(NetState ns) => $"{{ textentry {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {m_EntryID} {Parent.Intern(m_InitialText)} }}"; - private static readonly byte[] m_LayoutName = Gump.StringToBuffer(" { textentry "); - - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(90)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Hue.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(EntryID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(strings.Add(InitialText).ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); + disp.AppendLayout(m_Hue); + disp.AppendLayout(m_EntryID); + disp.AppendLayout(Parent.Intern(m_InitialText)); - buffer.Advance(writer.WrittenCount); - - entries++; + disp.TextEntries++; } } -} +} \ No newline at end of file diff --git a/Projects/Server/Gumps/GumpTextEntryLimited.cs b/Projects/Server/Gumps/GumpTextEntryLimited.cs index d9258f39f..2b4d983aa 100644 --- a/Projects/Server/Gumps/GumpTextEntryLimited.cs +++ b/Projects/Server/Gumps/GumpTextEntryLimited.cs @@ -18,69 +18,95 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpTextEntryLimited : GumpEntry { + private static byte[] m_LayoutName = Gump.StringToBuffer("textentrylimited"); + private int m_EntryID; + private int m_Hue; + private string m_InitialText; + private int m_Size; + private int m_Width, m_Height; + private int m_X, m_Y; + public GumpTextEntryLimited(int x, int y, int width, int height, int hue, int entryID, string initialText, int size = 0) { - X = x; - Y = y; - Width = width; - Height = height; - Hue = hue; - EntryID = entryID; - InitialText = initialText; - Size = size; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Hue = hue; + m_EntryID = entryID; + m_InitialText = initialText; + m_Size = size; } - public int X { get; set; } + public int X + { + get => m_X; + set => Delta(ref m_X, value); + } - public int Y { get; set; } + public int Y + { + get => m_Y; + set => Delta(ref m_Y, value); + } - public int Width { get; set; } + public int Width + { + get => m_Width; + set => Delta(ref m_Width, value); + } - public int Height { get; set; } + public int Height + { + get => m_Height; + set => Delta(ref m_Height, value); + } - public int Hue { get; set; } + public int Hue + { + get => m_Hue; + set => Delta(ref m_Hue, value); + } - public int EntryID { get; set; } + public int EntryID + { + get => m_EntryID; + set => Delta(ref m_EntryID, value); + } - public string InitialText { get; set; } + public string InitialText + { + get => m_InitialText; + set => Delta(ref m_InitialText, value); + } - public int Size { get; set; } + public int Size + { + get => m_Size; + set => Delta(ref m_Size, value); + } public override string Compile(NetState ns) => $"{{ textentrylimited {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {m_EntryID} {Parent.Intern(m_InitialText)} {m_Size} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(107)); - writer.Write(m_LayoutName); - writer.WriteAscii(X.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Y.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Width.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Hue.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(EntryID.ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(strings.Add(InitialText).ToString()); - writer.Write((byte)0x20); // ' ' - writer.WriteAscii(Size.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_X); + disp.AppendLayout(m_Y); + disp.AppendLayout(m_Width); + disp.AppendLayout(m_Height); + disp.AppendLayout(m_Hue); + disp.AppendLayout(m_EntryID); + disp.AppendLayout(Parent.Intern(m_InitialText)); + disp.AppendLayout(m_Size); - buffer.Advance(writer.WrittenCount); - - entries++; + disp.TextEntries++; } } } diff --git a/Projects/Server/Gumps/GumpTooltip.cs b/Projects/Server/Gumps/GumpTooltip.cs index 063d0f879..2982ebecc 100644 --- a/Projects/Server/Gumps/GumpTooltip.cs +++ b/Projects/Server/Gumps/GumpTooltip.cs @@ -18,31 +18,29 @@ * ***************************************************************************/ -using System.Buffers; -using Server.Buffers; -using Server.Collections; +using Server.Network; namespace Server.Gumps { public class GumpTooltip : GumpEntry { - public GumpTooltip(int number) => Number = number; + private static byte[] m_LayoutName = Gump.StringToBuffer("tooltip"); + private int m_Number; public GumpTooltip(int number) => m_Number = number; - public override string Compile(ArraySet strings) => $"{{ tooltip {Number} }}"; + public int Number + { + get => m_Number; + set => Delta(ref m_Number, value); + } public override string Compile(NetState ns) => $"{{ tooltip {m_Number} }}"; - public override void AppendTo(ArrayBufferWriter buffer, ArraySet strings, ref int entries, ref int switches) + public override void AppendTo(NetState ns, IGumpWriter disp) { - SpanWriter writer = new SpanWriter(buffer.GetSpan(22)); - writer.Write(m_LayoutName); - writer.WriteAscii(Number.ToString()); - writer.Write((byte)0x20); // ' ' - writer.Write((byte)0x7D); // '}' - - buffer.Advance(writer.WrittenCount); + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_Number); } } -} +} \ No newline at end of file diff --git a/Projects/Server/HuePicker.cs b/Projects/Server/HuePicker.cs index e30f84df4..a020fb6ff 100644 --- a/Projects/Server/HuePicker.cs +++ b/Projects/Server/HuePicker.cs @@ -20,11 +20,11 @@ using Server.Network; -namespace Server +namespace Server.HuePickers { public class HuePicker { - private static Serial m_NextSerial = 1; + private static int m_NextSerial = 1; public HuePicker(int itemID) { @@ -36,7 +36,7 @@ namespace Server ItemID = itemID; } - public Serial Serial{ get; } + public int Serial{ get; } public int ItemID{ get; } @@ -46,8 +46,8 @@ namespace Server public void SendTo(NetState state) { - Packets.SendDisplayHuePicker(state, Serial, ItemID); + state.Send(new DisplayHuePicker(this)); state.AddHuePicker(this); } } -} +} \ No newline at end of file diff --git a/Projects/Server/IAccount.cs b/Projects/Server/IAccount.cs index 3cdd8c90a..cbe1cc46d 100644 --- a/Projects/Server/IAccount.cs +++ b/Projects/Server/IAccount.cs @@ -20,7 +20,7 @@ using System; -namespace Server +namespace Server.Accounting { public static class AccountGold { diff --git a/Projects/Server/Insensitive.cs b/Projects/Server/Insensitive.cs index 6146e48d7..8156b85a1 100644 --- a/Projects/Server/Insensitive.cs +++ b/Projects/Server/Insensitive.cs @@ -29,14 +29,16 @@ namespace Server public static int Compare(string a, string b) => Comparer.Compare(a, b); - public static bool Equals(string a, string b) => a == null && b == null - || a != null && b != null && a.Length == b.Length && Comparer.Compare(a, b) == 0; + public static bool Equals(string a, string b) => + a == null && b == null || a != null && b != null && a.Length == b.Length && Comparer.Compare(a, b) == 0; - public static bool StartsWith(string a, string b) => a != null && b != null && a.Length >= b.Length && Comparer.Compare(a.Substring(0, b.Length), b) == 0; + public static bool StartsWith(string a, string b) => + a != null && b != null && a.Length >= b.Length && Comparer.Compare(a.Substring(0, b.Length), b) == 0; - public static bool EndsWith(string a, string b) => a != null && b != null && a.Length >= b.Length && Comparer.Compare(a.Substring(a.Length - b.Length), b) == 0; - - public static bool Contains(string a, string b) => a != null && b != null && a.Length >= b.Length && a.IndexOf(b, StringComparison.OrdinalIgnoreCase) >= 0; + public static bool EndsWith(string a, string b) => + a != null && b != null && a.Length >= b.Length && Comparer.Compare(a.Substring(a.Length - b.Length), b) == 0; + public static bool Contains(string a, string b) => + a != null && b != null && a.Length >= b.Length && a.IndexOf(b, StringComparison.OrdinalIgnoreCase) >= 0; } } diff --git a/Projects/Server/Interfaces.cs b/Projects/Server/Interfaces.cs index d3d556014..0294efa88 100644 --- a/Projects/Server/Interfaces.cs +++ b/Projects/Server/Interfaces.cs @@ -21,7 +21,7 @@ using System; using System.Collections.Generic; -namespace Server +namespace Server.Mobiles { public interface IMount { @@ -33,7 +33,10 @@ namespace Server { IMount Mount{ get; } } +} +namespace Server +{ public interface IVendor { DateTime LastRestock{ get; set; } @@ -108,4 +111,4 @@ namespace Server void OnBeforeSpawn(Point3D location, Map map); void OnAfterSpawn(); } -} \ No newline at end of file +} diff --git a/Projects/Server/Item.cs b/Projects/Server/Item.cs index e6655cded..66a4e9257 100644 --- a/Projects/Server/Item.cs +++ b/Projects/Server/Item.cs @@ -14,7 +14,7 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version.1 + * (at your option) any later version. * ***************************************************************************/ @@ -199,7 +199,7 @@ namespace Server Spawner = 0x100 } - public class Item : IHued, IComparable, ISerializable, ISpawnable, ITile + public class Item : IHued, IComparable, ISerializable, ISpawnable, IPropertyListObject { public const int QuestItemHue = 0x4EA; // Hmmmm... "for EA"? public static readonly List EmptyItems = new List(); @@ -340,22 +340,20 @@ namespace Server set => SetFlag(ImplFlag.Stackable, value); } - private ObjectPropertyList m_PropertyList; + public Packet RemovePacket => StaticPacketHandlers.GetRemoveEntityPacket(this); + public OPLInfo OPLPacket => StaticPacketHandlers.GetOPLInfoPacket(this); + public ObjectPropertyList PropertyList => StaticPacketHandlers.GetOPLPacket(this); - public ObjectPropertyList PropertyList - { - get - { - if (m_PropertyList == null) - { - m_PropertyList = new ObjectPropertyList(this); - GetProperties(m_PropertyList); - AppendChildProperties(m_PropertyList); - } - - return m_PropertyList; - } - } + // World packets need to be invalidated when any of the following changes: + // - ItemID + // - Amount + // - Location + // - Hue + // - Packet Flags + // - Direction + public Packet WorldPacket => StaticPacketHandlers.GetWorldItemPacket(this); + public Packet WorldPacketSA => StaticPacketHandlers.GetWorldItemSAPacket(this); + public Packet WorldPacketHS => StaticPacketHandlers.GetWorldItemHSPacket(this); [CommandProperty(AccessLevel.GameMaster)] public bool Visible @@ -366,6 +364,7 @@ namespace Server if (GetFlag(ImplFlag.Visible) != value) { SetFlag(ImplFlag.Visible, value); + ReleaseWorldPackets(); if (m_Map != null) { @@ -378,7 +377,7 @@ namespace Server Mobile m = state.Mobile; if (!m.CanSee(this) && m.InRange(worldLoc, GetUpdateRange(m))) - Packets.SendRemoveEntity(state, Serial); + state.Send(RemovePacket); } eable.Free(); @@ -398,6 +397,7 @@ namespace Server if (GetFlag(ImplFlag.Movable) != value) { SetFlag(ImplFlag.Movable, value); + ReleaseWorldPackets(); Delta(ItemDelta.Update); } } @@ -433,7 +433,16 @@ namespace Server public virtual bool IsVirtualItem => false; - public virtual int LabelNumber => m_ItemID < 0x4000 ? 1020000 + m_ItemID : 1078872 + m_ItemID; + public virtual int LabelNumber + { + get + { + if (m_ItemID < 0x4000) + return 1020000 + m_ItemID; + + return 1078872 + m_ItemID; + } + } [CommandProperty(AccessLevel.GameMaster)] public int TotalGold => GetTotal(TotalType.Gold); @@ -504,6 +513,8 @@ namespace Server if (m_Hue != value) { m_Hue = value; + ReleaseWorldPackets(); + Delta(ItemDelta.Update); } } @@ -565,6 +576,7 @@ namespace Server int oldPileWeight = PileWeight; m_ItemID = value; + ReleaseWorldPackets(); int newPileWeight = PileWeight; @@ -630,6 +642,8 @@ namespace Server if ((LightType)m_Direction != value) { m_Direction = (Direction)value; + ReleaseWorldPackets(); + Delta(ItemDelta.Update); } } @@ -644,6 +658,8 @@ namespace Server if (m_Direction != value) { m_Direction = value; + ReleaseWorldPackets(); + Delta(ItemDelta.Update); } } @@ -662,6 +678,7 @@ namespace Server int oldPileWeight = PileWeight; m_Amount = value; + ReleaseWorldPackets(); int newPileWeight = PileWeight; @@ -689,8 +706,6 @@ namespace Server public ItemData ItemData => TileData.ItemTable[m_ItemID & TileData.MaxItemValue]; - int ITile.ID => ItemData.Value; - public virtual bool CanTarget => true; public virtual bool DisplayLootType => true; @@ -706,6 +721,8 @@ namespace Server InvalidateProperties(); + ReleaseWorldPackets(); + Delta(ItemDelta.Update); } } @@ -781,7 +798,7 @@ namespace Server Mobile m = state.Mobile; if (m.InRange(oldLocation, GetUpdateRange(m))) - Packets.SendRemoveEntity(state, Serial); + state.Send(RemovePacket); } eable.Free(); @@ -791,6 +808,8 @@ namespace Server m_Location = location; OnLocationChange(oldRealLocation); + ReleaseWorldPackets(); + List items = LookupItems(); if (items != null) @@ -834,8 +853,7 @@ namespace Server { Mobile m = state.Mobile; - if (!m.InRange(location, GetUpdateRange(m))) - Packets.SendRemoveEntity(state, Serial); + if (!m.InRange(location, GetUpdateRange(m))) state.Send(RemovePacket); } eable.Free(); @@ -846,6 +864,8 @@ namespace Server m_Location = location; OnLocationChange(oldRealLocation); + ReleaseWorldPackets(); + eable = m_Map.GetClientsInRange(m_Location, GetMaxUpdateRange()); foreach (NetState state in eable) @@ -935,13 +955,17 @@ namespace Server { NetState ns = rootParent.NetState; - if (ns != null && rootParent.CanSee(this) && rootParent.InRange(worldLoc, GetUpdateRange(rootParent))) - { - Packets.SendContainerContentUpdate(ns, this); + if (ns != null) + if (rootParent.CanSee(this) && rootParent.InRange(worldLoc, GetUpdateRange(rootParent))) + { + if (ns.ContainerGridLines) + ns.Send(new ContainerContentUpdate6017(this)); + else + ns.Send(new ContainerContentUpdate(this)); - if (ObjectPropertyList.Enabled) - PropertyList.Send(ns); - } + if (ObjectPropertyList.Enabled) + ns.Send(OPLPacket); + } } SecureTrade st = GetSecureTradeCont()?.Trade; @@ -962,16 +986,19 @@ namespace Server if (ns != null && tradeRecip.CanSee(this) && tradeRecip.InRange(worldLoc, GetUpdateRange(tradeRecip))) { - Packets.SendContainerContentUpdate(ns, this); + if (ns.ContainerGridLines) + ns.Send(new ContainerContentUpdate6017(this)); + else + ns.Send(new ContainerContentUpdate(this)); if (ObjectPropertyList.Enabled) - PropertyList.Send(ns); + ns.Send(OPLPacket); } } List openers = contParent.Openers; - if (openers?.Count > 0) + if (openers != null) lock (openers) { for (int i = 0; i < openers.Count; ++i) @@ -981,7 +1008,9 @@ namespace Server int range = GetUpdateRange(mob); if (mob.Map != map || !mob.InRange(worldLoc, range)) + { openers.RemoveAt(i--); + } else { if (mob == rootParent || mob == tradeRecip) @@ -991,10 +1020,13 @@ namespace Server if (ns != null && mob.CanSee(this)) { - Packets.SendContainerContentUpdate(ns, this); + if (ns.ContainerGridLines) + ns.Send(new ContainerContentUpdate6017(this)); + else + ns.Send(new ContainerContentUpdate(this)); if (ObjectPropertyList.Enabled) - PropertyList.Send(ns); + ns.Send(OPLPacket); } } } @@ -1006,6 +1038,8 @@ namespace Server return; } + Packet p = null; + IPooledEnumerable eable = map.GetClientsInRange(worldLoc, GetMaxUpdateRange()); foreach (NetState state in eable) @@ -1020,26 +1054,39 @@ namespace Server SendInfoTo(state, ObjectPropertyList.Enabled); else { - if (m_Parent is Item) - Packets.SendContainerContentUpdate(state, this); + if (p != null) + state.Send(p); + else if (m_Parent is Item) + { + if (state.ContainerGridLines) + state.Send(new ContainerContentUpdate6017(this)); + else + state.Send(new ContainerContentUpdate(this)); + } else if (m_Parent is Mobile) - Packets.SendEquipUpdate(state, this); + { + p = new EquipUpdate(this); + p.Acquire(); + + state.Send(p); + } if (ObjectPropertyList.Enabled) - PropertyList.Send(state); + state.Send(OPLPacket); } } else if ((flags & ItemDelta.EquipOnly) != 0 && m_Parent is Mobile) { - Packets.SendEquipUpdate(state, this); + state.Send(p ?? (p = Packet.Acquire(new EquipUpdate(this)))); if (ObjectPropertyList.Enabled) - PropertyList.Send(state); + state.Send(OPLPacket); } else if (ObjectPropertyList.Enabled && (flags & ItemDelta.Properties) != 0) - PropertyList.Send(state); + state.Send(OPLPacket); } } + Packet.Release(p); eable.Free(); } @@ -1079,7 +1126,7 @@ namespace Server OnAfterDelete(); - ClearProperties(); + FreeCache(); } [CommandProperty(AccessLevel.Counselor)] @@ -1190,7 +1237,17 @@ namespace Server long ticks = LastMoved.Ticks; long now = DateTime.UtcNow.Ticks; - TimeSpan d = new TimeSpan(ticks - now); + TimeSpan d; + + try + { + d = new TimeSpan(ticks - now); + } + catch + { + if (ticks < now) d = TimeSpan.MaxValue; + else d = TimeSpan.MaxValue; + } double minutes = -d.TotalMinutes; @@ -1249,7 +1306,13 @@ namespace Server if (GetSaveFlag(flags, SaveFlag.Name)) writer.Write(info.m_Name); - if (GetSaveFlag(flags, SaveFlag.Parent)) writer.Write(m_Parent?.Deleted == false ? m_Parent.Serial : Serial.MinusOne); + if (GetSaveFlag(flags, SaveFlag.Parent)) + { + if (m_Parent?.Deleted == false) + writer.Write(m_Parent.Serial); + else + writer.Write(Serial.MinusOne); + } if (GetSaveFlag(flags, SaveFlag.Items)) writer.Write(items, false); @@ -1380,10 +1443,10 @@ namespace Server public List AcquireItems() { if (this is Container cont) - return cont.m_Items ??= new List(); + return cont.m_Items ?? (cont.m_Items = new List()); CompactInfo info = AcquireCompactInfo(); - return info.m_Items ??= new List(); + return info.m_Items ?? (info.m_Items = new List()); } private void SetFlag(ImplFlag flag, bool value) @@ -1475,7 +1538,7 @@ namespace Server /// public virtual void SendPropertiesTo(Mobile from) { - PropertyList.Send(from?.NetState); + from.Send(PropertyList); } /// @@ -1624,23 +1687,23 @@ namespace Server list.Add(1062203, "{0}", m.Name); // Blessed for ~1_NAME~ } - /// - /// Overridable. Fills an with everything applicable. By default, this invokes - /// , then Item.GetChildProperties or - /// Mobile.GetChildProperties. This method should be overridden to add any custom - /// properties. - /// - public virtual void GetProperties(ObjectPropertyList list) + /// + /// Overridable. Fills an with everything applicable. By default, this invokes + /// , then Item.GetChildProperties or + /// Mobile.GetChildProperties. This method should be overridden to add any custom + /// properties. + /// + public virtual void GetProperties(ObjectPropertyList list) { AddNameProperties(list); } - /// - /// Overridable. Event invoked when a child () is building it's . - /// Recursively calls Item.GetChildProperties or - /// Mobile.GetChildProperties. - /// - public virtual void GetChildProperties(ObjectPropertyList list, Item item) + /// + /// Overridable. Event invoked when a child () is building it's . + /// Recursively calls Item.GetChildProperties or + /// Mobile.GetChildProperties. + /// + public virtual void GetChildProperties(ObjectPropertyList list, Item item) { if (m_Parent is Item parentItem) parentItem.GetChildProperties(list, item); @@ -1648,12 +1711,12 @@ namespace Server parentMobile.GetChildProperties(list, item); } - /// - /// Overridable. Event invoked when a child () is building it's Name - /// . Recursively calls Item.GetChildNameProperties or - /// Mobile.GetChildNameProperties. - /// - public virtual void GetChildNameProperties(ObjectPropertyList list, Item item) + /// + /// Overridable. Event invoked when a child () is building it's Name + /// . Recursively calls Item.GetChildNameProperties or + /// Mobile.GetChildNameProperties. + /// + public virtual void GetChildNameProperties(ObjectPropertyList list, Item item) { if (m_Parent is Item parentItem) parentItem.GetChildNameProperties(list, item); @@ -1679,7 +1742,9 @@ namespace Server IEntity parent = bounce.m_Parent; if (parent?.Deleted != false) + { MoveToWorld(bounce.m_WorldLoc, bounce.m_Map); + } else if (parent is Item p) { IEntity root = p.RootParent; @@ -1691,7 +1756,9 @@ namespace Server p.AddItem(this); } else + { MoveToWorld(from.Location, from.Map); + } } else if (parent is Mobile parentMobile) { @@ -1699,7 +1766,9 @@ namespace Server MoveToWorld(bounce.m_WorldLoc, bounce.m_Map); } else + { MoveToWorld(bounce.m_WorldLoc, bounce.m_Map); + } ClearBounce(); } @@ -1790,14 +1859,19 @@ namespace Server MoveToWorld(location, m_Map); } - public void LabelTo(Mobile to, int number, string args = "") + public void LabelTo(Mobile to, int number) { - Packets.SendMessageLocalized(to?.NetState, Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", args); + to.Send(new MessageLocalized(Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", "")); + } + + public void LabelTo(Mobile to, int number, string args) + { + to.Send(new MessageLocalized(Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", args)); } public void LabelTo(Mobile to, string text) { - Packets.SendUnicodeMessage(to?.NetState, Serial, m_ItemID, MessageType.Label, 0x3B2, 3, "ENU", "", text); + to.Send(new UnicodeMessage(Serial, m_ItemID, MessageType.Label, 0x3B2, 3, "ENU", "", text)); } public void LabelTo(Mobile to, string format, params object[] args) @@ -1805,9 +1879,14 @@ namespace Server LabelTo(to, string.Format(format, args)); } - public void LabelToAffix(Mobile to, int number, AffixType type, string affix, string args = "") + public void LabelToAffix(Mobile to, int number, AffixType type, string affix) { - Packets.SendMessageLocalizedAffix(to?.NetState, Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", type, affix, args); + to.Send(new MessageLocalizedAffix(Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", type, affix, "")); + } + + public void LabelToAffix(Mobile to, int number, AffixType type, string affix, string args) + { + to.Send(new MessageLocalizedAffix(Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", type, affix, args)); } public virtual void LabelLootTypeTo(Mobile to) @@ -1921,7 +2000,8 @@ namespace Server public void ClearProperties() { - m_PropertyList = null; + StaticPacketHandlers.FreeOPLPacket(this); + StaticPacketHandlers.FreeOPLInfoPacket(this); } public void InvalidateProperties() @@ -1931,14 +2011,23 @@ namespace Server if (m_Map != null && m_Map != Map.Internal && !World.Loading) { - ObjectPropertyList oldList = m_PropertyList; - m_PropertyList = null; + ObjectPropertyList oldList = StaticPacketHandlers.FreeOPLPacket(this); if (oldList?.Hash != PropertyList.Hash) + { + StaticPacketHandlers.FreeOPLInfoPacket(this); Delta(ItemDelta.Properties); + } } else + { ClearProperties(); + } + } + + public void ReleaseWorldPackets() + { + StaticPacketHandlers.FreeWorldItemPackets(this); } public virtual int GetPacketFlags() @@ -1987,17 +2076,18 @@ namespace Server private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; - public IPooledEnumerable GetObjectsInRange(int range) => - m_Map?.GetObjectsInRange(m_Parent == null ? m_Location : GetWorldLocation(), range) ?? Map.NullEnumerable.Instance; + public IPooledEnumerable GetObjectsInRange(int range) + { + Map map = m_Map; - public IPooledEnumerable GetItemsInRange(int range) => - m_Map?.GetItemsInRange(m_Parent == null ? m_Location : GetWorldLocation(), range) ?? Map.NullEnumerable.Instance; + if (map == null) + return Map.NullEnumerable.Instance; - public IPooledEnumerable GetMobilesInRange(int range) => - m_Map?.GetMobilesInRange(m_Parent == null ? m_Location : GetWorldLocation(), range) ?? Map.NullEnumerable.Instance; + if (m_Parent == null) + return map.GetObjectsInRange(m_Location, range); - public IPooledEnumerable GetClientsInRange(int range) => - m_Map?.GetClientsInRange(m_Parent == null ? m_Location : GetWorldLocation(), range) ?? Map.NullEnumerable.Instance; + return map.GetObjectsInRange(GetWorldLocation(), range); + } public IPooledEnumerable GetItemsInRange(int range) { @@ -2448,7 +2538,9 @@ namespace Server if (heldBy != null) { if (GetBounce() != null) + { Bounce(heldBy); + } else { heldBy.Holding = null; @@ -2469,22 +2561,18 @@ namespace Server public virtual void SendInfoTo(NetState state, bool sendOplPacket) { - SendWorldPacketFor(state); + state.Send(GetWorldPacketFor(state)); - if (sendOplPacket) - PropertyList.Send(state); + if (sendOplPacket) state.Send(OPLPacket); } - // World packets need to be invalidated when any of the following changes: - // - ItemID - // - Amount - // - Location - // - Hue - // - Packet Flags - // - Direction - protected virtual void SendWorldPacketFor(NetState state) + protected virtual Packet GetWorldPacketFor(NetState state) { - Packets.SendWorldItem(state, this); + if (state.HighSeas) + return WorldPacketHS; + if (state.StygianAbyss) + return WorldPacketSA; + return WorldPacket; } public virtual int GetTotal(TotalType type) => 0; @@ -2664,7 +2752,10 @@ namespace Server public virtual void FreeCache() { - m_PropertyList = null; + ReleaseWorldPackets(); + StaticPacketHandlers.FreeRemoveItemPacket(this); + StaticPacketHandlers.FreeOPLInfoPacket(this); + StaticPacketHandlers.FreeOPLPacket(this); } public void PublicOverheadMessage(MessageType type, int hue, bool ascii, string text) @@ -2672,6 +2763,7 @@ namespace Server if (m_Map == null) return; + Packet p = null; Point3D worldLoc = GetWorldLocation(); IPooledEnumerable eable = m_Map.GetClientsInRange(worldLoc, GetMaxUpdateRange()); @@ -2682,21 +2774,36 @@ namespace Server if (m.CanSee(this) && m.InRange(worldLoc, GetUpdateRange(m))) { - if (ascii) - Packets.SendAsciiMessage(state, Serial, m_ItemID, type, hue, 3, Name, text); - else - Packets.SendUnicodeMessage(state, Serial, m_ItemID, type, hue, 3, "ENU", Name, text); + if (p == null) + { + if (ascii) + p = new AsciiMessage(Serial, m_ItemID, type, hue, 3, Name, text); + else + p = new UnicodeMessage(Serial, m_ItemID, type, hue, 3, "ENU", Name, text); + + p.Acquire(); + } + + state.Send(p); } } + Packet.Release(p); + eable.Free(); } - public void PublicOverheadMessage(MessageType type, int hue, int number, string args = "") + public void PublicOverheadMessage(MessageType type, int hue, int number) + { + PublicOverheadMessage(type, hue, number, ""); + } + + public void PublicOverheadMessage(MessageType type, int hue, int number, string args) { if (m_Map == null) return; + Packet p = null; Point3D worldLoc = GetWorldLocation(); IPooledEnumerable eable = m_Map.GetClientsInRange(worldLoc, GetMaxUpdateRange()); @@ -2706,9 +2813,16 @@ namespace Server Mobile m = state.Mobile; if (m.CanSee(this) && m.InRange(worldLoc, GetUpdateRange(m))) - Packets.SendMessageLocalized(state, Serial, m_ItemID, type, hue, 3, number, Name, args); + { + if (p == null) + p = Packet.Acquire(new MessageLocalized(Serial, m_ItemID, type, hue, 3, number, Name, args)); + + state.Send(p); + } } + Packet.Release(p); + eable.Free(); } @@ -3073,8 +3187,7 @@ namespace Server { Mobile m = state.Mobile; - if (m.InRange(worldLoc, GetUpdateRange(m))) - Packets.SendRemoveEntity(state, Serial); + if (m.InRange(worldLoc, GetUpdateRange(m))) state.Send(RemovePacket); } eable.Free(); @@ -3114,21 +3227,21 @@ namespace Server to.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", "")); } - public void SendLocalizedMessageTo(Mobile to, int number, string args = "") + public void SendLocalizedMessageTo(Mobile to, int number, string args) { if (Deleted || !to.CanSee(this)) return; - Packets.SendMessageLocalized(to.NetState, Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", args); + to.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", args)); } - public void SendLocalizedMessageTo(Mobile to, int number, AffixType affixType, string affix = "", string args = "") + public void SendLocalizedMessageTo(Mobile to, int number, AffixType affixType, string affix, string args) { if (Deleted || !to.CanSee(this)) return; - Packets.SendMessageLocalizedAffix(to.NetState, Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", affixType, affix, - args); + to.Send(new MessageLocalizedAffix(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", affixType, affix, + args)); } public virtual void OnSnoop(Mobile from) @@ -3280,7 +3393,7 @@ namespace Server public bool CheckLift(Mobile from) { - LRReason reject = LRReason.Unspecific; + LRReason reject = LRReason.Inspecific; return CheckLift(from, this, ref reject); } @@ -3307,8 +3420,8 @@ namespace Server ObjectPropertyList opl = PropertyList; if (opl.Header > 0) - Packets.SendMessageLocalized(from.NetState, Serial, m_ItemID, MessageType.Label, 0x3B2, 3, opl.Header, Name, - opl.HeaderArgs); + from.Send(new MessageLocalized(Serial, m_ItemID, MessageType.Label, 0x3B2, 3, opl.Header, Name, + opl.HeaderArgs)); } public virtual void OnSingleClick(Mobile from) @@ -3327,10 +3440,11 @@ namespace Server if (Name == null) { if (m_Amount <= 1) - Packets.SendMessageLocalized(ns, Serial, m_ItemID, MessageType.Label, 0x3B2, 3, LabelNumber); + ns.Send(new MessageLocalized(Serial, m_ItemID, MessageType.Label, 0x3B2, 3, LabelNumber, "", "")); else - Packets.SendMessageLocalizedAffix(ns, Serial, m_ItemID, MessageType.Label, 0x3B2, 3, LabelNumber, "", - AffixType.Append, $" : {m_Amount}"); + ns.Send(new MessageLocalizedAffix(Serial, m_ItemID, MessageType.Label, 0x3B2, 3, LabelNumber, "", + AffixType.Append, + $" : {m_Amount}", "")); } else { @@ -3420,8 +3534,8 @@ namespace Server if (BlessedFor != null) return false; - public virtual bool IsStandardLoot() => - !(Mobile.InsuranceEnabled && Insured) && BlessedFor == null && m_LootType == LootType.Regular; + return m_LootType == LootType.Regular; + } public override string ToString() => $"0x{Serial.Value:X} \"{GetType().Name}\""; @@ -3509,9 +3623,11 @@ namespace Server private Map m_Map; private LootType m_LootType; private Direction m_Direction; + #endregion #region Location Location Location! + public virtual void OnLocationChange(Point3D oldLocation) { } @@ -3540,8 +3656,7 @@ namespace Server { Mobile m = state.Mobile; - if (!m.InRange(value, GetUpdateRange(m))) - Packets.SendRemoveEntity(state, Serial); + if (!m.InRange(value, GetUpdateRange(m))) state.Send(RemovePacket); } eable.Free(); @@ -3549,6 +3664,7 @@ namespace Server Point3D oldLoc = m_Location; m_Location = value; + ReleaseWorldPackets(); SetLastMoved(); @@ -3571,17 +3687,24 @@ namespace Server else if (m_Parent is Item) { m_Location = value; + ReleaseWorldPackets(); Delta(ItemDelta.Update); } else + { m_Location = value; + ReleaseWorldPackets(); + } if (m_Parent == null) m_Map.OnMove(oldLocation, this); } else + { m_Location = value; + ReleaseWorldPackets(); + } OnLocationChange(oldLocation); } @@ -3607,9 +3730,11 @@ namespace Server get => m_Location.m_Z; set => Location = new Point3D(m_Location.m_X, m_Location.m_Y, value); } + #endregion #region OnDoubleClick[...] + public virtual void OnDoubleClick(Mobile from) { } @@ -3636,6 +3761,7 @@ namespace Server { from.SendLocalizedMessage(500447); // That is not accessible. } + #endregion } } diff --git a/Projects/Server/Items/Container.cs b/Projects/Server/Items/Container.cs index 92c86305f..150597e64 100644 --- a/Projects/Server/Items/Container.cs +++ b/Projects/Server/Items/Container.cs @@ -485,6 +485,9 @@ namespace Server.Items int extraItems = 0; int extraWeight = 0; +// from.SendMessage( String.Format( "There are {0} items in this container.", this.Items.Count ) ); +// from.SendMessage( String.Format( "There are {0} items being dropped into this container.", droppedItems.Length ) ); + for (int i = 0; i < droppedItems.Length; i++) { Item dropped = droppedItems[i]; @@ -593,7 +596,9 @@ namespace Server.Items } } else + { from.SendLocalizedMessage(500446); // That is too far away. + } } public virtual bool CheckContentDisplay(Mobile from) => @@ -625,7 +630,10 @@ namespace Server.Items if (ns != null) { - Packets.SendDisplayContainer(ns, Serial, (short)GumpID); + if (ns.HighSeas) + to.Send(new ContainerDisplayHS(this)); + else + to.Send(new ContainerDisplay(this)); SendContentTo(ns); @@ -634,7 +642,7 @@ namespace Server.Items List items = Items; for (int i = 0; i < items.Count; ++i) - items[i].PropertyList.SendOPLInfo(ns); + to.Send(items[i].OPLPacket); } } } @@ -656,7 +664,9 @@ namespace Server.Items Mobile mob = Openers[i]; if (mob == opener) + { contains = true; + } else { int range = GetUpdateRange(mob); @@ -669,14 +679,24 @@ namespace Server.Items if (!contains) { - Openers ??= new List(); + if (Openers == null) + Openers = new List(); + Openers.Add(opener); } else if (Openers?.Count == 0) + { Openers = null; + } } - public virtual void SendContentTo(NetState state) => Packets.SendContainerContent(state, state.Mobile, this); + public virtual void SendContentTo(NetState state) + { + if (state?.ContainerGridLines == true) + state.Send(new ContainerContent6017(state.Mobile, this)); + else + state.Send(new ContainerContent(state.Mobile, this)); + } public override void GetProperties(ObjectPropertyList list) { @@ -788,7 +808,8 @@ namespace Server.Items for (int j = 0; j < items[i].Length; ++j) totals[i] += items[i][j].Amount; - hasEnough |= totals[i] >= amount; + if (totals[i] >= amount) + hasEnough = true; } if (!hasEnough) @@ -880,7 +901,8 @@ namespace Server.Items for (int k = 0; k < items[i][j].Length; ++k) totals[i][j] += items[i][j][k].Amount; - hasEnough |= totals[i][j] >= amounts[i]; + if (totals[i][j] >= amounts[i]) + hasEnough = true; } if (!hasEnough) @@ -974,7 +996,8 @@ namespace Server.Items for (int k = 0; k < items[i][j].Length; ++k) totals[i][j] += items[i][j][k].Amount; - hasEnough |= totals[i][j] >= amounts[i]; + if (totals[i][j] >= amounts[i]) + hasEnough = true; } if (!hasEnough) @@ -1575,10 +1598,12 @@ namespace Server.Items public class ContainerData { - private static readonly Dictionary Table = new Dictionary(); + private static Dictionary m_Table; static ContainerData() { + m_Table = new Dictionary(); + string path = Path.Combine(Core.BaseDirectory, "Data/containers.cfg"); if (!File.Exists(path)) @@ -1604,7 +1629,7 @@ namespace Server.Items if (split.Length >= 3) { - int gumpId = Utility.ToInt32(split[0]); + int gumpID = Utility.ToInt32(split[0]); string[] aRect = split[1].Split(' '); if (aRect.Length < 4) @@ -1619,9 +1644,10 @@ namespace Server.Items int dropSound = Utility.ToInt32(split[2]); - ContainerData data = new ContainerData(gumpId, bounds, dropSound); + ContainerData data = new ContainerData(gumpID, bounds, dropSound); - Default ??= data; + if (Default == null) + Default = data; if (split.Length >= 4) { @@ -1631,10 +1657,10 @@ namespace Server.Items { int id = Utility.ToInt32(aIDs[i]); - if (Table.ContainsKey(id)) + if (m_Table.ContainsKey(id)) Console.WriteLine(@"Warning: double ItemID entry in Data\containers.cfg"); else - Table[id] = data; + m_Table[id] = data; } } } @@ -1646,12 +1672,13 @@ namespace Server.Items } } - Default ??= new ContainerData(0x3C, new Rectangle2D(44, 65, 142, 94), 0x48); + if (Default == null) + Default = new ContainerData(0x3C, new Rectangle2D(44, 65, 142, 94), 0x48); } - public ContainerData(int gumpId, Rectangle2D bounds, int dropSound) + public ContainerData(int gumpID, Rectangle2D bounds, int dropSound) { - GumpID = gumpId; + GumpID = gumpID; Bounds = bounds; DropSound = dropSound; } @@ -1664,9 +1691,9 @@ namespace Server.Items public int DropSound{ get; } - public static ContainerData GetData(int itemId) + public static ContainerData GetData(int itemID) { - Table.TryGetValue(itemId, out ContainerData data); + m_Table.TryGetValue(itemID, out ContainerData data); return data ?? Default; } } diff --git a/Projects/Server/Items/Containers.cs b/Projects/Server/Items/Containers.cs index eaa794144..181481652 100644 --- a/Projects/Server/Items/Containers.cs +++ b/Projects/Server/Items/Containers.cs @@ -18,6 +18,7 @@ * ***************************************************************************/ +using Server.Accounting; using Server.Network; namespace Server.Items @@ -53,9 +54,7 @@ namespace Server.Items { Owner.PrivateOverheadMessage(MessageType.Regular, 0x3B2, true, $"Bank container has {TotalItems} items, {TotalWeight} stones", Owner.NetState); - - if (Owner.NetState != null) - Packets.SendEquipUpdate(Owner.NetState, this); + Owner.Send(new EquipUpdate(this)); DisplayTo(Owner); } } @@ -98,8 +97,8 @@ namespace Server.Items { Opened = false; - if (SendDeleteOnClose && Owner != null) - Packets.SendRemoveEntity(Owner.NetState, Serial); + if (SendDeleteOnClose) + Owner?.Send(RemovePacket); } public override void OnSingleClick(Mobile from) diff --git a/Projects/Server/Items/SecureTradeContainer.cs b/Projects/Server/Items/SecureTradeContainer.cs index 063400fd2..e759a29a0 100644 --- a/Projects/Server/Items/SecureTradeContainer.cs +++ b/Projects/Server/Items/SecureTradeContainer.cs @@ -18,6 +18,7 @@ * ***************************************************************************/ +using Server.Accounting; using Server.Network; namespace Server.Items diff --git a/Projects/Server/Items/VirtualCheck.cs b/Projects/Server/Items/VirtualCheck.cs index 88e64fa94..514e60739 100644 --- a/Projects/Server/Items/VirtualCheck.cs +++ b/Projects/Server/Items/VirtualCheck.cs @@ -1,7 +1,8 @@ using Server.Gumps; +using Server.Items; using Server.Network; -namespace Server.Items +namespace Server { public sealed class VirtualCheck : Item { @@ -34,7 +35,7 @@ namespace Server.Items public override string DefaultName => "Offer Of Currency"; - public EditGump Editor { get; private set; } + public EditGump Editor{ get; private set; } [CommandProperty(AccessLevel.Administrator)] public int Plat @@ -170,8 +171,8 @@ namespace Server.Items CompileLayout(); } - public Mobile User { get; } - public VirtualCheck Check { get; private set; } + public Mobile User{ get; } + public VirtualCheck Check{ get; private set; } public override void OnServerClose(NetState owner) { diff --git a/Projects/Server/Items/VirtualHair.cs b/Projects/Server/Items/VirtualHair.cs index 697c7ce1b..db38e9743 100644 --- a/Projects/Server/Items/VirtualHair.cs +++ b/Projects/Server/Items/VirtualHair.cs @@ -18,7 +18,9 @@ * ***************************************************************************/ -namespace Server.Items +using Server.Network; + +namespace Server { public abstract class BaseHairInfo { @@ -59,7 +61,12 @@ namespace Server.Items public class HairInfo : BaseHairInfo { - public HairInfo(int itemid, int hue = 0) + public HairInfo(int itemid) + : base(itemid) + { + } + + public HairInfo(int itemid, int hue) : base(itemid, hue) { } @@ -75,7 +82,12 @@ namespace Server.Items public class FacialHairInfo : BaseHairInfo { - public FacialHairInfo(int itemid, int hue = 0) + public FacialHairInfo(int itemid) + : base(itemid) + { + } + + public FacialHairInfo(int itemid, int hue) : base(itemid, hue) { } @@ -144,4 +156,4 @@ namespace Server.Items m_Stream.Write(FacialHairInfo.FakeSerial(parent)); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Layer.cs b/Projects/Server/Layer.cs index 99f7c2ec0..936917bf6 100644 --- a/Projects/Server/Layer.cs +++ b/Projects/Server/Layer.cs @@ -1,23 +1,3 @@ -/*************************************************************************** - * Layer.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - namespace Server { /// diff --git a/Projects/Server/LightType.cs b/Projects/Server/LightType.cs index 61637af3d..cdab2e58b 100644 --- a/Projects/Server/LightType.cs +++ b/Projects/Server/LightType.cs @@ -1,23 +1,3 @@ -/*************************************************************************** - * LightType.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - namespace Server { public enum LightType diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index 7f9273ea5..53a975885 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -39,6 +39,10 @@ namespace Server { private static bool m_Crashed; private static Thread timerThread; + private static string m_BaseDirectory; + private static string m_ExePath; + + private static bool m_Cache = true; private static bool m_Profiling; private static DateTime m_ProfileStart; @@ -52,16 +56,18 @@ namespace Server * GetTickCount and GetTickCount64 have poor resolution. * GetTickCount64 is unavailable on Windows XP and Windows Server 2003. * Stopwatch.GetTimestamp() (QueryPerformanceCounter) is high resolution, but - * somewhat expensive to call because of its difference to DateTime.Now, + * somewhat expensive to call because of its defference to DateTime.Now, * which is why Stopwatch has been used to verify HRT before calling GetTimestamp(), * enabling the usage of DateTime.UtcNow instead. */ - private static readonly bool UsingHighResolutionTiming = Stopwatch.IsHighResolution; + private static readonly bool _HighRes = Stopwatch.IsHighResolution; private static readonly double _HighFrequency = 1000.0 / Stopwatch.Frequency; private static readonly double _LowFrequency = 1000.0 / TimeSpan.TicksPerSecond; + private static bool _UseHRT; + public static readonly bool Is64Bit = Environment.Is64BitProcess; internal static ConsoleEventHandler m_ConsoleEventHandler; @@ -93,8 +99,16 @@ namespace Server } } - public static TimeSpan ProfileTime => - m_ProfileStart > DateTime.MinValue ? m_ProfileTime + (DateTime.UtcNow - m_ProfileStart) : m_ProfileTime; + public static TimeSpan ProfileTime + { + get + { + if (m_ProfileStart > DateTime.MinValue) + return m_ProfileTime + (DateTime.UtcNow - m_ProfileStart); + + return m_ProfileTime; + } + } public static bool Service{ get; private set; } @@ -102,22 +116,28 @@ namespace Server internal static bool HaltOnWarning{ get; private set; } - public static List DataDirectories{ get; } = new List(); + public static Assembly Assembly{ get; set; } - public static Assembly Assembly { get; } = Assembly.GetEntryAssembly(); - - public static readonly Version Version = Assembly.GetName().Version; - - public static Process Process { get; } = Process.GetCurrentProcess(); + public static Version Version => Assembly.GetName().Version; + public static Process Process{ get; private set; } public static Thread Thread{ get; private set; } public static MultiTextWriter MultiConsoleOut{ get; private set; } + public static bool UsingHighResolutionTiming => _UseHRT && _HighRes && !Unix; + public static long TickCount => (long)Ticks; - public static double Ticks => - UsingHighResolutionTiming ? Stopwatch.GetTimestamp() * _HighFrequency : DateTime.UtcNow.Ticks * _LowFrequency; + public static double Ticks + { + get + { + if (_UseHRT && _HighRes && !Unix) return Stopwatch.GetTimestamp() * _HighFrequency; + + return DateTime.UtcNow.Ticks * _LowFrequency; + } + } public static bool MultiProcessor{ get; private set; } @@ -125,9 +145,28 @@ namespace Server public static bool Unix{ get; private set; } - public static string ExePath => Process.MainModule?.FileName; + public static string ExePath => m_ExePath ?? (m_ExePath = Assembly.Location); - public static readonly string BaseDirectory = Path.GetDirectoryName(ExePath ?? "") ?? ""; + public static string BaseDirectory + { + get + { + if (m_BaseDirectory == null) + try + { + m_BaseDirectory = ExePath; + + if (m_BaseDirectory.Length > 0) + m_BaseDirectory = Path.GetDirectoryName(m_BaseDirectory); + } + catch + { + m_BaseDirectory = ""; + } + + return m_BaseDirectory; + } + } public static bool Closing{ get; private set; } @@ -150,9 +189,15 @@ namespace Server if (m_Profiling) Utility.Separate(sb, "-profile", " "); + if (!m_Cache) + Utility.Separate(sb, "-nocache", " "); + if (HaltOnWarning) Utility.Separate(sb, "-haltonwarning", " "); + if (_UseHRT) + Utility.Separate(sb, "-usehrt", " "); + return sb.ToString(); } } @@ -234,8 +279,10 @@ namespace Server private static bool OnConsoleEvent(ConsoleEventType type) { - if (!(World.Saving || Service && type == ConsoleEventType.CTRL_LOGOFF_EVENT)) - Kill(); //Kill -> HandleClosed will handle waiting for the completion of flushing to disk + if (World.Saving || Service && type == ConsoleEventType.CTRL_LOGOFF_EVENT) + return true; + + Kill(); //Kill -> HandleClosed will handle waiting for the completion of flushing to disk return true; } @@ -274,7 +321,10 @@ namespace Server Console.WriteLine("done"); } - public static void Set() => m_Signal.Set(); + public static void Set() + { + m_Signal.Set(); + } public static void Main(string[] args) { @@ -282,12 +332,18 @@ namespace Server AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; foreach (string a in args) - { - Debug |= Insensitive.Equals(a, "-debug"); - Service |= Insensitive.Equals(a, "-service"); - Profiling |= Insensitive.Equals(a, "-profiling"); - HaltOnWarning |= Insensitive.Equals(a, "-haltonwarning"); - } + if (Insensitive.Equals(a, "-debug")) + Debug = true; + else if (Insensitive.Equals(a, "-service")) + Service = true; + else if (Insensitive.Equals(a, "-profile")) + Profiling = true; + else if (Insensitive.Equals(a, "-nocache")) + m_Cache = false; + else if (Insensitive.Equals(a, "-haltonwarning")) + HaltOnWarning = true; + else if (Insensitive.Equals(a, "-usehrt")) + _UseHRT = true; try { @@ -299,7 +355,9 @@ namespace Server Console.SetOut(MultiConsoleOut = new MultiTextWriter(new FileLogger("Logs/Console.log"))); } else + { Console.SetOut(MultiConsoleOut = new MultiTextWriter(Console.Out)); + } } catch { @@ -307,6 +365,8 @@ namespace Server } Thread = Thread.CurrentThread; + Process = Process.GetCurrentProcess(); + Assembly = Assembly.GetEntryAssembly(); if (Thread != null) Thread.Name = "Core Thread"; @@ -339,12 +399,6 @@ namespace Server Name = "Timer Thread" }; - Version ver = Version; - - // Added to help future code support on forums, as a 'check' people can ask for to it see if they recompiled core or not - Console.WriteLine("ModernUO - [https://github.com/modernuo/modernuo] v{0}.{1}.{2}{3}", ver.Major, ver.Minor, ver.Build, ver.Revision != 0 ? ver.Revision.ToString() : ""); - Console.WriteLine("Core: Running on {0}", RuntimeInformation.FrameworkDescription); - string s = Arguments; if (s.Length > 0) @@ -352,15 +406,17 @@ namespace Server ProcessorCount = Environment.ProcessorCount; - MultiProcessor |= ProcessorCount > 1; + if (ProcessorCount > 1) + MultiProcessor = true; - if (!Is64Bit) throw new NotSupportedException("Core: 32-bit operating systems are not supported"); + if (MultiProcessor || Is64Bit) + Console.WriteLine("Core: Optimizing for {0} {2}processor{1}", ProcessorCount, ProcessorCount == 1 ? "" : "s", + Is64Bit ? "64-bit " : ""); - if (MultiProcessor) - Console.WriteLine("Core: Optimizing for {0} processor{1}", ProcessorCount, ProcessorCount == 1 ? "" : "s"); - - if (Environment.OSVersion.Platform == PlatformID.Unix) + int platform = (int)Environment.OSVersion.Platform; + if (platform == 4 || platform == 128) { + // MS 4, MONO 128 Unix = true; Console.WriteLine("Core: Unix environment detected"); } @@ -373,8 +429,9 @@ namespace Server if (GCSettings.IsServerGC) Console.WriteLine("Core: Server garbage collection mode enabled"); - if (UsingHighResolutionTiming) - Console.WriteLine("Core: High resolution timing detected"); + if (_UseHRT) + Console.WriteLine("Core: Requested high resolution timing ({0})", + UsingHighResolutionTiming ? "Supported" : "Unsupported"); Console.WriteLine("RandomImpl: {0} ({1})", RandomImpl.Type.Name, RandomImpl.IsHardwareRNG ? "Hardware" : "Software"); @@ -416,9 +473,7 @@ namespace Server { m_Signal.WaitOne(); - - Task.WhenAll( - + Task.WaitAll( Task.Run(Mobile.ProcessDeltaQueue), Task.Run(Item.ProcessDeltaQueue) ); @@ -484,7 +539,8 @@ namespace Server BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) == null) { - warningSb ??= new StringBuilder(); + if (warningSb == null) warningSb = new StringBuilder(); + warningSb.AppendLine(" - No Serialize() method"); } @@ -494,7 +550,8 @@ namespace Server BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) == null) { - warningSb ??= new StringBuilder(); + if (warningSb == null) warningSb = new StringBuilder(); + warningSb.AppendLine(" - No Deserialize() method"); } @@ -508,8 +565,7 @@ namespace Server private static void VerifySerialization(Assembly a) { - if (a != null) - Parallel.ForEach(a.GetTypes(), VerifyType); + if (a != null) Parallel.ForEach(a.GetTypes(), VerifyType); } internal enum ConsoleEventType diff --git a/Projects/Server/Map.cs b/Projects/Server/Map.cs index af0513343..9f7235197 100644 --- a/Projects/Server/Map.cs +++ b/Projects/Server/Map.cs @@ -20,10 +20,8 @@ using System; using System.Collections; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using System.Threading; using Server.Items; using Server.Network; using Server.Targeting; @@ -47,7 +45,7 @@ namespace Server void Free(); } - public interface IPooledEnumerable : IPooledEnumerable, IEnumerable + public interface IPooledEnumerable : IPooledEnumerable, IEnumerable { } @@ -90,15 +88,21 @@ namespace Server return eable.Where(bounds.Contains); } - public static IEnumerable SelectMobiles(Sector s, Rectangle2D bounds) where T : Mobile => - s.Mobiles.OfType().Where(o => !o.Deleted && bounds.Contains(o)); + public static IEnumerable SelectMobiles(Sector s, Rectangle2D bounds) where T : Mobile + { + return s.Mobiles.OfType().Where(o => !o.Deleted && bounds.Contains(o)); + } - public static IEnumerable SelectItems(Sector s, Rectangle2D bounds) where T : Item => - s.Items.OfType() + public static IEnumerable SelectItems(Sector s, Rectangle2D bounds) where T : Item + { + return s.Items.OfType() .Where(o => o.Deleted == false && o.Parent == null && bounds.Contains(o)); + } - public static IEnumerable SelectMultis(Sector s, Rectangle2D bounds) => - s.Multis.Where(o => o?.Deleted == false && bounds.Contains(o.Location)); + public static IEnumerable SelectMultis(Sector s, Rectangle2D bounds) + { + return s.Multis.Where(o => o?.Deleted == false && bounds.Contains(o.Location)); + } public static IEnumerable SelectMultiTiles(Sector s, Rectangle2D bounds) { @@ -106,23 +110,26 @@ namespace Server { MultiComponentList c = o.Components; - for (int x = bounds.Start.X; x < bounds.End.X; x++) + int x, y, xo, yo; + StaticTile[] t, r; + + for (x = bounds.Start.X; x < bounds.End.X; x++) { - int xo = x - (o.X + c.Min.X); + xo = x - (o.X + c.Min.X); if (xo < 0 || xo >= c.Width) continue; - for (int y = bounds.Start.Y; y < bounds.End.Y; y++) + for (y = bounds.Start.Y; y < bounds.End.Y; y++) { - int yo = y - (o.Y + c.Min.Y); + yo = y - (o.Y + c.Min.Y); if (yo < 0 || yo >= c.Height) continue; - StaticTile[] t = c.Tiles[xo][yo]; + t = c.Tiles[xo][yo]; if (t.Length <= 0) continue; - StaticTile[] r = new StaticTile[t.Length]; + r = new StaticTile[t.Length]; for (int i = 0; i < t.Length; i++) { @@ -250,7 +257,7 @@ namespace Server public const int SectorShift = 4; public static int SectorActiveRange = 2; - private static readonly ConcurrentQueue> _FixPool = new ConcurrentQueue>(); + private static readonly Queue> _FixPool = new Queue>(128); private static readonly List _EmptyFixItems = new List(); private Region m_DefaultRegion; @@ -264,7 +271,9 @@ namespace Server private TileMatrix m_Tiles; - public Map(int mapID, int mapIndex, int fileIndex, int width, int height, byte season, string name, MapRules rules) + private object tileLock = new object(); + + public Map(int mapID, int mapIndex, int fileIndex, int width, int height, int season, string name, MapRules rules) { MapID = mapID; MapIndex = mapIndex; @@ -293,14 +302,17 @@ namespace Server public static List AllMaps{ get; } = new List(); - public byte Season{ get; set; } + public int Season{ get; set; } public TileMatrix Tiles { get { if (m_Tiles == null) - Interlocked.Exchange(ref m_Tiles, new TileMatrix(this, m_FileIndex, MapID, Width, Height)); + lock (tileLock) + { + m_Tiles = new TileMatrix(this, m_FileIndex, MapID, Width, Height); + } return m_Tiles; } @@ -318,7 +330,8 @@ namespace Server public Region DefaultRegion { - get => m_DefaultRegion ??= new Region(null, this, 0, new Rectangle3D[0]); + get => m_DefaultRegion ?? + (m_DefaultRegion = new Region(null, this, 0, new Rectangle3D[0])); set => m_DefaultRegion = value; } @@ -356,9 +369,15 @@ namespace Server public int CompareTo(Map other) => other == null ? -1 : MapID.CompareTo(other.MapID); - public static string[] GetMapNames() => Maps.Where(m => m != null).Select(m => m.Name).ToArray(); + public static string[] GetMapNames() + { + return Maps.Where(m => m != null).Select(m => m.Name).ToArray(); + } - public static Map[] GetMapValues() => Maps.Where(m => m != null).ToArray(); + public static Map[] GetMapValues() + { + return Maps.Where(m => m != null).ToArray(); + } public static Map Parse(string value) { @@ -369,7 +388,7 @@ namespace Server return Internal; if (!int.TryParse(value, out int index)) - return Maps.FirstOrDefault(m => Insensitive.Equals(m?.Name ?? "", value)); + return Maps.FirstOrDefault(m => m != null && Insensitive.Equals(m.Name, value)); return index == 127 ? Internal : Maps.FirstOrDefault(m => m?.MapIndex == index); } @@ -429,7 +448,15 @@ namespace Server if (map == null || map == Internal || x < 0 || x > map.Width || y < 0 || y > map.Height) return _EmptyFixItems; - if (!_FixPool.TryDequeue(out List pool) || pool == null) + List pool = null; + + lock (_FixPool) + { + if (_FixPool.Count > 0) + pool = _FixPool.Dequeue(); + } + + if (pool == null) pool = new List(128); // Arbitrary limit IPooledEnumerable eable = map.GetItemsInRange(new Point3D(x, y, 0), 0); @@ -451,8 +478,11 @@ namespace Server pool.Clear(); - if (_FixPool.Count < 128) - _FixPool.Enqueue(pool); + lock (_FixPool) + { + if (_FixPool.Count < 128) + _FixPool.Enqueue(pool); + } } public void FixColumn(int x, int y) @@ -548,13 +578,13 @@ namespace Server /// Gets the highest surface that is lower than . /// /// The reference point. - /// A surface ITile - public ITile GetTopSurface(Point3D p) + /// A surface or . + public object GetTopSurface(Point3D p) { if (this == Internal) return null; - ITile surface = null; + object surface = null; int surfaceZ = int.MinValue; @@ -906,7 +936,7 @@ namespace Server public sealed class PooledEnumerable : IPooledEnumerable, IDisposable { - private static readonly ConcurrentQueue> _Buffer = new ConcurrentQueue>(); + private static readonly Queue> _Buffer = new Queue>(0x400); private bool _IsDisposed; @@ -938,20 +968,29 @@ namespace Server _Pool.Clear(); _Pool.Capacity = Math.Max(_Pool.Capacity, 0x100); - _Buffer.Enqueue(this); + lock (((ICollection)_Buffer).SyncRoot) + { + _Buffer.Enqueue(this); + } } public static PooledEnumerable Instantiate(Map map, Rectangle2D bounds, PooledEnumeration.Selector selector) { - IEnumerable pool = PooledEnumeration.EnumerateSectors(map, bounds).SelectMany(s => selector(s, bounds)); + PooledEnumerable e = null; - if (_Buffer.TryDequeue(out PooledEnumerable e) && e != null) + lock (((ICollection)_Buffer).SyncRoot) { - e._Pool.AddRange(pool); - return e; + if (_Buffer.Count > 0) + e = _Buffer.Dequeue(); } - return new PooledEnumerable(pool); + IEnumerable pool = PooledEnumeration.EnumerateSectors(map, bounds).SelectMany(s => selector(s, bounds)); + + if (e == null) + return new PooledEnumerable(pool); + + e._Pool.AddRange(pool); + return e; } } @@ -992,7 +1031,6 @@ namespace Server public IPooledEnumerable GetMobilesInBounds(Rectangle2D bounds) where T : Mobile => PooledEnumeration.GetMobiles(this, bounds); - public IPooledEnumerable GetMobilesInBounds(Rectangle2D bounds) where T : Mobile => PooledEnumeration.GetMobiles(this, bounds); #endregion #region CanFit @@ -1025,7 +1063,8 @@ namespace Server if ((landFlags & TileFlag.Impassable) != 0 && avgZ > z && z + height > lowZ) return false; - hasSurface |= (landFlags & TileFlag.Impassable) == 0 && z == avgZ && !lt.Ignored; + if ((landFlags & TileFlag.Impassable) == 0 && z == avgZ && !lt.Ignored) + hasSurface = true; StaticTile[] staticTiles = Tiles.GetStaticTiles(x, y, true); @@ -1040,7 +1079,8 @@ namespace Server if ((surface || impassable) && staticTiles[i].Z + id.CalcHeight > z && z + height > staticTiles[i].Z) return false; - hasSurface |= surface && !impassable && z == staticTiles[i].Z + id.CalcHeight; + if (surface && !impassable && z == staticTiles[i].Z + id.CalcHeight) + hasSurface = true; } Sector sector = GetSector(x, y); @@ -1061,14 +1101,22 @@ namespace Server z + height > item.Z) return false; - hasSurface |= surface && !impassable && !item.Movable && z == item.Z + id.CalcHeight; + if (surface && !impassable && !item.Movable && z == item.Z + id.CalcHeight) + hasSurface = true; } } - return !(checkMobiles && mobs.Any(m => m.Location.m_X == x && m.Location.m_Y == y && - (m.AccessLevel == AccessLevel.Player || !m.Hidden) && - m.Z + 16 > z && z + height > m.Z)) && - (!requireSurface || hasSurface); + if (checkMobiles) + for (int i = 0; i < mobs.Count; ++i) + { + Mobile m = mobs[i]; + + if (m.Location.m_X == x && m.Location.m_Y == y && (m.AccessLevel == AccessLevel.Player || !m.Hidden) && + m.Z + 16 > z && z + height > m.Z) + return false; + } + + return !requireSurface || hasSurface; } #endregion @@ -1079,8 +1127,13 @@ namespace Server public bool CanSpawnMobile(Point2D p, int z) => CanSpawnMobile(p.m_X, p.m_Y, z); - public bool CanSpawnMobile(int x, int y, int z) => - Region.Find(new Point3D(x, y, z), this).AllowSpawn() && CanFit(x, y, z, 16); + public bool CanSpawnMobile(int x, int y, int z) + { + if (!Region.Find(new Point3D(x, y, z), this).AllowSpawn()) + return false; + + return CanFit(x, y, z, 16); + } #endregion diff --git a/Projects/Server/Menus/IMenu.cs b/Projects/Server/Menus/IMenu.cs index 075767f8b..56405f32e 100644 --- a/Projects/Server/Menus/IMenu.cs +++ b/Projects/Server/Menus/IMenu.cs @@ -24,10 +24,10 @@ namespace Server.Menus { public interface IMenu { - Serial Serial{ get; } + int Serial{ get; } int EntryLength{ get; } void SendTo(NetState state); void OnCancel(NetState state); void OnResponse(NetState state, int index); } -} +} \ No newline at end of file diff --git a/Projects/Server/Menus/ItemListMenu.cs b/Projects/Server/Menus/ItemListMenu.cs index 0ad2e424d..8fc57a153 100644 --- a/Projects/Server/Menus/ItemListMenu.cs +++ b/Projects/Server/Menus/ItemListMenu.cs @@ -20,7 +20,7 @@ using Server.Network; -namespace Server.Menus +namespace Server.Menus.ItemLists { public class ItemListEntry { @@ -40,7 +40,8 @@ namespace Server.Menus public class ItemListMenu : IMenu { - private static Serial m_NextSerial; + private static int m_NextSerial; + private int m_Serial; public ItemListMenu(string question, ItemListEntry[] entries) { @@ -49,18 +50,18 @@ namespace Server.Menus do { - Serial = m_NextSerial++; - Serial &= 0x7FFFFFFF; - } while (Serial == 0); + m_Serial = m_NextSerial++; + m_Serial &= 0x7FFFFFFF; + } while (m_Serial == 0); - Serial |= 0x80000000; + m_Serial = (int)((uint)m_Serial | 0x80000000); } public string Question{ get; } public ItemListEntry[] Entries{ get; set; } - public Serial Serial { get; private set; } + int IMenu.Serial => m_Serial; int IMenu.EntryLength => Entries.Length; @@ -75,7 +76,7 @@ namespace Server.Menus public void SendTo(NetState state) { state.AddMenu(this); - Packets.SendDisplayItemListMenu(state, this); + state.Send(new DisplayItemListMenu(this)); } } } diff --git a/Projects/Server/Menus/QuestionMenu.cs b/Projects/Server/Menus/QuestionMenu.cs index 3e65603d0..0fe6a5aa2 100644 --- a/Projects/Server/Menus/QuestionMenu.cs +++ b/Projects/Server/Menus/QuestionMenu.cs @@ -20,11 +20,12 @@ using Server.Network; -namespace Server.Menus +namespace Server.Menus.Questions { public class QuestionMenu : IMenu { - private static Serial m_NextSerial; + private static int m_NextSerial; + private int m_Serial; public QuestionMenu(string question, string[] answers) { @@ -33,16 +34,16 @@ namespace Server.Menus do { - Serial = ++m_NextSerial; - Serial &= 0x7FFFFFFF; - } while (Serial == 0); + m_Serial = ++m_NextSerial; + m_Serial &= 0x7FFFFFFF; + } while (m_Serial == 0); } public string Question{ get; set; } public string[] Answers{ get; } - public Serial Serial { get; private set; } + int IMenu.Serial => m_Serial; int IMenu.EntryLength => Answers.Length; @@ -57,7 +58,7 @@ namespace Server.Menus public void SendTo(NetState state) { state.AddMenu(this); - Packets.SendDisplayQuestionMenu(state, this); + state.Send(new DisplayQuestionMenu(this)); } } -} +} \ No newline at end of file diff --git a/Projects/Server/Mobile.cs b/Projects/Server/Mobile.cs index 55e1bed38..0fe1f420e 100644 --- a/Projects/Server/Mobile.cs +++ b/Projects/Server/Mobile.cs @@ -19,20 +19,21 @@ ***************************************************************************/ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Text; -using System.Threading; using System.Threading.Tasks; using Server.Accounting; using Server.ContextMenus; +using Server.Guilds; using Server.Gumps; +using Server.HuePickers; using Server.Items; using Server.Menus; +using Server.Mobiles; using Server.Network; +using Server.Prompts; using Server.Targeting; namespace Server @@ -61,10 +62,15 @@ namespace Server } public TimedSkillMod(SkillName skill, bool relative, double value, DateTime expire) - : base(skill, relative, value) => + : base(skill, relative, value) + { m_Expire = expire; + } - public override bool CheckCondition() => DateTime.UtcNow < m_Expire; + public override bool CheckCondition() + { + return DateTime.UtcNow < m_Expire; + } } public class EquippedSkillMod : SkillMod @@ -79,7 +85,10 @@ namespace Server m_Mobile = mobile; } - public override bool CheckCondition() => !m_Item.Deleted && !m_Mobile.Deleted && m_Item.Parent == m_Mobile; + public override bool CheckCondition() + { + return !m_Item.Deleted && !m_Mobile.Deleted && m_Item.Parent == m_Mobile; + } } public class DefaultSkillMod : SkillMod @@ -89,7 +98,10 @@ namespace Server { } - public override bool CheckCondition() => true; + public override bool CheckCondition() + { + return true; + } } public abstract class SkillMod @@ -269,14 +281,23 @@ namespace Server public int Offset{ get; } - public bool HasElapsed() => m_Duration != TimeSpan.Zero && DateTime.UtcNow - m_Added >= m_Duration; + public bool HasElapsed() + { + if (m_Duration == TimeSpan.Zero) + return false; + + return DateTime.UtcNow - m_Added >= m_Duration; + } } #endregion public class DamageEntry { - public DamageEntry(Mobile damager) => Damager = damager; + public DamageEntry(Mobile damager) + { + Damager = damager; + } public Mobile Damager{ get; } @@ -402,8 +423,10 @@ namespace Server public class MobileNotConnectedException : Exception { public MobileNotConnectedException(Mobile source, string message) - : base(message) => + : base(message) + { Source = source.ToString(); + } } #region Delegates @@ -433,7 +456,7 @@ namespace Server /// /// Base class representing players, npcs, and creatures. /// - public class Mobile : IHued, IComparable, ISerializable, ISpawnable + public class Mobile : IHued, IComparable, ISerializable, ISpawnable, IPropertyListObject { private const int WarmodeCatchCount = 4; // Allow four warmode changes in 0.5 seconds, any more will be delay for two seconds @@ -478,8 +501,8 @@ namespace Server 198 }; - private static ConcurrentQueue m_DeltaQueue = new ConcurrentQueue(); - private static ConcurrentQueue m_DeltaQueueR = new ConcurrentQueue(); + private static Queue m_DeltaQueue = new Queue(); + private static Queue m_DeltaQueueR = new Queue(); private static bool _processing; @@ -582,7 +605,7 @@ namespace Server [CommandProperty(AccessLevel.GameMaster)] public Race Race { - get => m_Race ??= Race.DefaultRace; + get => m_Race ?? (m_Race = Race.DefaultRace); set { Race oldRace = Race; @@ -733,7 +756,9 @@ namespace Server if (m_Holding != null) { UpdateTotal(m_Holding, TotalType.Weight, m_Holding.TotalWeight + m_Holding.PileWeight); - m_Holding.HeldBy ??= this; + + if (m_Holding.HeldBy == null) + m_Holding.HeldBy = this; } } } @@ -801,7 +826,8 @@ namespace Server if (m_StrLock != value) { m_StrLock = value; - Packets.SendStatLockInfo(m_NetState, this); + + m_NetState?.Send(new StatLockInfo(this)); } } } @@ -818,7 +844,8 @@ namespace Server if (m_DexLock != value) { m_DexLock = value; - Packets.SendStatLockInfo(m_NetState, this); + + m_NetState?.Send(new StatLockInfo(this)); } } } @@ -835,7 +862,8 @@ namespace Server if (m_IntLock != value) { m_IntLock = value; - Packets.SendStatLockInfo(m_NetState, this); + + m_NetState?.Send(new StatLockInfo(this)); } } } @@ -890,7 +918,7 @@ namespace Server return; } - Packets.SendChangeCombatant(m_NetState, m_Combatant?.Serial ?? Serial.Zero); + m_NetState?.Send(new ChangeCombatant(m_Combatant)); if (m_Combatant == null) { @@ -903,10 +931,14 @@ namespace Server } else { - m_ExpireCombatant ??= new ExpireCombatantTimer(this); + if (m_ExpireCombatant == null) + m_ExpireCombatant = new ExpireCombatantTimer(this); + m_ExpireCombatant.Start(); - m_CombatTimer ??= new CombatTimer(this); + if (m_CombatTimer == null) + m_CombatTimer = new CombatTimer(this); + m_CombatTimer.Start(); } @@ -997,8 +1029,8 @@ namespace Server m_Target = newTarget; - if (!TargetLocked) - Packets.SendTargetReq(m_NetState, newTarget); + if (newTarget != null && m_NetState != null && !TargetLocked) + m_NetState.Send(newTarget.GetPacketFor(m_NetState)); OnTargetChange(); } @@ -1015,9 +1047,9 @@ namespace Server { // Old packet is preferred until assistants catch up if (m_NetState.NewHaven && m_ContextMenu.RequiresNewPacket) - Packets.SendDisplayContextMenu(m_NetState, m_ContextMenu); + Send(new DisplayContextMenu(m_ContextMenu)); else - Packets.SendDisplayContextMenuOld(m_NetState, m_ContextMenu); + Send(new DisplayContextMenuOld(m_ContextMenu)); } } } @@ -1036,7 +1068,7 @@ namespace Server public static bool FwdEnabled{ get; set; } = true; - public static bool FwdUOTDOverride{ get; set; } + public static bool FwdUOTDOverride{ get; set; } = false; public static int FwdMaxSteps{ get; set; } = 4; @@ -1092,7 +1124,7 @@ namespace Server [CommandProperty(AccessLevel.GameMaster)] public Container Corpse{ get; set; } - public static char[] GhostChars{ get; set; } = { 'o', 'O' }; + public static char[] GhostChars{ get; set; } = new char[2] { 'o', 'O' }; public static bool NoSpeechLOS{ get; set; } @@ -1109,12 +1141,20 @@ namespace Server [CommandProperty(AccessLevel.GameMaster)] public Mobile LastKiller{ get; set; } - public static bool DefaultShowVisibleDamage { get; set; } + public static bool DefaultShowVisibleDamage + { + get => m_DefaultShowVisibleDamage; + set => m_DefaultShowVisibleDamage = value; + } - public static bool DefaultCanSeeVisibleDamage { get; set; } + public static bool DefaultCanSeeVisibleDamage + { + get => m_DefaultCanSeeVisibleDamage; + set => m_DefaultCanSeeVisibleDamage = value; + } - public virtual bool ShowVisibleDamage => DefaultShowVisibleDamage; - public virtual bool CanSeeVisibleDamage => DefaultCanSeeVisibleDamage; + public virtual bool ShowVisibleDamage => m_DefaultShowVisibleDamage; + public virtual bool CanSeeVisibleDamage => m_DefaultCanSeeVisibleDamage; [CommandProperty(AccessLevel.GameMaster)] public bool Squelched{ get; set; } @@ -1367,7 +1407,8 @@ namespace Server m_Warmode = value; Delta(MobileDelta.Flags); - Packets.SendSetWarMode(m_NetState, m_Warmode); + if (m_NetState != null) + Send(SetWarMode.Instantiate(value)); if (!m_Warmode) Combatant = null; @@ -1496,7 +1537,11 @@ namespace Server public string Language { get => m_Language; - set => m_Language = value; + set + { + if (m_Language != value) + m_Language = value; + } } [CommandProperty(AccessLevel.GameMaster)] @@ -1723,22 +1768,9 @@ namespace Server public Region Region => m_Region ?? (Map == null ? Map.Internal.DefaultRegion : Map.DefaultRegion); - private ObjectPropertyList m_PropertyList; - - public ObjectPropertyList PropertyList - { - get - { - if (m_PropertyList == null) - { - // TODO: Object Pool OPL - m_PropertyList = new ObjectPropertyList(this); - GetProperties(m_PropertyList); - } - - return m_PropertyList; - } - } + public Packet RemovePacket => StaticPacketHandlers.GetRemoveEntityPacket(this); + public OPLInfo OPLPacket => StaticPacketHandlers.GetOPLInfoPacket(this); + public ObjectPropertyList PropertyList => StaticPacketHandlers.GetOPLPacket(this); [CommandProperty(AccessLevel.GameMaster)] public int SolidHueOverride @@ -1779,8 +1811,10 @@ namespace Server if (m_BankBox?.Deleted == false && m_BankBox.Parent == this) return m_BankBox; - m_BankBox = FindItemOnLayer(Layer.Bank) as BankBox ?? new BankBox(this); - AddItem(m_BankBox); + m_BankBox = FindItemOnLayer(Layer.Bank) as BankBox; + + if (m_BankBox == null) + AddItem(m_BankBox = new BankBox(this)); return m_BankBox; } @@ -1802,7 +1836,13 @@ namespace Server public bool HasTrade { - get => m_NetState?.Trades.Count > 0; + get + { + if (m_NetState != null) + return m_NetState.Trades.Count > 0; + + return false; + } } public bool NoMoveHS{ get; set; } @@ -1893,7 +1933,8 @@ namespace Server if (m_MountItem?.Deleted == false && m_MountItem.Parent == this) item = m_MountItem; - item ??= FindItemOnLayer(Layer.Mount); + if (item == null) + item = FindItemOnLayer(Layer.Mount); if (!(item is IMountItem mountItem)) return null; @@ -1923,7 +1964,7 @@ namespace Server public virtual bool CanTarget => true; public virtual bool ClickTitle => true; - public virtual bool PropertyTitle => !OldPropertyTitles || ClickTitle; + public virtual bool PropertyTitle => OldPropertyTitles ? ClickTitle : true; public static bool DisableHiddenSelfClick{ get; set; } = true; @@ -1979,7 +2020,10 @@ namespace Server public virtual void Delete() { - if (Deleted || !World.OnDelete(this)) + if (Deleted) + return; + + if (!World.OnDelete(this)) return; if (m_NetState != null) @@ -2023,7 +2067,7 @@ namespace Server OnAfterDelete(); - ClearProperties(); + FreeCache(); } [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] @@ -2063,10 +2107,14 @@ namespace Server if (ns != null && m_Map != null) { ns.Sequence = 0; - Packets.SendMapChange(ns, m_Map); - Packets.SendMapPatches(ns); - Packets.SendSeasonChange(ns, GetSeason(), 1); - Packets.SendMobileUpdate(ns, this); + ns.Send(new MapChange(this)); + ns.Send(new MapPatches()); + ns.Send(SeasonChange.Instantiate(GetSeason(), true)); + + if (ns.StygianAbyss) + ns.Send(new MobileUpdate(this)); + else + ns.Send(new MobileUpdateOld(this)); ClearFastwalkStack(); } @@ -2074,15 +2122,25 @@ namespace Server if (ns != null) { if (m_Map != null) - Packets.SendServerChange(ns, this, m_Map); + ns.Send(new ServerChange(this, m_Map)); ns.Sequence = 0; ClearFastwalkStack(); - Packets.SendMobileIncoming(ns, this, this); - Packets.SendMobileUpdate(ns, this); - CheckLightLevels(true); - Packets.SendMobileUpdate(ns, this); + ns.Send(MobileIncoming.Create(ns, this, this)); + + if (ns.StygianAbyss) + { + ns.Send(new MobileUpdate(this)); + CheckLightLevels(true); + ns.Send(new MobileUpdate(this)); + } + else + { + ns.Send(new MobileUpdateOld(this)); + CheckLightLevels(true); + ns.Send(new MobileUpdateOld(this)); + } } SendEverything(); @@ -2093,10 +2151,20 @@ namespace Server ns.Sequence = 0; ClearFastwalkStack(); - Packets.SendMobileIncoming(ns, this, this); - Packets.SendSupportedFeatures(ns); - Packets.SendMobileUpdate(ns, this); - Packets.SendMobileAttributes(ns, this); + ns.Send(MobileIncoming.Create(ns, this, this)); + + if (ns.StygianAbyss) + { + ns.Send(SupportedFeatures.Instantiate(ns)); + ns.Send(new MobileUpdate(this)); + ns.Send(new MobileAttributes(this)); + } + else + { + ns.Send(SupportedFeatures.Instantiate(ns)); + ns.Send(new MobileUpdateOld(this)); + ns.Send(new MobileAttributes(this)); + } } OnMapChange(oldMap); @@ -2161,10 +2229,14 @@ namespace Server if (ns != null && m_Map != null) { ns.Sequence = 0; - Packets.SendMapChange(ns, m_Map); - Packets.SendMapPatches(ns); - Packets.SendSeasonChange(ns, GetSeason(), 1); - Packets.SendMobileUpdate(ns, this); + ns.Send(new MapChange(this)); + ns.Send(new MapPatches()); + ns.Send(SeasonChange.Instantiate(GetSeason(), true)); + + if (ns.StygianAbyss) + ns.Send(new MobileUpdate(this)); + else + ns.Send(new MobileUpdateOld(this)); ClearFastwalkStack(); } @@ -2177,15 +2249,25 @@ namespace Server if (ns != null) { if (m_Map != null) - Packets.SendServerChange(ns, this, m_Map); + Send(new ServerChange(this, m_Map)); ns.Sequence = 0; ClearFastwalkStack(); - Packets.SendMobileIncoming(ns, this, this); - Packets.SendMobileUpdate(ns, this); - CheckLightLevels(true); - Packets.SendMobileUpdate(ns, this); + ns.Send(MobileIncoming.Create(ns, this, this)); + + if (ns.StygianAbyss) + { + ns.Send(new MobileUpdate(this)); + CheckLightLevels(true); + ns.Send(new MobileUpdate(this)); + } + else + { + ns.Send(new MobileUpdateOld(this)); + CheckLightLevels(true); + ns.Send(new MobileUpdateOld(this)); + } } SendEverything(); @@ -2196,10 +2278,20 @@ namespace Server ns.Sequence = 0; ClearFastwalkStack(); - Packets.SendMobileIncoming(ns, this, this); - Packets.SendSupportedFeatures(ns); - Packets.SendMobileUpdate(ns, this); - Packets.SendMobileUpdate(ns, this); + ns.Send(MobileIncoming.Create(ns, this, this)); + + if (ns.StygianAbyss) + { + ns.Send(SupportedFeatures.Instantiate(ns)); + ns.Send(new MobileUpdate(this)); + ns.Send(new MobileAttributes(this)); + } + else + { + ns.Send(SupportedFeatures.Instantiate(ns)); + ns.Send(new MobileUpdateOld(this)); + ns.Send(new MobileAttributes(this)); + } } OnMapChange(oldMap); @@ -2258,7 +2350,9 @@ namespace Server sendAny = true; if (attrs == MobileDelta.Attributes) + { sendAll = true; + } else { sendHits = (attrs & MobileDelta.Hits) != 0; @@ -2267,7 +2361,7 @@ namespace Server } } - sendNonlocalIncoming |= (delta & MobileDelta.GhostUpdate) != 0; + if ((delta & MobileDelta.GhostUpdate) != 0) sendNonlocalIncoming = true; if ((delta & MobileDelta.Hue) != 0) { @@ -2299,11 +2393,11 @@ namespace Server sendUpdate = true; } else*/ - sendMoving |= (delta & (MobileDelta.Flags | MobileDelta.Noto)) != 0; + if ((delta & (MobileDelta.Flags | MobileDelta.Noto)) != 0) sendMoving = true; - sendHealthbarPoison |= (delta & MobileDelta.HealthbarPoison) != 0; + if ((delta & MobileDelta.HealthbarPoison) != 0) sendHealthbarPoison = true; - sendHealthbarYellow |= (delta & MobileDelta.HealthbarYellow) != 0; + if ((delta & MobileDelta.HealthbarYellow) != 0) sendHealthbarYellow = true; if ((delta & MobileDelta.Name) != 0) { @@ -2313,17 +2407,24 @@ namespace Server sendPublicStats = true; } - sendPrivateStats |= (delta & (MobileDelta.WeaponDamage | MobileDelta.Resistances | MobileDelta.Stat | MobileDelta.Weight | MobileDelta.Gold | MobileDelta.Armor | MobileDelta.StatCap | MobileDelta.Followers | MobileDelta.TithingPoints | MobileDelta.Race)) != 0; + if ((delta & (MobileDelta.WeaponDamage | MobileDelta.Resistances | MobileDelta.Stat | + MobileDelta.Weight | MobileDelta.Gold | MobileDelta.Armor | MobileDelta.StatCap | + MobileDelta.Followers | MobileDelta.TithingPoints | MobileDelta.Race)) != 0) + sendPrivateStats = true; if ((delta & MobileDelta.Hair) != 0) { - removeHair |= m.HairItemID <= 0; + if (m.HairItemID <= 0) + removeHair = true; + sendHair = true; } if ((delta & MobileDelta.FacialHair) != 0) { - removeFacialHair |= m.FacialHairItemID <= 0; + if (m.FacialHairItemID <= 0) + removeFacialHair = true; + sendFacialHair = true; } @@ -2337,42 +2438,58 @@ namespace Server { ourState.Sequence = 0; - Packets.SendMobileUpdate(ourState, m); + if (ourState.StygianAbyss) + ourState.Send(new MobileUpdate(m)); + else + ourState.Send(new MobileUpdateOld(m)); ClearFastwalkStack(); } if (sendIncoming) - Packets.SendMobileIncoming(ourState, m, m); + ourState.Send(MobileIncoming.Create(ourState, m, m)); if (ourState.StygianAbyss) { if (sendMoving) - Packets.SendMobileMoving(ourState, m, Notoriety.Compute(m, m)); + { + int noto = Notoriety.Compute(m, m); + ourState.Send(cache[0][noto] = Packet.Acquire(new MobileMoving(m, noto))); + } if (sendHealthbarPoison) - Packets.SendHealthbarPoison(ourState, m); + ourState.Send(new HealthbarPoison(m)); if (sendHealthbarYellow) - Packets.SendHealthbarYellow(ourState, m); + ourState.Send(new HealthbarYellow(m)); + } + else + { + if (sendMoving || sendHealthbarPoison || sendHealthbarYellow) + { + int noto = Notoriety.Compute(m, m); + ourState.Send(cache[1][noto] = Packet.Acquire(new MobileMovingOld(m, noto))); + } } - else if (sendMoving || sendHealthbarPoison || sendHealthbarYellow) - Packets.SendMobileMovingOld(ourState, m, Notoriety.Compute(m, m)); if (sendPublicStats || sendPrivateStats) - Packets.SendMobileStatusExtended(ourState, m); + { + ourState.Send(new MobileStatusExtended(m, m_NetState)); + } else if (sendAll) - Packets.SendMobileAttributes(ourState, m); + { + ourState.Send(new MobileAttributes(m)); + } else if (sendAny) { if (sendHits) - Packets.SendMobileHits(ourState, m); + ourState.Send(new MobileHits(m)); if (sendStam) - Packets.SendMobileStam(ourState, m); + ourState.Send(new MobileStam(m)); if (sendMana) - Packets.SendMobileMana(ourState, m); + ourState.Send(new MobileMana(m)); } if (sendStam || sendMana) @@ -2388,21 +2505,21 @@ namespace Server if (sendHair) { if (removeHair) - Packets.SendRemoveHair(ourState, m); + ourState.Send(new RemoveHair(m)); else - Packets.SendHairEquipUpdate(ourState, m); + ourState.Send(new HairEquipUpdate(m)); } if (sendFacialHair) { if (removeFacialHair) - Packets.SendRemoveFacialHair(ourState, m); + ourState.Send(new RemoveFacialHair(m)); else - Packets.SendFacialHairEquipUpdate(ourState, m); + ourState.Send(new FacialHairEquipUpdate(m)); } if (sendOPLUpdate) - PropertyList.Send(ourState); + ourState.Send(OPLPacket); } sendMoving = sendMoving || sendNonlocalMoving; @@ -2413,67 +2530,158 @@ namespace Server sendOPLUpdate || sendHair || sendFacialHair || sendHealthbarPoison || sendHealthbarYellow)) { + Mobile beholder; + + Packet hitsPacket = null; + Packet statPacketTrue = null; + Packet statPacketFalse = null; + Packet deadPacket = null; + Packet hairPacket = null; + Packet facialhairPacket = null; + Packet hbpPacket = null; + Packet hbyPacket = null; + IPooledEnumerable eable = m.Map.GetClientsInRange(m.m_Location); foreach (NetState state in eable) { - var beholder = state.Mobile; + beholder = state.Mobile; if (beholder != m && beholder.CanSee(m)) { if (sendRemove) - Packets.SendRemoveEntity(state, Serial); + state.Send(RemovePacket); if (sendIncoming) { - Packets.SendMobileIncoming(state, beholder, m); + state.Send(MobileIncoming.Create(state, beholder, m)); if (m.IsDeadBondedPet) - Packets.SendBondStatus(state, m.Serial, true); + { + if (deadPacket == null) + deadPacket = Packet.Acquire(new BondedStatus(0, m.Serial, 1)); + + state.Send(deadPacket); + } } if (state.StygianAbyss) { if (sendMoving) - Packets.SendMobileMoving(state, m, Notoriety.Compute(beholder, m)); + { + int noto = Notoriety.Compute(beholder, m); + + Packet p = cache[0][noto]; + + if (p == null) + cache[0][noto] = p = Packet.Acquire(new MobileMoving(m, noto)); + + state.Send(p); + } if (sendHealthbarPoison) - Packets.SendHealthbarPoison(state, m); + { + if (hbpPacket == null) + hbpPacket = Packet.Acquire(new HealthbarPoison(m)); + + state.Send(hbpPacket); + } if (sendHealthbarYellow) - Packets.SendHealthbarYellow(state, m); + { + if (hbyPacket == null) + hbyPacket = Packet.Acquire(new HealthbarYellow(m)); + + state.Send(hbyPacket); + } + } + else + { + if (sendMoving || sendHealthbarPoison || sendHealthbarYellow) + { + int noto = Notoriety.Compute(beholder, m); + + Packet p = cache[1][noto]; + + if (p == null) + cache[1][noto] = p = Packet.Acquire(new MobileMovingOld(m, noto)); + + state.Send(p); + } } - else if (sendMoving || sendHealthbarPoison || sendHealthbarYellow) - Packets.SendMobileMovingOld(state, m, Notoriety.Compute(beholder, m)); if (sendPublicStats) - Packets.SendMobileStatusCompact(state, m, m.CanBeRenamedBy(beholder)); + { + if (m.CanBeRenamedBy(beholder)) + { + if (statPacketTrue == null) + statPacketTrue = Packet.Acquire(new MobileStatusCompact(true, m)); + + state.Send(statPacketTrue); + } + else + { + if (statPacketFalse == null) + statPacketFalse = Packet.Acquire(new MobileStatusCompact(false, m)); + + state.Send(statPacketFalse); + } + } else if (sendHits) - Packets.SendNormalizedMobileHits(state, m); + { + if (hitsPacket == null) + hitsPacket = Packet.Acquire(new MobileHitsN(m)); + + state.Send(hitsPacket); + } if (sendHair) { - if (removeHair) - Packets.SendRemoveHair(state, m); - else - Packets.SendHairEquipUpdate(state, m); + if (hairPacket == null) + { + if (removeHair) + hairPacket = Packet.Acquire(new RemoveHair(m)); + else + hairPacket = Packet.Acquire(new HairEquipUpdate(m)); + } + + state.Send(hairPacket); } if (sendFacialHair) { - if (removeFacialHair) - Packets.SendRemoveFacialHair(state, m); - else - Packets.SendFacialHairEquipUpdate(state, m); + if (facialhairPacket == null) + { + if (removeFacialHair) + facialhairPacket = Packet.Acquire(new RemoveFacialHair(m)); + else + facialhairPacket = Packet.Acquire(new FacialHairEquipUpdate(m)); + } + + state.Send(facialhairPacket); } if (sendOPLUpdate) - PropertyList.Send(state); + state.Send(OPLPacket); } } + Packet.Release(hitsPacket); + Packet.Release(statPacketTrue); + Packet.Release(statPacketFalse); + Packet.Release(deadPacket); + Packet.Release(hairPacket); + Packet.Release(facialhairPacket); + Packet.Release(hbpPacket); + Packet.Release(hbyPacket); + eable.Free(); } + + if (sendMoving || sendNonlocalMoving || sendHealthbarPoison || sendHealthbarYellow) + for (int i = 0; i < cache.Length; ++i) + for (int j = 0; j < cache[i].Length; ++j) + Packet.Release(ref cache[i][j]); } public virtual int HuedItemID => m_Female ? 0x2107 : 0x2106; @@ -2567,7 +2775,7 @@ namespace Server writer.Write(EmoteHue); writer.Write(WhisperHue); writer.Write(YellHue); - writer.Write(Language); + writer.Write(m_Language); writer.Write(m_Female); writer.Write(m_Warmode); writer.Write(m_Hidden); @@ -2637,7 +2845,8 @@ namespace Server public virtual void UpdateResistances() { - Resistances ??= new[] { int.MinValue, int.MinValue, int.MinValue, int.MinValue, int.MinValue }; + if (Resistances == null) + Resistances = new int[5] { int.MinValue, int.MinValue, int.MinValue, int.MinValue, int.MinValue }; bool delta = false; @@ -2654,7 +2863,8 @@ namespace Server public virtual int GetResistance(ResistanceType type) { - Resistances ??= new[] { int.MinValue, int.MinValue, int.MinValue, int.MinValue, int.MinValue }; + if (Resistances == null) + Resistances = new int[5] { int.MinValue, int.MinValue, int.MinValue, int.MinValue, int.MinValue }; int v = (int)type; @@ -2674,7 +2884,8 @@ namespace Server public virtual void AddResistanceMod(ResistanceMod toAdd) { - ResistanceMods ??= new List(); + if (ResistanceMods == null) ResistanceMods = new List(); + ResistanceMods.Add(toAdd); UpdateResistances(); } @@ -2694,7 +2905,8 @@ namespace Server public virtual void ComputeResistances() { - Resistances ??= new[] { int.MinValue, int.MinValue, int.MinValue, int.MinValue, int.MinValue }; + if (Resistances == null) + Resistances = new int[] { int.MinValue, int.MinValue, int.MinValue, int.MinValue, int.MinValue }; for (int i = 0; i < Resistances.Length; ++i) Resistances[i] = 0; @@ -2743,37 +2955,49 @@ namespace Server } } - public virtual int GetMinResistance(ResistanceType type) => int.MinValue; + public virtual int GetMinResistance(ResistanceType type) + { + return int.MinValue; + } - public virtual int GetMaxResistance(ResistanceType type) => m_Player ? MaxPlayerResistance : int.MaxValue; + public virtual int GetMaxResistance(ResistanceType type) + { + return m_Player ? MaxPlayerResistance : int.MaxValue; + } - public int GetAOSStatus(int index) => AOSStatusHandler?.Invoke(this, index) ?? 0; + public int GetAOSStatus(int index) + { + return AOSStatusHandler?.Invoke(this, index) ?? 0; + } public virtual void SendPropertiesTo(Mobile from) { - PropertyList.Send(from.NetState); + from.Send(PropertyList); } public virtual void OnAosSingleClick(Mobile from) { ObjectPropertyList opl = PropertyList; - if (opl.Header <= 0) - return; + if (opl.Header > 0) + { + int hue; - int hue; + if (NameHue != -1) + hue = NameHue; + else if (m_AccessLevel > AccessLevel.Player) + hue = 11; + else + hue = Notoriety.GetHue(Notoriety.Compute(from, this)); - if (NameHue != -1) - hue = NameHue; - else if (m_AccessLevel > AccessLevel.Player) - hue = 11; - else - hue = Notoriety.GetHue(Notoriety.Compute(from, this)); - - Packets.SendMessageLocalized(from.NetState, Serial, Body, MessageType.Label, hue, 3, opl.Header, Name, opl.HeaderArgs); + from.Send(new MessageLocalized(Serial, Body, MessageType.Label, hue, 3, opl.Header, Name, opl.HeaderArgs)); + } } - public virtual string ApplyNameSuffix(string suffix) => suffix; + public virtual string ApplyNameSuffix(string suffix) + { + return suffix; + } public virtual void AddNameProperties(ObjectPropertyList list) { @@ -2784,13 +3008,18 @@ namespace Server if (ShowFameTitle && (m_Player || m_Body.IsHuman) && m_Fame >= 10000) prefix = m_Female ? "Lady" : "Lord"; - string suffix = PropertyTitle && !string.IsNullOrEmpty(Title) ? Title : ""; + string suffix = ""; + + if (PropertyTitle && !string.IsNullOrEmpty(Title)) + suffix = Title; BaseGuild guild = m_Guild; if (guild != null && (m_Player || m_DisplayGuildTitle)) + { suffix = suffix.Length > 0 ? $"{suffix} [{Utility.FixHtml(guild.Abbreviation)}]" : $"[{Utility.FixHtml(guild.Abbreviation)}]"; + } suffix = ApplyNameSuffix(suffix); @@ -2808,7 +3037,9 @@ namespace Server string title = GuildTitle?.Trim() ?? ""; if (NewGuildDisplay && title.Length > 0) + { list.Add("{0}, {1}", Utility.FixHtml(title), Utility.FixHtml(guild.Name)); + } else { if (title.Length > 0) @@ -2835,7 +3066,9 @@ namespace Server private void UpdateAggrExpire() { if (Deleted || Aggressors.Count == 0 && Aggressed.Count == 0) + { StopAggrExpire(); + } else if (m_ExpireAggrTimer == null) { m_ExpireAggrTimer = new ExpireAggressorsTimer(this); @@ -2868,7 +3101,7 @@ namespace Server info.Free(); if (m_NetState != null && CanSee(attacker) && Utility.InUpdateRange(m_Location, attacker.m_Location)) - Packets.SendMobileIncoming(m_NetState, this, attacker); + m_NetState.Send(MobileIncoming.Create(m_NetState, this, attacker)); } } @@ -2888,7 +3121,7 @@ namespace Server info.Free(); if (m_NetState != null && CanSee(defender) && Utility.InUpdateRange(m_Location, defender.m_Location)) - Packets.SendMobileIncoming(m_NetState, this, defender); + m_NetState.Send(MobileIncoming.Create(m_NetState, this, defender)); } } @@ -3000,23 +3233,44 @@ namespace Server return; } else + { ++m_WarmodeChanges; + } Warmode = value; } - public bool InLOS(Mobile target) => - !Deleted && m_Map != null && - (target == this || m_AccessLevel > AccessLevel.Player || m_Map.LineOfSight(this, target)); + public bool InLOS(Mobile target) + { + if (Deleted || m_Map == null) + return false; + if (target == this || m_AccessLevel > AccessLevel.Player) + return true; - public bool InLOS(object target) => - !Deleted && m_Map != null && - (target == this || m_AccessLevel > AccessLevel.Player || target is Item item && item.RootParent == this || m_Map.LineOfSight(this, target)); + return m_Map.LineOfSight(this, target); + } - public bool InLOS(Point3D target) => - !Deleted && m_Map != null && (m_AccessLevel > AccessLevel.Player || m_Map.LineOfSight(this, target)); + public bool InLOS(object target) + { + if (Deleted || m_Map == null) + return false; + if (target == this || m_AccessLevel > AccessLevel.Player) + return true; + if (target is Item item && item.RootParent == this) + return true; - public bool BeginAction() => BeginAction(typeof(T)); + return m_Map.LineOfSight(this, target); + } + + public bool InLOS(Point3D target) + { + return !Deleted && m_Map != null && (m_AccessLevel > AccessLevel.Player || m_Map.LineOfSight(this, target)); + } + + public bool BeginAction() + { + return BeginAction(typeof(T)); + } public bool BeginAction(object toLock) { @@ -3035,11 +3289,20 @@ namespace Server return false; } - public bool CanBeginAction() => CanBeginAction(typeof(T)); + public bool CanBeginAction() + { + return CanBeginAction(typeof(T)); + } - public bool CanBeginAction(object toLock) => _actions?.Contains(toLock) != true; + public bool CanBeginAction(object toLock) + { + return _actions == null || !_actions.Contains(toLock); + } - public void EndAction() => EndAction(typeof(T)); + public void EndAction() + { + EndAction(typeof(T)); + } public void EndAction(object toLock) { @@ -3051,7 +3314,10 @@ namespace Server } } - public virtual TimeSpan GetLogoutDelay() => Region.GetLogoutDelay(this); + public virtual TimeSpan GetLogoutDelay() + { + return Region.GetLogoutDelay(this); + } public void Paralyze(TimeSpan duration) { @@ -3075,7 +3341,10 @@ namespace Server } } - public override string ToString() => $"0x{Serial.Value:X} \"{Name}\""; + public override string ToString() + { + return $"0x{Serial.Value:X} \"{Name}\""; + } public virtual void SendSkillMessage() { @@ -3122,7 +3391,10 @@ namespace Server Combatant = m; } - public virtual bool CheckAttack(Mobile m) => Utility.InUpdateRange(this, m) && CanSee(m) && InLOS(m); + public virtual bool CheckAttack(Mobile m) + { + return Utility.InUpdateRange(this, m) && CanSee(m) && InLOS(m); + } /// /// Overridable. Virtual event invoked after the property has changed. @@ -3253,10 +3525,10 @@ namespace Server Aggressors.Add(AggressorInfo.Create(aggressor, this, criminal)); // new AggressorInfo( aggressor, this, criminal, true ) ); - if (CanSee(aggressor)) - Packets.SendMobileIncoming(m_NetState, this, aggressor); + if (CanSee(aggressor)) m_NetState?.Send(MobileIncoming.Create(m_NetState, this, aggressor)); - setCombatant |= Combatant == null; + if (Combatant == null) + setCombatant = true; UpdateAggrExpire(); } @@ -3266,10 +3538,10 @@ namespace Server aggressor.Aggressed.Add(AggressorInfo.Create(aggressor, this, criminal)); // new AggressorInfo( aggressor, this, criminal, false ) ); - if (CanSee(aggressor)) - Packets.SendMobileIncoming(m_NetState, this, aggressor); + if (CanSee(aggressor)) m_NetState?.Send(MobileIncoming.Create(m_NetState, this, aggressor)); - setCombatant |= Combatant == null; + if (Combatant == null) + setCombatant = true; UpdateAggrExpire(); } @@ -3296,8 +3568,8 @@ namespace Server Aggressed.RemoveAt(i); info.Free(); - if (CanSee(aggressed)) - Packets.SendMobileIncoming(m_NetState, this, aggressed); + if (m_NetState != null && CanSee(aggressed)) + m_NetState.Send(MobileIncoming.Create(m_NetState, this, aggressed)); break; } @@ -3322,8 +3594,8 @@ namespace Server Aggressors.RemoveAt(i); info.Free(); - if (CanSee(aggressor)) - Packets.SendMobileIncoming(m_NetState, this, aggressor); + if (m_NetState != null && CanSee(aggressor)) + m_NetState.Send(MobileIncoming.Create(m_NetState, this, aggressor)); break; } @@ -3332,14 +3604,22 @@ namespace Server UpdateAggrExpire(); } - public virtual int GetTotal(TotalType type) => - type switch + public virtual int GetTotal(TotalType type) + { + switch (type) { - TotalType.Gold => m_TotalGold, - TotalType.Items => m_TotalItems, - TotalType.Weight => m_TotalWeight, - _ => 0 - }; + case TotalType.Gold: + return m_TotalGold; + + case TotalType.Items: + return m_TotalItems; + + case TotalType.Weight: + return m_TotalWeight; + } + + return 0; + } public virtual void UpdateTotal(Item sender, TotalType type, int delta) { @@ -3402,13 +3682,21 @@ namespace Server m_QuestArrow = null; } - public void ClearTarget() => m_Target = null; + public void ClearTarget() + { + m_Target = null; + } - public Target BeginTarget(int range, bool allowGround, TargetFlags flags, TargetCallback callback) => - Target = new SimpleTarget(range, flags, allowGround, callback); + public Target BeginTarget(int range, bool allowGround, TargetFlags flags, TargetCallback callback) + { + return Target = new SimpleTarget(range, flags, allowGround, callback); + } public Target BeginTarget(int range, bool allowGround, TargetFlags flags, TargetStateCallback callback, - T state) => Target = new SimpleStateTarget(range, flags, allowGround, callback, state); + T state) + { + return Target = new SimpleStateTarget(range, flags, allowGround, callback, state); + } /// /// Overridable. Virtual event invoked after the Target property has changed. @@ -3417,7 +3705,10 @@ namespace Server { } - public virtual bool CheckContextMenuDisplay(IEntity target) => true; + public virtual bool CheckContextMenuDisplay(IEntity target) + { + return true; + } private bool InternalOnMove(Direction d) { @@ -3450,13 +3741,16 @@ namespace Server public virtual void ClearFastwalkStack() { - if (m_MoveRecords?.Count > 0) + if (m_MoveRecords != null && m_MoveRecords.Count > 0) m_MoveRecords.Clear(); m_EndQueue = Core.TickCount; } - public virtual bool CheckMovement(Direction d, out int newZ) => Movement.CheckMovement(this, d, out newZ); + public virtual bool CheckMovement(Direction d, out int newZ) + { + return Movement.Movement.CheckMovement(this, d, out newZ); + } public virtual bool Move(Direction d) { @@ -3538,21 +3832,42 @@ namespace Server if (oldSector != newSector) { - if (oldSector.Mobiles.Any( - m => m != this && m.X == oldX && m.Y == oldY && m.Z + 15 > oldZ && oldZ + 15 > m.Z && !m.OnMoveOff(this))) - return false; + for (int i = 0; i < oldSector.Mobiles.Count; ++i) + { + Mobile m = oldSector.Mobiles[i]; - if (oldSector.Items.Any(item => item.AtWorldPoint(oldX, oldY) && - (item.Z == oldZ || item.Z + item.ItemData.Height > oldZ && oldZ + 15 > item.Z) && - !item.OnMoveOff(this))) - return false; + if (m != this && m.X == oldX && m.Y == oldY && m.Z + 15 > oldZ && oldZ + 15 > m.Z && + !m.OnMoveOff(this)) + return false; + } - if (newSector.Mobiles.Any(m => m.X == x && m.Y == y && m.Z + 15 > newZ && newZ + 15 > m.Z && !m.OnMoveOver(this))) return false; + for (int i = 0; i < oldSector.Items.Count; ++i) + { + Item item = oldSector.Items[i]; - if (newSector.Items.Any(item => item.AtWorldPoint(x, y) && - (item.Z == newZ || item.Z + item.ItemData.Height > newZ && newZ + 15 > item.Z) && - !item.OnMoveOver(this))) - return false; + if (item.AtWorldPoint(oldX, oldY) && + (item.Z == oldZ || item.Z + item.ItemData.Height > oldZ && oldZ + 15 > item.Z) && + !item.OnMoveOff(this)) + return false; + } + + for (int i = 0; i < newSector.Mobiles.Count; ++i) + { + Mobile m = newSector.Mobiles[i]; + + if (m.X == x && m.Y == y && m.Z + 15 > newZ && newZ + 15 > m.Z && !m.OnMoveOver(this)) + return false; + } + + for (int i = 0; i < newSector.Items.Count; ++i) + { + Item item = newSector.Items[i]; + + if (item.AtWorldPoint(x, y) && + (item.Z == newZ || item.Z + item.ItemData.Height > newZ && newZ + 15 > item.Z) && + !item.OnMoveOver(this)) + return false; + } } else { @@ -3586,7 +3901,9 @@ namespace Server return false; } else + { return false; + } if (!InternalOnMove(d)) return false; @@ -3594,7 +3911,8 @@ namespace Server if (FwdEnabled && m_NetState != null && m_AccessLevel < FwdAccessOverride && (!FwdUOTDOverride || !m_NetState.IsUOTDClient)) { - m_MoveRecords ??= new Queue(6); + if (m_MoveRecords == null) + m_MoveRecords = new Queue(6); while (m_MoveRecords.Count > 0) { @@ -3639,7 +3957,8 @@ namespace Server DisruptiveAction(); } - Packets.SendMovementAck(m_NetState, this); + m_NetState?.Send(MovementAck.Instantiate(m_NetState.Sequence, + this)); //new MovementAck( m_NetState.Sequence, this ) ); SetLocation(newLocation, false); SetDirection(d); @@ -3660,27 +3979,59 @@ namespace Server m_MoveList.Add(mob); } else if (o is Item item && item.HandlesOnMovement) + { m_MoveList.Add(item); + } } eable.Free(); + Packet[][] cache = m_MovingPacketCache; + + /*for( int i = 0; i < cache.Length; ++i ) + for( int j = 0; j < cache[i].Length; ++j ) + Packet.Release( ref cache[i][j] );*/ + foreach (Mobile m in m_MoveClientList) { NetState ns = m.NetState; if (ns != null && Utility.InUpdateRange(m_Location, m.m_Location) && m.CanSee(this)) - Packets.SendMobileMoving(ns, this, Notoriety.Compute(m, this)); + { + if (ns.StygianAbyss) + { + int noto = Notoriety.Compute(m, this); + Packet p = cache[0][noto]; + + if (p == null) + cache[0][noto] = p = Packet.Acquire(new MobileMoving(this, noto)); + + ns.Send(p); + } + else + { + int noto = Notoriety.Compute(m, this); + Packet p = cache[1][noto]; + + if (p == null) + cache[1][noto] = p = Packet.Acquire(new MobileMovingOld(this, noto)); + + ns.Send(p); + } + } } + for (int i = 0; i < cache.Length; ++i) + for (int j = 0; j < cache[i].Length; ++j) + Packet.Release(ref cache[i][j]); + for (int i = 0; i < m_MoveList.Count; ++i) { IEntity o = m_MoveList[i]; if (o is Mobile mobile) mobile.OnMovement(this, oldLocation); - else if (o is Item item) - item.OnMovement(this, oldLocation); + else if (o is Item item) item.OnMovement(this, oldLocation); } if (m_MoveList.Count > 0) @@ -3698,9 +4049,15 @@ namespace Server { } - public int ComputeMovementSpeed() => ComputeMovementSpeed(Direction, false); + public int ComputeMovementSpeed() + { + return ComputeMovementSpeed(Direction, false); + } - public int ComputeMovementSpeed(Direction dir) => ComputeMovementSpeed(dir, true); + public int ComputeMovementSpeed(Direction dir) + { + return ComputeMovementSpeed(dir, true); + } public virtual int ComputeMovementSpeed(Direction dir, bool checkTurning) { @@ -3718,13 +4075,22 @@ namespace Server /// Overridable. Virtual event invoked when a Mobile moves off this Mobile. /// /// True if the move is allowed, false if not. - public virtual bool OnMoveOff(Mobile m) => true; + public virtual bool OnMoveOff(Mobile m) + { + return true; + } /// /// Overridable. Event invoked when a Mobile moves over this Mobile. /// /// True if the move is allowed, false if not. - public virtual bool OnMoveOver(Mobile m) => m_Map == null || Deleted || m.CheckShove(this); + public virtual bool OnMoveOver(Mobile m) + { + if (m_Map == null || Deleted) + return true; + + return m.CheckShove(this); + } public virtual bool CheckShove(Mobile shoved) { @@ -3784,7 +4150,10 @@ namespace Server Region.OnCriminalAction(this, message); } - public virtual bool IsSnoop(Mobile from) => from != this; + public virtual bool IsSnoop(Mobile from) + { + return from != this; + } /// /// Overridable. Any call to will silently fail if this method returns false. @@ -3884,7 +4253,10 @@ namespace Server Spawner = null; } - public virtual bool CheckSpellCast(ISpell spell) => true; + public virtual bool CheckSpellCast(ISpell spell) + { + return true; + } /// /// Overridable. Virtual event invoked when the Mobile casts a . @@ -3943,15 +4315,30 @@ namespace Server m_AutoManifestTimer?.Stop(); } - public virtual bool AllowSkillUse(SkillName name) => true; + public virtual bool AllowSkillUse(SkillName name) + { + return true; + } - public virtual bool UseSkill(SkillName name) => Skills.UseSkill(this, name); + public virtual bool UseSkill(SkillName name) + { + return Skills.UseSkill(this, name); + } - public virtual bool UseSkill(int skillID) => Skills.UseSkill(this, skillID); + public virtual bool UseSkill(int skillID) + { + return Skills.UseSkill(this, skillID); + } - public virtual DeathMoveResult GetParentMoveResultFor(Item item) => item.OnParentDeath(this); + public virtual DeathMoveResult GetParentMoveResultFor(Item item) + { + return item.OnParentDeath(this); + } - public virtual DeathMoveResult GetInventoryMoveResultFor(Item item) => item.OnInventoryDeath(this); + public virtual DeathMoveResult GetInventoryMoveResultFor(Item item) + { + return item.OnInventoryDeath(this); + } public virtual void Kill() { @@ -4075,10 +4462,20 @@ namespace Server Container c = CreateCorpseHandler?.Invoke(this, hair, facialhair, content, equip); + + /*m_Corpse = c; + + for ( int i = 0; c != null && i < content.Count; ++i ) + c.DropItem( (Item)content[i] ); + + if ( c != null ) + c.MoveToWorld( this.Location, this.Map );*/ + if (m_Map != null) { + Packet animPacket = null; + IPooledEnumerable eable = m_Map.GetClientsInRange(m_Location); - Serial cSerial = c?.Serial ?? Serial.Zero; foreach (NetState state in eable) if (state != m_NetState) @@ -4086,10 +4483,13 @@ namespace Server if (animPacket == null) animPacket = Packet.Acquire(new DeathAnimation(this, c)); - if (!state.Mobile.CanSee(this)) - Packets.SendRemoveEntity(state, Serial); + state.Send(animPacket); + + if (!state.Mobile.CanSee(this)) state.Send(RemovePacket); } + Packet.Release(animPacket); + eable.Free(); } @@ -4122,10 +4522,12 @@ namespace Server Effects.PlaySound(this, Map, sound); if (!m_Player) + { Delete(); + } else { - Packets.SendDeathStatus_Dead(NetState); + Send(DeathStatus.Instantiate(true)); Warmode = false; @@ -4151,13 +4553,16 @@ namespace Server ProcessDeltaQueue(); - Packets.SendDeathStatus_Alive(NetState); + Send(DeathStatus.Instantiate(false)); CheckStatTimers(); } } - public virtual bool CheckTarget(Mobile from, Target targ, object targeted) => true; + public virtual bool CheckTarget(Mobile from, Target targ, object targeted) + { + return true; + } public virtual void Use(Item item) { @@ -4173,18 +4578,28 @@ namespace Server bool okay = false; if (!Utility.InUpdateRange(this, item.GetWorldLocation())) + { item.OnDoubleClickOutOfRange(this); + } else if (!CanSee(item)) + { item.OnDoubleClickCantSee(this); + } else if (!item.IsAccessibleTo(this)) { - if (Region.Find(item.GetWorldLocation(), item.Map)?.SendInaccessibleMessage(item, this) != true) + Region reg = Region.Find(item.GetWorldLocation(), item.Map); + + if (reg?.SendInaccessibleMessage(item, this) != true) item.OnDoubleClickNotAccessible(this); } else if (!CheckAlive(false)) + { item.OnDoubleClickDead(this); + } else if (item.InSecureTrade) + { item.OnDoubleClickSecureTrade(this); + } else if (!AllowItemUse(item)) { } @@ -4192,9 +4607,13 @@ namespace Server { } else if (root is Mobile mobile && mobile.IsSnoop(this)) + { item.OnSnoop(this); - else - okay |= Region.OnDoubleClick(this, item); + } + else if (Region.OnDoubleClick(this, item)) + { + okay = true; + } if (okay) { @@ -4231,7 +4650,7 @@ namespace Server public virtual void Lift(Item item, int amount, out bool rejected, out LRReason reject) { rejected = true; - reject = LRReason.Unspecific; + reject = LRReason.Inspecific; if (item == null) return; @@ -4246,15 +4665,25 @@ namespace Server from.DisruptiveAction(); if (from.Holding != null) + { reject = LRReason.AreHolding; + } else if (from.AccessLevel < AccessLevel.GameMaster && !from.InRange(item.GetWorldLocation(), 2)) + { reject = LRReason.OutOfRange; + } else if (!from.CanSee(item) || !from.InLOS(item)) + { reject = LRReason.OutOfSight; + } else if (!item.VerifyMove(from)) + { reject = LRReason.CannotLift; + } else if (!item.IsAccessibleTo(from)) + { reject = LRReason.CannotLift; + } else if (item.Nontransferable && amount != item.Amount) { if (item.QuestItem) @@ -4270,11 +4699,17 @@ namespace Server IEntity root = item.RootParent; if (root is Mobile mobile && !mobile.CheckNonlocalLift(from, item)) + { reject = LRReason.TryToSteal; + } else if (!from.OnDragLift(item) || !item.OnDragLift(from)) - reject = LRReason.Unspecific; + { + reject = LRReason.Inspecific; + } else if (!from.CheckAlive()) - reject = LRReason.Unspecific; + { + reject = LRReason.Inspecific; + } else { item.SetLastMoved(); @@ -4303,14 +4738,25 @@ namespace Server if (DragEffects && map != null && (root == null || root is Item)) { IPooledEnumerable eable = map.GetClientsInRange(from.Location); + Packet p = null; Item rootItem = root as Item; - IEntity src = new Entity(rootItem?.Serial ?? Serial.Zero, - rootItem?.Location ?? item.Location, map); foreach (NetState ns in eable) if (ns.Mobile != from && ns.Mobile.CanSee(from) && ns.Mobile.InLOS(from) && ns.Mobile.CanSee(root)) - Packets.SendDragEffect(ns, src, from, item.ItemID, item.Hue, amount); + { + if (p == null) + { + IEntity src = new Entity(rootItem?.Serial ?? Serial.Zero, + rootItem?.Location ?? item.Location, map); + + p = Packet.Acquire(new DragEffect(src, from, item.ItemID, item.Hue, amount)); + } + + ns.Send(p); + } + + Packet.Release(p); eable.Free(); } @@ -4328,43 +4774,54 @@ namespace Server int liftSound = item.GetLiftSound(from); if (liftSound != -1) - Packets.SendPlaySound(from.NetState, liftSound, from); + from.Send(new PlaySound(liftSound, from)); from.NextActionTime = Core.TickCount + ActionDelay; - if (shouldFix) - fixMap?.FixColumn(fixLoc.m_X, fixLoc.m_Y); + if (fixMap != null && shouldFix) + fixMap.FixColumn(fixLoc.m_X, fixLoc.m_Y); - reject = LRReason.Unspecific; + reject = LRReason.Inspecific; rejected = false; } } } else - reject = LRReason.Unspecific; + { + reject = LRReason.Inspecific; + } } else { SendActionMessage(); - reject = LRReason.Unspecific; + reject = LRReason.Inspecific; } if (rejected && state != null) { - Packets.SendLiftRej(state, reject); + state.Send(new LiftRej(reject)); if (item.Deleted) return; if (item.Parent is Item) - Packets.SendContainerContentUpdate(state, item); + { + if (state.ContainerGridLines) + state.Send(new ContainerContentUpdate6017(item)); + else + state.Send(new ContainerContentUpdate(item)); + } else if (item.Parent is Mobile) - Packets.SendEquipUpdate(state, item); + { + state.Send(new EquipUpdate(item)); + } else + { item.SendInfoTo(state); + } if (ObjectPropertyList.Enabled && item.Parent != null) - item.PropertyList.Send(state); + state.Send(item.OPLPacket); } } @@ -4373,7 +4830,6 @@ namespace Server Item item; try { - // TODO: Kill this with a vengence... item = (Item)Activator.CreateInstance(oldItem.GetType()); } catch @@ -4403,8 +4859,7 @@ namespace Server if (oldItem.Parent is Mobile parentMobile) parentMobile.AddItem(item); - else if (oldItem.Parent is Item parentItem) - parentItem.AddItem(item); + else if (oldItem.Parent is Item parentItem) parentItem.AddItem(item); item.Delta(ItemDelta.Update); @@ -4421,8 +4876,8 @@ namespace Server if (map != null && (root == null || root is Item)) { IPooledEnumerable eable = map.GetClientsInRange(m_Location); + Packet p = null; Item rootItem = root as Item; - IEntity trg = new Entity(rootItem?.Serial ?? Serial.Zero, rootItem?.Location ?? item.Location, map); foreach (NetState ns in eable) { @@ -4430,9 +4885,21 @@ namespace Server continue; if (ns.Mobile != this && ns.Mobile.CanSee(this) && ns.Mobile.InLOS(this) && ns.Mobile.CanSee(root)) - Packets.SendDragEffect(ns, this, trg, item.ItemID, item.Hue, item.Amount); + { + if (p == null) + { + IEntity trg = new Entity(rootItem?.Serial ?? Serial.Zero, + rootItem?.Location ?? item.Location, map); + + p = Packet.Acquire(new DragEffect(this, trg, item.ItemID, item.Hue, item.Amount)); + } + + ns.Send(p); + } } + Packet.Release(p); + eable.Free(); } } @@ -4681,9 +5148,14 @@ namespace Server mutatedArgs = new SpeechEventArgs(this, mutatedText, type, hue, new int[0]); CheckSpeechManifest(); + ProcessDelta(); + Packet regp = null; + Packet mutp = null; + // TODO: Should this be sorted like onSpeech is below? + for (int i = 0; i < hears.Count; ++i) { Mobile heard = hears[i]; @@ -4693,21 +5165,36 @@ namespace Server heard.OnSpeech(regArgs); NetState ns = heard.NetState; + if (ns != null) - Packets.SendUnicodeMessage(ns, Serial, Body, type, hue, 3, Language, Name, - text); + { + if (regp == null) + regp = Packet.Acquire(new UnicodeMessage(Serial, Body, type, hue, 3, m_Language, Name, + text)); + + ns.Send(regp); + } } else { heard.OnSpeech(mutatedArgs); NetState ns = heard.NetState; + if (ns != null) - Packets.SendUnicodeMessage(ns, Serial, Body, type, hue, 3, Language, Name, - mutatedText); + { + if (mutp == null) + mutp = Packet.Acquire(new UnicodeMessage(Serial, Body, type, hue, 3, m_Language, Name, + mutatedText)); + + ns.Send(mutp); + } } } + Packet.Release(regp); + Packet.Release(mutp); + if (onSpeech.Count > 1) onSpeech.Sort(LocationComparer.GetInstance(this)); @@ -4723,7 +5210,9 @@ namespace Server heard.OnSpeech(mutatedArgs); } else + { ((Item)obj).OnSpeech(regArgs); + } } if (m_Hears.Count > 0) @@ -4734,9 +5223,15 @@ namespace Server } } - public static Mobile GetDamagerFrom(DamageEntry de) => de?.Damager; + public static Mobile GetDamagerFrom(DamageEntry de) + { + return de?.Damager; + } - public Mobile FindMostRecentDamager(bool allowSelf) => GetDamagerFrom(FindMostRecentDamageEntry(allowSelf)); + public Mobile FindMostRecentDamager(bool allowSelf) + { + return GetDamagerFrom(FindMostRecentDamageEntry(allowSelf)); + } public DamageEntry FindMostRecentDamageEntry(bool allowSelf) { @@ -4756,7 +5251,10 @@ namespace Server return null; } - public Mobile FindLeastRecentDamager(bool allowSelf) => GetDamagerFrom(FindLeastRecentDamageEntry(allowSelf)); + public Mobile FindLeastRecentDamager(bool allowSelf) + { + return GetDamagerFrom(FindLeastRecentDamageEntry(allowSelf)); + } public DamageEntry FindLeastRecentDamageEntry(bool allowSelf) { @@ -4781,7 +5279,10 @@ namespace Server return null; } - public Mobile FindMostTotalDamger(bool allowSelf) => GetDamagerFrom(FindMostTotalDamageEntry(allowSelf)); + public Mobile FindMostTotalDamger(bool allowSelf) + { + return GetDamagerFrom(FindMostTotalDamageEntry(allowSelf)); + } public DamageEntry FindMostTotalDamageEntry(bool allowSelf) { @@ -4803,7 +5304,10 @@ namespace Server return mostTotal; } - public Mobile FindLeastTotalDamger(bool allowSelf) => GetDamagerFrom(FindLeastTotalDamageEntry(allowSelf)); + public Mobile FindLeastTotalDamger(bool allowSelf) + { + return GetDamagerFrom(FindLeastTotalDamageEntry(allowSelf)); + } public DamageEntry FindLeastTotalDamageEntry(bool allowSelf) { @@ -4843,7 +5347,10 @@ namespace Server return null; } - public virtual Mobile GetDamageMaster(Mobile damagee) => null; + public virtual Mobile GetDamageMaster(Mobile damagee) + { + return null; + } public virtual DamageEntry RegisterDamage(int amount, Mobile from) { @@ -4859,9 +5366,23 @@ namespace Server if (master != null) { - List list = de.Responsible ?? new List(); + List list = de.Responsible; - DamageEntry resp = list.FirstOrDefault(check => check.Damager == master); + if (list == null) + de.Responsible = list = new List(); + + DamageEntry resp = null; + + for (int i = 0; i < list.Count; ++i) + { + DamageEntry check = list[i]; + + if (check.Damager == master) + { + resp = check; + break; + } + } if (resp == null) list.Add(resp = new DamageEntry(master)); @@ -4891,11 +5412,15 @@ namespace Server public virtual bool CanBeDamaged() { + return !m_Blessed; } - public virtual bool CanBeDamaged() => !m_Blessed; + public virtual void Damage(int amount, Mobile from) + { + Damage(amount, from, true); + } - public virtual void Damage(int amount, Mobile from = null, bool informMount = true) + public virtual void Damage(int amount, Mobile from, bool informMount) { if (!CanBeDamaged() || Deleted) return; @@ -4942,8 +5467,8 @@ namespace Server OnDamage(amount, from, newHits < 0); IMount m = Mount; - if (informMount) - m?.OnRiderDamaged(amount, from, newHits < 0); + if (m != null && informMount) + m.OnRiderDamaged(amount, from, newHits < 0); if (newHits < 0) { @@ -4955,22 +5480,64 @@ namespace Server Kill(); } else + { Hits = newHits; + } } } public void SendVisibleDamageRelated(Mobile from, int amount) { - if (amount <= 0) - return; + NetState ourState = m_NetState, theirState = from?.m_NetState; - NetState ourState = m_NetState ?? GetDamageMaster(from)?.m_NetState; - NetState theirState = from?.m_NetState ?? from?.GetDamageMaster(this)?.m_NetState; + if (ourState == null) + { + Mobile master = GetDamageMaster(from); - Packets.SendDamage(ourState, Serial, amount); + if (master != null) + ourState = master.m_NetState; + } - if (theirState != ourState) - Packets.SendDamage(theirState, Serial, amount); + if (theirState == null && from != null) + { + Mobile master = from.GetDamageMaster(this); + + if (master != null) + theirState = master.m_NetState; + } + + if (amount > 0 && (ourState != null || theirState != null)) + { + Packet p = null; // = new DamagePacket( this, amount ); + + if (ourState != null) + { + p = ourState.DamagePacket ? Packet.Acquire(new DamagePacket(this, amount)) : + Packet.Acquire(new DamagePacketOld(this, amount)); + + ourState.Send(p); + } + + if (theirState != null && theirState != ourState) + { + bool newPacket = theirState.DamagePacket; + + if (newPacket && !(p is DamagePacket)) + { + Packet.Release(p); + p = Packet.Acquire(new DamagePacket(this, amount)); + } + else if (!newPacket && !(p is DamagePacketOld)) + { + Packet.Release(p); + p = Packet.Acquire(new DamagePacketOld(this, amount)); + } + + theirState.Send(p); + } + + Packet.Release(p); + } } public void SendVisibleDamageEveryone(int amount) @@ -4985,24 +5552,41 @@ namespace Server IPooledEnumerable eable = map.GetClientsInRange(m_Location); + Packet pNew = null; + Packet pOld = null; + foreach (NetState ns in eable) if (ns.Mobile.CanSee(this)) - Packets.SendDamage(ns, Serial, amount); + { + if (ns.DamagePacket) + { + if (pNew == null) + pNew = Packet.Acquire(new DamagePacket(this, amount)); + + ns.Send(pNew); + } + else + { + if (pOld == null) + pOld = Packet.Acquire(new DamagePacketOld(this, amount)); + + ns.Send(pOld); + } + } + + Packet.Release(pNew); + Packet.Release(pOld); eable.Free(); } public void SendVisibleDamageSelective(Mobile from, int amount) { - if (amount <= 0) - return; + NetState ourState = m_NetState, theirState = from?.m_NetState; Mobile damager = from; Mobile damaged = this; - NetState ourState = m_NetState; - NetState theirState = from?.m_NetState; - if (ourState == null) { Mobile master = GetDamageMaster(from); @@ -5028,33 +5612,53 @@ namespace Server } } - if (damaged.CanSeeVisibleDamage) - Packets.SendDamage(ourState, Serial, amount); + if (amount > 0 && (ourState != null || theirState != null)) + { + if (damaged.CanSeeVisibleDamage && ourState != null) + { + if (ourState.DamagePacket) + ourState.Send(new DamagePacket(this, amount)); + else + ourState.Send(new DamagePacketOld(this, amount)); + } - if (theirState != ourState && damager.CanSeeVisibleDamage) - Packets.SendDamage(theirState, Serial, amount); + if (theirState != null && theirState != ourState && damager.CanSeeVisibleDamage) + { + if (theirState.DamagePacket) + theirState.Send(new DamagePacket(this, amount)); + else + theirState.Send(new DamagePacketOld(this, amount)); + } + } } public void Heal(int amount) { - Heal(amount, this); + Heal(amount, this, true); } - public void Heal(int amount, Mobile from, bool message = true) + public void Heal(int amount, Mobile from) { - if (!Alive || IsDeadBondedPet || !Region.OnHeal(this, ref amount)) + Heal(amount, from, true); + } + + public void Heal(int amount, Mobile from, bool message) + { + if (!Alive || IsDeadBondedPet) + return; + + if (!Region.OnHeal(this, ref amount)) return; OnHeal(ref amount, from); - if (Hits + amount > HitsMax) - amount = HitsMax - Hits; + if (Hits + amount > HitsMax) amount = HitsMax - Hits; Hits += amount; if (message && amount > 0) - Packets.SendMessageLocalizedAffix(m_NetState, Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008158, "", - AffixType.Append | AffixType.System, amount.ToString()); + m_NetState?.Send(new MessageLocalizedAffix(Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008158, "", + AffixType.Append | AffixType.System, amount.ToString(), "")); } public virtual void OnHeal(ref int amount, Mobile from) @@ -5264,7 +5868,8 @@ namespace Server if (version < 18) Virtues = new VirtueInfo(); - m_DisplayGuildTitle |= version < 11; + if (version < 11) + m_DisplayGuildTitle = true; if (version < 3) m_StatCap = 225; @@ -5285,7 +5890,7 @@ namespace Server EmoteHue = reader.ReadInt(); WhisperHue = reader.ReadInt(); YellHue = reader.ReadInt(); - Language = reader.ReadString(); + m_Language = reader.ReadString(); m_Female = reader.ReadBool(); m_Warmode = reader.ReadBool(); m_Hidden = reader.ReadBool(); @@ -5350,7 +5955,9 @@ namespace Server if (m_Criminal) { - m_ExpireCriminal ??= new ExpireCriminalTimer(this); + if (m_ExpireCriminal == null) + m_ExpireCriminal = new ExpireCriminalTimer(this); + m_ExpireCriminal.Start(); } @@ -5410,45 +6017,69 @@ namespace Server { if (CanRegenHits) { - m_HitsTimer ??= new HitsTimer(this); + if (m_HitsTimer == null) + m_HitsTimer = new HitsTimer(this); + m_HitsTimer.Start(); } else + { m_HitsTimer?.Stop(); + } } else + { Hits = HitsMax; + } if (Stam < StamMax) { if (CanRegenStam) { - m_StamTimer ??= new StamTimer(this); + if (m_StamTimer == null) + m_StamTimer = new StamTimer(this); + m_StamTimer.Start(); } else + { m_StamTimer?.Stop(); + } } else + { Stam = StamMax; + } if (Mana < ManaMax) { if (CanRegenMana) { - m_ManaTimer ??= new ManaTimer(this); + if (m_ManaTimer == null) + m_ManaTimer = new ManaTimer(this); + m_ManaTimer.Start(); } else + { m_ManaTimer?.Stop(); + } } else + { Mana = ManaMax; + } } - public static string GetAccessLevelName(AccessLevel level) => m_AccessLevelNames[(int)level]; + public static string GetAccessLevelName(AccessLevel level) + { + return m_AccessLevelNames[(int)level]; + } - public virtual bool CanPaperdollBeOpenedBy(Mobile from) => Body.IsHuman || Body.IsGhost || IsBodyMod; + public virtual bool CanPaperdollBeOpenedBy(Mobile from) + { + return Body.IsHuman || Body.IsGhost || IsBodyMod; + } public virtual void GetChildContextMenuEntries(Mobile from, List list, Item item) { @@ -5591,9 +6222,11 @@ namespace Server if (map == null) return; - ProcessDelta(); + Packet p = null; + //Packet pNew = null; + IPooledEnumerable eable = map.GetClientsInRange(m_Location); foreach (NetState state in eable) @@ -5601,52 +6234,70 @@ namespace Server { state.Mobile.ProcessDelta(); - if (Body.IsGargoyle) - { - frameCount = 10; + //if ( state.StygianAbyss ) { + //if ( pNew == null ) + //pNew = Packet.Acquire( new NewMobileAnimation( this, action, frameCount, delay ) ); - if (Flying) + //state.Send( pNew ); + //} else { + if (p == null) + { + #region SA + + if (Body.IsGargoyle) { - if (action >= 9 && action <= 11) - action = 71; - else if (action >= 12 && action <= 14) - action = 72; - else if (action == 20) - action = 77; - else if (action == 31) - action = 71; - else if (action == 34) - action = 78; - else if (action >= 200 && action <= 259) - action = 75; - else if (action >= 260 && action <= 270) action = 75; - } - else - { - if (action >= 200 && action <= 259) - action = 17; - else if (action >= 260 && action <= 270) - action = 16; + frameCount = 10; + + if (Flying) + { + if (action >= 9 && action <= 11) + action = 71; + else if (action >= 12 && action <= 14) + action = 72; + else if (action == 20) + action = 77; + else if (action == 31) + action = 71; + else if (action == 34) + action = 78; + else if (action >= 200 && action <= 259) + action = 75; + else if (action >= 260 && action <= 270) action = 75; + } + else + { + if (action >= 200 && action <= 259) + action = 17; + else if (action >= 260 && action <= 270) action = 16; + } } + + #endregion + + p = Packet.Acquire(new MobileAnimation(this, action, frameCount, repeatCount, forward, repeat, + delay)); } - Packets.SendMobileAnimation(state, this, action, frameCount, repeatCount, forward, repeat, delay); + state.Send(p); + //} } + Packet.Release(p); + //Packet.Release( pNew ); + eable.Free(); } public void SendSound(int soundID) { - SendSound(soundID, this); + if (soundID != -1 && m_NetState != null) + Send(new PlaySound(soundID, this)); } public void SendSound(int soundID, IPoint3D p) { - if (soundID == -1) - return; - - Packets.SendPlaySound(m_NetState, soundID, p); + if (soundID != -1 && m_NetState != null) + Send(new PlaySound(soundID, p)); } public void PlaySound(int soundID) @@ -5654,11 +6305,15 @@ namespace Server if (soundID == -1 || m_Map == null) return; + Packet p = Packet.Acquire(new PlaySound(soundID, this)); + IPooledEnumerable eable = m_Map.GetClientsInRange(m_Location); foreach (NetState state in eable) if (state.Mobile.CanSee(this)) - Packets.SendPlaySound(m_NetState, soundID, this); + state.Send(p); + + Packet.Release(p); eable.Free(); } @@ -5678,12 +6333,18 @@ namespace Server // Mobile did something which should unhide him public virtual void RevealingAction() { - Hidden |= m_Hidden && m_AccessLevel == AccessLevel.Player; + if (m_Hidden && m_AccessLevel == AccessLevel.Player) + Hidden = false; DisruptiveAction(); // Anything that unhides you will also distrupt meditation } - public void SendRemovePacket(bool everyone = true) + public void SendRemovePacket() + { + SendRemovePacket(true); + } + + public void SendRemovePacket(bool everyone) { if (m_Map == null) return; @@ -5692,7 +6353,7 @@ namespace Server foreach (NetState state in eable) if (state != m_NetState && (everyone || !state.Mobile.CanSee(this))) - Packets.SendRemoveEntity(state, Serial); + state.Send(RemovePacket); eable.Free(); } @@ -5708,12 +6369,12 @@ namespace Server if (o is Mobile m) { if (m != this && Utility.InUpdateRange(m_Location, m.m_Location)) - Packets.SendRemoveEntity(m_NetState, m.Serial); + m_NetState.Send(m.RemovePacket); } else if (o is Item item) { if (InRange(item.Location, item.GetUpdateRange(this))) - Packets.SendRemoveEntity(m_NetState, item.Serial); + m_NetState.Send(item.RemovePacket); } eable.Free(); @@ -5758,7 +6419,10 @@ namespace Server RevealingAction(); } - public virtual bool HandlesOnSpeech(Mobile from) => false; + public virtual bool HandlesOnSpeech(Mobile from) + { + return false; + } /// /// Overridable. Virtual event invoked when the Mobile hears speech. This event will only be invoked if @@ -5787,22 +6451,21 @@ namespace Server { if (CanSee(m) && Utility.InUpdateRange(m_Location, m.m_Location)) { - Packets.SendMobileIncoming(ns, this, m); + ns.Send(MobileIncoming.Create(ns, this, m)); if (ns.StygianAbyss) { if (m.Poisoned) - Packets.SendHealthbarPoison(ns, m); + ns.Send(new HealthbarPoison(m)); if (m.Blessed || m.YellowHealthbar) - Packets.SendHealthbarYellow(ns, m); + ns.Send(new HealthbarYellow(m)); } if (m.IsDeadBondedPet) - Packets.SendBondStatus(ns, m.Serial, true); + ns.Send(new BondedStatus(0, m.Serial, 1)); - if (ObjectPropertyList.Enabled) - m.PropertyList.SendOPLInfo(ns); + if (ObjectPropertyList.Enabled) ns.Send(m.OPLPacket); } } @@ -5839,7 +6502,10 @@ namespace Server m_Direction = dir; } - public virtual byte GetSeason() => m_Map?.Season ?? 1; + public virtual int GetSeason() + { + return m_Map?.Season ?? 1; + } public virtual int GetPacketFlags() { @@ -5918,15 +6584,17 @@ namespace Server foreach (NetState state in eable) if (!state.Mobile.CanSee(this)) - Packets.SendRemoveEntity(state, Serial); + { + state.Send(RemovePacket); + } else { - Packets.SendMobileIncoming(state, state.Mobile, this); + state.Send(MobileIncoming.Create(state, state.Mobile, this)); if (IsDeadBondedPet) - Packets.SendBondStatus(state, Serial, true); + state.Send(new BondedStatus(0, Serial, 1)); - if (ObjectPropertyList.Enabled) PropertyList.Send(state); + if (ObjectPropertyList.Enabled) state.Send(OPLPacket); } eable.Free(); @@ -6002,7 +6670,10 @@ namespace Server m_AccessLevel > AccessLevel.Player || m.Warmode); } - public virtual bool CanBeRenamedBy(Mobile from) => from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel; + public virtual bool CanBeRenamedBy(Mobile from) + { + return from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel; + } public virtual void OnGuildTitleChange(string oldTitle) { @@ -6026,9 +6697,17 @@ namespace Server return delta != 0 ? body : 0; } + public virtual void FreeCache() + { + StaticPacketHandlers.FreeRemoveItemPacket(this); + StaticPacketHandlers.FreeOPLInfoPacket(this); + StaticPacketHandlers.FreeOPLPacket(this); + } + public void ClearProperties() { - m_PropertyList = null; + StaticPacketHandlers.FreeOPLPacket(this); + StaticPacketHandlers.FreeOPLInfoPacket(this); } public void InvalidateProperties() @@ -6038,14 +6717,18 @@ namespace Server if (m_Map != null && m_Map != Map.Internal && !World.Loading) { - ObjectPropertyList oldList = m_PropertyList; - ClearProperties(); + ObjectPropertyList oldList = StaticPacketHandlers.FreeOPLPacket(this); if (oldList?.Hash != PropertyList.Hash) + { + StaticPacketHandlers.FreeOPLInfoPacket(this); Delta(MobileDelta.Properties); + } } else + { ClearProperties(); + } } public virtual void SetLocation(Point3D newLocation, bool isTeleport) @@ -6074,7 +6757,10 @@ namespace Server { m_NetState.Sequence = 0; - Packets.SendMobileUpdate(m_NetState, this); + if (m_NetState.StygianAbyss) + m_NetState.Send(new MobileUpdate(this)); + else + m_NetState.Send(new MobileUpdateOld(this)); ClearFastwalkStack(); } @@ -6089,7 +6775,7 @@ namespace Server foreach (NetState ns in eable) if (ns != m_NetState && !Utility.InUpdateRange(newLocation, ns.Mobile.Location)) - Packets.SendRemoveEntity(ns, Serial); + ns.Send(RemovePacket); eable.Free(); @@ -6119,40 +6805,44 @@ namespace Server bool inOldRange = Utility.InUpdateRange(oldLocation, m.m_Location); - if (m.NetState != null && + if (m.m_NetState != null && (isTeleport && (!m.m_NetState.HighSeas || !NoMoveHS) || !inOldRange) && m.CanSee(this)) { - Packets.SendMobileIncoming(m.m_NetState, m, this); + m.m_NetState.Send(MobileIncoming.Create(m.m_NetState, m, this)); if (m.m_NetState.StygianAbyss) { - Packets.SendHealthbarPoison(m.m_NetState, this); - Packets.SendHealthbarYellow(m.m_NetState, this); + //if ( m_Poison != null ) + m.m_NetState.Send(new HealthbarPoison(this)); + + //if ( m_Blessed || m_YellowHealthbar ) + m.m_NetState.Send(new HealthbarYellow(this)); } if (IsDeadBondedPet) - Packets.SendBondStatus(NetState, Serial, true); + m.m_NetState.Send(new BondedStatus(0, Serial, 1)); - if (ObjectPropertyList.Enabled) - PropertyList.Send(m.NetState); + if (ObjectPropertyList.Enabled) m.m_NetState.Send(OPLPacket); } if (inOldRange || !CanSee(m)) continue; - Packets.SendMobileIncoming(ourState, this, m); + ourState.Send(MobileIncoming.Create(ourState, this, m)); if (ourState.StygianAbyss) { - Packets.SendHealthbarPoison(ourState, m); - Packets.SendHealthbarYellow(ourState, m); + //if ( m.Poisoned ) + ourState.Send(new HealthbarPoison(m)); + + //if ( m.Blessed || m.YellowHealthbar ) + ourState.Send(new HealthbarYellow(m)); } if (m.IsDeadBondedPet) - Packets.SendBondStatus(ourState, Serial, true); + ourState.Send(new BondedStatus(0, m.Serial, 1)); - if (ObjectPropertyList.Enabled) - m.PropertyList.Send(ourState); + if (ObjectPropertyList.Enabled) ourState.Send(m.OPLPacket); } eeable.Free(); @@ -6166,19 +6856,21 @@ namespace Server if ((isTeleport && (!ns.HighSeas || !NoMoveHS) || !Utility.InUpdateRange(oldLocation, ns.Mobile.Location)) && ns.Mobile.CanSee(this)) { - Packets.SendMobileIncoming(ns, ns.Mobile, this); + ns.Send(MobileIncoming.Create(ns, ns.Mobile, this)); if (ns.StygianAbyss) { - Packets.SendHealthbarPoison(ns, this); - Packets.SendHealthbarYellow(ns, this); + //if ( m_Poison != null ) + ns.Send(new HealthbarPoison(this)); + + //if ( m_Blessed || m_YellowHealthbar ) + ns.Send(new HealthbarYellow(this)); } if (IsDeadBondedPet) - Packets.SendBondStatus(ns, Serial, true); + ns.Send(new BondedStatus(0, Serial, 1)); - if (ObjectPropertyList.Enabled) - PropertyList.Send(ns); + if (ObjectPropertyList.Enabled) ns.Send(OPLPacket); } eable.Free(); @@ -6197,9 +6889,15 @@ namespace Server { } - public bool HasFreeHand() => FindItemOnLayer(Layer.TwoHanded) == null; + public bool HasFreeHand() + { + return FindItemOnLayer(Layer.TwoHanded) == null; + } - public virtual IWeapon GetDefaultWeapon() => DefaultWeapon; + public virtual IWeapon GetDefaultWeapon() + { + return DefaultWeapon; + } public BankBox FindBankNoCreate() { @@ -6234,58 +6932,72 @@ namespace Server foreach (NetState state in eable) if (state.Mobile.CanSee(this)) { - Packets.SendMobileIncoming(state, state.Mobile, this); + state.Send(MobileIncoming.Create(state, state.Mobile, this)); if (state.StygianAbyss) { if (m_Poison != null) - Packets.SendHealthbarPoison(state, this); + state.Send(new HealthbarPoison(this)); if (m_Blessed || m_YellowHealthbar) - Packets.SendHealthbarYellow(state, this); + state.Send(new HealthbarYellow(this)); } if (IsDeadBondedPet) - Packets.SendBondStatus(state, Serial, true); + state.Send(new BondedStatus(0, Serial, 1)); - if (ObjectPropertyList.Enabled) - PropertyList.Send(state); + if (ObjectPropertyList.Enabled) state.Send(OPLPacket); } eable.Free(); } - public bool PlaceInBackpack(Item item) => - !item.Deleted && Backpack?.TryDropItem(this, item, false) == true; + public bool PlaceInBackpack(Item item) + { + if (item.Deleted) + return false; + + return Backpack?.TryDropItem(this, item, false) == true; + } public bool AddToBackpack(Item item) { if (item.Deleted) return false; - if (PlaceInBackpack(item)) - return true; - - Point3D loc = m_Location; - Map map = m_Map; - - if ((map == null || map == Map.Internal) && LogoutMap != null) + if (!PlaceInBackpack(item)) { - loc = LogoutLocation; - map = LogoutMap; + Point3D loc = m_Location; + Map map = m_Map; + + if ((map == null || map == Map.Internal) && LogoutMap != null) + { + loc = LogoutLocation; + map = LogoutMap; + } + + item.MoveToWorld(loc, map); + return false; } - item.MoveToWorld(loc, map); - return false; + return true; } - public virtual bool CheckLift(Mobile from, Item item, ref LRReason reject) => true; + public virtual bool CheckLift(Mobile from, Item item, ref LRReason reject) + { + return true; + } - public virtual bool CheckNonlocalLift(Mobile from, Item item) => - from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster; + public virtual bool CheckNonlocalLift(Mobile from, Item item) + { + return from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster; + } public virtual bool CheckTrade(Mobile to, Item item, SecureTradeContainer cont, bool message, bool checkItems, - int plusItems, int plusWeight) => true; + int plusItems, int plusWeight) + { + return true; + } public virtual bool OpenTrade(Mobile from, Item offer = null) { @@ -6300,7 +7012,7 @@ namespace Server if (!from.CheckTrade(this, offer, cont, true, true, 0, 0)) return false; - cont ??= theirState.AddTrade(ourState); + if (cont == null) cont = theirState.AddTrade(ourState); if (offer != null) cont.DropItem(offer); @@ -6441,10 +7153,15 @@ namespace Server { } - public virtual bool CheckNonlocalDrop(Mobile from, Item item, Item target) => - from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster; + public virtual bool CheckNonlocalDrop(Mobile from, Item item, Item target) + { + return from == this || from.AccessLevel > AccessLevel && from.AccessLevel >= AccessLevel.GameMaster; + } - public virtual bool CheckItemUse(Mobile from, Item item) => true; + public virtual bool CheckItemUse(Mobile from, Item item) + { + return true; + } /// /// Overridable. Virtual event invoked when successfully lifts from this @@ -6455,9 +7172,15 @@ namespace Server { } - public virtual bool AllowItemUse(Item item) => true; + public virtual bool AllowItemUse(Item item) + { + return true; + } - public virtual bool AllowEquipFrom(Mobile mob) => mob == this || mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > AccessLevel; + public virtual bool AllowEquipFrom(Mobile mob) + { + return mob == this || mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > AccessLevel; + } public virtual bool EquipItem(Item item) { @@ -6511,21 +7234,24 @@ namespace Server m_InDeltaQueue = true; if (_processing) - { - m_DeltaQueueR.Enqueue(this); + lock (m_DeltaQueueR) + { + m_DeltaQueueR.Enqueue(this); - try - { - using StreamWriter op = new StreamWriter("delta-recursion.log", true); - op.WriteLine("# {0}", DateTime.UtcNow); - op.WriteLine(new StackTrace()); - op.WriteLine(); + try + { + using (StreamWriter op = new StreamWriter("delta-recursion.log", true)) + { + op.WriteLine("# {0}", DateTime.UtcNow); + op.WriteLine(new StackTrace()); + op.WriteLine(); + } + } + catch + { + // ignored + } } - catch - { - // ignored - } - } else m_DeltaQueue.Enqueue(this); } @@ -6539,26 +7265,19 @@ namespace Server if (m_DeltaQueue.Count >= 512) { - ConcurrentQueue queue = new ConcurrentQueue(); - queue = Interlocked.Exchange(ref m_DeltaQueue, queue); - do - { - Parallel.For(0, queue.Count, - _ => - { - if (queue.TryDequeue(out Mobile m)) - m.ProcessDelta(); - }); - } while (queue.Count > 0); + Parallel.ForEach(m_DeltaQueue, m => m.ProcessDelta()); + m_DeltaQueue.Clear(); } else - while (m_DeltaQueue.TryDequeue(out Mobile m)) - m.ProcessDelta(); + { + while (m_DeltaQueue.Count > 0) + m_DeltaQueue.Dequeue().ProcessDelta(); + } _processing = false; - while (m_DeltaQueueR.TryDequeue(out Mobile m)) - m.ProcessDelta(); + while (m_DeltaQueueR.Count > 0) + m_DeltaQueueR.Dequeue().ProcessDelta(); } public virtual void OnKillsChange(int oldValue) @@ -6615,10 +7334,10 @@ namespace Server public virtual void OnStatsQuery(Mobile from) { if (from.Map == Map && Utility.InUpdateRange(this, from) && from.CanSee(this)) - Packets.SendMobileStatus(from.NetState, from, this, m_NetState); + from.Send(new MobileStatus(from, this, m_NetState)); if (from == this) - Packets.SendStatLockInfo(m_NetState, this); + Send(new StatLockInfo(this)); if (Party is IParty ip) ip.OnStatsQuery(from, this); @@ -6630,7 +7349,7 @@ namespace Server public virtual void OnSkillsQuery(Mobile from) { if (from == this) - Packets.SendSkillsUpdate(m_NetState, Skills); + Send(new SkillUpdate(Skills)); } /// @@ -6655,9 +7374,14 @@ namespace Server if (guild != null && (m_DisplayGuildTitle || m_Player && guild.Type != GuildType.Regular)) { - string title = GuildTitle?.Trim() ?? ""; + string title = GuildTitle; string type; + if (title == null) + title = ""; + else + title = title.Trim(); + if (guild.Type >= 0 && (int)guild.Type < m_GuildTypes.Length) type = m_GuildTypes[(int)guild.Type]; else @@ -6696,28 +7420,36 @@ namespace Server string val; if (prefix.Length > 0 && suffix.Length > 0) - val = $"{prefix} {name} {suffix}"; + val = string.Concat(prefix, " ", name, " ", suffix); else if (prefix.Length > 0) - val = $"{prefix} {name}"; + val = string.Concat(prefix, " ", name); else if (suffix.Length > 0) - val = $"{name} {suffix}"; + val = string.Concat(name, " ", suffix); else val = name; PrivateOverheadMessage(MessageType.Label, hue, AsciiClickMessage, val, from.NetState); } - public bool CheckSkill(SkillName skill, double minSkill, double maxSkill) => - SkillCheckLocationHandler?.Invoke(this, skill, minSkill, maxSkill) == true; + public bool CheckSkill(SkillName skill, double minSkill, double maxSkill) + { + return SkillCheckLocationHandler?.Invoke(this, skill, minSkill, maxSkill) == true; + } - public bool CheckSkill(SkillName skill, double chance) => - SkillCheckDirectLocationHandler?.Invoke(this, skill, chance) == true; + public bool CheckSkill(SkillName skill, double chance) + { + return SkillCheckDirectLocationHandler?.Invoke(this, skill, chance) == true; + } - public bool CheckTargetSkill(SkillName skill, object target, double minSkill, double maxSkill) => - SkillCheckTargetHandler?.Invoke(this, skill, target, minSkill, maxSkill) == true; + public bool CheckTargetSkill(SkillName skill, object target, double minSkill, double maxSkill) + { + return SkillCheckTargetHandler?.Invoke(this, skill, target, minSkill, maxSkill) == true; + } - public bool CheckTargetSkill(SkillName skill, object target, double chance) => - SkillCheckDirectTargetHandler?.Invoke(this, skill, target, chance) == true; + public bool CheckTargetSkill(SkillName skill, object target, double chance) + { + return SkillCheckDirectTargetHandler?.Invoke(this, skill, target, chance) == true; + } public virtual void DisruptiveAction() { @@ -6747,7 +7479,10 @@ namespace Server private static Queue m_InstancePool = new Queue(); public long m_End; - private MovementRecord(long end) => m_End = end; + private MovementRecord(long end) + { + m_End = end; + } public static MovementRecord NewInstance(long end) { @@ -6805,8 +7540,10 @@ namespace Server private TargetCallback m_Callback; public SimpleTarget(int range, TargetFlags flags, bool allowGround, TargetCallback callback) - : base(range, allowGround, flags) => + : base(range, allowGround, flags) + { m_Callback = callback; + } protected override void OnTarget(Mobile from, object targeted) { @@ -6838,8 +7575,10 @@ namespace Server private Mobile m_Mobile; public AutoManifestTimer(Mobile m, TimeSpan delay) - : base(delay) => + : base(delay) + { m_Mobile = m; + } protected override void OnTick() { @@ -6852,11 +7591,17 @@ namespace Server { private static LocationComparer m_Instance; - public LocationComparer(IEntity relativeTo) => RelativeTo = relativeTo; + public LocationComparer(IEntity relativeTo) + { + RelativeTo = relativeTo; + } public IEntity RelativeTo{ get; set; } - public int Compare(IEntity x, IEntity y) => GetDistance(x) - GetDistance(y); + public int Compare(IEntity x, IEntity y) + { + return GetDistance(x) - GetDistance(y); + } public static LocationComparer GetInstance(IEntity relativeTo) { @@ -6881,9 +7626,15 @@ namespace Server } } - int IComparable.CompareTo(IEntity other) => other == null ? -1 : Serial.CompareTo(other.Serial); + int IComparable.CompareTo(IEntity other) + { + return other == null ? -1 : Serial.CompareTo(other.Serial); + } - public int CompareTo(Mobile other) => other == null ? -1 : Serial.CompareTo(other.Serial); + public int CompareTo(Mobile other) + { + return other == null ? -1 : Serial.CompareTo(other.Serial); + } #region Handlers @@ -7251,7 +8002,9 @@ namespace Server if (m_CallbackHandlesCancel && m_Callback != null) m_Callback(from, ""); else + { m_CancelCallback?.Invoke(from, ""); + } } } @@ -7311,7 +8064,10 @@ namespace Server return Prompt = new SimpleStatePrompt(callback, callbackHandlesCancel, state); } - public Prompt BeginPrompt(PromptStateCallback callback, T state) => BeginPrompt(callback, false, state); + public Prompt BeginPrompt(PromptStateCallback callback, T state) + { + return BeginPrompt(callback, false, state); + } public Prompt Prompt { @@ -7332,12 +8088,14 @@ namespace Server m_Prompt = newPrompt; if (newPrompt != null) - Packets.SendUnicodePrompt(m_NetState, newPrompt.Serial); + Send(new UnicodePrompt(newPrompt)); } } + #endregion #region Get*Sound + public virtual int GetAngerSound() { if (BaseSoundID != 0) @@ -7377,27 +8135,65 @@ namespace Server if (m_Body.IsHuman) return Utility.Random(m_Female ? 0x314 : 0x423, m_Female ? 4 : 5); return -1; } + #endregion #region Get*InRange - public IPooledEnumerable GetItemsInRange(int range) => GetItemsInRange(range); - public IPooledEnumerable GetItemsInRange(int range) where T : Item => - m_Map?.GetItemsInRange(m_Location, range) ?? Map.NullEnumerable.Instance; + public IPooledEnumerable GetItemsInRange(int range) + { + return GetItemsInRange(range); + } - public IPooledEnumerable GetObjectsInRange(int range) => - m_Map?.GetObjectsInRange(m_Location, range) ?? Map.NullEnumerable.Instance; + public IPooledEnumerable GetItemsInRange(int range) where T : Item + { + Map map = m_Map; - public IPooledEnumerable GetMobilesInRange(int range) => GetMobilesInRange(range); + if (map == null) + return Map.NullEnumerable.Instance; - public IPooledEnumerable GetMobilesInRange(int range) where T : Mobile => - m_Map?.GetMobilesInRange(m_Location, range) ?? Map.NullEnumerable.Instance; + return map.GetItemsInRange(m_Location, range); + } + + public IPooledEnumerable GetObjectsInRange(int range) + { + Map map = m_Map; + + if (map == null) + return Map.NullEnumerable.Instance; + + return map.GetObjectsInRange(m_Location, range); + } + + public IPooledEnumerable GetMobilesInRange(int range) + { + return GetMobilesInRange(range); + } + + public IPooledEnumerable GetMobilesInRange(int range) where T : Mobile + { + Map map = m_Map; + + if (map == null) + return Map.NullEnumerable.Instance; + + return map.GetMobilesInRange(m_Location, range); + } + + public IPooledEnumerable GetClientsInRange(int range) + { + Map map = m_Map; + + if (map == null) + return Map.NullEnumerable.Instance; + + return map.GetClientsInRange(m_Location, range); + } - public IPooledEnumerable GetClientsInRange(int range) => - m_Map.GetClientsInRange(m_Location, range) ?? Map.NullEnumerable.Instance; #endregion #region Say/SayTo/Emote/Whisper/Yell + public void SayTo(Mobile to, bool ascii, string text) { PrivateOverheadMessage(MessageType.Regular, SpeechHue, ascii, text, to.NetState); @@ -7420,12 +8216,12 @@ namespace Server public void SayTo(Mobile to, int number) { - Packets.SendMessageLocalized(to?.NetState, Serial, Body, MessageType.Regular, SpeechHue, 3, number, Name); + to.Send(new MessageLocalized(Serial, Body, MessageType.Regular, SpeechHue, 3, number, Name, "")); } public void SayTo(Mobile to, int number, string args) { - Packets.SendMessageLocalized(to?.NetState, Serial, Body, MessageType.Regular, SpeechHue, 3, number, Name, args); + to.Send(new MessageLocalized(Serial, Body, MessageType.Regular, SpeechHue, 3, number, Name, args)); } public void Say(bool ascii, string text) @@ -7497,16 +8293,28 @@ namespace Server { PublicOverheadMessage(MessageType.Yell, YellHue, number, args); } + #endregion #region Gumps/Menus - public void SendHuePicker(HuePicker p) + + public bool SendHuePicker(HuePicker p, bool throwOnOffline = false) { if (m_NetState != null) + { p.SendTo(m_NetState); + return true; + } + + if (throwOnOffline) throw new MobileNotConnectedException(this, "Hue picker could not be sent."); + + return false; } - public Gump FindGump() where T : Gump => m_NetState?.Gumps.Find(g => g is T); + public Gump FindGump() where T : Gump + { + return m_NetState?.Gumps.Find(g => g is T); + } public bool CloseGump() where T : Gump { @@ -7517,7 +8325,8 @@ namespace Server if (gump != null) { - Packets.SendCloseGump(m_NetState, gump.TypeID, 0); + // TODO: Recycle CloseGump + m_NetState.Send(new CloseGump(gump.TypeID, 0)); m_NetState.RemoveGump(gump); gump.OnServerClose(m_NetState); } @@ -7538,14 +8347,18 @@ namespace Server foreach (Gump gump in gumps) { - Packets.SendCloseGump(ns, gump.TypeID, 0); + ns.Send(new CloseGump(gump.TypeID, 0)); + gump.OnServerClose(ns); } return true; } - public bool HasGump() where T : Gump => FindGump() != null; + public bool HasGump() where T : Gump + { + return FindGump() != null; + } public bool SendGump(Gump g) { @@ -7569,9 +8382,15 @@ namespace Server #region Beneficial Checks/Actions - public virtual bool CanBeBeneficial(Mobile target) => CanBeBeneficial(target, true, false); + public virtual bool CanBeBeneficial(Mobile target) + { + return CanBeBeneficial(target, true, false); + } - public virtual bool CanBeBeneficial(Mobile target, bool message) => CanBeBeneficial(target, message, false); + public virtual bool CanBeBeneficial(Mobile target, bool message) + { + return CanBeBeneficial(target, message, false); + } public virtual bool CanBeBeneficial(Mobile target, bool message, bool allowDead) { @@ -7650,9 +8469,15 @@ namespace Server #region Harmful Checks/Actions - public virtual bool CanBeHarmful(Mobile target) => CanBeHarmful(target, true); + public virtual bool CanBeHarmful(Mobile target) + { + return CanBeHarmful(target, true); + } - public virtual bool CanBeHarmful(Mobile target, bool message) => CanBeHarmful(target, message, false); + public virtual bool CanBeHarmful(Mobile target, bool message) + { + return CanBeHarmful(target, message, false); + } public virtual bool CanBeHarmful(Mobile target, bool message, bool ignoreOurBlessedness) { @@ -7910,10 +8735,15 @@ namespace Server if (Hits < HitsMax) { - m_HitsTimer ??= new HitsTimer(this); + if (m_HitsTimer == null) + m_HitsTimer = new HitsTimer(this); + m_HitsTimer.Start(); } - else if (Hits > HitsMax) Hits = HitsMax; + else if (Hits > HitsMax) + { + Hits = HitsMax; + } OnRawStrChange(oldValue); OnRawStatChange(StatType.Str, oldValue); @@ -7976,11 +8806,15 @@ namespace Server if (Stam < StamMax) { - m_StamTimer ??= new StamTimer(this); + if (m_StamTimer == null) + m_StamTimer = new StamTimer(this); + m_StamTimer.Start(); } else if (Stam > StamMax) + { Stam = StamMax; + } OnRawDexChange(oldValue); OnRawStatChange(StatType.Dex, oldValue); @@ -8043,11 +8877,15 @@ namespace Server if (Mana < ManaMax) { - m_ManaTimer ??= new ManaTimer(this); + if (m_ManaTimer == null) + m_ManaTimer = new ManaTimer(this); + m_ManaTimer.Start(); } else if (Mana > ManaMax) + { Mana = ManaMax; + } OnRawIntChange(oldValue); OnRawStatChange(StatType.Int, oldValue); @@ -8130,11 +8968,15 @@ namespace Server { if (CanRegenHits) { - m_HitsTimer ??= new HitsTimer(this); + if (m_HitsTimer == null) + m_HitsTimer = new HitsTimer(this); + m_HitsTimer.Start(); } else + { m_HitsTimer?.Stop(); + } } if (m_Hits != value) @@ -8166,7 +9008,9 @@ namespace Server return; if (value < 0) + { value = 0; + } else if (value >= StamMax) { value = StamMax; @@ -8178,11 +9022,15 @@ namespace Server { if (CanRegenStam) { - m_StamTimer ??= new StamTimer(this); + if (m_StamTimer == null) + m_StamTimer = new StamTimer(this); + m_StamTimer.Start(); } else + { m_StamTimer?.Stop(); + } } if (m_Stam != value) @@ -8237,11 +9085,15 @@ namespace Server { if (CanRegenMana) { - m_ManaTimer ??= new ManaTimer(this); + if (m_ManaTimer == null) + m_ManaTimer = new ManaTimer(this); + m_ManaTimer.Start(); } else + { m_ManaTimer?.Stop(); + } } if (m_Mana != value) @@ -8275,6 +9127,8 @@ namespace Server get => m_Poison; set { + /*if ( m_Poison != value && (m_Poison == null || value == null || m_Poison.Level < value.Level) ) + {*/ m_Poison = value; Delta(MobileDelta.HealthbarPoison); @@ -8292,6 +9146,7 @@ namespace Server } CheckStatTimers(); + /*}*/ } } @@ -8487,14 +9342,20 @@ namespace Server [CommandProperty(AccessLevel.GameMaster)] public int HairItemID { - get => m_Hair?.ItemID ?? 0; + get + { + if (m_Hair == null) + return 0; + + return m_Hair.ItemID; + } set { if (m_Hair == null && value > 0) m_Hair = new HairInfo(value); else if (value <= 0) m_Hair = null; - else if (m_Hair != null) + else m_Hair.ItemID = value; Delta(MobileDelta.Hair); @@ -8507,14 +9368,20 @@ namespace Server [CommandProperty(AccessLevel.GameMaster)] public int FacialHairItemID { - get => m_FacialHair?.ItemID ?? 0; + get + { + if (m_FacialHair == null) + return 0; + + return m_FacialHair.ItemID; + } set { if (m_FacialHair == null && value > 0) m_FacialHair = new FacialHairInfo(value); else if (value <= 0) m_FacialHair = null; - else if (m_FacialHair != null) + else m_FacialHair.ItemID = value; Delta(MobileDelta.FacialHair); @@ -8527,7 +9394,12 @@ namespace Server [CommandProperty(AccessLevel.GameMaster)] public int HairHue { - get => m_Hair?.Hue ?? 0; + get + { + if (m_Hair == null) + return 0; + return m_Hair.Hue; + } set { if (m_Hair != null) @@ -8541,7 +9413,13 @@ namespace Server [CommandProperty(AccessLevel.GameMaster)] public int FacialHairHue { - get => m_FacialHair?.Hue ?? 0; + get + { + if (m_FacialHair == null) + return 0; + + return m_FacialHair.Hue; + } set { if (m_FacialHair != null) @@ -8602,7 +9480,7 @@ namespace Server public void FixedEffect(int itemID, int speed, int duration) { - Effects.SendTargetEffect(this, itemID, speed, duration); + Effects.SendTargetEffect(this, itemID, speed, duration, 0, 0); } public void FixedParticles(int itemID, int speed, int duration, int effect, int hue, int renderMode, @@ -8627,9 +9505,9 @@ namespace Server Effects.SendTargetParticles(this, itemID, speed, duration, 0, 0, effect, layer, 0); } - public void BoltEffect() + public void BoltEffect(int hue) { - Effects.SendBoltEffect(this); + Effects.SendBoltEffect(this, true, hue); } #endregion @@ -8665,11 +9543,23 @@ namespace Server return ret; } - public Direction GetDirectionTo(Point2D p) => GetDirectionTo(p.m_X, p.m_Y); + public Direction GetDirectionTo(Point2D p) + { + return GetDirectionTo(p.m_X, p.m_Y); + } - public Direction GetDirectionTo(Point3D p) => GetDirectionTo(p.m_X, p.m_Y); + public Direction GetDirectionTo(Point3D p) + { + return GetDirectionTo(p.m_X, p.m_Y); + } - public Direction GetDirectionTo(IPoint2D p) => p == null ? Direction.North : GetDirectionTo(p.X, p.Y); + public Direction GetDirectionTo(IPoint2D p) + { + if (p == null) + return Direction.North; + + return GetDirectionTo(p.X, p.Y); + } #endregion @@ -8680,16 +9570,19 @@ namespace Server if (m_Map == null) return; + Packet p = ascii + ? (Packet)new AsciiMessage(Serial, Body, type, hue, 3, Name, text) + : new UnicodeMessage(Serial, Body, type, hue, 3, m_Language, Name, text); + + p.Acquire(); + IPooledEnumerable eable = m_Map.GetClientsInRange(m_Location); foreach (NetState state in eable) if (state.Mobile.CanSee(this) && (noLineOfSight || state.Mobile.InLOS(this))) - { - if (ascii) - Packets.SendAsciiMessage(state, Serial, Body, type, hue, 3, Name, text); - else - Packets.SendUnicodeMessage(state, Serial, Body, type, hue, 3, Language, Name, text); - } + state.Send(p); + + Packet.Release(p); eable.Free(); } @@ -8699,11 +9592,15 @@ namespace Server if (m_Map == null) return; + Packet p = Packet.Acquire(new MessageLocalized(Serial, Body, type, hue, 3, number, Name, args)); + IPooledEnumerable eable = m_Map.GetClientsInRange(m_Location); foreach (NetState state in eable) if (state.Mobile.CanSee(this) && (noLineOfSight || state.Mobile.InLOS(this))) - Packets.SendMessageLocalized(state, Serial, Body, type, hue, 3, number, Name, args); + state.Send(p); + + Packet.Release(p); eable.Free(); } @@ -8714,12 +9611,16 @@ namespace Server if (m_Map == null) return; + Packet p = Packet.Acquire(new MessageLocalizedAffix(Serial, Body, type, hue, 3, number, Name, affixType, + affix, args)); + IPooledEnumerable eable = m_Map.GetClientsInRange(m_Location); foreach (NetState state in eable) if (state.Mobile.CanSee(this) && (noLineOfSight || state.Mobile.InLOS(this))) - Packets.SendMessageLocalizedAffix(state, Serial, Body, type, hue, 3, number, Name, affixType, - affix, args); + state.Send(p); + + Packet.Release(p); eable.Free(); } @@ -8730,9 +9631,9 @@ namespace Server return; if (ascii) - Packets.SendAsciiMessage(state, Serial, Body, type, hue, 3, Name, text); + state.Send(new AsciiMessage(Serial, Body, type, hue, 3, Name, text)); else - Packets.SendUnicodeMessage(state, Serial, Body, type, hue, 3, Language, Name, text); + state.Send(new UnicodeMessage(Serial, Body, type, hue, 3, m_Language, Name, text)); } public void PrivateOverheadMessage(MessageType type, int hue, int number, NetState state) @@ -8742,23 +9643,25 @@ namespace Server public void PrivateOverheadMessage(MessageType type, int hue, int number, string args, NetState state) { - Packets.SendMessageLocalized(state, Serial, Body, type, hue, 3, number, Name, args); + state?.Send(new MessageLocalized(Serial, Body, type, hue, 3, number, Name, args)); } public void LocalOverheadMessage(MessageType type, int hue, bool ascii, string text) { - if (m_NetState == null) + NetState ns = m_NetState; + + if (ns == null) return; if (ascii) - Packets.SendAsciiMessage(m_NetState, Serial, Body, type, hue, 3, Name, text); + ns.Send(new AsciiMessage(Serial, Body, type, hue, 3, Name, text)); else - Packets.SendUnicodeMessage(m_NetState, Serial, Body, type, hue, 3, Language, Name, text); + ns.Send(new UnicodeMessage(Serial, Body, type, hue, 3, m_Language, Name, text)); } public void LocalOverheadMessage(MessageType type, int hue, int number, string args = "") { - Packets.SendMessageLocalized(m_NetState, Serial, Body, type, hue, 3, number, Name, args); + m_NetState?.Send(new MessageLocalized(Serial, Body, type, hue, 3, number, Name, args)); } public void NonlocalOverheadMessage(MessageType type, int hue, int number, string args = "") @@ -8766,11 +9669,15 @@ namespace Server if (m_Map == null) return; + Packet p = Packet.Acquire(new MessageLocalized(Serial, Body, type, hue, 3, number, Name, args)); + IPooledEnumerable eable = m_Map.GetClientsInRange(m_Location); foreach (NetState state in eable) if (state != m_NetState && state.Mobile.CanSee(this)) - Packets.SendMessageLocalized(state, Serial, Body, type, hue, 3, number, Name, args); + state.Send(p); + + Packet.Release(p); eable.Free(); } @@ -8780,16 +9687,19 @@ namespace Server if (m_Map == null) return; + Packet p = ascii + ? (Packet)new AsciiMessage(Serial, Body, type, hue, 3, Name, text) + : new UnicodeMessage(Serial, Body, type, hue, 3, Language, Name, text); + + p.Acquire(); + IPooledEnumerable eable = m_Map.GetClientsInRange(m_Location); foreach (NetState state in eable) if (state != m_NetState && state.Mobile.CanSee(this)) - { - if (ascii) - Packets.SendAsciiMessage(state, Serial, Body, type, hue, 3, Name, text); - else - Packets.SendUnicodeMessage(state, Serial, Body, type, hue, 3, Language, Name, text); - } + state.Send(p); + + Packet.Release(p); eable.Free(); } @@ -8798,22 +9708,29 @@ namespace Server #region SendLocalizedMessage - public void SendLocalizedMessage(int number, string args = "", int hue = 0x3B2) + public void SendLocalizedMessage(int number) + { + m_NetState?.Send(MessageLocalized.InstantiateGeneric(number)); + } + + public void SendLocalizedMessage(int number, string args, int hue = 0x3B2) { if (hue == 0x3B2 && string.IsNullOrEmpty(args)) - Packets.SendMessageLocalized(m_NetState, number); + m_NetState?.Send(MessageLocalized.InstantiateGeneric(number)); else - Packets.SendMessageLocalized(m_NetState, Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args); + m_NetState?.Send(new MessageLocalized(Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args)); } public void SendLocalizedMessage(int number, bool append, string affix, string args = "", int hue = 0x3B2) { - Packets.SendMessageLocalizedAffix(m_NetState, Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", - (append ? AffixType.Append : AffixType.Prepend) | AffixType.System, affix, args); + m_NetState?.Send(new MessageLocalizedAffix(Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", + (append ? AffixType.Append : AffixType.Prepend) | AffixType.System, affix, args)); } + #endregion #region Send[ASCII]Message + public void SendMessage(string text) { SendMessage(0x3B2, text); @@ -8826,7 +9743,7 @@ namespace Server public void SendMessage(int hue, string text) { - Packets.SendUnicodeMessage(m_NetState, Serial.MinusOne, -1, MessageType.Regular, hue, 3, "ENU", "System", text); + m_NetState?.Send(new UnicodeMessage(Serial.MinusOne, -1, MessageType.Regular, hue, 3, "ENU", "System", text)); } public void SendMessage(int hue, string format, params object[] args) @@ -8846,36 +9763,46 @@ namespace Server public void SendAsciiMessage(int hue, string text) { - Packets.SendAsciiMessage(m_NetState, Serial.MinusOne, -1, MessageType.Regular, hue, 3, "System", text); + m_NetState?.Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, 3, "System", text)); } public void SendAsciiMessage(int hue, string format, params object[] args) { SendAsciiMessage(hue, string.Format(format, args)); } + #endregion #region InRange - public bool InRange(Point2D p, int range) => - p.m_X >= m_Location.m_X - range - && p.m_X <= m_Location.m_X + range - && p.m_Y >= m_Location.m_Y - range - && p.m_Y <= m_Location.m_Y + range; - public bool InRange(Point3D p, int range) => - p.m_X >= m_Location.m_X - range - && p.m_X <= m_Location.m_X + range - && p.m_Y >= m_Location.m_Y - range - && p.m_Y <= m_Location.m_Y + range; + public bool InRange(Point2D p, int range) + { + return p.m_X >= m_Location.m_X - range + && p.m_X <= m_Location.m_X + range + && p.m_Y >= m_Location.m_Y - range + && p.m_Y <= m_Location.m_Y + range; + } + + public bool InRange(Point3D p, int range) + { + return p.m_X >= m_Location.m_X - range + && p.m_X <= m_Location.m_X + range + && p.m_Y >= m_Location.m_Y - range + && p.m_Y <= m_Location.m_Y + range; + } + + public bool InRange(IPoint2D p, int range) + { + return p.X >= m_Location.m_X - range + && p.X <= m_Location.m_X + range + && p.Y >= m_Location.m_Y - range + && p.Y <= m_Location.m_Y + range; + } - public bool InRange(IPoint2D p, int range) => - p.X >= m_Location.m_X - range - && p.X <= m_Location.m_X + range - && p.Y >= m_Location.m_Y - range - && p.Y <= m_Location.m_Y + range; #endregion #region OnDoubleClick[..] + /// /// Overridable. Event invoked when the Mobile is double clicked. By default, this method can either dismount or open the /// paperdoll. @@ -8927,17 +9854,45 @@ namespace Server if (CanPaperdollBeOpenedBy(from)) DisplayPaperdollTo(from); } + #endregion #region Armor + public Item ShieldArmor => FindItemOnLayer(Layer.TwoHanded); + public Item NeckArmor => FindItemOnLayer(Layer.Neck); + public Item HandArmor => FindItemOnLayer(Layer.Gloves); + public Item HeadArmor => FindItemOnLayer(Layer.Helm); + public Item ArmsArmor => FindItemOnLayer(Layer.Arms); - public Item LegsArmor => FindItemOnLayer(Layer.InnerLegs) ?? FindItemOnLayer(Layer.Pants); - public Item ChestArmor => FindItemOnLayer(Layer.InnerTorso) ?? FindItemOnLayer(Layer.Shirt); + + public Item LegsArmor + { + get + { + if (!(FindItemOnLayer(Layer.InnerLegs) is Item ar)) + ar = FindItemOnLayer(Layer.Pants); + + return ar; + } + } + + public Item ChestArmor + { + get + { + if (!(FindItemOnLayer(Layer.InnerTorso) is Item ar)) + ar = FindItemOnLayer(Layer.Shirt); + + return ar; + } + } + public Item Talisman => FindItemOnLayer(Layer.Talisman); + #endregion } } diff --git a/Projects/Server/Movement.cs b/Projects/Server/Movement.cs index 4d2748ffc..6544f6767 100644 --- a/Projects/Server/Movement.cs +++ b/Projects/Server/Movement.cs @@ -18,7 +18,7 @@ * ***************************************************************************/ -namespace Server +namespace Server.Movement { public static class Movement { diff --git a/Projects/Server/Network/Listener.cs b/Projects/Server/Network/Listener.cs index 5865f3b31..2146f9e16 100644 --- a/Projects/Server/Network/Listener.cs +++ b/Projects/Server/Network/Listener.cs @@ -76,7 +76,7 @@ namespace Server.Network DisplayListener(); - while (!Core.Closing) + while (true) { Socket s; try @@ -90,7 +90,7 @@ namespace Server.Network } if (VerifySocket(s)) - new NetState(s, pump); + _ = new NetState(s, pump); else Release(s); } @@ -105,9 +105,12 @@ namespace Server.Network { NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface adapter in adapters) - foreach (UnicastIPAddressInformation unicast in adapter.GetIPProperties().UnicastAddresses) - if (ipep.AddressFamily == unicast.Address.AddressFamily) - Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port); + { + IPInterfaceProperties properties = adapter.GetIPProperties(); + foreach (UnicastIPAddressInformation unicast in properties.UnicastAddresses) + if (ipep.AddressFamily == unicast.Address.AddressFamily) + Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port); + } } else { diff --git a/Projects/Server/Network/NetState.cs b/Projects/Server/Network/NetState.cs index bba0c0a3b..14355146d 100644 --- a/Projects/Server/Network/NetState.cs +++ b/Projects/Server/Network/NetState.cs @@ -26,13 +26,14 @@ using System.IO; using System.IO.Pipelines; using System.Net; using System.Net.Sockets; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Server.Accounting; +using Server.Diagnostics; using Server.Gumps; +using Server.HuePickers; using Server.Items; using Server.Menus; -using NetworkPackets = Server.Network.Packets; namespace Server.Network { @@ -92,6 +93,7 @@ namespace Server.Network { private string m_ToString; private ClientVersion m_Version; + private SendQueue m_SendQueue = new SendQueue(); public DateTime ConnectedOn { get; } @@ -109,8 +111,6 @@ namespace Server.Network private static AsyncState m_AsyncState = m_ResumeState; - public bool UseCompression { get; set; } - public IPacketEncoder PacketEncoder { get; set; } public static NetStateCreatedCallback CreatedCallback { get; set; } @@ -158,8 +158,7 @@ namespace Server.Network ProtocolChanges = ProtocolChanges.Version500a; else if (value >= m_Version407a) ProtocolChanges = ProtocolChanges.Version407a; - else if (value >= m_Version400a) - ProtocolChanges = ProtocolChanges.Version400a; + else if (value >= m_Version400a) ProtocolChanges = ProtocolChanges.Version400a; } } @@ -273,7 +272,9 @@ namespace Server.Network public Socket Socket { get; private set; } - public byte Sequence { get; set; } + public bool CompressionEnabled { get; set; } + + public int Sequence { get; set; } public List Gumps { get; private set; } @@ -299,7 +300,8 @@ namespace Server.Network public void AddMenu(IMenu menu) { - Menus ??= new List(); + if (Menus == null) + Menus = new List(); if (Menus.Count < MenuCap) Menus.Add(menu); @@ -327,7 +329,8 @@ namespace Server.Network public void AddHuePicker(HuePicker huePicker) { - HuePickers ??= new List(); + if (HuePickers == null) + HuePickers = new List(); if (HuePickers.Count < HuePickerCap) HuePickers.Add(huePicker); @@ -355,7 +358,8 @@ namespace Server.Network public void AddGump(Gump gump) { - Gumps ??= new List(); + if (Gumps == null) + Gumps = new List(); if (Gumps.Count < GumpCap) Gumps.Add(gump); @@ -383,8 +387,8 @@ namespace Server.Network public void LaunchBrowser(string url) { - NetworkPackets.SendMessageLocalized(this, Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231); - NetworkPackets.SendLaunchBrowser(this, url); + Send(new MessageLocalized(Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231, "", "")); + Send(new LaunchBrowser(url)); } public CityInfo[] CityInfo { get; set; } @@ -442,6 +446,17 @@ namespace Server.Network m_AsyncState = Interlocked.Exchange(ref m_AsyncState, m_ResumeState); } + public virtual void Send(Packet p) + { + if (Socket == null || BlockAllPackets) + { + p.OnSend(); + return; + } + + m_SendQueue.Enqueue(p); + } + public bool CheckEncrypted(int packetID) { if (!SentFirstPacket && packetID != 0xF0 && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 && @@ -455,35 +470,32 @@ namespace Server.Network return false; } - public Pipe RecvdPipe { get; private set; } - public Pipe SendPipe { get; private set; } + private Pipe m_RecvdPipe; private async Task Start(MessagePump pump) { - RecvdPipe = new Pipe(); - SendPipe = new Pipe(); + m_RecvdPipe = new Pipe(); Running = true; - await Task.WhenAll(HandlePackets(pump), ProcessSends(), ProcessRecvs()); + await Task.WhenAll(ProcessSends(), ProcessRecvs(), HandlePackets(pump)).ConfigureAwait(false); } private async Task ProcessRecvs() { - PipeWriter w = RecvdPipe.Writer; + PipeWriter w = m_RecvdPipe.Writer; - while (!Core.Closing) + while (true) { if (m_AsyncState.Paused) { - Interlocked.Exchange(ref m_NextCheckActivity, Core.TickCount + 90000); - await Timer.Pause(50); + await Timer.Pause(50).ConfigureAwait(false); continue; } try { Memory memory = w.GetMemory(); - int bytesRead = await Socket.ReceiveAsync(memory, SocketFlags.None); + int bytesRead = await Socket.ReceiveAsync(memory, SocketFlags.None).ConfigureAwait(false); if (bytesRead == 0) break; @@ -491,7 +503,7 @@ namespace Server.Network w.Advance(bytesRead); - FlushResult result = await w.FlushAsync(); + FlushResult result = await w.FlushAsync().ConfigureAwait(false); if (result.IsCompleted || result.IsCanceled) break; } @@ -505,7 +517,7 @@ namespace Server.Network Dispose(); } - private async Task HandlePackets(MessagePump pump) + private async Task ProcessSends() { while (true) try @@ -514,31 +526,26 @@ namespace Server.Network if (p == null) break; - long pos = PacketHandlers.ProcessPacket(pump, this, seq); + ReadOnlyMemory buffer = p.Compile(CompressionEnabled, out int length); - if (pos <= 0) - break; + if (buffer.Length <= 0 || length <= 0) + { + p.OnSend(); + return; + } - pr.AdvanceTo(seq.GetPosition(pos, seq.Start)); + buffer = buffer.Slice(0, length); - if (result.IsCompleted || result.IsCanceled) - break; - } + PacketSendProfile prof = null; - pr.Complete(); - } + if (Core.Profiling) + prof = PacketSendProfile.Acquire(p.GetType()); - public async Task Flush(int bytesWritten) - { - if (IsDisposing || BlockAllPackets) - return; + prof?.Start(); - SendPipe.Writer.Advance(bytesWritten); - FlushResult result = await SendPipe.Writer.FlushAsync(); + await Socket.SendAsync(buffer, SocketFlags.None).ConfigureAwait(false); - if (result.IsCompleted || result.IsCanceled) - Dispose(); - } + p.OnSend(); prof?.Finish(length); } @@ -555,44 +562,29 @@ namespace Server.Network } } - private async Task ProcessSends() + private async Task HandlePackets(MessagePump pump) { - PipeReader pr = SendPipe.Reader; + PipeReader pr = m_RecvdPipe.Reader; - while (!Core.Closing) + while (true) { - if (m_AsyncState.Paused) - { - await Timer.Pause(50); - continue; - } - ReadResult result = await pr.ReadAsync(); ReadOnlySequence seq = result.Buffer; if (seq.Length == 0) break; - if (!SequenceMarshal.TryGetReadOnlyMemory(seq, out ReadOnlyMemory memory)) + long pos = PacketHandlers.ProcessPacket(pump, this, seq); + + if (pos <= 0) break; - try - { - int bytesWritten = await Socket.SendAsync(memory, SocketFlags.None); - - pr.AdvanceTo(seq.GetPosition(bytesWritten)); - } - catch (SocketException ex) - { - Console.WriteLine(ex); - TraceException(ex); - break; - } + pr.AdvanceTo(seq.GetPosition(pos, seq.Start)); if (result.IsCompleted || result.IsCanceled) break; } - Dispose(); + pr.Complete(); } public PacketHandler GetHandler(int packetID) => @@ -647,17 +639,17 @@ namespace Server.Network Task.Run(async () => { - RecvdPipe.Reader.CancelPendingRead(); - RecvdPipe.Reader.Complete(); - await SendPipe.Writer.FlushAsync(); - SendPipe.Writer.Complete(); + m_RecvdPipe.Reader.CancelPendingRead(); + m_RecvdPipe.Reader.Complete(); + await m_RecvdPipe.Writer.FlushAsync().ConfigureAwait(false); + m_RecvdPipe.Writer.Complete(); try { Socket.Shutdown(SocketShutdown.Both); } catch (Exception ex) { TraceException(ex); } try { Socket.Close(); } catch (Exception ex) { TraceException(ex); } Socket = null; - RecvdPipe = null; - SendPipe = null; + m_RecvdPipe = null; + m_SendQueue = null; m_Disposed.Enqueue(this); }); } diff --git a/Projects/Server/Network/Packet.cs b/Projects/Server/Network/Packet.cs new file mode 100644 index 000000000..bb96362d5 --- /dev/null +++ b/Projects/Server/Network/Packet.cs @@ -0,0 +1,267 @@ +/*************************************************************************** + * Packet.cs + * ------------------- + * begin : August 2, 2019 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using Server.Diagnostics; +using System; +using System.Buffers; +using System.Diagnostics; +using System.IO; + +namespace Server.Network +{ + public abstract class Packet + { + private const int CompressorBufferSize = 0x10000; + + private const int BufferSize = 4096; + + private byte[] m_CompiledBuffer; + private int m_CompiledLength; + private int m_Length; + private State m_State; + + protected PacketWriter m_Stream; + + protected Packet(int packetID) + { + PacketID = packetID; + + if (Core.Profiling) + { + PacketSendProfile prof = PacketSendProfile.Acquire(GetType()); + prof.Increment(); + } + } + + protected Packet(int packetID, int length) + { + PacketID = packetID; + m_Length = length; + + m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length ); + m_Stream.Write((byte)packetID); + + if (Core.Profiling) + { + PacketSendProfile prof = PacketSendProfile.Acquire(GetType()); + prof.Increment(); + } + } + + public int PacketID { get; } + + public PacketWriter UnderlyingStream => m_Stream; + + public void EnsureCapacity(int length) + { + m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length ); + m_Stream.Write((byte)PacketID); + m_Stream.Write((short)0); + } + + public static Packet SetStatic(Packet p) + { + p.SetStatic(); + return p; + } + + public static Packet Acquire(Packet p) + { + p.Acquire(); + return p; + } + + public static void Release(ref Packet p) + { + p?.Release(); + p = null; + } + + public static void Release(Packet p) + { + p?.Release(); + } + + public void SetStatic() + { + m_State |= State.Static | State.Acquired; + } + + public void Acquire() + { + m_State |= State.Acquired; + } + + public void OnSend() + { + Core.Set(); // Is this still needed if this is done async? + + if ((m_State & (State.Acquired | State.Static)) == 0) + Free(); + } + + private void Free() + { + if (m_CompiledBuffer == null) + return; + + if ((m_State & State.Buffered) != 0) + ArrayPool.Shared.Return(m_CompiledBuffer); + + m_State &= ~(State.Static | State.Acquired | State.Buffered); + + m_CompiledBuffer = null; + } + + public void Release() + { + if ((m_State & State.Acquired) != 0) + Free(); + } + + public byte[] Compile(bool compress, out int length) + { + lock (this) + { + if (m_CompiledBuffer == null) + { + if ((m_State & State.Accessed) == 0) + { + m_State |= State.Accessed; + } + else + { + if ((m_State & State.Warned) == 0) + { + m_State |= State.Warned; + + try + { + using StreamWriter op = new StreamWriter("net_opt.log", true); + op.WriteLine("Redundant compile for packet {0}, use Acquire() and Release()", GetType()); + op.WriteLine(new StackTrace()); + } + catch + { + // ignored + } + } + + m_CompiledBuffer = new byte[0]; + m_CompiledLength = 0; + + length = m_CompiledLength; + return m_CompiledBuffer; + } + + InternalCompile(compress); + } + + length = m_CompiledLength; + return m_CompiledBuffer; + } + } + + private void InternalCompile(bool compress) + { + if (m_Length == 0) + { + long streamLen = m_Stream.Length; + + m_Stream.Seek(1, SeekOrigin.Begin); + m_Stream.Write((ushort)streamLen); + } + else if (m_Stream.Length != m_Length) + { + int diff = (int)m_Stream.Length - m_Length; + + Console.WriteLine("Packet: 0x{0:X2}: Bad packet length! ({1}{2} bytes)", PacketID, diff >= 0 ? "+" : "", + diff); + } + + MemoryStream ms = m_Stream.UnderlyingStream; + + m_CompiledBuffer = ms.GetBuffer(); + int length = (int)ms.Length; + + if (compress) + { + byte[] buffer = ArrayPool.Shared.Rent(CompressorBufferSize); + + Compression.Compress(m_CompiledBuffer, 0, length, buffer, out length); + + if (length <= 0) + { + Console.WriteLine("Warning: Compression buffer overflowed on packet 0x{0:X2} ('{1}') (length={2})", + PacketID, GetType().Name, length); + using StreamWriter op = new StreamWriter("compression_overflow.log", true); + op.WriteLine("{0} Warning: Compression buffer overflowed on packet 0x{1:X2} ('{2}') (length={3})", + DateTime.UtcNow, PacketID, GetType().Name, length); + op.WriteLine(new StackTrace()); + } + else + { + m_CompiledLength = length; + + if ((m_State & State.Static) != 0) + { + m_CompiledBuffer = new byte[length]; + Buffer.BlockCopy(buffer, 0, m_CompiledBuffer, 0, length); + ArrayPool.Shared.Return(buffer); + } + else + { + m_CompiledBuffer = buffer; + m_State |= State.Buffered; + } + } + } + else if (length > 0) + { + byte[] old = m_CompiledBuffer; + m_CompiledLength = length; + + if ((m_State & State.Static) != 0) + m_CompiledBuffer = new byte[length]; + else + { + m_CompiledBuffer = ArrayPool.Shared.Rent(length); + m_State |= State.Buffered; + } + + Buffer.BlockCopy(old, 0, m_CompiledBuffer, 0, length); + } + + PacketWriter.ReleaseInstance(m_Stream); + m_Stream = null; + } + + [Flags] + private enum State + { + Inactive = 0x00, + Static = 0x01, + Acquired = 0x02, + Accessed = 0x04, + Buffered = 0x08, + Warned = 0x10 + } + } +} diff --git a/Projects/Server/Network/PacketHandlers.cs b/Projects/Server/Network/PacketHandlers.cs index b29769a26..37ec26672 100644 --- a/Projects/Server/Network/PacketHandlers.cs +++ b/Projects/Server/Network/PacketHandlers.cs @@ -26,6 +26,7 @@ using Server.Accounting; using Server.ContextMenus; using Server.Diagnostics; using Server.Gumps; +using Server.HuePickers; using Server.Items; using Server.Menus; using Server.Prompts; @@ -55,6 +56,11 @@ namespace Server.Network public static class PacketHandlers { + public delegate void PlayCharCallback(NetState state, bool val); + + private const int BadFood = unchecked((int)0xBAADF00D); + private const int BadUOTD = unchecked((int)0xFFCEFFCE); + private const int m_AuthIDWindowSize = 128; private static PacketHandler[] m_6017Handlers; @@ -103,32 +109,43 @@ namespace Server.Network Register(0x01, 5, false, Disconnect); Register(0x02, 7, true, MovementReq); Register(0x03, 0, true, AsciiSpeech); + Register(0x04, 2, true, GodModeRequest); Register(0x05, 5, true, AttackReq); Register(0x06, 5, true, UseReq); Register(0x07, 7, true, LiftReq); Register(0x08, 14, true, DropReq); Register(0x09, 5, true, LookReq); + Register(0x0A, 11, true, Edit); Register(0x12, 0, true, TextCommand); Register(0x13, 10, true, EquipReq); + Register(0x14, 6, true, ChangeZ); Register(0x22, 3, true, Resynchronize); Register(0x2C, 2, true, DeathStatusResponse); Register(0x34, 10, true, MobileQuery); Register(0x3A, 0, true, ChangeSkillLock); Register(0x3B, 0, true, VendorBuyReply); + Register(0x47, 11, true, NewTerrain); + Register(0x48, 73, true, NewAnimData); + Register(0x58, 106, true, NewRegion); Register(0x5D, 73, false, PlayCharacter); + Register(0x61, 9, true, DeleteStatic); Register(0x6C, 19, true, TargetResponse); Register(0x6F, 0, true, SecureTrade); Register(0x72, 5, true, SetWarMode); Register(0x73, 2, false, PingReq); Register(0x75, 35, true, RenameRequest); + Register(0x79, 9, true, ResourceQuery); + Register(0x7E, 2, true, GodviewQuery); Register(0x7D, 13, true, MenuResponse); Register(0x80, 62, false, AccountLogin); Register(0x83, 39, false, DeleteCharacter); Register(0x91, 65, false, GameLogin); Register(0x95, 9, true, HuePickerResponse); + Register(0x96, 0, true, GameCentralMoniter); Register(0x98, 0, true, MobileNameRequest); Register(0x9A, 0, true, AsciiPromptResponse); Register(0x9B, 258, true, HelpRequest); + Register(0x9D, 51, true, GMSingle); Register(0x9F, 0, true, VendorSellReply); Register(0xA0, 3, false, PlayServer); Register(0xA4, 149, false, SystemInfo); @@ -144,6 +161,8 @@ namespace Server.Network Register(0xBF, 0, true, ExtendedCommand); Register(0xC2, 0, true, UnicodePromptResponse); Register(0xC8, 2, true, SetUpdateRange); + Register(0xC9, 6, true, TripTime); + Register(0xCA, 6, true, UTripTime); Register(0xCF, 0, false, AccountLogin); Register(0xD0, 0, true, ConfigurationFile); Register(0xD1, 2, true, LogoutReq); @@ -195,7 +214,9 @@ namespace Server.Network public static void Register(int packetID, int length, bool ingame, OnPacketReceive onReceive) { Handlers[packetID] = new PacketHandler(packetID, length, ingame, onReceive); - m_6017Handlers[packetID] ??= new PacketHandler(packetID, length, ingame, onReceive); + + if (m_6017Handlers[packetID] == null) + m_6017Handlers[packetID] = new PacketHandler(packetID, length, ingame, onReceive); } public static PacketHandler GetHandler(int packetID) => Handlers[packetID]; @@ -321,8 +342,6 @@ namespace Server.Network return -1; } - // Console.WriteLine("Packet Handler {0:X}", handler.PacketID); - long packetLength = handler.Length; if (handler.Length <= 0 && r.Length >= 3) { @@ -394,9 +413,9 @@ namespace Server.Network public static void EncodedCommand(NetState state, PacketReader pvSrc) { IEntity e = World.FindEntity(pvSrc.ReadUInt32()); - int packetId = pvSrc.ReadUInt16(); + int packetID = pvSrc.ReadUInt16(); - EncodedPacketHandler ph = GetEncodedHandler(packetId); + EncodedPacketHandler ph = GetEncodedHandler(packetID); if (ph != null) { @@ -404,7 +423,7 @@ namespace Server.Network { Console.WriteLine( "Client: {0}: Sent ingame packet (0xD7x{1:X2}) before having been attached to a mobile", state, - packetId); + packetID); state.Dispose(); } else if (ph.Ingame && state.Mobile.Deleted) @@ -517,30 +536,37 @@ namespace Server.Network if (vendor == null) return; - if (vendor.Deleted || !Utility.RangeCheck(vendor.Location, state.Mobile.Location, 10) || flag != 0x02) + if (vendor.Deleted || !Utility.RangeCheck(vendor.Location, state.Mobile.Location, 10)) { - Packets.SendEndVendorBuyOrSell(state, vendor.Serial); + state.Send(new EndVendorBuy(vendor)); return; } - msgSize -= 1 + 2 + 4 + 1; - - if (msgSize / 7 > 100) - return; - - List buyList = new List(msgSize / 7); - while (msgSize > 0) + if (flag == 0x02) { - pvSrc.ReadByte(); // layer - Serial serial = pvSrc.ReadUInt32(); - int amount = pvSrc.ReadInt16(); + msgSize -= 1 + 2 + 4 + 1; - buyList.Add(new BuyItemResponse(serial, amount)); - msgSize -= 7; + if (msgSize / 7 > 100) + return; + + List buyList = new List(msgSize / 7); + while (msgSize > 0) + { + byte layer = pvSrc.ReadByte(); + Serial serial = pvSrc.ReadUInt32(); + int amount = pvSrc.ReadInt16(); + + buyList.Add(new BuyItemResponse(serial, amount)); + msgSize -= 7; + } + + if (buyList.Count > 0 && vendor is IVendor v && v.OnBuyItems(state.Mobile, buyList)) + state.Send(new EndVendorBuy(vendor)); + } + else + { + state.Send(new EndVendorBuy(vendor)); } - - if (buyList.Count > 0 && vendor is IVendor v && v.OnBuyItems(state.Mobile, buyList)) - Packets.SendEndVendorBuyOrSell(state, vendor.Serial); } public static void VendorSellReply(NetState state, PacketReader pvSrc) @@ -552,7 +578,7 @@ namespace Server.Network if (vendor.Deleted || !Utility.RangeCheck(vendor.Location, state.Mobile.Location, 10)) { - Packets.SendEndVendorBuyOrSell(state, vendor.Serial); + state.Send(new EndVendorSell(vendor)); return; } @@ -564,14 +590,14 @@ namespace Server.Network for (int i = 0; i < count; i++) { Item item = World.FindItem(pvSrc.ReadUInt32()); - int amount = pvSrc.ReadInt16(); + int Amount = pvSrc.ReadInt16(); - if (item != null && amount > 0) - sellList.Add(new SellItemResponse(item, amount)); + if (item != null && Amount > 0) + sellList.Add(new SellItemResponse(item, Amount)); } if (sellList.Count > 0 && vendor is IVendor v && v.OnSellItems(state.Mobile, sellList)) - Packets.SendEndVendorBuyOrSell(state, vendor.Serial); + state.Send(new EndVendorSell(vendor)); } } @@ -583,6 +609,39 @@ namespace Server.Network EventSink.InvokeDeleteRequest(new DeleteRequestEventArgs(state, index)); } + public static void ResourceQuery(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + { + } + } + + public static void GameCentralMoniter(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + { + int type = pvSrc.ReadByte(); + int num1 = pvSrc.ReadInt32(); + + Console.WriteLine("God Client: {0}: Game central moniter", state); + Console.WriteLine(" - Type: {0}", type); + Console.WriteLine(" - Number: {0}", num1); + + pvSrc.Trace(state); + } + } + + public static void GodviewQuery(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) Console.WriteLine("God Client: {0}: Godview query 0x{1:X}", state, pvSrc.ReadByte()); + } + + public static void GMSingle(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + pvSrc.Trace(state); + } + public static void DeathStatusResponse(NetState state, PacketReader pvSrc) { // Ignored @@ -618,7 +677,7 @@ namespace Server.Network Mobile m = World.FindMobile(pvSrc.ReadUInt32()); if (m != null && Utility.InUpdateRange(state.Mobile, m) && state.Mobile.CanSee(m)) - Packets.SendMobileName(state, m); + state.Send(new MobileName(m)); } public static void RequestScrollWindow(NetState state, PacketReader pvSrc) @@ -655,6 +714,34 @@ namespace Server.Network } } + public static void TripTime(NetState state, PacketReader pvSrc) + { + int unk1 = pvSrc.ReadByte(); + int unk2 = pvSrc.ReadInt32(); + + state.Send(new TripTimeResponse(unk1)); + } + + public static void UTripTime(NetState state, PacketReader pvSrc) + { + int unk1 = pvSrc.ReadByte(); + int unk2 = pvSrc.ReadInt32(); + + state.Send(new UTripTimeResponse(unk1)); + } + + public static void ChangeZ(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + { + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int z = pvSrc.ReadSByte(); + + Console.WriteLine("God Client: {0}: Change Z ({1}, {2}, {3})", state, x, y, z); + } + } + public static void SystemInfo(NetState state, PacketReader pvSrc) { int v1 = pvSrc.ReadByte(); @@ -671,6 +758,83 @@ namespace Server.Network int v8 = pvSrc.ReadInt32(); } + public static void Edit(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + { + int type = pvSrc.ReadByte(); // 10 = static, 7 = npc, 4 = dynamic + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int id = pvSrc.ReadInt16(); + int z = pvSrc.ReadSByte(); + int hue = pvSrc.ReadUInt16(); + + Console.WriteLine("God Client: {0}: Edit {6} ({1}, {2}, {3}) 0x{4:X} (0x{5:X})", state, x, y, z, id, hue, + type); + } + } + + public static void DeleteStatic(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + { + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int z = pvSrc.ReadInt16(); + int id = pvSrc.ReadUInt16(); + + Console.WriteLine("God Client: {0}: Delete Static ({1}, {2}, {3}) 0x{4:X}", state, x, y, z, id); + } + } + + public static void NewAnimData(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + { + Console.WriteLine("God Client: {0}: New tile animation", state); + + pvSrc.Trace(state); + } + } + + public static void NewTerrain(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + { + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int id = pvSrc.ReadUInt16(); + int width = pvSrc.ReadInt16(); + int height = pvSrc.ReadInt16(); + + Console.WriteLine("God Client: {0}: New Terrain ({1}, {2})+({3}, {4}) 0x{5:X4}", state, x, y, width, height, + id); + } + } + + public static void NewRegion(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + { + string name = pvSrc.ReadString(40); + int unk = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int width = pvSrc.ReadInt16(); + int height = pvSrc.ReadInt16(); + int zStart = pvSrc.ReadInt16(); + int zEnd = pvSrc.ReadInt16(); + string desc = pvSrc.ReadString(40); + int soundFX = pvSrc.ReadInt16(); + int music = pvSrc.ReadInt16(); + int nightFX = pvSrc.ReadInt16(); + int dungeon = pvSrc.ReadByte(); + int light = pvSrc.ReadInt16(); + + Console.WriteLine("God Client: {0}: New Region '{1}' ('{2}')", state, name, desc); + } + } + public static void AccountID(NetState state, PacketReader pvSrc) { } @@ -806,6 +970,12 @@ namespace Server.Network } } + public static void GodModeRequest(NetState state, PacketReader pvSrc) + { + if (VerifyGC(state)) + state.Send(new GodModeReply(pvSrc.ReadBoolean())); + } + public static void AsciiPromptResponse(NetState state, PacketReader pvSrc) { uint serial = pvSrc.ReadUInt32(); @@ -1030,12 +1200,14 @@ namespace Server.Network public static void LogoutReq(NetState state, PacketReader pvSrc) { - Packets.SendLogoutAck(state); + state.Send(new LogoutAck()); } public static void ChangeSkillLock(NetState state, PacketReader pvSrc) { - state.Mobile.Skills[pvSrc.ReadInt16()]?.SetLockNoRelay((SkillLock)pvSrc.ReadByte()); + Skill s = state.Mobile.Skills[pvSrc.ReadInt16()]; + + s?.SetLockNoRelay((SkillLock)pvSrc.ReadByte()); } public static void HelpRequest(NetState state, PacketReader pvSrc) @@ -1046,13 +1218,13 @@ namespace Server.Network public static void TargetResponse(NetState state, PacketReader pvSrc) { int type = pvSrc.ReadByte(); - int targetId = pvSrc.ReadInt32(); + int targetID = pvSrc.ReadInt32(); int flags = pvSrc.ReadByte(); Serial serial = pvSrc.ReadUInt32(); int x = pvSrc.ReadInt16(), y = pvSrc.ReadInt16(), z = pvSrc.ReadInt16(); int graphic = pvSrc.ReadUInt16(); - if (targetId == unchecked((int)0xDEADBEEF)) + if (targetID == unchecked((int)0xDEADBEEF)) return; Mobile from = state.Mobile; @@ -1072,7 +1244,7 @@ namespace Server.Network // User pressed escape t.Cancel(from, TargetCancelType.Canceled); } - else if (t.TargetID != targetId) + else if (t.TargetID != targetID) { // Sanity, prevent fake target } @@ -1095,28 +1267,42 @@ namespace Server.Network t.Cancel(from, TargetCancelType.Canceled); return; } - - StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y, !t.DisallowMultis); - - if (state.HighSeas) + else { - ItemData id = TileData.ItemTable[graphic & TileData.MaxItemValue]; - if (id.Surface) z -= id.Height; - } + StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y, !t.DisallowMultis); - if (tiles.All(tile => tile.Z != z || tile.ID != graphic)) - { - t.Cancel(from, TargetCancelType.Canceled); - return; - } + bool valid = false; - toTarget = new StaticTarget(new Point3D(x, y, z), graphic); + if (state.HighSeas) + { + ItemData id = TileData.ItemTable[graphic & TileData.MaxItemValue]; + if (id.Surface) z -= id.Height; + } + + for (int i = 0; !valid && i < tiles.Length; ++i) + if (tiles[i].Z == z && tiles[i].ID == graphic) + valid = true; + + if (!valid) + { + t.Cancel(from, TargetCancelType.Canceled); + return; + } + else + { + toTarget = new StaticTarget(new Point3D(x, y, z), graphic); + } + } } } else if (serial.IsMobile) + { toTarget = World.FindMobile(serial); + } else if (serial.IsItem) + { toTarget = World.FindItem(serial); + } else { t.Cancel(from, TargetCancelType.Canceled); @@ -1252,8 +1438,13 @@ namespace Server.Network { Mobile m = state.Mobile; - Packets.SendMobileUpdate(state, m); - Packets.SendMobileIncoming(state, m, m); + if (state.StygianAbyss) + state.Send(new MobileUpdate(m)); + else + state.Send(new MobileUpdateOld(m)); + + state.Send(MobileIncoming.Create(state, m, m)); + m.SendEverything(); state.Sequence = 0; @@ -1305,24 +1496,24 @@ namespace Server.Network for (int i = 0; i < count; ++i) { - int speechId; + int speechID; if ((i & 1) == 0) { hold <<= 8; hold |= pvSrc.ReadByte(); - speechId = hold; + speechID = hold; hold = 0; } else { value = pvSrc.ReadInt16(); - speechId = (value & 0xFFF0) >> 4; + speechID = (value & 0xFFF0) >> 4; hold = value & 0xF; } - if (!keyList.Contains(speechId)) - keyList.Add(speechId); + if (!keyList.Contains(speechID)) + keyList.Add(speechID); } text = pvSrc.ReadUTF8StringSafe(); @@ -1359,7 +1550,9 @@ namespace Server.Network uint value = pvSrc.ReadUInt32(); if ((value & ~0x7FFFFFFF) != 0) + { from.OnPaperdollRequest(); + } else { Serial s = value; @@ -1383,7 +1576,9 @@ namespace Server.Network from.NextActionTime = Core.TickCount + Mobile.ActionDelay; } else + { from.SendActionMessage(); + } } public static void LookReq(NetState state, PacketReader pvSrc) @@ -1399,7 +1594,9 @@ namespace Server.Network if (m != null && from.CanSee(m) && Utility.InUpdateRange(from, m)) { if (SingleClickProps) + { m.OnAosSingleClick(from); + } else { if (from.Region.OnSingleClick(from, m)) @@ -1415,7 +1612,9 @@ namespace Server.Network Utility.InUpdateRange(from.Location, item.GetWorldLocation())) { if (SingleClickProps) + { item.OnAosSingleClick(from); + } else if (from.Region.OnSingleClick(from, item)) { if (item.Parent is Item item1) @@ -1429,25 +1628,25 @@ namespace Server.Network public static void PingReq(NetState state, PacketReader pvSrc) { - Packets.SendPingAck(state, pvSrc.ReadByte()); + state.Send(PingAck.Instantiate(pvSrc.ReadByte())); } public static void SetUpdateRange(NetState state, PacketReader pvSrc) { - Packets.SendChangeUpdateRange(state); + state.Send(ChangeUpdateRange.Instantiate(18)); } public static void MovementReq(NetState state, PacketReader pvSrc) { Direction dir = (Direction)pvSrc.ReadByte(); - byte seq = pvSrc.ReadByte(); - pvSrc.ReadInt32(); // key + int seq = pvSrc.ReadByte(); + int key = pvSrc.ReadInt32(); Mobile m = state.Mobile; if (state.Sequence == 0 && seq != 0 || !m.Move(dir)) { - Packets.SendMovementRej(state, seq, m); + state.Send(new MovementRej(seq, m)); state.Sequence = 0; m.ClearFastwalkStack(); @@ -1456,7 +1655,7 @@ namespace Server.Network { ++seq; - if (seq == 0) + if (seq == 256) seq = 1; state.Sequence = seq; @@ -1489,7 +1688,7 @@ namespace Server.Network { int packetID = pvSrc.ReadUInt16(); - // Console.WriteLine("Extended Packet: {0:X}", packetID); + Console.WriteLine("Extended Packet: {0:X}", packetID); PacketHandler ph = GetExtendedHandler(packetID); if (ph == null) @@ -1863,6 +2062,13 @@ namespace Server.Network if (m != null) switch (type) { + case 0x00: // Unknown, sent by godclient + { + if (VerifyGC(state)) + Console.WriteLine("God Client: {0}: Query 0x{1:X2} on {2} '{3}'", state, type, m.Serial, m.Name); + + break; + } case 0x04: // Stats { m.OnStatsQuery(from); @@ -1887,17 +2093,47 @@ namespace Server.Network string name = pvSrc.ReadString(30); - pvSrc.ReadInt16(); // Unknown - + pvSrc.Seek(2, SeekOrigin.Current); int flags = pvSrc.ReadInt32(); - pvSrc.Seek(24, SeekOrigin.Current); +/* if (FeatureProtection.DisabledFeatures != 0 && ThirdPartyAuthCallback != null) + { + bool authOK = false; + + ulong razorFeatures = ((ulong)pvSrc.ReadUInt32() << 32) | pvSrc.ReadUInt32(); + + if (razorFeatures == (ulong)FeatureProtection.DisabledFeatures) + { + bool doesNotMatch = false; + for (int i = 0; !doesNotMatch && i < m_ThirdPartyAuthKey.Length; i++) + doesNotMatch = pvSrc.ReadByte() != m_ThirdPartyAuthKey[i]; + + if (!doesNotMatch) + authOK = true; + } + else + { + pvSrc.Seek(16, SeekOrigin.Current); + } + + ThirdPartyAuthCallback(state, authOK); + }*/ +/* else + {*/ + pvSrc.Seek(24, SeekOrigin.Current); +/* }*/ + +/* if (ThirdPartyHackedCallback != null) + { + pvSrc.Seek(-2, SeekOrigin.Current); + if (pvSrc.ReadUInt16() == 0xDEAD) + ThirdPartyHackedCallback(state, true); + }*/ if (!state.Running) return; int charSlot = pvSrc.ReadInt32(); - // TODO: Handle IP address. int clientIP = pvSrc.ReadInt32(); IAccount a = state.Account; @@ -1916,7 +2152,7 @@ namespace Server.Network if (check != null && check.Map != Map.Internal && check != m) { Console.WriteLine("Login: {0}: Account in use", state); - Packets.SendPopupMessage(state, PMMessage.CharInWorld); + state.Send(new PopupMessage(PMMessage.CharInWorld)); return; } } @@ -1931,9 +2167,11 @@ namespace Server.Network // TODO: Make this wait one tick so we don't have to call it unnecessarily NetState.ProcessDisposedQueue(); - Packets.SendClientVersionReq(state); + + state.Send(new ClientVersionReq()); state.BlockAllPackets = true; + state.Flags = (ClientFlags)flags; state.Mobile = m; @@ -1945,38 +2183,93 @@ namespace Server.Network public static void DoLogin(NetState state, Mobile m) { - Packets.SendLoginConfirm(state, m); + state.Send(new LoginConfirm(m)); if (m.Map != null) - Packets.SendMapChange(state, m.Map); + state.Send(new MapChange(m)); - Packets.SendMapPatches(state); - Packets.SendSeasonChange(state, m.GetSeason(), 1); - Packets.SendSupportedFeatures(state); + state.Send(new MapPatches()); + + state.Send(SeasonChange.Instantiate(m.GetSeason(), true)); + + state.Send(SupportedFeatures.Instantiate(state)); state.Sequence = 0; - // TODO: Verify if we need this twice - Packets.SendMobileUpdate(state, m); - m.CheckLightLevels(true); - Packets.SendMobileUpdate(state, m); + if (state.NewMobileIncoming) + { + state.Send(new MobileUpdate(m)); + state.Send(new MobileUpdate(m)); - Packets.SendMobileIncoming(state, m, m); - Packets.SendMobileStatus(state, m, m); - Packets.SendSetWarMode(state, m.Warmode); + m.CheckLightLevels(true); - m.SendEverything(); + state.Send(new MobileUpdate(m)); - Packets.SendSupportedFeatures(state); - Packets.SendMobileUpdate(state, m); - Packets.SendMobileStatus(state, m, m); - Packets.SendSetWarMode(state, m.Warmode); - Packets.SendMobileIncoming(state, m, m); + state.Send(new MobileIncoming(m, m)); + //state.Send( new MobileAttributes( m ) ); + state.Send(new MobileStatus(m, m)); + state.Send(Network.SetWarMode.Instantiate(m.Warmode)); - Packets.SendLoginComplete(state); - Packets.SendCurrentTime(state); - Packets.SendMapChange(state, m.Map); - Packets.SendSeasonChange(state, m.GetSeason(), 1); + m.SendEverything(); + + state.Send(SupportedFeatures.Instantiate(state)); + state.Send(new MobileUpdate(m)); + //state.Send( new MobileAttributes( m ) ); + state.Send(new MobileStatus(m, m)); + state.Send(Network.SetWarMode.Instantiate(m.Warmode)); + state.Send(new MobileIncoming(m, m)); + } + else if (state.StygianAbyss) + { + state.Send(new MobileUpdate(m)); + state.Send(new MobileUpdate(m)); + + m.CheckLightLevels(true); + + state.Send(new MobileUpdate(m)); + + state.Send(new MobileIncomingSA(m, m)); + //state.Send( new MobileAttributes( m ) ); + state.Send(new MobileStatus(m, m)); + state.Send(Network.SetWarMode.Instantiate(m.Warmode)); + + m.SendEverything(); + + state.Send(SupportedFeatures.Instantiate(state)); + state.Send(new MobileUpdate(m)); + //state.Send( new MobileAttributes( m ) ); + state.Send(new MobileStatus(m, m)); + state.Send(Network.SetWarMode.Instantiate(m.Warmode)); + state.Send(new MobileIncomingSA(m, m)); + } + else + { + state.Send(new MobileUpdateOld(m)); + state.Send(new MobileUpdateOld(m)); + + m.CheckLightLevels(true); + + state.Send(new MobileUpdateOld(m)); + + state.Send(new MobileIncomingOld(m, m)); + //state.Send( new MobileAttributes( m ) ); + state.Send(new MobileStatus(m, m)); + state.Send(Network.SetWarMode.Instantiate(m.Warmode)); + + m.SendEverything(); + + state.Send(SupportedFeatures.Instantiate(state)); + state.Send(new MobileUpdateOld(m)); + //state.Send( new MobileAttributes( m ) ); + state.Send(new MobileStatus(m, m)); + state.Send(Network.SetWarMode.Instantiate(m.Warmode)); + state.Send(new MobileIncomingOld(m, m)); + } + + state.Send(LoginComplete.Instance); + state.Send(new CurrentTime()); + state.Send(SeasonChange.Instantiate(m.GetSeason(), true)); + state.Send(new MapChange(m)); EventSink.InvokeLogin(new LoginEventArgs(m)); @@ -2041,14 +2334,20 @@ namespace Server.Network race = Race.Races[raceID]; } else + { race = Race.Races[(byte)(genderRace / 2)]; + } + + if (race == null) + race = Race.DefaultRace; - race ??= Race.DefaultRace; CityInfo[] info = state.CityInfo; IAccount a = state.Account; if (info == null || a == null || cityIndex < 0 || cityIndex >= info.Length) + { state.Dispose(); + } else { // Check if anyone is using this account @@ -2059,7 +2358,7 @@ namespace Server.Network if (check != null && check.Map != Map.Internal) { Console.WriteLine("Login: {0}: Account in use", state); - Packets.SendPopupMessage(state, PMMessage.CharInWorld); + state.Send(new PopupMessage(PMMessage.CharInWorld)); return; } } @@ -2084,7 +2383,7 @@ namespace Server.Network race ); - Packets.SendClientVersionReq(state); + state.Send(new ClientVersionReq()); state.BlockAllPackets = true; @@ -2154,8 +2453,10 @@ namespace Server.Network bool female = genderRace % 2 != 0; - byte raceId = (byte)(genderRace < 4 ? 0 : genderRace / 2 - 1); - Race race = Race.Races[raceId] ?? Race.DefaultRace; + Race race; + + byte raceID = (byte)(genderRace < 4 ? 0 : genderRace / 2 - 1); + race = Race.Races[raceID] ?? Race.DefaultRace; CityInfo[] info = state.CityInfo; IAccount a = state.Account; @@ -2174,7 +2475,7 @@ namespace Server.Network if (check != null && check.Map != Map.Internal) { Console.WriteLine("Login: {0}: Account in use", state); - Packets.SendPopupMessage(state, PMMessage.CharInWorld); + state.Send(new PopupMessage(PMMessage.CharInWorld)); return; } } @@ -2200,20 +2501,25 @@ namespace Server.Network race ); - Packets.SendClientVersionReq(state); + state.Send(new ClientVersionReq()); + + state.BlockAllPackets = true; + EventSink.InvokeCharacterCreated(args); Mobile m = args.Mobile; if (m != null) { - state.BlockAllPackets = true; state.Mobile = m; m.NetState = state; new LoginTimer(state, m).Start(); } else + { + state.BlockAllPackets = false; state.Dispose(); + } } } @@ -2224,11 +2530,11 @@ namespace Server.Network int oldestID = 0; DateTime oldest = DateTime.MaxValue; - foreach (var (key, value) in m_AuthIDWindow) - if (value.Age < oldest) + foreach (KeyValuePair kvp in m_AuthIDWindow) + if (kvp.Value.Age < oldest) { - oldestID = key; - oldest = value.Age; + oldestID = kvp.Key; + oldest = kvp.Value.Age; } m_AuthIDWindow.Remove(oldestID); @@ -2258,13 +2564,13 @@ namespace Server.Network } state.SentFirstPacket = true; - state.UseCompression = true; int authID = pvSrc.ReadInt32(); if (m_AuthIDWindow.TryGetValue(authID, out AuthIDPersistence ap)) { m_AuthIDWindow.Remove(authID); + state.Version = ap.Version; } else if (ClientVerification) @@ -2298,12 +2604,19 @@ namespace Server.Network if (e.Accepted) { state.CityInfo = e.CityInfo; + state.CompressionEnabled = true; - Packets.SendSupportedFeatures(state); - Packets.SendCharacterList(state, state.CityInfo); + state.Send(SupportedFeatures.Instantiate(state)); + + if (state.NewCharacterList) + state.Send(new CharacterList(state.Account, state.CityInfo)); + else + state.Send(new CharacterListOld(state.Account, state.CityInfo)); } else + { state.Dispose(); + } } public static void PlayServer(NetState state, PacketReader pvSrc) @@ -2313,15 +2626,17 @@ namespace Server.Network IAccount a = state.Account; if (info == null || a == null || index < 0 || index >= info.Length) + { state.Dispose(); + } else { ServerInfo si = info[index]; - state.m_AuthID = GenerateAuthID(state); + state.m_AuthID = PlayServerAck.m_AuthID = GenerateAuthID(state); state.SentFirstPacket = false; - Packets.SendPlayServerAck(state, si); + state.Send(new PlayServerAck(si)); } } @@ -2419,13 +2734,13 @@ namespace Server.Network state.ServerInfo = info; - Packets.SendAccountLoginAck(state, info); + state.Send(new AccountLoginAck(info)); } } public static void AccountLogin_ReplyRej(NetState state, ALRReason reason) { - Packets.SendAccountLoginRej(state, reason); + state.Send(new AccountLoginRej(reason)); state.Dispose(); } @@ -2443,10 +2758,7 @@ namespace Server.Network protected override void OnTick() { if (m_State == null) - { Stop(); - return; - } if (m_State.Version != null) { diff --git a/Projects/Server/Network/PacketReader.cs b/Projects/Server/Network/PacketReader.cs index 2f33fc423..de6159bb1 100644 --- a/Projects/Server/Network/PacketReader.cs +++ b/Projects/Server/Network/PacketReader.cs @@ -104,206 +104,31 @@ namespace Server.Network public sbyte ReadSByte() => (sbyte)ReadByte(); - public bool ReadBoolean() => ReadByte() != 0; + public bool ReadBoolean() => ReadByte() > 0; - public bool IsSafeChar(int c) => c >= 0x20 && c < 0xFFFE; - - public string ReadUTF8StringSafe() + public string ReadUnicodeStringLE() { StringBuilder sb = new StringBuilder(); - bool end = false; - while (!(end |= m_Reader.End)) - { - ReadOnlySpan span = m_Reader.UnreadSpan; - int count = 0; - bool safe = true; - while (count < span.Length) - { - byte chr = span[count]; - if (chr == 0) - { - end = true; - break; - } - - if (!IsSafeChar(chr)) - { - safe = false; - break; - } - - count++; - } - - sb.Append(Encoding.UTF8.GetString(span.Slice(0, count))); - m_Reader.Advance(count + (safe ? 1 : 0)); - } + while (m_Reader.TryReadLittleEndian(out short c) && c != 0) + sb.Append((char)c); return sb.ToString(); } - public string ReadUTF8String() + public string ReadUnicodeStringLE(int fixedLength) { StringBuilder sb = new StringBuilder(); - bool end = false; - while (!(end |= m_Reader.End)) - { - ReadOnlySpan span = m_Reader.UnreadSpan; - int count = 0; - while (count < span.Length) - { - if (span[count] == 0) - { - end = true; - break; - } + while (fixedLength-- > 0 && m_Reader.TryReadLittleEndian(out short c) && c != 0) + sb.Append((char)c); - count++; - } - - sb.Append(Encoding.UTF8.GetString(span.Slice(0, count))); - m_Reader.Advance(count); - } + if (fixedLength > 0) + m_Reader.Advance(fixedLength); return sb.ToString(); } - public string ReadString() - { - StringBuilder sb = new StringBuilder(); - bool end = false; - - while (!(end |= m_Reader.End)) - { - ReadOnlySpan span = m_Reader.UnreadSpan; - int count = 0; - while (count < span.Length) - { - if (span[count] == 0) - { - end = true; - break; - } - - count++; - } - - sb.Append(Encoding.ASCII.GetString(span.Slice(0, count))); - m_Reader.Advance(count); - } - - return sb.ToString(); - } - - public string ReadString(int size) - { - StringBuilder sb = new StringBuilder(); - bool end = false; - - while (!(end |= m_Reader.End) && size > 0) - { - ReadOnlySpan span = m_Reader.UnreadSpan; - int count = 0; - while (count < span.Length && size > 0) - { - if (span[count] == 0) - { - end = true; - break; - } - - count++; - size--; - } - - sb.Append(Encoding.ASCII.GetString(span.Slice(0, count))); - m_Reader.Advance(count); - } - - if (size > 0) - m_Reader.Advance(size); - - return sb.ToString(); - } - - public bool IsSafeChar(int c) => c >= 0x20 && c < 0xFFFE; - - public string ReadUTF8StringSafe(int fixedLength) - { - StringBuilder sb = new StringBuilder(); - bool end = false; - - while (!(end |= m_Reader.End)) - { - ReadOnlySpan span = m_Reader.UnreadSpan; - int count = 0; - bool safe = true; - while (count < span.Length) - { - byte chr = span[count]; - if (chr == 0) - { - end = true; - break; - } - - if (!IsSafeChar(chr)) - { - safe = false; - break; - } - - count++; - } - - sb.Append(Encoding.ASCII.GetString(span.Slice(0, count))); - m_Reader.Advance(count + (safe ? 1 : 0)); - } - - return sb.ToString(); - } - - public string ReadStringSafe(int size) - { - StringBuilder sb = new StringBuilder(); - bool end = false; - - while (!(end |= m_Reader.End) && size > 0) - { - ReadOnlySpan span = m_Reader.UnreadSpan; - int count = 0; - bool safe = true; - while (count < span.Length && size > 0) - { - byte chr = span[count]; - if (chr == 0) - { - end = true; - break; - } - - if (!IsSafeChar(chr)) - { - safe = false; - break; - } - - count++; - size--; - } - - sb.Append(Encoding.ASCII.GetString(span.Slice(0, count))); - m_Reader.Advance(size + (safe ? 1 : 0)); - } - - public string ReadUTF8String() => - Utility.UTF8.GetString( - m_Reader.TryReadTo(out ReadOnlySpan span, (byte)'\0', true) ? span : - m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray() - ); - public string ReadUnicodeStringLESafe(int fixedLength) { StringBuilder sb = new StringBuilder(); @@ -329,6 +154,17 @@ namespace Server.Network return sb.ToString(); } + public string ReadUnicodeStringSafe() + { + StringBuilder sb = new StringBuilder(); + + while (m_Reader.TryReadBigEndian(out short c) && c != 0) + if (IsSafeChar(c)) + sb.Append((char)c); + + return sb.ToString(); + } + public string ReadUnicodeString() { StringBuilder sb = new StringBuilder(); @@ -339,24 +175,72 @@ namespace Server.Network return sb.ToString(); } - public string ReadUnicodeString(int fixedLength) + public bool IsSafeChar(int c) => c >= 0x20 && c < 0xFFFE; + + public string ReadUTF8StringSafe(int fixedLength) { - StringBuilder sb = new StringBuilder(); + string s; - while (fixedLength-- > 0 && m_Reader.TryReadBigEndian(out short c) && c != 0) - sb.Append((char)c); + if (m_Reader.TryReadTo(out ReadOnlySpan span, (byte)'\0', true)) + s = Utility.UTF8.GetString(span.Length > fixedLength ? span.Slice(0, fixedLength) : span); + else + { + long size = Math.Min(m_Reader.Remaining, fixedLength); + s = Utility.UTF8.GetString(m_Reader.Sequence.Slice(m_Reader.Position, size).ToArray()); + m_Reader.Advance(size); + } - if (fixedLength > 0) - m_Reader.Advance(fixedLength * 2); + StringBuilder sb = new StringBuilder(s.Length); + + for (int i = 0; i < s.Length; ++i) + if (IsSafeChar(s[i])) + sb.Append(s[i]); return sb.ToString(); } - public string ReadUnicodeStringSafe() + public string ReadUTF8StringSafe() + { + string s; + + if (m_Reader.TryReadTo(out ReadOnlySpan span, (byte)'\0', true)) + s = Utility.UTF8.GetString(span); + else + { + s = Utility.UTF8.GetString(m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray()); + m_Reader.Advance(m_Reader.Remaining); + } + + StringBuilder sb = new StringBuilder(s.Length); + + for (int i = 0; i < s.Length; ++i) + if (IsSafeChar(s[i])) + sb.Append(s[i]); + + return sb.ToString(); + } + + public string ReadUTF8String() => + Utility.UTF8.GetString( + m_Reader.TryReadTo(out ReadOnlySpan span, (byte)'\0', true) ? span : + m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray() + ); + + public string ReadString() { StringBuilder sb = new StringBuilder(); - while (m_Reader.TryReadBigEndian(out short c) && c != 0) + while (m_Reader.TryRead(out byte c)) + sb.Append((char)c); + + return sb.ToString(); + } + + public string ReadStringSafe() + { + StringBuilder sb = new StringBuilder(); + + while (m_Reader.TryRead(out byte c)) if (IsSafeChar(c)) sb.Append((char)c); @@ -376,5 +260,45 @@ namespace Server.Network return sb.ToString(); } + + public string ReadUnicodeString(int fixedLength) + { + StringBuilder sb = new StringBuilder(); + + while (fixedLength-- > 0 && m_Reader.TryReadBigEndian(out short c) && c != 0) + sb.Append((char)c); + + if (fixedLength > 0) + m_Reader.Advance(fixedLength * 2); + + return sb.ToString(); + } + + public string ReadStringSafe(int fixedLength) + { + StringBuilder sb = new StringBuilder(); + + while (fixedLength-- > 0 && m_Reader.TryRead(out byte c) && c != 0) + if (IsSafeChar(c)) + sb.Append((char)c); + + if (fixedLength > 0) + m_Reader.Advance(fixedLength); + + return sb.ToString(); + } + + public string ReadString(int fixedLength) + { + StringBuilder sb = new StringBuilder(); + + while (fixedLength-- > 0 && m_Reader.TryRead(out byte c) && c != 0) + sb.Append((char)c); + + if (fixedLength > 0) + m_Reader.Advance(fixedLength); + + return sb.ToString(); + } } } diff --git a/Projects/Server/Network/PacketWriter.cs b/Projects/Server/Network/PacketWriter.cs new file mode 100644 index 000000000..6587e3a7a --- /dev/null +++ b/Projects/Server/Network/PacketWriter.cs @@ -0,0 +1,346 @@ +/*************************************************************************** + * PacketWriter.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Text; + +namespace Server.Network +{ + /// + /// Provides functionality for writing primitive binary data. + /// + public class PacketWriter + { + private static ConcurrentQueue m_Pool = new ConcurrentQueue(); + + /// + /// Internal format buffer. + /// + private byte[] m_Buffer = new byte[4]; + + private int m_Capacity; + + /// + /// Instantiates a new PacketWriter instance with a given capacity. + /// + /// Initial capacity for the internal stream. + public PacketWriter(int capacity = 32) + { + UnderlyingStream = new MemoryStream(capacity); + m_Capacity = capacity; + } + + /// + /// Gets the total stream length. + /// + public long Length => UnderlyingStream.Length; + + /// + /// Gets or sets the current stream position. + /// + public long Position + { + get => UnderlyingStream.Position; + set => UnderlyingStream.Position = value; + } + + /// + /// The internal stream used by this PacketWriter instance. + /// + public MemoryStream UnderlyingStream { get; private set; } + + public static PacketWriter CreateInstance(int capacity = 32) + { + if (m_Pool.TryDequeue(out PacketWriter pw)) + { + pw.m_Capacity = capacity; + pw.UnderlyingStream.SetLength(0); + return pw; + } + + return new PacketWriter(capacity); + } + + public static void ReleaseInstance(PacketWriter pw) + { + m_Pool.Enqueue(pw); + } + + /// + /// Writes a 1-byte boolean value to the underlying stream. False is represented by 0, true by 1. + /// + public void Write(bool value) + { + UnderlyingStream.WriteByte((byte)(value ? 1 : 0)); + } + + /// + /// Writes a 1-byte unsigned integer value to the underlying stream. + /// + public void Write(byte value) + { + UnderlyingStream.WriteByte(value); + } + + /// + /// Writes a 1-byte signed integer value to the underlying stream. + /// + public void Write(sbyte value) + { + UnderlyingStream.WriteByte((byte)value); + } + + /// + /// Writes a 2-byte signed integer value to the underlying stream. + /// + public void Write(short value) + { + m_Buffer[0] = (byte)(value >> 8); + m_Buffer[1] = (byte)value; + + UnderlyingStream.Write(m_Buffer, 0, 2); + } + + /// + /// Writes a 2-byte unsigned integer value to the underlying stream. + /// + public void Write(ushort value) + { + m_Buffer[0] = (byte)(value >> 8); + m_Buffer[1] = (byte)value; + + UnderlyingStream.Write(m_Buffer, 0, 2); + } + + /// + /// Writes a 4-byte signed integer value to the underlying stream. + /// + public void Write(int value) + { + m_Buffer[0] = (byte)(value >> 24); + m_Buffer[1] = (byte)(value >> 16); + m_Buffer[2] = (byte)(value >> 8); + m_Buffer[3] = (byte)value; + + UnderlyingStream.Write(m_Buffer, 0, 4); + } + + /// + /// Writes a 4-byte unsigned integer value to the underlying stream. + /// + public void Write(uint value) + { + m_Buffer[0] = (byte)(value >> 24); + m_Buffer[1] = (byte)(value >> 16); + m_Buffer[2] = (byte)(value >> 8); + m_Buffer[3] = (byte)value; + + UnderlyingStream.Write(m_Buffer, 0, 4); + } + + /// + /// Writes a sequence of bytes to the underlying stream + /// + public void Write(byte[] buffer, int offset, int size) + { + UnderlyingStream.Write(buffer, offset, size); + } + + /// + /// Writes a fixed-length ASCII-encoded string value to the underlying stream. To fit (size), the string content is either + /// truncated or padded with null characters. + /// + public void WriteAsciiFixed(string value, int size) + { + if (value == null) + { + Console.WriteLine("Network: Attempted to WriteAsciiFixed() with null value"); + value = string.Empty; + } + + int length = value.Length; + + UnderlyingStream.SetLength(UnderlyingStream.Length + size); + + if (length >= size) + { + UnderlyingStream.Position += + Encoding.ASCII.GetBytes(value, 0, size, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + } + else + { + Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += size; + } + } + + /// + /// Writes a dynamic-length ASCII-encoded string value to the underlying stream, followed by a 1-byte null character. + /// + public void WriteAsciiNull(string value) + { + if (value == null) + { + Console.WriteLine("Network: Attempted to WriteAsciiNull() with null value"); + value = string.Empty; + } + + int length = value.Length; + + UnderlyingStream.SetLength(UnderlyingStream.Length + length + 1); + + Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += length + 1; + } + + /// + /// Writes a dynamic-length little-endian unicode string value to the underlying stream, followed by a 2-byte null character. + /// + public void WriteLittleUniNull(string value) + { + if (value == null) + { + Console.WriteLine("Network: Attempted to WriteLittleUniNull() with null value"); + value = string.Empty; + } + + int length = value.Length; + + UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2); + + UnderlyingStream.Position += Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += 2; + } + + /// + /// Writes a fixed-length little-endian unicode string value to the underlying stream. To fit (size), the string content is + /// either truncated or padded with null characters. + /// + public void WriteLittleUniFixed(string value, int size) + { + if (value == null) + { + Console.WriteLine("Network: Attempted to WriteLittleUniFixed() with null value"); + value = string.Empty; + } + + int length = value.Length; + size *= 2; + + UnderlyingStream.SetLength(UnderlyingStream.Length + size); + + if (length * 2 >= size) + { + UnderlyingStream.Position += + Encoding.Unicode.GetBytes(value, 0, size / 2, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + } + else + { + Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += size; + } + } + + /// + /// Writes a dynamic-length big-endian unicode string value to the underlying stream, followed by a 2-byte null character. + /// + public void WriteBigUniNull(string value) + { + if (value == null) + { + Console.WriteLine("Network: Attempted to WriteBigUniNull() with null value"); + value = string.Empty; + } + + int length = value.Length; + + UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2); + + UnderlyingStream.Position += + Encoding.BigEndianUnicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += 2; + } + + /// + /// Writes a fixed-length big-endian unicode string value to the underlying stream. To fit (size), the string content is + /// either truncated or padded with null characters. + /// + public void WriteBigUniFixed(string value, int size) + { + if (value == null) + { + Console.WriteLine("Network: Attempted to WriteBigUniFixed() with null value"); + value = string.Empty; + } + + int length = value.Length; + size *= 2; + + UnderlyingStream.SetLength(UnderlyingStream.Length + size); + + if (length * 2 >= size ) + { + UnderlyingStream.Position += + Encoding.BigEndianUnicode.GetBytes(value, 0, size / 2, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + } + else + { + Encoding.BigEndianUnicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += size; + } + } + + /// + /// Fills the stream from the current position up to (capacity) with 0x00's + /// + public void Fill() + { + Fill(m_Capacity - UnderlyingStream.Length); + } + + /// + /// Writes a number of 0x00 byte values to the underlying stream. + /// + public void Fill(long length) + { + if (UnderlyingStream.Position == UnderlyingStream.Length) + { + UnderlyingStream.SetLength(UnderlyingStream.Length + length); + UnderlyingStream.Seek(0, SeekOrigin.End); + } + else + { + UnderlyingStream.Write(new byte[length], 0, (int)length); + } + } + + /// + /// Offsets the current position from an origin. + /// + public long Seek(long offset, SeekOrigin origin) => UnderlyingStream.Seek(offset, origin); + + /// + /// Gets the entire stream content as a byte array. + /// + public byte[] ToArray() => UnderlyingStream.ToArray(); + } +} diff --git a/Projects/Server/Network/Packets.cs b/Projects/Server/Network/Packets.cs new file mode 100644 index 000000000..330f3d3fe --- /dev/null +++ b/Projects/Server/Network/Packets.cs @@ -0,0 +1,4170 @@ +/*************************************************************************** + * Packets.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using Server.Accounting; +using Server.ContextMenus; +using Server.Gumps; +using Server.HuePickers; +using Server.Items; +using Server.Menus; +using Server.Menus.ItemLists; +using Server.Menus.Questions; +using Server.Prompts; +using Server.Targeting; + +namespace Server.Network +{ + public enum PMMessage : byte + { + CharNoExist = 1, + CharExists = 2, + CharInWorld = 5, + LoginSyncError = 6, + IdleWarning = 7 + } + + public enum LRReason : byte + { + CannotLift = 0, + OutOfRange = 1, + OutOfSight = 2, + TryToSteal = 3, + AreHolding = 4, + Inspecific = 5 + } + + /*public enum CMEFlags + { + None = 0x00, + Locked = 0x01, + Arrow = 0x02, + x0004 = 0x04, + Color = 0x20, + x0040 = 0x40, + x0080 = 0x80 + }*/ + + public sealed class DamagePacketOld : Packet + { + public DamagePacketOld(Mobile m, int amount) : base(0xBF) + { + EnsureCapacity(11); + + m_Stream.Write((short)0x22); + m_Stream.Write((byte)1); + m_Stream.Write(m.Serial); + + if (amount > 255) + amount = 255; + else if (amount < 0) + amount = 0; + + m_Stream.Write((byte)amount); + } + } + + public sealed class DamagePacket : Packet + { + public DamagePacket(Mobile m, int amount) : base(0x0B, 7) + { + m_Stream.Write(m.Serial); + + if (amount > 0xFFFF) + amount = 0xFFFF; + else if (amount < 0) + amount = 0; + + m_Stream.Write((ushort)amount); + } + + /*public DamagePacket( Mobile m, int amount ) : base( 0xBF ) + { + EnsureCapacity( 11 ); + + m_Stream.Write( (short) 0x22 ); + m_Stream.Write( (byte) 1 ); + m_Stream.Write( (int) m.Serial ); + + if ( amount > 255 ) + amount = 255; + else if ( amount < 0 ) + amount = 0; + + m_Stream.Write( (byte)amount ); + }*/ + } + + public sealed class CancelArrow : Packet + { + public CancelArrow() : base(0xBA, 6) + { + m_Stream.Write((byte)0); + m_Stream.Write((short)-1); + m_Stream.Write((short)-1); + } + } + + public sealed class SetArrow : Packet + { + public SetArrow(int x, int y) : base(0xBA, 6) + { + m_Stream.Write((byte)1); + m_Stream.Write((short)x); + m_Stream.Write((short)y); + } + } + + public sealed class CancelArrowHS : Packet + { + public CancelArrowHS(int x, int y, Serial s) : base(0xBA, 10) + { + m_Stream.Write((byte)0); + m_Stream.Write((short)x); + m_Stream.Write((short)y); + m_Stream.Write(s); + } + } + + public sealed class SetArrowHS : Packet + { + public SetArrowHS(int x, int y, Serial s) : base(0xBA, 10) + { + m_Stream.Write((byte)1); + m_Stream.Write((short)x); + m_Stream.Write((short)y); + m_Stream.Write(s); + } + } + + public sealed class DisplaySecureTrade : Packet + { + public DisplaySecureTrade(Mobile them, Container first, Container second, string name) + : base(0x6F) + { + if (name == null) name = ""; + + EnsureCapacity(18 + name.Length); + + m_Stream.Write((byte)0); // Display + m_Stream.Write(them.Serial); + m_Stream.Write(first.Serial); + m_Stream.Write(second.Serial); + m_Stream.Write(true); + + m_Stream.WriteAsciiFixed(name, 30); + } + } + + public sealed class CloseSecureTrade : Packet + { + public CloseSecureTrade(Container cont) + : base(0x6F) + { + EnsureCapacity(8); + + m_Stream.Write((byte)1); // Close + m_Stream.Write(cont.Serial); + } + } + + public enum TradeFlag : byte + { + Display = 0x0, + Close = 0x1, + Update = 0x2, + UpdateGold = 0x3, + UpdateLedger = 0x4 + } + + public sealed class UpdateSecureTrade : Packet + { + public UpdateSecureTrade(Container cont, bool first, bool second) + : this(cont, TradeFlag.Update, first ? 1 : 0, second ? 1 : 0) + { + } + + public UpdateSecureTrade(Container cont, TradeFlag flag, int first, int second) + : base(0x6F) + { + EnsureCapacity(17); + + m_Stream.Write((byte)flag); + m_Stream.Write(cont.Serial); + m_Stream.Write(first); + m_Stream.Write(second); + } + } + + public sealed class SecureTradeEquip : Packet + { + public SecureTradeEquip(Item item, Mobile m) : base(0x25, 20) + { + m_Stream.Write(item.Serial); + m_Stream.Write((short)item.ItemID); + m_Stream.Write((byte)0); + m_Stream.Write((short)item.Amount); + m_Stream.Write((short)item.X); + m_Stream.Write((short)item.Y); + m_Stream.Write(m.Serial); + m_Stream.Write((short)item.Hue); + } + } + + public sealed class SecureTradeEquip6017 : Packet + { + public SecureTradeEquip6017(Item item, Mobile m) : base(0x25, 21) + { + m_Stream.Write(item.Serial); + m_Stream.Write((short)item.ItemID); + m_Stream.Write((byte)0); + m_Stream.Write((short)item.Amount); + m_Stream.Write((short)item.X); + m_Stream.Write((short)item.Y); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write(m.Serial); + m_Stream.Write((short)item.Hue); + } + } + + public sealed class MapPatches : Packet + { + public MapPatches() : base(0xBF) + { + EnsureCapacity(9 + 3 * 8); + + m_Stream.Write((short)0x0018); + + m_Stream.Write(4); + + m_Stream.Write(Map.Felucca.Tiles.Patch.StaticBlocks); + m_Stream.Write(Map.Felucca.Tiles.Patch.LandBlocks); + + m_Stream.Write(Map.Trammel.Tiles.Patch.StaticBlocks); + m_Stream.Write(Map.Trammel.Tiles.Patch.LandBlocks); + + m_Stream.Write(Map.Ilshenar.Tiles.Patch.StaticBlocks); + m_Stream.Write(Map.Ilshenar.Tiles.Patch.LandBlocks); + + m_Stream.Write(Map.Malas.Tiles.Patch.StaticBlocks); + m_Stream.Write(Map.Malas.Tiles.Patch.LandBlocks); + } + } + + public sealed class ObjectHelpResponse : Packet + { + public ObjectHelpResponse(IEntity e, string text) : base(0xB7) + { + EnsureCapacity(9 + text.Length * 2); + + m_Stream.Write(e.Serial); + m_Stream.WriteBigUniNull(text); + } + } + + public sealed class VendorBuyContent : Packet + { + public VendorBuyContent(List list) + : base(0x3c) + { + EnsureCapacity(list.Count * 19 + 5); + + m_Stream.Write((short)list.Count); + + //The client sorts these by their X/Y value. + //OSI sends these in weird order. X/Y highest to lowest and serial lowest to highest + //These are already sorted by serial (done by the vendor class) but we have to send them by x/y + //(the x74 packet is sent in 'correct' order.) + for (int i = list.Count - 1; i >= 0; --i) + { + BuyItemState bis = list[i]; + + m_Stream.Write(bis.MySerial); + m_Stream.Write((ushort)bis.ItemID); + m_Stream.Write((byte)0); //itemid offset + m_Stream.Write((ushort)bis.Amount); + m_Stream.Write((short)(i + 1)); //x + m_Stream.Write((short)1); //y + m_Stream.Write(bis.ContainerSerial); + m_Stream.Write((ushort)bis.Hue); + } + } + } + + public sealed class VendorBuyContent6017 : Packet + { + public VendorBuyContent6017(List list) : base(0x3c) + { + EnsureCapacity(list.Count * 20 + 5); + + m_Stream.Write((short)list.Count); + + //The client sorts these by their X/Y value. + //OSI sends these in weird order. X/Y highest to lowest and serial loewst to highest + //These are already sorted by serial (done by the vendor class) but we have to send them by x/y + //(the x74 packet is sent in 'correct' order.) + for (int i = list.Count - 1; i >= 0; --i) + { + BuyItemState bis = list[i]; + + m_Stream.Write(bis.MySerial); + m_Stream.Write((ushort)bis.ItemID); + m_Stream.Write((byte)0); //itemid offset + m_Stream.Write((ushort)bis.Amount); + m_Stream.Write((short)(i + 1)); //x + m_Stream.Write((short)1); //y + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write(bis.ContainerSerial); + m_Stream.Write((ushort)bis.Hue); + } + } + } + + public sealed class DisplayBuyList : Packet + { + public DisplayBuyList(Mobile vendor) : base(0x24, 7) + { + m_Stream.Write(vendor.Serial); + m_Stream.Write((short)0x30); // buy window id? + } + } + + public sealed class DisplayBuyListHS : Packet + { + public DisplayBuyListHS(Mobile vendor) : base(0x24, 9) + { + m_Stream.Write(vendor.Serial); + m_Stream.Write((short)0x30); // buy window id? + m_Stream.Write((short)0x00); + } + } + + public sealed class VendorBuyList : Packet + { + public VendorBuyList(Mobile vendor, List list) + : base(0x74) + { + EnsureCapacity(256); + + m_Stream.Write(!(vendor.FindItemOnLayer(Layer.ShopBuy) is Container BuyPack) ? Serial.MinusOne : BuyPack.Serial); + + m_Stream.Write((byte)list.Count); + + for (int i = 0; i < list.Count; ++i) + { + BuyItemState bis = list[i]; + + m_Stream.Write(bis.Price); + + string desc = bis.Description ?? ""; + + m_Stream.Write((byte)(desc.Length + 1)); + m_Stream.WriteAsciiNull(desc); + } + } + } + + public sealed class VendorSellList : Packet + { + public VendorSellList(Mobile shopkeeper, ICollection sis) : base(0x9E) + { + EnsureCapacity(256); + + m_Stream.Write(shopkeeper.Serial); + + m_Stream.Write((ushort)sis.Count); + + foreach (SellItemState state in sis) + { + m_Stream.Write(state.Item.Serial); + m_Stream.Write((ushort)state.Item.ItemID); + m_Stream.Write((ushort)state.Item.Hue); + m_Stream.Write((ushort)state.Item.Amount); + m_Stream.Write((ushort)state.Price); + + string name = state.Item.Name; + + if (name == null || (name = name.Trim()).Length <= 0) + name = state.Name; + + if (name == null) + name = ""; + + m_Stream.Write((ushort)name.Length); + m_Stream.WriteAsciiFixed(name, (ushort)name.Length); + } + } + } + + public sealed class EndVendorSell : Packet + { + public EndVendorSell(Mobile Vendor) : base(0x3B, 8) + { + m_Stream.Write((ushort)8); //length + m_Stream.Write(Vendor.Serial); + m_Stream.Write((byte)0); + } + } + + public sealed class EndVendorBuy : Packet + { + public EndVendorBuy(Mobile Vendor) : base(0x3B, 8) + { + m_Stream.Write((ushort)8); //length + m_Stream.Write(Vendor.Serial); + m_Stream.Write((byte)0); + } + } + + public sealed class DeathAnimation : Packet + { + public DeathAnimation(Mobile killed, Item corpse) : base(0xAF, 13) + { + m_Stream.Write(killed.Serial); + m_Stream.Write(corpse?.Serial ?? Serial.Zero); + m_Stream.Write(0); + } + } + + public sealed class StatLockInfo : Packet + { + public StatLockInfo(Mobile m) : base(0xBF) + { + EnsureCapacity(12); + + m_Stream.Write((short)0x19); + m_Stream.Write((byte)2); + m_Stream.Write(m.Serial); + m_Stream.Write((byte)0); + + int lockBits = (int)m.StrLock << 4 | (int)m.DexLock << 2 | (int)m.IntLock; + + m_Stream.Write((byte)lockBits); + } + } + + public class EquipInfoAttribute + { + public EquipInfoAttribute(int number, int charges = -1) + { + Number = number; + Charges = charges; + } + + public int Number{ get; } + + public int Charges{ get; } + } + + public class EquipmentInfo + { + public EquipmentInfo(int number, Mobile crafter, bool unidentified, EquipInfoAttribute[] attributes) + { + Number = number; + Crafter = crafter; + Unidentified = unidentified; + Attributes = attributes; + } + + public int Number{ get; } + + public Mobile Crafter{ get; } + + public bool Unidentified{ get; } + + public EquipInfoAttribute[] Attributes{ get; } + } + + public sealed class DisplayEquipmentInfo : Packet + { + public DisplayEquipmentInfo(Item item, EquipmentInfo info) : base(0xBF) + { + EquipInfoAttribute[] attrs = info.Attributes; + + EnsureCapacity(17 + (info.Crafter?.Name.Length ?? 0) + + (info.Unidentified ? 4 : 0) + attrs.Length * 6); + + m_Stream.Write((short)0x10); + m_Stream.Write(item.Serial); + + m_Stream.Write(info.Number); + + if (info.Crafter != null) + { + string name = info.Crafter.Name; + + m_Stream.Write(-3); + + if (name == null) + { + m_Stream.Write((ushort)0); + } + else + { + int length = name.Length; + m_Stream.Write((ushort)length); + m_Stream.WriteAsciiFixed(name, length); + } + } + + if (info.Unidentified) m_Stream.Write(-4); + + for (int i = 0; i < attrs.Length; ++i) + { + m_Stream.Write(attrs[i].Number); + m_Stream.Write((short)attrs[i].Charges); + } + + m_Stream.Write(-1); + } + } + + public sealed class ChangeUpdateRange : Packet + { + private static ChangeUpdateRange[] m_Cache = new ChangeUpdateRange[0x100]; + + public ChangeUpdateRange(int range) : base(0xC8, 2) + { + m_Stream.Write((byte)range); + } + + public static ChangeUpdateRange Instantiate(int range) + { + byte idx = (byte)range; + ChangeUpdateRange p = m_Cache[idx]; + + if (p == null) + { + m_Cache[idx] = p = new ChangeUpdateRange(range); + p.SetStatic(); + } + + return p; + } + } + + public sealed class ChangeCombatant : Packet + { + public ChangeCombatant(Mobile combatant) : base(0xAA, 5) + { + m_Stream.Write(combatant?.Serial ?? Serial.Zero); + } + } + + public sealed class DisplayHuePicker : Packet + { + public DisplayHuePicker(HuePicker huePicker) : base(0x95, 9) + { + m_Stream.Write(huePicker.Serial); + m_Stream.Write((short)0); + m_Stream.Write((short)huePicker.ItemID); + } + } + + public sealed class TripTimeResponse : Packet + { + public TripTimeResponse(int unk) : base(0xC9, 6) + { + m_Stream.Write((byte)unk); + m_Stream.Write(Environment.TickCount); + } + } + + public sealed class UTripTimeResponse : Packet + { + public UTripTimeResponse(int unk) : base(0xCA, 6) + { + m_Stream.Write((byte)unk); + m_Stream.Write(Environment.TickCount); + } + } + + public sealed class UnicodePrompt : Packet + { + public UnicodePrompt(Prompt prompt) : base(0xC2) + { + EnsureCapacity(21); + + m_Stream.Write(prompt.Serial); + m_Stream.Write(prompt.Serial); + m_Stream.Write(0); + m_Stream.Write(0); + m_Stream.Write((short)0); + } + } + + public sealed class ChangeCharacter : Packet + { + public ChangeCharacter(IAccount a) : base(0x81) + { + EnsureCapacity(305); + + int count = 0; + + for (int i = 0; i < a.Length; ++i) + if (a[i] != null) + ++count; + + m_Stream.Write((byte)count); + m_Stream.Write((byte)0); + + for (int i = 0; i < a.Length; ++i) + if (a[i] != null) + { + string name = a[i].Name; + + if (name == null) + name = "-null-"; + else if ((name = name.Trim()).Length == 0) + name = "-empty-"; + + m_Stream.WriteAsciiFixed(name, 30); + m_Stream.Fill(30); // password + } + else + { + m_Stream.Fill(60); + } + } + } + + public sealed class DeathStatus : Packet + { + public static readonly Packet Dead = SetStatic(new DeathStatus(true)); + public static readonly Packet Alive = SetStatic(new DeathStatus(false)); + + public DeathStatus(bool dead) : base(0x2C, 2) + { + m_Stream.Write((byte)(dead ? 0 : 2)); + } + + public static Packet Instantiate(bool dead) => dead ? Dead : Alive; + } + + public sealed class SpeedControl : Packet + { + public static readonly Packet WalkSpeed = SetStatic(new SpeedControl(2)); + public static readonly Packet MountSpeed = SetStatic(new SpeedControl(1)); + public static readonly Packet Disable = SetStatic(new SpeedControl(0)); + + public SpeedControl(int speedControl) + : base(0xBF) + { + EnsureCapacity(3); + + m_Stream.Write((short)0x26); + m_Stream.Write((byte)speedControl); + } + } + + public sealed class InvalidMapEnable : Packet + { + public InvalidMapEnable() : base(0xC6, 1) + { + } + } + + public sealed class BondedStatus : Packet + { + public BondedStatus(int val1, Serial serial, int val2) : base(0xBF) + { + EnsureCapacity(11); + + m_Stream.Write((short)0x19); + m_Stream.Write((byte)val1); + m_Stream.Write(serial); + m_Stream.Write((byte)val2); + } + } + + public sealed class ToggleSpecialAbility : Packet + { + public ToggleSpecialAbility(int abilityID, bool active) + : base(0xBF) + { + EnsureCapacity(7); + + m_Stream.Write((short)0x25); + + m_Stream.Write((short)abilityID); + m_Stream.Write(active); + } + } + + public sealed class DisplayItemListMenu : Packet + { + public DisplayItemListMenu(ItemListMenu menu) : base(0x7C) + { + EnsureCapacity(256); + + m_Stream.Write(((IMenu)menu).Serial); + m_Stream.Write((short)0); + + string question = menu.Question; + + if (question == null) + { + m_Stream.Write((byte)0); + } + else + { + int questionLength = question.Length; + m_Stream.Write((byte)questionLength); + m_Stream.WriteAsciiFixed(question, questionLength); + } + + ItemListEntry[] entries = menu.Entries; + + int entriesLength = (byte)entries.Length; + + m_Stream.Write((byte)entriesLength); + + for (int i = 0; i < entriesLength; ++i) + { + ItemListEntry e = entries[i]; + + m_Stream.Write((ushort)e.ItemID); + m_Stream.Write((short)e.Hue); + + string name = e.Name; + + if (name == null) + { + m_Stream.Write((byte)0); + } + else + { + int nameLength = name.Length; + m_Stream.Write((byte)nameLength); + m_Stream.WriteAsciiFixed(name, nameLength); + } + } + } + } + + public sealed class DisplayQuestionMenu : Packet + { + public DisplayQuestionMenu(QuestionMenu menu) : base(0x7C) + { + EnsureCapacity(256); + + m_Stream.Write(((IMenu)menu).Serial); + m_Stream.Write((short)0); + + string question = menu.Question; + + if (question == null) + { + m_Stream.Write((byte)0); + } + else + { + int questionLength = question.Length; + m_Stream.Write((byte)questionLength); + m_Stream.WriteAsciiFixed(question, questionLength); + } + + string[] answers = menu.Answers; + + int answersLength = (byte)answers.Length; + + m_Stream.Write((byte)answersLength); + + for (int i = 0; i < answersLength; ++i) + { + m_Stream.Write(0); + + string answer = answers[i]; + + if (answer == null) + { + m_Stream.Write((byte)0); + } + else + { + int answerLength = answer.Length; + m_Stream.Write((byte)answerLength); + m_Stream.WriteAsciiFixed(answer, answerLength); + } + } + } + } + + public sealed class GlobalLightLevel : Packet + { + private static GlobalLightLevel[] m_Cache = new GlobalLightLevel[0x100]; + + public GlobalLightLevel(int level) : base(0x4F, 2) + { + m_Stream.Write((sbyte)level); + } + + public static GlobalLightLevel Instantiate(int level) + { + byte lvl = (byte)level; + GlobalLightLevel p = m_Cache[lvl]; + + if (p == null) + { + m_Cache[lvl] = p = new GlobalLightLevel(level); + p.SetStatic(); + } + + return p; + } + } + + public sealed class PersonalLightLevel : Packet + { + public PersonalLightLevel(Mobile m) : this(m, m.LightLevel) + { + } + + public PersonalLightLevel(Mobile m, int level) : base(0x4E, 6) + { + m_Stream.Write(m.Serial); + m_Stream.Write((sbyte)level); + } + } + + public sealed class PersonalLightLevelZero : Packet + { + public PersonalLightLevelZero(Mobile m) : base(0x4E, 6) + { + m_Stream.Write(m.Serial); + m_Stream.Write((sbyte)0); + } + } + + [Flags] + public enum CMEFlags + { + None = 0x00, + Disabled = 0x01, + Arrow = 0x02, + Highlighted = 0x04, + Colored = 0x20 + } + + public sealed class DisplayContextMenu : Packet + { + public DisplayContextMenu(ContextMenu menu) : base(0xBF) + { + ContextMenuEntry[] entries = menu.Entries; + + int length = (byte)entries.Length; + + EnsureCapacity(12 + length * 8); + + m_Stream.Write((short)0x14); + m_Stream.Write((short)0x02); + + IEntity target = menu.Target as IEntity; + + m_Stream.Write(target?.Serial ?? Serial.MinusOne); + + m_Stream.Write((byte)length); + + Point3D p; + + if (target is Mobile) + p = target.Location; + else if (target is Item item) + p = item.GetWorldLocation(); + else + p = Point3D.Zero; + + for (int i = 0; i < length; ++i) + { + ContextMenuEntry e = entries[i]; + + m_Stream.Write(e.Number); + m_Stream.Write((short)i); + + int range = e.Range; + + if (range == -1) + range = 18; + + CMEFlags flags = e.Enabled && menu.From.InRange(p, range) ? CMEFlags.None : CMEFlags.Disabled; + + flags |= e.Flags; + + m_Stream.Write((short)flags); + } + } + } + + public sealed class DisplayContextMenuOld : Packet + { + public DisplayContextMenuOld(ContextMenu menu) : base(0xBF) + { + ContextMenuEntry[] entries = menu.Entries; + + int length = (byte)entries.Length; + + EnsureCapacity(12 + length * 8); + + m_Stream.Write((short)0x14); + m_Stream.Write((short)0x01); + + IEntity target = menu.Target as IEntity; + + m_Stream.Write(target?.Serial ?? Serial.MinusOne); + + m_Stream.Write((byte)length); + + Point3D p; + + if (target is Mobile) + p = target.Location; + else if (target is Item item) + p = item.GetWorldLocation(); + else + p = Point3D.Zero; + + for (int i = 0; i < length; ++i) + { + ContextMenuEntry e = entries[i]; + + m_Stream.Write((short)i); + m_Stream.Write((ushort)(e.Number - 3000000)); + + int range = e.Range; + + if (range == -1) + range = 18; + + CMEFlags flags = e.Enabled && menu.From.InRange(p, range) ? CMEFlags.None : CMEFlags.Disabled; + + int color = e.Color & 0xFFFF; + + if (color != 0xFFFF) + flags |= CMEFlags.Colored; + + flags |= e.Flags; + + m_Stream.Write((short)flags); + + if ((flags & CMEFlags.Colored) != 0) + m_Stream.Write((short)color); + } + } + } + + public sealed class DisplayProfile : Packet + { + public DisplayProfile(bool realSerial, Mobile m, string header, string body, string footer) : base(0xB8) + { + if (header == null) + header = ""; + + if (body == null) + body = ""; + + if (footer == null) + footer = ""; + + EnsureCapacity(12 + header.Length + footer.Length * 2 + body.Length * 2); + + m_Stream.Write(realSerial ? m.Serial : Serial.Zero); + m_Stream.WriteAsciiNull(header); + m_Stream.WriteBigUniNull(footer); + m_Stream.WriteBigUniNull(body); + } + } + + public sealed class CloseGump : Packet + { + public CloseGump(int typeID, int buttonID) : base(0xBF) + { + EnsureCapacity(13); + + m_Stream.Write((short)0x04); + m_Stream.Write(typeID); + m_Stream.Write(buttonID); + } + } + + public sealed class EquipUpdate : Packet + { + public EquipUpdate(Item item) : base(0x2E, 15) + { + Serial parentSerial; + + Mobile parent = item.Parent as Mobile; + + if (parent != null) + { + parentSerial = parent.Serial; + } + else + { + Console.WriteLine("Warning: EquipUpdate on item with !(parent is Mobile)"); + parentSerial = Serial.Zero; + } + + int hue = item.Hue; + + if (parent?.SolidHueOverride >= 0) + hue = parent.SolidHueOverride; + + m_Stream.Write(item.Serial); + m_Stream.Write((short)item.ItemID); + m_Stream.Write((byte)0); + m_Stream.Write((byte)item.Layer); + m_Stream.Write(parentSerial); + m_Stream.Write((short)hue); + } + } + + public sealed class WorldItem : Packet + { + public WorldItem(Item item) : base(0x1A) + { + EnsureCapacity(20); + + // 14 base length + // +2 - Amount + // +2 - Hue + // +1 - Flags + + uint serial = item.Serial.Value; + int itemID = item.ItemID & 0x3FFF; + int amount = item.Amount; + Point3D loc = item.Location; + int x = loc.m_X; + int y = loc.m_Y; + int hue = item.Hue; + int flags = item.GetPacketFlags(); + int direction = (int)item.Direction; + + if (amount != 0) + serial |= 0x80000000; + else + serial &= 0x7FFFFFFF; + + m_Stream.Write(serial); + + if (item is BaseMulti) + m_Stream.Write((short)(itemID | 0x4000)); + else + m_Stream.Write((short)itemID); + + if (amount != 0) m_Stream.Write((short)amount); + + x &= 0x7FFF; + + if (direction != 0) x |= 0x8000; + + m_Stream.Write((short)x); + + y &= 0x3FFF; + + if (hue != 0) y |= 0x8000; + + if (flags != 0) y |= 0x4000; + + m_Stream.Write((short)y); + + if (direction != 0) + m_Stream.Write((byte)direction); + + m_Stream.Write((sbyte)loc.m_Z); + + if (hue != 0) + m_Stream.Write((ushort)hue); + + if (flags != 0) + m_Stream.Write((byte)flags); + } + } + + public sealed class WorldItemSA : Packet + { + public WorldItemSA(Item item) : base(0xF3, 24) + { + m_Stream.Write((short)0x1); + + int itemID = item.ItemID; + + if (item is BaseMulti) + { + m_Stream.Write((byte)0x02); + + m_Stream.Write(item.Serial); + + itemID &= 0x3FFF; + + m_Stream.Write((short)itemID); + + m_Stream.Write((byte)0); + /*} else if ( ) { + m_Stream.Write( (byte) 0x01 ); + + m_Stream.Write( (int) item.Serial ); + + m_Stream.Write( (short) itemID ); + + m_Stream.Write( (byte) item.Direction );*/ + } + else + { + m_Stream.Write((byte)0x00); + + m_Stream.Write(item.Serial); + + itemID &= 0x7FFF; + + m_Stream.Write((short)itemID); + + m_Stream.Write((byte)0); + } + + int amount = item.Amount; + m_Stream.Write((short)amount); + m_Stream.Write((short)amount); + + Point3D loc = item.Location; + int x = loc.m_X & 0x7FFF; + int y = loc.m_Y & 0x3FFF; + m_Stream.Write((short)x); + m_Stream.Write((short)y); + m_Stream.Write((sbyte)loc.m_Z); + + m_Stream.Write((byte)item.Light); + m_Stream.Write((short)item.Hue); + m_Stream.Write((byte)item.GetPacketFlags()); + } + } + + public sealed class WorldItemHS : Packet + { + public WorldItemHS(Item item) : base(0xF3, 26) + { + m_Stream.Write((short)0x1); + + int itemID = item.ItemID; + + if (item is BaseMulti) + { + m_Stream.Write((byte)0x02); + + m_Stream.Write(item.Serial); + + itemID &= 0x3FFF; + + m_Stream.Write((ushort)itemID); + + m_Stream.Write((byte)0); + /*} else if ( ) { + m_Stream.Write( (byte) 0x01 ); + + m_Stream.Write( (int) item.Serial ); + + m_Stream.Write( (ushort) itemID ); + + m_Stream.Write( (byte) item.Direction );*/ + } + else + { + m_Stream.Write((byte)0x00); + + m_Stream.Write(item.Serial); + + itemID &= 0xFFFF; + + m_Stream.Write((ushort)itemID); + + m_Stream.Write((byte)0); + } + + int amount = item.Amount; + m_Stream.Write((short)amount); + m_Stream.Write((short)amount); + + Point3D loc = item.Location; + int x = loc.m_X & 0x7FFF; + int y = loc.m_Y & 0x3FFF; + m_Stream.Write((short)x); + m_Stream.Write((short)y); + m_Stream.Write((sbyte)loc.m_Z); + + m_Stream.Write((byte)item.Light); + m_Stream.Write((short)item.Hue); + m_Stream.Write((byte)item.GetPacketFlags()); + + m_Stream.Write((short)0x00); // ?? + } + } + + public sealed class LiftRej : Packet + { + public LiftRej(LRReason reason) : base(0x27, 2) + { + m_Stream.Write((byte)reason); + } + } + + public sealed class LogoutAck : Packet + { + public LogoutAck() : base(0xD1, 2) + { + m_Stream.Write((byte)0x01); + } + } + + public sealed class Weather : Packet + { + public Weather(int v1, int v2, int v3) : base(0x65, 4) + { + m_Stream.Write((byte)v1); + m_Stream.Write((byte)v2); + m_Stream.Write((byte)v3); + } + } + + public sealed class UnkD3 : Packet + { + public UnkD3(Mobile beholder, Mobile beheld) : base(0xD3) + { + EnsureCapacity(256); + + //int + //short + //short + //short + //byte + //byte + //short + //byte + //byte + //short + //short + //short + //while ( int != 0 ) + //{ + //short + //byte + //short + //} + + m_Stream.Write(beheld.Serial); + m_Stream.Write((short)beheld.Body); + m_Stream.Write((short)beheld.X); + m_Stream.Write((short)beheld.Y); + m_Stream.Write((sbyte)beheld.Z); + m_Stream.Write((byte)beheld.Direction); + m_Stream.Write((ushort)beheld.Hue); + m_Stream.Write((byte)beheld.GetPacketFlags()); + m_Stream.Write((byte)Notoriety.Compute(beholder, beheld)); + + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + + m_Stream.Write(0); + } + } + + public sealed class GQRequest : Packet + { + public GQRequest() : base(0xC3) + { + EnsureCapacity(256); + + m_Stream.Write(1); + m_Stream.Write(2); // ID + m_Stream.Write(3); // Customer ? (this) + m_Stream.Write(4); // Customer this (?) + m_Stream.Write(0); + m_Stream.Write((short)0); + m_Stream.Write((short)6); + m_Stream.Write((byte)'r'); + m_Stream.Write((byte)'e'); + m_Stream.Write((byte)'g'); + m_Stream.Write((byte)'i'); + m_Stream.Write((byte)'o'); + m_Stream.Write((byte)'n'); + m_Stream.Write(7); // Call time in seconds + m_Stream.Write((short)2); // Map (0=fel,1=tram,2=ilsh) + m_Stream.Write(8); // X + m_Stream.Write(9); // Y + m_Stream.Write(10); // Z + m_Stream.Write(11); // Volume + m_Stream.Write(12); // Rank + m_Stream.Write(-1); + m_Stream.Write(1); // type + } + } + + /// + /// Causes the client to walk in a given direction. It does not send a movement request. + /// + public sealed class PlayerMove : Packet + { + public PlayerMove(Direction d) : base(0x97, 2) + { + m_Stream.Write((byte)d); + + // @4C63B0 + } + } + + /// + /// Displays a message "There are currently [count] available calls in the global queue.". + /// + public sealed class GQCount : Packet + { + public GQCount(int unk, int count) : base(0xCB, 7) + { + m_Stream.Write((short)unk); + m_Stream.Write(count); + } + } + + /// + /// Asks the client for it's version + /// + public sealed class ClientVersionReq : Packet + { + public ClientVersionReq() : base(0xBD) + { + EnsureCapacity(3); + } + } + + /// + /// Asks the client for it's "assist version". (Perhaps for UOAssist?) + /// + public sealed class AssistVersionReq : Packet + { + public AssistVersionReq(int unk) : base(0xBE) + { + EnsureCapacity(7); + + m_Stream.Write(unk); + } + } + + public enum EffectType + { + Moving = 0x00, + Lightning = 0x01, + FixedXYZ = 0x02, + FixedFrom = 0x03 + } + + public class ParticleEffect : Packet + { + public ParticleEffect(EffectType type, Serial from, Serial to, int itemID, Point3D fromPoint, Point3D toPoint, + int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode, int effect, + int explodeEffect, int explodeSound, Serial serial, int layer, int unknown) : base(0xC7, 49) + { + m_Stream.Write((byte)type); + m_Stream.Write(from); + m_Stream.Write(to); + m_Stream.Write((short)itemID); + m_Stream.Write((short)fromPoint.m_X); + m_Stream.Write((short)fromPoint.m_Y); + m_Stream.Write((sbyte)fromPoint.m_Z); + m_Stream.Write((short)toPoint.m_X); + m_Stream.Write((short)toPoint.m_Y); + m_Stream.Write((sbyte)toPoint.m_Z); + m_Stream.Write((byte)speed); + m_Stream.Write((byte)duration); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0); + m_Stream.Write(fixedDirection); + m_Stream.Write(explode); + m_Stream.Write(hue); + m_Stream.Write(renderMode); + m_Stream.Write((short)effect); + m_Stream.Write((short)explodeEffect); + m_Stream.Write((short)explodeSound); + m_Stream.Write(serial); + m_Stream.Write((byte)layer); + m_Stream.Write((short)unknown); + } + + public ParticleEffect(EffectType type, Serial from, Serial to, int itemID, IPoint3D fromPoint, IPoint3D toPoint, + int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode, int effect, + int explodeEffect, int explodeSound, Serial serial, int layer, int unknown) : base(0xC7, 49) + { + m_Stream.Write((byte)type); + m_Stream.Write(from); + m_Stream.Write(to); + m_Stream.Write((short)itemID); + m_Stream.Write((short)fromPoint.X); + m_Stream.Write((short)fromPoint.Y); + m_Stream.Write((sbyte)fromPoint.Z); + m_Stream.Write((short)toPoint.X); + m_Stream.Write((short)toPoint.Y); + m_Stream.Write((sbyte)toPoint.Z); + m_Stream.Write((byte)speed); + m_Stream.Write((byte)duration); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0); + m_Stream.Write(fixedDirection); + m_Stream.Write(explode); + m_Stream.Write(hue); + m_Stream.Write(renderMode); + m_Stream.Write((short)effect); + m_Stream.Write((short)explodeEffect); + m_Stream.Write((short)explodeSound); + m_Stream.Write(serial); + m_Stream.Write((byte)layer); + m_Stream.Write((short)unknown); + } + } + + public class HuedEffect : Packet + { + public HuedEffect(EffectType type, Serial from, Serial to, int itemID, Point3D fromPoint, Point3D toPoint, int speed, + int duration, bool fixedDirection, bool explode, int hue, int renderMode) : base(0xC0, 36) + { + m_Stream.Write((byte)type); + m_Stream.Write(from); + m_Stream.Write(to); + m_Stream.Write((short)itemID); + m_Stream.Write((short)fromPoint.m_X); + m_Stream.Write((short)fromPoint.m_Y); + m_Stream.Write((sbyte)fromPoint.m_Z); + m_Stream.Write((short)toPoint.m_X); + m_Stream.Write((short)toPoint.m_Y); + m_Stream.Write((sbyte)toPoint.m_Z); + m_Stream.Write((byte)speed); + m_Stream.Write((byte)duration); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0); + m_Stream.Write(fixedDirection); + m_Stream.Write(explode); + m_Stream.Write(hue); + m_Stream.Write(renderMode); + } + + public HuedEffect(EffectType type, Serial from, Serial to, int itemID, IPoint3D fromPoint, IPoint3D toPoint, + int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode) : base(0xC0, 36) + { + m_Stream.Write((byte)type); + m_Stream.Write(from); + m_Stream.Write(to); + m_Stream.Write((short)itemID); + m_Stream.Write((short)fromPoint.X); + m_Stream.Write((short)fromPoint.Y); + m_Stream.Write((sbyte)fromPoint.Z); + m_Stream.Write((short)toPoint.X); + m_Stream.Write((short)toPoint.Y); + m_Stream.Write((sbyte)toPoint.Z); + m_Stream.Write((byte)speed); + m_Stream.Write((byte)duration); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0); + m_Stream.Write(fixedDirection); + m_Stream.Write(explode); + m_Stream.Write(hue); + m_Stream.Write(renderMode); + } + } + + public sealed class TargetParticleEffect : ParticleEffect + { + public TargetParticleEffect(IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, + int layer, int unknown) : base(EffectType.FixedFrom, e.Serial, Serial.Zero, itemID, e.Location, e.Location, + speed, duration, true, false, hue, renderMode, effect, 1, 0, e.Serial, layer, unknown) + { + } + } + + public sealed class TargetEffect : HuedEffect + { + public TargetEffect(IEntity e, int itemID, int speed, int duration, int hue, int renderMode) : base( + EffectType.FixedFrom, e.Serial, Serial.Zero, itemID, e.Location, e.Location, speed, duration, true, false, hue, + renderMode) + { + } + } + + public sealed class LocationParticleEffect : ParticleEffect + { + public LocationParticleEffect(IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, + int unknown) : base(EffectType.FixedXYZ, e.Serial, Serial.Zero, itemID, e.Location, e.Location, speed, duration, + true, false, hue, renderMode, effect, 1, 0, e.Serial, 255, unknown) + { + } + } + + public sealed class LocationEffect : HuedEffect + { + public LocationEffect(IPoint3D p, int itemID, int speed, int duration, int hue, int renderMode) : base( + EffectType.FixedXYZ, Serial.Zero, Serial.Zero, itemID, p, p, speed, duration, true, false, hue, renderMode) + { + } + } + + public sealed class MovingParticleEffect : ParticleEffect + { + public MovingParticleEffect(IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, + bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, EffectLayer layer, + int unknown) : base(EffectType.Moving, from.Serial, to.Serial, itemID, from.Location, to.Location, speed, + duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, Serial.Zero, + (int)layer, unknown) + { + } + } + + public sealed class MovingEffect : HuedEffect + { + public MovingEffect(IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, + bool explodes, int hue, int renderMode) : base(EffectType.Moving, from.Serial, to.Serial, itemID, from.Location, + to.Location, speed, duration, fixedDirection, explodes, hue, renderMode) + { + } + } + + public enum ScreenEffectType + { + FadeOut = 0x00, + FadeIn = 0x01, + LightFlash = 0x02, + FadeInOut = 0x03, + DarkFlash = 0x04 + } + + public class ScreenEffect : Packet + { + public ScreenEffect(ScreenEffectType type) + : base(0x70, 28) + { + m_Stream.Write((byte)0x04); + m_Stream.Fill(8); + m_Stream.Write((short)type); + m_Stream.Fill(16); + } + } + + public sealed class ScreenFadeOut : ScreenEffect + { + public static readonly Packet Instance = SetStatic(new ScreenFadeOut()); + + public ScreenFadeOut() + : base(ScreenEffectType.FadeOut) + { + } + } + + public sealed class ScreenFadeIn : ScreenEffect + { + public static readonly Packet Instance = SetStatic(new ScreenFadeIn()); + + public ScreenFadeIn() + : base(ScreenEffectType.FadeIn) + { + } + } + + public sealed class ScreenFadeInOut : ScreenEffect + { + public static readonly Packet Instance = SetStatic(new ScreenFadeInOut()); + + public ScreenFadeInOut() + : base(ScreenEffectType.FadeInOut) + { + } + } + + public sealed class ScreenLightFlash : ScreenEffect + { + public static readonly Packet Instance = SetStatic(new ScreenLightFlash()); + + public ScreenLightFlash() + : base(ScreenEffectType.LightFlash) + { + } + } + + public sealed class ScreenDarkFlash : ScreenEffect + { + public static readonly Packet Instance = SetStatic(new ScreenDarkFlash()); + + public ScreenDarkFlash() + : base(ScreenEffectType.DarkFlash) + { + } + } + + public enum DeleteResultType + { + PasswordInvalid, + CharNotExist, + CharBeingPlayed, + CharTooYoung, + CharQueued, + BadRequest + } + + public sealed class DeleteResult : Packet + { + public DeleteResult(DeleteResultType res) : base(0x85, 2) + { + m_Stream.Write((byte)res); + } + } + + /*public sealed class MovingEffect : Packet + { + public MovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool turn, int hue, int renderMode ) : base( 0xC0, 36 ) + { + m_Stream.Write( (byte) 0x00 ); + m_Stream.Write( (int) from.Serial ); + m_Stream.Write( (int) to.Serial ); + m_Stream.Write( (short) itemID ); + m_Stream.Write( (short) from.Location.m_X ); + m_Stream.Write( (short) from.Location.m_Y ); + m_Stream.Write( (sbyte) from.Location.m_Z ); + m_Stream.Write( (short) to.Location.m_X ); + m_Stream.Write( (short) to.Location.m_Y ); + m_Stream.Write( (sbyte) to.Location.m_Z ); + m_Stream.Write( (byte) speed ); + m_Stream.Write( (byte) duration ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (bool) fixedDirection ); + m_Stream.Write( (bool) turn ); + m_Stream.Write( (int) hue ); + m_Stream.Write( (int) renderMode ); + } + }*/ + + /*public sealed class LocationEffect : Packet + { + public LocationEffect( IPoint3D p, int itemID, int duration, int hue, int renderMode ) : base( 0xC0, 36 ) + { + m_Stream.Write( (byte) 0x02 ); + m_Stream.Write( (int) Serial.Zero ); + m_Stream.Write( (int) Serial.Zero ); + m_Stream.Write( (short) itemID ); + m_Stream.Write( (short) p.X ); + m_Stream.Write( (short) p.Y ); + m_Stream.Write( (sbyte) p.Z ); + m_Stream.Write( (short) p.X ); + m_Stream.Write( (short) p.Y ); + m_Stream.Write( (sbyte) p.Z ); + m_Stream.Write( (byte) 10 ); + m_Stream.Write( (byte) duration ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 1 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (int) hue ); + m_Stream.Write( (int) renderMode ); + } + }*/ + + public sealed class BoltEffect : Packet + { + public BoltEffect(IEntity target, int hue) : base(0xC0, 36) + { + m_Stream.Write((byte)0x01); // type + m_Stream.Write(target.Serial); + m_Stream.Write(Serial.Zero); + m_Stream.Write((short)0); // itemID + m_Stream.Write((short)target.X); + m_Stream.Write((short)target.Y); + m_Stream.Write((sbyte)target.Z); + m_Stream.Write((short)target.X); + m_Stream.Write((short)target.Y); + m_Stream.Write((sbyte)target.Z); + m_Stream.Write((byte)0); // speed + m_Stream.Write((byte)0); // duration + m_Stream.Write((short)0); // unk + m_Stream.Write(false); // fixed direction + m_Stream.Write(false); // explode + m_Stream.Write(hue); + m_Stream.Write(0); // render mode + } + } + + public sealed class DisplaySpellbook : Packet + { + public DisplaySpellbook(Item book) : base(0x24, 7) + { + m_Stream.Write(book.Serial); + m_Stream.Write((short)-1); + } + } + + public sealed class DisplaySpellbookHS : Packet + { + public DisplaySpellbookHS(Item book) : base(0x24, 9) + { + m_Stream.Write(book.Serial); + m_Stream.Write((short)-1); + m_Stream.Write((short)0x7D); + } + } + + public sealed class NewSpellbookContent : Packet + { + public NewSpellbookContent(Item item, int graphic, int offset, ulong content) : base(0xBF) + { + EnsureCapacity(23); + + m_Stream.Write((short)0x1B); + m_Stream.Write((short)0x01); + + m_Stream.Write(item.Serial); + m_Stream.Write((short)graphic); + m_Stream.Write((short)offset); + + for (int i = 0; i < 8; ++i) + m_Stream.Write((byte)(content >> i * 8)); + } + } + + public sealed class SpellbookContent : Packet + { + public SpellbookContent(int count, int offset, ulong content, Item item) : base(0x3C) + { + EnsureCapacity(5 + count * 19); + + int written = 0; + + m_Stream.Write((ushort)0); + + ulong mask = 1; + + for (int i = 0; i < 64; ++i, mask <<= 1) + if ((content & mask) != 0) + { + m_Stream.Write(0x7FFFFFFF - i); + m_Stream.Write((ushort)0); + m_Stream.Write((byte)0); + m_Stream.Write((ushort)(i + offset)); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write(item.Serial); + m_Stream.Write((short)0); + + ++written; + } + + m_Stream.Seek(3, SeekOrigin.Begin); + m_Stream.Write((ushort)written); + } + } + + public sealed class SpellbookContent6017 : Packet + { + public SpellbookContent6017(int count, int offset, ulong content, Item item) : base(0x3C) + { + EnsureCapacity(5 + count * 20); + + int written = 0; + + m_Stream.Write((ushort)0); + + ulong mask = 1; + + for (int i = 0; i < 64; ++i, mask <<= 1) + if ((content & mask) != 0) + { + m_Stream.Write(0x7FFFFFFF - i); + m_Stream.Write((ushort)0); + m_Stream.Write((byte)0); + m_Stream.Write((ushort)(i + offset)); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write(item.Serial); + m_Stream.Write((short)0); + + ++written; + } + + m_Stream.Seek(3, SeekOrigin.Begin); + m_Stream.Write((ushort)written); + } + } + + public sealed class ContainerDisplay : Packet + { + public ContainerDisplay(Container c) : base(0x24, 7) + { + m_Stream.Write(c.Serial); + m_Stream.Write((short)c.GumpID); + } + } + + public sealed class ContainerDisplayHS : Packet + { + public ContainerDisplayHS(Container c) : base(0x24, 9) + { + m_Stream.Write(c.Serial); + m_Stream.Write((short)c.GumpID); + m_Stream.Write((short)0x7D); + } + } + + public sealed class ContainerContentUpdate : Packet + { + public ContainerContentUpdate(Item item) : base(0x25, 20) + { + Serial parentSerial; + + if (item.Parent is Item parentItem) + { + parentSerial = parentItem.Serial; + } + else + { + Console.WriteLine("Warning: ContainerContentUpdate on item with !(parent is Item)"); + parentSerial = Serial.Zero; + } + + m_Stream.Write(item.Serial); + m_Stream.Write((ushort)item.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)item.Amount); + m_Stream.Write((short)item.X); + m_Stream.Write((short)item.Y); + m_Stream.Write(parentSerial); + m_Stream.Write((ushort)(item.QuestItem ? Item.QuestItemHue : item.Hue)); + } + } + + public sealed class ContainerContentUpdate6017 : Packet + { + public ContainerContentUpdate6017(Item item) : base(0x25, 21) + { + Serial parentSerial; + + if (item.Parent is Item parentItem) + { + parentSerial = parentItem.Serial; + } + else + { + Console.WriteLine("Warning: ContainerContentUpdate on item with !(parent is Item)"); + parentSerial = Serial.Zero; + } + + m_Stream.Write(item.Serial); + m_Stream.Write((ushort)item.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)item.Amount); + m_Stream.Write((short)item.X); + m_Stream.Write((short)item.Y); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write(parentSerial); + m_Stream.Write((ushort)(item.QuestItem ? Item.QuestItemHue : item.Hue)); + } + } + + public sealed class ContainerContent : Packet + { + public ContainerContent(Mobile beholder, Item beheld) : base(0x3C) + { + List items = beheld.Items; + int count = items.Count; + + EnsureCapacity(5 + count * 19); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write((ushort)0); + + for (int i = 0; i < count; ++i) + { + Item child = items[i]; + + if (!child.Deleted && beholder.CanSee(child)) + { + Point3D loc = child.Location; + + m_Stream.Write(child.Serial); + m_Stream.Write((ushort)child.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)child.Amount); + m_Stream.Write((short)loc.m_X); + m_Stream.Write((short)loc.m_Y); + m_Stream.Write(beheld.Serial); + m_Stream.Write((ushort)(child.QuestItem ? Item.QuestItemHue : child.Hue)); + + ++written; + } + } + + m_Stream.Seek(pos, SeekOrigin.Begin); + m_Stream.Write((ushort)written); + } + } + + public sealed class ContainerContent6017 : Packet + { + public ContainerContent6017(Mobile beholder, Item beheld) : base(0x3C) + { + List items = beheld.Items; + int count = items.Count; + + EnsureCapacity(5 + count * 20); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write((ushort)0); + + for (int i = 0; i < count; ++i) + { + Item child = items[i]; + + if (!child.Deleted && beholder.CanSee(child)) + { + Point3D loc = child.Location; + + m_Stream.Write(child.Serial); + m_Stream.Write((ushort)child.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)child.Amount); + m_Stream.Write((short)loc.m_X); + m_Stream.Write((short)loc.m_Y); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write(beheld.Serial); + m_Stream.Write((ushort)(child.QuestItem ? Item.QuestItemHue : child.Hue)); + + ++written; + } + } + + m_Stream.Seek(pos, SeekOrigin.Begin); + m_Stream.Write((ushort)written); + } + } + + public sealed class SetWarMode : Packet + { + public static readonly Packet InWarMode = SetStatic(new SetWarMode(true)); + public static readonly Packet InPeaceMode = SetStatic(new SetWarMode(false)); + + public SetWarMode(bool mode) : base(0x72, 5) + { + m_Stream.Write(mode); + m_Stream.Write((byte)0x00); + m_Stream.Write((byte)0x32); + m_Stream.Write((byte)0x00); + //m_Stream.Fill(); + } + + public static Packet Instantiate(bool mode) => mode ? InWarMode : InPeaceMode; + } + + public sealed class Swing : Packet + { + public Swing(int flag, Mobile attacker, Mobile defender) : base(0x2F, 10) + { + m_Stream.Write((byte)flag); + m_Stream.Write(attacker.Serial); + m_Stream.Write(defender.Serial); + } + } + + public sealed class NullFastwalkStack : Packet + { + public NullFastwalkStack() : base(0xBF) + { + EnsureCapacity(256); + m_Stream.Write((short)0x1); + m_Stream.Write(0x0); + m_Stream.Write(0x0); + m_Stream.Write(0x0); + m_Stream.Write(0x0); + m_Stream.Write(0x0); + m_Stream.Write(0x0); + } + } + + public sealed class RemoveEntity : Packet + { + public RemoveEntity(IEntity entity) : base(0x1D, 5) + { + m_Stream.Write(entity.Serial); + } + } + + public sealed class ServerChange : Packet + { + public ServerChange(Mobile m, Map map) : base(0x76, 16) + { + m_Stream.Write((short)m.X); + m_Stream.Write((short)m.Y); + m_Stream.Write((short)m.Z); + m_Stream.Write((byte)0); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write((short)map.Width); + m_Stream.Write((short)map.Height); + } + } + + public sealed class SkillUpdate : Packet + { + public SkillUpdate(Skills skills) : base(0x3A) + { + EnsureCapacity(6 + skills.Length * 9); + + m_Stream.Write((byte)0x02); // type: absolute, capped + + for (int i = 0; i < skills.Length; ++i) + { + Skill s = skills[i]; + + double v = s.NonRacialValue; + int uv = (int)(v * 10); + + if (uv < 0) + uv = 0; + else if (uv >= 0x10000) + uv = 0xFFFF; + + m_Stream.Write((ushort)(s.Info.SkillID + 1)); + m_Stream.Write((ushort)uv); + m_Stream.Write((ushort)s.BaseFixedPoint); + m_Stream.Write((byte)s.Lock); + m_Stream.Write((ushort)s.CapFixedPoint); + } + + m_Stream.Write((short)0); // terminate + } + } + + public sealed class Sequence : Packet + { + public Sequence(int num) : base(0x7B, 2) + { + m_Stream.Write((byte)num); + } + } + + public sealed class SkillChange : Packet + { + public SkillChange(Skill skill) : base(0x3A) + { + EnsureCapacity(13); + + double v = skill.NonRacialValue; + int uv = (int)(v * 10); + + if (uv < 0) + uv = 0; + else if (uv >= 0x10000) + uv = 0xFFFF; + + m_Stream.Write((byte)0xDF); // type: delta, capped + m_Stream.Write((ushort)skill.Info.SkillID); + m_Stream.Write((ushort)uv); + m_Stream.Write((ushort)skill.BaseFixedPoint); + m_Stream.Write((byte)skill.Lock); + m_Stream.Write((ushort)skill.CapFixedPoint); + + /*m_Stream.Write( (short) skill.Info.SkillID ); + m_Stream.Write( (short) (skill.Value * 10.0) ); + m_Stream.Write( (short) (skill.Base * 10.0) ); + m_Stream.Write( (byte) skill.Lock ); + m_Stream.Write( (short) skill.CapFixedPoint );*/ + } + } + + public sealed class LaunchBrowser : Packet + { + public LaunchBrowser(string url) : base(0xA5) + { + if (url == null) url = ""; + + EnsureCapacity(4 + url.Length); + + m_Stream.WriteAsciiNull(url); + } + } + + public sealed class MessageLocalized : Packet + { + private static MessageLocalized[] m_Cache_IntLoc = new MessageLocalized[15000]; + private static MessageLocalized[] m_Cache_CliLoc = new MessageLocalized[100000]; + private static MessageLocalized[] m_Cache_CliLocCmp = new MessageLocalized[5000]; + + public MessageLocalized(Serial serial, int graphic, MessageType type, int hue, int font, int number, string name, + string args) : base(0xC1) + { + if (name == null) name = ""; + if (args == null) args = ""; + + if (hue == 0) + hue = 0x3B2; + + EnsureCapacity(50 + args.Length * 2); + + m_Stream.Write(serial); + m_Stream.Write((short)graphic); + m_Stream.Write((byte)type); + m_Stream.Write((short)hue); + m_Stream.Write((short)font); + m_Stream.Write(number); + m_Stream.WriteAsciiFixed(name, 30); + m_Stream.WriteLittleUniNull(args); + } + + public static MessageLocalized InstantiateGeneric(int number) + { + MessageLocalized[] cache = null; + int index = 0; + + if (number >= 3000000) + { + cache = m_Cache_IntLoc; + index = number - 3000000; + } + else if (number >= 1000000) + { + cache = m_Cache_CliLoc; + index = number - 1000000; + } + else if (number >= 500000) + { + cache = m_Cache_CliLocCmp; + index = number - 500000; + } + + MessageLocalized p; + + if (cache != null && index >= 0 && index < cache.Length) + { + p = cache[index]; + + if (p == null) + { + cache[index] = p = new MessageLocalized(Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, number, + "System", ""); + p.SetStatic(); + } + } + else + { + p = new MessageLocalized(Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, number, "System", ""); + } + + return p; + } + } + + public sealed class MobileMoving : Packet + { + public MobileMoving(Mobile m, int noto) : base(0x77, 17) + { + Point3D loc = m.Location; + + int hue = m.Hue; + + if (m.SolidHueOverride >= 0) + hue = m.SolidHueOverride; + + m_Stream.Write(m.Serial); + m_Stream.Write((short)m.Body); + m_Stream.Write((short)loc.m_X); + m_Stream.Write((short)loc.m_Y); + m_Stream.Write((sbyte)loc.m_Z); + m_Stream.Write((byte)m.Direction); + m_Stream.Write((short)hue); + m_Stream.Write((byte)m.GetPacketFlags()); + m_Stream.Write((byte)noto); + } + } + + // Pre-7.0.0.0 Mobile Moving + public sealed class MobileMovingOld : Packet + { + public MobileMovingOld(Mobile m, int noto) : base(0x77, 17) + { + Point3D loc = m.Location; + + int hue = m.Hue; + + if (m.SolidHueOverride >= 0) + hue = m.SolidHueOverride; + + m_Stream.Write(m.Serial); + m_Stream.Write((short)m.Body); + m_Stream.Write((short)loc.m_X); + m_Stream.Write((short)loc.m_Y); + m_Stream.Write((sbyte)loc.m_Z); + m_Stream.Write((byte)m.Direction); + m_Stream.Write((short)hue); + m_Stream.Write((byte)m.GetOldPacketFlags()); + m_Stream.Write((byte)noto); + } + } + + public sealed class MultiTargetReqHS : Packet + { + public MultiTargetReqHS(MultiTarget t) : base(0x99, 30) + { + m_Stream.Write(t.AllowGround); + m_Stream.Write(t.TargetID); + m_Stream.Write((byte)t.Flags); + + m_Stream.Fill(); + + m_Stream.Seek(18, SeekOrigin.Begin); + m_Stream.Write((short)t.MultiID); + m_Stream.Write((short)t.Offset.X); + m_Stream.Write((short)t.Offset.Y); + m_Stream.Write((short)t.Offset.Z); + + // DWORD Hue + } + } + + public sealed class MultiTargetReq : Packet + { + public MultiTargetReq(MultiTarget t) : base(0x99, 26) + { + m_Stream.Write(t.AllowGround); + m_Stream.Write(t.TargetID); + m_Stream.Write((byte)t.Flags); + + m_Stream.Fill(); + + m_Stream.Seek(18, SeekOrigin.Begin); + m_Stream.Write((short)t.MultiID); + m_Stream.Write((short)t.Offset.X); + m_Stream.Write((short)t.Offset.Y); + m_Stream.Write((short)t.Offset.Z); + } + } + + public sealed class CancelTarget : Packet + { + public static readonly Packet Instance = SetStatic(new CancelTarget()); + + public CancelTarget() : base(0x6C, 19) + { + m_Stream.Write((byte)0); + m_Stream.Write(0); + m_Stream.Write((byte)3); + m_Stream.Fill(); + } + } + + public sealed class TargetReq : Packet + { + public TargetReq(Target t) : base(0x6C, 19) + { + m_Stream.Write(t.AllowGround); + m_Stream.Write(t.TargetID); + m_Stream.Write((byte)t.Flags); + m_Stream.Fill(); + } + } + + public sealed class DragEffect : Packet + { + public DragEffect(IEntity src, IEntity trg, int itemID, int hue, int amount) : base(0x23, 26) + { + m_Stream.Write((short)itemID); + m_Stream.Write((byte)0); + m_Stream.Write((short)hue); + m_Stream.Write((short)amount); + m_Stream.Write(src.Serial); + m_Stream.Write((short)src.X); + m_Stream.Write((short)src.Y); + m_Stream.Write((sbyte)src.Z); + m_Stream.Write(trg.Serial); + m_Stream.Write((short)trg.X); + m_Stream.Write((short)trg.Y); + m_Stream.Write((sbyte)trg.Z); + } + } + + public interface IGumpWriter + { + int TextEntries{ get; set; } + int Switches{ get; set; } + + void AppendLayout(bool val); + void AppendLayout(int val); + void AppendLayout(uint val); + void AppendLayoutNS(int val); + void AppendLayout(string text); + void AppendLayout(byte[] buffer); + void WriteStrings(List strings); + void Flush(); + } + + public sealed class DisplayGumpPacked : Packet, IGumpWriter + { + private static byte[] m_True = Gump.StringToBuffer(" 1"); + private static byte[] m_False = Gump.StringToBuffer(" 0"); + + private static byte[] m_BeginTextSeparator = Gump.StringToBuffer(" @"); + private static byte[] m_EndTextSeparator = Gump.StringToBuffer("@"); + + private static byte[] m_Buffer = new byte[48]; + + private Gump m_Gump; + + private PacketWriter m_Layout; + + private int m_StringCount; + private PacketWriter m_Strings; + + static DisplayGumpPacked() => m_Buffer[0] = (byte)' '; + + public DisplayGumpPacked(Gump gump) + : base(0xDD) + { + m_Gump = gump; + + m_Layout = PacketWriter.CreateInstance(8192); + m_Strings = PacketWriter.CreateInstance(8192); + } + + public int TextEntries{ get; set; } + + public int Switches{ get; set; } + + public void AppendLayout(bool val) + { + AppendLayout(val ? m_True : m_False); + } + + public void AppendLayout(int val) + { + string toString = val.ToString(); + int bytes = Encoding.ASCII.GetBytes(toString, 0, toString.Length, m_Buffer, 1) + 1; + + m_Layout.Write(m_Buffer, 0, bytes); + } + + public void AppendLayout(uint val) + { + string toString = val.ToString(); + int bytes = Encoding.ASCII.GetBytes(toString, 0, toString.Length, m_Buffer, 1) + 1; + + m_Layout.Write(m_Buffer, 0, bytes); + } + + public void AppendLayoutNS(int val) + { + string toString = val.ToString(); + int bytes = Encoding.ASCII.GetBytes(toString, 0, toString.Length, m_Buffer, 1); + + m_Layout.Write(m_Buffer, 1, bytes); + } + + public void AppendLayout(string text) + { + AppendLayout(m_BeginTextSeparator); + + m_Layout.WriteAsciiFixed(text, text.Length); + + AppendLayout(m_EndTextSeparator); + } + + public void AppendLayout(byte[] buffer) + { + m_Layout.Write(buffer, 0, buffer.Length); + } + + public void WriteStrings(List strings) + { + m_StringCount = strings.Count; + + for (int i = 0; i < strings.Count; ++i) + { + string v = strings[i] ?? ""; + + m_Strings.Write((ushort)v.Length); + m_Strings.WriteBigUniFixed(v, v.Length); + } + } + + public void Flush() + { + EnsureCapacity(28 + (int)m_Layout.Length + (int)m_Strings.Length); + + m_Stream.Write(m_Gump.Serial); + m_Stream.Write(m_Gump.TypeID); + m_Stream.Write(m_Gump.X); + m_Stream.Write(m_Gump.Y); + + // Note: layout MUST be null terminated (don't listen to krrios) + m_Layout.Write((byte)0); + WritePacked(m_Layout); + + m_Stream.Write(m_StringCount); + + WritePacked(m_Strings); + + PacketWriter.ReleaseInstance(m_Layout); + PacketWriter.ReleaseInstance(m_Strings); + } + + private void WritePacked(PacketWriter src) + { + byte[] buffer = src.UnderlyingStream.GetBuffer(); + int length = (int)src.Length; + + if (length == 0) + { + m_Stream.Write(0); + return; + } + + int wantLength = 1 + buffer.Length * 1024 / 1000; + + wantLength += 4095; + wantLength &= ~4095; + + byte[] packBuffer = ArrayPool.Shared.Rent(wantLength); + + int packLength = wantLength; + + Compression.Pack(packBuffer, ref packLength, buffer, length, ZLibQuality.Default); + + m_Stream.Write(4 + packLength); + m_Stream.Write(length); + m_Stream.Write(packBuffer, 0, packLength); + + ArrayPool.Shared.Return(packBuffer); + } + } + + public sealed class DisplayGumpFast : Packet, IGumpWriter + { + private static byte[] m_True = Gump.StringToBuffer(" 1"); + private static byte[] m_False = Gump.StringToBuffer(" 0"); + + private static byte[] m_BeginTextSeparator = Gump.StringToBuffer(" @"); + private static byte[] m_EndTextSeparator = Gump.StringToBuffer("@"); + + private byte[] m_Buffer = new byte[48]; + private int m_LayoutLength; + + public DisplayGumpFast(Gump g) : base(0xB0) + { + m_Buffer[0] = (byte)' '; + + EnsureCapacity(4096); + + m_Stream.Write(g.Serial); + m_Stream.Write(g.TypeID); + m_Stream.Write(g.X); + m_Stream.Write(g.Y); + m_Stream.Write((ushort)0xFFFF); + } + + public int TextEntries{ get; set; } + + public int Switches{ get; set; } + + public void AppendLayout(bool val) + { + AppendLayout(val ? m_True : m_False); + } + + public void AppendLayout(int val) + { + string toString = val.ToString(); + int bytes = Encoding.ASCII.GetBytes(toString, 0, toString.Length, m_Buffer, 1) + 1; + + m_Stream.Write(m_Buffer, 0, bytes); + m_LayoutLength += bytes; + } + + public void AppendLayout(uint val) + { + string toString = val.ToString(); + int bytes = Encoding.ASCII.GetBytes(toString, 0, toString.Length, m_Buffer, 1) + 1; + + m_Stream.Write(m_Buffer, 0, bytes); + m_LayoutLength += bytes; + } + + public void AppendLayoutNS(int val) + { + string toString = val.ToString(); + int bytes = Encoding.ASCII.GetBytes(toString, 0, toString.Length, m_Buffer, 1); + + m_Stream.Write(m_Buffer, 1, bytes); + m_LayoutLength += bytes; + } + + public void AppendLayout(string text) + { + AppendLayout(m_BeginTextSeparator); + + int length = text.Length; + m_Stream.WriteAsciiFixed(text, length); + m_LayoutLength += length; + + AppendLayout(m_EndTextSeparator); + } + + public void AppendLayout(byte[] buffer) + { + int length = buffer.Length; + m_Stream.Write(buffer, 0, length); + m_LayoutLength += length; + } + + public void WriteStrings(List text) + { + m_Stream.Seek(19, SeekOrigin.Begin); + m_Stream.Write((ushort)m_LayoutLength); + m_Stream.Seek(0, SeekOrigin.End); + + m_Stream.Write((ushort)text.Count); + + for (int i = 0; i < text.Count; ++i) + { + string v = text[i] ?? ""; + + int length = (ushort)v.Length; + + m_Stream.Write((ushort)length); + m_Stream.WriteBigUniFixed(v, length); + } + } + + public void Flush() + { + } + } + + public sealed class DisplayGump : Packet + { + public DisplayGump(Gump g, string layout, string[] text) : base(0xB0) + { + if (layout == null) layout = ""; + + EnsureCapacity(256); + + m_Stream.Write(g.Serial); + m_Stream.Write(g.TypeID); + m_Stream.Write(g.X); + m_Stream.Write(g.Y); + m_Stream.Write((ushort)(layout.Length + 1)); + m_Stream.WriteAsciiNull(layout); + + m_Stream.Write((ushort)text.Length); + + for (int i = 0; i < text.Length; ++i) + { + string v = text[i] ?? ""; + + ushort length = (ushort)v.Length; + + m_Stream.Write(length); + m_Stream.WriteBigUniFixed(v, length); + } + } + } + + public sealed class DisplayPaperdoll : Packet + { + public DisplayPaperdoll(Mobile m, string text, bool canLift) : base(0x88, 66) + { + byte flags = 0x00; + + if (m.Warmode) + flags |= 0x01; + + if (canLift) + flags |= 0x02; + + m_Stream.Write(m.Serial); + m_Stream.WriteAsciiFixed(text, 60); + m_Stream.Write(flags); + } + } + + public sealed class PopupMessage : Packet + { + public PopupMessage(PMMessage msg) : base(0x53, 2) + { + m_Stream.Write((byte)msg); + } + } + + public sealed class PlaySound : Packet + { + public PlaySound(int soundID, IPoint3D target) : base(0x54, 12) + { + m_Stream.Write((byte)1); // flags + m_Stream.Write((short)soundID); + m_Stream.Write((short)0); // volume + m_Stream.Write((short)target.X); + m_Stream.Write((short)target.Y); + m_Stream.Write((short)target.Z); + } + } + + public sealed class PlayMusic : Packet + { + public static readonly Packet InvalidInstance = SetStatic(new PlayMusic(MusicName.Invalid)); + + private static Packet[] m_Instances = new Packet[60]; + + public PlayMusic(MusicName name) : base(0x6D, 3) + { + m_Stream.Write((short)name); + } + + public static Packet GetInstance(MusicName name) + { + if (name == MusicName.Invalid) + return InvalidInstance; + + int v = (int)name; + Packet p; + + if (v >= 0 && v < m_Instances.Length) + { + p = m_Instances[v]; + + if (p == null) + m_Instances[v] = p = SetStatic(new PlayMusic(name)); + } + else + { + p = new PlayMusic(name); + } + + return p; + } + } + + public sealed class ScrollMessage : Packet + { + public ScrollMessage(int type, int tip, string text) : base(0xA6) + { + if (text == null) text = ""; + + EnsureCapacity(10 + text.Length); + + m_Stream.Write((byte)type); + m_Stream.Write(tip); + m_Stream.Write((ushort)text.Length); + m_Stream.WriteAsciiFixed(text, text.Length); + } + } + + public sealed class CurrentTime : Packet + { + public CurrentTime() : base(0x5B, 4) + { + DateTime now = DateTime.UtcNow; + + m_Stream.Write((byte)now.Hour); + m_Stream.Write((byte)now.Minute); + m_Stream.Write((byte)now.Second); + } + } + + public sealed class MapChange : Packet + { + public MapChange(Mobile m) : base(0xBF) + { + EnsureCapacity(6); + + m_Stream.Write((short)0x08); + m_Stream.Write((byte)(m.Map?.MapID ?? 0)); + } + } + + public sealed class SeasonChange : Packet + { + private static SeasonChange[][] m_Cache = new SeasonChange[][] + { + new SeasonChange[2], + new SeasonChange[2], + new SeasonChange[2], + new SeasonChange[2], + new SeasonChange[2] + }; + + public SeasonChange(int season, bool playSound = true) : base(0xBC, 3) + { + m_Stream.Write((byte)season); + m_Stream.Write(playSound); + } + + public static SeasonChange Instantiate(int season) => Instantiate(season, true); + + public static SeasonChange Instantiate(int season, bool playSound) + { + if (season >= 0 && season < m_Cache.Length) + { + int idx = playSound ? 1 : 0; + + SeasonChange p = m_Cache[season][idx]; + + if (p == null) + { + m_Cache[season][idx] = p = new SeasonChange(season, playSound); + p.SetStatic(); + } + + return p; + } + + return new SeasonChange(season, playSound); + } + } + + public sealed class SupportedFeatures : Packet + { + public SupportedFeatures(NetState ns) : base(0xB9, ns.ExtendedSupportedFeatures ? 5 : 3) + { + FeatureFlags flags = ExpansionInfo.CoreExpansion.SupportedFeatures; + + flags |= Value; + + if (ns.Account is IAccount acct && acct.Limit >= 6) + { + flags |= FeatureFlags.LiveAccount; + flags &= ~FeatureFlags.UOTD; + + if (acct.Limit > 6) + flags |= FeatureFlags.SeventhCharacterSlot; + else + flags |= FeatureFlags.SixthCharacterSlot; + } + + if (ns.ExtendedSupportedFeatures) + m_Stream.Write((uint)flags); + else + m_Stream.Write((ushort)flags); + } + + public static FeatureFlags Value{ get; set; } + + public static SupportedFeatures Instantiate(NetState ns) => new SupportedFeatures(ns); + } + + public static class AttributeNormalizer + { + public static int Maximum{ get; set; } = 25; + + public static bool Enabled{ get; set; } = true; + + public static void Write(PacketWriter stream, int cur, int max) + { + if (Enabled && max != 0) + { + stream.Write((short)Maximum); + stream.Write((short)(cur * Maximum / max)); + } + else + { + stream.Write((short)max); + stream.Write((short)cur); + } + } + + public static void WriteReverse(PacketWriter stream, int cur, int max) + { + if (Enabled && max != 0) + { + stream.Write((short)(cur * Maximum / max)); + stream.Write((short)Maximum); + } + else + { + stream.Write((short)cur); + stream.Write((short)max); + } + } + } + + public sealed class MobileHits : Packet + { + public MobileHits(Mobile m) : base(0xA1, 9) + { + m_Stream.Write(m.Serial); + m_Stream.Write((short)m.HitsMax); + m_Stream.Write((short)m.Hits); + } + } + + public sealed class MobileHitsN : Packet + { + public MobileHitsN(Mobile m) : base(0xA1, 9) + { + m_Stream.Write(m.Serial); + AttributeNormalizer.Write(m_Stream, m.Hits, m.HitsMax); + } + } + + public sealed class MobileMana : Packet + { + public MobileMana(Mobile m) : base(0xA2, 9) + { + m_Stream.Write(m.Serial); + m_Stream.Write((short)m.ManaMax); + m_Stream.Write((short)m.Mana); + } + } + + public sealed class MobileManaN : Packet + { + public MobileManaN(Mobile m) : base(0xA2, 9) + { + m_Stream.Write(m.Serial); + AttributeNormalizer.Write(m_Stream, m.Mana, m.ManaMax); + } + } + + public sealed class MobileStam : Packet + { + public MobileStam(Mobile m) : base(0xA3, 9) + { + m_Stream.Write(m.Serial); + m_Stream.Write((short)m.StamMax); + m_Stream.Write((short)m.Stam); + } + } + + public sealed class MobileStamN : Packet + { + public MobileStamN(Mobile m) : base(0xA3, 9) + { + m_Stream.Write(m.Serial); + AttributeNormalizer.Write(m_Stream, m.Stam, m.StamMax); + } + } + + public sealed class MobileAttributes : Packet + { + public MobileAttributes(Mobile m) : base(0x2D, 17) + { + m_Stream.Write(m.Serial); + + m_Stream.Write((short)m.HitsMax); + m_Stream.Write((short)m.Hits); + + m_Stream.Write((short)m.ManaMax); + m_Stream.Write((short)m.Mana); + + m_Stream.Write((short)m.StamMax); + m_Stream.Write((short)m.Stam); + } + } + + public sealed class MobileAttributesN : Packet + { + public MobileAttributesN(Mobile m) : base(0x2D, 17) + { + m_Stream.Write(m.Serial); + + AttributeNormalizer.Write(m_Stream, m.Hits, m.HitsMax); + AttributeNormalizer.Write(m_Stream, m.Mana, m.ManaMax); + AttributeNormalizer.Write(m_Stream, m.Stam, m.StamMax); + } + } + + public sealed class PathfindMessage : Packet + { + public PathfindMessage(IPoint3D p) : base(0x38, 7) + { + m_Stream.Write((short)p.X); + m_Stream.Write((short)p.Y); + m_Stream.Write((short)p.Z); + } + } + + // unsure of proper format, client crashes + public sealed class MobileName : Packet + { + public MobileName(Mobile m) : base(0x98) + { + EnsureCapacity(37); + + m_Stream.Write(m.Serial); + m_Stream.WriteAsciiFixed(m.Name ?? "", 30); + } + } + + public sealed class MobileAnimation : Packet + { + public MobileAnimation(Mobile m, int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) : + base(0x6E, 14) + { + m_Stream.Write(m.Serial); + m_Stream.Write((short)action); + m_Stream.Write((short)frameCount); + m_Stream.Write((short)repeatCount); + m_Stream.Write(!forward); // protocol has really "reverse" but I find this more intuitive + m_Stream.Write(repeat); + m_Stream.Write((byte)delay); + } + } + + public sealed class NewMobileAnimation : Packet + { + public NewMobileAnimation(Mobile m, int action, int frameCount, int delay) : base(0xE2, 10) + { + m_Stream.Write(m.Serial); + m_Stream.Write((short)action); + m_Stream.Write((short)frameCount); + m_Stream.Write((byte)delay); + } + } + + public sealed class MobileStatusCompact : Packet + { + public MobileStatusCompact(bool canBeRenamed, Mobile m) : base(0x11) + { + EnsureCapacity(43); + + m_Stream.Write(m.Serial); + m_Stream.WriteAsciiFixed(m.Name ?? "", 30); + + AttributeNormalizer.WriteReverse(m_Stream, m.Hits, m.HitsMax); + + m_Stream.Write(canBeRenamed); + + m_Stream.Write((byte)0); // type + } + } + + public sealed class MobileStatusExtended : Packet + { + public MobileStatusExtended(Mobile m) : this(m, m.NetState) + { + } + + public MobileStatusExtended(Mobile m, NetState ns) : base(0x11) + { + string name = m.Name ?? ""; + + int type; + + if (Core.HS && ns?.ExtendedStatus == true) + { + type = 6; + EnsureCapacity(121); + } + else if (Core.ML && ns?.SupportsExpansion(Expansion.ML) == true) + { + type = 5; + EnsureCapacity(91); + } + else + { + type = Core.AOS ? 4 : 3; + EnsureCapacity(88); + } + + m_Stream.Write(m.Serial); + m_Stream.WriteAsciiFixed(name, 30); + + m_Stream.Write((short)m.Hits); + m_Stream.Write((short)m.HitsMax); + + m_Stream.Write(m.CanBeRenamedBy(m)); + + m_Stream.Write((byte)type); + + m_Stream.Write(m.Female); + + m_Stream.Write((short)m.Str); + m_Stream.Write((short)m.Dex); + m_Stream.Write((short)m.Int); + + m_Stream.Write((short)m.Stam); + m_Stream.Write((short)m.StamMax); + + m_Stream.Write((short)m.Mana); + m_Stream.Write((short)m.ManaMax); + + m_Stream.Write(m.TotalGold); + m_Stream.Write((short)(Core.AOS ? m.PhysicalResistance : (int)(m.ArmorRating + 0.5))); + m_Stream.Write((short)(Mobile.BodyWeight + m.TotalWeight)); + + if (type >= 5) + { + m_Stream.Write((short)m.MaxWeight); + m_Stream.Write((byte)(m.Race.RaceID + 1)); // Would be 0x00 if it's a non-ML enabled account but... + } + + m_Stream.Write((short)m.StatCap); + + m_Stream.Write((byte)m.Followers); + m_Stream.Write((byte)m.FollowersMax); + + if (type >= 4) + { + m_Stream.Write((short)m.FireResistance); // Fire + m_Stream.Write((short)m.ColdResistance); // Cold + m_Stream.Write((short)m.PoisonResistance); // Poison + m_Stream.Write((short)m.EnergyResistance); // Energy + m_Stream.Write((short)m.Luck); // Luck + + IWeapon weapon = m.Weapon; + + if (weapon != null) + { + weapon.GetStatusDamage(m, out int min, out int max); + m_Stream.Write((short)min); // Damage min + m_Stream.Write((short)max); // Damage max + } + else + { + m_Stream.Write((short)0); // Damage min + m_Stream.Write((short)0); // Damage max + } + + m_Stream.Write(m.TithingPoints); + } + + if (type >= 6) + for (int i = 0; i < 15; ++i) + m_Stream.Write((short)m.GetAOSStatus(i)); + } + } + + public sealed class MobileStatus : Packet + { + public MobileStatus(Mobile beholder, Mobile beheld) : this(beholder, beheld, beheld.NetState) + { + } + + public MobileStatus(Mobile beholder, Mobile beheld, NetState ns) : base(0x11) + { + string name = beheld.Name ?? ""; + + int type; + + if (beholder != beheld) + { + type = 0; + EnsureCapacity(43); + } + else if (Core.HS && ns?.ExtendedStatus == true) + { + type = 6; + EnsureCapacity(121); + } + else if (Core.ML && ns?.SupportsExpansion(Expansion.ML) == true) + { + type = 5; + EnsureCapacity(91); + } + else + { + type = Core.AOS ? 4 : 3; + EnsureCapacity(88); + } + + m_Stream.Write(beheld.Serial); + + m_Stream.WriteAsciiFixed(name, 30); + + if (beholder == beheld) + WriteAttr(beheld.Hits, beheld.HitsMax); + else + WriteAttrNorm(beheld.Hits, beheld.HitsMax); + + m_Stream.Write(beheld.CanBeRenamedBy(beholder)); + + m_Stream.Write((byte)type); + + if (type <= 0) + return; + + m_Stream.Write(beheld.Female); + + m_Stream.Write((short)beheld.Str); + m_Stream.Write((short)beheld.Dex); + m_Stream.Write((short)beheld.Int); + + WriteAttr(beheld.Stam, beheld.StamMax); + WriteAttr(beheld.Mana, beheld.ManaMax); + + m_Stream.Write(beheld.TotalGold); + m_Stream.Write((short)(Core.AOS ? beheld.PhysicalResistance : (int)(beheld.ArmorRating + 0.5))); + m_Stream.Write((short)(Mobile.BodyWeight + beheld.TotalWeight)); + + if (type >= 5) + { + m_Stream.Write((short)beheld.MaxWeight); + m_Stream.Write((byte)(beheld.Race.RaceID + 1)); // Would be 0x00 if it's a non-ML enabled account but... + } + + m_Stream.Write((short)beheld.StatCap); + + m_Stream.Write((byte)beheld.Followers); + m_Stream.Write((byte)beheld.FollowersMax); + + if (type >= 4) + { + m_Stream.Write((short)beheld.FireResistance); // Fire + m_Stream.Write((short)beheld.ColdResistance); // Cold + m_Stream.Write((short)beheld.PoisonResistance); // Poison + m_Stream.Write((short)beheld.EnergyResistance); // Energy + m_Stream.Write((short)beheld.Luck); // Luck + + IWeapon weapon = beheld.Weapon; + + if (weapon != null) + { + weapon.GetStatusDamage(beheld, out int min, out int max); + m_Stream.Write((short)min); // Damage min + m_Stream.Write((short)max); // Damage max + } + else + { + m_Stream.Write((short)0); // Damage min + m_Stream.Write((short)0); // Damage max + } + + m_Stream.Write(beheld.TithingPoints); + } + + if (type >= 6) + for (int i = 0; i < 15; ++i) + m_Stream.Write((short)beheld.GetAOSStatus(i)); + } + + private void WriteAttr(int current, int maximum) + { + m_Stream.Write((short)current); + m_Stream.Write((short)maximum); + } + + private void WriteAttrNorm(int current, int maximum) + { + AttributeNormalizer.WriteReverse(m_Stream, current, maximum); + } + } + + public sealed class HealthbarPoison : Packet + { + public HealthbarPoison(Mobile m) : base(0x17) + { + EnsureCapacity(12); + + m_Stream.Write(m.Serial); + m_Stream.Write((short)1); + + m_Stream.Write((short)1); + + Poison p = m.Poison; + + if (p != null) + m_Stream.Write((byte)(p.Level + 1)); + else + m_Stream.Write((byte)0); + } + } + + public sealed class HealthbarYellow : Packet + { + public HealthbarYellow(Mobile m) : base(0x17) + { + EnsureCapacity(12); + + m_Stream.Write(m.Serial); + m_Stream.Write((short)1); + + m_Stream.Write((short)2); + + if (m.Blessed || m.YellowHealthbar) + m_Stream.Write((byte)1); + else + m_Stream.Write((byte)0); + } + } + + public sealed class MobileUpdate : Packet + { + public MobileUpdate(Mobile m) : base(0x20, 19) + { + int hue = m.Hue; + + if (m.SolidHueOverride >= 0) + hue = m.SolidHueOverride; + + m_Stream.Write(m.Serial); + m_Stream.Write((short)m.Body); + m_Stream.Write((byte)0); + m_Stream.Write((short)hue); + m_Stream.Write((byte)m.GetPacketFlags()); + m_Stream.Write((short)m.X); + m_Stream.Write((short)m.Y); + m_Stream.Write((short)0); + m_Stream.Write((byte)m.Direction); + m_Stream.Write((sbyte)m.Z); + } + } + + // Pre-7.0.0.0 Mobile Update + public sealed class MobileUpdateOld : Packet + { + public MobileUpdateOld(Mobile m) : base(0x20, 19) + { + int hue = m.Hue; + + if (m.SolidHueOverride >= 0) + hue = m.SolidHueOverride; + + m_Stream.Write(m.Serial); + m_Stream.Write((short)m.Body); + m_Stream.Write((byte)0); + m_Stream.Write((short)hue); + m_Stream.Write((byte)m.GetOldPacketFlags()); + m_Stream.Write((short)m.X); + m_Stream.Write((short)m.Y); + m_Stream.Write((short)0); + m_Stream.Write((byte)m.Direction); + m_Stream.Write((sbyte)m.Z); + } + } + + public sealed class MobileIncoming : Packet + { + private static ThreadLocal m_DupedLayersTL = new ThreadLocal(() => { return new int[256]; }); + private static ThreadLocal m_VersionTL = new ThreadLocal(); + + public Mobile m_Beheld; + + public MobileIncoming(Mobile beholder, Mobile beheld) : base(0x78) + { + m_Beheld = beheld; + + int m_Version = ++m_VersionTL.Value; + int[] m_DupedLayers = m_DupedLayersTL.Value; + + List eq = beheld.Items; + int count = eq.Count; + + if (beheld.HairItemID > 0) + count++; + if (beheld.FacialHairItemID > 0) + count++; + + EnsureCapacity(23 + count * 9); + + int hue = beheld.Hue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + m_Stream.Write(beheld.Serial); + m_Stream.Write((short)beheld.Body); + m_Stream.Write((short)beheld.X); + m_Stream.Write((short)beheld.Y); + m_Stream.Write((sbyte)beheld.Z); + m_Stream.Write((byte)beheld.Direction); + m_Stream.Write((short)hue); + m_Stream.Write((byte)beheld.GetPacketFlags()); + m_Stream.Write((byte)Notoriety.Compute(beholder, beheld)); + + for (int i = 0; i < eq.Count; ++i) + { + Item item = eq[i]; + + byte layer = (byte)item.Layer; + + if (!item.Deleted && beholder.CanSee(item) && m_DupedLayers[layer] != m_Version) + { + m_DupedLayers[layer] = m_Version; + + hue = item.Hue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = item.ItemID & 0xFFFF; + + m_Stream.Write(item.Serial); + m_Stream.Write((ushort)itemID); + m_Stream.Write(layer); + + m_Stream.Write((short)hue); + } + } + + if (beheld.HairItemID > 0) + if (m_DupedLayers[(int)Layer.Hair] != m_Version) + { + m_DupedLayers[(int)Layer.Hair] = m_Version; + hue = beheld.HairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.HairItemID & 0xFFFF; + + m_Stream.Write(HairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.Hair); + + m_Stream.Write((short)hue); + } + + if (beheld.FacialHairItemID > 0) + if (m_DupedLayers[(int)Layer.FacialHair] != m_Version) + { + m_DupedLayers[(int)Layer.FacialHair] = m_Version; + hue = beheld.FacialHairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.FacialHairItemID & 0xFFFF; + + m_Stream.Write(FacialHairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.FacialHair); + + m_Stream.Write((short)hue); + } + + m_Stream.Write(0); // terminate + } + + public static Packet Create(NetState ns, Mobile beholder, Mobile beheld) + { + if (ns.NewMobileIncoming) + return new MobileIncoming(beholder, beheld); + if (ns.StygianAbyss) + return new MobileIncomingSA(beholder, beheld); + return new MobileIncomingOld(beholder, beheld); + } + } + + public sealed class MobileIncomingSA : Packet + { + private static ThreadLocal m_DupedLayersTL = new ThreadLocal(() => { return new int[256]; }); + private static ThreadLocal m_VersionTL = new ThreadLocal(); + + public Mobile m_Beheld; + + public MobileIncomingSA(Mobile beholder, Mobile beheld) : base(0x78) + { + m_Beheld = beheld; + + int m_Version = ++m_VersionTL.Value; + int[] m_DupedLayers = m_DupedLayersTL.Value; + + List eq = beheld.Items; + int count = eq.Count; + + if (beheld.HairItemID > 0) + count++; + if (beheld.FacialHairItemID > 0) + count++; + + EnsureCapacity(23 + count * 9); + + int hue = beheld.Hue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + m_Stream.Write(beheld.Serial); + m_Stream.Write((short)beheld.Body); + m_Stream.Write((short)beheld.X); + m_Stream.Write((short)beheld.Y); + m_Stream.Write((sbyte)beheld.Z); + m_Stream.Write((byte)beheld.Direction); + m_Stream.Write((short)hue); + m_Stream.Write((byte)beheld.GetPacketFlags()); + m_Stream.Write((byte)Notoriety.Compute(beholder, beheld)); + + for (int i = 0; i < eq.Count; ++i) + { + Item item = eq[i]; + + byte layer = (byte)item.Layer; + + if (!item.Deleted && beholder.CanSee(item) && m_DupedLayers[layer] != m_Version) + { + m_DupedLayers[layer] = m_Version; + + hue = item.Hue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = item.ItemID & 0x7FFF; + bool writeHue = hue != 0; + + if (writeHue) + itemID |= 0x8000; + + m_Stream.Write(item.Serial); + m_Stream.Write((ushort)itemID); + m_Stream.Write(layer); + + if (writeHue) + m_Stream.Write((short)hue); + } + } + + if (beheld.HairItemID > 0) + if (m_DupedLayers[(int)Layer.Hair] != m_Version) + { + m_DupedLayers[(int)Layer.Hair] = m_Version; + hue = beheld.HairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.HairItemID & 0x7FFF; + + bool writeHue = hue != 0; + + if (writeHue) + itemID |= 0x8000; + + m_Stream.Write(HairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.Hair); + + if (writeHue) + m_Stream.Write((short)hue); + } + + if (beheld.FacialHairItemID > 0) + if (m_DupedLayers[(int)Layer.FacialHair] != m_Version) + { + m_DupedLayers[(int)Layer.FacialHair] = m_Version; + hue = beheld.FacialHairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.FacialHairItemID & 0x7FFF; + + bool writeHue = hue != 0; + + if (writeHue) + itemID |= 0x8000; + + m_Stream.Write(FacialHairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.FacialHair); + + if (writeHue) + m_Stream.Write((short)hue); + } + + m_Stream.Write(0); // terminate + } + } + + // Pre-7.0.0.0 Mobile Incoming + public sealed class MobileIncomingOld : Packet + { + private static ThreadLocal m_DupedLayersTL = new ThreadLocal(() => { return new int[256]; }); + private static ThreadLocal m_VersionTL = new ThreadLocal(); + + public Mobile m_Beheld; + + public MobileIncomingOld(Mobile beholder, Mobile beheld) : base(0x78) + { + m_Beheld = beheld; + + int m_Version = ++m_VersionTL.Value; + int[] m_DupedLayers = m_DupedLayersTL.Value; + + List eq = beheld.Items; + int count = eq.Count; + + if (beheld.HairItemID > 0) + count++; + if (beheld.FacialHairItemID > 0) + count++; + + EnsureCapacity(23 + count * 9); + + int hue = beheld.Hue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + m_Stream.Write(beheld.Serial); + m_Stream.Write((short)beheld.Body); + m_Stream.Write((short)beheld.X); + m_Stream.Write((short)beheld.Y); + m_Stream.Write((sbyte)beheld.Z); + m_Stream.Write((byte)beheld.Direction); + m_Stream.Write((short)hue); + m_Stream.Write((byte)beheld.GetOldPacketFlags()); + m_Stream.Write((byte)Notoriety.Compute(beholder, beheld)); + + for (int i = 0; i < eq.Count; ++i) + { + Item item = eq[i]; + + byte layer = (byte)item.Layer; + + if (!item.Deleted && beholder.CanSee(item) && m_DupedLayers[layer] != m_Version) + { + m_DupedLayers[layer] = m_Version; + + hue = item.Hue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = item.ItemID & 0x7FFF; + bool writeHue = hue != 0; + + if (writeHue) + itemID |= 0x8000; + + m_Stream.Write(item.Serial); + m_Stream.Write((ushort)itemID); + m_Stream.Write(layer); + + if (writeHue) + m_Stream.Write((short)hue); + } + } + + if (beheld.HairItemID > 0) + if (m_DupedLayers[(int)Layer.Hair] != m_Version) + { + m_DupedLayers[(int)Layer.Hair] = m_Version; + hue = beheld.HairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.HairItemID & 0x7FFF; + + bool writeHue = hue != 0; + + if (writeHue) + itemID |= 0x8000; + + m_Stream.Write(HairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.Hair); + + if (writeHue) + m_Stream.Write((short)hue); + } + + if (beheld.FacialHairItemID > 0) + if (m_DupedLayers[(int)Layer.FacialHair] != m_Version) + { + m_DupedLayers[(int)Layer.FacialHair] = m_Version; + hue = beheld.FacialHairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.FacialHairItemID & 0x7FFF; + + bool writeHue = hue != 0; + + if (writeHue) + itemID |= 0x8000; + + m_Stream.Write(FacialHairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.FacialHair); + + if (writeHue) + m_Stream.Write((short)hue); + } + + m_Stream.Write(0); // terminate + } + } + + public sealed class AsciiMessage : Packet + { + public AsciiMessage(Serial serial, int graphic, MessageType type, int hue, int font, string name, string text) : + base(0x1C) + { + if (name == null) + name = ""; + + if (text == null) + text = ""; + + if (hue == 0) + hue = 0x3B2; + + EnsureCapacity(45 + text.Length); + + m_Stream.Write(serial); + m_Stream.Write((short)graphic); + m_Stream.Write((byte)type); + m_Stream.Write((short)hue); + m_Stream.Write((short)font); + m_Stream.WriteAsciiFixed(name, 30); + m_Stream.WriteAsciiNull(text); + } + } + + public sealed class UnicodeMessage : Packet + { + public UnicodeMessage(Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name, + string text) : base(0xAE) + { + if (string.IsNullOrEmpty(lang)) lang = "ENU"; + if (name == null) name = ""; + if (text == null) text = ""; + + if (hue == 0) + hue = 0x3B2; + + EnsureCapacity(50 + text.Length * 2); + + m_Stream.Write(serial); + m_Stream.Write((short)graphic); + m_Stream.Write((byte)type); + m_Stream.Write((short)hue); + m_Stream.Write((short)font); + m_Stream.WriteAsciiFixed(lang, 4); + m_Stream.WriteAsciiFixed(name, 30); + m_Stream.WriteBigUniNull(text); + } + } + + public sealed class PingAck : Packet + { + private static PingAck[] m_Cache = new PingAck[0x100]; + + public PingAck(byte ping) : base(0x73, 2) + { + m_Stream.Write(ping); + } + + public static PingAck Instantiate(byte ping) + { + PingAck p = m_Cache[ping]; + + if (p == null) + { + m_Cache[ping] = p = new PingAck(ping); + p.SetStatic(); + } + + return p; + } + } + + public sealed class MovementRej : Packet + { + public MovementRej(int seq, Mobile m) : base(0x21, 8) + { + m_Stream.Write((byte)seq); + m_Stream.Write((short)m.X); + m_Stream.Write((short)m.Y); + m_Stream.Write((byte)m.Direction); + m_Stream.Write((sbyte)m.Z); + } + } + + public sealed class MovementAck : Packet + { + private static MovementAck[] m_Cache = new MovementAck[8 * 256]; + + private MovementAck(int seq, int noto) : base(0x22, 3) + { + m_Stream.Write((byte)seq); + m_Stream.Write((byte)noto); + } + + public static MovementAck Instantiate(int seq, Mobile m) + { + int noto = Notoriety.Compute(m, m); + + MovementAck p = m_Cache[noto * seq]; + + if (p == null) + { + m_Cache[noto * seq] = p = new MovementAck(seq, noto); + p.SetStatic(); + } + + return p; + } + } + + public sealed class LoginConfirm : Packet + { + public LoginConfirm(Mobile m) : base(0x1B, 37) + { + m_Stream.Write(m.Serial); + m_Stream.Write(0); + m_Stream.Write((short)m.Body); + m_Stream.Write((short)m.X); + m_Stream.Write((short)m.Y); + m_Stream.Write((short)m.Z); + m_Stream.Write((byte)m.Direction); + m_Stream.Write((byte)0); + m_Stream.Write(-1); + + Map map = m.Map; + + if (map == null || map == Map.Internal) + map = m.LogoutMap; + + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write((short)(map?.Width ?? 6144)); + m_Stream.Write((short)(map?.Height ?? 4096)); + + m_Stream.Fill(); + } + } + + public sealed class LoginComplete : Packet + { + public static readonly Packet Instance = SetStatic(new LoginComplete()); + + public LoginComplete() : base(0x55, 1) + { + } + } + + public sealed class CharacterListUpdate : Packet + { + public CharacterListUpdate(IAccount a) : base(0x86) + { + EnsureCapacity(4 + a.Length * 60); + + int highSlot = -1; + + for (int i = 0; i < a.Length; ++i) + if (a[i] != null) + highSlot = i; + + int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5); + + m_Stream.Write((byte)count); + + for (int i = 0; i < count; ++i) + { + Mobile m = a[i]; + + if (m != null) + { + m_Stream.WriteAsciiFixed(m.Name, 30); + m_Stream.Fill(30); // password + } + else + { + m_Stream.Fill(60); + } + } + } + } + + [Flags] + public enum ThirdPartyFeature : ulong + { + FilterWeather = 1, + FilterLight = 1 << 1, + + SmartTarget = 1 << 2, + RangedTarget = 1 << 3, + + AutoOpenDoors = 1 << 4, + + DequipOnCast = 1 << 5, + AutoPotionEquip = 1 << 6, + + ProtectHeals = 1 << 7, + + LoopedMacros = 1 << 8, + + UseOnceAgent = 1 << 9, + RestockAgent = 1 << 10, + SellAgent = 1 << 11, + BuyAgent = 1 << 12, + + PotionHotkeys = 1 << 13, + + RandomTargets = 1 << 14, + ClosestTargets = 1 << 15, // All closest target hotkeys + OverheadHealth = 1 << 16, // Health and Mana/Stam messages shown over player's heads + + AutolootAgent = 1 << 17, + BoneCutterAgent = 1 << 18, + AdvancedMacros = 1 << 19, + AutoRemount = 1 << 20, + AutoBandage = 1 << 21, + EnemyTargetShare = 1 << 22, + FilterSeason = 1 << 23, + SpellTargetShare = 1 << 24, + + All = ulong.MaxValue + } + + public static class FeatureProtection + { + public static ThirdPartyFeature DisabledFeatures{ get; private set; } = 0; + + public static void Disable(ThirdPartyFeature feature) + { + SetDisabled(feature, true); + } + + public static void Enable(ThirdPartyFeature feature) + { + SetDisabled(feature, false); + } + + public static void SetDisabled(ThirdPartyFeature feature, bool value) + { + if (value) + DisabledFeatures |= feature; + else + DisabledFeatures &= ~feature; + } + } + + public sealed class CharacterList : Packet + { + //private static MD5CryptoServiceProvider m_MD5Provider; + + public CharacterList(IAccount a, CityInfo[] info) : base(0xA9) + { + EnsureCapacity(11 + a.Length * 60 + info.Length * 89); + + int highSlot = -1; + + for (int i = 0; i < a.Length; ++i) + if (a[i] != null) + highSlot = i; + + int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5); + + m_Stream.Write((byte)count); + + for (int i = 0; i < count; ++i) + if (a[i] != null) + { + m_Stream.WriteAsciiFixed(a[i].Name, 30); + m_Stream.Fill(30); // password + } + else + { + m_Stream.Fill(60); + } + + m_Stream.Write((byte)info.Length); + + for (int i = 0; i < info.Length; ++i) + { + CityInfo ci = info[i]; + + m_Stream.Write((byte)i); + m_Stream.WriteAsciiFixed(ci.City, 32); + m_Stream.WriteAsciiFixed(ci.Building, 32); + m_Stream.Write(ci.X); + m_Stream.Write(ci.Y); + m_Stream.Write(ci.Z); + m_Stream.Write(ci.Map.MapID); + m_Stream.Write(ci.Description); + m_Stream.Write(0); + } + + CharacterListFlags flags = ExpansionInfo.CoreExpansion.CharacterListFlags; + + if (count > 6) + flags |= CharacterListFlags.SeventhCharacterSlot | + CharacterListFlags.SixthCharacterSlot; // 7th Character Slot - TODO: Is SixthCharacterSlot Required? + else if (count == 6) + flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot + else if (a.Limit == 1) + flags |= CharacterListFlags.SlotLimit & + CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character + + m_Stream.Write((int)(flags | AdditionalFlags)); // Additional Flags + + m_Stream.Write((short)-1); + + /*ThirdPartyFeature disabled = FeatureProtection.DisabledFeatures; + + if (disabled != 0) + { + if (m_MD5Provider == null) + m_MD5Provider = new MD5CryptoServiceProvider(); + + m_Stream.UnderlyingStream.Flush(); + + byte[] hashCode = m_MD5Provider.ComputeHash(m_Stream.UnderlyingStream.GetBuffer(), 0, + (int)m_Stream.UnderlyingStream.Length); + byte[] buffer = new byte[28]; + + for (int i = 0; i < count; ++i) + { + Utility.RandomBytes(buffer); + + m_Stream.Seek(35 + i * 60, SeekOrigin.Begin); + m_Stream.Write(buffer, 0, buffer.Length); + } + + m_Stream.Seek(35, SeekOrigin.Begin); + m_Stream.Write((int)((long)disabled >> 32)); + m_Stream.Write((int)disabled); + + m_Stream.Seek(95, SeekOrigin.Begin); + m_Stream.Write(hashCode, 0, hashCode.Length); + }*/ + } + + public static CharacterListFlags AdditionalFlags{ get; set; } + } + + public sealed class CharacterListOld : Packet + { + // private static MD5CryptoServiceProvider m_MD5Provider; + + public CharacterListOld(IAccount a, CityInfo[] info) : base(0xA9) + { + EnsureCapacity(9 + a.Length * 60 + info.Length * 63); + + int highSlot = -1; + + for (int i = 0; i < a.Length; ++i) + if (a[i] != null) + highSlot = i; + + int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5); + + m_Stream.Write((byte)count); + + for (int i = 0; i < count; ++i) + if (a[i] != null) + { + m_Stream.WriteAsciiFixed(a[i].Name, 30); + m_Stream.Fill(30); // password + } + else + { + m_Stream.Fill(60); + } + + m_Stream.Write((byte)info.Length); + + for (int i = 0; i < info.Length; ++i) + { + CityInfo ci = info[i]; + + m_Stream.Write((byte)i); + m_Stream.WriteAsciiFixed(ci.City, 31); + m_Stream.WriteAsciiFixed(ci.Building, 31); + } + + CharacterListFlags flags = ExpansionInfo.CoreExpansion.CharacterListFlags; + + if (count > 6) + flags |= CharacterListFlags.SeventhCharacterSlot | + CharacterListFlags.SixthCharacterSlot; // 7th Character Slot - TODO: Is SixthCharacterSlot Required? + else if (count == 6) + flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot + else if (a.Limit == 1) + flags |= CharacterListFlags.SlotLimit & + CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character + + m_Stream.Write((int)(flags | CharacterList.AdditionalFlags)); // Additional Flags + } + } + + public sealed class ClearWeaponAbility : Packet + { + public static readonly Packet Instance = SetStatic(new ClearWeaponAbility()); + + public ClearWeaponAbility() : base(0xBF) + { + EnsureCapacity(5); + + m_Stream.Write((short)0x21); + } + } + + public enum ALRReason : byte + { + Invalid = 0x00, + InUse = 0x01, + Blocked = 0x02, + BadPass = 0x03, + Idle = 0xFE, + BadComm = 0xFF + } + + public sealed class AccountLoginRej : Packet + { + public AccountLoginRej(ALRReason reason) : base(0x82, 2) + { + m_Stream.Write((byte)reason); + } + } + + [Flags] + public enum AffixType : byte + { + Append = 0x00, + Prepend = 0x01, + System = 0x02 + } + + public sealed class MessageLocalizedAffix : Packet + { + public MessageLocalizedAffix(Serial serial, int graphic, MessageType messageType, int hue, int font, int number, + string name, AffixType affixType, string affix, string args) : base(0xCC) + { + if (name == null) name = ""; + if (affix == null) affix = ""; + if (args == null) args = ""; + + if (hue == 0) + hue = 0x3B2; + + EnsureCapacity(52 + affix.Length + args.Length * 2); + + m_Stream.Write(serial); + m_Stream.Write((short)graphic); + m_Stream.Write((byte)messageType); + m_Stream.Write((short)hue); + m_Stream.Write((short)font); + m_Stream.Write(number); + m_Stream.Write((byte)affixType); + m_Stream.WriteAsciiFixed(name, 30); + m_Stream.WriteAsciiNull(affix); + m_Stream.WriteBigUniNull(args); + } + } + + public sealed class ServerInfo + { + public ServerInfo(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address) + { + Name = name; + FullPercent = fullPercent; + TimeZone = tz.GetUtcOffset(DateTime.Now).Hours; + Address = address; + } + + public string Name{ get; set; } + + public int FullPercent{ get; set; } + + public int TimeZone{ get; set; } + + public IPEndPoint Address{ get; set; } + } + + public sealed class FollowMessage : Packet + { + public FollowMessage(Serial serial1, Serial serial2) : base(0x15, 9) + { + m_Stream.Write(serial1); + m_Stream.Write(serial2); + } + } + + public sealed class AccountLoginAck : Packet + { + public AccountLoginAck(ServerInfo[] info) : base(0xA8) + { + EnsureCapacity(6 + info.Length * 40); + + m_Stream.Write((byte)0x5D); // Unknown + + m_Stream.Write((ushort)info.Length); + + for (int i = 0; i < info.Length; ++i) + { + ServerInfo si = info[i]; + + m_Stream.Write((ushort)i); + m_Stream.WriteAsciiFixed(si.Name, 32); + m_Stream.Write((byte)si.FullPercent); + m_Stream.Write((sbyte)si.TimeZone); + m_Stream.Write(Utility.GetAddressValue(si.Address.Address)); + } + } + } + + public sealed class DisplaySignGump : Packet + { + public DisplaySignGump(Serial serial, int gumpID, string unknown, string caption) : base(0x8B) + { + if (unknown == null) unknown = ""; + if (caption == null) caption = ""; + + EnsureCapacity(16 + unknown.Length + caption.Length); + + m_Stream.Write(serial); + m_Stream.Write((short)gumpID); + m_Stream.Write((short)unknown.Length); + m_Stream.WriteAsciiFixed(unknown, unknown.Length); + m_Stream.Write((short)(caption.Length + 1)); + m_Stream.WriteAsciiFixed(caption, caption.Length + 1); + } + } + + public sealed class GodModeReply : Packet + { + public GodModeReply(bool reply) : base(0x2B, 2) + { + m_Stream.Write(reply); + } + } + + public sealed class PlayServerAck : Packet + { + internal static int m_AuthID = -1; + + public PlayServerAck(ServerInfo si) : base(0x8C, 11) + { + int addr = Utility.GetAddressValue(si.Address.Address); + + m_Stream.Write((byte)addr); + m_Stream.Write((byte)(addr >> 8)); + m_Stream.Write((byte)(addr >> 16)); + m_Stream.Write((byte)(addr >> 24)); + + m_Stream.Write((short)si.Address.Port); + m_Stream.Write(m_AuthID); + } + } +} diff --git a/Projects/Server/Network/Packets/Accounts.cs b/Projects/Server/Network/Packets/Accounts.cs deleted file mode 100644 index 83715af62..000000000 --- a/Projects/Server/Network/Packets/Accounts.cs +++ /dev/null @@ -1,325 +0,0 @@ -using System; -using Server.Buffers; - -namespace Server.Network -{ - public enum DeleteResultType : byte - { - PasswordInvalid, - CharNotExist, - CharBeingPlayed, - CharTooYoung, - CharQueued, - BadRequest - } - - public enum PMMessage : byte - { - CharNoExist = 1, - CharExists = 2, - CharInWorld = 5, - LoginSyncError = 6, - IdleWarning = 7 - } - - public enum ALRReason : byte - { - Invalid = 0x00, - InUse = 0x01, - Blocked = 0x02, - BadPass = 0x03, - Idle = 0xFE, - BadComm = 0xFF - } - - public static partial class Packets - { - public static void SendDeleteResult(NetState ns, DeleteResultType res) - { - if (ns == null) - return; - - Span span = ns.SendPipe.Writer.GetSpan(2); - span[0] = 0x85; // Packet ID - span[1] = (byte)res; - - // Not compressed with Huffman - _ = ns.Flush(2); - } - - public static void SendPopupMessage(NetState ns, PMMessage msg) - { - ns?.Send(stackalloc byte[] - { - 0x53, // Packet ID - (byte)msg - }); - } - - public static void SendAccountLoginRej(NetState ns, ALRReason reason) - { - if (ns == null) - return; - - Span span = ns.SendPipe.Writer.GetSpan(2); - span[0] = 0x82; // Packet ID - span[1] = (byte)reason; - - // Not compressed with Huffman - _ = ns.Flush(2); - } - - public static void SendSupportedFeatures(NetState ns) - { - if (ns == null) - return; - - int length = ns.ExtendedSupportedFeatures ? 5 : 3; - - Span bytes = stackalloc byte[length]; - - SpanWriter w = new SpanWriter(bytes); - w.Write((byte)0xB9); // Packet ID - - FeatureFlags flags = ExpansionInfo.CoreExpansion.SupportedFeatures; - - if (ns.Account?.Limit >= 6) - { - flags &= ~FeatureFlags.UOTD; - flags |= FeatureFlags.LiveAccount | - (ns.Account.Limit > 6 ? FeatureFlags.SeventhCharacterSlot : FeatureFlags.SixthCharacterSlot); - } - - if (ns.ExtendedSupportedFeatures) - w.Write((uint)flags); - else - w.Write((ushort)flags); - - ns.Send(w.RawSpan); - } - - public static void SendCharacterList(NetState ns, CityInfo[] info) - { - if (ns == null) - return; - - if (ns.NewCharacterList) - SendCharacterListNew(ns, ns.Account, info); - else - SendCharacterListOld(ns, ns.Account, info); - } - - public static void SendCharacterListNew(NetState ns, IAccount a, CityInfo[] info) - { - if (ns == null) - return; - - int highSlot = -1; - - for (int i = 0; i < a.Length; ++i) - if (a[i] != null) - highSlot = i; - - int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5); - int length = 11 + count * 60 + info.Length * 89; - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0xA9); // Packet ID - w.Write((short)length); // Length - - w.Write((byte)count); - - for (int i = 0; i < count; ++i) - if (a[i] != null) - { - w.WriteAsciiFixed(a[i].Name, 30); - w.Position += 30; - } - else - w.Position += 60; - - w.Write((byte)info.Length); - - for (int i = 0; i < info.Length; ++i) - { - CityInfo ci = info[i]; - - w.Write((byte)i); - w.WriteAsciiFixed(ci.City, 32); - w.WriteAsciiFixed(ci.Building, 32); - w.Write(ci.X); - w.Write(ci.Y); - w.Write(ci.Z); - w.Write(ci.Map.MapID); - w.Write(ci.Description); - w.Position += 4; // w.Write(0); - } - - CharacterListFlags flags = ExpansionInfo.CoreExpansion.CharacterListFlags; - - if (count > 6) - flags |= CharacterListFlags.SeventhCharacterSlot | - CharacterListFlags.SixthCharacterSlot; // 7th Character Slot - TODO: Is SixthCharacterSlot Required? - else if (count == 6) - flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot - else if (a.Limit == 1) - flags |= CharacterListFlags.SlotLimit & - CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character - - w.Write((int)flags); - - w.Write((short)-1); - - ns.Send(w.Span); - - // TODO: Razor support? - } - - public static void SendCharacterListOld(NetState ns, IAccount a, CityInfo[] info) - { - if (ns == null) - return; - - int highSlot = -1; - - for (int i = 0; i < a.Length; ++i) - if (a[i] != null) - highSlot = i; - - int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5); - int length = 9 + count * 60 + info.Length * 63; - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0xA9); // Packet ID - w.Write((short)length); // Length - - w.Write((byte)count); - - for (int i = 0; i < count; ++i) - if (a[i] != null) - { - w.WriteAsciiFixed(a[i].Name, 30); - w.Position += 30; - } - else - w.Position += 60; - - w.Write((byte)info.Length); - - for (int i = 0; i < info.Length; ++i) - { - CityInfo ci = info[i]; - - w.Write((byte)i); - w.WriteAsciiFixed(ci.City, 31); - w.WriteAsciiFixed(ci.Building, 31); - } - - CharacterListFlags flags = ExpansionInfo.CoreExpansion.CharacterListFlags; - - if (count > 6) - flags |= CharacterListFlags.SeventhCharacterSlot | - CharacterListFlags.SixthCharacterSlot; // 7th Character Slot - TODO: Is SixthCharacterSlot Required? - else if (count == 6) - flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot - else if (a.Limit == 1) - flags |= CharacterListFlags.SlotLimit & - CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character - - w.Write((int)flags); - - ns.Send(w.RawSpan); - - // TODO: Razor support? - } - - public static void SendCharacterListUpdate(NetState ns, IAccount a) - { - if (ns == null) - return; - - int highSlot = -1; - - for (int i = 0; i < a.Length; ++i) - if (a[i] != null) - highSlot = i; - - int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5); - - int length = 4 + count * 60; - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x86); // Packet ID - w.Write((short)length); // Length - - w.Write((byte)count); - - for (int i = 0; i < count; ++i) - { - Mobile m = a[i]; - - if (m != null) - { - w.WriteAsciiFixed(m.Name, 30); - w.Position += 30; - } - else - w.Position += 60; - } - - ns.Send(w.RawSpan); - } - - public static void SendPlayServerAck(NetState ns, ServerInfo si) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(ns.SendPipe.Writer.GetSpan(11)); - w.Write((byte)0x8C); // Packet ID - - int addr = Utility.GetAddressValue(si.Address.Address); - - w.Write((byte)addr); - w.Write((byte)(addr >> 8)); - w.Write((byte)(addr >> 16)); - w.Write((byte)(addr >> 24)); - - w.Write((short)si.Address.Port); - w.Write(ns.m_AuthID); - - // Not compressed with Huffman - _ = ns.Flush(11); - } - - public static void SendAccountLoginAck(NetState ns, ServerInfo[] info) - { - if (ns == null) - return; - - int length = 6 + info.Length * 40; - - SpanWriter w = new SpanWriter(ns.SendPipe.Writer.GetSpan(length)); - w.Write((byte)0xA8); // Packet ID - w.Write((short)length); - - w.Write((byte)0x5D); // Unknown - - w.Write((ushort)info.Length); - - for (int i = 0; i < info.Length; ++i) - { - ServerInfo si = info[i]; - - w.Write((ushort)i); - w.WriteAsciiFixed(si.Name, 32, true); - w.Write((byte)si.FullPercent); - w.Write((sbyte)si.TimeZone); - w.Write(Utility.GetAddressValue(si.Address.Address)); - } - - // Not compressed with Huffman - _ = ns.Flush(length); - } - } -} diff --git a/Projects/Server/Network/Packets/Arrow.cs b/Projects/Server/Network/Packets/Arrow.cs deleted file mode 100644 index 373140c9b..000000000 --- a/Projects/Server/Network/Packets/Arrow.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Server.Buffers; - -namespace Server.Network -{ - public static partial class Packets - { - public static void SendSetArrow(NetState ns, short x, short y) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[6]); - w.Write((byte)0xBA); // Packet ID - - w.Write((byte)1); - w.Write(x); - w.Write(y); - - ns.Send(w.RawSpan); - } - - private static byte[] _cancelArrowPacket; - - public static void SendCancelArrow(NetState ns) - { - ns?.Send(_cancelArrowPacket ??= new byte[] - { - 0xBA, // Packet ID - 0x00, - 0xFF, - 0xFF, - 0xFF, - 0xFF - }); - } - - public static void SendSetArrowHS(NetState ns, Serial s, short x, short y) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[10]); - w.Write((byte)0xBA); // Packet ID - - w.Write((byte)1); - w.Write(x); - w.Write(y); - w.Write(s); - - ns.Send(w.RawSpan); - } - - public static void SendCancelArrowHS(NetState ns, Serial s, short x, short y) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[10]); - w.Write((byte)0xBA); // Packet ID - - w.Position++; - w.Write(x); - w.Write(y); - w.Write(s); - - ns.Send(w.RawSpan); - } - } -} diff --git a/Projects/Server/Network/Packets/Attributes.cs b/Projects/Server/Network/Packets/Attributes.cs deleted file mode 100644 index b228912d5..000000000 --- a/Projects/Server/Network/Packets/Attributes.cs +++ /dev/null @@ -1,168 +0,0 @@ -using Server.Buffers; - -namespace Server.Network -{ - public static partial class Packets - { - public static class AttributeNormalizer - { - public static int Maximum { get; set; } = 25; - - public static bool Enabled { get; set; } = true; - - public static void Write(SpanWriter w, int cur, int max) - { - if (Enabled && max != 0) - { - w.Write((short)Maximum); - w.Write((short)(cur * Maximum / max)); - } - else - { - w.Write((short)max); - w.Write((short)cur); - } - } - - public static void WriteReverse(SpanWriter w, int cur, int max) - { - if (Enabled && max != 0) - { - w.Write((short)(cur * Maximum / max)); - w.Write((short)Maximum); - } - else - { - w.Write((short)cur); - w.Write((short)max); - } - } - } - - public static void SendMobileHits(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0xA1); // Packet ID - - w.Write(m.Serial); - w.Write((short)m.HitsMax); - w.Write((short)m.Hits); - - ns.Send(w.RawSpan); - } - - public static void SendNormalizedMobileHits(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0xA1); // Packet ID - - w.Write(m.Serial); - AttributeNormalizer.Write(w, m.Hits, m.HitsMax); - - ns.Send(w.RawSpan); - } - - public static void SendMobileMana(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0xA2); // Packet ID - - w.Write(m.Serial); - w.Write((short)m.ManaMax); - w.Write((short)m.Mana); - - ns.Send(w.RawSpan); - } - - public static void SendNormalizedMobileMana(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0xA2); // Packet ID - - w.Write(m.Serial); - AttributeNormalizer.Write(w, m.Mana, m.ManaMax); - - ns.Send(w.RawSpan); - } - - public static void SendMobileStam(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0xA3); // Packet ID - - w.Write(m.Serial); - w.Write((short)m.StamMax); - w.Write((short)m.Stam); - - ns.Send(w.RawSpan); - } - - public static void SendNormalizedMobileStam(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0xA3); // Packet ID - - w.Write(m.Serial); - AttributeNormalizer.Write(w, m.Stam, m.StamMax); - - ns.Send(w.RawSpan); - } - - public static void SendMobileAttributes(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[17]); - w.Write((byte)0x2D); // Packet ID - - w.Write(m.Serial); - - w.Write((short)m.HitsMax); - w.Write((short)m.Hits); - - w.Write((short)m.ManaMax); - w.Write((short)m.Mana); - - w.Write((short)m.StamMax); - w.Write((short)m.Stam); - - ns.Send(w.RawSpan); - } - - public static void SendNormalizedMobileAttributes(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[17]); - w.Write((byte)0x2D); // Packet ID - - w.Write(m.Serial); - - AttributeNormalizer.Write(w, m.Hits, m.HitsMax); - AttributeNormalizer.Write(w, m.Mana, m.ManaMax); - AttributeNormalizer.Write(w, m.Stam, m.StamMax); - - ns.Send(w.RawSpan); - } - } -} diff --git a/Projects/Server/Network/Packets/Containers.cs b/Projects/Server/Network/Packets/Containers.cs deleted file mode 100644 index e57acd250..000000000 --- a/Projects/Server/Network/Packets/Containers.cs +++ /dev/null @@ -1,217 +0,0 @@ -using System; -using System.Collections.Generic; -using Server.Buffers; - -namespace Server.Network -{ - public static partial class Packets - { - public static void SendDisplayContainer(NetState ns, Serial s, short gumpId = -1) - { - if (ns == null) - return; - - if (ns.HighSeas) - SendDisplayContainerHS(ns, s, gumpId); - else - SendDisplayContainerOld(ns, s, gumpId); - } - - public static void SendDisplayContainerOld(NetState ns, Serial s, short gumpId = -1) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[7]); - w.Write((byte)0x24); // Packet ID - - w.Write(s); - w.Write(gumpId); - - ns.Send(w.RawSpan); - } - - public static void SendDisplayContainerHS(NetState ns, Serial s, short gumpId = -1) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0x24); // Packet ID - - w.Write(s); - w.Write(gumpId); - w.Write((short)0x7D); - - ns.Send(w.RawSpan); - } - - public static void SendContainerContentUpdate(NetState ns, Item item) - { - if (ns == null) - return; - - if (ns.ContainerGridLines) - SendContainerContentUpdateNew(ns, item); - else - SendContainerContentUpdateOld(ns, item); - } - - public static void SendContainerContentUpdateOld(NetState ns, Item item) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[20]); - w.Write((byte)0x25); // Packet ID - - Serial parentSerial; - - if (item.Parent is Item parentItem) - parentSerial = parentItem.Serial; - else - { - Console.WriteLine("Warning: ContainerContentUpdate on item with !(parent is Item)"); - parentSerial = Serial.Zero; - } - - w.Write(item.Serial); - w.Write((ushort)item.ItemID); - w.Position++; // w.Write((byte)0); // signed, itemID offset - w.Write((ushort)item.Amount); - w.Write((short)item.X); - w.Write((short)item.Y); - w.Write(parentSerial); - w.Write((ushort)(item.QuestItem ? Item.QuestItemHue : item.Hue)); - - ns.Send(w.RawSpan); - } - - public static void SendContainerContentUpdateNew(NetState ns, Item item) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[21]); - w.Write((byte)0x25); // Packet ID - - Serial parentSerial; - - if (item.Parent is Item parentItem) - parentSerial = parentItem.Serial; - else - { - Console.WriteLine("Warning: ContainerContentUpdate on item with !(parent is Item)"); - parentSerial = Serial.Zero; - } - - w.Write(item.Serial); - w.Write((ushort)item.ItemID); - w.Position++; // signed, itemID offset - w.Write((ushort)item.Amount); - w.Write((short)item.X); - w.Write((short)item.Y); - w.Position++; // Grid Location? - w.Write(parentSerial); - w.Write((ushort)(item.QuestItem ? Item.QuestItemHue : item.Hue)); - - ns.Send(w.RawSpan); - } - - public static void SendContainerContent(NetState ns, Mobile beholder, Item beheld) - { - if (ns == null) - return; - - if (ns.ContainerGridLines) - SendContainerContentNew(ns, beholder, beheld); - else - SendContainerContentOld(ns, beholder, beheld); - } - - public static void SendContainerContentOld(NetState ns, Mobile beholder, Item beheld) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[5 + beheld.Items.Count * 19]); - w.Write((byte)0x3C); // Packet ID - w.Position += 4; // Dynamic Length, Item Count - - List items = beheld.Items; - int count = items.Count; - - ushort written = 0; - - for (int i = 0; i < count; ++i) - { - Item child = items[i]; - - if (!child.Deleted && beholder.CanSee(child)) - { - Point3D loc = child.Location; - - w.Write(child.Serial); - w.Write((ushort)child.ItemID); - w.Position++; // signed, itemID offset - w.Write((ushort)child.Amount); - w.Write((short)loc.m_X); - w.Write((short)loc.m_Y); - w.Write(beheld.Serial); - w.Write((ushort)(child.QuestItem ? Item.QuestItemHue : child.Hue)); - - ++written; - } - } - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - w.Write(written); - - ns.Send(w.Span); - } - - public static void SendContainerContentNew(NetState ns, Mobile beholder, Item beheld) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[5 + beheld.Items.Count * 20]); - w.Write((byte)0x3C); // Packet ID - w.Position += 4; // Dynamic Length, Item Count - - List items = beheld.Items; - int count = items.Count; - - ushort written = 0; - - for (int i = 0; i < count; ++i) - { - Item child = items[i]; - - if (!child.Deleted && beholder.CanSee(child)) - { - Point3D loc = child.Location; - - w.Write(child.Serial); - w.Write((ushort)child.ItemID); - w.Position++; // signed, itemID offset - w.Write((ushort)child.Amount); - w.Write((short)loc.m_X); - w.Write((short)loc.m_Y); - w.Position++; // Grid Location? - w.Write(beheld.Serial); - w.Write((ushort)(child.QuestItem ? Item.QuestItemHue : child.Hue)); - - ++written; - } - } - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - w.Write(written); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Damage.cs b/Projects/Server/Network/Packets/Damage.cs deleted file mode 100644 index d7c734b8d..000000000 --- a/Projects/Server/Network/Packets/Damage.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Server.Buffers; - -namespace Server.Network -{ - public static partial class Packets - { - public static void SendDamage(NetState ns, Serial m, int amount) - { - if (ns == null) - return; - - if (ns.DamagePacket) - SendDamageNew(ns, m, amount); - else - SendDamageOld(ns, m, amount); - } - public static void SendDamageOld(NetState ns, Serial m, int amount) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[11]); - w.Write((byte)0xBF); // Extended Packet ID - w.Write((ushort)11); // Length - - w.Write((short)0x22); - w.Write((byte)1); - w.Write(m); - - if (amount > 255) - amount = 255; - else if (amount < 0) - amount = 0; - - w.Write((byte)amount); - - ns.Send(w.Span); - } - - public static void SendDamageNew(NetState ns, Serial m, int amount) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0xBF); // Extended Packet ID - w.Write((ushort)9); // Length - - w.Write(m); - - if (amount > 0xFFFF) - amount = 0xFFFF; - else if (amount < 0) - amount = 0; - - w.Write((ushort)amount); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Effects.cs b/Projects/Server/Network/Packets/Effects.cs deleted file mode 100644 index 0ca33ac71..000000000 --- a/Projects/Server/Network/Packets/Effects.cs +++ /dev/null @@ -1,283 +0,0 @@ -using Server.Buffers; - -namespace Server.Network -{ - public enum EffectType : byte - { - Moving, - Lightning, - FixedXYZ, - FixedFrom, - Screen - } - - public enum ScreenEffectType : short - { - FadeOut, - FadeIn, - LightFlash, - FadeInOut, - DarkFlash - } - - public static partial class Packets - { - private static readonly int ParticleEffectPacketLength = 49; - private static readonly int HuedEffectPacketLength = 36; - private static readonly int OldEffectPacketLength = 28; - - public static void SendParticalEffect(NetState ns, EffectType type, Serial from, Serial to, - int itemId, IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, - bool explode, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, Serial serial, - int layer, int unknown) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[ParticleEffectPacketLength]); - w.Write((byte)0xC7); // Packet ID - - w.Write((byte)type); - w.Write(from); - w.Write(to); - w.Write((short)itemId); - w.Write((short)fromPoint.X); - w.Write((short)fromPoint.Y); - w.Write((sbyte)fromPoint.Z); - w.Write((short)toPoint.X); - w.Write((short)toPoint.Y); - w.Write((sbyte)toPoint.Z); - w.Write((byte)speed); - w.Write((byte)duration); - w.Position += 2; - // w.Write((byte)0); - // w.Write((byte)0); - w.Write(fixedDirection); - w.Write(explode); - w.Write(hue); - w.Write(renderMode); - w.Write((short)effect); - w.Write((short)explodeEffect); - w.Write((short)explodeSound); - w.Write(serial); - w.Write((byte)layer); - w.Write((short)unknown); - - ns.Send(w.RawSpan); - } - - public static void SendHuedEffect(NetState ns, EffectType type, Serial from, Serial to, int itemId, - IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue, - int renderMode) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[HuedEffectPacketLength]); - w.Write((byte)0xC0); // Packet ID - - w.Write((byte)type); - w.Write(from); - w.Write(to); - w.Write((short)itemId); - w.Write((short)fromPoint.X); - w.Write((short)fromPoint.Y); - w.Write((sbyte)fromPoint.Z); - w.Write((short)toPoint.X); - w.Write((short)toPoint.Y); - w.Write((sbyte)toPoint.Z); - w.Write((byte)speed); - w.Write((byte)duration); - w.Position += 2; - // w.Write((byte)0); - // w.Write((byte)0); - w.Write(fixedDirection); - w.Write(explode); - w.Write(hue); - w.Write(renderMode); - - ns.Send(w.RawSpan); - } - - public static void SendScreenEffect(NetState ns, ScreenEffectType screen) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[HuedEffectPacketLength]); - w.Write((byte)0xC0); // Packet ID - - w.Write((byte)0x04); - w.Position += 8; - w.Write((short)screen); - - ns.Send(w.RawSpan); - } - - public static void SendScreenOldEffect(NetState ns, ScreenEffectType screen) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[OldEffectPacketLength]); - w.Write((byte)0x70); // Packet ID - - w.Write((byte)0x04); - w.Position += 8; - w.Write((short)screen); - - ns.Send(w.RawSpan); - } - - public static void SendBoltEffect(NetState ns, IEntity target) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[HuedEffectPacketLength]); - w.Write((byte)0xC0); // Packet ID - - w.Write((byte)0x01); - w.Write(target.Serial); - w.Position += 6; - w.Write((short)target.X); - w.Write((short)target.Y); - w.Write((sbyte)target.Z); - w.Write((short)target.X); - w.Write((short)target.Y); - w.Write((sbyte)target.Z); - - ns.Send(w.RawSpan); - } - - public static void SendOldBoltEffect(NetState ns, IEntity target) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[OldEffectPacketLength]); - w.Write((byte)0x70); // Packet ID - - w.Write((byte)0x01); - w.Write(target.Serial); - w.Position += 6; - w.Write((short)target.X); - w.Write((short)target.Y); - w.Write((sbyte)target.Z); - w.Write((short)target.X); - w.Write((short)target.Y); - w.Write((sbyte)target.Z); - - ns.Send(w.RawSpan); - } - - public static void SendEffect(NetState ns, EffectType type, Serial from, Serial to, int itemId, - IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[HuedEffectPacketLength]); - w.Write((byte)0xC0); // Packet ID - - w.Write((byte)type); - w.Write(from); - w.Write(to); - w.Write((short)itemId); - w.Write((short)fromPoint.X); - w.Write((short)fromPoint.Y); - w.Write((sbyte)fromPoint.Z); - w.Write((short)toPoint.X); - w.Write((short)toPoint.Y); - w.Write((sbyte)toPoint.Z); - w.Write((byte)speed); - w.Write((byte)duration); - w.Position += 2; - // w.Write((byte)0); - // w.Write((byte)0); - w.Write(fixedDirection); - w.Write(explode); - - ns.Send(w.RawSpan); - } - - public static void SendOldEffect(NetState ns, EffectType type, Serial from, Serial to, int itemId, - IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[OldEffectPacketLength]); - w.Write((byte)0x70); // Packet ID - - w.Write((byte)type); - w.Write(from); - w.Write(to); - w.Write((short)itemId); - w.Write((short)fromPoint.X); - w.Write((short)fromPoint.Y); - w.Write((sbyte)fromPoint.Z); - w.Write((short)toPoint.X); - w.Write((short)toPoint.Y); - w.Write((sbyte)toPoint.Z); - w.Write((byte)speed); - w.Write((byte)duration); - w.Position += 2; - // w.Write((byte)0); - // w.Write((byte)0); - w.Write(fixedDirection); - w.Write(explode); - - ns.Send(w.RawSpan); - } - - public static void SendLocationParticleEffect(NetState ns, IEntity e, int itemId, int speed, int duration, int hue, int renderMode, - int effect, int unknown) - { - SendParticalEffect(ns, EffectType.FixedXYZ, e.Serial, Serial.Zero, itemId, e.Location, e.Location, speed, duration, - true, false, hue, renderMode, effect, 1, 0, e.Serial, 255, unknown); - } - - public static void SendLocationHuedEffect(NetState ns, IPoint3D p, int itemId, int speed, int duration, int hue, int renderMode) - { - SendHuedEffect(ns, EffectType.FixedXYZ, Serial.Zero, Serial.Zero, itemId, p, p, speed, duration, true, false, - hue, renderMode); - } - - public static void SendMovingParticleEffect(NetState ns, IEntity from, IEntity to, int itemId, int speed, int duration, bool fixedDirection, - bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, EffectLayer layer, - int unknown) - { - SendParticalEffect(ns, EffectType.Moving, from.Serial, to.Serial, itemId, from.Location, to.Location, speed, - duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, Serial.Zero, - (int)layer, unknown); - } - - public static void SendMovingHuedEffect(NetState ns, IEntity from, IEntity to, int itemId, int speed, int duration, bool fixedDirection, - bool explodes, int hue, int renderMode) - { - SendHuedEffect(ns, EffectType.Moving, from.Serial, to.Serial, itemId, from.Location, - to.Location, speed, duration, fixedDirection, explodes, hue, renderMode); - } - - public static void SendMovingHuedEffect(NetState ns, IPoint3D from, IPoint3D to, int itemId, int speed, int duration, bool fixedDirection, - bool explodes, int hue, int renderMode) - { - SendHuedEffect(ns, EffectType.Moving, Serial.Zero, Serial.Zero, itemId, from, - to, speed, duration, fixedDirection, explodes, hue, renderMode); - } - - public static void SendTargetParticleEffect(NetState ns, IEntity e, int itemId, int speed, int duration, int hue, int renderMode, - int effect, int layer, int unknown) - { - SendParticalEffect(ns, EffectType.FixedFrom, e.Serial, Serial.Zero, itemId, e.Location, e.Location, - speed, duration, true, false, hue, renderMode, effect, 1, 0, e.Serial, layer, unknown); - } - - public static void SendTargetHuedEffect(NetState ns, IEntity e, int itemId, int speed, int duration, int hue, int renderMode) - { - SendHuedEffect(ns, EffectType.FixedFrom, e.Serial, Serial.Zero, itemId, e.Location, e.Location, speed, duration, - true, false, hue, renderMode); - } - } -} diff --git a/Projects/Server/Network/Packets/Gumps.cs b/Projects/Server/Network/Packets/Gumps.cs deleted file mode 100644 index 9591a5dfc..000000000 --- a/Projects/Server/Network/Packets/Gumps.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System.Buffers; -using System.Collections.Generic; -using Server.Buffers; -using Server.Gumps; - -namespace Server.Network -{ - public interface IGumpWriter - { - int TextEntries { get; set; } - int Switches { get; set; } - ArrayBufferWriter Layout { get; } - - int Intern(string value); - void WriteStrings(List strings); - void Flush(NetState ns); - } - - public static partial class Packets - { - public static void SendCloseGump(NetState ns, int typeId, int buttonId) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[13]); - w.Write((byte)0xBF); // Packet ID - w.Write((short)13); // Length - - w.Write((short)0x04); // Command - w.Write(typeId); - w.Write(buttonId); - - ns.Send(w.Span); - } - - public static void SendDisplayGump(NetState ns, Gump g, string layout, string[] text) - { - if (ns == null) - return; - - layout ??= ""; - - // Assume no longer than 128 characters per text element - SpanWriter w = new SpanWriter(stackalloc byte[20 + layout.Length + 1 + (258 * text?.Length ?? 0)]); - w.Write((byte)0xB0); // Packet ID - w.Position += 2; // Dynamic Length - - w.Write(g.Serial); - w.Write(g.TypeID); - w.Write(g.X); - w.Write(g.Y); - w.Write((ushort)(layout.Length + 1)); - w.WriteAsciiNull(layout); - - w.Write((ushort)(text?.Length ?? 0)); - - for (int i = 0; i < text?.Length; ++i) - { - string v = text[i] ?? ""; - - ushort length = (ushort)v.Length; - - w.Write(length); - w.WriteBigUni(v); - } - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - - public static void SendDisplaySignGump(NetState ns, Serial serial, int gumpId, string unknown, string caption) - { - if (ns == null) - return; - - int length = 14 + caption.Length + unknown.Length; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x8B); // Packet ID - w.Write((short)length); - - w.Write(serial); - w.Write((short)gumpId); - w.Write((short)unknown.Length); - w.WriteAsciiFixed(unknown, unknown.Length); - w.Write((short)(caption.Length + 1)); - w.WriteAsciiFixed(caption, caption.Length); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Items.cs b/Projects/Server/Network/Packets/Items.cs deleted file mode 100644 index ccc42e042..000000000 --- a/Projects/Server/Network/Packets/Items.cs +++ /dev/null @@ -1,330 +0,0 @@ -using Server.Buffers; -using Server.Items; - -namespace Server.Network -{ - public enum LRReason : byte - { - CannotLift, - OutOfRange, - OutOfSight, - TryToSteal, - AreHolding, - Unspecific - } - - public static partial class Packets - { - public static void SendWorldItem(NetState ns, Item item) - { - if (ns == null) - return; - - if (ns.HighSeas) - SendWorldItemHS(ns, item); - else if (ns.StygianAbyss) - SendWorldItemSA(ns, item); - else - SendWorldItemOld(ns, item); - } - - public static void SendWorldItemOld(NetState ns, Item item) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[20]); - w.Write((byte)0x1A); // Packet ID - w.Position += 2; // Dynamic Length - - uint serial = item.Serial.Value; - int itemId = item.ItemID & 0x3FFF; - int amount = item.Amount; - Point3D loc = item.Location; - int x = loc.m_X; - int y = loc.m_Y; - int hue = item.Hue; - int flags = item.GetPacketFlags(); - int direction = (int)item.Direction; - - if (amount != 0) - serial |= 0x80000000; - else - serial &= 0x7FFFFFFF; - - w.Write(serial); - - if (item is BaseMulti) - w.Write((short)(itemId | 0x4000)); - else - w.Write((short)itemId); - - if (amount != 0) - w.Write((short)amount); - - x &= 0x7FFF; - - if (direction != 0) x |= 0x8000; - - w.Write((short)x); - - y &= 0x3FFF; - - if (hue != 0) y |= 0x8000; - - if (flags != 0) y |= 0x4000; - - w.Write((short)y); - - if (direction != 0) - w.Write((byte)direction); - - w.Write((sbyte)loc.m_Z); - - if (hue != 0) - w.Write((ushort)hue); - - if (flags != 0) - w.Write((byte)flags); - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - - public static void SendWorldItemSA(NetState ns, Item item) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[24]); - w.Write((byte)0xF3); // Packet ID - - w.Write((short)0x01); - - int itemId = item.ItemID; - - if (item is BaseMulti) - { - w.Write((byte)0x02); - - w.Write(item.Serial); - - itemId &= 0x3FFF; - - w.Write((short)itemId); - - w.Position++; // w.Write((byte)0); - } - else - { - w.Position++; // w.Write((byte)0); - - w.Write(item.Serial); - - itemId &= 0x7FFF; - - w.Write((short)itemId); - - w.Write((byte)item.Direction); - } - - short amount = (short)item.Amount; - w.Write(amount); - w.Write(amount); - - Point3D loc = item.Location; - w.Write((short)(loc.m_X & 0x7FFF)); - w.Write((short)(loc.m_Y & 0x3FFF)); - w.Write((sbyte)loc.m_Z); - - w.Write((byte)item.Light); - w.Write((short)item.Hue); - w.Write((byte)item.GetPacketFlags()); - - ns.Send(w.Span); - } - - public static void SendWorldItemHS(NetState ns, Item item) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[26]); - w.Write((byte)0xF3); // Packet ID - - w.Write((short)0x01); - - int itemId = item.ItemID; - - if (item is BaseMulti) - { - w.Write((byte)0x02); - - w.Write(item.Serial); - - itemId &= 0x3FFF; - - w.Write((short)itemId); - - w.Position++; // w.Write((byte)0); - } - else - { - w.Position++; // w.Write((byte)0); - - w.Write(item.Serial); - - itemId &= 0x7FFF; - - w.Write((short)itemId); - - w.Write((byte)item.Direction); - } - - short amount = (short)item.Amount; - w.Write(amount); - w.Write(amount); - - Point3D loc = item.Location; - w.Write((short)(loc.m_X & 0x7FFF)); - w.Write((short)(loc.m_Y & 0x3FFF)); - w.Write((sbyte)loc.m_Z); - - w.Write((byte)item.Light); - w.Write((short)item.Hue); - w.Write((byte)item.GetPacketFlags()); - w.Position += 2; - - ns.Send(w.Span); - } - - public static void SendLiftRej(NetState ns, LRReason reason) - { - ns?.Send(stackalloc byte[] - { - 0x27, // Packet ID - (byte)reason - }); - } - - public static void SendSpellbookContent(NetState ns, Serial s, int count, int offset, ulong content) - { - if (ns == null) - return; - - if (ObjectPropertyList.Enabled && ns.NewSpellbook) - SendSpellbookContentNew(ns, s, count, offset, content); - else if (ns.ContainerGridLines) - SendSpellbookContent6017(ns, s, count, offset, content); - else - SendSpellbookContentOld(ns, s, count, offset, content); - } - - public static void SendSpellbookContentOld(NetState ns, Serial s, int count, int offset, ulong content) - { - if (ns == null) - return; - - int length = 5 + count * 19; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x3C); // Packet ID - w.Write((short)length); // Length - - // This should always be the same as written - w.Write((ushort)count); - - ulong mask = 1; - - for (int i = 0; i < 64; ++i, mask <<= 1) - if ((content & mask) != 0) - { - w.Write(0x7FFFFFFF - i); - w.Position += 3; - w.Write((ushort)(i + offset)); - w.Position += 4; - w.Write(s); - w.Position += 2; - } - - ns.Send(w.Span); - } - - public static void SendSpellbookContent6017(NetState ns, Serial s, int count, int offset, ulong content) - { - if (ns == null) - return; - - int length = 5 + count * 20; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x3C); // Packet ID - w.Write((short)length); // Length - - // This should always be the same as written - w.Write((ushort)count); - - ulong mask = 1; - - for (int i = 0; i < 64; ++i, mask <<= 1) - if ((content & mask) != 0) - { - w.Write(0x7FFFFFFF - i); - w.Position += 3; - w.Write((ushort)(i + offset)); - w.Position += 5; // Grid Location? - w.Write(s); - w.Position += 2; - } - - ns.Send(w.Span); - } - - public static void SendSpellbookContentNew(NetState ns, Serial s, int graphic, int offset, ulong content) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[23]); - w.Write((byte)0x3C); // Packet ID - w.Write((short)23); // Length - - - w.Write((short)0x1B); - w.Write((short)0x01); - - w.Write(s); - w.Write((short)graphic); - w.Write((short)offset); - - for (int i = 0; i < 8; ++i) - w.Write((byte)(content >> (i * 8))); - - ns.Send(w.Span); - } - - public static void SendDragEffect(NetState ns, IEntity src, IEntity trg, int itemID, int hue, int amount) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[26]); - w.Write((byte)0x23); // Packet ID - - w.Write((short)itemID); - w.Position++; // w.Write((byte)0); - w.Write((short)hue); - w.Write((short)amount); - w.Write(src.Serial); - w.Write((short)src.X); - w.Write((short)src.Y); - w.Write((sbyte)src.Z); - w.Write(trg.Serial); - w.Write((short)trg.X); - w.Write((short)trg.Y); - w.Write((sbyte)trg.Z); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Map.cs b/Projects/Server/Network/Packets/Map.cs deleted file mode 100644 index 336a859e6..000000000 --- a/Projects/Server/Network/Packets/Map.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Server.Buffers; - -namespace Server.Network -{ - public static partial class Packets - { - private static byte[] m_MapPatchesPacket; - - public static void SendMapPatches(NetState ns) - { - if (ns == null) - return; - - if (m_MapPatchesPacket == null) - { - SpanWriter w = new SpanWriter(m_MapPatchesPacket = new byte[57]); - w.Write((byte)0xBF); // Extended Packet ID - w.Write((ushort)57); // Dynamic Length - - w.Write((short)0x18); // Map Patches - w.Write(6); // Map count - - w.Write(Map.Felucca.Tiles.Patch.StaticBlocks); - w.Write(Map.Felucca.Tiles.Patch.LandBlocks); - - w.Write(Map.Trammel.Tiles.Patch.StaticBlocks); - w.Write(Map.Trammel.Tiles.Patch.LandBlocks); - - w.Write(Map.Ilshenar.Tiles.Patch.StaticBlocks); - w.Write(Map.Ilshenar.Tiles.Patch.LandBlocks); - - w.Write(Map.Malas.Tiles.Patch.StaticBlocks); - w.Write(Map.Malas.Tiles.Patch.LandBlocks); - - w.Write(Map.Tokuno.Tiles.Patch.StaticBlocks); - w.Write(Map.Tokuno.Tiles.Patch.LandBlocks); - - w.Write(Map.TerMur.Tiles.Patch.StaticBlocks); - w.Write(Map.TerMur.Tiles.Patch.LandBlocks); - } - - ns.Send(m_MapPatchesPacket); - } - - private static readonly byte[][][] _seasonChangePackets = { - new byte[2][], new byte[2][], new byte[2][], new byte[2][], new byte[2][] - }; - - public static void SendSeasonChange(NetState ns, byte season, byte playSound) - { - ns?.Send(_seasonChangePackets[season][playSound] ??= new byte[] - { - 0xBC, // Packet ID - season, - playSound - }); - } - - public static void SendMapChange(NetState ns, Map map) - { - ns?.Send(stackalloc byte[6] - { - 0xBF, // Extended Packet ID - 0x00, - 0x06, // Length - 0x00, - 0x08, // Command - (byte)(map?.MapID ?? 0) - }); - } - } -} diff --git a/Projects/Server/Network/Packets/Menus.cs b/Projects/Server/Network/Packets/Menus.cs deleted file mode 100644 index a17af9506..000000000 --- a/Projects/Server/Network/Packets/Menus.cs +++ /dev/null @@ -1,235 +0,0 @@ -using System; -using Server.Buffers; -using Server.ContextMenus; -using Server.Menus; - -namespace Server.Network -{ - [Flags] - public enum CMEFlags - { - None = 0x00, - Disabled = 0x01, - Arrow = 0x02, - Highlighted = 0x04, - Colored = 0x20 - } - - public static partial class Packets - { - public static void SendDisplayItemListMenu(NetState ns, ItemListMenu menu) - { - if (ns == null) - return; - - // 10 + 128 + (255 * (128 + 5)) - SpanWriter w = new SpanWriter(stackalloc byte[138 + menu.Entries.Length * 133]); - w.Write((byte)0x7C); // Packet ID - w.Position += 2; // Dynamic Length - - w.Write(menu.Serial); - w.Position += 2; // w.Write((short)0); - - string question = menu.Question; - - if (question == null) - w.Position++; // w.Write((byte)0); - else - { - int questionLength = question.Length; - w.Write((byte)questionLength); - w.WriteAsciiFixed(question, questionLength); - } - - ItemListEntry[] entries = menu.Entries; - - int entriesLength = (byte)entries.Length; - - w.Write((byte)entriesLength); - - for (int i = 0; i < entriesLength; ++i) - { - ItemListEntry e = entries[i]; - - w.Write((ushort)e.ItemID); - w.Write((short)e.Hue); - - string name = e.Name; - - if (name == null) - w.Position++; // w.Write((byte)0); - else - { - int nameLength = name.Length; - w.Write((byte)nameLength); - w.WriteAsciiFixed(name, nameLength); - } - } - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - - public static void SendDisplayQuestionMenu(NetState ns, QuestionMenu menu) - { - if (ns == null) - return; - - // 10 + 128 + (255 * (128 + 5)) - SpanWriter w = new SpanWriter(stackalloc byte[138 + menu.Answers.Length * 133]); - w.Write((byte)0x7C); // Packet ID - w.Position += 2; // Dynamic Length - - w.Write(menu.Serial); - w.Position += 2; // w.Write((short)0); - - string question = menu.Question; - - if (question == null) - w.Position++; // w.Write((byte)0); - else - { - int questionLength = question.Length; - w.Write((byte)questionLength); - w.WriteAsciiFixed(question, questionLength); - } - - string[] answers = menu.Answers; - - int answersLength = (byte)answers.Length; - - w.Write((byte)answersLength); - - for (int i = 0; i < answersLength; ++i) - { - w.Position += 4; // w.Write(0); - - string answer = answers[i]; - - if (answer == null) - w.Position++; // w.Write((byte)0); - else - { - int answerLength = answer.Length; - w.Write((byte)answerLength); - w.WriteAsciiFixed(answer, answerLength); - } - } - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - - public static void SendDisplayContextMenu(NetState ns, ContextMenu menu) - { - if (ns == null) - return; - - ContextMenuEntry[] entries = menu.Entries; - - int length = 12 + entries.Length * 8; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0xBF); // Packet ID - w.Write((short)length); // Length - - w.Write((short)0x14); // Command - w.Write((short)0x02); - - IEntity target = menu.Target as IEntity; - - w.Write(target?.Serial ?? Serial.MinusOne); - - w.Write((byte)entries.Length); - - Point3D p; - - if (target is Mobile) - p = target.Location; - else if (target is Item item) - p = item.GetWorldLocation(); - else - p = Point3D.Zero; - - for (int i = 0; i < entries.Length; ++i) - { - ContextMenuEntry e = entries[i]; - - w.Write(e.Number); - w.Write((short)i); - - int range = e.Range; - - if (range == -1) - range = 18; - - w.Write((short)(e.Flags | (e.Enabled && menu.From.InRange(p, range) ? CMEFlags.None : CMEFlags.Disabled))); - } - - ns.Send(w.Span); - } - - public static void SendDisplayContextMenuOld(NetState ns, ContextMenu menu) - { - if (ns == null) - return; - - ContextMenuEntry[] entries = menu.Entries; - - SpanWriter w = new SpanWriter(stackalloc byte[12 + entries.Length * 8]); - w.Write((byte)0xBF); // Packet ID - w.Position += 2; // Dynamic Length - - w.Write((short)0x14); // Command - w.Write((short)0x01); // Old! - - IEntity target = menu.Target as IEntity; - - w.Write(target?.Serial ?? Serial.MinusOne); - - w.Write((byte)entries.Length); - - Point3D p; - - if (target is Mobile) - p = target.Location; - else if (target is Item item) - p = item.GetWorldLocation(); - else - p = Point3D.Zero; - - for (int i = 0; i < entries.Length; ++i) - { - ContextMenuEntry e = entries[i]; - - w.Write((short)i); - w.Write((ushort)(e.Number - 3000000)); - - int range = e.Range; - - if (range == -1) - range = 18; - - CMEFlags flags = e.Flags | (e.Enabled && menu.From.InRange(p, range) ? CMEFlags.None : CMEFlags.Disabled); - - int color = e.Color & 0xFFFF; - - if (color != 0xFFFF) - flags |= CMEFlags.Colored; - - w.Write((short)flags); - - if ((flags & CMEFlags.Colored) != 0) - w.Write((short)color); - } - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Messages.cs b/Projects/Server/Network/Packets/Messages.cs deleted file mode 100644 index 5a4426f30..000000000 --- a/Projects/Server/Network/Packets/Messages.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Collections.Generic; -using Server.Buffers; - -namespace Server.Network -{ - [Flags] - public enum AffixType : byte - { - Append = 0x00, - Prepend = 0x01, - System = 0x02 - } - - public static partial class Packets - { - private static readonly Dictionary _messageLocalizedPackets = new Dictionary(); - - public static void SendMessageLocalized(NetState ns, int number) - { - if (ns == null) - return; - - if (_messageLocalizedPackets.TryGetValue(number, out byte[] packet)) - { - ns.Send(packet); - return; - } - - SpanWriter w = new SpanWriter(packet = new byte[50]); - w.Write((byte)0xC1); // Packet ID - w.Write((short)50); // Length - - w.Write(Serial.MinusOne); - w.Write((short)-1); - w.Position++; // w.Write((byte)MessageType.Regular); - w.Write((short)0x3B2); - w.Write((short)3); - w.Write(number); - w.WriteAsciiFixed("System", 30); - - _messageLocalizedPackets[number] = packet; - - ns.Send(packet); - } - - public static void SendMessageLocalized(NetState ns, Serial serial, int graphic, MessageType type, int hue, int font, int number, string name = "", - string args = "") - { - if (ns == null) - return; - - int length = 50 + args.Length * 2; - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0xC1); // Packet ID - w.Write((short)length); // Length - - if (hue == 0) hue = 0x3B2; - - w.Write(serial); - w.Write((short)graphic); - w.Write((byte)type); - w.Write((short)hue); - w.Write((short)font); - w.Write(number); - w.WriteAsciiFixed(name ?? "", 30); - w.WriteLittleUniNull(args); - - ns.Send(w.Span); - } - - public static void SendMessageLocalizedAffix(NetState ns, Serial serial, int graphic, MessageType type, int hue, int font, int number, - string name = "", AffixType affixType = AffixType.System, string affix = "", string args = "") - { - if (ns == null) - return; - - affix ??= ""; - args ??= ""; - - if (hue == 0) hue = 0x3B2; - - int length = 52 + affix.Length + args.Length * 2; - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0xCC); // Packet ID - w.Write((short)length); // Length - - w.Write(serial); - w.Write((short)graphic); - w.Write((byte)type); - w.Write((short)hue); - w.Write((short)font); - w.Write(number); - w.Write((byte)affixType); - w.WriteAsciiFixed(name ?? "", 30); - w.WriteAsciiNull(affix); - w.WriteBigUniNull(args); // Not little endian? Ugh - - ns.Send(w.Span); - } - - // TODO: Handle IEnumerable - public static void SendAsciiMessage(NetState ns, Serial serial, int graphic, MessageType type, int hue, int font, string name, string text) - { - if (ns == null) - return; - - text ??= ""; - - if (hue == 0) hue = 0x3B2; - - int length = 45 + text.Length; - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x1C); // Packet ID - w.Write((short)length); // Length - - w.Write(serial); - w.Write((short)graphic); - w.Write((byte)type); - w.Write((short)hue); - w.Write((short)font); - w.WriteAsciiFixed(name ?? "", 30); - w.WriteAsciiNull(text); - - ns.Send(w.Span); - } - - // TODO: Handle IEnumerable - public static void SendUnicodeMessage(NetState ns, Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name, - string text) - { - if (ns == null) - return; - - if (string.IsNullOrEmpty(lang)) lang = "ENU"; - name ??= ""; - text ??= ""; - if (hue == 0) hue = 0x3B2; - - int length = 50 + text.Length * 2; - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0xAE); // Packet ID - w.Write((short)length); // Length - - w.Write(serial); - w.Write((short)graphic); - w.Write((byte)type); - w.Write((short)hue); - w.Write((short)font); - w.WriteAsciiFixed(lang, 4); - w.WriteAsciiFixed(name, 30); - w.WriteBigUniNull(text); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Mobiles.cs b/Projects/Server/Network/Packets/Mobiles.cs deleted file mode 100644 index fd55b230b..000000000 --- a/Projects/Server/Network/Packets/Mobiles.cs +++ /dev/null @@ -1,959 +0,0 @@ -using System; -using System.Collections.Generic; -using Server.Buffers; -using Server.Items; - -namespace Server.Network -{ - public static partial class Packets - { - public static void SendDeathAnimation(NetState ns, Serial killed, Serial corpse) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[13]); - w.Write((byte)0xAF); // Packet ID - - w.Write(killed); - w.Write(corpse); - w.Position++; w.Write(0); - - ns.Send(w.Span); - } - - public static void SendStatLockInfo(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[12]); - w.Write((byte)0xBF); // Extended Packet ID - w.Write((short)12); // Length - - w.Write((short)0x19); // Subcommand - w.Write((byte)2); - w.Write(m.Serial); - w.Write((short)((int)m.StrLock << 4 | (int)m.DexLock << 2 | (int)m.IntLock)); - - ns.Send(w.Span); - } - - public static void SendBondStatus(NetState ns, Serial m, bool bonded) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[11]); - w.Write((byte)0xBF); // Extended Packet ID - w.Write((short)11); // Length - - w.Write((short)0x19); // Command - w.Position++; // w.Write((byte)0); // Subcommand - w.Write(m); - w.Write(bonded); - - ns.Send(w.Span); - } - - public static void SendPersonalLightLevel(NetState ns, Serial m, sbyte level) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[6]); - w.Write((byte)0x4E); // Packet ID - - w.Write(m); - w.Write(level); - - ns.Send(w.Span); - } - - public static void SendPersonalLightLevelZero(NetState ns, Serial m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[6]); - w.Write((byte)0x4E); // Packet ID - - w.Write(m); - w.Position++; // level 0 - - ns.Send(w.Span); - } - - public static void SendEquipUpdate(NetState ns, Item item) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[15]); - w.Write((byte)0x2E); // Packet ID - - Serial parentSerial = Serial.Zero; - int hue = item.Hue; - - if (item.Parent is Mobile parent) - { - parentSerial = parent.Serial; - if (parent.SolidHueOverride >= 0) - hue = parent.SolidHueOverride; - } - else - Console.WriteLine("Warning: EquipUpdate on item with an invalid parent"); - - w.Write(item.Serial); - w.Write((short)item.ItemID); - w.Write((short)item.Layer); - w.Write(parentSerial); - w.Write((short)hue); - - ns.Send(w.Span); - } - - public static void SendSwing(NetState ns, Serial attacker, Serial defender) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[10]); - w.Write((byte)0x2F); // Packet ID - - w.Position++; // ? - w.Write(attacker); - w.Write(defender); - - ns.Send(w.Span); - } - - public static void SendMobileMoving(NetState ns, Mobile m, int noto) - { - if (ns == null) - return; - - if (ns.StygianAbyss) - SendMobileMovingNew(ns, m, noto); - else - SendMobileMovingOld(ns, m, noto); - } - - public static void SendMobileMovingNew(NetState ns, Mobile m, int noto) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[17]); - w.Write((byte)0x77); // Packet ID - - Point3D loc = m.Location; - - w.Write(m.Serial); - w.Write((short)m.Body); - w.Write((short)loc.m_X); - w.Write((short)loc.m_Y); - w.Write((sbyte)loc.m_Z); - w.Write((byte)m.Direction); - w.Write((short)(m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.Hue)); - w.Write((byte)m.GetPacketFlags()); - w.Write((byte)noto); - - ns.Send(w.Span); - } - - public static void SendMobileMovingOld(NetState ns, Mobile m, int noto) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[17]); - w.Write((byte)0x77); // Packet ID - - Point3D loc = m.Location; - - w.Write(m.Serial); - w.Write((short)m.Body); - w.Write((short)loc.m_X); - w.Write((short)loc.m_Y); - w.Write((sbyte)loc.m_Z); - w.Write((byte)m.Direction); - w.Write((short)(m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.Hue)); - w.Write((byte)m.GetOldPacketFlags()); - w.Write((byte)noto); - - ns.Send(w.Span); - } - - public static void SendDisplayPaperdoll(NetState ns, Mobile m, string text, bool canLift) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[66]); - w.Write((byte)0x88); // Packet ID - - byte flags = 0x00; - - if (m.Warmode) - flags |= 0x01; - - if (canLift) - flags |= 0x02; - - w.Write(m.Serial); - w.WriteAsciiFixed(text, 60); - w.Write(flags); - - ns.Send(w.Span); - } - - public static void SendMobileName(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[37]); - w.Write((byte)0x98); // Packet ID - w.Write((ushort)37); // Dynamic Length - - w.Write(m.Serial); - w.WriteAsciiFixed(m.Name ?? "", 30); - - ns.Send(w.Span); - } - - public static void SendMobileAnimation(NetState ns, Mobile m, int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[14]); - w.Write((byte)0x6E); // Packet ID - - w.Write(m.Serial); - w.Write((short)action); - w.Write((short)frameCount); - w.Write((short)repeatCount); - w.Write(!forward); // protocol has really "reverse" but I find this more intuitive - w.Write(repeat); - w.Write((byte)delay); - - ns.Send(w.Span); - } - - public static void SendNewMobileAnimation(NetState ns, Mobile m, int action, int frameCount, int delay) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[10]); - w.Write((byte)0xE2); // Packet ID - - w.Write(m.Serial); - w.Write((short)action); - w.Write((short)frameCount); - w.Write((byte)delay); - - ns.Send(w.Span); - } - - public static void SendMobileStatusCompact(NetState ns, Mobile m, bool canBeRenamed = false) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[43]); - w.Write((byte)0x11); // Packet ID - w.Write((ushort)43); // Length - - w.Write(m.Serial); - w.WriteAsciiFixed(m.Name ?? "", 30); - - AttributeNormalizer.WriteReverse(w, m.Hits, m.HitsMax); - - w.Write(canBeRenamed); - - w.Position++; // type - - ns.Send(w.Span); - } - - public static void SendMobileStatusExtended(NetState to, Mobile m) - { - SendMobileStatusExtended(to, m, m.NetState); - } - - public static void SendMobileStatusExtended(NetState to, Mobile m, NetState ns) - { - if (to == null) - return; - - byte type; - short length; - - if (Core.HS && ns?.ExtendedStatus == true) - { - type = 6; - length = 121; - } - else if (Core.ML && ns?.SupportsExpansion(Expansion.ML) == true) - { - type = 5; - length = 91; - } - else if (Core.AOS) - { - type = 4; - length = 88; - } - else - { - type = 3; - length = 70; - } - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x11); // Packet ID - w.Write(length); // Length - - w.Write(m.Serial); - w.WriteAsciiFixed(m.Name ?? "", 30); - - w.Write((short)m.Hits); - w.Write((short)m.HitsMax); - - w.Write(m.CanBeRenamedBy(m)); - - w.Write(type); - - w.Write(m.Female); - - w.Write((short)m.Str); - w.Write((short)m.Dex); - w.Write((short)m.Int); - - w.Write((short)m.Stam); - w.Write((short)m.StamMax); - - w.Write((short)m.Mana); - w.Write((short)m.ManaMax); - - w.Write(m.TotalGold); - w.Write((short)(Core.AOS ? m.PhysicalResistance : (int)(m.ArmorRating + 0.5))); - w.Write((short)(Mobile.BodyWeight + m.TotalWeight)); - - if (type >= 5) - { - w.Write((short)m.MaxWeight); - w.Write((byte)(m.Race.RaceID + 1)); // Would be 0x00 if it's a non-ML enabled account but... - } - - w.Write((short)m.StatCap); - - w.Write((byte)m.Followers); - w.Write((byte)m.FollowersMax); - - if (type >= 4) - { - w.Write((short)m.FireResistance); // Fire - w.Write((short)m.ColdResistance); // Cold - w.Write((short)m.PoisonResistance); // Poison - w.Write((short)m.EnergyResistance); // Energy - w.Write((short)m.Luck); // Luck - - IWeapon weapon = m.Weapon; - - if (weapon != null) - { - weapon.GetStatusDamage(m, out int min, out int max); - w.Write((short)min); // Damage min - w.Write((short)max); // Damage max - } - else - w.Position += 4; // Damage min, Damage max - - w.Write(m.TithingPoints); - } - - if (type >= 6) - for (int i = 0; i < 15; ++i) - w.Write((short)m.GetAOSStatus(i)); - - to.Send(w.Span); - } - - public static void SendMobileStatus(NetState to, Mobile beholder, Mobile beheld) - { - SendMobileStatus(to, beholder, beheld, beheld.NetState); - } - - public static void SendMobileStatus(NetState to, Mobile beholder, Mobile beheld, NetState ns) - { - if (to == null) - return; - - int type; - short length; - - if (beholder != beheld) - { - type = 0; - length = 43; - } - else if (Core.HS && ns?.ExtendedStatus == true) - { - type = 6; - length = 121; - } - else if (Core.ML && ns?.SupportsExpansion(Expansion.ML) == true) - { - type = 5; - length = 91; - } - else if (Core.AOS) - { - type = 4; - length = 88; - } - else - { - type = 3; - length = 70; - } - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x11); // Packet ID - w.Write((ushort)length); // Length - - w.Write(beheld.Serial); - - w.WriteAsciiFixed(beheld.Name ?? "", 30); - - if (beholder == beheld) - { - w.Write((short)beheld.Hits); - w.Write((short)beheld.HitsMax); - } - else - AttributeNormalizer.WriteReverse(w, beheld.Hits, beheld.HitsMax); - - w.Write(beheld.CanBeRenamedBy(beholder)); - - w.Write((byte)type); - - if (type <= 0) - return; - - w.Write(beheld.Female); - - w.Write((short)beheld.Str); - w.Write((short)beheld.Dex); - w.Write((short)beheld.Int); - - w.Write((short)beheld.Stam); - w.Write((short)beheld.StamMax); - - w.Write((short)beheld.Mana); - w.Write((short)beheld.ManaMax); - - w.Write(beheld.TotalGold); - w.Write((short)(Core.AOS ? beheld.PhysicalResistance : (int)(beheld.ArmorRating + 0.5))); - w.Write((short)(Mobile.BodyWeight + beheld.TotalWeight)); - - if (type >= 5) - { - w.Write((short)beheld.MaxWeight); - w.Write((byte)(beheld.Race.RaceID + 1)); // Would be 0x00 if it's a non-ML enabled account but... - } - - w.Write((short)beheld.StatCap); - - w.Write((byte)beheld.Followers); - w.Write((byte)beheld.FollowersMax); - - if (type >= 4) - { - w.Write((short)beheld.FireResistance); // Fire - w.Write((short)beheld.ColdResistance); // Cold - w.Write((short)beheld.PoisonResistance); // Poison - w.Write((short)beheld.EnergyResistance); // Energy - w.Write((short)beheld.Luck); // Luck - - IWeapon weapon = beheld.Weapon; - - if (weapon != null) - { - weapon.GetStatusDamage(beheld, out int min, out int max); - w.Write((short)min); // Damage min - w.Write((short)max); // Damage max - } - else - w.Position += 2; // Damage min, Damage max - - w.Write(beheld.TithingPoints); - } - - if (type >= 6) - for (int i = 0; i < 15; ++i) - w.Write((short)beheld.GetAOSStatus(i)); - - to.Send(w.Span); - } - - public static void SendHealthbarPoison(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[12]); - w.Write((byte)0x17); // Packet ID - w.Write((ushort)12); // Length - - w.Write(m.Serial); - w.Write((short)1); - w.Write((short)1); - - Poison p = m.Poison; - - if (p != null) - w.Write((byte)(p.Level + 1)); - else - w.Position++; - - ns.Send(w.Span); - } - - public static void SendHealthbarYellow(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[12]); - w.Write((byte)0x17); // Packet ID - w.Write((ushort)12); // Length - - w.Write(m.Serial); - w.Write((short)1); - w.Write((short)2); - - w.Write(m.Blessed || m.YellowHealthbar); - - ns.Send(w.Span); - } - - public static void SendMobileUpdate(NetState ns, Mobile m) - { - if (ns == null) - return; - - if (ns.StygianAbyss) - SendMobileUpdateSA(ns, m); - else - SendMobileUpdateOld(ns, m); - } - - public static void SendMobileUpdateSA(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[19]); - w.Write((byte)0x20); // Packet ID - - int hue = m.Hue; - - if (m.SolidHueOverride >= 0) - hue = m.SolidHueOverride; - - w.Write(m.Serial); - w.Write((short)m.Body); - w.Position++; // w.Write((byte)0); - w.Write((short)hue); - w.Write((byte)m.GetPacketFlags()); - w.Write((short)m.X); - w.Write((short)m.Y); - w.Position += 2; // w.Write((short)0); - w.Write((byte)m.Direction); - w.Write((sbyte)m.Z); - - ns.Send(w.Span); - } - - public static void SendMobileUpdateOld(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[19]); - w.Write((byte)0x20); // Packet ID - - int hue = m.Hue; - - if (m.SolidHueOverride >= 0) - hue = m.SolidHueOverride; - - w.Write(m.Serial); - w.Write((short)m.Body); - w.Position++; // w.Write((byte)0); - w.Write((short)hue); - w.Write((byte)m.GetOldPacketFlags()); - w.Write((short)m.X); - w.Write((short)m.Y); - w.Position += 2; // w.Write((short)0); - w.Write((byte)m.Direction); - w.Write((sbyte)m.Z); - - ns.Send(w.Span); - } - - public static void SendMobileIncoming(NetState ns, Mobile beholder, Mobile beheld) - { - if (ns == null) - return; - - if (ns.NewMobileIncoming) - SendMobileIncomingNew(ns, beholder, beheld); - else if (ns.StygianAbyss) - SendMobileIncomingSA(ns, beholder, beheld); - else - SendMobileIncomingOld(ns, beholder, beheld); - } - - public static void SendMobileIncomingNew(NetState ns, Mobile beholder, Mobile beheld) - { - if (ns == null) - return; - - Span dupedLayers = stackalloc bool[256]; - - List eq = beheld.Items; - int count = eq.Count; - - if (beheld.HairItemID > 0) - count++; - if (beheld.FacialHairItemID > 0) - count++; - - SpanWriter w = new SpanWriter(stackalloc byte[23 + count * 9]); - w.Write((byte)0x78); // Packet ID - w.Position += 2; // Dynamic Length - - int hue = beheld.Hue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - w.Write(beheld.Serial); - w.Write((short)beheld.Body); - w.Write((short)beheld.X); - w.Write((short)beheld.Y); - w.Write((sbyte)beheld.Z); - w.Write((byte)beheld.Direction); - w.Write((short)hue); - w.Write((byte)beheld.GetPacketFlags()); - w.Write(Notoriety.Compute(beholder, beheld)); - - for (int i = 0; i < eq.Count; ++i) - { - Item item = eq[i]; - - byte layer = (byte)item.Layer; - - if (!item.Deleted && beholder.CanSee(item) && !dupedLayers[layer]) - { - dupedLayers[layer] = true; - - hue = item.Hue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - w.Write(item.Serial); - w.Write((ushort)(item.ItemID & 0xFFFF)); - w.Write(layer); - w.Write((short)hue); - } - } - - if (beheld.HairItemID > 0 && !dupedLayers[(int)Layer.Hair]) - { - hue = beheld.HairHue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - w.Write(HairInfo.FakeSerial(beheld.Serial)); - w.Write((ushort)(beheld.HairItemID & 0xFFFF)); - w.Write((byte)Layer.Hair); - w.Write((short)hue); - } - - if (beheld.FacialHairItemID > 0 && !dupedLayers[(int)Layer.FacialHair]) - { - hue = beheld.FacialHairHue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - w.Write(FacialHairInfo.FakeSerial(beheld.Serial)); - w.Write((ushort)(beheld.FacialHairItemID & 0xFFFF)); - w.Write((byte)Layer.FacialHair); - w.Write((short)hue); - } - - w.Position += 4; // w.Write(0) - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - - public static void SendMobileIncomingSA(NetState ns, Mobile beholder, Mobile beheld) - { - if (ns == null) - return; - - Span dupedLayers = stackalloc bool[256]; - - List eq = beheld.Items; - int count = eq.Count; - - if (beheld.HairItemID > 0) - count++; - if (beheld.FacialHairItemID > 0) - count++; - - SpanWriter w = new SpanWriter(stackalloc byte[23 + count * 9]); - w.Write((byte)0x78); // Packet ID - w.Position += 2; // Dynamic Length - - int hue = beheld.Hue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - w.Write(beheld.Serial); - w.Write((short)beheld.Body); - w.Write((short)beheld.X); - w.Write((short)beheld.Y); - w.Write((sbyte)beheld.Z); - w.Write((byte)beheld.Direction); - w.Write((short)hue); - w.Write((byte)beheld.GetPacketFlags()); - w.Write(Notoriety.Compute(beholder, beheld)); - - for (int i = 0; i < eq.Count; ++i) - { - Item item = eq[i]; - - byte layer = (byte)item.Layer; - - if (!item.Deleted && beholder.CanSee(item) && !dupedLayers[layer]) - { - dupedLayers[layer] = true; - - hue = item.Hue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - int itemId = item.ItemID & 0x7FFF; - bool writeHue = hue != 0; - - if (writeHue) - itemId |= 0x8000; - - w.Write(item.Serial); - w.Write((ushort)itemId); - w.Write(layer); - - if (writeHue) - w.Write((short)hue); - } - } - - if (beheld.HairItemID > 0 && !dupedLayers[(int)Layer.Hair]) - { - hue = beheld.HairHue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - int itemId = beheld.HairItemID & 0x7FFF; - - bool writeHue = hue != 0; - - if (writeHue) - itemId |= 0x8000; - - w.Write(HairInfo.FakeSerial(beheld.Serial)); - w.Write((ushort)itemId); - w.Write((byte)Layer.Hair); - - if (writeHue) - w.Write((short)hue); - } - - if (beheld.FacialHairItemID > 0 && !dupedLayers[(int)Layer.FacialHair]) - { - hue = beheld.FacialHairHue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - int itemId = beheld.FacialHairItemID & 0x7FFF; - - bool writeHue = hue != 0; - - if (writeHue) - itemId |= 0x8000; - - w.Write(FacialHairInfo.FakeSerial(beheld.Serial)); - w.Write((ushort)itemId); - w.Write((byte)Layer.FacialHair); - - if (writeHue) - w.Write((short)hue); - } - - w.Position += 4; // w.Write(0) - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - - public static void SendMobileIncomingOld(NetState ns, Mobile beholder, Mobile beheld) - { - if (ns == null) - return; - - Span dupedLayers = stackalloc bool[256]; - - List eq = beheld.Items; - int count = eq.Count; - - if (beheld.HairItemID > 0) - count++; - if (beheld.FacialHairItemID > 0) - count++; - - SpanWriter w = new SpanWriter(stackalloc byte[23 + count * 9]); - w.Write((byte)0x78); // Packet ID - w.Position += 2; // Dynamic Length - - int hue = beheld.Hue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - w.Write(beheld.Serial); - w.Write((short)beheld.Body); - w.Write((short)beheld.X); - w.Write((short)beheld.Y); - w.Write((sbyte)beheld.Z); - w.Write((byte)beheld.Direction); - w.Write((short)hue); - w.Write((byte)beheld.GetOldPacketFlags()); - w.Write(Notoriety.Compute(beholder, beheld)); - - for (int i = 0; i < eq.Count; ++i) - { - Item item = eq[i]; - - byte layer = (byte)item.Layer; - - if (!item.Deleted && beholder.CanSee(item) && !dupedLayers[layer]) - { - dupedLayers[layer] = true; - - hue = item.Hue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - int itemId = item.ItemID & 0x7FFF; - bool writeHue = hue != 0; - - if (writeHue) - itemId |= 0x8000; - - w.Write(item.Serial); - w.Write((ushort)itemId); - w.Write(layer); - - if (writeHue) - w.Write((short)hue); - } - } - - if (beheld.HairItemID > 0 && !dupedLayers[(int)Layer.Hair]) - { - hue = beheld.HairHue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - int itemId = beheld.HairItemID & 0x7FFF; - - bool writeHue = hue != 0; - - if (writeHue) - itemId |= 0x8000; - - w.Write(HairInfo.FakeSerial(beheld.Serial)); - w.Write((ushort)itemId); - w.Write((byte)Layer.Hair); - - if (writeHue) - w.Write((short)hue); - } - - if (beheld.FacialHairItemID > 0 && !dupedLayers[(int)Layer.FacialHair]) - { - hue = beheld.FacialHairHue; - - if (beheld.SolidHueOverride >= 0) - hue = beheld.SolidHueOverride; - - int itemId = beheld.FacialHairItemID & 0x7FFF; - - bool writeHue = hue != 0; - - if (writeHue) - itemId |= 0x8000; - - w.Write(FacialHairInfo.FakeSerial(beheld.Serial)); - w.Write((ushort)itemId); - w.Write((byte)Layer.FacialHair); - - if (writeHue) - w.Write((short)hue); - } - - w.Position += 4; // w.Write(0) - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - - ns.Send(w.Span); - } - - public static void SendFollowMessage(NetState ns, Serial s1, Serial s2) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0x15); // Packet ID - - w.Write(s1); - w.Write(s2); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Player.cs b/Projects/Server/Network/Packets/Player.cs deleted file mode 100644 index 0346d6626..000000000 --- a/Projects/Server/Network/Packets/Player.cs +++ /dev/null @@ -1,550 +0,0 @@ -using System; -using Server.Buffers; - -namespace Server.Network -{ - public static partial class Packets - { - public static void SendObjectHelpResponse(NetState ns, Serial e, string text) - { - if (ns == null) - return; - - text ??= ""; - - int length = 9 + text.Length * 2; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte) 0xB7); // Extended Packet ID - w.Write((ushort) length); // Length - - w.Write(e); - w.WriteBigUniNull(text); - - ns.Send(w.Span); - } - - public static void SendChangeUpdateRange(NetState ns, byte range = 18) - { - ns?.Send(stackalloc byte[] - { - 0xC8, // Packet ID - range - }); - } - - public static void SendChangeCombatant(NetState ns, Serial combatant) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[5]); - w.Write((byte)0xAA); // Packet ID - - w.Write(combatant); - - ns.Send(w.Span); - } - - public static void SendDisplayHuePicker(NetState ns, Serial s, int itemId) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0x95); // Packet ID - - w.Write(s); - w.Position += 2; // w.Write((short)0); - w.Write((short)itemId); - - ns.Send(w.Span); - } - - public static void SendUnicodePrompt(NetState ns, Serial message) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[21]); - w.Write((byte)0xC2); // Packet ID - w.Write((short)21); // Length - - w.Write(message); // Should be Player serial? - w.Write(message); - w.Position += 10; - - ns.Send(w.Span); - } - - public static void SendDeathStatus_Dead(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0x2C, // Packet ID - 0x00 - }); - } - - public static void SendDeathStatus_Alive(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0x2C, // Packet ID - 0x02 // Why not 1? - }); - } - - private static readonly byte[][] _speedControlPackets = new byte[3][]; - - public static void SendSpeedControlDisabled(NetState ns) - { - ns?.Send(_speedControlPackets[0] ??= new byte[] - { - 0xBF, // Extended Packet ID - 0x00, - 0x06, // Length - 0x26, - 0x00 // Disabled - }); - } - - public static void SendSpeedControlMount(NetState ns) - { - ns?.Send(_speedControlPackets[1] ??= new byte[] - { - 0xBF, // Extended Packet ID - 0x00, - 0x06, // Length - 0x26, - 0x01 // Mount - }); - } - - public static void SendSpeedControlWalk(NetState ns) - { - ns?.Send(_speedControlPackets[2] ??= new byte[] - { - 0xBF, // Extended Packet ID - 0x00, - 0x06, // Length - 0x26, - 0x02 // Walk - }); - } - - public static void SendToggleSpecialAbility(NetState ns, short ability, bool active) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[8]); - w.Write((byte)0xBF); // Packet ID - w.Write((short)8); // Length - - w.Write((short)0x25); // Command - w.Write(ability); - w.Write(active); - - ns.Send(w.Span); - } - - public static void SendGlobalLightLevel(NetState ns, sbyte level) - { - ns?.Send(stackalloc byte[] - { - 0x4F, // Packet ID - (byte)level - }); - } - - public static void SendLogoutAck(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0xD1, // Packet ID - 0x01 - }); - } - - public static void SendWeather(NetState ns, byte type, byte density, sbyte temperature) - { - ns?.Send(stackalloc byte[] - { - 0x65, // Packet ID - type, - density, - (byte)temperature - }); - } - - public static void SendPlayerMove(NetState ns, Direction d) - { - ns?.Send(stackalloc byte[] - { - 0x97, // Packet ID - (byte)d - }); - } - - public static void SendClientVersionReq(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0xBD, // Packet ID - 0x00, - 0x03 - }); - } - - public static void SendSetWarMode(NetState ns, bool warmode) - { - if (warmode) - SendInWarMode(ns); - else - SendInPeaceMode(ns); - } - - public static void SendInWarMode(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0x72, // Packet ID - 0x01, // War mode - 0x00, - 0x32, // ? - 0x00 - }); - } - - public static void SendInPeaceMode(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0x72, // Packet ID - 0x00, // Peace mode - 0x00, - 0x32, // ? - 0x00 - }); - } - - public static void SendRemoveEntity(NetState ns, Serial entity) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[5]); - w.Write((byte)0x1D); // Packet ID - - w.Write(entity); - - ns.Send(w.Span); - } - - public static void SendServerChange(NetState ns, Mobile m, Map map) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[16]); - w.Write((byte)0x76); // Packet ID - - w.Write((short)m.X); - w.Write((short)m.Y); - w.Write((short)m.Z); - w.Position += 5; - w.Write((short)map.Width); - w.Write((short)map.Height); - - ns.Send(w.Span); - } - - public static void SendSkillsUpdate(NetState ns, Skills skills) - { - if (ns == null) - return; - - int length = 6 + skills.Length * 9; - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x3A); // Packet ID - w.Write((short)length); // Length - - w.Write((byte)0x02); // type: absolute, capped - - for (int i = 0; i < skills.Length; ++i) - { - Skill s = skills[i]; - - double v = s.NonRacialValue; - int uv = (int)(v * 10); - - if (uv < 0) - uv = 0; - else if (uv >= 0x10000) - uv = 0xFFFF; - - w.Write((ushort)(s.Info.SkillID + 1)); - w.Write((ushort)uv); - w.Write((ushort)s.BaseFixedPoint); - w.Write((byte)s.Lock); - w.Write((ushort)s.CapFixedPoint); - } - - w.Position += 2; - - ns.Send(w.Span); - } - - public static void SendSkillChange(NetState ns, Skill skill) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[13]); - w.Write((byte)0x3A); // Packet ID - w.Write((short)13); // Length - - - double v = skill.NonRacialValue; - int uv = (int)(v * 10); - - if (uv < 0) - uv = 0; - else if (uv >= 0x10000) - uv = 0xFFFF; - - w.Write((byte)0xDF); // type: delta, capped - w.Write((ushort)skill.Info.SkillID); - w.Write((ushort)uv); - w.Write((ushort)skill.BaseFixedPoint); - w.Write((byte)skill.Lock); - w.Write((ushort)skill.CapFixedPoint); - - ns.Send(w.Span); - } - - public static void SendLaunchBrowser(NetState ns, string url) - { - if (ns == null) - return; - - url ??= ""; - - int length = 4 + url.Length; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0xA5); // Packet ID - w.Write((short)length); // Length - - w.WriteAsciiNull(url); - - ns.Send(w.Span); - } - - // TODO: Optimize for IEnumerable - public static void SendPlaySound(NetState ns, int soundId, IPoint3D target) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[12]); - w.Write((byte)0x54); // Packet ID - - w.Write((byte)1); // flags - w.Write((short)soundId); - w.Position += 2; // volume? - w.Write((short)target.X); - w.Write((short)target.Y); - w.Write((short)target.Z); - - ns.Send(w.Span); - } - - public static void SendPlayRepeatingSound(NetState ns, int soundId, IPoint3D target) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[12]); - w.Write((byte)0x54); // Packet ID - - w.Position++; // flags - w.Write((short)soundId); - w.Position += 2; // volume? - w.Write((short)target.X); - w.Write((short)target.Y); - w.Write((short)target.Z); - - ns.Send(w.Span); - } - - public static void SendPlayMusic(NetState ns, MusicName music) - { - ushort value = (ushort)music; - ns?.Send(stackalloc byte[] - { - 0x6D, // Packet ID - (byte)(value >> 8), - (byte)(value & 0xFF) - }); - } - - public static void SendStopMusic(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0x6D, // Packet ID - 0x1F, - 0xFF - }); - } - - public static void SendScrollMessage(NetState ns, int type, int tip, string text) - { - if (ns == null) - return; - - text ??= ""; - - int length = 10 + text.Length; - - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0xA6); // Packet ID - w.Write((short)length); // Length - - w.Write((byte)type); - w.Write(tip); - w.Write((ushort)text.Length); - w.WriteAsciiFixed(text, text.Length); - - ns.Send(w.Span); - } - - public static void SendCurrentTime(NetState ns) - { - if (ns == null) - return; - - // TODO: Don't call UtcNow so readily. - DateTime now = DateTime.UtcNow; - - ns.Send(stackalloc byte[] - { - 0x5B, // Packet ID - (byte)now.Hour, - (byte)now.Minute, - (byte)now.Second - }); - } - - public static void SendPathfindMessage(NetState ns, IPoint3D p) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[7]); - w.Write((byte)0x38); // Packet ID - - w.Write((short)p.X); - w.Write((short)p.Y); - w.Write((short)p.Z); - - ns.Send(w.Span); - } - - public static void SendPingAck(NetState ns, byte ping) - { - ns?.Send(stackalloc byte[2] - { - 0x73, // Packet ID - ping - }); - } - - public static void SendMovementRej(NetState ns, int seq, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[8]); - w.Write((byte)0x21); // Packet ID - - w.Write((byte)seq); - w.Write((short)m.X); - w.Write((short)m.Y); - w.Write((byte)m.Direction); - w.Write((sbyte)m.Z); - - ns.Send(w.Span); - } - - public static void SendMovementAck(NetState ns, Mobile m) - { - if (ns == null) - return; - - SendMovementAck(ns, ns.Sequence, Notoriety.Compute(m, m)); - } - - public static void SendMovementAck(NetState ns, byte seq, byte noto) - { - ns?.Send(stackalloc byte[3] - { - 0x22, - seq, - noto - }); - } - - public static void SendLoginConfirm(NetState ns, Mobile m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[37]); - w.Write((byte)0x1B); // Packet ID - - w.Write(m.Serial); - w.Position++; - w.Write((short)m.Body); - w.Write((short)m.X); - w.Write((short)m.Y); - w.Write((short)m.Z); - w.Write((byte)m.Direction); - w.Position++; - w.Write(-1); - - Map map = m.Map; - - if (map == null || map == Map.Internal) - map = m.LogoutMap; - - w.Position += 4; - w.Write((short)(map?.Width ?? 6144)); - w.Write((short)(map?.Height ?? 4096)); - w.Position += 9; - - ns.Send(w.Span); - } - - public static void SendLoginComplete(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0x55 // Packet ID - }); - } - - public static void SendClearWeaponAbility(NetState ns) - { - ns?.Send(stackalloc byte[] - { - 0xBF, // Extended Packet ID - 0x00, - 0x05, // Length - 0x21, // Command - 0x00 - }); - } - } -} diff --git a/Projects/Server/Network/Packets/Profile.cs b/Projects/Server/Network/Packets/Profile.cs deleted file mode 100644 index 5a0106623..000000000 --- a/Projects/Server/Network/Packets/Profile.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Server.Buffers; - -namespace Server.Network -{ - public static partial class Packets - { - public static void SendDisplayProfile(NetState ns, Serial m, string header, string body, string footer) - { - if (ns == null) - return; - - header ??= ""; - body ??= ""; - footer ??= ""; - - int length = 12 + header.Length + footer.Length * 2 + body.Length * 2; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0xB8); // Packet ID - w.Write((short)length); // Length - - w.Write(m); - w.WriteAsciiNull(header); - w.WriteBigUniNull(footer); - w.WriteBigUniNull(body); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Targeting.cs b/Projects/Server/Network/Packets/Targeting.cs deleted file mode 100644 index 68c4aee7f..000000000 --- a/Projects/Server/Network/Packets/Targeting.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Server.Buffers; -using Server.Targeting; - -namespace Server.Network -{ - public static partial class Packets - { - public static void SendMultiTargetReqHS(NetState ns, MultiTarget t) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[30]); - w.Write((byte)0x99); // Packet ID - - w.Write(t.AllowGround); - w.Write(t.TargetID); - w.Write((byte)t.Flags); - w.Position += 11; - w.Write((short)t.MultiID); - w.Write((short)t.Offset.X); - w.Write((short)t.Offset.Y); - w.Write((short)t.Offset.Z); - // 4 bytes unknown? - - ns.Send(w.Span); - } - - public static void SendMultiTargetReq(NetState ns, MultiTarget t) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[26]); - w.Write((byte)0x99); // Packet ID - - w.Write(t.AllowGround); - w.Write(t.TargetID); - w.Write((byte)t.Flags); - w.Position += 14; - w.Write((short)t.MultiID); - w.Write((short)t.Offset.X); - w.Write((short)t.Offset.Y); - w.Write((short)t.Offset.Z); - - ns.Send(w.Span); - } - - private static byte[] _targetReqPacket; - - public static void SendCancelTarget(NetState ns) - { - if (ns == null) - return; - - if (_targetReqPacket == null) - { - _targetReqPacket = new byte[19]; - _targetReqPacket[0] = 0x6C; // Packet ID - _targetReqPacket[6] = 0x03; // ? - } - - ns.Send(_targetReqPacket); - } - - public static void SendTargetReq(NetState ns, Target t) - { - if (ns == null || t == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[19]); - w.Write((byte)0x6C); // Packet ID - - w.Write(t.AllowGround); - w.Write(t.TargetID); - w.Write((byte)t.Flags); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Trade.cs b/Projects/Server/Network/Packets/Trade.cs deleted file mode 100644 index 2e8745928..000000000 --- a/Projects/Server/Network/Packets/Trade.cs +++ /dev/null @@ -1,139 +0,0 @@ -using Server.Buffers; - -namespace Server.Network -{ - public enum TradeFlag : byte - { - Display = 0x0, - Close = 0x1, - Update = 0x2, - UpdateGold = 0x3, - UpdateLedger = 0x4 - } - - public static partial class Packets - { - public static void SendDisplaySecureTrade(NetState ns, Serial them, Serial firstCont, Serial secondCont, string name = "") - { - if (ns == null) - return; - - name ??= ""; - - int length = 17 + name.Length; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x6F); // Packet ID - w.Write((short)length); // Length - - w.Position++; // Display - w.Write(them); - w.Write(firstCont); - w.Write(secondCont); - w.Write(name.Length > 0); - w.WriteAscii(name); - - ns.Send(w.Span); - } - - public static void SendCloseSecureTrade(NetState ns, Serial cont) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[8]); - w.Write((byte)0x6F); // Packet ID - w.Write((ushort)8); // Length - - w.Write((byte)1); // Close - w.Write(cont); - - ns.Send(w.Span); - } - - public static void SendUpdateSecureTrade(NetState ns, Serial cont, bool fromAccepted, bool toAccepted) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[10]); - w.Write((byte)0x6F); // Packet ID - w.Write((ushort)10); // Length - - w.Write((byte)TradeFlag.Update); - w.Write(cont); - w.Write(fromAccepted); - w.Write(toAccepted); - - ns.Send(w.Span); - } - - public static void SendUpdateSecureTrade(NetState ns, Serial cont, TradeFlag flag, int first, int second) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[16]); - w.Write((byte)0x6F); // Packet ID - w.Write((ushort)16); // Length - - w.Write((byte)flag); - w.Write(cont); - w.Write(first); - w.Write(second); - - ns.Send(w.Span); - } - - public static void SendSecureTradeEquip(NetState ns, Item item, Serial m) - { - if (ns == null) - return; - - if (ns.ContainerGridLines) - SendSecureTradeEquipNew(ns, item, m); - else - SendSecureTradeEquipOld(ns, item, m); - } - - public static void SendSecureTradeEquipOld(NetState ns, Item item, Serial m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[20]); - w.Write((byte)0x25); // Packet ID - - w.Write(item.Serial); - w.Write((short)item.ItemID); - w.Position++; // Write((byte)0) - w.Write((short)item.Amount); - w.Write((short)item.X); - w.Write((short)item.Y); - w.Write(m); - w.Write((short)item.Hue); - - ns.Send(w.Span); - } - - public static void SendSecureTradeEquipNew(NetState ns, Item item, Serial m) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[21]); - w.Write((byte)0x25); // Packet ID - - w.Write(item.Serial); - w.Write((short)item.ItemID); - w.Position++; // Write((byte)0) - w.Write((short)item.Amount); - w.Write((short)item.X); - w.Write((short)item.Y); - w.Write(m); - w.Position++; // Write((byte)0) Grid Location? - w.Write((short)item.Hue); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/Packets/Vendors.cs b/Projects/Server/Network/Packets/Vendors.cs deleted file mode 100644 index 257a468cd..000000000 --- a/Projects/Server/Network/Packets/Vendors.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System.Collections.Generic; -using Server.Buffers; -using Server.Items; - -namespace Server.Network -{ - public static partial class Packets - { - public static void SendVendorBuyContent(NetState ns, IList list) - { - if (ns == null) - return; - - if (ns.ContainerGridLines) - SendVendorBuyContentNew(ns, list); - else - SendVendorBuyContentOld(ns, list); - } - - public static void SendVendorBuyContentOld(NetState ns, IList list) - { - if (ns == null) - return; - - int length = 5 + list.Count * 19; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x3C); // Packet ID - w.Write((ushort)length); // Length - - w.Write((short)list.Count); - - //The client sorts these by their X/Y value. - //OSI sends these in weird order. X/Y highest to lowest and serial lowest to highest - //These are already sorted by serial (done by the vendor class) but we have to send them by x/y - //(the x74 packet is sent in 'correct' order.) - for (int i = list.Count - 1; i >= 0; --i) - { - BuyItemState bis = list[i]; - - w.Write(bis.MySerial); - w.Write((ushort)bis.ItemID); - w.Position++; // Write((byte)0); itemid offset - w.Write((ushort)bis.Amount); - w.Write((short)(i + 1)); //x - w.Write((short)1); //y - w.Write(bis.ContainerSerial); - w.Write((ushort)bis.Hue); - } - - ns.Send(w.RawSpan); - } - - public static void SendVendorBuyContentNew(NetState ns, IList list) - { - if (ns == null) - return; - - int length = 5 + list.Count * 20; - SpanWriter w = new SpanWriter(stackalloc byte[length]); - w.Write((byte)0x3C); // Packet ID - w.Write((ushort)length); // Length - - w.Write((short)list.Count); - - //The client sorts these by their X/Y value. - //OSI sends these in weird order. X/Y highest to lowest and serial lowest to highest - //These are already sorted by serial (done by the vendor class) but we have to send them by x/y - //(the x74 packet is sent in 'correct' order.) - for (int i = list.Count - 1; i >= 0; --i) - { - BuyItemState bis = list[i]; - - w.Write(bis.MySerial); - w.Write((ushort)bis.ItemID); - w.Position++; // Write((byte)0); itemid offset - w.Write((ushort)bis.Amount); - w.Write((short)(i + 1)); //x - w.Write((short)1); //y - w.Position++; // Write((byte)0); Grid Location? - w.Write(bis.ContainerSerial); - w.Write((ushort)bis.Hue); - } - - ns.Send(w.RawSpan); - } - - public static void SendDisplayBuyList(NetState ns, Serial vendor) - { - if (ns == null) - return; - - if (ns.HighSeas) - SendDisplayBuyListHS(ns, vendor); - else - SendDisplayBuyListOld(ns, vendor); - } - - public static void SendDisplayBuyListOld(NetState ns, Serial vendor) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[7]); - w.Write((byte)0x24); // Packet ID - - w.Write(vendor); - w.Write((short)0x30); // buy window id? - - ns.Send(w.RawSpan); - } - - public static void SendDisplayBuyListHS(NetState ns, Serial vendor) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[9]); - w.Write((byte)0x24); // Packet ID - - w.Write(vendor); - w.Write((short)0x30); // buy window id? - //w.Write((short)0x00); // Unknown - - ns.Send(w.RawSpan); - } - - public static void SendVendorBuyList(NetState ns, Mobile vendor, IList list) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[8 + 135 * list.Count]); - w.Write((byte)0x74); // Packet ID - w.Position += 2; // Dynamic Length - - w.Write(!(vendor.FindItemOnLayer(Layer.ShopBuy) is Container BuyPack) ? Serial.MinusOne : BuyPack.Serial); - - w.Write((byte)list.Count); - - for (int i = 0; i < list.Count; ++i) - { - BuyItemState bis = list[i]; - - w.Write(bis.Price); - - string desc = bis.Description ?? ""; - w.Write((byte)(desc.Length + 1)); - w.WriteAsciiNull(desc); - } - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - ns.Send(w.Span); - } - - public static void SendVendorSellList(NetState ns, Serial shopkeeper, IList list) - { - if (ns == null) - return; - - ushort count = (ushort)list.Count; - SpanWriter w = new SpanWriter(stackalloc byte[9 + 140 * count]); - w.Write((byte)0x9E); // Packet ID - w.Position += 2; //( Dynamic Length - - w.Write(shopkeeper); - - w.Write(count); - - for (int i = 0; i < count; ++i) - { - SellItemState state = list[i]; - - w.Write(state.Item.Serial); - w.Write((ushort)state.Item.ItemID); - w.Write((ushort)state.Item.Hue); - w.Write((ushort)state.Item.Amount); - w.Write((ushort)state.Price); - - string name = state.Item.Name; - - if (name == null || (name = name.Trim()).Length <= 0) - name = state.Name ?? ""; - - w.Write((ushort)name.Length); - w.WriteAsciiFixed(name, (ushort)name.Length); - } - - w.Position = 1; - w.Write((ushort)w.WrittenCount); - ns.Send(w.Span); - } - - public static void SendEndVendorBuyOrSell(NetState ns, Serial vendor) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[8]); - w.Write((byte)0x3B); // Packet ID - - w.Write(vendor); - - ns.Send(w.RawSpan); - } - } -} diff --git a/Projects/Server/Network/Packets/VirtualHair.cs b/Projects/Server/Network/Packets/VirtualHair.cs deleted file mode 100644 index 05622a480..000000000 --- a/Projects/Server/Network/Packets/VirtualHair.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Server.Buffers; -using Server.Items; - -namespace Server.Network -{ - public static partial class Packets - { - public static void SendHairEquipUpdate(NetState ns, Mobile parent) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[15]); - w.Write((byte)0x2E); // Packet ID - - int hue = parent.HairHue; - - if (parent.SolidHueOverride >= 0) - hue = parent.SolidHueOverride; - - w.Write(HairInfo.FakeSerial(parent.Serial)); - w.Write((short)parent.HairItemID); - w.Write((short)Layer.Hair); - w.Write(parent.Serial); - w.Write((short)hue); - - ns.Send(w.Span); - } - - public static void SendFacialHairEquipUpdate(NetState ns, Mobile parent) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[15]); - w.Write((byte)0x2E); // Packet ID - - int hue = parent.FacialHairHue; - - if (parent.SolidHueOverride >= 0) - hue = parent.SolidHueOverride; - - w.Write(FacialHairInfo.FakeSerial(parent.Serial)); - w.Write((short)parent.FacialHairItemID); - w.Write((short)Layer.Hair); - w.Write(parent.Serial); - w.Write((short)hue); - - ns.Send(w.Span); - } - - public static void SendRemoveHair(NetState ns, Mobile parent) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[5]); - w.Write((byte)0x1D); // Packet ID - - w.Write(HairInfo.FakeSerial(parent.Serial)); - - ns.Send(w.Span); - } - - public static void SendRemoveFacialHair(NetState ns, Mobile parent) - { - if (ns == null) - return; - - SpanWriter w = new SpanWriter(stackalloc byte[5]); - w.Write((byte)0x1D); // Packet ID - - w.Write(FacialHairInfo.FakeSerial(parent.Serial)); - - ns.Send(w.Span); - } - } -} diff --git a/Projects/Server/Network/SendQueue.cs b/Projects/Server/Network/SendQueue.cs new file mode 100644 index 000000000..c074de17e --- /dev/null +++ b/Projects/Server/Network/SendQueue.cs @@ -0,0 +1,44 @@ +/*************************************************************************** + * SendQueue.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System.Collections.Concurrent; +using System.Threading.Tasks; + +namespace Server.Network +{ + public class SendQueue + { + private BlockingCollection m_Queue = new BlockingCollection(new ConcurrentQueue()); + + public void Enqueue(T t) + { + m_Queue.Add(t); + } + + public Task DequeueAsync() + { + TaskCompletionSource taskCompletion = new TaskCompletionSource(); + Task.Run(() => taskCompletion.SetResult(Dequeue())); + return taskCompletion.Task; + } + + public T Dequeue() => m_Queue.Take(); + } +} diff --git a/Projects/Server/Network/ServerInfo.cs b/Projects/Server/Network/ServerInfo.cs deleted file mode 100644 index 0215ff29d..000000000 --- a/Projects/Server/Network/ServerInfo.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Net; - -namespace Server.Network -{ - public sealed class ServerInfo - { - public ServerInfo(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address) - { - Name = name; - FullPercent = fullPercent; - TimeZone = tz.GetUtcOffset(DateTime.Now).Hours; - Address = address; - } - - public string Name { get; set; } - - public int FullPercent { get; set; } - - public int TimeZone { get; set; } - - public IPEndPoint Address { get; set; } - } -} diff --git a/Projects/Server/Network/SocketExtensions.cs b/Projects/Server/Network/SocketExtensions.cs index 0b50b9909..e03a79243 100644 --- a/Projects/Server/Network/SocketExtensions.cs +++ b/Projects/Server/Network/SocketExtensions.cs @@ -34,7 +34,7 @@ namespace Server.Network public static ArraySegment GetArray(this ReadOnlyMemory memory) { - if (MemoryMarshal.TryGetArray(memory, out ArraySegment result)) + if (MemoryMarshal.TryGetArray(memory, out var result)) return result; throw new InvalidOperationException("Buffer backed by array was expected"); @@ -42,7 +42,7 @@ namespace Server.Network public static ArraySegment GetArray(this ReadOnlySequence memory) { - if (SequenceMarshal.TryGetArray(memory, out ArraySegment result)) + if (SequenceMarshal.TryGetArray(memory, out var result)) return result; throw new InvalidOperationException("Buffer backed by array was expected"); diff --git a/Projects/Server/Network/StaticPacketHandlers.cs b/Projects/Server/Network/StaticPacketHandlers.cs new file mode 100644 index 000000000..b2c710581 --- /dev/null +++ b/Projects/Server/Network/StaticPacketHandlers.cs @@ -0,0 +1,135 @@ +/*************************************************************************** + * StaticPacketHandlers.cs + * ------------------- + * begin : March 15, 2019 + * copyright : (C) The ModernUO Team + * email : hi@modernuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System.Collections.Concurrent; + +namespace Server.Network +{ + public static class StaticPacketHandlers + { + private static ConcurrentDictionary OPLInfoPackets = new ConcurrentDictionary(); + private static ConcurrentDictionary ObjectPropertyListPackets = new ConcurrentDictionary(); + private static ConcurrentDictionary RemoveEntityPackets = new ConcurrentDictionary(); + + private static ConcurrentDictionary WorldItemPackets = new ConcurrentDictionary(); + private static ConcurrentDictionary WorldItemSAPackets = new ConcurrentDictionary(); + private static ConcurrentDictionary WorldItemHSPackets = new ConcurrentDictionary(); + + public static OPLInfo GetOPLInfoPacket(IPropertyListObject obj) + { + return OPLInfoPackets.GetOrAdd(obj, value => + { + OPLInfo packet = new OPLInfo(value.PropertyList); + packet.SetStatic(); + return packet; + }); + } + + public static OPLInfo FreeOPLInfoPacket(IPropertyListObject obj) + { + if (OPLInfoPackets.TryRemove(obj, out OPLInfo p)) + Packet.Release(p); + + return p; + } + + public static ObjectPropertyList GetOPLPacket(IPropertyListObject obj) + { + return ObjectPropertyListPackets.GetOrAdd(obj, value => + { + ObjectPropertyList list = new ObjectPropertyList(value); + + value.GetProperties(list); + if (value is Item item) + item.AppendChildProperties(list); + + list.Terminate(); + list.SetStatic(); + return list; + }); + } + + public static ObjectPropertyList FreeOPLPacket(IPropertyListObject obj) + { + if (ObjectPropertyListPackets.TryRemove(obj, out ObjectPropertyList list)) + Packet.Release(list); + + return list; + } + + public static RemoveEntity GetRemoveEntityPacket(IEntity entity) + { + return RemoveEntityPackets.GetOrAdd(entity, value => + { + RemoveEntity packet = new RemoveEntity(value); + packet.SetStatic(); + return packet; + }); + } + + public static void FreeRemoveItemPacket(IEntity entity) + { + if (RemoveEntityPackets.TryRemove(entity, out RemoveEntity p)) + Packet.Release(p); + } + + public static WorldItem GetWorldItemPacket(Item item) + { + return WorldItemPackets.GetOrAdd(item, value => + { + WorldItem packet = new WorldItem(value); + packet.SetStatic(); + return packet; + }); + } + + public static WorldItemSA GetWorldItemSAPacket(Item item) + { + return WorldItemSAPackets.GetOrAdd(item, value => + { + WorldItemSA packet = new WorldItemSA(value); + packet.SetStatic(); + return packet; + }); + } + + public static WorldItemHS GetWorldItemHSPacket(Item item) + { + return WorldItemHSPackets.GetOrAdd(item, value => + { + WorldItemHS packet = new WorldItemHS(value); + packet.SetStatic(); + return packet; + }); + } + + public static void FreeWorldItemPackets(Item item) + { + if (WorldItemPackets.TryRemove(item, out WorldItem wi)) + Packet.Release(wi); + + if (WorldItemSAPackets.TryRemove(item, out WorldItemSA wisa)) + Packet.Release(wisa); + + if (WorldItemHSPackets.TryRemove(item, out WorldItemHS wihs)) + Packet.Release(wihs); + } + } +} diff --git a/Projects/Server/Notoriety.cs b/Projects/Server/Notoriety.cs index a5e025a60..60dd4e3b6 100644 --- a/Projects/Server/Notoriety.cs +++ b/Projects/Server/Notoriety.cs @@ -20,17 +20,17 @@ namespace Server { - public delegate byte NotorietyHandler(Mobile source, Mobile target); + public delegate int NotorietyHandler(Mobile source, Mobile target); public static class Notoriety { - public const byte Innocent = 1; - public const byte Ally = 2; - public const byte CanBeAttacked = 3; - public const byte Criminal = 4; - public const byte Enemy = 5; - public const byte Murderer = 6; - public const byte Invulnerable = 7; + public const int Innocent = 1; + public const int Ally = 2; + public const int CanBeAttacked = 3; + public const int Criminal = 4; + public const int Enemy = 5; + public const int Murderer = 6; + public const int Invulnerable = 7; public static NotorietyHandler Handler{ get; set; } @@ -46,7 +46,13 @@ namespace Server 0x035 }; - public static int GetHue(int noto) => noto < 0 || noto >= Hues.Length ? 0 : Hues[noto]; + public static int GetHue(int noto) + { + if (noto < 0 || noto >= Hues.Length) + return 0; + + return Hues[noto]; + } public static int Compute(Mobile source, Mobile target) => Handler?.Invoke(source, target) ?? CanBeAttacked; } diff --git a/Projects/Server/ObjectPropertyList.cs b/Projects/Server/ObjectPropertyList.cs index fc1c8aaf5..abb437934 100644 --- a/Projects/Server/ObjectPropertyList.cs +++ b/Projects/Server/ObjectPropertyList.cs @@ -18,19 +18,27 @@ * ***************************************************************************/ -using System; -using System.Buffers; +using System.IO; using System.Text; -using Server.Buffers; using Server.Network; namespace Server { - public sealed class ObjectPropertyList + public interface IPropertyListObject : IEntity { + ObjectPropertyList PropertyList{ get; } + OPLInfo OPLPacket{ get; } + + void GetProperties(ObjectPropertyList list); + } + + public sealed class ObjectPropertyList : Packet + { + private static byte[] m_Buffer = new byte[1024]; + private static Encoding m_Encoding = Encoding.Unicode; + // Each of these are localized to "~1_NOTHING~" which allows the string argument to be used - // TODO: There are more of these, add them. - private static readonly int[] m_StringNumbers = + private static int[] m_StringNumbers = { 1042971, 1070722 @@ -39,9 +47,18 @@ namespace Server private int m_Hash; private int m_Strings; - private ArrayBufferWriter m_Buffer = new ArrayBufferWriter(); + public ObjectPropertyList(IEntity e) : base(0xD6) + { + EnsureCapacity(128); - public ObjectPropertyList(IEntity e) => Entity = e; + Entity = e; + + m_Stream.Write((short)1); + m_Stream.Write(e.Serial); + m_Stream.Write((byte)0); + m_Stream.Write((byte)0); + m_Stream.Write(e.Serial); + } public IEntity Entity{ get; } @@ -53,26 +70,29 @@ namespace Server public static bool Enabled{ get; set; } - public void Send(NetState ns) + public void Add(int number) { - if (ns == null) + if (number == 0) return; - ReadOnlySpan body = m_Buffer.WrittenSpan; + AddHash(number); - ushort length = (ushort)(19 + body.Length); - SpanWriter writer = new SpanWriter(stackalloc byte[length]); - writer.Write((byte)0xD6); // Packet ID - writer.Write(length); // Dynamic Length + if (Header == 0) + { + Header = number; + HeaderArgs = ""; + } - writer.Write((short)1); // Command - writer.Write(Entity.Serial); - writer.Position += 2; - writer.Write(m_Hash); - writer.Write(body); - writer.Position += 4; + m_Stream.Write(number); + m_Stream.Write((short)0); + } - ns.Send(writer.Span); + public void Terminate() + { + m_Stream.Write(0); + + m_Stream.Seek(11, SeekOrigin.Begin); + m_Stream.Write(m_Hash); } public void AddHash(int val) @@ -81,12 +101,13 @@ namespace Server m_Hash ^= val >> 26 & 0x3F; } - public void Add(int number, string arguments = "") + public void Add(int number, string arguments) { if (number == 0) return; - arguments ??= ""; + if (arguments == null) + arguments = ""; if (Header == 0) { @@ -95,17 +116,34 @@ namespace Server } AddHash(number); - if (arguments != "") - AddHash(arguments.GetHashCode()); + AddHash(arguments.GetHashCode()); - int argLength = Encoding.Unicode.GetByteCount(arguments); - int length = 6 + argLength; - SpanWriter writer = new SpanWriter(m_Buffer.GetSpan(length)); - writer.Write(number); - writer.Write((short)argLength); - writer.WriteLittleUni(arguments); + m_Stream.Write(number); - m_Buffer.Advance(length); + int byteCount = m_Encoding.GetByteCount(arguments); + + if (byteCount > m_Buffer.Length) + m_Buffer = new byte[byteCount]; + + byteCount = m_Encoding.GetBytes(arguments, 0, arguments.Length, m_Buffer, 0); + + m_Stream.Write((short)byteCount); + m_Stream.Write(m_Buffer, 0, byteCount); + } + + public void Add(int number, string format, object arg0) + { + Add(number, string.Format(format, arg0)); + } + + public void Add(int number, string format, object arg0, object arg1) + { + Add(number, string.Format(format, arg0, arg1)); + } + + public void Add(int number, string format, object arg0, object arg1, object arg2) + { + Add(number, string.Format(format, arg0, arg1, arg2)); } public void Add(int number, string format, params object[] args) @@ -120,20 +158,42 @@ namespace Server Add(GetStringNumber(), text); } + public void Add(string format, string arg0) + { + Add(GetStringNumber(), string.Format(format, arg0)); + } + + public void Add(string format, string arg0, string arg1) + { + Add(GetStringNumber(), string.Format(format, arg0, arg1)); + } + + public void Add(string format, string arg0, string arg1, string arg2) + { + Add(GetStringNumber(), string.Format(format, arg0, arg1, arg2)); + } + public void Add(string format, params object[] args) { Add(GetStringNumber(), string.Format(format, args)); } + } - public void SendOPLInfo(NetState ns) + public sealed class OPLInfo : Packet + { + /*public OPLInfo( ObjectPropertyList list ) : base( 0xBF ) { - SpanWriter writer = new SpanWriter(stackalloc byte[9]); - writer.Write((byte)0xDC); // Packet ID + EnsureCapacity( 13 ); - writer.Write(Entity.Serial); - writer.Write(m_Hash); + m_Stream.Write( (short) 0x10 ); + m_Stream.Write( (int) list.Entity.Serial ); + m_Stream.Write( (int) list.Hash ); + }*/ - ns.Send(writer.Span); + public OPLInfo(ObjectPropertyList list) : base(0xDC, 9) + { + m_Stream.Write(list.Entity.Serial); + m_Stream.Write(list.Hash); } } } diff --git a/Projects/Server/Persistence/BinaryMemoryWriter.cs b/Projects/Server/Persistence/BinaryMemoryWriter.cs index d84f04238..266cc76cf 100644 --- a/Projects/Server/Persistence/BinaryMemoryWriter.cs +++ b/Projects/Server/Persistence/BinaryMemoryWriter.cs @@ -20,7 +20,7 @@ using System.IO; -namespace Server.Persistence +namespace Server { public sealed class BinaryMemoryWriter : BinaryFileWriter { diff --git a/Projects/Server/Persistence/DualSaveStrategy.cs b/Projects/Server/Persistence/DualSaveStrategy.cs index 090484330..8e9ce9785 100644 --- a/Projects/Server/Persistence/DualSaveStrategy.cs +++ b/Projects/Server/Persistence/DualSaveStrategy.cs @@ -20,7 +20,7 @@ using System.Threading; -namespace Server.Persistence +namespace Server { public sealed class DualSaveStrategy : StandardSaveStrategy { diff --git a/Projects/Server/Persistence/DynamicSaveStrategy.cs b/Projects/Server/Persistence/DynamicSaveStrategy.cs index 5e87114f5..0132c1f52 100644 --- a/Projects/Server/Persistence/DynamicSaveStrategy.cs +++ b/Projects/Server/Persistence/DynamicSaveStrategy.cs @@ -23,8 +23,9 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; +using Server.Guilds; -namespace Server.Persistence +namespace Server { public sealed class DynamicSaveStrategy : SaveStrategy { diff --git a/Projects/Server/Persistence/FileOperations.cs b/Projects/Server/Persistence/FileOperations.cs index 89ec8a90a..3939c9e48 100644 --- a/Projects/Server/Persistence/FileOperations.cs +++ b/Projects/Server/Persistence/FileOperations.cs @@ -18,9 +18,16 @@ * ***************************************************************************/ -using System.IO; -namespace Server.Persistence +using System; +using System.IO; +#if !MONO +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +#endif + +namespace Server { public static class FileOperations { @@ -31,8 +38,12 @@ namespace Server.Persistence public static int Concurrency{ get; set; } = 1; + public static bool Unbuffered{ get; set; } = true; + public static bool AreSynchronous => Concurrency < 1; + public static bool AreAsynchronous => Concurrency > 0; + public static FileStream OpenSequentialStream(string path, FileMode mode, FileAccess access, FileShare share) { FileOptions options = FileOptions.SequentialScan; @@ -93,5 +104,6 @@ namespace Server.Persistence internal static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, IntPtr securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); } +#endif } } diff --git a/Projects/Server/Persistence/FileQueue.cs b/Projects/Server/Persistence/FileQueue.cs index 9390bc6e6..082c11ded 100644 --- a/Projects/Server/Persistence/FileQueue.cs +++ b/Projects/Server/Persistence/FileQueue.cs @@ -23,7 +23,7 @@ using System.Buffers; using System.Collections.Generic; using System.Threading; -namespace Server.Persistence +namespace Server { public delegate void FileCommitCallback(FileQueue.Chunk chunk); @@ -47,7 +47,7 @@ namespace Server.Persistence public FileQueue(int concurrentWrites, FileCommitCallback callback) { - if (concurrentWrites < 1) throw new ArgumentOutOfRangeException(nameof(concurrentWrites)); + if (concurrentWrites < 1) throw new ArgumentOutOfRangeException("concurrentWrites"); if (bufferSize < 1) throw new ArgumentOutOfRangeException("bufferSize"); @@ -134,7 +134,7 @@ namespace Server.Persistence { if (active[slot] != chunk) throw new ArgumentException(); - ArrayPool.Shared.Return(chunk.Buffer, true); + ArrayPool.Shared.Return(chunk.Buffer); if (pending.Count > 0) { @@ -157,17 +157,18 @@ namespace Server.Persistence public void Enqueue(byte[] buffer, int offset, int size) { - if (buffer == null) throw new ArgumentNullException(nameof(buffer)); + if (buffer == null) throw new ArgumentNullException("buffer"); - if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); - if (size < 0) throw new ArgumentOutOfRangeException(nameof(size)); + if (offset < 0) throw new ArgumentOutOfRangeException("offset"); + if (size < 0) throw new ArgumentOutOfRangeException("size"); if (buffer.Length - offset < size) throw new ArgumentException(); Position += size; while (size > 0) { - buffered.buffer ??= ArrayPool.Shared.Rent(bufferSize); + if (buffered.buffer == null) + buffered.buffer = ArrayPool.Shared.Rent(bufferSize); byte[] page = buffered.buffer; // buffer page int pageSpace = page.Length - buffered.length; // available bytes in page diff --git a/Projects/Server/Persistence/ParallelSaveStrategy.cs b/Projects/Server/Persistence/ParallelSaveStrategy.cs index b79c9ca5f..80614bc3c 100644 --- a/Projects/Server/Persistence/ParallelSaveStrategy.cs +++ b/Projects/Server/Persistence/ParallelSaveStrategy.cs @@ -22,8 +22,9 @@ using System; using System.Collections; using System.Collections.Generic; using System.Threading; +using Server.Guilds; -namespace Server.Persistence +namespace Server { public sealed class ParallelSaveStrategy : SaveStrategy { diff --git a/Projects/Server/Persistence/Persistence.cs b/Projects/Server/Persistence/Persistence.cs index c8f9f291f..61c3dc9c7 100644 --- a/Projects/Server/Persistence/Persistence.cs +++ b/Projects/Server/Persistence/Persistence.cs @@ -5,7 +5,7 @@ using System.IO; #endregion -namespace Server.Persistence +namespace Server { public static class Persistence { diff --git a/Projects/Server/Persistence/QueuedMemoryWriter.cs b/Projects/Server/Persistence/QueuedMemoryWriter.cs index 468183a9b..1bcd67982 100644 --- a/Projects/Server/Persistence/QueuedMemoryWriter.cs +++ b/Projects/Server/Persistence/QueuedMemoryWriter.cs @@ -21,7 +21,7 @@ using System.Collections.Generic; using System.IO; -namespace Server.Persistence +namespace Server { public sealed class QueuedMemoryWriter : BinaryFileWriter { diff --git a/Projects/Server/Persistence/SaveStrategy.cs b/Projects/Server/Persistence/SaveStrategy.cs index b53ad34a6..dbf7f6938 100644 --- a/Projects/Server/Persistence/SaveStrategy.cs +++ b/Projects/Server/Persistence/SaveStrategy.cs @@ -18,7 +18,7 @@ * ***************************************************************************/ -namespace Server.Persistence +namespace Server { public abstract class SaveStrategy { diff --git a/Projects/Server/Persistence/SequentialFileWriter.cs b/Projects/Server/Persistence/SequentialFileWriter.cs index d232639cd..9b1d327b6 100644 --- a/Projects/Server/Persistence/SequentialFileWriter.cs +++ b/Projects/Server/Persistence/SequentialFileWriter.cs @@ -21,7 +21,7 @@ using System; using System.IO; -namespace Server.Persistence +namespace Server { public sealed class SequentialFileWriter : Stream { diff --git a/Projects/Server/Persistence/StandardSaveStrategy.cs b/Projects/Server/Persistence/StandardSaveStrategy.cs index 810564058..8b32c1cd0 100644 --- a/Projects/Server/Persistence/StandardSaveStrategy.cs +++ b/Projects/Server/Persistence/StandardSaveStrategy.cs @@ -20,8 +20,9 @@ using System; using System.Collections.Generic; +using Server.Guilds; -namespace Server.Persistence +namespace Server { public class StandardSaveStrategy : SaveStrategy { @@ -90,7 +91,7 @@ namespace Server.Persistence idx.Write((int)(bin.Position - start)); - m.ClearProperties(); + m.FreeCache(); } tdb.Write(World.m_MobileTypes.Count); @@ -143,7 +144,7 @@ namespace Server.Persistence idx.Write((int)(bin.Position - start)); - item.ClearProperties(); + item.FreeCache(); } tdb.Write(World.m_ItemTypes.Count); diff --git a/Projects/Server/Prompt.cs b/Projects/Server/Prompt.cs index d54c87edf..36c9de092 100644 --- a/Projects/Server/Prompt.cs +++ b/Projects/Server/Prompt.cs @@ -18,11 +18,11 @@ * ***************************************************************************/ -namespace Server +namespace Server.Prompts { public abstract class Prompt { - private static Serial m_Serials; + private static int m_Serials; protected Prompt() { @@ -32,7 +32,7 @@ namespace Server } while (Serial == 0); } - public Serial Serial{ get; } + public int Serial{ get; } public virtual void OnCancel(Mobile from) { @@ -42,4 +42,4 @@ namespace Server { } } -} +} \ No newline at end of file diff --git a/Projects/Server/QuestArrow.cs b/Projects/Server/QuestArrow.cs index c36a3f637..5dd3cef2e 100644 --- a/Projects/Server/QuestArrow.cs +++ b/Projects/Server/QuestArrow.cs @@ -58,9 +58,9 @@ namespace Server return; if (ns.HighSeas) - Packets.SendSetArrowHS(ns, Target.Serial, (short)x, (short)y); + ns.Send(new SetArrowHS(x, y, Target.Serial)); else - Packets.SendSetArrow(ns, (short)x, (short)y); + ns.Send(new SetArrow(x, y)); } public void Stop() @@ -80,9 +80,9 @@ namespace Server if (ns != null) { if (ns.HighSeas) - Packets.SendCancelArrowHS(ns, Target.Serial, (short)x, (short)y); + ns.Send(new CancelArrowHS(x, y, Target.Serial)); else - Packets.SendCancelArrow(ns); + ns.Send(new CancelArrow()); } Running = false; @@ -97,4 +97,4 @@ namespace Server { } } -} +} \ No newline at end of file diff --git a/Projects/Server/Region.cs b/Projects/Server/Region.cs index 649645e5d..572d4750a 100644 --- a/Projects/Server/Region.cs +++ b/Projects/Server/Region.cs @@ -21,17 +21,15 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Xml; using Server.Network; using Server.Targeting; namespace Server { - public enum MusicName : ushort + public enum MusicName { - Invalid = 0xFFFF, - None = 0x1FFF, + Invalid = -1, OldUlt01 = 0, Create1, DragFlit, @@ -475,7 +473,13 @@ namespace Server List list = new List(); for (int i = 0; i < Sectors?.Length; i++) - list.AddRange(Sectors[i].Players.Where(player => player.Region.IsPartOf(this))); + { + Sector sector = Sectors[i]; + + foreach (Mobile player in sector.Players) + if (player.Region.IsPartOf(this)) + list.Add(player); + } return list; } @@ -485,7 +489,13 @@ namespace Server int count = 0; for (int i = 0; i < Sectors?.Length; i++) - count += Sectors[i].Players.Count(player => player.Region.IsPartOf(this)); + { + Sector sector = Sectors[i]; + + foreach (Mobile player in sector.Players) + if (player.Region.IsPartOf(this)) + count++; + } return count; } @@ -494,7 +504,13 @@ namespace Server List list = new List(); for (int i = 0; i < Sectors?.Length; i++) - list.AddRange(Sectors[i].Mobiles.Where(mobile => mobile.Region.IsPartOf(this))); + { + Sector sector = Sectors[i]; + + foreach (Mobile mobile in sector.Mobiles) + if (mobile.Region.IsPartOf(this)) + list.Add(mobile); + } return list; } @@ -503,7 +519,13 @@ namespace Server int count = 0; for (int i = 0; i < Sectors?.Length; i++) - count += Sectors[i].Mobiles.Count(mobile => mobile.Region.IsPartOf(this)); + { + Sector sector = Sectors[i]; + + foreach (Mobile mobile in sector.Mobiles) + if (mobile.Region.IsPartOf(this)) + count++; + } return count; } @@ -679,8 +701,7 @@ namespace Server { m.CheckLightLevels(false); - if (oldRegion == null || oldRegion.Music != newRegion.Music) - Packets.SendPlayMusic(m.NetState, newRegion.Music); + if (oldRegion == null || oldRegion.Music != newRegion.Music) m.Send(PlayMusic.GetInstance(newRegion.Music)); } Region oldR = oldRegion; diff --git a/Projects/Server/Sector.cs b/Projects/Server/Sector.cs index 57f708064..32d9810cf 100644 --- a/Projects/Server/Sector.cs +++ b/Projects/Server/Sector.cs @@ -91,7 +91,8 @@ namespace Server private void Add(ref List list, T value) { - list ??= new List(); + if (list == null) list = new List(); + list.Add(value); } diff --git a/Projects/Server/SecureTrade.cs b/Projects/Server/SecureTrade.cs index ae20e2f62..a1d3872e3 100644 --- a/Projects/Server/SecureTrade.cs +++ b/Projects/Server/SecureTrade.cs @@ -18,11 +18,16 @@ * ***************************************************************************/ +#region References + using System; using System.Collections.Generic; +using Server.Accounting; using Server.Items; using Server.Network; +#endregion + namespace Server { public class SecureTrade @@ -34,33 +39,56 @@ namespace Server From = new SecureTradeInfo(this, from, new SecureTradeContainer(this)); To = new SecureTradeInfo(this, to, new SecureTradeContainer(this)); - NetState fromNS = from.NetState; - NetState toNS = to.NetState; + bool from6017 = from.NetState?.ContainerGridLines == true; + bool to6017 = to.NetState?.ContainerGridLines == true; - bool from704565 = fromNS?.NewSecureTrading == true; - bool to704565 = toNS?.NewSecureTrading == true; + bool from704565 = from.NetState?.NewSecureTrading == true; + bool to704565 = to.NetState?.NewSecureTrading == true; + + from.Send(new MobileStatus(from, to)); + from.Send(new UpdateSecureTrade(From.Container, false, false)); + + if (from6017) + from.Send(new SecureTradeEquip6017(To.Container, to)); + else + from.Send(new SecureTradeEquip(To.Container, to)); + + from.Send(new UpdateSecureTrade(From.Container, false, false)); + + if (from6017) + from.Send(new SecureTradeEquip6017(From.Container, from)); + else + from.Send(new SecureTradeEquip(From.Container, from)); + + from.Send(new DisplaySecureTrade(to, From.Container, To.Container, to.Name)); + from.Send(new UpdateSecureTrade(From.Container, false, false)); - Packets.SendMobileStatus(fromNS, from, to); - Packets.SendUpdateSecureTrade(fromNS, From.Container.Serial, false, false); - Packets.SendSecureTradeEquip(fromNS, To.Container, to.Serial); - Packets.SendUpdateSecureTrade(fromNS, From.Container.Serial, false, false); - Packets.SendSecureTradeEquip(fromNS, To.Container, from.Serial); - Packets.SendDisplaySecureTrade(fromNS, to.Serial, From.Container.Serial, To.Container.Serial, to.Name); - Packets.SendUpdateSecureTrade(fromNS, From.Container.Serial, false, false); if (from.Account != null && from704565) - Packets.SendUpdateSecureTrade(fromNS, From.Container.Serial, TradeFlag.UpdateLedger,from.Account.TotalGold, - from.Account.TotalPlat); + from.Send( + new UpdateSecureTrade(From.Container, TradeFlag.UpdateLedger, from.Account.TotalGold, + from.Account.TotalPlat)); + + to.Send(new MobileStatus(to, from)); + to.Send(new UpdateSecureTrade(To.Container, false, false)); + + if (to6017) + to.Send(new SecureTradeEquip6017(From.Container, from)); + else + to.Send(new SecureTradeEquip(From.Container, from)); + + to.Send(new UpdateSecureTrade(To.Container, false, false)); + + if (to6017) + to.Send(new SecureTradeEquip6017(To.Container, to)); + else + to.Send(new SecureTradeEquip(To.Container, to)); + + to.Send(new DisplaySecureTrade(from, To.Container, From.Container, from.Name)); + to.Send(new UpdateSecureTrade(To.Container, false, false)); - Packets.SendMobileStatus(toNS, to, from); - Packets.SendUpdateSecureTrade(toNS, To.Container.Serial, false, false); - Packets.SendSecureTradeEquip(toNS, From.Container, from.Serial); - Packets.SendUpdateSecureTrade(toNS, To.Container.Serial, false, false); - Packets.SendSecureTradeEquip(toNS, From.Container, to.Serial); - Packets.SendDisplaySecureTrade(toNS, from.Serial, To.Container.Serial, From.Container.Serial, from.Name); - Packets.SendUpdateSecureTrade(toNS, To.Container.Serial, false, false); if (to.Account != null && to704565) - Packets.SendUpdateSecureTrade(toNS, To.Container.Serial, TradeFlag.UpdateLedger,to.Account.TotalGold, - to.Account.TotalPlat); + to.Send(new UpdateSecureTrade(To.Container, TradeFlag.UpdateLedger, to.Account.TotalGold, + to.Account.TotalPlat)); } public SecureTradeInfo From{ get; } @@ -84,8 +112,7 @@ namespace Server item.OnSecureTrade(From.Mobile, To.Mobile, From.Mobile, false); - if (!item.Deleted) - From.Mobile.AddToBackpack(item); + if (!item.Deleted) From.Mobile.AddToBackpack(item); } list = To.Container.Items; @@ -109,15 +136,16 @@ namespace Server { if (!Valid) return; + From.Mobile.Send(new CloseSecureTrade(From.Container)); + To.Mobile.Send(new CloseSecureTrade(To.Container)); + Valid = false; NetState ns = From.Mobile.NetState; - Packets.SendCloseSecureTrade(ns, From.Container.Serial); ns?.RemoveTrade(this); ns = To.Mobile.NetState; - Packets.SendCloseSecureTrade(ns, To.Container.Serial); ns?.RemoveTrade(this); @@ -142,9 +170,8 @@ namespace Server int plat = left.Mobile.Account.TotalPlat; int gold = left.Mobile.Account.TotalGold; - if (from.NetState?.NewSecureTrading == true) - Packets.SendUpdateSecureTrade(from.NetState, left.Container.Serial, TradeFlag.UpdateLedger, - from.Account.TotalPlat, from.Account.TotalGold); + left.Mobile.Send(new UpdateSecureTrade(left.Container, TradeFlag.UpdateLedger, gold, plat)); + } if (right.Mobile.NetState?.NewSecureTrading == true) right.Mobile.Send(new UpdateSecureTrade(right.Container, TradeFlag.UpdateGold, left.Gold, left.Plat)); @@ -214,8 +241,8 @@ namespace Server From.Accepted = false; To.Accepted = false; - Packets.SendUpdateSecureTrade(From.Mobile.NetState, From.Container.Serial, From.Accepted, To.Accepted); - Packets.SendUpdateSecureTrade(To.Mobile.NetState, To.Container.Serial, To.Accepted, From.Accepted); + From.Mobile.Send(new UpdateSecureTrade(From.Container, From.Accepted, To.Accepted)); + To.Mobile.Send(new UpdateSecureTrade(To.Container, To.Accepted, From.Accepted)); return; } @@ -255,8 +282,8 @@ namespace Server } else if (!From.IsDisposed && !To.IsDisposed) { - Packets.SendUpdateSecureTrade(From.Mobile.NetState, From.Container.Serial, From.Accepted, To.Accepted); - Packets.SendUpdateSecureTrade(To.Mobile.NetState, To.Container.Serial, To.Accepted, From.Accepted); + From.Mobile.Send(new UpdateSecureTrade(From.Container, From.Accepted, To.Accepted)); + To.Mobile.Send(new UpdateSecureTrade(To.Container, To.Accepted, From.Accepted)); } } diff --git a/Projects/Server/Serial.cs b/Projects/Server/Serial.cs index 1b88958dd..b7d7678e9 100644 --- a/Projects/Server/Serial.cs +++ b/Projects/Server/Serial.cs @@ -35,7 +35,7 @@ namespace Server { get { - while (World.FindMobile(LastMobile += 1) != null) + while (World.FindMobile(LastMobile = LastMobile + 1) != null) { } @@ -47,7 +47,7 @@ namespace Server { get { - while (World.FindItem(LastItem += 1) != null) + while (World.FindItem(LastItem = LastItem + 1) != null) { } diff --git a/Projects/Server/Serialization.cs b/Projects/Server/Serialization.cs index 85545c962..106e9c731 100644 --- a/Projects/Server/Serialization.cs +++ b/Projects/Server/Serialization.cs @@ -24,6 +24,7 @@ using System.IO; using System.Net; using System.Text; using System.Threading; +using Server.Guilds; namespace Server { @@ -583,7 +584,10 @@ namespace Server public override void Write(BaseGuild value) { - Write(value?.Id ?? 0); + if (value == null) + Write(0); + else + Write(value.Id); } public override void WriteItem(T value) @@ -912,7 +916,10 @@ namespace Server public override IEntity ReadEntity() { Serial serial = ReadUInt(); - return World.FindEntity(serial) ?? new Entity(serial, new Point3D(0, 0, 0), Map.Internal); + IEntity entity = World.FindEntity(serial); + if (entity == null) + return new Entity(serial, new Point3D(0, 0, 0), Map.Internal); + return entity; } public override Item ReadItem() => World.FindItem(ReadUInt()); @@ -1363,7 +1370,10 @@ namespace Server public override void Write(BaseGuild value) { - Write(value?.Id ?? 0); + if (value == null) + Write(0); + else + Write(value.Id); } public override void WriteItem(T value) diff --git a/Projects/Server/Server.csproj b/Projects/Server/Server.csproj index 9af9d04e5..e7ce12400 100644 --- a/Projects/Server/Server.csproj +++ b/Projects/Server/Server.csproj @@ -37,10 +37,6 @@ ..\..\Distribution ..\..\Distribution 8.0 - DEBUG;TRACE - false - full - true diff --git a/Projects/Server/Skills.cs b/Projects/Server/Skills.cs index 94c9fb6b6..46eea944d 100644 --- a/Projects/Server/Skills.cs +++ b/Projects/Server/Skills.cs @@ -543,8 +543,10 @@ namespace Server } } else + { // Will be discarded new Skill(this, null, reader); + } //for ( int i = count; i < info.Length; ++i ) // m_Skills[i] = new Skill( this, info[i], 0, 1000, SkillLock.Up ); @@ -699,7 +701,7 @@ namespace Server m_Highest = skill; Owner.OnSkillInvalidated(skill); - Packets.SendSkillChange(Owner.NetState, skill); + Owner.NetState?.Send(new SkillChange(skill)); } #region Skill Getters & Setters @@ -880,4 +882,4 @@ namespace Server #endregion } -} +} \ No newline at end of file diff --git a/Projects/Server/Targeting/MultiTarget.cs b/Projects/Server/Targeting/MultiTarget.cs index 726a1f324..b0f7ac754 100644 --- a/Projects/Server/Targeting/MultiTarget.cs +++ b/Projects/Server/Targeting/MultiTarget.cs @@ -24,10 +24,10 @@ namespace Server.Targeting { public abstract class MultiTarget : Target { - protected MultiTarget(int multiId, Point3D offset, int range = 10, bool allowGround = true, TargetFlags flags = TargetFlags.None) + protected MultiTarget(int multiID, Point3D offset, int range = 10, bool allowGround = true, TargetFlags flags = TargetFlags.None) : base(range, allowGround, flags) { - MultiID = multiId; + MultiID = multiID; Offset = offset; } @@ -35,12 +35,11 @@ namespace Server.Targeting public Point3D Offset{ get; set; } - public override void Send(NetState ns) + public override Packet GetPacketFor(NetState ns) { if (ns.HighSeas) - Packets.SendMultiTargetReqHS(ns, this); - else - Packets.SendMultiTargetReq(ns, this); + return new MultiTargetReqHS(this); + return new MultiTargetReq(this); } } } diff --git a/Projects/Server/Targeting/Target.cs b/Projects/Server/Targeting/Target.cs index baa66cb17..72f595a95 100644 --- a/Projects/Server/Targeting/Target.cs +++ b/Projects/Server/Targeting/Target.cs @@ -25,13 +25,13 @@ namespace Server.Targeting { public abstract class Target { - private static int _nextTargetId; + private static int m_NextTargetID; private Timer m_TimeoutTimer; protected Target(int range, bool allowGround, TargetFlags flags) { - TargetID = ++_nextTargetId; + TargetID = ++m_NextTargetID; Range = range; AllowGround = allowGround; Flags = flags; @@ -57,7 +57,7 @@ namespace Server.Targeting public static void Cancel(Mobile m) { - Packets.SendCancelTarget(m.NetState); + m.NetState?.Send(CancelTarget.Instance); m.Target?.OnTargetCancel(m, TargetCancelType.Canceled); } diff --git a/Projects/Server/TileData.cs b/Projects/Server/TileData.cs index 637c8379d..ff97764af 100644 --- a/Projects/Server/TileData.cs +++ b/Projects/Server/TileData.cs @@ -316,10 +316,9 @@ namespace Server { bin.Read(m_StringBuffer, 0, 20); - int count = 0; - while (count < 20 && m_StringBuffer[count++] != 0) - { - } + int count; + + for (count = 0; count < 20 && m_StringBuffer[count] != 0; ++count) ; return Encoding.ASCII.GetString(m_StringBuffer, 0, count); } diff --git a/Projects/Server/TileMatrix.cs b/Projects/Server/TileMatrix.cs index 310b4f1ac..953da3dd7 100644 --- a/Projects/Server/TileMatrix.cs +++ b/Projects/Server/TileMatrix.cs @@ -191,7 +191,8 @@ namespace Server if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight) return; - m_StaticTiles[x] ??= new StaticTile[BlockHeight][][][]; + if (m_StaticTiles[x] == null) + m_StaticTiles[x] = new StaticTile[BlockHeight][][][]; m_StaticTiles[x][y] = value; @@ -207,7 +208,8 @@ namespace Server if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || DataStream == null || IndexStream == null) return EmptyStaticBlock; - m_StaticTiles[x] ??= new StaticTile[BlockHeight][][][]; + if (m_StaticTiles[x] == null) + m_StaticTiles[x] = new StaticTile[BlockHeight][][][]; StaticTile[][][] tiles = m_StaticTiles[x][y]; @@ -285,7 +287,9 @@ namespace Server if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight) return; - m_LandTiles[x] ??= new LandTile[BlockHeight][]; + if (m_LandTiles[x] == null) + m_LandTiles[x] = new LandTile[BlockHeight][]; + m_LandTiles[x][y] = value; if (m_LandPatches[x] == null) @@ -300,7 +304,8 @@ namespace Server if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || MapStream == null) return m_InvalidLandBlock; - m_LandTiles[x] ??= new LandTile[BlockHeight][]; + if (m_LandTiles[x] == null) + m_LandTiles[x] = new LandTile[BlockHeight][]; LandTile[] tiles = m_LandTiles[x][y]; @@ -384,7 +389,7 @@ namespace Server while (pCur < pEnd) { lists[pCur->m_X & 0x7][pCur->m_Y & 0x7].Add(pCur->m_ID, pCur->m_Z); - pCur += 1; + pCur = pCur + 1; } StaticTile[][][] tiles = new StaticTile[8][][]; @@ -464,13 +469,8 @@ namespace Server } } - public interface ITile - { - int ID { get; } - } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct LandTile : ITile + public struct LandTile { internal short m_ID; internal sbyte m_Z; @@ -501,7 +501,7 @@ namespace Server } [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct StaticTile : ITile + public struct StaticTile { internal ushort m_ID; internal byte m_X; diff --git a/Projects/Server/Timer.cs b/Projects/Server/Timer.cs index b2ece459b..9d37b32f5 100644 --- a/Projects/Server/Timer.cs +++ b/Projects/Server/Timer.cs @@ -87,7 +87,8 @@ namespace Server get => m_Priority; set { - m_PrioritySet |= !m_PrioritySet; + if (!m_PrioritySet) + m_PrioritySet = true; if (m_Priority != value) { @@ -195,13 +196,17 @@ namespace Server if (ts >= TimeSpan.FromSeconds(5.0)) return TimerPriority.TwoFiftyMS; - public static TimerPriority ComputePriority(TimeSpan ts) => - ts >= TimeSpan.FromMinutes(1.0) ? TimerPriority.FiveSeconds : - ts >= TimeSpan.FromSeconds(10.0) ? TimerPriority.OneSecond : - ts >= TimeSpan.FromSeconds(5.0) ? TimerPriority.TwoFiftyMS : - ts >= TimeSpan.FromSeconds(2.5) ? TimerPriority.FiftyMS : - ts >= TimeSpan.FromSeconds(1.0) ? TimerPriority.TwentyFiveMS : - ts >= TimeSpan.FromSeconds(0.5) ? TimerPriority.TenMS : TimerPriority.EveryTick; + if (ts >= TimeSpan.FromSeconds(2.5)) + return TimerPriority.FiftyMS; + + if (ts >= TimeSpan.FromSeconds(1.0)) + return TimerPriority.TwentyFiveMS; + + if (ts >= TimeSpan.FromSeconds(0.5)) + return TimerPriority.TenMS; + + return TimerPriority.EveryTick; + } public void Start() { @@ -235,11 +240,11 @@ namespace Server public class TimerThread { - private static readonly Dictionary m_Changed = new Dictionary(); + private static Dictionary m_Changed = new Dictionary(); - private static readonly long[] m_NextPriorities = new long[8]; + private static long[] m_NextPriorities = new long[8]; - private static readonly long[] m_PriorityDelays = { + private static long[] m_PriorityDelays = { 0, 10, 25, @@ -261,7 +266,7 @@ namespace Server new List() }; - private static readonly AutoResetEvent m_Signal = new AutoResetEvent(false); + private static AutoResetEvent m_Signal = new AutoResetEvent(false); public static void DumpInfo(TextWriter tw) { @@ -284,9 +289,14 @@ namespace Server list.Add(t); } - foreach (var (key, list) in hash) + foreach (KeyValuePair> kv in hash) + { + string key = kv.Key; + List list = kv.Value; + tw.WriteLine("Type: {0}; Count: {1}; Percent: {2}%", key, list.Count, (int)(100 * (list.Count / (double)m_Timers[i].Count))); + } tw.WriteLine(); tw.WriteLine(); @@ -296,7 +306,9 @@ namespace Server public static void Change(Timer t, int newIndex, bool isAdd) { lock (m_Changed) + { m_Changed[t] = TimerChangeEntry.GetInstance(t, newIndex, isAdd); + } m_Signal.Set(); } diff --git a/Projects/Server/Utility.cs b/Projects/Server/Utility.cs index 4041a5e1c..d4c4a1b70 100644 --- a/Projects/Server/Utility.cs +++ b/Projects/Server/Utility.cs @@ -22,7 +22,6 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; @@ -119,8 +118,8 @@ namespace Server private static Stack m_ConsoleColors = new Stack(); - public static Encoding UTF8 => m_UTF8 ??= new UTF8Encoding(false, false); - public static Encoding UTF8WithEncoding => m_UTF8WithEncoding ??= new UTF8Encoding(true, false); + public static Encoding UTF8 => m_UTF8 ?? (m_UTF8 = new UTF8Encoding(false, false)); + public static Encoding UTF8WithEncoding => m_UTF8WithEncoding ?? (m_UTF8WithEncoding = new UTF8Encoding(true, false)); public static void Separate(StringBuilder sb, string value, string separator) { @@ -139,7 +138,8 @@ namespace Server public static IPAddress Intern(IPAddress ipAddress) { - _ipAddressTable ??= new Dictionary(); + if (_ipAddressTable == null) + _ipAddressTable = new Dictionary(); if (!_ipAddressTable.TryGetValue(ipAddress, out IPAddress interned)) { @@ -518,15 +518,79 @@ namespace Server int adx = Math.Abs(dx); int ady = Math.Abs(dy); - if (adx >= ady * 3) return dx > 0 ? Direction.East : Direction.West; + if (adx >= ady * 3) + { + if (dx > 0) + return Direction.East; + return Direction.West; + } - if (ady >= adx * 3) return dy > 0 ? Direction.South : Direction.North; + if (ady >= adx * 3) + { + if (dy > 0) + return Direction.South; + return Direction.North; + } - if (dx > 0) return dy > 0 ? Direction.Down : Direction.Right; + if (dx > 0) + { + if (dy > 0) + return Direction.Down; + return Direction.Right; + } return dy > 0 ? Direction.Left : Direction.Up; } + /* Should probably be rewritten to use an ITile interface + + public static bool CanMobileFit( int z, StaticTile[] tiles ) + { + int checkHeight = 15; + int checkZ = z; + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + if ( ((checkZ + checkHeight) > tile.Z && checkZ < (tile.Z + tile.Height))*/ + /* || (tile.Z < (checkZ + checkHeight) && (tile.Z + tile.Height) > checkZ)*/ /* ) + { + return false; + } + else if ( checkHeight == 0 && tile.Height == 0 && checkZ == tile.Z ) + { + return false; + } + } + + return true; + } + + public static bool IsInContact( StaticTile check, StaticTile[] tiles ) + { + int checkHeight = check.Height; + int checkZ = check.Z; + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + if ( ((checkZ + checkHeight) > tile.Z && checkZ < (tile.Z + tile.Height))*/ + /* || (tile.Z < (checkZ + checkHeight) && (tile.Z + tile.Height) > checkZ)*/ /* ) + { + return true; + } + else if ( checkHeight == 0 && tile.Height == 0 && checkZ == tile.Z ) + { + return true; + } + } + + return false; + } + */ + public static object GetArrayCap(Array array, int index, object emptyValue = null) { if (array.Length > 0) @@ -729,7 +793,14 @@ namespace Server public static List SafeConvertList(List list) where TOutput : class { List output = new List(list.Capacity); - output.AddRange(list.OfType()); + + for (int i = 0; i < list.Count; i++) + { + TOutput t = list[i] as TOutput; + + if (t != null) + output.Add(t); + } return output; } @@ -960,8 +1031,6 @@ namespace Server public static double RandomDouble() => RandomImpl.NextDouble(); - public static double RandomDouble() => RandomImpl.NextDouble(); - #endregion #region Random Hues diff --git a/Projects/Server/VirtueInfo.cs b/Projects/Server/VirtueInfo.cs index 1b6130197..833e03071 100644 --- a/Projects/Server/VirtueInfo.cs +++ b/Projects/Server/VirtueInfo.cs @@ -130,7 +130,8 @@ namespace Server public void SetValue(int index, int value) { - Values ??= new int[8]; + if (Values == null) + Values = new int[8]; Values[index] = value; } @@ -161,4 +162,4 @@ namespace Server } } } -} +} \ No newline at end of file diff --git a/Projects/Server/World.cs b/Projects/Server/World.cs index 911d1f8cc..9f4f67b98 100644 --- a/Projects/Server/World.cs +++ b/Projects/Server/World.cs @@ -24,14 +24,14 @@ using System.Diagnostics; using System.IO; using System.Reflection; using System.Threading; +using Server.Guilds; using Server.Network; -using Server.Persistence; namespace Server { public static class World { - private static readonly ManualResetEvent m_DiskWriteHandle = new ManualResetEvent(true); + private static ManualResetEvent m_DiskWriteHandle = new ManualResetEvent(true); private static Queue _addQueue, _deleteQueue; @@ -91,19 +91,22 @@ namespace Server public static void Broadcast(int hue, bool ascii, string text) { + Packet p; + + if (ascii) + p = new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, 3, "System", text); + else + p = new UnicodeMessage(Serial.MinusOne, -1, MessageType.Regular, hue, 3, "ENU", "System", text); + List list = NetState.Instances; - for (int i = 0; i < list.Count; ++i) - { - NetState state = list[i]; - if (state == null) - continue; + p.Acquire(); - if (ascii) - Packets.SendAsciiMessage(state, Serial.MinusOne, -1, MessageType.Regular, hue, 3, "System", text); - else - Packets.SendUnicodeMessage(state, Serial.MinusOne, -1, MessageType.Regular, hue, 3, "ENU", "System", text); - } + for (int i = 0; i < list.Count; ++i) + if (list[i].Mobile != null) + list[i].Send(p); + + p.Release(); } public static void Broadcast(int hue, bool ascii, string format, params object[] args) @@ -176,6 +179,8 @@ namespace Server _addQueue = new Queue(); _deleteQueue = new Queue(); + int mobileCount, itemCount, guildCount; + object[] ctorArgs = new object[1]; List items = new List(); @@ -569,7 +574,7 @@ namespace Server } } - private static void SaveIndex(IReadOnlyList list, string path) where T : IEntityEntry + private static void SaveIndex(List list, string path) where T : IEntityEntry { if (!Directory.Exists("Saves/Mobiles/")) Directory.CreateDirectory("Saves/Mobiles/"); @@ -598,10 +603,12 @@ namespace Server idxWriter.Close(); } - idxWriter.Close(); + public static void Save() + { + Save(true, false); } - public static void Save(bool message = true, bool permitBackgroundWrite = false) + public static void Save(bool message, bool permitBackgroundWrite) { if (Saving) return; @@ -665,7 +672,15 @@ namespace Server NetState.Resume(); } - public static IEntity FindEntity(Serial serial) => serial.IsItem ? (IEntity)FindItem(serial) : serial.IsMobile ? FindMobile(serial) : null; + public static IEntity FindEntity(Serial serial) + { + if (serial.IsItem) + return FindItem(serial); + if (serial.IsMobile) + return FindMobile(serial); + + return null; + } public static Mobile FindMobile(Serial serial) {