Cleanup BatterySystem (#41298)

* cleanup

* fix fixtures

* this belongs into the next PR

* review

* misc

---------

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
This commit is contained in:
slarticodefast
2025-11-08 21:55:02 +01:00
committed by GitHub
parent 841c09bbf1
commit 7155d0d291
45 changed files with 356 additions and 366 deletions

View 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
});

View 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,

View 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))
{

View 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);

View 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}");

View 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));
}
}

View 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>

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -9,232 +9,115 @@ using JetBrains.Annotations;
using Robust.Shared.Utility;
using Robust.Shared.Timing;
namespace Content.Server.Power.EntitySystems
namespace Content.Server.Power.EntitySystems;
[UsedImplicitly]
public sealed partial class BatterySystem : SharedBatterySystem
{
[UsedImplicitly]
public sealed class BatterySystem : SharedBatterySystem
[Dependency] private readonly IGameTiming _timing = default!;
public override void Initialize()
{
[Dependency] private readonly IGameTiming _timing = default!;
base.Initialize();
public override void Initialize()
SubscribeLocalEvent<ExaminableBatteryComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnBatteryRejuvenate);
SubscribeLocalEvent<PowerNetworkBatteryComponent, RejuvenateEvent>(OnNetBatteryRejuvenate);
SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
SubscribeLocalEvent<BatteryComponent, ChangeChargeEvent>(OnChangeCharge);
SubscribeLocalEvent<BatteryComponent, GetChargeEvent>(OnGetCharge);
SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync);
SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync);
}
private void OnNetBatteryRejuvenate(Entity<PowerNetworkBatteryComponent> ent, ref RejuvenateEvent args)
{
ent.Comp.NetworkBattery.CurrentStorage = ent.Comp.NetworkBattery.Capacity;
}
private void OnBatteryRejuvenate(Entity<BatteryComponent> ent, ref RejuvenateEvent args)
{
SetCharge(ent.AsNullable(), ent.Comp.MaxCharge);
}
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")
)
);
}
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))
{
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);
DebugTools.Assert(bat.CurrentCharge <= bat.MaxCharge && bat.CurrentCharge >= 0);
netBat.NetworkBattery.Capacity = bat.MaxCharge;
netBat.NetworkBattery.CurrentStorage = bat.CurrentCharge;
}
}
private void OnNetBatteryRejuvenate(EntityUid uid, PowerNetworkBatteryComponent component, RejuvenateEvent args)
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))
{
component.NetworkBattery.CurrentStorage = component.NetworkBattery.Capacity;
SetCharge((uid, bat), netBat.NetworkBattery.CurrentStorage);
}
}
private void OnBatteryRejuvenate(EntityUid uid, BatteryComponent component, RejuvenateEvent args)
/// <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;
}
private void OnChangeCharge(Entity<BatteryComponent> ent, ref ChangeChargeEvent args)
{
if (args.ResidualValue == 0)
return;
args.ResidualValue -= ChangeCharge(ent.AsNullable(), args.ResidualValue);
}
private void OnGetCharge(Entity<BatteryComponent> entity, ref GetChargeEvent args)
{
args.CurrentCharge += entity.Comp.CurrentCharge;
args.MaxCharge += entity.Comp.MaxCharge;
}
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))
{
SetCharge(uid, component.MaxCharge, component);
}
if (!comp.AutoRecharge || IsFull((uid, bat)))
continue;
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")
)
);
}
}
if (comp.NextAutoRecharge > curTime)
continue;
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);
}
private void OnGetCharge(Entity<BatteryComponent> entity, ref GetChargeEvent args)
{
args.CurrentCharge += entity.Comp.CurrentCharge;
args.MaxCharge += entity.Comp.MaxCharge;
}
public override float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
{
if (value <= 0 || !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
return 0;
return ChangeCharge(uid, -value, battery);
}
public override void SetMaxCharge(EntityUid uid, float value, BatteryComponent? battery = null)
{
if (!Resolve(uid, ref battery))
return;
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;
var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
RaiseLocalEvent(uid, ref ev);
}
public void SetCharge(EntityUid uid, float value, BatteryComponent? battery = null)
{
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);
}
/// <summary>
/// Changes the current battery charge by some value
/// </summary>
public override float ChangeCharge(EntityUid uid, float value, BatteryComponent? battery = null)
{
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;
}
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;
SetChargeCooldown(uid, batteryself.AutoRechargePauseTime, batteryself);
}
/// <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;
if (value >= 0)
batteryself.NextAutoRecharge = _timing.CurTime + TimeSpan.FromSeconds(value);
else
batteryself.NextAutoRecharge = _timing.CurTime;
}
/// <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)
{
if (!Resolve(uid, ref battery, false) || value > battery.CurrentCharge)
return false;
UseCharge(uid, value, battery);
return true;
}
/// <summary>
/// Returns whether the battery is full.
/// </summary>
public bool IsFull(EntityUid uid, BatteryComponent? battery = null)
{
if (!Resolve(uid, ref battery))
return false;
return battery.CurrentCharge >= battery.MaxCharge;
SetCharge((uid, bat), bat.CurrentCharge + comp.AutoRechargeRate * frameTime);
}
}
}

View 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);
}

View 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

View 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
}
}

View 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();

View 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);

View 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;

View 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);

View 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);

View 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;
}

View 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);
}
}
}

View 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);
}

View 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);
}
}
}

View 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;
}

View 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;

View File

@@ -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);
}

View 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)
{
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>
/// 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;
}
/// <summary>
/// Checks if the entity has a self recharge and puts it on cooldown if applicable.
/// Removes the given amount of charge from the battery.
/// </summary>
public virtual void TrySetChargeCooldown(EntityUid uid, float value = -1) { }
/// <returns>The actually changed amount.</returns>
public virtual float UseCharge(Entity<BatteryComponent?> ent, float amount)
{
return 0f;
}
public virtual bool TryUseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
/// <summary>
/// If sufficient charge is available on the battery, use it. Otherwise, don't.
/// Always returns false on the client.
/// </summary>
/// <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) { }
}

View File

@@ -494,7 +494,6 @@ entities:
parent: 1
- type: BatterySelfRecharger
autoRechargeRate: 50000
autoRecharge: True
- proto: BasaltOne
entities:
- uid: 353

View File

@@ -363,7 +363,6 @@ entities:
parent: 1
- type: BatterySelfRecharger
autoRechargeRate: 50000
autoRecharge: True
- proto: AtmosFixFreezerMarker
entities:
- uid: 348

View 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:

View File

@@ -504,7 +504,6 @@ entities:
parent: 1
- type: BatterySelfRecharger
autoRechargeRate: 200000
autoRecharge: True
- proto: BarberScissors
entities:
- uid: 649

View File

@@ -584,7 +584,6 @@ entities:
parent: 2
- type: BatterySelfRecharger
autoRechargeRate: 50000
autoRecharge: True
- uid: 362
components:
- type: Transform

View File

@@ -297,7 +297,6 @@ entities:
parent: 292
- type: BatterySelfRecharger
autoRechargeRate: 50000
autoRecharge: True
- type: Godmode
missingComponents:
- Construction

View File

@@ -247,7 +247,6 @@
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

View File

@@ -300,7 +300,6 @@
maxCharge: 600
startingCharge: 600
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 2
- type: Item
size: Normal

View File

@@ -26,7 +26,6 @@
maxCharge: 1000
startingCharge: 1000
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 40
- type: Gun
fireRate: 0.75

View File

@@ -54,7 +54,6 @@
proto: WatcherBolt
fireCost: 50
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 50
- type: Battery
maxCharge: 1000

View File

@@ -175,7 +175,6 @@
maxCharge: 1000
startingCharge: 1000
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 50
- type: Gun
fireRate: 0.3

View File

@@ -51,7 +51,6 @@
proto: RedLightLaser
fireCost: 50
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 50
- type: Battery
maxCharge: 1000

View 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
@@ -226,7 +224,6 @@
maxCharge: 720
startingCharge: 720
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 12 # takes 1 minute to charge itself back to full
- type: entity
@@ -262,7 +259,6 @@
maxCharge: 1200
startingCharge: 1200
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 40
# Power cage (big heavy power cell for big devices)

View File

@@ -664,7 +664,6 @@
proto: RedMediumLaser
fireCost: 100
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 40
- type: MagazineVisuals
magState: mag
@@ -712,7 +711,6 @@
proto: RedMediumLaser
fireCost: 100
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 30
- type: MagazineVisuals
magState: mag
@@ -808,7 +806,6 @@
proto: RedMediumLaser
fireCost: 100
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 40
- type: StaticPrice
price: 750
@@ -901,9 +898,7 @@
fireCost: 62.5
pacifismAllowedMode: true
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 48
autoRechargePause: true
autoRechargePauseTime: 10
- type: entity

View File

@@ -124,6 +124,5 @@
maxCharge: 10000
startingCharge: 10000
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 25
- type: AmmoCounter

View File

@@ -135,7 +135,6 @@
maxCharge: 1000
startingCharge: 1000
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 25
- type: AmmoCounter

View File

@@ -160,7 +160,6 @@
maxCharge: 3000
startingCharge: 3000
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 25
- type: AmmoCounter

View File

@@ -132,7 +132,6 @@
maxCharge: 90
startingCharge: 90
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 1
- type: AmmoCounter
- type: Item

View File

@@ -124,7 +124,6 @@
components:
- type: BatterySelfRecharger
autoRechargeRate: 50000
autoRecharge: True
- type: entity
parent: BaseSubstation
@@ -138,7 +137,6 @@
components:
- type: BatterySelfRecharger
autoRechargeRate: 50000
autoRecharge: True
- type: entity
parent: BaseSubstationWall
@@ -152,7 +150,6 @@
components:
- type: BatterySelfRecharger
autoRechargeRate: 50000
autoRecharge: True
- type: entity
parent: BaseAPC
@@ -166,7 +163,6 @@
components:
- type: BatterySelfRecharger
autoRechargeRate: 50000
autoRecharge: True
- type: entity
id: DebugPowerReceiver