using System.Collections.Generic; namespace IdleSpectator; /// /// Fact-preserving multi-variant activity lines (anti-stale dossier feed). /// public static class ActivityProse { private static readonly Dictionary Variants = new Dictionary { ["fighting"] = new[] { "Locked in combat", "Trading blows", "In the fray", "Clash of steel" }, ["fight"] = new[] { "Locked in combat", "Trading blows", "In the fray" }, ["attack"] = new[] { "Strikes at {target}", "Presses the attack on {target}", "Lunges toward {target}" }, ["hunt"] = new[] { "Hunts {target}", "Stalks {target}", "On the trail of {target}" }, ["eating"] = new[] { "Taking a meal", "Eating", "Breaking hunger" }, ["eat"] = new[] { "Taking a meal", "Eating", "Breaking hunger" }, ["sleep"] = new[] { "Sleeping", "Resting", "Deep in slumber" }, ["random_move"] = new[] { "Wandering", "Roaming aimlessly", "Drifting along" }, ["pollinate"] = new[] { "Dusts the blossom", "Works the flower", "Leaves pollen behind", "Humming over petals" }, ["farm"] = new[] { "Tends the fields", "Works the soil", "Farming the plot" }, ["harvest"] = new[] { "Harvests the crop", "Gathers the yield", "Cuts the ripe fields" }, ["mine"] = new[] { "Delves the mine", "Chipping ore", "Deep in the dig" }, ["build"] = new[] { "Building", "Raising walls", "At the worksite" }, ["gather"] = new[] { "Gathering stores", "Foraging supplies", "Collecting goods" }, ["woodcut"] = new[] { "Felling timber", "Cutting wood", "Axe to the trees" }, ["fire"] = new[] { "Fighting the blaze", "Dousing flames", "Racing the fire" }, ["fireman"] = new[] { "Fighting the blaze", "Dousing flames", "Racing the fire" }, ["social"] = new[] { "Socializing", "In conversation", "Among companions" }, ["lover"] = new[] { "Seeking a lover", "Drawn to {target}", "Heart on the path" }, ["unload"] = new[] { "Unloads goods in town", "Delivers the haul", "Empties the pack at home" }, ["store"] = new[] { "Stores supplies", "Stocking the village", "Puts goods away" }, ["fish"] = new[] { "Fishing", "Casting for fish", "Working the waters" }, ["trade"] = new[] { "Trading", "Bartering goods", "On a trade run" }, ["run_away"] = new[] { "Fleeing", "Running for safety", "In retreat" }, ["make_decision"] = new[] { "Considering next steps", "Weighing a choice", "Paused in thought" }, ["wait"] = new[] { "Waiting", "Holding still", "Biding time" }, ["BehPollinate"] = new[] { "Dusts the blossom", "Works the flower", "Leaves pollen behind" }, ["BehUnloadResources"] = new[] { "Unloads goods in town", "Delivers the haul", "Empties the pack at home" }, ["BehAttackActorHuntingTarget"] = new[] { "Hunts {target}", "Strikes prey", "Closes on the quarry" }, ["BehCityActorRemoveFire"] = new[] { "Dousing flames", "Fighting the blaze", "Beats back the fire" } }; public static string Format( ActivityKind kind, string key, string rawFact, string target, long subjectId, int lineIndex) { if (string.IsNullOrEmpty(rawFact) && string.IsNullOrEmpty(key)) { return ""; } string template = PickTemplate(key, subjectId, lineIndex); if (string.IsNullOrEmpty(template)) { return rawFact ?? key ?? ""; } string t = string.IsNullOrEmpty(target) ? "their mark" : target; return template.Replace("{target}", t); } private static string PickTemplate(string key, long subjectId, int lineIndex) { if (string.IsNullOrEmpty(key)) { return null; } string[] bag = null; if (Variants.TryGetValue(key, out bag) && bag != null && bag.Length > 0) { return bag[PickIndex(subjectId, key, lineIndex, bag.Length)]; } string lower = key.ToLowerInvariant(); foreach (KeyValuePair kv in Variants) { if (lower.IndexOf(kv.Key, System.StringComparison.Ordinal) >= 0 && kv.Value != null && kv.Value.Length > 0) { return kv.Value[PickIndex(subjectId, kv.Key, lineIndex, kv.Value.Length)]; } } return null; } private static int PickIndex(long subjectId, string key, int lineIndex, int count) { if (count <= 1) { return 0; } unchecked { int h = (int)(subjectId * 397) ^ (key?.GetHashCode() ?? 0) ^ (lineIndex * 31); // Extra jitter so back-to-back repeats of the same task shift. h ^= (int)(UnityEngine.Time.unscaledTime * 10f); if (h < 0) { h = -h; } return h % count; } } }