using System; using System.Collections.Generic; using System.Linq; using SS14.Shared.Prototypes; using SS14.Shared.Serialization; using SS14.Shared.Utility; using YamlDotNet.RepresentationModel; namespace Content.Shared.Construction { [Prototype("construction")] public class ConstructionPrototype : IPrototype, IIndexedPrototype { private string _name; private string _description; private SpriteSpecifier _icon; private List _keywords; private List _categorySegments; private List _stages = new List(); private ConstructionType _type; private string _id; private string _result; private string _placementMode; /// /// Friendly name displayed in the construction GUI. /// public string Name => _name; /// /// "Useful" description displayed in the construction GUI. /// public string Description => _description; /// /// Texture path inside the construction GUI. /// public SpriteSpecifier Icon => _icon; /// /// A list of keywords that are used for searching. /// public IReadOnlyList Keywords => _keywords; /// /// The split up segments of the category. /// public IReadOnlyList CategorySegments => _categorySegments; /// /// The list of stages of construction. /// Construction is separated into "stages" which is basically a state in a linear FSM. /// The stage has forward and optionally backwards "steps" which are the criteria to move around in the FSM. /// NOTE that the stages are mapped differently than they appear in the prototype. /// In the prototype, the forward step is displayed as "to move into this stage" and reverse "to move out of" /// Stage 0 is considered "construction not started" and last stage is considered "construction is finished". /// As such, neither last or 0 stage have actual stage DATA, only backward/forward steps respectively. /// This would be akward for a YAML prototype because it's always jagged. /// public IReadOnlyList Stages => _stages; public ConstructionType Type => _type; public string ID => _id; /// /// The prototype name of the entity prototype when construction is done. /// public string Result => _result; public string PlacementMode => _placementMode; public void LoadFrom(YamlMappingNode mapping) { var ser = YamlObjectSerializer.NewReader(mapping); _name = ser.ReadDataField("name"); ser.DataField(ref _id, "id", string.Empty); ser.DataField(ref _description, "description", string.Empty); ser.DataField(ref _icon, "icon", SpriteSpecifier.Invalid); ser.DataField(ref _type, "objecttype", ConstructionType.Structure); ser.DataField(ref _result, "result", null); ser.DataField(ref _placementMode, "placementmode", "PlaceFree"); _keywords = ser.ReadDataField>("keywords", new List()); { var cat = ser.ReadDataField("category"); var split = cat.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); _categorySegments = split.ToList(); } { SpriteSpecifier nextIcon = null; ConstructionStep nextBackward = null; foreach (var stepMap in mapping.GetNode("steps").Cast()) { var step = ReadStepPrototype(stepMap); _stages.Add(new ConstructionStage(step, nextIcon, nextBackward)); if (stepMap.TryGetNode("icon", out var node)) { nextIcon = SpriteSpecifier.FromYaml(node); } if (stepMap.TryGetNode("reverse", out YamlMappingNode revMap)) { nextBackward = ReadStepPrototype(revMap); } } _stages.Add(new ConstructionStage(null, nextIcon, nextBackward)); } } ConstructionStep ReadStepPrototype(YamlMappingNode step) { int amount = 1; if (step.TryGetNode("amount", out var node)) { amount = node.AsInt(); } if (step.TryGetNode("material", out node)) { return new ConstructionStepMaterial( node.AsEnum(), amount ); } if (step.TryGetNode("tool", out node)) { return new ConstructionStepTool( node.AsEnum(), amount ); } throw new InvalidOperationException("Not enough data specified to determine step."); } } public sealed class ConstructionStage { /// /// The icon of the construction frame at this stage. /// public readonly SpriteSpecifier Icon; /// /// The step that should be completed to move away from this stage to the next one. /// public readonly ConstructionStep Forward; /// /// The optional step that can be completed to move away from this stage to the previous one. /// public readonly ConstructionStep Backward; public ConstructionStage(ConstructionStep forward, SpriteSpecifier icon = null, ConstructionStep backward = null) { Icon = icon; Forward = forward; Backward = backward; } } public enum ConstructionType { Structure, Item, } public abstract class ConstructionStep { public readonly int Amount = 1; protected ConstructionStep(int amount) { Amount = amount; } } public class ConstructionStepTool : ConstructionStep { public readonly ToolType Tool; public ConstructionStepTool(ToolType tool, int amount) : base(amount) { Tool = tool; } public enum ToolType { Wrench, Welder, Screwdriver, Crowbar, Wirecutters, } } public class ConstructionStepMaterial : ConstructionStep { public readonly MaterialType Material; public ConstructionStepMaterial(MaterialType material, int amount) : base(amount) { Material = material; } public enum MaterialType { Metal, Glass, Cable, } } }