using Content.Shared.Examine; using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; using Content.Shared.Humanoid.Prototypes; using Content.Shared.IdentityManagement; using Content.Shared.Preferences; using Content.Shared.Verbs; using Robust.Shared.GameObjects.Components.Localization; using Robust.Shared.Prototypes; namespace Content.Server.Humanoid; public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem { [Dependency] private readonly MarkingManager _markingManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMarkingsSet); SubscribeLocalEvent(OnBaseLayersSet); SubscribeLocalEvent>(OnVerbsRequest); SubscribeLocalEvent(OnExamined); } private void OnExamined(EntityUid uid, HumanoidAppearanceComponent component, ExaminedEvent args) { var identity = Identity.Entity(uid, EntityManager); var species = GetSpeciesRepresentation(component.Species).ToLower(); var age = GetAgeRepresentation(component.Species, component.Age); args.PushText(Loc.GetString("humanoid-appearance-component-examine", ("user", identity), ("age", age), ("species", species))); } // this was done enough times that it only made sense to do it here /// /// Clones a humanoid's appearance to a target mob, provided they both have humanoid components. /// /// Source entity to fetch the original appearance from. /// Target entity to apply the source entity's appearance to. /// Source entity's humanoid component. /// Target entity's humanoid component. public void CloneAppearance(EntityUid source, EntityUid target, HumanoidAppearanceComponent? sourceHumanoid = null, HumanoidAppearanceComponent? targetHumanoid = null) { if (!Resolve(source, ref sourceHumanoid) || !Resolve(target, ref targetHumanoid)) { return; } targetHumanoid.Species = sourceHumanoid.Species; targetHumanoid.SkinColor = sourceHumanoid.SkinColor; targetHumanoid.EyeColor = sourceHumanoid.EyeColor; targetHumanoid.Age = sourceHumanoid.Age; SetSex(target, sourceHumanoid.Sex, false, targetHumanoid); targetHumanoid.CustomBaseLayers = new(sourceHumanoid.CustomBaseLayers); targetHumanoid.MarkingSet = new(sourceHumanoid.MarkingSet); targetHumanoid.Gender = sourceHumanoid.Gender; if (TryComp(target, out var grammar)) { grammar.Gender = sourceHumanoid.Gender; } Dirty(targetHumanoid); } /// /// Removes a marking from a humanoid by ID. /// /// Humanoid mob's UID /// The marking to try and remove. /// Whether to immediately sync this to the humanoid /// Humanoid component of the entity public void RemoveMarking(EntityUid uid, string marking, bool sync = true, HumanoidAppearanceComponent? humanoid = null) { if (!Resolve(uid, ref humanoid) || !_markingManager.Markings.TryGetValue(marking, out var prototype)) { return; } humanoid.MarkingSet.Remove(prototype.MarkingCategory, marking); if (sync) Dirty(humanoid); } /// /// Removes a marking from a humanoid by category and index. /// /// Humanoid mob's UID /// Category of the marking /// Index of the marking /// Humanoid component of the entity public void RemoveMarking(EntityUid uid, MarkingCategories category, int index, HumanoidAppearanceComponent? humanoid = null) { if (index < 0 || !Resolve(uid, ref humanoid) || !humanoid.MarkingSet.TryGetCategory(category, out var markings) || index >= markings.Count) { return; } humanoid.MarkingSet.Remove(category, index); Dirty(humanoid); } /// /// Sets the marking ID of the humanoid in a category at an index in the category's list. /// /// Humanoid mob's UID /// Category of the marking /// Index of the marking /// The marking ID to use /// Humanoid component of the entity public void SetMarkingId(EntityUid uid, MarkingCategories category, int index, string markingId, HumanoidAppearanceComponent? humanoid = null) { if (index < 0 || !_markingManager.MarkingsByCategory(category).TryGetValue(markingId, out var markingPrototype) || !Resolve(uid, ref humanoid) || !humanoid.MarkingSet.TryGetCategory(category, out var markings) || index >= markings.Count) { return; } var marking = markingPrototype.AsMarking(); for (var i = 0; i < marking.MarkingColors.Count && i < markings[index].MarkingColors.Count; i++) { marking.SetColor(i, markings[index].MarkingColors[i]); } humanoid.MarkingSet.Replace(category, index, marking); Dirty(humanoid); } /// /// Sets the marking colors of the humanoid in a category at an index in the category's list. /// /// Humanoid mob's UID /// Category of the marking /// Index of the marking /// The marking colors to use /// Humanoid component of the entity public void SetMarkingColor(EntityUid uid, MarkingCategories category, int index, List colors, HumanoidAppearanceComponent? humanoid = null) { if (index < 0 || !Resolve(uid, ref humanoid) || !humanoid.MarkingSet.TryGetCategory(category, out var markings) || index >= markings.Count) { return; } for (var i = 0; i < markings[index].MarkingColors.Count && i < colors.Count; i++) { markings[index].SetColor(i, colors[i]); } Dirty(humanoid); } /// /// Takes ID of the species prototype, returns UI-friendly name of the species. /// public string GetSpeciesRepresentation(string speciesId) { if (_prototypeManager.TryIndex(speciesId, out var species)) { return Loc.GetString(species.Name); } else { return Loc.GetString("humanoid-appearance-component-unknown-species"); } } public string GetAgeRepresentation(string species, int age) { _prototypeManager.TryIndex(species, out var speciesPrototype); if (speciesPrototype == null) { Logger.Error("Tried to get age representation of species that couldn't be indexed: " + species); return Loc.GetString("identity-age-young"); } if (age < speciesPrototype.YoungAge) { return Loc.GetString("identity-age-young"); } if (age < speciesPrototype.OldAge) { return Loc.GetString("identity-age-middle-aged"); } return Loc.GetString("identity-age-old"); } }