From c50322c0e3e1104cdac9fb04a445da25a507feb8 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 15 Mar 2021 16:18:28 -0700 Subject: [PATCH] fix(network): Adds UOG & Fixes ConnectUO packet (#552) - [X] Adds UOG Extended and Compact (0xF1 0x51 packet) - [X] Fixes ConnectUO bad length --- Projects/Server/Buffers/ValueStringBuilder.cs | 2 +- Projects/Server/Maps/Map.cs | 2 +- Projects/Server/Mobiles/Mobile.cs | 4 +- Projects/Server/Utilities/Utility.cs | 61 ++++++++++- .../Commands/Object Creation/Decorate.cs | 2 +- .../Commands/Object Creation/DecorateMag.cs | 2 +- Projects/UOContent/Engines/Harvest/Mining.cs | 2 +- .../UOContent/Engines/Pathing/FastMovement.cs | 6 +- .../UOContent/Engines/Pathing/Movement.cs | 6 +- .../UOContent/Engines/Pathing/PathFollower.cs | 2 +- .../Engines/Pathing/SlowAStarAlgorithm.cs | 2 +- .../Treasures of Tokuno/TreasuresOfTokuno.cs | 2 +- .../Items/Construction/Doors/HouseDoors.cs | 2 +- Projects/UOContent/Items/Misc/Guillotine.cs | 2 +- .../Items/Skill Items/Tools/BaseRunicTool.cs | 2 +- .../Items/Special/Veteran Rewards/Cannon.cs | 8 +- Projects/UOContent/Misc/Geometry.cs | 4 +- Projects/UOContent/Mobiles/Special/Paragon.cs | 2 +- Projects/UOContent/Multis/Boats/BaseBoat.cs | 8 +- Projects/UOContent/Multis/Houses/BaseHouse.cs | 2 +- Projects/UOContent/Network/ConnectUO.cs | 2 +- Projects/UOContent/Network/UOGateway.cs | 103 ++++++++++++++++++ Projects/UOContent/Skills/Discordance.cs | 2 +- .../UOContent/Spells/Fifth/PoisonField.cs | 2 +- Projects/UOContent/Spells/Fourth/FireField.cs | 2 +- 25 files changed, 196 insertions(+), 38 deletions(-) create mode 100644 Projects/UOContent/Network/UOGateway.cs diff --git a/Projects/Server/Buffers/ValueStringBuilder.cs b/Projects/Server/Buffers/ValueStringBuilder.cs index 8d990016a..cb826487d 100644 --- a/Projects/Server/Buffers/ValueStringBuilder.cs +++ b/Projects/Server/Buffers/ValueStringBuilder.cs @@ -193,7 +193,7 @@ namespace Server.Buffers [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void Append(uint value) { - int bufferLength = Utility.CountDigits(value); + int bufferLength = value.CountDigits(); int pos = _length; if ((uint)pos + (uint)bufferLength >= _chars.Length) diff --git a/Projects/Server/Maps/Map.cs b/Projects/Server/Maps/Map.cs index 00dda91e8..31d7c58c6 100644 --- a/Projects/Server/Maps/Map.cs +++ b/Projects/Server/Maps/Map.cs @@ -478,7 +478,7 @@ namespace Server top = zBottom; } - avg = Math.Abs(zTop - zBottom) > Math.Abs(zLeft - zRight) + avg = (zTop - zBottom).Abs() > (zLeft - zRight).Abs() ? FloorAverage(zLeft, zRight) : FloorAverage(zTop, zBottom); } diff --git a/Projects/Server/Mobiles/Mobile.cs b/Projects/Server/Mobiles/Mobile.cs index 2eda04241..ef8b17f93 100644 --- a/Projects/Server/Mobiles/Mobile.cs +++ b/Projects/Server/Mobiles/Mobile.cs @@ -9086,8 +9086,8 @@ namespace Server var rx = (dx - dy) * 44; var ry = (dx + dy) * 44; - var ax = Math.Abs(rx); - var ay = Math.Abs(ry); + var ax = rx.Abs(); + var ay = ry.Abs(); Direction ret; diff --git a/Projects/Server/Utilities/Utility.cs b/Projects/Server/Utilities/Utility.cs index 3a0e2eee5..b1e908e47 100644 --- a/Projects/Server/Utilities/Utility.cs +++ b/Projects/Server/Utilities/Utility.cs @@ -577,8 +577,8 @@ namespace Server var dx = to.X - from.X; var dy = to.Y - from.Y; - var adx = Math.Abs(dx); - var ady = Math.Abs(dy); + var adx = Abs(dx); + var ady = Abs(dy); if (adx >= ady * 3) { @@ -1395,7 +1395,21 @@ namespace Server } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CountDigits(uint value) + public static int Abs(this int value) + { + int mask = value >> 31; + return (value + mask) ^ mask; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long Abs(this long value) + { + long mask = value >> 63; + return (value + mask) ^ mask; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CountDigits(this uint value) { int digits = 1; if (value >= 100000) @@ -1428,6 +1442,47 @@ namespace Server return digits; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CountDigits(this int value) + { + int absValue = Abs(value); + + int digits = 1; + if (absValue >= 100000) + { + absValue /= 100000; + digits += 5; + } + + if (absValue < 10) + { + // no-op + } + else if (absValue < 100) + { + digits++; + } + else if (absValue < 1000) + { + digits += 2; + } + else if (absValue < 10000) + { + digits += 3; + } + else + { + digits += 4; + } + + if (value < 0) + { + digits += 1; // negative + } + + return digits; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DivRem(uint a, uint b, out uint result) { diff --git a/Projects/UOContent/Commands/Object Creation/Decorate.cs b/Projects/UOContent/Commands/Object Creation/Decorate.cs index 4a99370e9..7f1a8a569 100644 --- a/Projects/UOContent/Commands/Object Creation/Decorate.cs +++ b/Projects/UOContent/Commands/Object Creation/Decorate.cs @@ -1072,7 +1072,7 @@ namespace Server.Commands { res = true; } - else if (Math.Abs(item.Z - z) < 8) + else if ((item.Z - z).Abs() < 8) { m_DeleteQueue.Enqueue(item); } diff --git a/Projects/UOContent/Commands/Object Creation/DecorateMag.cs b/Projects/UOContent/Commands/Object Creation/DecorateMag.cs index 330d296a0..bc9bab697 100644 --- a/Projects/UOContent/Commands/Object Creation/DecorateMag.cs +++ b/Projects/UOContent/Commands/Object Creation/DecorateMag.cs @@ -1069,7 +1069,7 @@ namespace Server.Commands { res = true; } - else if (Math.Abs(item.Z - z) < 8) + else if ((item.Z - z).Abs() < 8) { m_DeleteQueue.Enqueue(item); } diff --git a/Projects/UOContent/Engines/Harvest/Mining.cs b/Projects/UOContent/Engines/Harvest/Mining.cs index 843a716fb..ea721a5c1 100644 --- a/Projects/UOContent/Engines/Harvest/Mining.cs +++ b/Projects/UOContent/Engines/Harvest/Mining.cs @@ -414,7 +414,7 @@ namespace Server.Engines.Harvest var z = map.GetAverageZ(x, y); - if (Math.Abs(z - from.Z) < 10 && map.CanSpawnMobile(x, y, z)) + if ((z - from.Z).Abs() < 10 && map.CanSpawnMobile(x, y, z)) { spawned.OnBeforeSpawn(new Point3D(x, y, z), map); spawned.MoveToWorld(new Point3D(x, y, z), map); diff --git a/Projects/UOContent/Engines/Pathing/FastMovement.cs b/Projects/UOContent/Engines/Pathing/FastMovement.cs index 6eef714b8..d753f1941 100644 --- a/Projects/UOContent/Engines/Pathing/FastMovement.cs +++ b/Projects/UOContent/Engines/Pathing/FastMovement.cs @@ -297,7 +297,7 @@ namespace Server.Movement if (moveIsOk) { - var cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); + var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs(); if (cmp > 0 || cmp == 0 && ourZ > newZ) { @@ -379,7 +379,7 @@ namespace Server.Movement if (moveIsOk) { - var cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); + var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs(); if (cmp > 0 || cmp == 0 && ourZ > newZ) { @@ -445,7 +445,7 @@ namespace Server.Movement if (moveIsOk) { - var cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); + var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs(); if (cmp > 0 || cmp == 0 && ourZ > newZ) { diff --git a/Projects/UOContent/Engines/Pathing/Movement.cs b/Projects/UOContent/Engines/Pathing/Movement.cs index c3c8ca0cb..6fda9fc22 100644 --- a/Projects/UOContent/Engines/Pathing/Movement.cs +++ b/Projects/UOContent/Engines/Pathing/Movement.cs @@ -464,7 +464,7 @@ namespace Server.Movement if (moveIsOk) { - var cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); + var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs(); if (cmp > 0 || cmp == 0 && ourZ > newZ) { @@ -532,7 +532,7 @@ namespace Server.Movement if (moveIsOk) { - var cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); + var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs(); if (cmp > 0 || cmp == 0 && ourZ > newZ) { @@ -591,7 +591,7 @@ namespace Server.Movement if (moveIsOk) { - var cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); + var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs(); if (cmp > 0 || cmp == 0 && ourZ > newZ) { diff --git a/Projects/UOContent/Engines/Pathing/PathFollower.cs b/Projects/UOContent/Engines/Pathing/PathFollower.cs index ecacdfd71..2596f1dad 100644 --- a/Projects/UOContent/Engines/Pathing/PathFollower.cs +++ b/Projects/UOContent/Engines/Pathing/PathFollower.cs @@ -86,7 +86,7 @@ namespace Server } public static bool Check(Point3D loc, Point3D goal, int range) => - Utility.InRange(loc, goal, range) && (range > 1 || Math.Abs(loc.Z - goal.Z) < 16); + Utility.InRange(loc, goal, range) && (range > 1 || (loc.Z - goal.Z).Abs() < 16); public bool Follow(bool run, int range) { diff --git a/Projects/UOContent/Engines/Pathing/SlowAStarAlgorithm.cs b/Projects/UOContent/Engines/Pathing/SlowAStarAlgorithm.cs index 53ae6b473..6299b1863 100644 --- a/Projects/UOContent/Engines/Pathing/SlowAStarAlgorithm.cs +++ b/Projects/UOContent/Engines/Pathing/SlowAStarAlgorithm.cs @@ -86,7 +86,7 @@ namespace Server.PathAlgorithms.SlowAStar } } - if (curNode.x == goalNode.x && curNode.y == goalNode.y && Math.Abs(curNode.z - goalNode.z) < 16) + if (curNode.x == goalNode.x && curNode.y == goalNode.y && (curNode.z - goalNode.z).Abs() < 16) { if (closedCount == MaxNodes) { diff --git a/Projects/UOContent/Engines/Treasures of Tokuno/TreasuresOfTokuno.cs b/Projects/UOContent/Engines/Treasures of Tokuno/TreasuresOfTokuno.cs index f6e985ef1..65b6efec3 100644 --- a/Projects/UOContent/Engines/Treasures of Tokuno/TreasuresOfTokuno.cs +++ b/Projects/UOContent/Engines/Treasures of Tokuno/TreasuresOfTokuno.cs @@ -265,7 +265,7 @@ namespace Server.Mobiles { var range = 3; - if (pm.Alive && Math.Abs(Z - pm.Z) < 16 && InRange(m, range) && !InRange(oldLocation, range)) + if (pm.Alive && (Z - pm.Z).Abs() < 16 && InRange(m, range) && !InRange(oldLocation, range)) { if (pm.ToTItemsTurnedIn >= TreasuresOfTokuno.ItemsPerReward) { diff --git a/Projects/UOContent/Items/Construction/Doors/HouseDoors.cs b/Projects/UOContent/Items/Construction/Doors/HouseDoors.cs index de68dee7b..88bbfed4a 100644 --- a/Projects/UOContent/Items/Construction/Doors/HouseDoors.cs +++ b/Projects/UOContent/Items/Construction/Doors/HouseDoors.cs @@ -284,7 +284,7 @@ namespace Server.Items var rx = from.X - X; var ry = from.Y - Y; - var az = Math.Abs(from.Z - Z); + var az = (from.Z - Z).Abs(); return rx >= x && rx < x + w && ry >= y && ry < y + h && az <= 4; } diff --git a/Projects/UOContent/Items/Misc/Guillotine.cs b/Projects/UOContent/Items/Misc/Guillotine.cs index c98a41e64..ab08c3c91 100644 --- a/Projects/UOContent/Items/Misc/Guillotine.cs +++ b/Projects/UOContent/Items/Misc/Guillotine.cs @@ -28,7 +28,7 @@ namespace Server.Items { var p = GetWorldLocation(); - if (Utility.Random(Math.Max(Math.Abs(from.X - p.X), Math.Abs(from.Y - p.Y))) < 1) + if (Utility.Random(Math.Max((from.X - p.X).Abs(), (from.Y - p.Y).Abs())) < 1) { Effects.PlaySound(from.Location, from.Map, from.GetHurtSound()); from.PublicOverheadMessage(MessageType.Regular, from.SpeechHue, true, "Ouch!"); diff --git a/Projects/UOContent/Items/Skill Items/Tools/BaseRunicTool.cs b/Projects/UOContent/Items/Skill Items/Tools/BaseRunicTool.cs index 3e500fe79..1bd5e4495 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/BaseRunicTool.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/BaseRunicTool.cs @@ -132,7 +132,7 @@ namespace Server.Items percent = v; } - percent *= 10000 + 10000 / (Math.Abs(high - low) + 1); + percent *= 10000 + 10000 / ((high - low).Abs() + 1); return low + (high - low) * percent / 1000001; } diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs b/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs index d89063b0a..e8835985b 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs @@ -291,28 +291,28 @@ namespace Server.Items switch (m_Cannon.CannonDirection) { case CannonDirection.North: - if (y < 0 && Math.Abs(x) <= -y / 3) + if (y < 0 && x.Abs() <= -y / 3) { allow = true; } break; case CannonDirection.East: - if (x > 0 && Math.Abs(y) <= x / 3) + if (x > 0 && y.Abs() <= x / 3) { allow = true; } break; case CannonDirection.South: - if (y > 0 && Math.Abs(x) <= y / 3) + if (y > 0 && x.Abs() <= y / 3) { allow = true; } break; case CannonDirection.West: - if (x < 0 && Math.Abs(y) <= -x / 3) + if (x < 0 && y.Abs() <= -x / 3) { allow = true; } diff --git a/Projects/UOContent/Misc/Geometry.cs b/Projects/UOContent/Misc/Geometry.cs index a99e52f0a..5af881d2b 100644 --- a/Projects/UOContent/Misc/Geometry.cs +++ b/Projects/UOContent/Misc/Geometry.cs @@ -192,7 +192,7 @@ namespace Server.Misc public static void Line2D(Point3D start, Point3D end, Map map, DoEffect_Callback effect) { - var steep = Math.Abs(end.Y - start.Y) > Math.Abs(end.X - start.X); + var steep = (end.Y - start.Y).Abs() > (end.X - start.X).Abs(); var x0 = start.X; var x1 = end.X; @@ -212,7 +212,7 @@ namespace Server.Misc } var deltax = x1 - x0; - var deltay = Math.Abs(y1 - y0); + var deltay = (y1 - y0).Abs(); var error = deltax / 2; var ystep = y0 < y1 ? 1 : -1; var y = y0; diff --git a/Projects/UOContent/Mobiles/Special/Paragon.cs b/Projects/UOContent/Mobiles/Special/Paragon.cs index 2942ead6a..13b5a0c6a 100644 --- a/Projects/UOContent/Mobiles/Special/Paragon.cs +++ b/Projects/UOContent/Mobiles/Special/Paragon.cs @@ -101,7 +101,7 @@ namespace Server.Mobiles { bc.Karma = (int)(bc.Karma * KarmaBuff); - if (Math.Abs(bc.Karma) > 32000) + if (bc.Karma.Abs() > 32000) { bc.Karma = 32000 * Math.Sign(bc.Karma); } diff --git a/Projects/UOContent/Multis/Boats/BaseBoat.cs b/Projects/UOContent/Multis/Boats/BaseBoat.cs index 9421dba90..ee62f9a26 100644 --- a/Projects/UOContent/Multis/Boats/BaseBoat.cs +++ b/Projects/UOContent/Multis/Boats/BaseBoat.cs @@ -1518,8 +1518,8 @@ namespace Server.Multis var dx = x - X; var dy = y - Y; - var adx = Math.Abs(dx); - var ady = Math.Abs(dy); + var adx = dx.Abs(); + var ady = dy.Abs(); var dir = Utility.GetDirection(this, new Point2D(x, y)); var iDir = (int)dir; @@ -1527,7 +1527,7 @@ namespace Server.Multis // Compute the maximum distance we can travel without going too far away if (iDir % 2 == 0) // North, East, South and West { - maxSpeed = Math.Abs(adx - ady); + maxSpeed = (adx - ady).Abs(); } else // Right, Down, Left and Up { @@ -1732,7 +1732,7 @@ namespace Server.Multis } } - if (!NewBoatMovement || Math.Abs(xOffset) > 1 || Math.Abs(yOffset) > 1) + if (!NewBoatMovement || xOffset.Abs() > 1 || yOffset.Abs() > 1) { Teleport(xOffset, yOffset, 0); } diff --git a/Projects/UOContent/Multis/Houses/BaseHouse.cs b/Projects/UOContent/Multis/Houses/BaseHouse.cs index ad5469b99..da4ebce2d 100644 --- a/Projects/UOContent/Multis/Houses/BaseHouse.cs +++ b/Projects/UOContent/Multis/Houses/BaseHouse.cs @@ -744,7 +744,7 @@ namespace Server.Multis foreach (var entity in eable) { - if (Math.Abs(location.Z - entity.Z) <= 16) + if ((location.Z - entity.Z).Abs() <= 16) { if (entity is PlayerVendor || entity is PlayerBarkeeper || entity is PlayerVendorPlaceholder) { diff --git a/Projects/UOContent/Network/ConnectUO.cs b/Projects/UOContent/Network/ConnectUO.cs index 96c3766a0..93b7a1091 100644 --- a/Projects/UOContent/Network/ConnectUO.cs +++ b/Projects/UOContent/Network/ConnectUO.cs @@ -109,7 +109,7 @@ namespace Server.Network var writer = new SpanWriter(stackalloc byte[15]); writer.Write((byte)0xC0); // Packet ID - writer.Write(17); // Length + writer.Write((ushort)17); // Length writer.Write(ConnectUOProtocolVersion); // Version writer.Write((byte)_serverType); writer.Write((int)(Core.TickCount / 1000)); diff --git a/Projects/UOContent/Network/UOGateway.cs b/Projects/UOContent/Network/UOGateway.cs new file mode 100644 index 000000000..6e1d0cd51 --- /dev/null +++ b/Projects/UOContent/Network/UOGateway.cs @@ -0,0 +1,103 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019-2021 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: UOGateway.cs * + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Buffers; +using System.Text; +using Server.Misc; +using Server.Text; + +namespace Server.Network +{ + public static class UOGateway + { + public static void Configure() + { + var enabled = ServerConfiguration.GetOrUpdateSetting("uogateway.enabled", true); + + if (enabled) + { + FreeshardProtocol.Register(0xFE, false, QueryCompactShardStats); + FreeshardProtocol.Register(0xFF, false, QueryExtendedShardStats); + } + } + + public static void QueryCompactShardStats(NetState ns, CircularBufferReader reader, ref int packetLength) + { + ns.SendCompactShardStats( + (uint)(Core.TickCount / 1000), + TcpServer.Instances.Count, + World.Items.Count, + World.Mobiles.Count, + GC.GetTotalMemory(false) + ); + } + + public static void QueryExtendedShardStats(NetState ns, CircularBufferReader reader, ref int packetLength) + { + const long ticksInHour = 1000 * 60 * 60; + ns.SendExtendedShardStats( + ServerList.ServerName, + (int)(Core.TickCount / ticksInHour), + TcpServer.Instances.Count, + World.Items.Count, + World.Mobiles.Count, + (int)(GC.GetTotalMemory(false) / 1024) + ); + } + + public static void SendCompactShardStats( + this NetState ns, uint age, int clients, int items, int mobiles, long mem + ) + { + if (ns == null) + { + return; + } + + var writer = new SpanWriter(stackalloc byte[27]); + writer.Write((byte)0x51); // Packet ID + writer.Write((ushort)27); // Length + writer.Write(clients); + writer.Write(items); + writer.Write(mobiles); + writer.Write(age); + writer.Write(mem); + + ns.Send(writer.Span); + } + + public static void SendExtendedShardStats( + this NetState ns, string name, int age, int clients, int items, int mobiles, int mem + ) + { + if (ns == null) + { + return; + } + + var str = + $"ModernUO, Name={name}, Age={age}, Clients={clients}, Items={items}, Chars={mobiles}, Mem={mem}, Ver=2"; + + var length = Encoding.UTF8.GetMaxByteCount(str.Length); + + Span span = stackalloc byte[length + 1]; + Encoding.UTF8.GetBytes(str, span); + span[^1] = 0; // Terminator + + ns.Send(span); + } + } +} diff --git a/Projects/UOContent/Skills/Discordance.cs b/Projects/UOContent/Skills/Discordance.cs index e666a0356..1b00dc94c 100644 --- a/Projects/UOContent/Skills/Discordance.cs +++ b/Projects/UOContent/Skills/Discordance.cs @@ -288,7 +288,7 @@ namespace Server.SkillHandlers } } - var info = new DiscordanceInfo(from, targ, Math.Abs(effect), mods); + var info = new DiscordanceInfo(from, targ, effect.Abs(), mods); info.m_Timer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromSeconds(1.25), diff --git a/Projects/UOContent/Spells/Fifth/PoisonField.cs b/Projects/UOContent/Spells/Fifth/PoisonField.cs index edcf30ee8..29bbb7509 100644 --- a/Projects/UOContent/Spells/Fifth/PoisonField.cs +++ b/Projects/UOContent/Spells/Fifth/PoisonField.cs @@ -105,7 +105,7 @@ namespace Server.Spells.Fifth m_End = Core.Now + duration; - m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(Math.Abs(val) * 0.2), caster.InLOS(this), canFit); + m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(val.Abs() * 0.2), caster.InLOS(this), canFit); m_Timer.Start(); } diff --git a/Projects/UOContent/Spells/Fourth/FireField.cs b/Projects/UOContent/Spells/Fourth/FireField.cs index ff8c3c754..0889ed104 100644 --- a/Projects/UOContent/Spells/Fourth/FireField.cs +++ b/Projects/UOContent/Spells/Fourth/FireField.cs @@ -120,7 +120,7 @@ namespace Server.Spells.Fourth m_End = Core.Now + duration; - m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(Math.Abs(val) * 0.2), caster.InLOS(this), canFit); + m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(val.Abs() * 0.2), caster.InLOS(this), canFit); m_Timer.Start(); }