using Content.Shared.Clothing.Components; using Content.Shared.Clothing.EntitySystems; using Content.Shared.Emp; using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement.Components; using Content.Shared.Prototypes; using Robust.Shared.Prototypes; namespace Content.Server.Clothing.Systems; public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem { [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IdentitySystem _identity = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnSelected); } private void OnMapInit(EntityUid uid, ChameleonClothingComponent component, MapInitEvent args) { SetSelectedPrototype(uid, component.Default, true, component); } private void OnSelected(EntityUid uid, ChameleonClothingComponent component, ChameleonPrototypeSelectedMessage args) { SetSelectedPrototype(uid, args.SelectedId, component: component); } private void UpdateUi(EntityUid uid, ChameleonClothingComponent? component = null) { if (!Resolve(uid, ref component)) return; var state = new ChameleonBoundUserInterfaceState(component.Slot, component.Default, component.RequireTag); UI.SetUiState(uid, ChameleonUiKey.Key, state); } /// /// Change chameleon items name, description and sprite to mimic other entity prototype. /// public override void SetSelectedPrototype(EntityUid uid, string? protoId, bool forceUpdate = false, ChameleonClothingComponent? component = null) { if (!Resolve(uid, ref component, false)) return; // check that wasn't already selected // forceUpdate on component init ignores this check if (component.Default == protoId && !forceUpdate) return; // make sure that it is valid change if (string.IsNullOrEmpty(protoId) || !_proto.TryIndex(protoId, out EntityPrototype? proto)) return; if (!IsValidTarget(proto, component.Slot, component.RequireTag)) return; component.Default = protoId; UpdateIdentityBlocker(uid, component, proto); UpdateVisuals(uid, component); UpdateUi(uid, component); Dirty(uid, component); } public override void Update(float frameTime) { base.Update(frameTime); // Randomize EMP-affected clothing var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out _, out var chameleon)) { if (!chameleon.EmpContinuous) continue; if (Timing.CurTime < chameleon.NextEmpChange) continue; // randomly pick cloth element from available and apply it var pick = GetRandomValidPrototype(chameleon.Slot, chameleon.RequireTag); SetSelectedPrototype(uid, pick, component: chameleon); chameleon.NextEmpChange += TimeSpan.FromSeconds(1f / chameleon.EmpChangeIntensity); } } private void UpdateIdentityBlocker(EntityUid uid, ChameleonClothingComponent component, EntityPrototype proto) { if (proto.HasComponent(Factory)) EnsureComp(uid); else RemComp(uid); if (component.User != null) _identity.QueueIdentityUpdate(component.User.Value); } }