]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Chameleon Projector Battery, Price Decrease (#42271)
authorScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Wed, 7 Jan 2026 05:51:44 +0000 (06:51 +0100)
committerGitHub <noreply@github.com>
Wed, 7 Jan 2026 05:51:44 +0000 (05:51 +0000)
* init

* fuck using

* glowup

* unused

* meta

* whuh

* review

* tests

* Update SharedChameleonProjectorSystem.cs

Content.Client/Power/Visualizers/PowerDeviceVisuals.cs
Content.Shared/Polymorph/Systems/SharedChameleonProjectorSystem.cs
Resources/Prototypes/Catalog/uplink_catalog.yml
Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml
Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml
Resources/Textures/Objects/Devices/chameleon_projector.rsi/decharging.png [new file with mode: 0644]
Resources/Textures/Objects/Devices/chameleon_projector.rsi/icon.png
Resources/Textures/Objects/Devices/chameleon_projector.rsi/meta.json
Resources/Textures/Objects/Devices/chameleon_projector.rsi/powered.png [new file with mode: 0644]

index 5cc86d203d56988cf85330a0c47c39738891b0ce..057dabae5d1f5702bfc43121032a20abe2e37067 100644 (file)
@@ -3,5 +3,6 @@ namespace Content.Client.Power;
 /// Remains in use by portable scrubbers and lathes.
 public enum PowerDeviceVisualLayers : byte
 {
-    Powered
+    Powered,
+    Charging
 }
index 6c686ff55527c439e90105077977e5eff11f2bdf..bf6fea5b470b4a4376c93a226f980429d34160ca 100644 (file)
@@ -14,6 +14,8 @@ using Robust.Shared.Prototypes;
 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;
 
@@ -34,6 +36,7 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem
     [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()
     {
@@ -53,6 +56,7 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem
         SubscribeLocalEvent<ChameleonProjectorComponent, HandDeselectedEvent>(OnDeselected);
         SubscribeLocalEvent<ChameleonProjectorComponent, GotUnequippedHandEvent>(OnUnequipped);
         SubscribeLocalEvent<ChameleonProjectorComponent, ComponentShutdown>(OnProjectorShutdown);
+        SubscribeLocalEvent<ChameleonProjectorComponent, ItemToggledEvent>(OnProjectorToggled);
     }
 
     #region Disguise entity
@@ -105,6 +109,18 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem
         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)
@@ -136,6 +152,10 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem
             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;
@@ -206,7 +226,8 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem
             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);
@@ -216,7 +237,7 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem
 
         var disguise = SpawnAttachedTo(proj.DisguiseProto, user.ToCoordinates());
 
-        var disguised = AddComp<ChameleonDisguisedComponent>(user);
+        var disguised = EnsureComp<ChameleonDisguisedComponent>(user);
         disguised.Disguise = disguise;
         Dirty(user, disguised);
 
@@ -246,21 +267,38 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem
         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>
index 6b56eced0d6f308de1856591326e682cb7ebe0d7..c800eddab7c516f52a57860531096f75637cb52a 100644 (file)
   productEntity: ChameleonProjector
   discountCategory: rareDiscounts
   discountDownTo:
-    Telecrystal: 4
+    Telecrystal: 2
   cost:
-    Telecrystal: 7
+    Telecrystal: 3
   categories:
   - UplinkDeception
 
index 9260574c665a3f200d5abd23af9da6f2a2127b60..e69b092afac4aa7c323605287bc1cca81610ec64 100644 (file)
@@ -1,12 +1,18 @@
 - 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
index f212354123fd3f30095f1ee16bc2636d9d8915c1..7ad58ef5eb5589d598af45ade322dd8ef4f230cc 100644 (file)
     - state: icon-xenoborg-projector
   - type: ItemBorgModule
     hands:
-    - item: ChameleonProjector
+    - item: ChameleonProjectorNoBattery
   - type: BorgModuleIcon
     icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-projector-module }
 
diff --git a/Resources/Textures/Objects/Devices/chameleon_projector.rsi/decharging.png b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/decharging.png
new file mode 100644 (file)
index 0000000..a818589
Binary files /dev/null and b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/decharging.png differ
index ce20b5eeeed277078a03893f96e9ce1aa8ca518f..2d74fcfb85ba6d2e8b9fce94af65ced378f2465c 100644 (file)
Binary files a/Resources/Textures/Objects/Devices/chameleon_projector.rsi/icon.png and b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/icon.png differ
index 6a28032ba6a9a9b8a54c829f099b13f77991a120..5a007d22ae670ec70c3d7b77af1ef7c926126f54 100644 (file)
@@ -1,14 +1,17 @@
 {
   "version": 1,
   "license": "CC-BY-SA-3.0",
-  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/71a1fee2f13730adee5302d34bfa0f0262314d63,  Inhands by TiniestShark (github)",
+  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/71a1fee2f13730adee5302d34bfa0f0262314d63,  Inhands by TiniestShark (github), decharging, icon and powered seperated by ScarKy0(Github)",
   "size": {
     "x": 32,
     "y": 32
   },
   "states": [
     {
-      "name": "icon",
+      "name": "icon"
+    },
+    {
+      "name": "powered",
       "delays": [
         [
           0.2,
         ]
       ]
     },
+    {
+      "name": "decharging",
+      "delays": [
+        [
+          0.2,
+          0.2,
+          0.2,
+          0.2
+        ]
+      ]
+    },
     {
       "name": "inhand-left",
       "directions": 4
diff --git a/Resources/Textures/Objects/Devices/chameleon_projector.rsi/powered.png b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/powered.png
new file mode 100644 (file)
index 0000000..628dac6
Binary files /dev/null and b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/powered.png differ