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(); // Time period to lock NPCs into idling public static int MinIdleSeconds { get; private set; } public static int MaxIdleSeconds { get; private set; } // Null when the table is unloaded (test fixtures). Immutable after Configure, so creatures cache it. public static SpeedClassEntry FindEntry(BaseCreature bc) { if ((bc.SpeedClass == SpeedLevel.None || !_speedsByLevel.TryGetValue(bc.SpeedClass, out var sp)) && !_speedsByType.TryGetValue(bc.GetType(), out sp)) { _speedsByLevel.TryGetValue(SpeedLevel.Medium, out sp); } return sp; } public static void RegisterSpeed(SpeedClassEntry entry) { _speedsByLevel[entry.Level] = entry; foreach (var type in entry.Types) { _speedsByType[type] = entry; } } public static void Configure() { 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; } // Movement clock (seconds per step); absent/0 = inherit the matching think value. [JsonPropertyName("activeMove")] public double ActiveMoveSpeed { get; init; } [JsonPropertyName("passiveMove")] public double PassiveMoveSpeed { get; init; } [JsonPropertyName("types")] public HashSet Types { get; init; } } }