]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Cleanup BatterySystem (#41298)
authorslarticodefast <161409025+slarticodefast@users.noreply.github.com>
Sat, 8 Nov 2025 20:55:02 +0000 (21:55 +0100)
committerGitHub <noreply@github.com>
Sat, 8 Nov 2025 20:55:02 +0000 (20:55 +0000)
* cleanup

* fix fixtures

* this belongs into the next PR

* review

* misc

---------

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
45 files changed:
Content.IntegrationTests/Tests/Power/PowerTest.cs
Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs
Content.Server/Light/EntitySystems/EmergencyLightSystem.cs
Content.Server/Light/EntitySystems/HandheldLightSystem.cs
Content.Server/Mech/Systems/MechSystem.cs
Content.Server/Ninja/Systems/BatteryDrainerSystem.cs
Content.Server/Ninja/Systems/SpaceNinjaSystem.cs
Content.Server/Power/Components/BatterySelfRechargerComponent.cs [deleted file]
Content.Server/Power/EntitySystems/BatterySystem.API.cs [new file with mode: 0644]
Content.Server/Power/EntitySystems/BatterySystem.cs
Content.Server/Power/EntitySystems/ChargerSystem.cs
Content.Server/Power/EntitySystems/PowerNetSystem.cs
Content.Server/Power/SetBatteryPercentCommand.cs
Content.Server/PowerCell/PowerCellSystem.Draw.cs
Content.Server/PowerCell/PowerCellSystem.cs
Content.Server/PowerSink/PowerSinkSystem.cs
Content.Server/Radio/EntitySystems/JammerSystem.cs
Content.Server/Silicons/StationAi/StationAiSystem.cs
Content.Server/Stunnable/Systems/StunbatonSystem.cs
Content.Server/Tesla/EntitySystem/TeslaCoilSystem.cs
Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs
Content.Server/Xenoarchaeology/Artifact/XAE/XAEChargeBatterySystem.cs
Content.Shared/Power/ChargeEvents.cs
Content.Shared/Power/Components/BatteryComponent.cs
Content.Shared/Power/Components/BatterySelfRechargerComponent.cs [new file with mode: 0644]
Content.Shared/Power/EntitySystems/SharedBatterySystem.cs
Resources/Maps/Lavaland/grasslanddome.yml
Resources/Maps/Lavaland/snowydome.yml
Resources/Maps/Misc/terminal.yml
Resources/Maps/Nonstations/wizardsden.yml
Resources/Maps/Ruins/ruined_prison_ship.yml
Resources/Maps/Shuttles/arrivals.yml
Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml
Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml
Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml
Resources/Prototypes/Entities/Mobs/NPCs/lavaland.yml
Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml
Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml
Resources/Prototypes/Entities/Objects/Power/powercells.yml
Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml
Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml
Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml
Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml
Resources/Prototypes/Entities/Structures/Power/debug_power.yml

index ab8a421c03395b6a9ce32f0c4df6e9de1d38d8fd..85bd3666971874f892b1f3bcf33454678e671bf0 100644 (file)
@@ -402,8 +402,8 @@ namespace Content.IntegrationTests.Tests.Power
                 battery = entityManager.GetComponent<BatteryComponent>(generatorEnt);
                 consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt);
 
-                batterySys.SetMaxCharge(generatorEnt, startingCharge, battery);
-                batterySys.SetCharge(generatorEnt, startingCharge, battery);
+                batterySys.SetMaxCharge((generatorEnt, battery), startingCharge);
+                batterySys.SetCharge((generatorEnt, battery), startingCharge);
                 netBattery.MaxSupply = 400;
                 netBattery.SupplyRampRate = 400;
                 netBattery.SupplyRampTolerance = 100;
@@ -513,8 +513,8 @@ namespace Content.IntegrationTests.Tests.Power
                 supplier.SupplyRampRate = rampRate;
                 supplier.SupplyRampTolerance = rampTol;
 
-                batterySys.SetMaxCharge(batteryEnt, 100_000, battery);
-                batterySys.SetCharge(batteryEnt, 100_000, battery);
+                batterySys.SetMaxCharge((batteryEnt, battery), 100_000);
+                batterySys.SetCharge((batteryEnt, battery), 100_000);
                 netBattery.MaxSupply = draw / 2;
                 netBattery.SupplyRampRate = rampRate;
                 netBattery.SupplyRampTolerance = rampTol;
@@ -600,7 +600,7 @@ namespace Content.IntegrationTests.Tests.Power
 
                 supplier.MaxSupply = 500;
                 supplier.SupplyRampTolerance = 500;
-                batterySys.SetMaxCharge(batteryEnt, 100_000, battery);
+                batterySys.SetMaxCharge((batteryEnt, battery), 100_000);
                 netBattery.MaxChargeRate = 1_000;
                 netBattery.Efficiency = 0.5f;
             });
@@ -670,8 +670,8 @@ namespace Content.IntegrationTests.Tests.Power
                 netBattery.MaxSupply = 400;
                 netBattery.SupplyRampTolerance = 400;
                 netBattery.SupplyRampRate = 100_000;
-                batterySys.SetMaxCharge(batteryEnt, 100_000, battery);
-                batterySys.SetCharge(batteryEnt, 100_000, battery);
+                batterySys.SetMaxCharge((batteryEnt, battery), 100_000);
+                batterySys.SetCharge((batteryEnt, battery), 100_000);
             });
 
             // Run some ticks so everything is stable.
@@ -750,8 +750,8 @@ namespace Content.IntegrationTests.Tests.Power
                 netBattery.SupplyRampTolerance = 400;
                 netBattery.SupplyRampRate = 100_000;
                 netBattery.Efficiency = 0.5f;
-                batterySys.SetMaxCharge(batteryEnt, 1_000_000, battery);
-                batterySys.SetCharge(batteryEnt, 1_000_000, battery);
+                batterySys.SetMaxCharge((batteryEnt, battery), 1_000_000);
+                batterySys.SetCharge((batteryEnt, battery), 1_000_000);
             });
 
             // Run some ticks so everything is stable.
@@ -841,8 +841,8 @@ namespace Content.IntegrationTests.Tests.Power
                 supplier.MaxSupply = 1000;
                 supplier.SupplyRampTolerance = 1000;
 
-                batterySys.SetMaxCharge(batteryEnt1, 1_000_000, battery1);
-                batterySys.SetMaxCharge(batteryEnt2, 1_000_000, battery2);
+                batterySys.SetMaxCharge((batteryEnt1, battery1), 1_000_000);
+                batterySys.SetMaxCharge((batteryEnt2, battery2), 1_000_000);
 
                 netBattery1.MaxChargeRate = 1_000;
                 netBattery2.MaxChargeRate = 1_000;
@@ -945,10 +945,10 @@ namespace Content.IntegrationTests.Tests.Power
                 netBattery2.SupplyRampTolerance = 1000;
                 netBattery1.SupplyRampRate = 100_000;
                 netBattery2.SupplyRampRate = 100_000;
-                batterySys.SetMaxCharge(batteryEnt1, 100_000, battery1);
-                batterySys.SetMaxCharge(batteryEnt2, 100_000, battery2);
-                batterySys.SetCharge(batteryEnt1, 100_000, battery1);
-                batterySys.SetCharge(batteryEnt2, 100_000, battery2);
+                batterySys.SetMaxCharge((batteryEnt1, battery1), 100_000);
+                batterySys.SetMaxCharge((batteryEnt2, battery2), 100_000);
+                batterySys.SetCharge((batteryEnt1, battery1), 100_000);
+                batterySys.SetCharge((batteryEnt2, battery2), 100_000);
             });
 
             // Run some ticks so everything is stable.
@@ -1031,8 +1031,8 @@ namespace Content.IntegrationTests.Tests.Power
                 supplier.MaxSupply = 1000;
                 supplier.SupplyRampTolerance = 1000;
 
-                batterySys.SetMaxCharge(batteryEnt1, 1_000_000, battery1);
-                batterySys.SetMaxCharge(batteryEnt2, 1_000_000, battery2);
+                batterySys.SetMaxCharge((batteryEnt1, battery1), 1_000_000);
+                batterySys.SetMaxCharge((batteryEnt2, battery2), 1_000_000);
 
                 netBattery1.MaxChargeRate = 20;
                 netBattery2.MaxChargeRate = 20;
@@ -1107,8 +1107,8 @@ namespace Content.IntegrationTests.Tests.Power
                 netBattery.MaxSupply = 1000;
                 netBattery.SupplyRampTolerance = 200;
                 netBattery.SupplyRampRate = 10;
-                batterySys.SetMaxCharge(batteryEnt, 100_000, battery);
-                batterySys.SetCharge(batteryEnt, 100_000, battery);
+                batterySys.SetMaxCharge((batteryEnt, battery), 100_000);
+                batterySys.SetCharge((batteryEnt, battery), 100_000);
             });
 
             // Run some ticks so everything is stable.
@@ -1253,7 +1253,7 @@ namespace Content.IntegrationTests.Tests.Power
                 generatorSupplier.MaxSupply = 1000;
                 generatorSupplier.SupplyRampTolerance = 1000;
 
-                batterySys.SetCharge(apcEnt, 0, apcBattery);
+                batterySys.SetCharge((apcEnt, apcBattery), 0);
             });
 
             server.RunTicks(5); //let run a few ticks for PowerNets to reevaluate and start charging apc
@@ -1314,8 +1314,8 @@ namespace Content.IntegrationTests.Tests.Power
                 extensionCableSystem.SetProviderTransferRange(apcExtensionEnt, range);
                 extensionCableSystem.SetReceiverReceptionRange(powerReceiverEnt, range);
 
-                batterySys.SetMaxCharge(apcEnt, 10000, battery);  //arbitrary nonzero amount of charge
-                batterySys.SetCharge(apcEnt, battery.MaxCharge, battery); //fill battery
+                batterySys.SetMaxCharge((apcEnt, battery), 10000);  //arbitrary nonzero amount of charge
+                batterySys.SetCharge((apcEnt, battery), battery.MaxCharge); //fill battery
 
                 receiver.Load = 1; //arbitrary small amount of power
             });
index 41228b5ac8f5f90103d38d3f6b04b7a90afe19bd..4f96a25a5c616a260ada6a501769f26b2da5d206 100644 (file)
@@ -169,7 +169,7 @@ public sealed partial class AdminVerbSystem
                 Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
                 Act = () =>
                 {
-                    _batterySystem.SetCharge(args.Target, battery.MaxCharge, battery);
+                    _batterySystem.SetCharge((args.Target, battery), battery.MaxCharge);
                 },
                 Impact = LogImpact.Medium,
                 Message = Loc.GetString("admin-trick-refill-battery-description"),
@@ -184,7 +184,7 @@ public sealed partial class AdminVerbSystem
                 Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
                 Act = () =>
                 {
-                    _batterySystem.SetCharge(args.Target, 0, battery);
+                    _batterySystem.SetCharge((args.Target, battery), 0);
                 },
                 Impact = LogImpact.Medium,
                 Message = Loc.GetString("admin-trick-drain-battery-description"),
@@ -200,9 +200,8 @@ public sealed partial class AdminVerbSystem
                 Act = () =>
                 {
                     var recharger = EnsureComp<BatterySelfRechargerComponent>(args.Target);
-                    recharger.AutoRecharge = true;
                     recharger.AutoRechargeRate = battery.MaxCharge; // Instant refill.
-                    recharger.AutoRechargePause = false; // No delay.
+                    recharger.AutoRechargePauseTime = TimeSpan.Zero; // No delay.
                 },
                 Impact = LogImpact.Medium,
                 Message = Loc.GetString("admin-trick-infinite-battery-object-description"),
@@ -553,7 +552,7 @@ public sealed partial class AdminVerbSystem
                         if (!HasComp<StationInfiniteBatteryTargetComponent>(ent))
                             continue;
                         var battery = EnsureComp<BatteryComponent>(ent);
-                        _batterySystem.SetCharge(ent, battery.MaxCharge, battery);
+                        _batterySystem.SetCharge((ent, battery), battery.MaxCharge);
                     }
                 },
                 Impact = LogImpact.Extreme,
@@ -574,7 +573,7 @@ public sealed partial class AdminVerbSystem
                         if (!HasComp<StationInfiniteBatteryTargetComponent>(ent))
                             continue;
                         var battery = EnsureComp<BatteryComponent>(ent);
-                        _batterySystem.SetCharge(ent, 0, battery);
+                        _batterySystem.SetCharge((ent, battery), 0);
                     }
                 },
                 Impact = LogImpact.Extreme,
@@ -599,9 +598,8 @@ public sealed partial class AdminVerbSystem
                         var recharger = EnsureComp<BatterySelfRechargerComponent>(ent);
                         var battery = EnsureComp<BatteryComponent>(ent);
 
-                        recharger.AutoRecharge = true;
                         recharger.AutoRechargeRate = battery.MaxCharge; // Instant refill.
-                        recharger.AutoRechargePause = false; // No delay.
+                        recharger.AutoRechargePauseTime = TimeSpan.Zero; // No delay.
                     }
                 },
                 Impact = LogImpact.Extreme,
index 0aea245c797bd0f9b9bb711be168ef08914ab0c6..eddef878539fb09d0bda4e343354b8432f42e201 100644 (file)
@@ -145,7 +145,7 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
     {
         if (entity.Comp.State == EmergencyLightState.On)
         {
-            if (!_battery.TryUseCharge(entity.Owner, entity.Comp.Wattage * frameTime, battery))
+            if (!_battery.TryUseCharge((entity.Owner, battery), entity.Comp.Wattage * frameTime))
             {
                 SetState(entity.Owner, entity.Comp, EmergencyLightState.Empty);
                 TurnOff(entity);
@@ -153,8 +153,8 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
         }
         else
         {
-            _battery.SetCharge(entity.Owner, battery.CurrentCharge + entity.Comp.ChargingWattage * frameTime * entity.Comp.ChargingEfficiency, battery);
-            if (_battery.IsFull(entity, battery))
+            _battery.SetCharge((entity.Owner, battery), battery.CurrentCharge + entity.Comp.ChargingWattage * frameTime * entity.Comp.ChargingEfficiency);
+            if (_battery.IsFull((entity.Owner, battery)))
             {
                 if (TryComp<ApcPowerReceiverComponent>(entity.Owner, out var receiver))
                 {
index 2c8d18539ffed7df8569c4f0876cca95a9dac780..7167aa496367bbfd53ec1fab99f54c26483ee9f4 100644 (file)
@@ -253,7 +253,7 @@ namespace Content.Server.Light.EntitySystems
                 _appearance.SetData(uid, HandheldLightVisuals.Power, HandheldLightPowerStates.Dying, appearanceComponent);
             }
 
-            if (component.Activated && !_battery.TryUseCharge(batteryUid.Value, component.Wattage * frameTime, battery))
+            if (component.Activated && !_battery.TryUseCharge((batteryUid.Value, battery), component.Wattage * frameTime))
                 TurnOff(uid, false);
 
             UpdateLevel(uid);
index 923c7018688c6bc34ee4356e7d4aa59439c331e0..89297a6e86278dfc1b7a99a37091d7204a947829 100644 (file)
@@ -340,7 +340,7 @@ public sealed partial class MechSystem : SharedMechSystem
         if (!TryComp<BatteryComponent>(battery, out var batteryComp))
             return false;
 
-        _battery.SetCharge(battery!.Value, batteryComp.CurrentCharge + delta.Float(), batteryComp);
+        _battery.SetCharge((battery.Value, batteryComp), batteryComp.CurrentCharge + delta.Float());
         if (batteryComp.CurrentCharge != component.Energy) //if there's a discrepency, we have to resync them
         {
             Log.Debug($"Battery charge was not equal to mech charge. Battery {batteryComp.CurrentCharge}. Mech {component.Energy}");
index e5633866089f1664947fee2162b5fc0deedd3cdc..7b9d229d73cb5a2ed6a2c731de6324a095c88ef2 100644 (file)
@@ -95,17 +95,17 @@ public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
         // higher tier storages can charge more
         var maxDrained = pnb.MaxSupply * comp.DrainTime;
         var input = Math.Min(Math.Min(available, required / comp.DrainEfficiency), maxDrained);
-        if (!_battery.TryUseCharge(target, input, targetBattery))
+        if (!_battery.TryUseCharge((target, targetBattery), input))
             return false;
 
         var output = input * comp.DrainEfficiency;
-        _battery.SetCharge(comp.BatteryUid.Value, battery.CurrentCharge + output, battery);
+        _battery.SetCharge((comp.BatteryUid.Value, battery), battery.CurrentCharge + output);
         // TODO: create effect message or something
         Spawn("EffectSparks", Transform(target).Coordinates);
         _audio.PlayPvs(comp.SparkSound, target);
         _popup.PopupEntity(Loc.GetString("battery-drainer-success", ("battery", target)), uid, uid);
 
         // repeat the doafter until battery is full
-        return !_battery.IsFull(comp.BatteryUid.Value, battery);
+        return !_battery.IsFull((comp.BatteryUid.Value, battery));
     }
 }
index ff88926723ec6b5ca70faccabcf4377140b5d647..fd7f908738d46b82128207ffbad99d44b35faa87 100644 (file)
@@ -106,7 +106,7 @@ public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem
     /// <inheritdoc/>
     public override bool TryUseCharge(EntityUid user, float charge)
     {
-        return GetNinjaBattery(user, out var uid, out var battery) && _battery.TryUseCharge(uid.Value, charge, battery);
+        return GetNinjaBattery(user, out var uid, out var battery) && _battery.TryUseCharge((uid.Value, battery), charge);
     }
 
     /// <summary>
diff --git a/Content.Server/Power/Components/BatterySelfRechargerComponent.cs b/Content.Server/Power/Components/BatterySelfRechargerComponent.cs
deleted file mode 100644 (file)
index 1cb92d9..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-
-namespace Content.Server.Power.Components
-{
-    /// <summary>
-    ///     Self-recharging battery.
-    /// </summary>
-    [RegisterComponent]
-    public sealed partial class BatterySelfRechargerComponent : Component
-    {
-        /// <summary>
-        /// Does the entity auto recharge?
-        /// </summary>
-        [DataField] public bool AutoRecharge;
-
-        /// <summary>
-        /// At what rate does the entity automatically recharge?
-        /// </summary>
-        [DataField] public float AutoRechargeRate;
-
-        /// <summary>
-        /// Should this entity stop automatically recharging if a charge is used?
-        /// </summary>
-        [DataField] public bool AutoRechargePause = false;
-
-        /// <summary>
-        /// How long should the entity stop automatically recharging if a charge is used?
-        /// </summary>
-        [DataField] public float AutoRechargePauseTime = 0f;
-
-        /// <summary>
-        /// Do not auto recharge if this timestamp has yet to happen, set for the auto recharge pause system.
-        /// </summary>
-        [DataField] public TimeSpan NextAutoRecharge = TimeSpan.FromSeconds(0f);
-    }
-}
diff --git a/Content.Server/Power/EntitySystems/BatterySystem.API.cs b/Content.Server/Power/EntitySystems/BatterySystem.API.cs
new file mode 100644 (file)
index 0000000..6ddf1f4
--- /dev/null
@@ -0,0 +1,104 @@
+using Content.Shared.Power;
+using Content.Shared.Power.Components;
+
+namespace Content.Server.Power.EntitySystems;
+
+public sealed partial class BatterySystem
+{
+    public override float ChangeCharge(Entity<BatteryComponent?> ent, float amount)
+    {
+        if (!Resolve(ent, ref ent.Comp))
+            return 0;
+
+        var newValue = Math.Clamp(ent.Comp.CurrentCharge + amount, 0, ent.Comp.MaxCharge);
+        var delta = newValue - ent.Comp.CurrentCharge;
+        ent.Comp.CurrentCharge = newValue;
+
+        TrySetChargeCooldown(ent.Owner);
+
+        var ev = new ChargeChangedEvent(ent.Comp.CurrentCharge, ent.Comp.MaxCharge);
+        RaiseLocalEvent(ent, ref ev);
+        return delta;
+    }
+
+    public override float UseCharge(Entity<BatteryComponent?> ent, float amount)
+    {
+        if (amount <= 0 || !Resolve(ent, ref ent.Comp) || ent.Comp.CurrentCharge == 0)
+            return 0;
+
+        return ChangeCharge(ent, -amount);
+    }
+
+    public override bool TryUseCharge(Entity<BatteryComponent?> ent, float amount)
+    {
+        if (!Resolve(ent, ref ent.Comp, false) || amount > ent.Comp.CurrentCharge)
+            return false;
+
+        UseCharge(ent, amount);
+        return true;
+    }
+
+    public override void SetCharge(Entity<BatteryComponent?> ent, float value)
+    {
+        if (!Resolve(ent, ref ent.Comp))
+            return;
+
+        var oldCharge = ent.Comp.CurrentCharge;
+        ent.Comp.CurrentCharge = MathHelper.Clamp(value, 0, ent.Comp.MaxCharge);
+        if (MathHelper.CloseTo(ent.Comp.CurrentCharge, oldCharge) &&
+            !(oldCharge != ent.Comp.CurrentCharge && ent.Comp.CurrentCharge == ent.Comp.MaxCharge))
+        {
+            return;
+        }
+
+        var ev = new ChargeChangedEvent(ent.Comp.CurrentCharge, ent.Comp.MaxCharge);
+        RaiseLocalEvent(ent, ref ev);
+    }
+    public override void SetMaxCharge(Entity<BatteryComponent?> ent, float value)
+    {
+        if (!Resolve(ent, ref ent.Comp))
+            return;
+
+        var old = ent.Comp.MaxCharge;
+        ent.Comp.MaxCharge = Math.Max(value, 0);
+        ent.Comp.CurrentCharge = Math.Min(ent.Comp.CurrentCharge, ent.Comp.MaxCharge);
+        if (MathHelper.CloseTo(ent.Comp.MaxCharge, old))
+            return;
+
+        var ev = new ChargeChangedEvent(ent.Comp.CurrentCharge, ent.Comp.MaxCharge);
+        RaiseLocalEvent(ent, ref ev);
+    }
+
+    public override void TrySetChargeCooldown(Entity<BatterySelfRechargerComponent?> ent)
+    {
+        if (!Resolve(ent, ref ent.Comp, false))
+            return;
+
+        if (ent.Comp.AutoRechargePauseTime == TimeSpan.Zero)
+            return; // no recharge pause
+
+        if (_timing.CurTime + ent.Comp.AutoRechargePauseTime <= ent.Comp.NextAutoRecharge)
+            return; // the current pause is already longer
+
+        SetChargeCooldown(ent, ent.Comp.AutoRechargePauseTime);
+    }
+
+    public override void SetChargeCooldown(Entity<BatterySelfRechargerComponent?> ent, TimeSpan cooldown)
+    {
+        if (!Resolve(ent, ref ent.Comp))
+            return;
+
+        ent.Comp.NextAutoRecharge = _timing.CurTime + cooldown;
+    }
+
+    /// <summary>
+    /// Returns whether the battery is full.
+    /// </summary>
+    public bool IsFull(Entity<BatteryComponent?> ent)
+    {
+        if (!Resolve(ent, ref ent.Comp))
+            return false;
+
+        return ent.Comp.CurrentCharge >= ent.Comp.MaxCharge;
+    }
+}
index c49a2f0f6b44ca563cb1ab9a730d0d3f85221c12..4b6a52c0f117169f585a2f3efd56d1d08af1ddc5 100644 (file)
@@ -9,232 +9,115 @@ using JetBrains.Annotations;
 using Robust.Shared.Utility;
 using Robust.Shared.Timing;
 
-namespace Content.Server.Power.EntitySystems
-{
-    [UsedImplicitly]
-    public sealed class BatterySystem : SharedBatterySystem
-    {
-        [Dependency] private readonly IGameTiming _timing = default!;
-
-        public override void Initialize()
-        {
-            base.Initialize();
-
-            SubscribeLocalEvent<ExaminableBatteryComponent, ExaminedEvent>(OnExamine);
-            SubscribeLocalEvent<PowerNetworkBatteryComponent, RejuvenateEvent>(OnNetBatteryRejuvenate);
-            SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnBatteryRejuvenate);
-            SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
-            SubscribeLocalEvent<BatteryComponent, ChangeChargeEvent>(OnChangeCharge);
-            SubscribeLocalEvent<BatteryComponent, GetChargeEvent>(OnGetCharge);
-
-            SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync);
-            SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync);
-        }
-
-        private void OnNetBatteryRejuvenate(EntityUid uid, PowerNetworkBatteryComponent component, RejuvenateEvent args)
-        {
-            component.NetworkBattery.CurrentStorage = component.NetworkBattery.Capacity;
-        }
+namespace Content.Server.Power.EntitySystems;
 
-        private void OnBatteryRejuvenate(EntityUid uid, BatteryComponent component, RejuvenateEvent args)
-        {
-            SetCharge(uid, component.MaxCharge, component);
-        }
-
-        private void OnExamine(EntityUid uid, ExaminableBatteryComponent component, ExaminedEvent args)
-        {
-            if (!TryComp<BatteryComponent>(uid, out var batteryComponent))
-                return;
-            if (args.IsInDetailsRange)
-            {
-                var effectiveMax = batteryComponent.MaxCharge;
-                if (effectiveMax == 0)
-                    effectiveMax = 1;
-                var chargeFraction = batteryComponent.CurrentCharge / effectiveMax;
-                var chargePercentRounded = (int)(chargeFraction * 100);
-                args.PushMarkup(
-                    Loc.GetString(
-                        "examinable-battery-component-examine-detail",
-                        ("percent", chargePercentRounded),
-                        ("markupPercentColor", "green")
-                    )
-                );
-            }
-        }
-
-        private void PreSync(NetworkBatteryPreSync ev)
-        {
-            // Ignoring entity pausing. If the entity was paused, neither component's data should have been changed.
-            var enumerator = AllEntityQuery<PowerNetworkBatteryComponent, BatteryComponent>();
-            while (enumerator.MoveNext(out var netBat, out var bat))
-            {
-                DebugTools.Assert(bat.CurrentCharge <= bat.MaxCharge && bat.CurrentCharge >= 0);
-                netBat.NetworkBattery.Capacity = bat.MaxCharge;
-                netBat.NetworkBattery.CurrentStorage = bat.CurrentCharge;
-            }
-        }
-
-        private void PostSync(NetworkBatteryPostSync ev)
-        {
-            // Ignoring entity pausing. If the entity was paused, neither component's data should have been changed.
-            var enumerator = AllEntityQuery<PowerNetworkBatteryComponent, BatteryComponent>();
-            while (enumerator.MoveNext(out var uid, out var netBat, out var bat))
-            {
-                SetCharge(uid, netBat.NetworkBattery.CurrentStorage, bat);
-            }
-        }
-
-        public override void Update(float frameTime)
-        {
-            var query = EntityQueryEnumerator<BatterySelfRechargerComponent, BatteryComponent>();
-            while (query.MoveNext(out var uid, out var comp, out var batt))
-            {
-                if (!comp.AutoRecharge || IsFull(uid, batt))
-                    continue;
-
-                if (comp.AutoRechargePause)
-                {
-                    if (comp.NextAutoRecharge > _timing.CurTime)
-                        continue;
-                }
-
-                SetCharge(uid, batt.CurrentCharge + comp.AutoRechargeRate * frameTime, batt);
-            }
-        }
-
-        /// <summary>
-        /// Gets the price for the power contained in an entity's battery.
-        /// </summary>
-        private void CalculateBatteryPrice(EntityUid uid, BatteryComponent component, ref PriceCalculationEvent args)
-        {
-            args.Price += component.CurrentCharge * component.PricePerJoule;
-        }
-        private void OnChangeCharge(Entity<BatteryComponent> entity, ref ChangeChargeEvent args)
-        {
-            if (args.ResidualValue == 0)
-                return;
-
-            args.ResidualValue -= ChangeCharge(entity, args.ResidualValue);
-        }
+[UsedImplicitly]
+public sealed partial class BatterySystem : SharedBatterySystem
+{
+    [Dependency] private readonly IGameTiming _timing = default!;
 
-        private void OnGetCharge(Entity<BatteryComponent> entity, ref GetChargeEvent args)
-        {
-            args.CurrentCharge += entity.Comp.CurrentCharge;
-            args.MaxCharge += entity.Comp.MaxCharge;
-        }
+    public override void Initialize()
+    {
+        base.Initialize();
 
-        public override float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
-        {
-            if (value <= 0 || !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
-                return 0;
+        SubscribeLocalEvent<ExaminableBatteryComponent, ExaminedEvent>(OnExamine);
+        SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnBatteryRejuvenate);
+        SubscribeLocalEvent<PowerNetworkBatteryComponent, RejuvenateEvent>(OnNetBatteryRejuvenate);
+        SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
+        SubscribeLocalEvent<BatteryComponent, ChangeChargeEvent>(OnChangeCharge);
+        SubscribeLocalEvent<BatteryComponent, GetChargeEvent>(OnGetCharge);
 
-            return ChangeCharge(uid, -value, battery);
-        }
+        SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync);
+        SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync);
+    }
 
-        public override void SetMaxCharge(EntityUid uid, float value, BatteryComponent? battery = null)
-        {
-            if (!Resolve(uid, ref battery))
-                return;
+    private void OnNetBatteryRejuvenate(Entity<PowerNetworkBatteryComponent> ent, ref RejuvenateEvent args)
+    {
+        ent.Comp.NetworkBattery.CurrentStorage = ent.Comp.NetworkBattery.Capacity;
+    }
 
-            var old = battery.MaxCharge;
-            battery.MaxCharge = Math.Max(value, 0);
-            battery.CurrentCharge = Math.Min(battery.CurrentCharge, battery.MaxCharge);
-            if (MathHelper.CloseTo(battery.MaxCharge, old))
-                return;
+    private void OnBatteryRejuvenate(Entity<BatteryComponent> ent, ref RejuvenateEvent args)
+    {
+        SetCharge(ent.AsNullable(), ent.Comp.MaxCharge);
+    }
 
-            var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
-            RaiseLocalEvent(uid, ref ev);
-        }
+    private void OnExamine(Entity<ExaminableBatteryComponent> ent, ref ExaminedEvent args)
+    {
+        if (!args.IsInDetailsRange)
+            return;
+
+        if (!TryComp<BatteryComponent>(ent, out var battery))
+            return;
+
+        var chargePercentRounded = 0;
+        if (battery.MaxCharge != 0)
+            chargePercentRounded = (int)(100 * battery.CurrentCharge / battery.MaxCharge);
+        args.PushMarkup(
+            Loc.GetString(
+                "examinable-battery-component-examine-detail",
+                ("percent", chargePercentRounded),
+                ("markupPercentColor", "green")
+            )
+        );
+    }
 
-        public void SetCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+    private void PreSync(NetworkBatteryPreSync ev)
+    {
+        // Ignoring entity pausing. If the entity was paused, neither component's data should have been changed.
+        var enumerator = AllEntityQuery<PowerNetworkBatteryComponent, BatteryComponent>();
+        while (enumerator.MoveNext(out var netBat, out var bat))
         {
-            if (!Resolve(uid, ref battery))
-                return;
-
-            var old = battery.CurrentCharge;
-            battery.CurrentCharge = MathHelper.Clamp(value, 0, battery.MaxCharge);
-            if (MathHelper.CloseTo(battery.CurrentCharge, old) &&
-                !(old != battery.CurrentCharge && battery.CurrentCharge == battery.MaxCharge))
-            {
-                return;
-            }
-
-            var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
-            RaiseLocalEvent(uid, ref ev);
+            DebugTools.Assert(bat.CurrentCharge <= bat.MaxCharge && bat.CurrentCharge >= 0);
+            netBat.NetworkBattery.Capacity = bat.MaxCharge;
+            netBat.NetworkBattery.CurrentStorage = bat.CurrentCharge;
         }
+    }
 
-        /// <summary>
-        /// Changes the current battery charge by some value
-        /// </summary>
-        public override float ChangeCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+    private void PostSync(NetworkBatteryPostSync ev)
+    {
+        // Ignoring entity pausing. If the entity was paused, neither component's data should have been changed.
+        var enumerator = AllEntityQuery<PowerNetworkBatteryComponent, BatteryComponent>();
+        while (enumerator.MoveNext(out var uid, out var netBat, out var bat))
         {
-            if (!Resolve(uid, ref battery))
-                return 0;
-
-            var newValue = Math.Clamp(battery.CurrentCharge + value, 0, battery.MaxCharge);
-            var delta = newValue - battery.CurrentCharge;
-            battery.CurrentCharge = newValue;
-
-            TrySetChargeCooldown(uid);
-
-            var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
-            RaiseLocalEvent(uid, ref ev);
-            return delta;
+            SetCharge((uid, bat), netBat.NetworkBattery.CurrentStorage);
         }
+    }
 
-        public override void TrySetChargeCooldown(EntityUid uid, float value = -1)
-        {
-            if (!TryComp<BatterySelfRechargerComponent>(uid, out var batteryself))
-                return;
-
-            if (!batteryself.AutoRechargePause)
-                return;
-
-            // If no answer or a negative is given for value, use the default from AutoRechargePauseTime.
-            if (value < 0)
-                value = batteryself.AutoRechargePauseTime;
-
-            if (_timing.CurTime + TimeSpan.FromSeconds(value) <= batteryself.NextAutoRecharge)
-                return;
+    /// <summary>
+    /// Gets the price for the power contained in an entity's battery.
+    /// </summary>
+    private void CalculateBatteryPrice(Entity<BatteryComponent> ent, ref PriceCalculationEvent args)
+    {
+        args.Price += ent.Comp.CurrentCharge * ent.Comp.PricePerJoule;
+    }
 
-            SetChargeCooldown(uid, batteryself.AutoRechargePauseTime, batteryself);
-        }
+    private void OnChangeCharge(Entity<BatteryComponent> ent, ref ChangeChargeEvent args)
+    {
+        if (args.ResidualValue == 0)
+            return;
 
-        /// <summary>
-        /// Puts the entity's self recharge on cooldown for the specified time.
-        /// </summary>
-        public void SetChargeCooldown(EntityUid uid, float value, BatterySelfRechargerComponent? batteryself = null)
-        {
-            if (!Resolve(uid, ref batteryself))
-                return;
+        args.ResidualValue -= ChangeCharge(ent.AsNullable(), args.ResidualValue);
+    }
 
-            if (value >= 0)
-                batteryself.NextAutoRecharge = _timing.CurTime + TimeSpan.FromSeconds(value);
-            else
-                batteryself.NextAutoRecharge = _timing.CurTime;
-        }
+    private void OnGetCharge(Entity<BatteryComponent> entity, ref GetChargeEvent args)
+    {
+        args.CurrentCharge += entity.Comp.CurrentCharge;
+        args.MaxCharge += entity.Comp.MaxCharge;
+    }
 
-        /// <summary>
-        ///     If sufficient charge is available on the battery, use it. Otherwise, don't.
-        /// </summary>
-        public override bool TryUseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+    public override void Update(float frameTime)
+    {
+        var query = EntityQueryEnumerator<BatterySelfRechargerComponent, BatteryComponent>();
+        var curTime = _timing.CurTime;
+        while (query.MoveNext(out var uid, out var comp, out var bat))
         {
-            if (!Resolve(uid, ref battery, false) || value > battery.CurrentCharge)
-                return false;
-
-            UseCharge(uid, value, battery);
-            return true;
-        }
+            if (!comp.AutoRecharge || IsFull((uid, bat)))
+                continue;
 
-        /// <summary>
-        /// Returns whether the battery is full.
-        /// </summary>
-        public bool IsFull(EntityUid uid, BatteryComponent? battery = null)
-        {
-            if (!Resolve(uid, ref battery))
-                return false;
+            if (comp.NextAutoRecharge > curTime)
+                continue;
 
-            return battery.CurrentCharge >= battery.MaxCharge;
+            SetCharge((uid, bat), bat.CurrentCharge + comp.AutoRechargeRate * frameTime);
         }
     }
 }
index e8dc9e99629e7cf40c14b53c978cc48fb182beeb..d523de65dbf730fad5eb39a22297cbdf57a90ed0 100644 (file)
@@ -221,7 +221,7 @@ public sealed class ChargerSystem : SharedChargerSystem
         if (!SearchForBattery(container.ContainedEntities[0], out var heldEnt, out var heldBattery))
             return CellChargerStatus.Off;
 
-        if (_battery.IsFull(heldEnt.Value, heldBattery))
+        if (_battery.IsFull((heldEnt.Value, heldBattery)))
             return CellChargerStatus.Charged;
 
         return CellChargerStatus.Charging;
@@ -241,7 +241,7 @@ public sealed class ChargerSystem : SharedChargerSystem
         if (!SearchForBattery(targetEntity, out var batteryUid, out var heldBattery))
             return;
 
-        _battery.SetCharge(batteryUid.Value, heldBattery.CurrentCharge + component.ChargeRate * frameTime, heldBattery);
+        _battery.SetCharge((batteryUid.Value, heldBattery), heldBattery.CurrentCharge + component.ChargeRate * frameTime);
         UpdateStatus(uid, component);
     }
 
index 6a69550fcfdf45bb4c805045caa2453ac4bc8461..5b6b922ddf4b3b323135ab3215d2cf9ac33f3a40 100644 (file)
@@ -358,13 +358,13 @@ namespace Content.Server.Power.EntitySystems
 
                     if (requireBattery)
                     {
-                        _battery.SetCharge(uid, battery.CurrentCharge - apcBattery.IdleLoad * frameTime, battery);
+                        _battery.SetCharge((uid, battery), battery.CurrentCharge - apcBattery.IdleLoad * frameTime);
                     }
                     // Otherwise try to charge the battery
-                    else if (powered && !_battery.IsFull(uid, battery))
+                    else if (powered && !_battery.IsFull((uid, battery)))
                     {
                         apcReceiver.Load += apcBattery.BatteryRechargeRate * apcBattery.BatteryRechargeEfficiency;
-                        _battery.SetCharge(uid, battery.CurrentCharge + apcBattery.BatteryRechargeRate * frameTime, battery);
+                        _battery.SetCharge((uid, battery), battery.CurrentCharge + apcBattery.BatteryRechargeRate * frameTime);
                     }
 
                     // Enable / disable the battery if the state changed
index 03d6d30f8a43cebc5298aba7f28ffdbadc6dff92..a6123382fd9cec6b4c00fc18cd92915bcd7ab7f7 100644 (file)
@@ -40,7 +40,7 @@ namespace Content.Server.Power
                 shell.WriteLine(Loc.GetString($"cmd-setbatterypercent-battery-not-found", ("id", id)));
                 return;
             }
-            _batterySystem.SetCharge(id.Value, battery.MaxCharge * percent / 100, battery);
+            _batterySystem.SetCharge((id.Value, battery), battery.MaxCharge * percent / 100);
             // Don't acknowledge b/c people WILL forall this
         }
     }
index 40e54ba13a93e40940b8ad004bcbd19a71721b96..d0dafb1ef6464333fcd938c85fc6d0d8446c3d21 100644 (file)
@@ -28,7 +28,7 @@ public sealed partial class PowerCellSystem
             if (!TryGetBatteryFromSlot(uid, out var batteryEnt, out var battery, slot))
                 continue;
 
-            if (_battery.TryUseCharge(batteryEnt.Value, comp.DrawRate * (float)comp.Delay.TotalSeconds, battery))
+            if (_battery.TryUseCharge((batteryEnt.Value, battery), comp.DrawRate * (float)comp.Delay.TotalSeconds))
                 continue;
 
             var ev = new PowerCellSlotEmptyEvent();
index 6c00cdd30013a5578d6a930d32bb425183ec2062..f358e1bc34017e6ff4b213b1b1eb222e441c5184 100644 (file)
@@ -174,7 +174,7 @@ public sealed partial class PowerCellSystem : SharedPowerCellSystem
             return false;
         }
 
-        if (!_battery.TryUseCharge(batteryEnt.Value, charge, battery))
+        if (!_battery.TryUseCharge((batteryEnt.Value, battery), charge))
         {
             if (user != null)
                 _popup.PopupEntity(Loc.GetString("power-cell-insufficient"), uid, user.Value);
index d1071d3e38b4d17d229721ccca04a705f375b01b..328bff89f4d6902ec5d65a7887886c4a1c948713 100644 (file)
@@ -66,7 +66,7 @@ namespace Content.Server.PowerSink
                 if (!transform.Anchored)
                     continue;
 
-                _battery.ChangeCharge(entity, networkLoad.NetworkLoad.ReceivingPower * frameTime, battery);
+                _battery.ChangeCharge((entity, battery), networkLoad.NetworkLoad.ReceivingPower * frameTime);
 
                 var currentBatteryThreshold = battery.CurrentCharge / battery.MaxCharge;
 
index 02c9c64c6ef16157df8ad53393305fd24c5f9370..3ec2e9c38c2c09887a82d6825b6fa9c8ca39681f 100644 (file)
@@ -34,7 +34,7 @@ public sealed class JammerSystem : SharedJammerSystem
 
             if (_powerCell.TryGetBatteryFromSlot(uid, out var batteryUid, out var battery))
             {
-                if (!_battery.TryUseCharge(batteryUid.Value, GetCurrentWattage((uid, jam)) * frameTime, battery))
+                if (!_battery.TryUseCharge((batteryUid.Value, battery), GetCurrentWattage((uid, jam)) * frameTime))
                 {
                     ChangeLEDState(uid, false);
                     RemComp<ActiveRadioJammerComponent>(uid);
index a9198d5816f5ad7d34a7fdbb23191c45e2ecba66..0045b921e51af310eefaeb8bbdb5785ccb99bfff 100644 (file)
@@ -125,7 +125,7 @@ public sealed class StationAiSystem : SharedStationAiSystem
         // into an AI core that has a full battery and full integrity.
         if (TryComp<BatteryComponent>(ent, out var battery))
         {
-            _battery.SetCharge(ent, battery.MaxCharge);
+            _battery.SetCharge((ent, battery), battery.MaxCharge);
         }
 
         _damageable.ClearAllDamage(ent.Owner);
index 7f8aa37036d9074ef9930d366b2b7860e99a318d..a22a4c09fab540a7cd1abb65efd51b66bf393dce 100644 (file)
@@ -33,7 +33,7 @@ namespace Content.Server.Stunnable.Systems
         private void OnStaminaHitAttempt(Entity<StunbatonComponent> entity, ref StaminaDamageOnHitAttemptEvent args)
         {
             if (!_itemToggle.IsActivated(entity.Owner) ||
-            !TryComp<BatteryComponent>(entity.Owner, out var battery) || !_battery.TryUseCharge(entity.Owner, entity.Comp.EnergyPerUse, battery))
+            !TryComp<BatteryComponent>(entity.Owner, out var battery) || !_battery.TryUseCharge((entity.Owner, battery), entity.Comp.EnergyPerUse))
             {
                 args.Cancelled = true;
             }
index f3cae90b40d1d9e7737b86d4dbd6aa156c8f267a..988ade86cee437a769d98a637af5199781e8fdac 100644 (file)
@@ -24,7 +24,7 @@ public sealed class TeslaCoilSystem : EntitySystem
     {
         if (TryComp<BatteryComponent>(coil, out var batteryComponent))
         {
-            _battery.SetCharge(coil, batteryComponent.CurrentCharge + coil.Comp.ChargeFromLightning);
+            _battery.SetCharge((coil, batteryComponent), batteryComponent.CurrentCharge + coil.Comp.ChargeFromLightning);
         }
     }
 }
index 700a15e1b0132c0a21ade33258a7e7e825485ab7..c1e442c24b8ae3139dac85b6ed944d3942001be5 100644 (file)
@@ -68,6 +68,7 @@ public sealed partial class GunSystem
 
     protected override void TakeCharge(Entity<BatteryAmmoProviderComponent> entity)
     {
+        // Take charge from either the BatteryComponent or PowerCellSlotComponent.
         var ev = new ChangeChargeEvent(-entity.Comp.FireCost);
         RaiseLocalEvent(entity, ref ev);
     }
index 85ffc756272c7ff80d9bbbb6dc2158cccc464d33..21952912d73844672641cfa80e53dcd59a826836 100644 (file)
@@ -25,7 +25,7 @@ public sealed class XAEChargeBatterySystem : BaseXAESystem<XAEChargeBatteryCompo
         _lookup.GetEntitiesInRange(args.Coordinates, chargeBatteryComponent.Radius, _batteryEntities);
         foreach (var battery in _batteryEntities)
         {
-            _battery.SetCharge(battery, battery.Comp.MaxCharge, battery);
+            _battery.SetCharge(battery.AsNullable(), battery.Comp.MaxCharge);
         }
     }
 }
index db412e91d9a48452055f10553361bf1a175c228c..cc9dc49a7c829e5ebfc9f534d26f4a7cb76b0204 100644 (file)
@@ -1,3 +1,6 @@
+using Content.Shared.Power.Components;
+using Content.Shared.PowerCell.Components;
+
 namespace Content.Shared.Power;
 
 /// <summary>
@@ -7,27 +10,36 @@ namespace Content.Shared.Power;
 public readonly record struct ChargeChangedEvent(float Charge, float MaxCharge);
 
 /// <summary>
+/// Event that supports multiple battery types.
 /// Raised when it is necessary to get information about battery charges.
+/// Works with either <see cref="BatteryComponent"/> or <see cref="PowerCellSlotComponent"/>.
+/// If there are multiple batteries then the results will be summed up.
 /// </summary>
 [ByRefEvent]
-public sealed class GetChargeEvent : EntityEventArgs
+public record struct GetChargeEvent
 {
     public float CurrentCharge;
     public float MaxCharge;
 }
 
 /// <summary>
-/// Raised when it is necessary to change the current battery charge to a some value.
+/// Method event that supports multiple battery types.
+/// Raised when it is necessary to change the current battery charge by some value.
+/// Works with either <see cref="BatteryComponent"/> or <see cref="PowerCellSlotComponent"/>.
+/// If there are multiple batteries then they will be changed in order of subscription until the total value was reached.
 /// </summary>
 [ByRefEvent]
-public sealed class ChangeChargeEvent : EntityEventArgs
+public record struct ChangeChargeEvent(float Amount)
 {
-    public float OriginalValue;
-    public float ResidualValue;
+    /// <summary>
+    /// The total amount of charge to change the battery's storage by (in joule).
+    /// A positive value adds charge, a negative value removes charge.
+    /// </summary>
+    public readonly float Amount = Amount;
 
-    public ChangeChargeEvent(float value)
-    {
-        OriginalValue = value;
-        ResidualValue = value;
-    }
+    /// <summary>
+    /// The amount of charge that still has to be removed.
+    /// For cases where there are multiple batteries.
+    /// </summary>
+    public float ResidualValue = Amount;
 }
index 6a2d2a5051003f7882c9b24a6e486f3109326115..6a65405115d26e69d3869553e158c42f3af78c78 100644 (file)
@@ -11,10 +11,8 @@ namespace Content.Shared.Power.Components;
 [Access(typeof(SharedBatterySystem))]
 public partial class BatteryComponent : Component
 {
-    public string SolutionName = "battery";
-
     /// <summary>
-    /// Maximum charge of the battery in joules (ie. watt seconds)
+    /// Maximum charge of the battery in joules (i.e. watt seconds)
     /// </summary>
     [DataField]
     [GuidebookData]
@@ -23,11 +21,11 @@ public partial class BatteryComponent : Component
     /// <summary>
     /// Current charge of the battery in joules (ie. watt seconds)
     /// </summary>
-    [DataField("startingCharge")]
+    [DataField("startingCharge")] // TODO: rename this datafield to currentCharge
     public float CurrentCharge;
 
     /// <summary>
-    /// The price per one joule. Default is 1 credit for 10kJ.
+    /// The price per one joule. Default is 1 speso for 10kJ.
     /// </summary>
     [DataField]
     public float PricePerJoule = 0.0001f;
diff --git a/Content.Shared/Power/Components/BatterySelfRechargerComponent.cs b/Content.Shared/Power/Components/BatterySelfRechargerComponent.cs
new file mode 100644 (file)
index 0000000..3881980
--- /dev/null
@@ -0,0 +1,36 @@
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Shared.Power.Components;
+
+/// <summary>
+/// Self-recharging battery.
+/// To be used in combination with <see cref="BatteryComponent"/>.
+/// </summary>
+[RegisterComponent, AutoGenerateComponentPause]
+public sealed partial class BatterySelfRechargerComponent : Component
+{
+    /// <summary>
+    /// Is the component currently enabled?
+    /// </summary>
+    [DataField]
+    public bool AutoRecharge = true;
+
+    /// <summary>
+    /// At what rate does the entity automatically recharge?
+    /// </summary>
+    [DataField]
+    public float AutoRechargeRate;
+
+    /// <summary>
+    /// How long should the entity stop automatically recharging if charge is used?
+    /// </summary>
+    [DataField]
+    public TimeSpan AutoRechargePauseTime = TimeSpan.FromSeconds(0);
+
+    /// <summary>
+    /// Do not auto recharge if this timestamp has yet to happen, set for the auto recharge pause system.
+    /// </summary>
+    [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+    [AutoPausedField]
+    public TimeSpan NextAutoRecharge = TimeSpan.FromSeconds(0);
+}
index a9d5db3f331615de28d47f4665b753b15c15f3f0..d067a685d496e7d67c40fdaec60d240003eaac1a 100644 (file)
@@ -12,33 +12,61 @@ public abstract class SharedBatterySystem : EntitySystem
         SubscribeLocalEvent<BatteryComponent, EmpPulseEvent>(OnEmpPulse);
     }
 
-    private void OnEmpPulse(Entity<BatteryComponent> entity, ref EmpPulseEvent args)
+    private void OnEmpPulse(Entity<BatteryComponent> ent, ref EmpPulseEvent args)
     {
         args.Affected = true;
-        UseCharge(entity, args.EnergyConsumption, entity.Comp);
+        UseCharge(ent.AsNullable(), args.EnergyConsumption);
         // Apply a cooldown to the entity's self recharge if needed to avoid it immediately self recharging after an EMP.
-        TrySetChargeCooldown(entity);
+        TrySetChargeCooldown(ent.Owner);
     }
 
-    public virtual float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+    /// <summary>
+    /// Changes the battery's charge by the given amount.
+    /// A positive value will add charge, a negative value will remove charge.
+    /// </summary>
+    /// <returns>The actually changed amount.</returns>
+    public virtual float ChangeCharge(Entity<BatteryComponent?> ent, float amount)
     {
         return 0f;
     }
 
-    public virtual void SetMaxCharge(EntityUid uid, float value, BatteryComponent? battery = null) { }
-
-    public virtual float ChangeCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+    /// <summary>
+    /// Removes the given amount of charge from the battery.
+    /// </summary>
+    /// <returns>The actually changed amount.</returns>
+    public virtual float UseCharge(Entity<BatteryComponent?> ent, float amount)
     {
         return 0f;
     }
 
     /// <summary>
-    /// Checks if the entity has a self recharge and puts it on cooldown if applicable.
+    /// If sufficient charge is available on the battery, use it. Otherwise, don't.
+    /// Always returns false on the client.
     /// </summary>
-    public virtual void TrySetChargeCooldown(EntityUid uid, float value = -1) { }
-
-    public virtual bool TryUseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+    /// <returns>If the full amount was able to be removed.</returns>
+    public virtual bool TryUseCharge(Entity<BatteryComponent?> ent, float amount)
     {
         return false;
     }
+
+    /// <summary>
+    /// Sets the battery's charge.
+    /// </summary>
+    public virtual void SetCharge(Entity<BatteryComponent?> ent, float value) { }
+
+    /// <summary>
+    /// Sets the battery's maximum charge.
+    /// </summary>
+    public virtual void SetMaxCharge(Entity<BatteryComponent?> ent, float value) { }
+
+    /// <summary>
+    /// Checks if the entity has a self recharge and puts it on cooldown if applicable.
+    /// Uses the cooldown time given in the component.
+    /// </summary>
+    public virtual void TrySetChargeCooldown(Entity<BatterySelfRechargerComponent?> ent) { }
+
+    /// <summary>
+    /// Puts the entity's self recharge on cooldown for the specified time.
+    /// </summary>
+    public virtual void SetChargeCooldown(Entity<BatterySelfRechargerComponent?> ent, TimeSpan cooldown) { }
 }
index 800176593ee883731c4bfbb89a723bedf3f469ce..9d92c7b108a8f7091cb6d57c496b3fbe21d9b6be 100644 (file)
@@ -494,7 +494,6 @@ entities:
       parent: 1
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
 - proto: BasaltOne
   entities:
   - uid: 353
index d9c12c724b79da6126939d018dbc4b4b08da23ef..6c2f55049d39ec3df7a9928fedc93e92f57b0e33 100644 (file)
@@ -363,7 +363,6 @@ entities:
       parent: 1
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
 - proto: AtmosFixFreezerMarker
   entities:
   - uid: 348
index 68897953f7adf7fd7c631ac836255e4d7d9bc093..bb0491e9cec8159dcc179a165f8fb77c4614c1b0 100644 (file)
@@ -1381,7 +1381,6 @@ entities:
     - type: Godmode
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
     - type: Fixtures
       fixtures: {}
     missingComponents:
@@ -1398,7 +1397,6 @@ entities:
     - type: Godmode
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
     - type: Fixtures
       fixtures: {}
     missingComponents:
@@ -1415,7 +1413,6 @@ entities:
     - type: Godmode
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
     - type: Fixtures
       fixtures: {}
     missingComponents:
@@ -1432,7 +1429,6 @@ entities:
     - type: Godmode
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
     - type: Fixtures
       fixtures: {}
     missingComponents:
@@ -1450,7 +1446,6 @@ entities:
     - type: Godmode
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
     - type: Fixtures
       fixtures: {}
     missingComponents:
@@ -1467,7 +1462,6 @@ entities:
     - type: Godmode
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
     - type: Fixtures
       fixtures: {}
     missingComponents:
index b08dac6b68e63db802ae47ef337704b68318d8b8..7846b2596b8ad6b2ba4e1c7f320c16139d93738f 100644 (file)
@@ -504,7 +504,6 @@ entities:
       parent: 1
     - type: BatterySelfRecharger
       autoRechargeRate: 200000
-      autoRecharge: True
 - proto: BarberScissors
   entities:
   - uid: 649
index d953e10700ddd914d603186cca0b99ec0a971588..89ae5e5171e69b973ac7a126633ccff4725d6107 100644 (file)
@@ -584,7 +584,6 @@ entities:
       parent: 2
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
   - uid: 362
     components:
     - type: Transform
index 3c853ef7395620f3689b8c37bd8eaafa4e4c420f..f419f26a1f0e6c9ab81e40f42b0a4605efc28882 100644 (file)
@@ -297,7 +297,6 @@ entities:
       parent: 292
     - type: BatterySelfRecharger
       autoRechargeRate: 50000
-      autoRecharge: True
     - type: Godmode
     missingComponents:
     - Construction
index 53772f62153b4aaee12cb83d1e50168a1ea437f0..3b85ce94c9ee2b0a3a626d4ca4486cb5a30d6856 100644 (file)
     maxCharge: 600 #lights drain 3/s but recharge of 2 makes this 1/s. Therefore 600 is 10 minutes of light.
     startingCharge: 600
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 2 #recharge of 2 makes total drain 1w / s so max charge is 1:1 with time. Time to fully charge should be 5 minutes. Having recharge gives light an extended flicker period which gives you some warning to return to light area.
 
 - type: entity
index 5cc78d90b09c874d12e4e37aaa6ee23de227ba24..341404af2b2d78e39f5647b0afb325d57e8db1e5 100644 (file)
     maxCharge: 600
     startingCharge: 600
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 2
   - type: Item
     size: Normal
index 8229b103e7d36c6e66b01e371b4bcd70f16a1e26..65cc71aaa86db7f4fd9ef0fabacfdc1423baa17c 100644 (file)
@@ -26,7 +26,6 @@
       maxCharge: 1000
       startingCharge: 1000
     - type: BatterySelfRecharger
-      autoRecharge: true
       autoRechargeRate: 40
     - type: Gun
       fireRate: 0.75
index 7d6c28fc95cc3c7f934915796287f295b1c74cee..b4add804aef4d6f3f747026ff24d36265bec3f87 100644 (file)
@@ -54,7 +54,6 @@
     proto: WatcherBolt
     fireCost: 50
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 50
   - type: Battery
     maxCharge: 1000
index 4717e200ddb8d62fde86426d1d47234fc7055fa1..1531e348f72c932edbe50b27a89e706d85bbc6d9 100644 (file)
     maxCharge: 1000
     startingCharge: 1000
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 50
   - type: Gun
     fireRate: 0.3
index 64fa4e22924d48adf349a5f63bdacb863badd0bf..173c5ad165421ada4c257830318968a150e73592 100644 (file)
@@ -51,7 +51,6 @@
       proto: RedLightLaser
       fireCost: 50
     - type: BatterySelfRecharger
-      autoRecharge: true
       autoRechargeRate: 50
     - type: Battery
       maxCharge: 1000
index e4651a5875d29d9e8ca22b21b0b709a1b293b139..4ce96419bf37f8f605fba2f86af8556abc51329c 100644 (file)
@@ -98,9 +98,7 @@
   description: A self rechargeable power cell, designed for fast recharge rate at the expense of capacity.
   components:
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 36 # 10 seconds to recharge
-    autoRechargePause: true
     autoRechargePauseTime: 30
 
 - type: entity
     maxCharge: 720
     startingCharge: 720
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 12 # takes 1 minute to charge itself back to full
 
 - type: entity
       maxCharge: 1200
       startingCharge: 1200
     - type: BatterySelfRecharger
-      autoRecharge: true
       autoRechargeRate: 40
 
 # Power cage (big heavy power cell for big devices)
index 8e2650b5fea7e994b3f018f443b2f13e3c8a8b8c..10181b54e70a3cec43632a31ce2d68a6c28156a9 100644 (file)
     proto: RedMediumLaser
     fireCost: 100
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 40
   - type: MagazineVisuals
     magState: mag
     proto: RedMediumLaser
     fireCost: 100
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 30
   - type: MagazineVisuals
     magState: mag
     proto: RedMediumLaser
     fireCost: 100
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 40
   - type: StaticPrice
     price: 750
       fireCost: 62.5
       pacifismAllowedMode: true
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 48
-    autoRechargePause: true
     autoRechargePauseTime: 10
 
 - type: entity
index 80d71669a7e8f1a222a369bab2979edf58ca420b..be57d5f0f91b597d28081e3f66aebdbb127a295b 100644 (file)
       maxCharge: 10000
       startingCharge: 10000
     - type: BatterySelfRecharger
-      autoRecharge: true
       autoRechargeRate: 25
     - type: AmmoCounter
index ec3fa31297307173b40fe578ee0bde827859de3e..ca40d1940d19310f7cc6b50ec98b109f8cb615e6 100644 (file)
     maxCharge: 1000
     startingCharge: 1000
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 25
   - type: AmmoCounter
 
index 2ecaaec89ebd9042ff2d22af2cc8decc352117ea..15ddb7b38e859b7500a9aa2b86e3e6f0f21ef1ef 100644 (file)
     maxCharge: 3000
     startingCharge: 3000
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 25
   - type: AmmoCounter
 
index ec7e4b3e7f7ec72308d75b6e53efd3de8be15c7e..6b8c4eebe1ffd3402a47b8e6cc5e111e1f69fe11 100644 (file)
     maxCharge: 90
     startingCharge: 90
   - type: BatterySelfRecharger
-    autoRecharge: true
     autoRechargeRate: 1
   - type: AmmoCounter
   - type: Item
index a2e1c585fb42f5f9650139534ef57fbc5c43d940..a9c3671c33dfdb04cf12dd46956900566ea8bd43 100644 (file)
   components:
   - type: BatterySelfRecharger
     autoRechargeRate: 50000
-    autoRecharge: True
 
 - type: entity
   parent: BaseSubstation
   components:
   - type: BatterySelfRecharger
     autoRechargeRate: 50000
-    autoRecharge: True
 
 - type: entity
   parent: BaseSubstationWall
   components:
   - type: BatterySelfRecharger
     autoRechargeRate: 50000
-    autoRecharge: True
 
 - type: entity
   parent: BaseAPC
   components:
   - type: BatterySelfRecharger
     autoRechargeRate: 50000
-    autoRecharge: True
 
 - type: entity
   id: DebugPowerReceiver