using System; using System.Collections.Generic; using System.IO; using System.Text.Json.Serialization; using Server.Json; namespace Server.Mobiles; public enum SpeedLevel { None, VerySlow, Slow, Medium, Fast, VeryFast } public static class NPCSpeeds { private const string _tablePath = "Data/npc-speeds.json"; private static readonly Dictionary _speedsByType = new(); private static readonly Dictionary _speedsByLevel = new(); // Enabled for pets on HS+ public static bool ScaleSpeedByDex { get; private set; } public static double MinDelay { get; private set; } public static double MaxDelay { get; private set; } public static int MinDex { get; private set; } public static int MaxDex { get; private set; } // Time period to lock NPCs into idling public static int MinIdleSeconds { get; private set; } public static int MaxIdleSeconds { get; private set; } public static void GetSpeeds(BaseCreature bc, out double activeSpeed, out double passiveSpeed) { // Used for scaling pet's speed by dex in HS+ if (bc.ScaleSpeedByDex) { var maxDex = MaxDex; double min = MinDelay; double max = MaxDelay; var dex = Math.Clamp(bc.Dex, MinDex, maxDex); activeSpeed = Math.Max(max - (max - min) * ((double)dex / maxDex), min); passiveSpeed = activeSpeed * 2; return; } if ((bc.SpeedClass == SpeedLevel.None || !_speedsByLevel.TryGetValue(bc.SpeedClass, out var sp)) && !_speedsByType.TryGetValue(bc.GetType(), out sp)) { sp = _speedsByLevel[SpeedLevel.Medium]; } activeSpeed = sp.ActiveSpeed; passiveSpeed = sp.PassiveSpeed; } public static void RegisterSpeed(SpeedClassEntry entry) { _speedsByLevel[entry.Level] = entry; foreach (var type in entry.Types) { _speedsByType[type] = entry; } } public static void Configure() { ScaleSpeedByDex = ServerConfiguration.GetSetting("movement.delay.scaleSpeedByDex", Core.HS); MinDelay = ServerConfiguration.GetSetting("movement.delay.npcMinDelay", 0.1); MaxDelay = ServerConfiguration.GetSetting("movement.delay.npcMaxDelay", 0.4); MaxDex = ServerConfiguration.GetSetting("movement.delay.npcMinDex", 50); MaxDex = ServerConfiguration.GetSetting("movement.delay.npcMaxDex", 200); MinIdleSeconds = ServerConfiguration.GetSetting("movement.delay.npcMinIdle", 15); MaxIdleSeconds = ServerConfiguration.GetSetting("movement.delay.npcMaxIdle", 25); var path = Path.Combine(Core.BaseDirectory, _tablePath); if (!File.Exists(path)) { return; } var speeds = JsonConfig.Deserialize(path); for (var i = 0; i < speeds.Length; i++) { RegisterSpeed(speeds[i]); } } public record SpeedClassEntry { [JsonPropertyName("level")] public SpeedLevel Level { get; init; } [JsonPropertyName("active")] public double ActiveSpeed { get; init; } [JsonPropertyName("passive")] public double PassiveSpeed { get; init; } [JsonPropertyName("types")] public HashSet Types { get; init; } } }