using System.Diagnostics.CodeAnalysis; using MultiversalDiplomacy.Model; namespace MultiversalDiplomacy.Script; /// /// A script handler for modifying a game before it begins. /// public class SetupScriptHandler(World world) : IScriptHandler { public string Prompt => "5dp> "; public World World { get; private set; } = world; public IScriptHandler? HandleInput(string input) { var args = input.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (args.Length == 0) { return this; } var command = args[0]; switch (command) { case "help": case "?": Console.WriteLine("commands:"); Console.WriteLine(" begin: complete setup and start the game"); Console.WriteLine(" list : list things in a game category"); Console.WriteLine(" option : set a game option"); Console.WriteLine(" unit [location]: add a unit to the game"); Console.WriteLine(" may be \"province/location\""); break; case "begin": return null; // TODO case "list" when args.Length == 1: Console.WriteLine("usage:"); Console.WriteLine(" list powers: the powers in the game"); Console.WriteLine(" list units: units created so far"); break; case "list" when args[1] == "powers": Console.WriteLine("Powers:"); foreach (string powerName in World.Powers) { Console.WriteLine($" {powerName}"); } break; case "list" when args[1] == "units": Console.WriteLine("Units:"); foreach (Unit unit in World.Units) { Console.WriteLine($" {unit}"); } break; case "option" when args.Length < 3: throw new NotImplementedException(); case "unit" when args.Length < 4: Console.WriteLine("usage: unit [power] [type] [province] "); break; case "unit": string power = args[1]; string type = args[2]; string province = args[3]; string? location = args.Length >= 5 ? args[4] : null; if (ParseUnit(power, type, province, location, out Unit? newUnit)) { World = World.Update(units: World.Units.Append(newUnit)); Console.WriteLine($"Created {newUnit}"); } break; default: // noop on comments that begin with # if (!command.StartsWith('#')) { Console.WriteLine($"Unrecognized command: {command}"); } break; } return this; } private bool ParseUnit( string powerArg, string typeArg, string provinceArg, string? locationArg, [NotNullWhen(true)] out Unit? newUnit) { newUnit = null; // Parse the power name by substring matching. var matchingPowers = World.Powers.Where(p => p.StartsWithAnyCase(powerArg)); if (!matchingPowers.Any()) { Console.WriteLine($"No power named \"{powerArg}\""); return false; } if (matchingPowers.Count() > 1) { Console.WriteLine($"Ambiguous power \"{powerArg}\" between {string.Join(", ", matchingPowers)}"); return false; } string power = matchingPowers.First(); // Parse the unit type by substring matching. var matchingTypes = Enum.GetNames().Where(t => t.StartsWithAnyCase(typeArg)); if (!matchingTypes.Any()) { Console.WriteLine($"No unit type \"{typeArg}\""); return false; } if (matchingTypes.Count() > 1) { Console.WriteLine($"Ambiguous unit type \"{typeArg}\" between {string.Join(", ", matchingTypes)}"); return false; } UnitType type = Enum.Parse(matchingTypes.First()); // Parse the province by matching the province name or one of its abbreviations, // allowing location specifications separated by a forward slash, e.g. spa/nc. if (provinceArg.Contains('/')) { var split = provinceArg.Split('/', 2); locationArg ??= split[1]; provinceArg = split[0]; } var matchingProvs = World.Provinces.Where(pr => pr.Abbreviations.Any(abv => abv.EqualsAnyCase(provinceArg)) || pr.Name.EqualsAnyCase(provinceArg)); if (!matchingProvs.Any()) { Console.WriteLine($"No province matches \"{provinceArg}\""); return false; } if (matchingProvs.Count() > 1) { Console.WriteLine($"Ambiguous province \"{provinceArg}\" between {string.Join(", ", matchingProvs)}"); return false; } Province province = matchingProvs.First(); Location location; locationArg ??= type == UnitType.Army ? "land" : "water"; var matchingLocs = locationArg is null ? province.Locations.Where(loc => type == UnitType.Army && loc.Type == LocationType.Land || type == UnitType.Fleet && loc.Type == LocationType.Water) : province.Locations.Where(loc => loc.Name.EqualsAnyCase(locationArg) || loc.Abbreviation.EqualsAnyCase(locationArg)); if (!matchingLocs.Any()) { Console.WriteLine($"Province {province.Name} has no {locationArg} location"); return false; } location = matchingLocs.First(); newUnit = Unit.Build(location.Key, Season.First, powerArg, type); return true; } }