using Robust.Shared.Serialization.Manager;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Damage.Systems;
+using Content.Shared.Item.ItemToggle;
+using Content.Shared.Item.ItemToggle.Components;
namespace Content.Shared.Polymorph.Systems;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedTransformSystem _xform = default!;
+ [Dependency] private readonly ItemToggleSystem _toggle = default!;
public override void Initialize()
{
SubscribeLocalEvent<ChameleonProjectorComponent, HandDeselectedEvent>(OnDeselected);
SubscribeLocalEvent<ChameleonProjectorComponent, GotUnequippedHandEvent>(OnUnequipped);
SubscribeLocalEvent<ChameleonProjectorComponent, ComponentShutdown>(OnProjectorShutdown);
+ SubscribeLocalEvent<ChameleonProjectorComponent, ItemToggledEvent>(OnProjectorToggled);
}
#region Disguise entity
TryDisguise(ent, args.User, target);
}
+ private void OnProjectorToggled(Entity<ChameleonProjectorComponent> ent, ref ItemToggledEvent args)
+ {
+ if (args.Activated)
+ return;
+
+ if (ent.Comp.Disguised == null)
+ return;
+
+ // We don't toggle here as this is only called when we subscribe to being toggled off.
+ TryReveal(ent.Comp.Disguised.Value);
+ }
+
private void OnGetVerbs(Entity<ChameleonProjectorComponent> ent, ref GetVerbsEvent<UtilityVerb> args)
{
if (!args.CanAccess)
return false;
}
+ // We do a TryComp, so if the item has variations without ItemToggle, they can still be used just fine.
+ if (TryComp<ItemToggleComponent>(ent.Owner, out var itemToggle) && !_toggle.TryActivate((ent.Owner, itemToggle), user))
+ return false;
+
_popup.PopupClient(Loc.GetString("chameleon-projector-success"), target, user);
Disguise(ent, user, target);
return true;
return;
// reveal first to allow quick switching
- TryReveal(user);
+ if (ent.Comp.Disguised != null)
+ ClearDisguise(ent, ent.Comp.Disguised.Value);
// add actions for controlling transform aspects
_actions.AddAction(user, ref proj.NoRotActionEntity, proj.NoRotAction, container: ent);
var disguise = SpawnAttachedTo(proj.DisguiseProto, user.ToCoordinates());
- var disguised = AddComp<ChameleonDisguisedComponent>(user);
+ var disguised = EnsureComp<ChameleonDisguisedComponent>(user);
disguised.Disguise = disguise;
Dirty(user, disguised);
if (!Resolve(ent, ref ent.Comp, false))
return false;
- if (TryComp<ChameleonDisguiseComponent>(ent.Comp.Disguise, out var disguise)
- && TryComp<ChameleonProjectorComponent>(disguise.Projector, out var proj))
- {
- proj.Disguised = null;
- }
+ if (!TryComp<ChameleonDisguiseComponent>(ent.Comp.Disguise, out var disguise)
+ || !TryComp<ChameleonProjectorComponent>(disguise.Projector, out var proj))
+ return false;
- var xform = Transform(ent);
- xform.NoLocalRotation = false;
- _xform.Unanchor(ent, xform);
+ ClearDisguise((disguise.Projector, proj), ent);
+ _toggle.TryDeactivate(disguise.Projector);
- Del(ent.Comp.Disguise);
RemComp<ChameleonDisguisedComponent>(ent);
return true;
}
+ /// <summary>
+ /// Clears the disguise for the projector, allowing the user to immediately disguise again.
+ /// </summary>
+ /// <param name="ent">The entity for which to clear the disguise</param>
+ /// <param name="disguised">The disguised entity.</param>
+ private void ClearDisguise(Entity<ChameleonProjectorComponent> ent, Entity<ChameleonDisguisedComponent?> disguised)
+ {
+ if (!Resolve(disguised, ref disguised.Comp, false))
+ return;
+
+ if (ent.Comp.Disguised == null)
+ return;
+
+ var xform = Transform(ent.Comp.Disguised.Value);
+ xform.NoLocalRotation = false;
+ _xform.Unanchor(disguised, xform);
+
+ ent.Comp.Disguised = null;
+ Del(disguised.Comp.Disguise);
+ }
+
/// <summary>
/// Reveal a projector's user, if any.
/// </summary>
- type: entity
parent: [BaseItem, BaseSyndicateContraband]
- id: ChameleonProjector
+ id: ChameleonProjectorNoBattery
name: chameleon projector
description: Holoparasite technology used to create a hard-light replica of any object around you. Disguise is destroyed when picked up or deactivated.
components:
- type: Sprite
sprite: /Textures/Objects/Devices/chameleon_projector.rsi
- state: icon
+ layers:
+ - state: icon
+ - state: powered
+ map: [ "enum.PowerDeviceVisualLayers.Powered" ]
+ - state: decharging
+ map: [ "enum.PowerDeviceVisualLayers.Charging" ]
+ visible: false
- type: ChameleonProjector
whitelist:
components:
- type: StaticPrice
price: 5000
+- type: entity
+ parent: ChameleonProjectorNoBattery
+ id: ChameleonProjector
+ name: chameleon projector
+ description: Holoparasite technology used to create a hard-light replica of any object around you. Disguise is destroyed when picked up or deactivated.
+ suffix: Battery
+ components:
+ - type: Appearance
+ - type: GenericVisualizer
+ visuals:
+ enum.BatteryVisuals.State:
+ enum.PowerDeviceVisualLayers.Powered:
+ Full: { visible: true }
+ Neither: { visible: true }
+ Empty: { visible: false }
+ enum.BatteryVisuals.Charging:
+ enum.PowerDeviceVisualLayers.Charging:
+ Charging: { visible: false }
+ Decharging: { visible: true }
+ Constant: { visible: false }
+ - type: BatteryVisuals
+ - type: ContainerContainer
+ containers:
+ cell_slot: !type:ContainerSlot
+ - type: ItemSlots
+ slots:
+ cell_slot:
+ name: power-cell-slot-component-slot-name-default
+ startingItem: PowerCellMedium
+ - type: PowerCellSlot
+ cellSlotId: cell_slot
+ - type: PowerCellDraw
+ drawRate: 4 # About 3 minutes with a medium cell.
+ - type: ToggleCellDraw
+ - type: ItemToggle
+ onActivate: false
+ onUse: false
+
- type: entity
categories: [ HideSpawnMenu ]
id: ChameleonDisguise