Rewrite map generator settings UI logic.
This commit is contained in:
committed by
Gustas Kažukauskas
parent
8f46247dc9
commit
78f660124c
@@ -13,389 +13,231 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA.Mods.Common.Traits;
|
||||||
|
using OpenRA.Support;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.MapGenerator
|
namespace OpenRA.Mods.Common.MapGenerator
|
||||||
{
|
{
|
||||||
public sealed class MapGeneratorSettings
|
public abstract class MapGeneratorOption
|
||||||
{
|
{
|
||||||
/// <summary>How an option should be treated for UI purposes.</summary>
|
[FieldLoader.Ignore]
|
||||||
public enum UiType
|
public readonly string Id;
|
||||||
|
public readonly string Label = null;
|
||||||
|
public readonly int Priority = 0;
|
||||||
|
|
||||||
|
protected MapGeneratorOption(string id, MiniYaml yaml)
|
||||||
{
|
{
|
||||||
Hidden,
|
Id = id;
|
||||||
DropDown,
|
FieldLoader.Load(this, yaml);
|
||||||
Checkbox,
|
|
||||||
Integer,
|
|
||||||
Float,
|
|
||||||
String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Represents a bunch of settings, along with UI information.</summary>
|
public abstract IReadOnlyCollection<MiniYamlNode> GetSettings(ITerrainInfo terrainInfo);
|
||||||
public sealed class Choice
|
|
||||||
{
|
|
||||||
/// <summary>Uniquely identifies a Choice within an Option.</summary>
|
|
||||||
public readonly string Id;
|
|
||||||
|
|
||||||
/// <summary>The label to use for UI selection. Post-fluent.</summary>
|
public virtual IEnumerable<string> GetFluentReferences()
|
||||||
|
{
|
||||||
|
if (Label != null)
|
||||||
|
yield return Label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MapGeneratorBooleanOption : MapGeneratorOption
|
||||||
|
{
|
||||||
|
[FieldLoader.Require]
|
||||||
|
public readonly string Parameter = null;
|
||||||
|
public readonly bool Default = false;
|
||||||
|
public bool Value;
|
||||||
|
|
||||||
|
public MapGeneratorBooleanOption(string id, MiniYaml yaml)
|
||||||
|
: base(id, yaml)
|
||||||
|
{
|
||||||
|
Value = Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IReadOnlyCollection<MiniYamlNode> GetSettings(ITerrainInfo terrainInfo)
|
||||||
|
{
|
||||||
|
return [new MiniYamlNode(Parameter, FieldSaver.FormatValue(Value))];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MapGeneratorIntegerOption : MapGeneratorOption
|
||||||
|
{
|
||||||
|
[FieldLoader.Require]
|
||||||
|
public readonly string Parameter = null;
|
||||||
|
public readonly int Default = 0;
|
||||||
|
public int Value;
|
||||||
|
|
||||||
|
public MapGeneratorIntegerOption(string id, MiniYaml yaml)
|
||||||
|
: base(id, yaml)
|
||||||
|
{
|
||||||
|
Value = Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IReadOnlyCollection<MiniYamlNode> GetSettings(ITerrainInfo terrainInfo)
|
||||||
|
{
|
||||||
|
return [new MiniYamlNode(Parameter, FieldSaver.FormatValue(Value))];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MapGeneratorMultiChoiceOption : MapGeneratorOption
|
||||||
|
{
|
||||||
|
public class MapGeneratorDropdownChoice
|
||||||
|
{
|
||||||
public readonly string Label = null;
|
public readonly string Label = null;
|
||||||
|
public readonly string[] Tileset = null;
|
||||||
|
|
||||||
/// <summary>The tooltip to use for UI selection. Post-fluent.</summary>
|
[FieldLoader.LoadUsing(nameof(LoadSettings))]
|
||||||
public readonly string Description = null;
|
[FieldLoader.Require]
|
||||||
|
public readonly ImmutableList<MiniYamlNode> Settings = null;
|
||||||
|
|
||||||
/// <summary>
|
static ImmutableList<MiniYamlNode> LoadSettings(MiniYaml yaml)
|
||||||
/// Only offer the Choice for these tilesets. (If null, show for all.)
|
|
||||||
/// </summary>
|
|
||||||
public readonly IReadOnlySet<string> Tileset = null;
|
|
||||||
|
|
||||||
/// <summary>(Partial) settings to combine into the final overall settings.</summary>
|
|
||||||
public readonly MiniYaml Settings;
|
|
||||||
|
|
||||||
public Choice(string id, MiniYaml my)
|
|
||||||
{
|
{
|
||||||
Id = id;
|
return yaml.NodeWithKey("Settings").Value.Nodes.ToImmutableList();
|
||||||
var label = my.NodeWithKeyOrDefault("Label")?.Value.Value;
|
|
||||||
if (label != null)
|
|
||||||
{
|
|
||||||
Label = FluentProvider.GetMessage($"{label}.label");
|
|
||||||
FluentProvider.TryGetMessage($"{label}.description", out Description);
|
|
||||||
}
|
|
||||||
|
|
||||||
Tileset = my.NodeWithKeyOrDefault("Tileset")?.Value.Value
|
|
||||||
?.Split(',')
|
|
||||||
.ToImmutableHashSet();
|
|
||||||
Settings = my.NodeWithKey("Settings").Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Create a choice that represents a top-level setting with a given value.</summary>
|
|
||||||
public Choice(string setting, string value)
|
|
||||||
{
|
|
||||||
Id = value;
|
|
||||||
Label = value;
|
|
||||||
Description = null;
|
|
||||||
Tileset = null;
|
|
||||||
Settings = new MiniYaml(null, [new MiniYamlNode(setting, value)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DumpFluent(MiniYaml my, List<string> references)
|
|
||||||
{
|
|
||||||
var label = my.NodeWithKeyOrDefault("Label")?.Value.Value;
|
|
||||||
if (label != null)
|
|
||||||
{
|
|
||||||
references.Add($"{label}.label");
|
|
||||||
|
|
||||||
// Descriptions are optional.
|
|
||||||
if (FluentProvider.TryGetMessage($"{label}.description", out _))
|
|
||||||
references.Add($"{label}.description");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Check whether this choice is permitted for this map.</summary>
|
|
||||||
public bool Allowed(ITerrainInfo terrainInfo)
|
|
||||||
{
|
|
||||||
if (Tileset != null && !Tileset.Contains(terrainInfo.Id))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>For single-setting choices, creates a new choice for that setting with a given value.</summary>
|
|
||||||
public Choice NewValue(string value)
|
|
||||||
{
|
|
||||||
if (Settings.Nodes.Length != 1)
|
|
||||||
throw new InvalidOperationException("NewValue can only be used on single-setting Choices");
|
|
||||||
return new(Settings.Nodes[0].Key, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class Option
|
[FieldLoader.LoadUsing(nameof(LoadChoices))]
|
||||||
|
public readonly Dictionary<string, MapGeneratorDropdownChoice> Choices = null;
|
||||||
|
|
||||||
|
static Dictionary<string, MapGeneratorDropdownChoice> LoadChoices(MiniYaml yaml)
|
||||||
{
|
{
|
||||||
/// <summary>Unique identifier for this Option.</summary>
|
var ret = new Dictionary<string, MapGeneratorDropdownChoice>();
|
||||||
[FieldLoader.Ignore]
|
foreach (var node in yaml.Nodes)
|
||||||
public readonly string Id;
|
|
||||||
|
|
||||||
/// <summary>The label to use for UI selection. Post-fluent.</summary>
|
|
||||||
[FieldLoader.Ignore]
|
|
||||||
public readonly string Label = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>For multiple-choice options (dropdowns/checkboxes) holds the allowed Choices.</para>
|
|
||||||
/// <para>For text entry Options, contains the default value.</para>
|
|
||||||
/// <para>If this is empty, the map is not compatible with the generator.</para>
|
|
||||||
/// </summary>
|
|
||||||
[FieldLoader.Ignore]
|
|
||||||
public readonly IReadOnlyList<Choice> Choices;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>The default Choice for this option.</para>
|
|
||||||
/// <para>Default will be ignored if it is not valid for the map.</para>
|
|
||||||
/// </summary>
|
|
||||||
[FieldLoader.Ignore]
|
|
||||||
public readonly Choice Default;
|
|
||||||
|
|
||||||
public readonly double Min = double.NegativeInfinity;
|
|
||||||
public readonly double Max = double.PositiveInfinity;
|
|
||||||
|
|
||||||
/// <summary>Whether the Option can be randomized.</summary>
|
|
||||||
public readonly bool Random = false;
|
|
||||||
|
|
||||||
/// <summary>How an option should be treated for UI purposes.</summary>
|
|
||||||
[FieldLoader.Ignore]
|
|
||||||
public readonly UiType Ui;
|
|
||||||
|
|
||||||
/// <summary>Settings layering priority. Higher overrides lower.</summary>
|
|
||||||
public readonly int Priority = 0;
|
|
||||||
|
|
||||||
public Option(string id, MiniYaml my, ITerrainInfo terrainInfo)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
FieldLoader.Load(this, my);
|
|
||||||
var label = my.NodeWithKeyOrDefault("Label")?.Value.Value;
|
|
||||||
if (label != null)
|
|
||||||
Label = FluentProvider.GetMessage(label);
|
|
||||||
|
|
||||||
var choices = new List<Choice>();
|
|
||||||
Choices = choices;
|
|
||||||
|
|
||||||
var integerSetting = my.NodeWithKeyOrDefault("Integer");
|
|
||||||
var floatSetting = my.NodeWithKeyOrDefault("Float");
|
|
||||||
var stringSetting = my.NodeWithKeyOrDefault("String");
|
|
||||||
var checkboxSetting = my.NodeWithKeyOrDefault("Checkbox");
|
|
||||||
var simpleChoiceSetting = my.NodeWithKeyOrDefault("SimpleChoice");
|
|
||||||
var textSetting = integerSetting ?? floatSetting ?? stringSetting;
|
|
||||||
if (textSetting != null)
|
|
||||||
{
|
|
||||||
var setting = textSetting.Value.Value;
|
|
||||||
var value = my.NodeWithKeyOrDefault("Default")?.Value.Value ?? "";
|
|
||||||
var choice = new Choice(setting, value);
|
|
||||||
choices.Add(choice);
|
|
||||||
Default = choice;
|
|
||||||
Ui =
|
|
||||||
integerSetting != null ? UiType.Integer :
|
|
||||||
floatSetting != null ? UiType.Float :
|
|
||||||
UiType.String;
|
|
||||||
|
|
||||||
if (Ui == UiType.Integer)
|
|
||||||
{
|
|
||||||
if (Min == double.NegativeInfinity)
|
|
||||||
Min = int.MinValue;
|
|
||||||
if (Max == double.PositiveInfinity)
|
|
||||||
Max = int.MaxValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (checkboxSetting != null)
|
|
||||||
{
|
|
||||||
var setting = checkboxSetting.Value.Value;
|
|
||||||
var falseChoice = new Choice(setting, "False");
|
|
||||||
var trueChoice = new Choice(setting, "True");
|
|
||||||
choices.Add(falseChoice);
|
|
||||||
choices.Add(trueChoice);
|
|
||||||
var enabled = (my.NodeWithKeyOrDefault("Default")?.Value.Value ?? "False") == "True";
|
|
||||||
Default = enabled ? trueChoice : falseChoice;
|
|
||||||
Ui = UiType.Checkbox;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (simpleChoiceSetting != null)
|
|
||||||
{
|
|
||||||
var setting = simpleChoiceSetting.Value.Value;
|
|
||||||
var values = simpleChoiceSetting.Value
|
|
||||||
.NodeWithKey("Values").Value.Value
|
|
||||||
.Split(',');
|
|
||||||
foreach (var value in values)
|
|
||||||
choices.Add(new Choice(setting, value));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var node in my.Nodes)
|
|
||||||
{
|
|
||||||
var split = node.Key.Split('@');
|
|
||||||
if (split[0] == "Choice")
|
|
||||||
{
|
|
||||||
string choiceId = null;
|
|
||||||
if (split.Length >= 2)
|
|
||||||
choiceId = split[1];
|
|
||||||
var choice = new Choice(choiceId, node.Value);
|
|
||||||
if (choice.Allowed(terrainInfo))
|
|
||||||
choices.Add(choice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Choices.Count > 0)
|
|
||||||
{
|
|
||||||
var defaultOrder = my.NodeWithKeyOrDefault("Default")?.Value.Value;
|
|
||||||
if (defaultOrder != null)
|
|
||||||
{
|
|
||||||
foreach (var defaultChoice in defaultOrder.Split(','))
|
|
||||||
{
|
|
||||||
Default = Choices.FirstOrDefault(choice => choice.Id == defaultChoice);
|
|
||||||
if (Default != null)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Default == null)
|
|
||||||
throw new YamlException($"None of option `{id}`'s default choices `{defaultOrder}` are not valid");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Default = Choices[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ui = Label == null ? UiType.Hidden : UiType.DropDown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DumpFluent(MiniYaml my, List<string> references)
|
|
||||||
{
|
|
||||||
var label = my.NodeWithKeyOrDefault("Label")?.Value.Value;
|
|
||||||
if (label != null)
|
|
||||||
references.Add(label);
|
|
||||||
foreach (var node in my.Nodes)
|
|
||||||
if (node.Key.Split('@')[0] == "Choice")
|
|
||||||
Choice.DumpFluent(node.Value, references);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ValidateChoice(Choice choice)
|
|
||||||
{
|
|
||||||
switch (Ui)
|
|
||||||
{
|
|
||||||
case UiType.Integer:
|
|
||||||
{
|
|
||||||
var valid = long.TryParse(choice.Id, out var value);
|
|
||||||
if (value < Min || value > Max)
|
|
||||||
valid = false;
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
case UiType.Float:
|
|
||||||
{
|
|
||||||
var valid = double.TryParse(choice.Id, out var value);
|
|
||||||
if (value < Min || value > Max)
|
|
||||||
valid = false;
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
case UiType.String:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return Choices.Contains(choice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Choice RandomChoice()
|
|
||||||
{
|
|
||||||
if (Random)
|
|
||||||
{
|
|
||||||
var random = (long)Guid.NewGuid().GetHashCode() - int.MinValue;
|
|
||||||
switch (Ui)
|
|
||||||
{
|
|
||||||
case UiType.Integer:
|
|
||||||
var intRandom = (int)(random % (long)(Max - Min + 1) + (long)Min);
|
|
||||||
return Default.NewValue(intRandom.ToStringInvariant());
|
|
||||||
case UiType.Float:
|
|
||||||
var floatRandom = (float)((double)0xffffffff * random / (Max - Min) + Min);
|
|
||||||
return Default.NewValue(floatRandom.ToStringInvariant());
|
|
||||||
case UiType.Checkbox:
|
|
||||||
case UiType.DropDown:
|
|
||||||
if (Choices.Count == 0)
|
|
||||||
throw new InvalidOperationException($"Map is not compatible with Option `{Id}`");
|
|
||||||
return Choices[(int)(random % Choices.Count)];
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException($"Option `{Id}` does not have a randomizable type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsFreeform()
|
|
||||||
{
|
|
||||||
switch (Ui)
|
|
||||||
{
|
|
||||||
case UiType.Hidden:
|
|
||||||
case UiType.DropDown:
|
|
||||||
case UiType.Checkbox:
|
|
||||||
return false;
|
|
||||||
case UiType.Integer:
|
|
||||||
case UiType.Float:
|
|
||||||
case UiType.String:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Bad UiType");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly IReadOnlyList<Option> Options;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parse settings from a MiniYaml definition. Returns null if the map isn't compatible.
|
|
||||||
/// </summary>
|
|
||||||
public static MapGeneratorSettings LoadSettings(MiniYaml my, ITerrainInfo terrainInfo)
|
|
||||||
{
|
|
||||||
var options = new List<Option>();
|
|
||||||
|
|
||||||
foreach (var node in my.Nodes)
|
|
||||||
{
|
{
|
||||||
var split = node.Key.Split('@');
|
var split = node.Key.Split('@');
|
||||||
if (split[0] == "Option")
|
if (split.Length == 2 && split[0] == "Choice")
|
||||||
{
|
ret.Add(split[1], FieldLoader.Load<MapGeneratorDropdownChoice>(node.Value));
|
||||||
string id = null;
|
|
||||||
if (split.Length >= 2)
|
|
||||||
id = split[1];
|
|
||||||
var option = new Option(id, node.Value, terrainInfo);
|
|
||||||
if (option.Choices.Count == 0)
|
|
||||||
return null;
|
|
||||||
options.Add(option);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MapGeneratorSettings(options);
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<string> DumpFluent(MiniYaml my)
|
public readonly string[] Default = null;
|
||||||
|
string value = null;
|
||||||
|
|
||||||
|
public MapGeneratorMultiChoiceOption(string id, MiniYaml yaml)
|
||||||
|
: base(id, yaml) { }
|
||||||
|
|
||||||
|
public override IReadOnlyCollection<MiniYamlNode> GetSettings(ITerrainInfo terrainInfo)
|
||||||
{
|
{
|
||||||
var references = new List<string>();
|
var validChoices = ValidChoices(terrainInfo);
|
||||||
DumpFluent(my, references);
|
if (validChoices.Contains(value))
|
||||||
return references;
|
return Choices[value].Settings;
|
||||||
|
|
||||||
|
var fallback = Default?.FirstOrDefault(validChoices.Contains) ?? validChoices.FirstOrDefault();
|
||||||
|
return fallback != null ? Choices[fallback].Settings : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DumpFluent(MiniYaml my, List<string> references)
|
public string Value
|
||||||
{
|
{
|
||||||
foreach (var node in my.Nodes)
|
get => value;
|
||||||
if (node.Key.Split('@')[0] == "Option")
|
set
|
||||||
Option.DumpFluent(node.Value, references);
|
|
||||||
}
|
|
||||||
|
|
||||||
MapGeneratorSettings(IReadOnlyList<Option> options)
|
|
||||||
{
|
|
||||||
Options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<Option, Choice> DefaultChoices()
|
|
||||||
{
|
|
||||||
return Options.ToDictionary(option => option, option => option.Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Merge all choices into a complete settings MiniYaml.</summary>
|
|
||||||
public MiniYaml Compile(IReadOnlyDictionary<Option, Choice> choices)
|
|
||||||
{
|
|
||||||
var layers = new List<IReadOnlyCollection<MiniYamlNode>>();
|
|
||||||
|
|
||||||
// Apply the choices in their canonical order.
|
|
||||||
foreach (var option in Options.OrderBy(option => option.Priority))
|
|
||||||
{
|
{
|
||||||
var choice = choices[option];
|
if (!Choices.ContainsKey(value))
|
||||||
if (!option.ValidateChoice(choice))
|
throw new ArgumentException($"{value} is not in the list of valid choices");
|
||||||
throw new ArgumentException($"Option `{option.Id}` has illegal choice");
|
|
||||||
layers.Add(choice.Settings.Nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
var settingsNodes = MiniYaml.Merge(layers);
|
this.value = value;
|
||||||
return new MiniYaml(null, settingsNodes);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> ValidChoices(ITerrainInfo terrainInfo)
|
||||||
|
{
|
||||||
|
return Choices
|
||||||
|
.Where(kv => kv.Value.Tileset == null || kv.Value.Tileset.Contains(terrainInfo.Id))
|
||||||
|
.Select(kv => kv.Key)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> GetFluentReferences()
|
||||||
|
{
|
||||||
|
if (Label != null)
|
||||||
|
yield return Label;
|
||||||
|
|
||||||
|
foreach (var c in Choices.Values)
|
||||||
|
{
|
||||||
|
if (c.Label == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
yield return c.Label + ".label";
|
||||||
|
|
||||||
|
// Descriptions are optional
|
||||||
|
if (FluentProvider.TryGetMessage(c.Label + ".description", out _))
|
||||||
|
yield return c.Label + ".description";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MapGeneratorMultiIntegerChoiceOption : MapGeneratorOption
|
||||||
|
{
|
||||||
|
[FieldLoader.Require]
|
||||||
|
public readonly string Parameter = null;
|
||||||
|
|
||||||
|
[FieldLoader.Require]
|
||||||
|
public readonly int[] Choices = null;
|
||||||
|
|
||||||
|
public readonly int? Default = null;
|
||||||
|
int value;
|
||||||
|
|
||||||
|
public MapGeneratorMultiIntegerChoiceOption(string id, MiniYaml yaml)
|
||||||
|
: base(id, yaml)
|
||||||
|
{
|
||||||
|
Value = Default ?? Choices?.First() ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Value
|
||||||
|
{
|
||||||
|
get => value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!Choices.Contains(value))
|
||||||
|
throw new ArgumentException($"{value} is not in the list of valid choices");
|
||||||
|
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IReadOnlyCollection<MiniYamlNode> GetSettings(ITerrainInfo terrainInfo)
|
||||||
|
{
|
||||||
|
return [new MiniYamlNode(Parameter, FieldSaver.FormatValue(Value))];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class MapGeneratorSettings : IMapGeneratorSettings
|
||||||
|
{
|
||||||
|
public MapGeneratorSettings(MiniYaml yaml)
|
||||||
|
{
|
||||||
|
foreach (var node in yaml.Nodes)
|
||||||
|
{
|
||||||
|
var split = node.Key.Split('@');
|
||||||
|
if (split.Length != 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (split[0] == "BooleanOption")
|
||||||
|
Options.Add(new MapGeneratorBooleanOption(split[1], node.Value));
|
||||||
|
else if (split[0] == "IntegerOption")
|
||||||
|
Options.Add(new MapGeneratorIntegerOption(split[1], node.Value));
|
||||||
|
else if (split[0] == "MultiIntegerChoiceOption")
|
||||||
|
Options.Add(new MapGeneratorMultiIntegerChoiceOption(split[1], node.Value));
|
||||||
|
else if (split[0] == "MultiChoiceOption")
|
||||||
|
Options.Add(new MapGeneratorMultiChoiceOption(split[1], node.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MapGeneratorOption> Options { get; } = [];
|
||||||
|
|
||||||
|
public void Randomize(MersenneTwister random)
|
||||||
|
{
|
||||||
|
if (Options.FirstOrDefault(o => o.Id == "Seed") is MapGeneratorIntegerOption seed)
|
||||||
|
seed.Value = random.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MiniYaml Compile(ITerrainInfo terrainInfo)
|
||||||
|
{
|
||||||
|
// Apply the choices in their canonical order.
|
||||||
|
var layers = Options
|
||||||
|
.OrderBy(option => option.Priority)
|
||||||
|
.Select(o => o.GetSettings(terrainInfo));
|
||||||
|
|
||||||
|
return new MiniYaml(null, MiniYaml.Merge(layers));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using OpenRA.Mods.Common.MapGenerator;
|
using OpenRA.Mods.Common.MapGenerator;
|
||||||
using OpenRA.Mods.Common.Terrain;
|
using OpenRA.Mods.Common.Terrain;
|
||||||
using OpenRA.Support;
|
using OpenRA.Support;
|
||||||
@@ -50,12 +51,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
static List<string> FluentReferencesLoader(MiniYaml my)
|
static List<string> FluentReferencesLoader(MiniYaml my)
|
||||||
{
|
{
|
||||||
return MapGeneratorSettings.DumpFluent(my.NodeWithKey("Settings").Value);
|
return new MapGeneratorSettings(my.NodeWithKey("Settings").Value)
|
||||||
|
.Options.SelectMany(o => o.GetFluentReferences()).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapGeneratorSettings GetSettings(ITerrainInfo terrainInfo)
|
public IMapGeneratorSettings GetSettings()
|
||||||
{
|
{
|
||||||
return MapGeneratorSettings.LoadSettings(Settings, terrainInfo);
|
return new MapGeneratorSettings(Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Generate(Map map, MiniYaml settings)
|
public void Generate(Map map, MiniYaml settings)
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
static List<string> FluentReferencesLoader(MiniYaml my)
|
static List<string> FluentReferencesLoader(MiniYaml my)
|
||||||
{
|
{
|
||||||
return MapGeneratorSettings.DumpFluent(my.NodeWithKey("Settings").Value);
|
return new MapGeneratorSettings(my.NodeWithKey("Settings").Value)
|
||||||
|
.Options.SelectMany(o => o.GetFluentReferences()).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int FractionMax = 1000;
|
const int FractionMax = 1000;
|
||||||
@@ -481,9 +482,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapGeneratorSettings GetSettings(ITerrainInfo terrainInfo)
|
public IMapGeneratorSettings GetSettings()
|
||||||
{
|
{
|
||||||
return MapGeneratorSettings.LoadSettings(Settings, terrainInfo);
|
return new MapGeneratorSettings(Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Generate(Map map, MiniYaml settings)
|
public void Generate(Map map, MiniYaml settings)
|
||||||
|
|||||||
@@ -969,16 +969,23 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
: base(message, inner) { }
|
: base(message, inner) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IMapGeneratorSettings
|
||||||
|
{
|
||||||
|
/// <summary>Returns the options that allow users to customise the result.</summary>
|
||||||
|
List<MapGeneratorOption> Options { get; }
|
||||||
|
|
||||||
|
void Randomize(MersenneTwister random);
|
||||||
|
|
||||||
|
/// <summary>Merge all choices into a complete settings MiniYaml.</summary>
|
||||||
|
MiniYaml Compile(ITerrainInfo terrainInfo);
|
||||||
|
}
|
||||||
|
|
||||||
public interface IMapGeneratorInfo : ITraitInfoInterface
|
public interface IMapGeneratorInfo : ITraitInfoInterface
|
||||||
{
|
{
|
||||||
string Type { get; }
|
string Type { get; }
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
IMapGeneratorSettings GetSettings();
|
||||||
/// Get the generator settings available for this tileset.
|
|
||||||
/// Returns null if not compatible with the given tileset.
|
|
||||||
/// </summary>
|
|
||||||
MapGeneratorSettings GetSettings(ITerrainInfo terrainInfo);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate or manipulate a supplied map in-place.
|
/// Generate or manipulate a supplied map in-place.
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ using System.Collections.Immutable;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using OpenRA.Mods.Common.MapGenerator;
|
||||||
using OpenRA.Mods.Common.Traits;
|
using OpenRA.Mods.Common.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.UtilityCommands
|
namespace OpenRA.Mods.Common.UtilityCommands
|
||||||
@@ -204,9 +205,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
.Select(variable => config.Choices[variable].Length)
|
.Select(variable => config.Choices[variable].Length)
|
||||||
.ToImmutableArray();
|
.ToImmutableArray();
|
||||||
|
|
||||||
var generator =
|
var generator = modData.DefaultRules.Actors[SystemActors.EditorWorld]
|
||||||
modData.DefaultRules.Actors[SystemActors.EditorWorld].TraitInfos<IMapGeneratorInfo>()
|
.TraitInfos<IMapGeneratorInfo>()
|
||||||
.FirstOrDefault(info => info.Type == config.MapGeneratorType);
|
.FirstOrDefault(info => info.Type == config.MapGeneratorType);
|
||||||
if (generator == null)
|
if (generator == null)
|
||||||
throw new ArgumentException($"No map generator with type `{config.MapGeneratorType}`");
|
throw new ArgumentException($"No map generator with type `{config.MapGeneratorType}`");
|
||||||
|
|
||||||
@@ -246,7 +247,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
.Select(kv => $"{kv.Key}={kv.Value}")
|
.Select(kv => $"{kv.Key}={kv.Value}")
|
||||||
.ToHashSet();
|
.ToHashSet();
|
||||||
|
|
||||||
var tileset = modData.DefaultTerrainInfo[iterationChoices[Configuration.TilesetVariable]];
|
var terrainInfo = modData.DefaultTerrainInfo[iterationChoices[Configuration.TilesetVariable]];
|
||||||
iterationChoices.Remove(Configuration.TilesetVariable);
|
iterationChoices.Remove(Configuration.TilesetVariable);
|
||||||
|
|
||||||
var size = iterationChoices[Configuration.SizeVariable]
|
var size = iterationChoices[Configuration.SizeVariable]
|
||||||
@@ -263,26 +264,31 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
if (size.Length != 2)
|
if (size.Length != 2)
|
||||||
throw new ArgumentException($"bad map size `{iterationChoices[Configuration.SizeVariable]}`");
|
throw new ArgumentException($"bad map size `{iterationChoices[Configuration.SizeVariable]}`");
|
||||||
|
|
||||||
var map = new Map(modData, tileset, size[0], size[1]);
|
var map = new Map(modData, terrainInfo, size[0], size[1]);
|
||||||
var maxTerrainHeight = map.Grid.MaximumTerrainHeight;
|
var maxTerrainHeight = map.Grid.MaximumTerrainHeight;
|
||||||
var tl = new PPos(1, 1 + maxTerrainHeight);
|
var tl = new PPos(1, 1 + maxTerrainHeight);
|
||||||
var br = new PPos(size[0], size[1] + maxTerrainHeight);
|
var br = new PPos(size[0], size[1] + maxTerrainHeight);
|
||||||
map.SetBounds(tl, br);
|
map.SetBounds(tl, br);
|
||||||
|
|
||||||
var settings = generator.GetSettings(tileset);
|
var settings = generator.GetSettings();
|
||||||
var choices = settings.DefaultChoices();
|
foreach (var o in settings.Options)
|
||||||
foreach (var option in choices.Keys)
|
{
|
||||||
if (iterationChoices.TryGetValue(option.Id, out var choice))
|
if (iterationChoices.TryGetValue(o.Id, out var choice))
|
||||||
{
|
{
|
||||||
choices[option] = option.IsFreeform()
|
if (o is MapGeneratorBooleanOption bo)
|
||||||
? choices[option].NewValue(choice)
|
bo.Value = FieldLoader.GetValue<bool>("choice", choice);
|
||||||
: option.Choices.First(c => c.Id == choice);
|
else if (o is MapGeneratorIntegerOption io)
|
||||||
iterationChoices.Remove(option.Id);
|
io.Value = FieldLoader.GetValue<int>("choice", choice);
|
||||||
|
else if (o is MapGeneratorMultiIntegerChoiceOption mio)
|
||||||
|
mio.Value = FieldLoader.GetValue<int>("choice", choice);
|
||||||
|
else if (o is MapGeneratorMultiChoiceOption mo)
|
||||||
|
mo.Value = choice;
|
||||||
|
|
||||||
|
iterationChoices.Remove(o.Id);
|
||||||
}
|
}
|
||||||
else if (config.NoDefaults)
|
else if (config.NoDefaults)
|
||||||
{
|
throw new ArgumentException($"No choices specified for option `{o.Id}`");
|
||||||
throw new ArgumentException($"No choices specified for option `{option.Id}`");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (iterationChoices.Count != 0)
|
if (iterationChoices.Count != 0)
|
||||||
throw new ArgumentException($"Unknown options: {string.Join(", ", iterationChoices.Keys)}");
|
throw new ArgumentException($"Unknown options: {string.Join(", ", iterationChoices.Keys)}");
|
||||||
@@ -292,8 +298,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
tests++;
|
tests++;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var my = settings.Compile(choices);
|
generator.Generate(map, settings.Compile(terrainInfo));
|
||||||
generator.Generate(map, my);
|
|
||||||
}
|
}
|
||||||
catch (Exception e) when (e is MapGenerationException || e is YamlException)
|
catch (Exception e) when (e is MapGenerationException || e is YamlException)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,24 +27,18 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
[FluentReference("name")]
|
[FluentReference("name")]
|
||||||
const string StrGenerated = "notification-map-generator-generated";
|
const string StrGenerated = "notification-map-generator-generated";
|
||||||
[FluentReference]
|
[FluentReference]
|
||||||
const string StrBadOption = "notification-map-generator-bad-option";
|
|
||||||
[FluentReference]
|
|
||||||
const string StrFailed = "notification-map-generator-failed";
|
const string StrFailed = "notification-map-generator-failed";
|
||||||
[FluentReference]
|
[FluentReference]
|
||||||
const string StrFailedCancel = "label-map-generator-failed-cancel";
|
const string StrFailedCancel = "label-map-generator-failed-cancel";
|
||||||
|
|
||||||
readonly EditorActionManager editorActionManager;
|
readonly EditorActionManager editorActionManager;
|
||||||
readonly ButtonWidget generateButtonWidget;
|
|
||||||
readonly ButtonWidget generateRandomButtonWidget;
|
|
||||||
readonly World world;
|
readonly World world;
|
||||||
readonly WorldRenderer worldRenderer;
|
readonly WorldRenderer worldRenderer;
|
||||||
readonly ModData modData;
|
readonly ModData modData;
|
||||||
|
|
||||||
// nullable
|
// nullable
|
||||||
IMapGeneratorInfo selectedGenerator;
|
IMapGeneratorInfo selectedGenerator;
|
||||||
|
IMapGeneratorSettings selectedSettings;
|
||||||
readonly Dictionary<IMapGeneratorInfo, MapGeneratorSettings> generatorsToSettings;
|
|
||||||
readonly Dictionary<IMapGeneratorInfo, Dictionary<MapGeneratorSettings.Option, MapGeneratorSettings.Choice>> generatorsToSettingsChoices;
|
|
||||||
|
|
||||||
readonly ScrollPanelWidget settingsPanel;
|
readonly ScrollPanelWidget settingsPanel;
|
||||||
readonly Widget checkboxSettingTemplate;
|
readonly Widget checkboxSettingTemplate;
|
||||||
@@ -60,42 +54,25 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
this.worldRenderer = worldRenderer;
|
this.worldRenderer = worldRenderer;
|
||||||
this.modData = modData;
|
this.modData = modData;
|
||||||
|
|
||||||
selectedGenerator = null;
|
|
||||||
generatorsToSettings = [];
|
|
||||||
generatorsToSettingsChoices = [];
|
|
||||||
|
|
||||||
var mapGenerators = new List<IMapGeneratorInfo>();
|
|
||||||
var terrainInfo = modData.DefaultTerrainInfo[world.Map.Tileset];
|
|
||||||
foreach (var generator in world.Map.Rules.Actors[SystemActors.EditorWorld].TraitInfos<IMapGeneratorInfo>())
|
|
||||||
{
|
|
||||||
var settings = generator.GetSettings(terrainInfo);
|
|
||||||
if (settings == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var choices = settings.DefaultChoices();
|
|
||||||
mapGenerators.Add(generator);
|
|
||||||
generatorsToSettingsChoices.Add(generator, choices);
|
|
||||||
generatorsToSettings.Add(generator, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
generateButtonWidget = widget.Get<ButtonWidget>("GENERATE_BUTTON");
|
|
||||||
generateRandomButtonWidget = widget.Get<ButtonWidget>("GENERATE_RANDOM_BUTTON");
|
|
||||||
|
|
||||||
settingsPanel = widget.Get<ScrollPanelWidget>("SETTINGS_PANEL");
|
settingsPanel = widget.Get<ScrollPanelWidget>("SETTINGS_PANEL");
|
||||||
checkboxSettingTemplate = settingsPanel.Get<Widget>("CHECKBOX_TEMPLATE");
|
checkboxSettingTemplate = settingsPanel.Get<Widget>("CHECKBOX_TEMPLATE");
|
||||||
textSettingTemplate = settingsPanel.Get<Widget>("TEXT_TEMPLATE");
|
textSettingTemplate = settingsPanel.Get<Widget>("TEXT_TEMPLATE");
|
||||||
dropDownSettingTemplate = settingsPanel.Get<Widget>("DROPDOWN_TEMPLATE");
|
dropDownSettingTemplate = settingsPanel.Get<Widget>("DROPDOWN_TEMPLATE");
|
||||||
|
|
||||||
|
var generateButtonWidget = widget.Get<ButtonWidget>("GENERATE_BUTTON");
|
||||||
generateButtonWidget.OnClick = GenerateMap;
|
generateButtonWidget.OnClick = GenerateMap;
|
||||||
|
|
||||||
|
var generateRandomButtonWidget = widget.Get<ButtonWidget>("GENERATE_RANDOM_BUTTON");
|
||||||
generateRandomButtonWidget.OnClick = () =>
|
generateRandomButtonWidget.OnClick = () =>
|
||||||
{
|
{
|
||||||
Randomize();
|
selectedSettings?.Randomize(world.LocalRandom);
|
||||||
|
UpdateSettingsUi();
|
||||||
GenerateMap();
|
GenerateMap();
|
||||||
};
|
};
|
||||||
|
|
||||||
var generatorDropDown = widget.Get<DropDownButtonWidget>("GENERATOR");
|
var generatorDropDown = widget.Get<DropDownButtonWidget>("GENERATOR");
|
||||||
ChangeGenerator(mapGenerators.FirstOrDefault());
|
var mapGenerators = world.Map.Rules.Actors[SystemActors.EditorWorld].TraitInfos<IMapGeneratorInfo>();
|
||||||
if (selectedGenerator != null)
|
if (mapGenerators.Count > 0)
|
||||||
{
|
{
|
||||||
var label = new CachedTransform<IMapGeneratorInfo, string>(g => FluentProvider.GetMessage(g.Name));
|
var label = new CachedTransform<IMapGeneratorInfo, string>(g => FluentProvider.GetMessage(g.Name));
|
||||||
generatorDropDown.GetText = () => label.Update(selectedGenerator);
|
generatorDropDown.GetText = () => label.Update(selectedGenerator);
|
||||||
@@ -104,7 +81,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
ScrollItemWidget SetupItem(IMapGeneratorInfo g, ScrollItemWidget template)
|
ScrollItemWidget SetupItem(IMapGeneratorInfo g, ScrollItemWidget template)
|
||||||
{
|
{
|
||||||
bool IsSelected() => g.Type == selectedGenerator.Type;
|
bool IsSelected() => g.Type == selectedGenerator.Type;
|
||||||
void OnClick() => ChangeGenerator(mapGenerators.First(generator => generator.Type == g.Type));
|
void OnClick() => ChangeGenerator(g);
|
||||||
var item = ScrollItemWidget.Setup(template, IsSelected, OnClick);
|
var item = ScrollItemWidget.Setup(template, IsSelected, OnClick);
|
||||||
var label = FluentProvider.GetMessage(g.Name);
|
var label = FluentProvider.GetMessage(g.Name);
|
||||||
item.Get<LabelWidget>("LABEL").GetText = () => label;
|
item.Get<LabelWidget>("LABEL").GetText = () => label;
|
||||||
@@ -120,6 +97,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
generateRandomButtonWidget.IsDisabled = () => true;
|
generateRandomButtonWidget.IsDisabled = () => true;
|
||||||
generatorDropDown.IsDisabled = () => true;
|
generatorDropDown.IsDisabled = () => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChangeGenerator(mapGenerators.FirstOrDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class RandomMapEditorAction : IEditorAction
|
sealed class RandomMapEditorAction : IEditorAction
|
||||||
@@ -155,6 +134,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
void ChangeGenerator(IMapGeneratorInfo newGenerator)
|
void ChangeGenerator(IMapGeneratorInfo newGenerator)
|
||||||
{
|
{
|
||||||
selectedGenerator = newGenerator;
|
selectedGenerator = newGenerator;
|
||||||
|
selectedSettings = newGenerator?.GetSettings();
|
||||||
|
|
||||||
UpdateSettingsUi();
|
UpdateSettingsUi();
|
||||||
}
|
}
|
||||||
@@ -166,89 +146,119 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
if (selectedGenerator == null)
|
if (selectedGenerator == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var settings = generatorsToSettings[selectedGenerator];
|
foreach (var o in selectedSettings.Options)
|
||||||
var choices = generatorsToSettingsChoices[selectedGenerator];
|
|
||||||
foreach (var option in settings.Options)
|
|
||||||
{
|
{
|
||||||
Widget settingWidget;
|
Widget settingWidget = null;
|
||||||
|
switch (o)
|
||||||
switch (option.Ui)
|
|
||||||
{
|
{
|
||||||
case MapGeneratorSettings.UiType.Hidden:
|
case MapGeneratorBooleanOption bo:
|
||||||
continue;
|
{
|
||||||
|
settingWidget = checkboxSettingTemplate.Clone();
|
||||||
|
var checkboxWidget = settingWidget.Get<CheckboxWidget>("CHECKBOX");
|
||||||
|
var label = FluentProvider.GetMessage(bo.Label);
|
||||||
|
checkboxWidget.GetText = () => label;
|
||||||
|
checkboxWidget.IsChecked = () => bo.Value;
|
||||||
|
checkboxWidget.OnClick = () => bo.Value ^= true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MapGeneratorSettings.UiType.DropDown:
|
case MapGeneratorIntegerOption io:
|
||||||
|
{
|
||||||
|
settingWidget = textSettingTemplate.Clone();
|
||||||
|
var labelWidget = settingWidget.Get<LabelWidget>("LABEL");
|
||||||
|
var label = FluentProvider.GetMessage(io.Label);
|
||||||
|
labelWidget.GetText = () => label;
|
||||||
|
var textFieldWidget = settingWidget.Get<TextFieldWidget>("INPUT");
|
||||||
|
textFieldWidget.Type = TextFieldType.Integer;
|
||||||
|
textFieldWidget.Text = FieldSaver.FormatValue(io.Value);
|
||||||
|
textFieldWidget.OnTextEdited = () =>
|
||||||
|
{
|
||||||
|
var valid = int.TryParse(textFieldWidget.Text, out io.Value);
|
||||||
|
textFieldWidget.IsValid = () => valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
textFieldWidget.OnEscKey = _ => { textFieldWidget.YieldKeyboardFocus(); return true; };
|
||||||
|
textFieldWidget.OnEnterKey = _ => { textFieldWidget.YieldKeyboardFocus(); return true; };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MapGeneratorMultiIntegerChoiceOption mio:
|
||||||
{
|
{
|
||||||
settingWidget = dropDownSettingTemplate.Clone();
|
settingWidget = dropDownSettingTemplate.Clone();
|
||||||
var label = settingWidget.Get<LabelWidget>("LABEL");
|
var labelWidget = settingWidget.Get<LabelWidget>("LABEL");
|
||||||
label.GetText = () => option.Label;
|
var label = FluentProvider.GetMessage(mio.Label);
|
||||||
var dropDown = settingWidget.Get<DropDownButtonWidget>("DROPDOWN");
|
labelWidget.GetText = () => label;
|
||||||
dropDown.GetText = () => choices[option].Label;
|
|
||||||
dropDown.OnMouseDown = _ =>
|
|
||||||
{
|
|
||||||
ScrollItemWidget SetupItem(MapGeneratorSettings.Choice choice, ScrollItemWidget template)
|
|
||||||
{
|
|
||||||
bool IsSelected() => choice == choices[option];
|
|
||||||
void OnClick() => choices[option] = choice;
|
|
||||||
var item = ScrollItemWidget.Setup(template, IsSelected, OnClick);
|
|
||||||
item.Get<LabelWidget>("LABEL").GetText = () => choice.Label;
|
|
||||||
item.GetTooltipText =
|
|
||||||
choice.Description != null
|
|
||||||
? () => choice.Description
|
|
||||||
: null;
|
|
||||||
|
|
||||||
|
var labelCache = new CachedTransform<int, string>(v => FieldSaver.FormatValue(v));
|
||||||
|
var dropDownWidget = settingWidget.Get<DropDownButtonWidget>("DROPDOWN");
|
||||||
|
dropDownWidget.GetText = () => labelCache.Update(mio.Value);
|
||||||
|
dropDownWidget.OnMouseDown = _ =>
|
||||||
|
{
|
||||||
|
ScrollItemWidget SetupItem(int choice, ScrollItemWidget template)
|
||||||
|
{
|
||||||
|
bool IsSelected() => choice == mio.Value;
|
||||||
|
void OnClick() => mio.Value = choice;
|
||||||
|
var item = ScrollItemWidget.Setup(template, IsSelected, OnClick);
|
||||||
|
|
||||||
|
var itemLabel = FieldSaver.FormatValue(choice);
|
||||||
|
item.Get<LabelWidget>("LABEL").GetText = () => itemLabel;
|
||||||
|
item.GetTooltipText = null;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
dropDown.ShowDropDown("LABEL_DROPDOWN_WITH_TOOLTIP_TEMPLATE", option.Choices.Count * 30, option.Choices, SetupItem);
|
dropDownWidget.ShowDropDown("LABEL_DROPDOWN_WITH_TOOLTIP_TEMPLATE", mio.Choices.Length * 30, mio.Choices, SetupItem);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MapGeneratorSettings.UiType.Checkbox:
|
case MapGeneratorMultiChoiceOption mo:
|
||||||
{
|
{
|
||||||
if (option.Choices.Count != 2)
|
var validChoices = mo.ValidChoices(world.Map.Rules.TerrainInfo);
|
||||||
throw new InvalidOperationException("Checkbox option that does not have two choices");
|
if (!validChoices.Contains(mo.Value))
|
||||||
settingWidget = checkboxSettingTemplate.Clone();
|
mo.Value = mo.Default?.FirstOrDefault(validChoices.Contains) ?? validChoices.FirstOrDefault();
|
||||||
var checkbox = settingWidget.Get<CheckboxWidget>("CHECKBOX");
|
|
||||||
checkbox.GetText = () => option.Label;
|
|
||||||
checkbox.IsChecked = () => choices[option] == option.Choices[1];
|
|
||||||
checkbox.OnClick = () =>
|
|
||||||
choices[option] =
|
|
||||||
choices[option] == option.Choices[1]
|
|
||||||
? option.Choices[0]
|
|
||||||
: option.Choices[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MapGeneratorSettings.UiType.Integer:
|
if (mo.Label != null && validChoices.Count > 0)
|
||||||
case MapGeneratorSettings.UiType.Float:
|
|
||||||
case MapGeneratorSettings.UiType.String:
|
|
||||||
{
|
|
||||||
if (option.Choices.Count != 1)
|
|
||||||
throw new InvalidOperationException("Text option that does not have one choice");
|
|
||||||
settingWidget = textSettingTemplate.Clone();
|
|
||||||
var label = settingWidget.Get<LabelWidget>("LABEL");
|
|
||||||
label.GetText = () => option.Label;
|
|
||||||
var input = settingWidget.Get<TextFieldWidget>("INPUT");
|
|
||||||
input.Text = choices[option].Id;
|
|
||||||
input.OnTextEdited = () =>
|
|
||||||
{
|
{
|
||||||
var choice = choices[option].NewValue(input.Text);
|
settingWidget = dropDownSettingTemplate.Clone();
|
||||||
choices[option] = choice;
|
var labelWidget = settingWidget.Get<LabelWidget>("LABEL");
|
||||||
var valid = option.ValidateChoice(choice);
|
var label = FluentProvider.GetMessage(mo.Label);
|
||||||
input.IsValid = () => valid;
|
labelWidget.GetText = () => label;
|
||||||
};
|
|
||||||
|
var labelCache = new CachedTransform<string, string>(v => FluentProvider.GetMessage(mo.Choices[v].Label + ".label"));
|
||||||
|
var dropDownWidget = settingWidget.Get<DropDownButtonWidget>("DROPDOWN");
|
||||||
|
dropDownWidget.GetText = () => labelCache.Update(mo.Value);
|
||||||
|
dropDownWidget.OnMouseDown = _ =>
|
||||||
|
{
|
||||||
|
ScrollItemWidget SetupItem(string choice, ScrollItemWidget template)
|
||||||
|
{
|
||||||
|
bool IsSelected() => choice == mo.Value;
|
||||||
|
void OnClick() => mo.Value = choice;
|
||||||
|
var item = ScrollItemWidget.Setup(template, IsSelected, OnClick);
|
||||||
|
|
||||||
|
var itemLabel = FluentProvider.GetMessage(mo.Choices[choice].Label + ".label");
|
||||||
|
item.Get<LabelWidget>("LABEL").GetText = () => itemLabel;
|
||||||
|
if (FluentProvider.TryGetMessage(mo.Choices[choice].Label + ".description", out var desc))
|
||||||
|
item.GetTooltipText = () => desc;
|
||||||
|
else
|
||||||
|
item.GetTooltipText = null;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
dropDownWidget.ShowDropDown("LABEL_DROPDOWN_WITH_TOOLTIP_TEMPLATE", validChoices.Count * 30, validChoices, SetupItem);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
input.OnEscKey = _ => { input.YieldKeyboardFocus(); return true; };
|
|
||||||
input.OnEnterKey = _ => { input.YieldKeyboardFocus(); return true; };
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException("Unsupported MapGeneratorSettings.UiType");
|
throw new NotImplementedException($"Unhandled MapGeneratorOption type {o.GetType().Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settingWidget == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
settingWidget.IsVisible = () => true;
|
settingWidget.IsVisible = () => true;
|
||||||
settingsPanel.AddChild(settingWidget);
|
settingsPanel.AddChild(settingWidget);
|
||||||
}
|
}
|
||||||
@@ -266,18 +276,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
cancelText: StrFailedCancel);
|
cancelText: StrFailedCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Randomize()
|
|
||||||
{
|
|
||||||
var choices = generatorsToSettingsChoices[selectedGenerator];
|
|
||||||
foreach (var option in choices.Keys)
|
|
||||||
{
|
|
||||||
if (option.Random)
|
|
||||||
choices[option] = option.RandomChoice();
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateSettingsUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenerateMap()
|
void GenerateMap()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -293,22 +291,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
void GenerateMapMayThrow()
|
void GenerateMapMayThrow()
|
||||||
{
|
{
|
||||||
var map = world.Map;
|
var map = world.Map;
|
||||||
var tileset = modData.DefaultTerrainInfo[map.Tileset];
|
var terrainInfo = map.Rules.TerrainInfo;
|
||||||
var generatedMap = new Map(modData, tileset, map.MapSize.X, map.MapSize.Y);
|
var generatedMap = new Map(modData, terrainInfo, map.MapSize.X, map.MapSize.Y);
|
||||||
var bounds = map.Bounds;
|
var bounds = map.Bounds;
|
||||||
generatedMap.SetBounds(new PPos(bounds.Left, bounds.Top), new PPos(bounds.Right - 1, bounds.Bottom - 1));
|
generatedMap.SetBounds(new PPos(bounds.Left, bounds.Top), new PPos(bounds.Right - 1, bounds.Bottom - 1));
|
||||||
var choices = generatorsToSettingsChoices[selectedGenerator];
|
|
||||||
|
|
||||||
foreach (var optionChoice in choices)
|
var settings = selectedSettings.Compile(terrainInfo);
|
||||||
{
|
|
||||||
var option = optionChoice.Key;
|
|
||||||
var choice = optionChoice.Value;
|
|
||||||
if (!option.ValidateChoice(choice))
|
|
||||||
throw new MapGenerationException(
|
|
||||||
FluentProvider.GetMessage(StrBadOption, "option", option.Label));
|
|
||||||
}
|
|
||||||
|
|
||||||
var settings = generatorsToSettings[selectedGenerator].Compile(choices);
|
|
||||||
|
|
||||||
// Run main generator logic. May throw.
|
// Run main generator logic. May throw.
|
||||||
var generateStopwatch = Stopwatch.StartNew();
|
var generateStopwatch = Stopwatch.StartNew();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Type: experimental
|
Type: experimental
|
||||||
Name: map-generator-experimental
|
Name: map-generator-experimental
|
||||||
Settings:
|
Settings:
|
||||||
Option@hidden_defaults:
|
MultiChoiceOption@hidden_defaults:
|
||||||
Choice@hidden_defaults:
|
Choice@hidden_defaults:
|
||||||
Settings:
|
Settings:
|
||||||
TerrainFeatureSize: 20480
|
TerrainFeatureSize: 20480
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
ForestObstacles: Trees
|
ForestObstacles: Trees
|
||||||
UnplayableObstacles: Obstructions
|
UnplayableObstacles: Obstructions
|
||||||
CivilianBuildingsObstacles: CivilianBuildings
|
CivilianBuildingsObstacles: CivilianBuildings
|
||||||
Option@hidden_tileset_overrides:
|
MultiChoiceOption@hidden_tileset_overrides:
|
||||||
Choice@common:
|
Choice@common:
|
||||||
Tileset: DESERT,SNOW,TEMPERAT
|
Tileset: DESERT,SNOW,TEMPERAT
|
||||||
Settings:
|
Settings:
|
||||||
@@ -87,12 +87,11 @@
|
|||||||
RepaintTiles:
|
RepaintTiles:
|
||||||
255: Snow
|
255: Snow
|
||||||
1: Water
|
1: Water
|
||||||
Option@Seed:
|
IntegerOption@Seed:
|
||||||
Label: label-cnc-map-generator-option-seed
|
Label: label-cnc-map-generator-option-seed
|
||||||
Random: True
|
Parameter: Seed
|
||||||
Default: 0
|
Default: 0
|
||||||
Integer: Seed
|
MultiChoiceOption@TerrainType:
|
||||||
Option@TerrainType:
|
|
||||||
Label: label-cnc-map-generator-option-terrain-type
|
Label: label-cnc-map-generator-option-terrain-type
|
||||||
Priority: 2
|
Priority: 2
|
||||||
Default: Gardens,Rocky
|
Default: Gardens,Rocky
|
||||||
@@ -170,13 +169,13 @@
|
|||||||
Mountains: 1000
|
Mountains: 1000
|
||||||
Roughness: 850
|
Roughness: 850
|
||||||
MinimumTerrainContourSpacing: 5
|
MinimumTerrainContourSpacing: 5
|
||||||
Option@Rotations:
|
MultiIntegerChoiceOption@Rotations:
|
||||||
Label: label-cnc-map-generator-option-rotations
|
Label: label-cnc-map-generator-option-rotations
|
||||||
SimpleChoice: Rotations
|
Parameter: Rotations
|
||||||
Values: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
|
Choices: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
|
||||||
Default: 2
|
Default: 2
|
||||||
Priority: 1
|
Priority: 1
|
||||||
Option@Mirror:
|
MultiChoiceOption@Mirror:
|
||||||
Label: label-cnc-map-generator-option-mirror
|
Label: label-cnc-map-generator-option-mirror
|
||||||
Default: None
|
Default: None
|
||||||
Priority: 1
|
Priority: 1
|
||||||
@@ -200,7 +199,7 @@
|
|||||||
Label: label-cnc-map-generator-choice-mirror-top-right-matches-bottom-left
|
Label: label-cnc-map-generator-choice-mirror-top-right-matches-bottom-left
|
||||||
Settings:
|
Settings:
|
||||||
Mirror: TopRightMatchesBottomLeft
|
Mirror: TopRightMatchesBottomLeft
|
||||||
Option@Shape:
|
MultiChoiceOption@Shape:
|
||||||
Label: label-cnc-map-generator-option-shape
|
Label: label-cnc-map-generator-option-shape
|
||||||
Default: Square
|
Default: Square
|
||||||
Priority: 1
|
Priority: 1
|
||||||
@@ -217,13 +216,13 @@
|
|||||||
Tileset: DESERT
|
Tileset: DESERT
|
||||||
Settings:
|
Settings:
|
||||||
ExternalCircularBias: -1
|
ExternalCircularBias: -1
|
||||||
Option@Players:
|
MultiIntegerChoiceOption@Players:
|
||||||
Label: label-cnc-map-generator-option-players
|
Label: label-cnc-map-generator-option-players
|
||||||
SimpleChoice: Players
|
Parameter: Players
|
||||||
Values: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
|
Choices: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
|
||||||
Default: 1
|
Default: 1
|
||||||
Priority: 1
|
Priority: 1
|
||||||
Option@Resources:
|
MultiChoiceOption@Resources:
|
||||||
Label: label-cnc-map-generator-option-resources
|
Label: label-cnc-map-generator-option-resources
|
||||||
Default: Medium
|
Default: Medium
|
||||||
Choice@None:
|
Choice@None:
|
||||||
@@ -285,7 +284,7 @@
|
|||||||
ResourceSpawnWeights:
|
ResourceSpawnWeights:
|
||||||
MaximumExpansionResourceSpawns: 0
|
MaximumExpansionResourceSpawns: 0
|
||||||
MaximumResourceSpawnsPerExpansion: 1
|
MaximumResourceSpawnsPerExpansion: 1
|
||||||
Option@Buildings:
|
MultiChoiceOption@Buildings:
|
||||||
Label: label-cnc-map-generator-option-buildings
|
Label: label-cnc-map-generator-option-buildings
|
||||||
Default: Standard
|
Default: Standard
|
||||||
Choice@None:
|
Choice@None:
|
||||||
@@ -327,7 +326,7 @@
|
|||||||
MaximumBuildings: 10
|
MaximumBuildings: 10
|
||||||
BuildingWeights:
|
BuildingWeights:
|
||||||
v19: 1
|
v19: 1
|
||||||
Option@Density:
|
MultiChoiceOption@Density:
|
||||||
Label: label-cnc-map-generator-option-density
|
Label: label-cnc-map-generator-option-density
|
||||||
Default: Players
|
Default: Players
|
||||||
Priority: 1
|
Priority: 1
|
||||||
@@ -366,17 +365,17 @@
|
|||||||
Settings:
|
Settings:
|
||||||
AreaEntityBonus: 800
|
AreaEntityBonus: 800
|
||||||
PlayerCountEntityBonus: 0
|
PlayerCountEntityBonus: 0
|
||||||
Option@DenyWalledArea:
|
BooleanOption@DenyWalledArea:
|
||||||
Label: label-cnc-map-generator-option-deny-walled-areas
|
Label: label-cnc-map-generator-option-deny-walled-areas
|
||||||
Checkbox: DenyWalledAreas
|
Parameter: DenyWalledAreas
|
||||||
Default: True
|
Default: True
|
||||||
Priority: 1
|
Priority: 1
|
||||||
Option@Roads:
|
BooleanOption@Roads:
|
||||||
Label: label-cnc-map-generator-option-roads
|
Label: label-cnc-map-generator-option-roads
|
||||||
Checkbox: Roads
|
Parameter: Roads
|
||||||
Default: True
|
Default: True
|
||||||
Priority: 1
|
Priority: 1
|
||||||
Option@CivilianDensity:
|
MultiChoiceOption@CivilianDensity:
|
||||||
Label: label-cnc-map-generator-option-civilian-density
|
Label: label-cnc-map-generator-option-civilian-density
|
||||||
Default: Default
|
Default: Default
|
||||||
Priority: 3
|
Priority: 3
|
||||||
@@ -411,7 +410,7 @@
|
|||||||
Type: clear
|
Type: clear
|
||||||
Name: map-generator-clear
|
Name: map-generator-clear
|
||||||
Settings:
|
Settings:
|
||||||
Option@Tile:
|
MultiChoiceOption@Tile:
|
||||||
Label: label-clear-map-generator-option-tile
|
Label: label-clear-map-generator-option-tile
|
||||||
Choice@CommonClear:
|
Choice@CommonClear:
|
||||||
Label: label-clear-map-generator-choice-tile-clear
|
Label: label-clear-map-generator-choice-tile-clear
|
||||||
|
|||||||
@@ -1142,5 +1142,4 @@ keycode =
|
|||||||
## MapGeneratorToolLogic
|
## MapGeneratorToolLogic
|
||||||
label-map-generator-failed-cancel = Dismiss
|
label-map-generator-failed-cancel = Dismiss
|
||||||
notification-map-generator-generated = Generated using { $name }
|
notification-map-generator-generated = Generated using { $name }
|
||||||
notification-map-generator-bad-option = Option "{ $option }" is invalid
|
|
||||||
notification-map-generator-failed = Map generation failed
|
notification-map-generator-failed = Map generation failed
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Type: experimental
|
Type: experimental
|
||||||
Name: map-generator-experimental
|
Name: map-generator-experimental
|
||||||
Settings:
|
Settings:
|
||||||
Option@hidden_defaults:
|
MultiChoiceOption@hidden_defaults:
|
||||||
Choice@hidden_defaults:
|
Choice@hidden_defaults:
|
||||||
Settings:
|
Settings:
|
||||||
TerrainFeatureSize: 20480
|
TerrainFeatureSize: 20480
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
ForestObstacles: Trees
|
ForestObstacles: Trees
|
||||||
UnplayableObstacles: Obstructions
|
UnplayableObstacles: Obstructions
|
||||||
CivilianBuildingsObstacles: CivilianBuildings
|
CivilianBuildingsObstacles: CivilianBuildings
|
||||||
Option@hidden_tileset_overrides:
|
MultiChoiceOption@hidden_tileset_overrides:
|
||||||
Choice@desert:
|
Choice@desert:
|
||||||
Tileset: DESERT
|
Tileset: DESERT
|
||||||
Settings:
|
Settings:
|
||||||
@@ -86,12 +86,11 @@
|
|||||||
Settings:
|
Settings:
|
||||||
LandTile: 255
|
LandTile: 255
|
||||||
WaterTile: 1
|
WaterTile: 1
|
||||||
Option@Seed:
|
IntegerOption@Seed:
|
||||||
Label: label-ra-map-generator-option-seed
|
Label: label-ra-map-generator-option-seed
|
||||||
Random: True
|
Parameter: Seed
|
||||||
Default: 0
|
Default: 0
|
||||||
Integer: Seed
|
MultiChoiceOption@TerrainType:
|
||||||
Option@TerrainType:
|
|
||||||
Label: label-ra-map-generator-option-terrain-type
|
Label: label-ra-map-generator-option-terrain-type
|
||||||
Priority: 2
|
Priority: 2
|
||||||
Default: Gardens
|
Default: Gardens
|
||||||
@@ -193,13 +192,13 @@
|
|||||||
Forests: 0
|
Forests: 0
|
||||||
SpawnBuildSize: 6
|
SpawnBuildSize: 6
|
||||||
MinimumSpawnRadius: 4
|
MinimumSpawnRadius: 4
|
||||||
Option@Rotations:
|
MultiIntegerChoiceOption@Rotations:
|
||||||
Label: label-ra-map-generator-option-rotations
|
Label: label-ra-map-generator-option-rotations
|
||||||
SimpleChoice: Rotations
|
Parameter: Rotations
|
||||||
Values: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
|
Choices: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
|
||||||
Default: 2
|
Default: 2
|
||||||
Priority: 1
|
Priority: 1
|
||||||
Option@Mirror:
|
MultiChoiceOption@Mirror:
|
||||||
Label: label-ra-map-generator-option-mirror
|
Label: label-ra-map-generator-option-mirror
|
||||||
Default: None
|
Default: None
|
||||||
Priority: 1
|
Priority: 1
|
||||||
@@ -223,7 +222,7 @@
|
|||||||
Label: label-ra-map-generator-choice-mirror-top-right-matches-bottom-left
|
Label: label-ra-map-generator-choice-mirror-top-right-matches-bottom-left
|
||||||
Settings:
|
Settings:
|
||||||
Mirror: TopRightMatchesBottomLeft
|
Mirror: TopRightMatchesBottomLeft
|
||||||
Option@Shape:
|
MultiChoiceOption@Shape:
|
||||||
Label: label-ra-map-generator-option-shape
|
Label: label-ra-map-generator-option-shape
|
||||||
Default: Square
|
Default: Square
|
||||||
Priority: 1
|
Priority: 1
|
||||||
@@ -239,13 +238,13 @@
|
|||||||
Label: label-ra-map-generator-choice-shape-circle-water
|
Label: label-ra-map-generator-choice-shape-circle-water
|
||||||
Settings:
|
Settings:
|
||||||
ExternalCircularBias: -1
|
ExternalCircularBias: -1
|
||||||
Option@Players:
|
MultiIntegerChoiceOption@Players:
|
||||||
Label: label-ra-map-generator-option-players
|
Label: label-ra-map-generator-option-players
|
||||||
SimpleChoice: Players
|
Parameter: Players
|
||||||
Values: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
|
Choices: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
|
||||||
Default: 1
|
Default: 1
|
||||||
Priority: 1
|
Priority: 1
|
||||||
Option@Resources:
|
MultiChoiceOption@Resources:
|
||||||
Label: label-ra-map-generator-option-resources
|
Label: label-ra-map-generator-option-resources
|
||||||
Default: Medium
|
Default: Medium
|
||||||
Choice@None:
|
Choice@None:
|
||||||
@@ -303,7 +302,7 @@
|
|||||||
ResourceSpawnWeights:
|
ResourceSpawnWeights:
|
||||||
MaximumExpansionResourceSpawns: 0
|
MaximumExpansionResourceSpawns: 0
|
||||||
MaximumResourceSpawnsPerExpansion: 1
|
MaximumResourceSpawnsPerExpansion: 1
|
||||||
Option@Buildings:
|
MultiChoiceOption@Buildings:
|
||||||
Label: label-ra-map-generator-option-buildings
|
Label: label-ra-map-generator-option-buildings
|
||||||
Default: Standard
|
Default: Standard
|
||||||
Choice@None:
|
Choice@None:
|
||||||
@@ -346,7 +345,7 @@
|
|||||||
MaximumBuildings: 10
|
MaximumBuildings: 10
|
||||||
BuildingWeights:
|
BuildingWeights:
|
||||||
oilb: 1
|
oilb: 1
|
||||||
Option@Density:
|
MultiChoiceOption@Density:
|
||||||
Label: label-ra-map-generator-option-density
|
Label: label-ra-map-generator-option-density
|
||||||
Default: Players
|
Default: Players
|
||||||
Priority: 1
|
Priority: 1
|
||||||
@@ -385,17 +384,17 @@
|
|||||||
Settings:
|
Settings:
|
||||||
AreaEntityBonus: 800
|
AreaEntityBonus: 800
|
||||||
PlayerCountEntityBonus: 0
|
PlayerCountEntityBonus: 0
|
||||||
Option@DenyWalledArea:
|
BooleanOption@DenyWalledArea:
|
||||||
Label: label-ra-map-generator-option-deny-walled-areas
|
Label: label-ra-map-generator-option-deny-walled-areas
|
||||||
Checkbox: DenyWalledAreas
|
Parameter: DenyWalledAreas
|
||||||
Default: True
|
Default: True
|
||||||
Priority: 1
|
Priority: 1
|
||||||
Option@Roads:
|
BooleanOption@Roads:
|
||||||
Label: label-ra-map-generator-option-roads
|
Label: label-ra-map-generator-option-roads
|
||||||
Checkbox: Roads
|
Parameter: Roads
|
||||||
Default: True
|
Default: True
|
||||||
Priority: 1
|
Priority: 1
|
||||||
Option@CivilianDensity:
|
MultiChoiceOption@CivilianDensity:
|
||||||
Label: label-ra-map-generator-option-civilian-density
|
Label: label-ra-map-generator-option-civilian-density
|
||||||
Default: Default
|
Default: Default
|
||||||
Priority: 3
|
Priority: 3
|
||||||
@@ -430,7 +429,7 @@
|
|||||||
Type: clear
|
Type: clear
|
||||||
Name: map-generator-clear
|
Name: map-generator-clear
|
||||||
Settings:
|
Settings:
|
||||||
Option@Tile:
|
MultiChoiceOption@Tile:
|
||||||
Label: label-clear-map-generator-option-tile
|
Label: label-clear-map-generator-option-tile
|
||||||
Choice@DesertClear:
|
Choice@DesertClear:
|
||||||
Label: label-clear-map-generator-choice-tile-clear
|
Label: label-clear-map-generator-choice-tile-clear
|
||||||
|
|||||||
Reference in New Issue
Block a user