2024-08-16 22:52:13 +00:00
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2024-08-21 13:35:28 +00:00
|
|
|
using System.Text.RegularExpressions;
|
2024-08-16 22:52:13 +00:00
|
|
|
|
|
|
|
using MultiversalDiplomacy.Model;
|
|
|
|
|
2024-08-21 13:35:28 +00:00
|
|
|
using static MultiversalDiplomacy.Model.OrderRegex;
|
|
|
|
|
2024-08-16 22:52:13 +00:00
|
|
|
namespace MultiversalDiplomacy.Script;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// A script handler for modifying a game before it begins.
|
|
|
|
/// </summary>
|
2024-08-18 03:01:50 +00:00
|
|
|
public class SetupScriptHandler(World world, bool strict = false) : IScriptHandler
|
2024-08-16 22:52:13 +00:00
|
|
|
{
|
2024-08-21 13:35:28 +00:00
|
|
|
public string Prompt => "setup> ";
|
2024-08-16 22:52:13 +00:00
|
|
|
|
|
|
|
public World World { get; private set; } = world;
|
|
|
|
|
2024-08-18 03:01:50 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Whether unsuccessful commands should terminate the script.
|
|
|
|
/// </summary>
|
|
|
|
public bool Strict { get; } = strict;
|
|
|
|
|
2024-08-16 22:52:13 +00:00
|
|
|
public IScriptHandler? HandleInput(string input)
|
|
|
|
{
|
|
|
|
var args = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
2024-08-21 16:47:13 +00:00
|
|
|
if (args.Length == 0 || input.StartsWith('#'))
|
2024-08-16 22:52:13 +00:00
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
var command = args[0];
|
|
|
|
switch (command)
|
|
|
|
{
|
|
|
|
case "help":
|
|
|
|
case "?":
|
|
|
|
Console.WriteLine("commands:");
|
2024-08-18 04:24:59 +00:00
|
|
|
Console.WriteLine(" begin: complete setup and start the game (alias: ---)");
|
2024-08-16 22:52:13 +00:00
|
|
|
Console.WriteLine(" list <type>: list things in a game category");
|
|
|
|
Console.WriteLine(" option <name> <value>: set a game option");
|
|
|
|
Console.WriteLine(" unit <power> <type> <province> [location]: add a unit to the game");
|
|
|
|
Console.WriteLine(" <province> may be \"province/location\"");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "begin":
|
2024-08-18 04:24:59 +00:00
|
|
|
case "---":
|
2024-08-21 14:27:48 +00:00
|
|
|
Console.WriteLine("Starting game");
|
2024-08-21 16:11:39 +00:00
|
|
|
Console.WriteLine("Ready for orders");
|
2024-08-18 04:24:59 +00:00
|
|
|
return new GameScriptHandler(World, Strict);
|
2024-08-16 22:52:13 +00:00
|
|
|
|
|
|
|
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:
|
2024-08-21 13:35:28 +00:00
|
|
|
throw new NotImplementedException("There are no supported options yet");
|
2024-08-16 22:52:13 +00:00
|
|
|
|
2024-08-21 13:35:28 +00:00
|
|
|
case "unit" when args.Length < 2:
|
|
|
|
Console.WriteLine("usage: unit [power] [type] [province]</location>");
|
2024-08-16 22:52:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case "unit":
|
2024-08-21 13:35:28 +00:00
|
|
|
string unitSpec = input["unit ".Length..];
|
|
|
|
if (TryParseUnit(unitSpec, out Unit? newUnit)) {
|
2024-08-16 22:52:13 +00:00
|
|
|
World = World.Update(units: World.Units.Append(newUnit));
|
|
|
|
Console.WriteLine($"Created {newUnit}");
|
2024-08-18 03:01:50 +00:00
|
|
|
} else if (Strict) {
|
|
|
|
return null;
|
2024-08-16 22:52:13 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2024-08-21 16:11:39 +00:00
|
|
|
Console.WriteLine($"Unrecognized command: \"{command}\"");
|
2024-08-18 03:01:50 +00:00
|
|
|
if (Strict) return null;
|
2024-08-16 22:52:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2024-08-21 13:35:28 +00:00
|
|
|
private bool TryParseUnit(string unitSpec, [NotNullWhen(true)] out Unit? newUnit)
|
2024-08-16 22:52:13 +00:00
|
|
|
{
|
|
|
|
newUnit = null;
|
|
|
|
|
2024-08-21 13:35:28 +00:00
|
|
|
OrderRegex re = new(World);
|
|
|
|
Regex reUnit = new($"^{re.Power} {OrderRegex.Type} {re.Province}(?:{SlashLocation}|{ParenLocation})?$");
|
|
|
|
Match match = reUnit.Match(unitSpec);
|
|
|
|
if (!match.Success) {
|
|
|
|
Console.WriteLine($"Could not match unit spec \"{unitSpec}\"");
|
2024-08-16 22:52:13 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-08-21 13:35:28 +00:00
|
|
|
string power = World.Powers.First(p => p.EqualsAnyCase(match.Groups[1].Value));
|
|
|
|
|
|
|
|
string typeName = Enum.GetNames<UnitType>().First(name => name.StartsWithAnyCase(match.Groups[2].Value));
|
|
|
|
UnitType type = Enum.Parse<UnitType>(typeName);
|
|
|
|
|
|
|
|
Province province = World.Map.Provinces.First(prov
|
|
|
|
=> prov.Name.EqualsAnyCase(match.Groups[3].Value)
|
|
|
|
|| prov.Abbreviations.Any(abv => abv.EqualsAnyCase(match.Groups[3].Value)));
|
|
|
|
|
|
|
|
string locationName = match.Groups[4].Length > 0 ? match.Groups[4].Value : match.Groups[5].Value;
|
|
|
|
Location location = province.Locations.First(loc
|
|
|
|
=> loc.Name.StartsWithAnyCase(locationName)
|
|
|
|
|| loc.Abbreviation.StartsWithAnyCase(locationName));
|
2024-08-16 22:52:13 +00:00
|
|
|
|
2024-08-21 13:35:28 +00:00
|
|
|
newUnit = Unit.Build(location.Key, Season.First, power, type);
|
2024-08-16 22:52:13 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|