using Content.Shared.Clothing.Components; using Content.Shared.Inventory; using Content.Shared.Inventory.Events; using Content.Shared.Item; using Content.Shared.Tag; using Robust.Shared.Prototypes; namespace Content.Shared.Clothing.EntitySystems; public abstract class SharedChameleonClothingSystem : EntitySystem { [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedItemSystem _itemSystem = default!; [Dependency] private readonly ClothingSystem _clothingSystem = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnGotEquipped); SubscribeLocalEvent(OnGotUnequipped); } private void OnGotEquipped(EntityUid uid, ChameleonClothingComponent component, GotEquippedEvent args) { component.User = args.Equipee; } private void OnGotUnequipped(EntityUid uid, ChameleonClothingComponent component, GotUnequippedEvent args) { component.User = null; } // Updates chameleon visuals and meta information. // This function is called on a server after user selected new outfit. // And after that on a client after state was updated. // This 100% makes sure that server and client have exactly same data. protected void UpdateVisuals(EntityUid uid, ChameleonClothingComponent component) { if (string.IsNullOrEmpty(component.SelectedId) || !_proto.TryIndex(component.SelectedId, out EntityPrototype? proto)) return; // world sprite icon UpdateSprite(uid, proto); // copy name and description var meta = MetaData(uid); _metaData.SetEntityName(uid, proto.Name, meta); _metaData.SetEntityDescription(uid, proto.Description, meta); // item sprite logic if (TryComp(uid, out ItemComponent? item) && proto.TryGetComponent(out ItemComponent? otherItem, _factory)) { _itemSystem.CopyVisuals(uid, otherItem, item); } // clothing sprite logic if (TryComp(uid, out ClothingComponent? clothing) && proto.TryGetComponent("Clothing", out ClothingComponent? otherClothing)) { _clothingSystem.CopyVisuals(uid, otherClothing, clothing); } } protected virtual void UpdateSprite(EntityUid uid, EntityPrototype proto) { } /// /// Check if this entity prototype is valid target for chameleon item. /// public bool IsValidTarget(EntityPrototype proto, SlotFlags chameleonSlot = SlotFlags.NONE) { // check if entity is valid if (proto.Abstract || proto.NoSpawn) return false; // check if it is marked as valid chameleon target if (!proto.TryGetComponent(out TagComponent? tags, _factory) || !tags.Tags.Contains("WhitelistChameleon")) return false; // check if it's valid clothing if (!proto.TryGetComponent("Clothing", out ClothingComponent? clothing)) return false; if (!clothing.Slots.HasFlag(chameleonSlot)) return false; return true; } }