Markings (#7072)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using Robust.Shared.Random;
|
||||
using Content.Shared.Markings;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Shared.CharacterAppearance
|
||||
{
|
||||
@@ -11,7 +13,8 @@ namespace Content.Shared.CharacterAppearance
|
||||
string facialHairStyleId,
|
||||
Color facialHairColor,
|
||||
Color eyeColor,
|
||||
Color skinColor)
|
||||
Color skinColor,
|
||||
MarkingsSet markings)
|
||||
{
|
||||
HairStyleId = hairStyleId;
|
||||
HairColor = ClampColor(hairColor);
|
||||
@@ -19,6 +22,7 @@ namespace Content.Shared.CharacterAppearance
|
||||
FacialHairColor = ClampColor(facialHairColor);
|
||||
EyeColor = ClampColor(eyeColor);
|
||||
SkinColor = ClampColor(skinColor);
|
||||
Markings = markings;
|
||||
}
|
||||
|
||||
public string HairStyleId { get; }
|
||||
@@ -27,35 +31,41 @@ namespace Content.Shared.CharacterAppearance
|
||||
public Color FacialHairColor { get; }
|
||||
public Color EyeColor { get; }
|
||||
public Color SkinColor { get; }
|
||||
public MarkingsSet Markings { get; }
|
||||
|
||||
public HumanoidCharacterAppearance WithHairStyleName(string newName)
|
||||
{
|
||||
return new(newName, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor);
|
||||
return new(newName, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings);
|
||||
}
|
||||
|
||||
public HumanoidCharacterAppearance WithHairColor(Color newColor)
|
||||
{
|
||||
return new(HairStyleId, newColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor);
|
||||
return new(HairStyleId, newColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings);
|
||||
}
|
||||
|
||||
public HumanoidCharacterAppearance WithFacialHairStyleName(string newName)
|
||||
{
|
||||
return new(HairStyleId, HairColor, newName, FacialHairColor, EyeColor, SkinColor);
|
||||
return new(HairStyleId, HairColor, newName, FacialHairColor, EyeColor, SkinColor, Markings);
|
||||
}
|
||||
|
||||
public HumanoidCharacterAppearance WithFacialHairColor(Color newColor)
|
||||
{
|
||||
return new(HairStyleId, HairColor, FacialHairStyleId, newColor, EyeColor, SkinColor);
|
||||
return new(HairStyleId, HairColor, FacialHairStyleId, newColor, EyeColor, SkinColor, Markings);
|
||||
}
|
||||
|
||||
public HumanoidCharacterAppearance WithEyeColor(Color newColor)
|
||||
{
|
||||
return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, newColor, SkinColor);
|
||||
return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, newColor, SkinColor, Markings);
|
||||
}
|
||||
|
||||
public HumanoidCharacterAppearance WithSkinColor(Color newColor)
|
||||
{
|
||||
return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, newColor);
|
||||
return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, newColor, Markings);
|
||||
}
|
||||
|
||||
public HumanoidCharacterAppearance WithMarkings(MarkingsSet newMarkings)
|
||||
{
|
||||
return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, newMarkings);
|
||||
}
|
||||
|
||||
public static HumanoidCharacterAppearance Default()
|
||||
@@ -66,7 +76,8 @@ namespace Content.Shared.CharacterAppearance
|
||||
HairStyles.DefaultFacialHairStyle,
|
||||
Color.Black,
|
||||
Color.Black,
|
||||
Color.FromHex("#C0967F")
|
||||
Color.FromHex("#C0967F"),
|
||||
new MarkingsSet()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,7 +101,7 @@ namespace Content.Shared.CharacterAppearance
|
||||
.WithBlue(RandomizeColor(newHairColor.B));
|
||||
|
||||
// TODO: Add random eye and skin color
|
||||
return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor, Color.Black, Color.FromHex("#C0967F"));
|
||||
return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor, Color.Black, Color.FromHex("#C0967F"), new MarkingsSet());
|
||||
|
||||
float RandomizeColor(float channel)
|
||||
{
|
||||
@@ -103,7 +114,7 @@ namespace Content.Shared.CharacterAppearance
|
||||
return new(color.RByte, color.GByte, color.BByte);
|
||||
}
|
||||
|
||||
public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance)
|
||||
public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<SpriteAccessoryManager>();
|
||||
var hairStyleId = appearance.HairStyleId;
|
||||
@@ -123,13 +134,17 @@ namespace Content.Shared.CharacterAppearance
|
||||
var eyeColor = ClampColor(appearance.EyeColor);
|
||||
var skinColor = ClampColor(appearance.SkinColor);
|
||||
|
||||
var validMarkingsSet = MarkingsSet.EnsureValid(appearance.Markings);
|
||||
validMarkingsSet = MarkingsSet.FilterSpecies(validMarkingsSet, species);
|
||||
|
||||
return new HumanoidCharacterAppearance(
|
||||
hairStyleId,
|
||||
hairColor,
|
||||
facialHairStyleId,
|
||||
facialHairColor,
|
||||
eyeColor,
|
||||
skinColor);
|
||||
skinColor,
|
||||
validMarkingsSet);
|
||||
}
|
||||
|
||||
public bool MemberwiseEquals(ICharacterAppearance maybeOther)
|
||||
@@ -141,6 +156,7 @@ namespace Content.Shared.CharacterAppearance
|
||||
if (!FacialHairColor.Equals(other.FacialHairColor)) return false;
|
||||
if (!EyeColor.Equals(other.EyeColor)) return false;
|
||||
if (!SkinColor.Equals(other.SkinColor)) return false;
|
||||
if (!Markings.Equals(other.Markings)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ namespace Content.Shared.CharacterAppearance
|
||||
[Serializable, NetSerializable]
|
||||
public enum HumanoidVisualLayers : byte
|
||||
{
|
||||
TailBehind,
|
||||
Tail,
|
||||
Hair,
|
||||
FacialHair,
|
||||
Chest,
|
||||
Head,
|
||||
Snout,
|
||||
Frills,
|
||||
Horns,
|
||||
HeadSide, // side parts (i.e., frills)
|
||||
HeadTop, // top parts (i.e., ears)
|
||||
Eyes,
|
||||
RArm,
|
||||
LArm,
|
||||
@@ -22,7 +22,6 @@ namespace Content.Shared.CharacterAppearance
|
||||
LLeg,
|
||||
RFoot,
|
||||
LFoot,
|
||||
TailFront,
|
||||
Handcuffs,
|
||||
StencilMask,
|
||||
Fire,
|
||||
|
||||
@@ -17,14 +17,13 @@ namespace Content.Shared.CharacterAppearance
|
||||
yield return HumanoidVisualLayers.Chest;
|
||||
break;
|
||||
case BodyPartType.Tail:
|
||||
yield return HumanoidVisualLayers.TailFront;
|
||||
yield return HumanoidVisualLayers.TailBehind;
|
||||
yield return HumanoidVisualLayers.Tail;
|
||||
break;
|
||||
case BodyPartType.Head:
|
||||
yield return HumanoidVisualLayers.Head;
|
||||
yield return HumanoidVisualLayers.Snout;
|
||||
yield return HumanoidVisualLayers.Frills;
|
||||
yield return HumanoidVisualLayers.Horns;
|
||||
yield return HumanoidVisualLayers.HeadSide;
|
||||
yield return HumanoidVisualLayers.HeadTop;
|
||||
yield return HumanoidVisualLayers.Eyes;
|
||||
yield return HumanoidVisualLayers.FacialHair;
|
||||
yield return HumanoidVisualLayers.Hair;
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.IoC;
|
||||
using Content.Shared.Localizations;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Markings;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
@@ -38,6 +39,7 @@ namespace Content.Shared.Entry
|
||||
_initTileDefinitions();
|
||||
CheckReactions();
|
||||
IoCManager.Resolve<SpriteAccessoryManager>().Initialize();
|
||||
IoCManager.Resolve<MarkingManager>().Initialize();
|
||||
}
|
||||
|
||||
private void CheckReactions()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.CharacterAppearance;
|
||||
using Content.Shared.Markings;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Shared.IoC
|
||||
@@ -8,6 +9,7 @@ namespace Content.Shared.IoC
|
||||
public static void Register()
|
||||
{
|
||||
IoCManager.Register<SpriteAccessoryManager, SpriteAccessoryManager>();
|
||||
IoCManager.Register<MarkingManager, MarkingManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
105
Content.Shared/Markings/Marking.cs
Normal file
105
Content.Shared/Markings/Marking.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Shared.Markings
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class Marking : IEquatable<Marking>, IComparable<Marking>, IComparable<string>
|
||||
{
|
||||
private List<Color> _markingColors = new();
|
||||
|
||||
private Marking(string markingId,
|
||||
List<Color> markingColors)
|
||||
{
|
||||
MarkingId = markingId;
|
||||
_markingColors = markingColors;
|
||||
}
|
||||
|
||||
public Marking(string markingId,
|
||||
IReadOnlyList<Color> markingColors)
|
||||
: this(markingId, new List<Color>(markingColors))
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
public Marking(string markingId)
|
||||
: this(markingId, new List<Color>())
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
public Marking(string markingId, int colorCount)
|
||||
{
|
||||
MarkingId = markingId;
|
||||
List<Color> colors = new();
|
||||
for (int i = 0; i < colorCount; i++)
|
||||
colors.Add(Color.White);
|
||||
_markingColors = colors;
|
||||
}
|
||||
|
||||
[DataField("markingId")]
|
||||
[ViewVariables]
|
||||
public string MarkingId { get; } = default!;
|
||||
|
||||
[DataField("markingColor")]
|
||||
[ViewVariables]
|
||||
public IReadOnlyList<Color> MarkingColors => _markingColors;
|
||||
|
||||
public void SetColor(int colorIndex, Color color) =>
|
||||
_markingColors[colorIndex] = color;
|
||||
|
||||
public int CompareTo(Marking? marking)
|
||||
{
|
||||
if (marking == null) return 1;
|
||||
else return this.MarkingId.CompareTo(marking.MarkingId);
|
||||
}
|
||||
|
||||
public int CompareTo(string? markingId)
|
||||
{
|
||||
if (markingId == null) return 1;
|
||||
return this.MarkingId.CompareTo(markingId);
|
||||
}
|
||||
|
||||
public bool Equals(Marking? other)
|
||||
{
|
||||
if (other == null) return false;
|
||||
return (this.MarkingId.Equals(other.MarkingId));
|
||||
}
|
||||
|
||||
|
||||
// look this could be better but I don't think serializing
|
||||
// colors is the correct thing to do
|
||||
//
|
||||
// this is still janky imo but serializing a color and feeding
|
||||
// it into the default JSON serializer (which is just *fine*)
|
||||
// doesn't seem to have compatible interfaces? this 'works'
|
||||
// for now but should eventually be improved so that this can,
|
||||
// in fact just be serialized through a convenient interface
|
||||
new public string ToString()
|
||||
{
|
||||
// reserved character
|
||||
string sanitizedName = this.MarkingId.Replace('@', '_');
|
||||
List<string> colorStringList = new();
|
||||
foreach (Color color in _markingColors)
|
||||
colorStringList.Add(color.ToHex());
|
||||
|
||||
return $"{sanitizedName}@{String.Join(',', colorStringList)}";
|
||||
}
|
||||
|
||||
public static Marking? ParseFromDbString(string input)
|
||||
{
|
||||
if (input.Length == 0) return null;
|
||||
var split = input.Split('@');
|
||||
if (split.Length != 2) return null;
|
||||
List<Color> colorList = new();
|
||||
foreach (string color in split[1].Split(','))
|
||||
colorList.Add(Color.FromHex(color));
|
||||
|
||||
return new Marking(split[0], colorList);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Content.Shared/Markings/MarkingCategories.cs
Normal file
19
Content.Shared/Markings/MarkingCategories.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Markings
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public enum MarkingCategories : byte
|
||||
{
|
||||
Head,
|
||||
HeadTop,
|
||||
HeadSide,
|
||||
Snout,
|
||||
Chest,
|
||||
Arms,
|
||||
Legs,
|
||||
Tail,
|
||||
Overlay
|
||||
}
|
||||
}
|
||||
68
Content.Shared/Markings/MarkingManager.cs
Normal file
68
Content.Shared/Markings/MarkingManager.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Markings
|
||||
{
|
||||
public sealed class MarkingManager
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
private readonly List<MarkingPrototype> _index = new();
|
||||
private readonly Dictionary<MarkingCategories, List<MarkingPrototype>> _markingDict = new();
|
||||
private readonly Dictionary<string, MarkingPrototype> _markings = new();
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_prototypeManager.PrototypesReloaded += OnPrototypeReload;
|
||||
|
||||
foreach (var category in Enum.GetValues<MarkingCategories>())
|
||||
_markingDict.Add(category, new List<MarkingPrototype>());
|
||||
|
||||
foreach (var prototype in _prototypeManager.EnumeratePrototypes<MarkingPrototype>())
|
||||
{
|
||||
_index.Add(prototype);
|
||||
_markingDict[prototype.MarkingCategory].Add(prototype);
|
||||
_markings.Add(prototype.ID, prototype);
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, MarkingPrototype> Markings() => _markings;
|
||||
public IReadOnlyDictionary<MarkingCategories, List<MarkingPrototype>> CategorizedMarkings() => _markingDict;
|
||||
|
||||
public IReadOnlyDictionary<MarkingCategories, List<MarkingPrototype>> MarkingsBySpecies(string species)
|
||||
{
|
||||
var result = new Dictionary<MarkingCategories, List<MarkingPrototype>>(_markingDict);
|
||||
|
||||
foreach (var list in result.Values)
|
||||
{
|
||||
list.RemoveAll(marking => marking.SpeciesRestrictions != null && marking.SpeciesRestrictions.Contains(species));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool IsValidMarking(Marking marking, [NotNullWhen(true)] out MarkingPrototype? markingResult)
|
||||
{
|
||||
return _markings.TryGetValue(marking.MarkingId, out markingResult);
|
||||
}
|
||||
|
||||
private void OnPrototypeReload(PrototypesReloadedEventArgs args)
|
||||
{
|
||||
if(!args.ByType.TryGetValue(typeof(MarkingPrototype), out var set))
|
||||
return;
|
||||
|
||||
|
||||
_index.RemoveAll(i => set.Modified.ContainsKey(i.ID));
|
||||
|
||||
foreach (var prototype in set.Modified.Values)
|
||||
{
|
||||
var markingPrototype = (MarkingPrototype) prototype;
|
||||
_index.Add(markingPrototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Content.Shared/Markings/MarkingPrototype.cs
Normal file
39
Content.Shared/Markings/MarkingPrototype.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.CharacterAppearance;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Markings
|
||||
{
|
||||
[Prototype("marking")]
|
||||
public sealed class MarkingPrototype : IPrototype
|
||||
{
|
||||
[IdDataField]
|
||||
public string ID { get; } = "uwu";
|
||||
|
||||
public string Name { get; private set; } = default!;
|
||||
|
||||
[DataField("bodyPart", required: true)]
|
||||
public HumanoidVisualLayers BodyPart { get; } = default!;
|
||||
|
||||
[DataField("markingCategory", required: true)]
|
||||
public MarkingCategories MarkingCategory { get; } = default!;
|
||||
|
||||
[DataField("speciesRestriction")]
|
||||
public List<string>? SpeciesRestrictions { get; }
|
||||
|
||||
[DataField("followSkinColor")]
|
||||
public bool FollowSkinColor { get; } = false;
|
||||
|
||||
[DataField("sprites", required: true)]
|
||||
public List<SpriteSpecifier> Sprites { get; private set; } = default!;
|
||||
|
||||
public Marking AsMarking()
|
||||
{
|
||||
return new Marking(ID, Sprites.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Content.Shared/Markings/MarkingsComponent.cs
Normal file
58
Content.Shared/Markings/MarkingsComponent.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.CharacterAppearance;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Markings
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class MarkingsComponent : Component
|
||||
{
|
||||
public Dictionary<HumanoidVisualLayers, List<Marking>> ActiveMarkings = new();
|
||||
|
||||
// Layer points for the attached mob. This is verified client side (but should be verified server side, eventually as well),
|
||||
// but upon render for the given entity with this component, it will start subtracting
|
||||
// points from this set. Upon depletion, no more sprites in this layer will be
|
||||
// rendered. If an entry is null, however, it is considered 'unlimited points' for
|
||||
// that layer.
|
||||
//
|
||||
// Layer points are useful for restricting the amount of markings a specific layer can use
|
||||
// for specific mobs (i.e., a lizard should only use one set of horns and maybe two frills),
|
||||
// and all species with selectable tails should have exactly one tail)
|
||||
//
|
||||
// If something is required, then something must be selected in that category. Otherwise,
|
||||
// the first instance of a marking in that category will be added to a character
|
||||
// upon round start.
|
||||
[DataField("layerPoints")]
|
||||
public Dictionary<MarkingCategories, MarkingPoints> LayerPoints = new();
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
public sealed class MarkingPoints
|
||||
{
|
||||
[DataField("points", required: true)]
|
||||
public int Points = 0;
|
||||
[DataField("required", required: true)]
|
||||
public bool Required = false;
|
||||
// Default markings for this layer.
|
||||
[DataField("defaultMarkings")]
|
||||
public List<string> DefaultMarkings = new();
|
||||
|
||||
public static Dictionary<MarkingCategories, MarkingPoints> CloneMarkingPointDictionary(Dictionary<MarkingCategories, MarkingPoints> self)
|
||||
{
|
||||
var clone = new Dictionary<MarkingCategories, MarkingPoints>();
|
||||
|
||||
foreach (var (category, points) in self)
|
||||
{
|
||||
clone[category] = new MarkingPoints()
|
||||
{
|
||||
Points = points.Points,
|
||||
Required = points.Required,
|
||||
DefaultMarkings = points.DefaultMarkings
|
||||
};
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
283
Content.Shared/Markings/MarkingsSet.cs
Normal file
283
Content.Shared/Markings/MarkingsSet.cs
Normal file
@@ -0,0 +1,283 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Markings;
|
||||
|
||||
// TODO: Maybe put points logic into here too? It would make some sense
|
||||
// but it would have to be a template loaded in, otherwise clients could
|
||||
// send really invalid points sets that would have to be verified on the
|
||||
// server/client every time
|
||||
//
|
||||
// currently marking point constraints are just validated upon data send
|
||||
// from the client's UI (which might be a nono, means that connections
|
||||
// can just send garbage marking sets and it will save on the server)
|
||||
// and when an entity is rendered, (which is OK enough)
|
||||
//
|
||||
// equally, we'd need to access references every time we wanted to get
|
||||
// the managers required, which... not *terrible* if we do null default
|
||||
// params
|
||||
[Serializable, NetSerializable]
|
||||
public class MarkingsSet : IEnumerable, IEquatable<MarkingsSet>
|
||||
{
|
||||
// if you want a rust style VecDeque, you're looking at
|
||||
// the wrong place, i just wanted a similar API + some
|
||||
// markings specific functions
|
||||
private List<Marking> _markings = new();
|
||||
|
||||
public int Count
|
||||
{
|
||||
get => _markings.Count;
|
||||
}
|
||||
|
||||
public MarkingsSet()
|
||||
{
|
||||
}
|
||||
|
||||
public MarkingsSet(List<Marking> markings)
|
||||
{
|
||||
_markings = markings;
|
||||
}
|
||||
|
||||
public MarkingsSet(MarkingsSet other)
|
||||
{
|
||||
_markings = new(other._markings);
|
||||
}
|
||||
|
||||
public Marking this[int idx] => Index(idx);
|
||||
|
||||
public Marking Index(int idx)
|
||||
{
|
||||
return _markings[idx];
|
||||
}
|
||||
|
||||
// Gets a marking idx spaces from the back of the list.
|
||||
public Marking IndexReverse(int idx)
|
||||
{
|
||||
return _markings[_markings.Count - 1 - idx];
|
||||
}
|
||||
|
||||
public void AddFront(Marking marking)
|
||||
{
|
||||
_markings.Insert(0, marking);
|
||||
}
|
||||
|
||||
public void AddBack(Marking marking)
|
||||
{
|
||||
_markings.Add(marking);
|
||||
}
|
||||
|
||||
public bool Remove(Marking marking)
|
||||
{
|
||||
return _markings.Remove(marking);
|
||||
}
|
||||
|
||||
public bool Contains(Marking marking)
|
||||
{
|
||||
return _markings.Contains(marking);
|
||||
}
|
||||
|
||||
public int FindIndexOf(string id)
|
||||
{
|
||||
return _markings.FindIndex(m => m.MarkingId == id);
|
||||
}
|
||||
|
||||
// Shifts a marking's rank upwards (i.e., towards the front of the list)
|
||||
public void ShiftRankUp(int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= _markings.Count || idx - 1 < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var temp = _markings[idx - 1];
|
||||
_markings[idx - 1] = _markings[idx];
|
||||
_markings[idx] = temp;
|
||||
}
|
||||
|
||||
// Shifts up from the back (i.e., 2nd position from end)
|
||||
public void ShiftRankUpFromEnd(int idx)
|
||||
{
|
||||
ShiftRankUp(Count - idx - 1);
|
||||
}
|
||||
|
||||
// Ditto, but the opposite direction.
|
||||
public void ShiftRankDown(int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= _markings.Count || idx + 1 >= _markings.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var temp = _markings[idx + 1];
|
||||
_markings[idx + 1] = _markings[idx];
|
||||
_markings[idx] = temp;
|
||||
}
|
||||
|
||||
// Ditto as above.
|
||||
public void ShiftRankDownFromEnd(int idx)
|
||||
{
|
||||
ShiftRankDown(Count - idx - 1);
|
||||
}
|
||||
|
||||
// Ensures that all markings in a set are valid.
|
||||
public static MarkingsSet EnsureValid(MarkingsSet set, MarkingManager? manager = null)
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
manager = IoCManager.Resolve<MarkingManager>();
|
||||
}
|
||||
|
||||
var newList = set._markings.Where(marking => manager.Markings().ContainsKey(marking.MarkingId)).ToList();
|
||||
|
||||
set._markings = newList;
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
// Filters out markings based on species.
|
||||
public static MarkingsSet FilterSpecies(MarkingsSet set, string species)
|
||||
{
|
||||
var _markingsManager = IoCManager.Resolve<MarkingManager>();
|
||||
var newList = set._markings.Where(marking =>
|
||||
{
|
||||
if (!_markingsManager.Markings().TryGetValue(marking.MarkingId, out MarkingPrototype? prototype))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prototype.SpeciesRestrictions != null)
|
||||
{
|
||||
if (!prototype.SpeciesRestrictions.Contains(species))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}).ToList();
|
||||
|
||||
set._markings = newList;
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
// Processes a MarkingsSet using the given dictionary of MarkingPoints.
|
||||
public static MarkingsSet ProcessPoints(MarkingsSet set, Dictionary<MarkingCategories, MarkingPoints> points)
|
||||
{
|
||||
var finalSet = new List<Marking>();
|
||||
var _markingsManager = IoCManager.Resolve<MarkingManager>();
|
||||
|
||||
foreach (var marking in set)
|
||||
{
|
||||
if (_markingsManager.Markings().TryGetValue(marking.MarkingId, out MarkingPrototype? markingPrototype))
|
||||
{
|
||||
if (points.TryGetValue(markingPrototype.MarkingCategory, out var pointsRemaining))
|
||||
{
|
||||
if (pointsRemaining.Points == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pointsRemaining.Points--;
|
||||
|
||||
finalSet.Add(marking);
|
||||
}
|
||||
else
|
||||
{
|
||||
// points don't exist otherwise
|
||||
finalSet.Add(marking);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set._markings = finalSet;
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return (IEnumerator) GetEnumerator();
|
||||
}
|
||||
|
||||
public MarkingsEnumerator GetEnumerator()
|
||||
{
|
||||
return new MarkingsEnumerator(_markings, false);
|
||||
}
|
||||
|
||||
public IEnumerator GetReverseEnumerator()
|
||||
{
|
||||
return (IEnumerator) new MarkingsEnumerator(_markings, true);
|
||||
}
|
||||
|
||||
public bool Equals(MarkingsSet? set)
|
||||
{
|
||||
if (set == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _markings.SequenceEqual(set._markings);
|
||||
}
|
||||
}
|
||||
|
||||
public class MarkingsEnumerator : IEnumerator
|
||||
{
|
||||
private List<Marking> _markings;
|
||||
private bool _reverse;
|
||||
|
||||
int position;
|
||||
|
||||
public MarkingsEnumerator(List<Marking> markings, bool reverse)
|
||||
{
|
||||
_markings = markings;
|
||||
_reverse = reverse;
|
||||
|
||||
if (_reverse)
|
||||
{
|
||||
position = _markings.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_reverse)
|
||||
{
|
||||
position--;
|
||||
return (position >= 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
position++;
|
||||
return (position < _markings.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
if (_reverse)
|
||||
{
|
||||
position = _markings.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = -1;
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get => _markings[position];
|
||||
}
|
||||
|
||||
public Marking Current
|
||||
{
|
||||
get => _markings[position];
|
||||
}
|
||||
}
|
||||
@@ -302,7 +302,7 @@ namespace Content.Shared.Preferences
|
||||
name = RandomName();
|
||||
}
|
||||
|
||||
var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance);
|
||||
var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species);
|
||||
|
||||
var prefsUnavailableMode = PreferenceUnavailable switch
|
||||
{
|
||||
|
||||
@@ -43,8 +43,6 @@ public sealed class SpeciesPrototype : IPrototype
|
||||
/// </summary>
|
||||
[DataField("skinColoration", required: true)]
|
||||
public SpeciesSkinColor SkinColoration { get; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
public enum SpeciesSkinColor
|
||||
|
||||
Reference in New Issue
Block a user