Unify BatteryComponent and PredictedBatteryComponent (#41867)
* unify * cleanup and merge conflicts * floating points --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
parent
d039f6fdfd
commit
17ff77b61f
|
|
@ -23,7 +23,7 @@ public sealed partial class BorgMenu : FancyWindow
|
||||||
[Dependency] private readonly IEntityManager _entity = default!;
|
[Dependency] private readonly IEntityManager _entity = default!;
|
||||||
private readonly NameModifierSystem _nameModifier;
|
private readonly NameModifierSystem _nameModifier;
|
||||||
private readonly PowerCellSystem _powerCell;
|
private readonly PowerCellSystem _powerCell;
|
||||||
private readonly PredictedBatterySystem _battery;
|
private readonly SharedBatterySystem _battery;
|
||||||
|
|
||||||
public Action? BrainButtonPressed;
|
public Action? BrainButtonPressed;
|
||||||
public Action? IdChipButtonPressed; // DeltaV
|
public Action? IdChipButtonPressed; // DeltaV
|
||||||
|
|
@ -47,7 +47,7 @@ public sealed partial class BorgMenu : FancyWindow
|
||||||
|
|
||||||
_nameModifier = _entity.System<NameModifierSystem>();
|
_nameModifier = _entity.System<NameModifierSystem>();
|
||||||
_powerCell = _entity.System<PowerCellSystem>();
|
_powerCell = _entity.System<PowerCellSystem>();
|
||||||
_battery = _entity.System<PredictedBatterySystem>();
|
_battery = _entity.System<SharedBatterySystem>();
|
||||||
|
|
||||||
_maxNameLength = _cfgManager.GetCVar(CCVars.MaxNameLength);
|
_maxNameLength = _cfgManager.GetCVar(CCVars.MaxNameLength);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
|
||||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||||
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly IPlayerManager _player = default!;
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
nodeGroupID: HVPower
|
nodeGroupID: HVPower
|
||||||
- type: PowerNetworkBattery
|
- type: PowerNetworkBattery
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
netsync: false
|
||||||
- type: BatteryCharger
|
- type: BatteryCharger
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|
@ -68,6 +69,7 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
nodeGroupID: HVPower
|
nodeGroupID: HVPower
|
||||||
- type: PowerNetworkBattery
|
- type: PowerNetworkBattery
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
netsync: false
|
||||||
- type: BatteryDischarger
|
- type: BatteryDischarger
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|
@ -85,6 +87,7 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
nodeGroupID: HVPower
|
nodeGroupID: HVPower
|
||||||
- type: PowerNetworkBattery
|
- type: PowerNetworkBattery
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
netsync: false
|
||||||
- type: BatteryDischarger
|
- type: BatteryDischarger
|
||||||
node: output
|
node: output
|
||||||
- type: BatteryCharger
|
- type: BatteryCharger
|
||||||
|
|
@ -110,6 +113,7 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
maxSupply: 1000
|
maxSupply: 1000
|
||||||
supplyRampTolerance: 1000
|
supplyRampTolerance: 1000
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
netsync: false
|
||||||
maxCharge: 1000
|
maxCharge: 1000
|
||||||
startingCharge: 1000
|
startingCharge: 1000
|
||||||
- type: Transform
|
- type: Transform
|
||||||
|
|
@ -119,6 +123,7 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
id: ApcDummy
|
id: ApcDummy
|
||||||
components:
|
components:
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
netsync: false
|
||||||
maxCharge: 10000
|
maxCharge: 10000
|
||||||
startingCharge: 10000
|
startingCharge: 10000
|
||||||
- type: PowerNetworkBattery
|
- type: PowerNetworkBattery
|
||||||
|
|
@ -380,6 +385,8 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
const float startingCharge = 100_000;
|
const float startingCharge = 100_000;
|
||||||
|
|
||||||
PowerNetworkBatteryComponent netBattery = default!;
|
PowerNetworkBatteryComponent netBattery = default!;
|
||||||
|
EntityUid generatorEnt = default!;
|
||||||
|
EntityUid consumerEnt = default!;
|
||||||
BatteryComponent battery = default!;
|
BatteryComponent battery = default!;
|
||||||
PowerConsumerComponent consumer = default!;
|
PowerConsumerComponent consumer = default!;
|
||||||
|
|
||||||
|
|
@ -395,8 +402,8 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i));
|
entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
var generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.Owner.ToCoordinates());
|
generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.Owner.ToCoordinates());
|
||||||
var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2));
|
consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2));
|
||||||
|
|
||||||
netBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(generatorEnt);
|
netBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(generatorEnt);
|
||||||
battery = entityManager.GetComponent<BatteryComponent>(generatorEnt);
|
battery = entityManager.GetComponent<BatteryComponent>(generatorEnt);
|
||||||
|
|
@ -441,7 +448,8 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
|
|
||||||
// Trivial integral to calculate expected power spent.
|
// Trivial integral to calculate expected power spent.
|
||||||
const double spentExpected = (200 + 100) / 2.0 * 0.25;
|
const double spentExpected = (200 + 100) / 2.0 * 0.25;
|
||||||
Assert.That(battery.CurrentCharge, Is.EqualTo(startingCharge - spentExpected).Within(tickDev));
|
var currentCharge = batterySys.GetCharge((generatorEnt, battery));
|
||||||
|
Assert.That(currentCharge, Is.EqualTo(startingCharge - spentExpected).Within(tickDev));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -460,7 +468,8 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
|
|
||||||
// Trivial integral to calculate expected power spent.
|
// Trivial integral to calculate expected power spent.
|
||||||
const double spentExpected = (400 + 100) / 2.0 * 0.75 + 400 * 0.25;
|
const double spentExpected = (400 + 100) / 2.0 * 0.75 + 400 * 0.25;
|
||||||
Assert.That(battery.CurrentCharge, Is.EqualTo(startingCharge - spentExpected).Within(tickDev));
|
var currentCharge = batterySys.GetCharge((generatorEnt, battery));
|
||||||
|
Assert.That(currentCharge, Is.EqualTo(startingCharge - spentExpected).Within(tickDev));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -576,6 +585,8 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
var batterySys = entityManager.System<BatterySystem>();
|
var batterySys = entityManager.System<BatterySystem>();
|
||||||
var mapSys = entityManager.System<SharedMapSystem>();
|
var mapSys = entityManager.System<SharedMapSystem>();
|
||||||
|
EntityUid generatorEnt = default!;
|
||||||
|
EntityUid batteryEnt = default!;
|
||||||
PowerSupplierComponent supplier = default!;
|
PowerSupplierComponent supplier = default!;
|
||||||
BatteryComponent battery = default!;
|
BatteryComponent battery = default!;
|
||||||
|
|
||||||
|
|
@ -591,8 +602,8 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i));
|
entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates());
|
generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates());
|
||||||
var batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", grid.Owner.ToCoordinates(0, 2));
|
batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", grid.Owner.ToCoordinates(0, 2));
|
||||||
|
|
||||||
supplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt);
|
supplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt);
|
||||||
var netBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(batteryEnt);
|
var netBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(batteryEnt);
|
||||||
|
|
@ -615,7 +626,8 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
{
|
{
|
||||||
// half a second @ 500 W = 250
|
// half a second @ 500 W = 250
|
||||||
// 50% efficiency, so 125 J stored total.
|
// 50% efficiency, so 125 J stored total.
|
||||||
Assert.That(battery.CurrentCharge, Is.EqualTo(125).Within(0.1));
|
var currentCharge = batterySys.GetCharge((batteryEnt, battery));
|
||||||
|
Assert.That(currentCharge, Is.EqualTo(125).Within(0.1));
|
||||||
Assert.That(supplier.CurrentSupply, Is.EqualTo(500).Within(0.1));
|
Assert.That(supplier.CurrentSupply, Is.EqualTo(500).Within(0.1));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -633,6 +645,9 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
var gameTiming = server.ResolveDependency<IGameTiming>();
|
var gameTiming = server.ResolveDependency<IGameTiming>();
|
||||||
var batterySys = entityManager.System<BatterySystem>();
|
var batterySys = entityManager.System<BatterySystem>();
|
||||||
var mapSys = entityManager.System<SharedMapSystem>();
|
var mapSys = entityManager.System<SharedMapSystem>();
|
||||||
|
EntityUid batteryEnt = default!;
|
||||||
|
EntityUid supplyEnt = default!;
|
||||||
|
EntityUid consumerEnt = default!;
|
||||||
PowerConsumerComponent consumer = default!;
|
PowerConsumerComponent consumer = default!;
|
||||||
PowerSupplierComponent supplier = default!;
|
PowerSupplierComponent supplier = default!;
|
||||||
PowerNetworkBatteryComponent netBattery = default!;
|
PowerNetworkBatteryComponent netBattery = default!;
|
||||||
|
|
@ -653,9 +668,9 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1));
|
var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1));
|
||||||
entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180);
|
entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180);
|
||||||
|
|
||||||
var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2));
|
batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2));
|
||||||
var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0));
|
supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0));
|
||||||
var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3));
|
consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3));
|
||||||
|
|
||||||
consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt);
|
consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt);
|
||||||
supplier = entityManager.GetComponent<PowerSupplierComponent>(supplyEnt);
|
supplier = entityManager.GetComponent<PowerSupplierComponent>(supplyEnt);
|
||||||
|
|
@ -694,7 +709,8 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
Assert.That(netBattery.SupplyRampPosition, Is.EqualTo(200).Within(0.1));
|
Assert.That(netBattery.SupplyRampPosition, Is.EqualTo(200).Within(0.1));
|
||||||
|
|
||||||
const int expectedSpent = 200;
|
const int expectedSpent = 200;
|
||||||
Assert.That(battery.CurrentCharge, Is.EqualTo(battery.MaxCharge - expectedSpent).Within(tickDev));
|
var currentCharge = batterySys.GetCharge((batteryEnt, battery));
|
||||||
|
Assert.That(currentCharge, Is.EqualTo(battery.MaxCharge - expectedSpent).Within(tickDev));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -711,6 +727,9 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
var gameTiming = server.ResolveDependency<IGameTiming>();
|
var gameTiming = server.ResolveDependency<IGameTiming>();
|
||||||
var batterySys = entityManager.System<BatterySystem>();
|
var batterySys = entityManager.System<BatterySystem>();
|
||||||
var mapSys = entityManager.System<SharedMapSystem>();
|
var mapSys = entityManager.System<SharedMapSystem>();
|
||||||
|
EntityUid batteryEnt = default!;
|
||||||
|
EntityUid supplyEnt = default!;
|
||||||
|
EntityUid consumerEnt = default!;
|
||||||
PowerConsumerComponent consumer = default!;
|
PowerConsumerComponent consumer = default!;
|
||||||
PowerSupplierComponent supplier = default!;
|
PowerSupplierComponent supplier = default!;
|
||||||
PowerNetworkBatteryComponent netBattery = default!;
|
PowerNetworkBatteryComponent netBattery = default!;
|
||||||
|
|
@ -731,9 +750,9 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1));
|
var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1));
|
||||||
entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180);
|
entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180);
|
||||||
|
|
||||||
var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2));
|
batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2));
|
||||||
var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0));
|
supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0));
|
||||||
var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3));
|
consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3));
|
||||||
|
|
||||||
consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt);
|
consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt);
|
||||||
supplier = entityManager.GetComponent<PowerSupplierComponent>(supplyEnt);
|
supplier = entityManager.GetComponent<PowerSupplierComponent>(supplyEnt);
|
||||||
|
|
@ -772,7 +791,8 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
Assert.That(netBattery.SupplyRampPosition, Is.EqualTo(400).Within(0.1));
|
Assert.That(netBattery.SupplyRampPosition, Is.EqualTo(400).Within(0.1));
|
||||||
|
|
||||||
const int expectedSpent = 400;
|
const int expectedSpent = 400;
|
||||||
Assert.That(battery.CurrentCharge, Is.EqualTo(battery.MaxCharge - expectedSpent).Within(tickDev));
|
var currentCharge = batterySys.GetCharge((batteryEnt, battery));
|
||||||
|
Assert.That(currentCharge, Is.EqualTo(battery.MaxCharge - expectedSpent).Within(tickDev));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1223,6 +1243,9 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
var batterySys = entityManager.System<BatterySystem>();
|
var batterySys = entityManager.System<BatterySystem>();
|
||||||
var mapSys = entityManager.System<SharedMapSystem>();
|
var mapSys = entityManager.System<SharedMapSystem>();
|
||||||
|
EntityUid generatorEnt = default!;
|
||||||
|
EntityUid substationEnt = default!;
|
||||||
|
EntityUid apcEnt = default!;
|
||||||
PowerNetworkBatteryComponent substationNetBattery = default!;
|
PowerNetworkBatteryComponent substationNetBattery = default!;
|
||||||
BatteryComponent apcBattery = default!;
|
BatteryComponent apcBattery = default!;
|
||||||
|
|
||||||
|
|
@ -1242,9 +1265,9 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
entityManager.SpawnEntity("CableMV", grid.Owner.ToCoordinates(0, 1));
|
entityManager.SpawnEntity("CableMV", grid.Owner.ToCoordinates(0, 1));
|
||||||
entityManager.SpawnEntity("CableMV", grid.Owner.ToCoordinates(0, 2));
|
entityManager.SpawnEntity("CableMV", grid.Owner.ToCoordinates(0, 2));
|
||||||
|
|
||||||
var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0));
|
generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0));
|
||||||
var substationEnt = entityManager.SpawnEntity("SubstationDummy", grid.Owner.ToCoordinates(0, 1));
|
substationEnt = entityManager.SpawnEntity("SubstationDummy", grid.Owner.ToCoordinates(0, 1));
|
||||||
var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.Owner.ToCoordinates(0, 2));
|
apcEnt = entityManager.SpawnEntity("ApcDummy", grid.Owner.ToCoordinates(0, 2));
|
||||||
|
|
||||||
var generatorSupplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt);
|
var generatorSupplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt);
|
||||||
substationNetBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(substationEnt);
|
substationNetBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(substationEnt);
|
||||||
|
|
@ -1262,8 +1285,9 @@ namespace Content.IntegrationTests.Tests.Power
|
||||||
{
|
{
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
|
var currentCharge = batterySys.GetCharge((apcEnt, apcBattery));
|
||||||
Assert.That(substationNetBattery.CurrentSupply, Is.GreaterThan(0)); //substation should be providing power
|
Assert.That(substationNetBattery.CurrentSupply, Is.GreaterThan(0)); //substation should be providing power
|
||||||
Assert.That(apcBattery.CurrentCharge, Is.GreaterThan(0)); //apc battery should have gained charge
|
Assert.That(currentCharge, Is.GreaterThan(0)); //apc battery should have gained charge
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Content.Server.Maps;
|
using Content.Server.Maps;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Server.Power.NodeGroups;
|
using Content.Server.Power.NodeGroups;
|
||||||
using Content.Server.Power.Pow3r;
|
using Content.Server.Power.Pow3r;
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
|
|
@ -47,6 +48,7 @@ public sealed class StationPowerTests
|
||||||
var entMan = server.EntMan;
|
var entMan = server.EntMan;
|
||||||
var protoMan = server.ProtoMan;
|
var protoMan = server.ProtoMan;
|
||||||
var ticker = entMan.System<GameTicker>();
|
var ticker = entMan.System<GameTicker>();
|
||||||
|
var batterySys = entMan.System<BatterySystem>();
|
||||||
|
|
||||||
// Load the map
|
// Load the map
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
|
|
@ -70,7 +72,8 @@ public sealed class StationPowerTests
|
||||||
if (node.NodeGroup is not IBasePowerNet group)
|
if (node.NodeGroup is not IBasePowerNet group)
|
||||||
continue;
|
continue;
|
||||||
networks.TryGetValue(group.NetworkNode, out var charge);
|
networks.TryGetValue(group.NetworkNode, out var charge);
|
||||||
networks[group.NetworkNode] = charge + battery.CurrentCharge;
|
var currentCharge = batterySys.GetCharge((uid, battery));
|
||||||
|
networks[group.NetworkNode] = charge + currentCharge;
|
||||||
}
|
}
|
||||||
var totalStartingCharge = networks.MaxBy(n => n.Value).Value;
|
var totalStartingCharge = networks.MaxBy(n => n.Value).Value;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ using Content.Server.Cargo.Components;
|
||||||
using Content.Server.Doors.Systems;
|
using Content.Server.Doors.Systems;
|
||||||
using Content.Server.Hands.Systems;
|
using Content.Server.Hands.Systems;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.Power.EntitySystems;
|
|
||||||
using Content.Server.Revenant.Components; // Imp
|
using Content.Server.Revenant.Components; // Imp
|
||||||
using Content.Server.Revenant.EntitySystems; // Imp
|
using Content.Server.Revenant.EntitySystems; // Imp
|
||||||
using Content.Server.Stack;
|
using Content.Server.Stack;
|
||||||
|
|
@ -55,8 +54,7 @@ public sealed partial class AdminVerbSystem
|
||||||
[Dependency] private readonly AdminTestArenaSystem _adminTestArenaSystem = default!;
|
[Dependency] private readonly AdminTestArenaSystem _adminTestArenaSystem = default!;
|
||||||
[Dependency] private readonly StationJobsSystem _stationJobsSystem = default!;
|
[Dependency] private readonly StationJobsSystem _stationJobsSystem = default!;
|
||||||
[Dependency] private readonly JointSystem _jointSystem = default!;
|
[Dependency] private readonly JointSystem _jointSystem = default!;
|
||||||
[Dependency] private readonly BatterySystem _batterySystem = default!;
|
[Dependency] private readonly SharedBatterySystem _batterySystem = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _predictedBatterySystem = default!;
|
|
||||||
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
||||||
[Dependency] private readonly GunSystem _gun = default!;
|
[Dependency] private readonly GunSystem _gun = default!;
|
||||||
[Dependency] private readonly RevenantAnimatedSystem _revenantAnimate = default!; // Imp
|
[Dependency] private readonly RevenantAnimatedSystem _revenantAnimate = default!; // Imp
|
||||||
|
|
@ -166,57 +164,6 @@ public sealed partial class AdminVerbSystem
|
||||||
args.Verbs.Add(makeVulnerable);
|
args.Verbs.Add(makeVulnerable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<PredictedBatteryComponent>(args.Target, out var pBattery))
|
|
||||||
{
|
|
||||||
Verb refillBattery = new()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("admin-verbs-refill-battery"),
|
|
||||||
Category = VerbCategory.Tricks,
|
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
_predictedBatterySystem.SetCharge((args.Target, pBattery), pBattery.MaxCharge);
|
|
||||||
},
|
|
||||||
Impact = LogImpact.Medium,
|
|
||||||
Message = Loc.GetString("admin-trick-refill-battery-description"),
|
|
||||||
Priority = (int)TricksVerbPriorities.RefillBattery,
|
|
||||||
};
|
|
||||||
args.Verbs.Add(refillBattery);
|
|
||||||
|
|
||||||
Verb drainBattery = new()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("admin-verbs-drain-battery"),
|
|
||||||
Category = VerbCategory.Tricks,
|
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
_predictedBatterySystem.SetCharge((args.Target, pBattery), 0);
|
|
||||||
},
|
|
||||||
Impact = LogImpact.Medium,
|
|
||||||
Priority = (int)TricksVerbPriorities.DrainBattery,
|
|
||||||
};
|
|
||||||
args.Verbs.Add(drainBattery);
|
|
||||||
|
|
||||||
Verb infiniteBattery = new()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("admin-verbs-infinite-battery"),
|
|
||||||
Category = VerbCategory.Tricks,
|
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
var recharger = EnsureComp<PredictedBatterySelfRechargerComponent>(args.Target);
|
|
||||||
recharger.AutoRechargeRate = pBattery.MaxCharge; // Instant refill.
|
|
||||||
recharger.AutoRechargePauseTime = TimeSpan.Zero; // No delay.
|
|
||||||
Dirty(args.Target, recharger);
|
|
||||||
_predictedBatterySystem.RefreshChargeRate((args.Target, pBattery));
|
|
||||||
},
|
|
||||||
Impact = LogImpact.Medium,
|
|
||||||
Message = Loc.GetString("admin-trick-infinite-battery-object-description"),
|
|
||||||
Priority = (int)TricksVerbPriorities.InfiniteBattery,
|
|
||||||
};
|
|
||||||
args.Verbs.Add(infiniteBattery);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TryComp<BatteryComponent>(args.Target, out var battery))
|
if (TryComp<BatteryComponent>(args.Target, out var battery))
|
||||||
{
|
{
|
||||||
Verb refillBattery = new()
|
Verb refillBattery = new()
|
||||||
|
|
@ -259,6 +206,8 @@ public sealed partial class AdminVerbSystem
|
||||||
var recharger = EnsureComp<BatterySelfRechargerComponent>(args.Target);
|
var recharger = EnsureComp<BatterySelfRechargerComponent>(args.Target);
|
||||||
recharger.AutoRechargeRate = battery.MaxCharge; // Instant refill.
|
recharger.AutoRechargeRate = battery.MaxCharge; // Instant refill.
|
||||||
recharger.AutoRechargePauseTime = TimeSpan.Zero; // No delay.
|
recharger.AutoRechargePauseTime = TimeSpan.Zero; // No delay.
|
||||||
|
Dirty(args.Target, recharger);
|
||||||
|
_batterySystem.RefreshChargeRate((args.Target, battery));
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Medium,
|
Impact = LogImpact.Medium,
|
||||||
Message = Loc.GetString("admin-trick-infinite-battery-object-description"),
|
Message = Loc.GetString("admin-trick-infinite-battery-object-description"),
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ public sealed partial class BuildMech : IGraphAction
|
||||||
|
|
||||||
var cell = container.ContainedEntities[0];
|
var cell = container.ContainedEntities[0];
|
||||||
|
|
||||||
if (!entityManager.TryGetComponent<PredictedBatteryComponent>(cell, out var batteryComponent))
|
if (!entityManager.TryGetComponent<BatteryComponent>(cell, out var batteryComponent))
|
||||||
{
|
{
|
||||||
Logger.Warning($"Mech construct entity {uid} had an invalid entity in container \"{Container}\"! Aborting build mech action.");
|
Logger.Warning($"Mech construct entity {uid} had an invalid entity in container \"{Container}\"! Aborting build mech action.");
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_battery.SetCharge((entity.Owner, battery), battery.CurrentCharge + entity.Comp.ChargingWattage * frameTime * entity.Comp.ChargingEfficiency);
|
_battery.ChangeCharge((entity.Owner, battery), entity.Comp.ChargingWattage * frameTime * entity.Comp.ChargingEfficiency);
|
||||||
if (_battery.IsFull((entity.Owner, battery)))
|
if (_battery.IsFull((entity.Owner, battery)))
|
||||||
{
|
{
|
||||||
if (TryComp<ApcPowerReceiverComponent>(entity.Owner, out var receiver))
|
if (TryComp<ApcPowerReceiverComponent>(entity.Owner, out var receiver))
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Content.Server.Light.EntitySystems
|
||||||
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
|
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
|
||||||
[Dependency] private readonly PopupSystem _popup = default!;
|
[Dependency] private readonly PopupSystem _popup = default!;
|
||||||
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly SharedPointLightSystem _lights = default!;
|
[Dependency] private readonly SharedPointLightSystem _lights = default!;
|
||||||
|
|
@ -147,7 +147,7 @@ namespace Content.Server.Light.EntitySystems
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Very important: Make this charge rate based instead of instantly removing charge each update step.
|
// TODO: Very important: Make this charge rate based instead of instantly removing charge each update step.
|
||||||
// See PredictedBatteryComponent
|
// See BatteryComponent
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
var toRemove = new RemQueue<Entity<HandheldLightComponent>>();
|
var toRemove = new RemQueue<Entity<HandheldLightComponent>>();
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public sealed partial class MechSystem : SharedMechSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly ContainerSystem _container = default!;
|
[Dependency] private readonly ContainerSystem _container = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||||
|
|
@ -88,7 +88,7 @@ public sealed partial class MechSystem : SharedMechSystem
|
||||||
if (TryComp<WiresPanelComponent>(uid, out var panel) && !panel.Open)
|
if (TryComp<WiresPanelComponent>(uid, out var panel) && !panel.Open)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (component.BatterySlot.ContainedEntity == null && TryComp<PredictedBatteryComponent>(args.Used, out var battery))
|
if (component.BatterySlot.ContainedEntity == null && TryComp<BatteryComponent>(args.Used, out var battery))
|
||||||
{
|
{
|
||||||
InsertBattery(uid, args.Used, component, battery);
|
InsertBattery(uid, args.Used, component, battery);
|
||||||
_actionBlocker.UpdateCanMove(uid);
|
_actionBlocker.UpdateCanMove(uid);
|
||||||
|
|
@ -109,7 +109,7 @@ public sealed partial class MechSystem : SharedMechSystem
|
||||||
|
|
||||||
private void OnInsertBattery(EntityUid uid, MechComponent component, EntInsertedIntoContainerMessage args)
|
private void OnInsertBattery(EntityUid uid, MechComponent component, EntInsertedIntoContainerMessage args)
|
||||||
{
|
{
|
||||||
if (args.Container != component.BatterySlot || !TryComp<PredictedBatteryComponent>(args.Entity, out var battery))
|
if (args.Container != component.BatterySlot || !TryComp<BatteryComponent>(args.Entity, out var battery))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
component.Energy = _battery.GetCharge((args.Entity, battery));
|
component.Energy = _battery.GetCharge((args.Entity, battery));
|
||||||
|
|
@ -337,7 +337,7 @@ public sealed partial class MechSystem : SharedMechSystem
|
||||||
if (battery == null)
|
if (battery == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!TryComp<PredictedBatteryComponent>(battery, out var batteryComp))
|
if (!TryComp<BatteryComponent>(battery, out var batteryComp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_battery.SetCharge((battery.Value, batteryComp), _battery.GetCharge((battery.Value, batteryComp)) + delta.Float());
|
_battery.SetCharge((battery.Value, batteryComp), _battery.GetCharge((battery.Value, batteryComp)) + delta.Float());
|
||||||
|
|
@ -353,7 +353,7 @@ public sealed partial class MechSystem : SharedMechSystem
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InsertBattery(EntityUid uid, EntityUid toInsert, MechComponent? component = null, PredictedBatteryComponent? battery = null)
|
public void InsertBattery(EntityUid uid, EntityUid toInsert, MechComponent? component = null, BatteryComponent? battery = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref component, false))
|
if (!Resolve(uid, ref component, false))
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using Content.Server.Ninja.Events;
|
using Content.Server.Ninja.Events;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.Power.EntitySystems;
|
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Ninja.Components;
|
using Content.Shared.Ninja.Components;
|
||||||
|
|
@ -17,8 +16,7 @@ namespace Content.Server.Ninja.Systems;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
|
public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly BatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _predictedBattery = default!;
|
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
|
@ -80,20 +78,20 @@ public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
|
||||||
protected override bool TryDrainPower(Entity<BatteryDrainerComponent> ent, EntityUid target)
|
protected override bool TryDrainPower(Entity<BatteryDrainerComponent> ent, EntityUid target)
|
||||||
{
|
{
|
||||||
var (uid, comp) = ent;
|
var (uid, comp) = ent;
|
||||||
if (comp.BatteryUid == null || !TryComp<PredictedBatteryComponent>(comp.BatteryUid.Value, out var battery))
|
if (comp.BatteryUid == null || !TryComp<BatteryComponent>(comp.BatteryUid.Value, out var battery))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!TryComp<BatteryComponent>(target, out var targetBattery) || !TryComp<PowerNetworkBatteryComponent>(target, out var pnb))
|
if (!TryComp<BatteryComponent>(target, out var targetBattery) || !TryComp<PowerNetworkBatteryComponent>(target, out var pnb))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (MathHelper.CloseToPercent(targetBattery.CurrentCharge, 0))
|
var available = _battery.GetCharge((target, targetBattery));
|
||||||
|
if (MathHelper.CloseToPercent(available, 0))
|
||||||
{
|
{
|
||||||
_popup.PopupEntity(Loc.GetString("battery-drainer-empty", ("battery", target)), uid, uid, PopupType.Medium);
|
_popup.PopupEntity(Loc.GetString("battery-drainer-empty", ("battery", target)), uid, uid, PopupType.Medium);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var available = targetBattery.CurrentCharge;
|
var required = battery.MaxCharge - _battery.GetCharge((comp.BatteryUid.Value, battery));
|
||||||
var required = battery.MaxCharge - _predictedBattery.GetCharge((comp.BatteryUid.Value, battery));
|
|
||||||
// higher tier storages can charge more
|
// higher tier storages can charge more
|
||||||
var maxDrained = pnb.MaxSupply * comp.DrainTime;
|
var maxDrained = pnb.MaxSupply * comp.DrainTime;
|
||||||
var input = Math.Min(Math.Min(available, required / comp.DrainEfficiency), maxDrained);
|
var input = Math.Min(Math.Min(available, required / comp.DrainEfficiency), maxDrained);
|
||||||
|
|
@ -101,15 +99,13 @@ public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var output = input * comp.DrainEfficiency;
|
var output = input * comp.DrainEfficiency;
|
||||||
// PowerCells use PredictedBatteryComponent
|
_battery.ChangeCharge((comp.BatteryUid.Value, battery), output);
|
||||||
// SMES, substations and APCs use BatteryComponent
|
|
||||||
_predictedBattery.ChangeCharge((comp.BatteryUid.Value, battery), output);
|
|
||||||
// TODO: create effect message or something
|
// TODO: create effect message or something
|
||||||
Spawn("EffectSparks", Transform(target).Coordinates);
|
Spawn("EffectSparks", Transform(target).Coordinates);
|
||||||
_audio.PlayPvs(comp.SparkSound, target);
|
_audio.PlayPvs(comp.SparkSound, target);
|
||||||
_popup.PopupEntity(Loc.GetString("battery-drainer-success", ("battery", target)), uid, uid);
|
_popup.PopupEntity(Loc.GetString("battery-drainer-success", ("battery", target)), uid, uid);
|
||||||
|
|
||||||
// repeat the doafter until battery is full
|
// repeat the doafter until battery is full
|
||||||
return !_predictedBattery.IsFull((comp.BatteryUid.Value, battery));
|
return !_battery.IsFull((comp.BatteryUid.Value, battery));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace Content.Server.Ninja.Systems;
|
||||||
|
|
||||||
public sealed class ItemCreatorSystem : SharedItemCreatorSystem
|
public sealed class ItemCreatorSystem : SharedItemCreatorSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
|
||||||
if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery))
|
if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!TryComp<PredictedBatteryComponent>(args.EntityUid, out var inserting))
|
if (!TryComp<BatteryComponent>(args.EntityUid, out var inserting))
|
||||||
{
|
{
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
return;
|
return;
|
||||||
|
|
@ -88,11 +88,11 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function assigns a score to a power cell depending on the capacity, to be used when comparing which cell is better.
|
// this function assigns a score to a power cell depending on the capacity, to be used when comparing which cell is better.
|
||||||
private float GetCellScore(EntityUid uid, PredictedBatteryComponent battcomp)
|
private float GetCellScore(EntityUid uid, BatteryComponent battcomp)
|
||||||
{
|
{
|
||||||
// if a cell is able to automatically recharge, boost the score drastically depending on the recharge rate,
|
// if a cell is able to automatically recharge, boost the score drastically depending on the recharge rate,
|
||||||
// this is to ensure a ninja can still upgrade to a micro reactor cell even if they already have a medium or high.
|
// this is to ensure a ninja can still upgrade to a micro reactor cell even if they already have a medium or high.
|
||||||
if (TryComp<PredictedBatterySelfRechargerComponent>(uid, out var selfcomp))
|
if (TryComp<BatterySelfRechargerComponent>(uid, out var selfcomp))
|
||||||
return battcomp.MaxCharge + selfcomp.AutoRechargeRate * AutoRechargeValue;
|
return battcomp.MaxCharge + selfcomp.AutoRechargeRate * AutoRechargeValue;
|
||||||
return battcomp.MaxCharge;
|
return battcomp.MaxCharge;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Content.Server.Ninja.Systems;
|
||||||
public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem
|
public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly CodeConditionSystem _codeCondition = default!;
|
[Dependency] private readonly CodeConditionSystem _codeCondition = default!;
|
||||||
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
||||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||||
|
|
@ -91,7 +91,7 @@ public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the battery component in a ninja's suit, if it's worn.
|
/// Get the battery component in a ninja's suit, if it's worn.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool GetNinjaBattery(EntityUid user, [NotNullWhen(true)] out EntityUid? batteryUid, [NotNullWhen(true)] out PredictedBatteryComponent? batteryComp)
|
public bool GetNinjaBattery(EntityUid user, [NotNullWhen(true)] out EntityUid? batteryUid, [NotNullWhen(true)] out BatteryComponent? batteryComp)
|
||||||
{
|
{
|
||||||
if (TryComp<SpaceNinjaComponent>(user, out var ninja)
|
if (TryComp<SpaceNinjaComponent>(user, out var ninja)
|
||||||
&& ninja.Suit != null
|
&& ninja.Suit != null
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Content.Server.Ninja.Systems;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class StunProviderSystem : SharedStunProviderSystem
|
public sealed class StunProviderSystem : SharedStunProviderSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using Content.Server.Power.Components;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Power;
|
using Content.Shared.Power;
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
|
using Content.Shared.Power.EntitySystems;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
|
|
||||||
namespace Content.Server.Power.EntitySystems;
|
namespace Content.Server.Power.EntitySystems;
|
||||||
|
|
@ -24,6 +25,7 @@ public sealed class BatteryInterfaceSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = null!;
|
[Dependency] private readonly UserInterfaceSystem _uiSystem = null!;
|
||||||
|
[Dependency] private readonly SharedBatterySystem _battery = null!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
|
@ -48,7 +50,7 @@ public sealed class BatteryInterfaceSystem : EntitySystem
|
||||||
var netBattery = Comp<PowerNetworkBatteryComponent>(ent);
|
var netBattery = Comp<PowerNetworkBatteryComponent>(ent);
|
||||||
netBattery.CanCharge = args.On;
|
netBattery.CanCharge = args.On;
|
||||||
|
|
||||||
_adminLog.Add(LogType.Action,$"{ToPrettyString(args.Actor):actor} set input breaker to {args.On} on {ToPrettyString(ent):target}");
|
_adminLog.Add(LogType.Action, $"{ToPrettyString(args.Actor):actor} set input breaker to {args.On} on {ToPrettyString(ent):target}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleSetOutputBreaker(Entity<BatteryInterfaceComponent> ent, ref BatterySetOutputBreakerMessage args)
|
private void HandleSetOutputBreaker(Entity<BatteryInterfaceComponent> ent, ref BatterySetOutputBreakerMessage args)
|
||||||
|
|
@ -56,7 +58,7 @@ public sealed class BatteryInterfaceSystem : EntitySystem
|
||||||
var netBattery = Comp<PowerNetworkBatteryComponent>(ent);
|
var netBattery = Comp<PowerNetworkBatteryComponent>(ent);
|
||||||
netBattery.CanDischarge = args.On;
|
netBattery.CanDischarge = args.On;
|
||||||
|
|
||||||
_adminLog.Add(LogType.Action,$"{ToPrettyString(args.Actor):actor} set output breaker to {args.On} on {ToPrettyString(ent):target}");
|
_adminLog.Add(LogType.Action, $"{ToPrettyString(args.Actor):actor} set output breaker to {args.On} on {ToPrettyString(ent):target}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleSetChargeRate(Entity<BatteryInterfaceComponent> ent, ref BatterySetChargeRateMessage args)
|
private void HandleSetChargeRate(Entity<BatteryInterfaceComponent> ent, ref BatterySetChargeRateMessage args)
|
||||||
|
|
@ -90,13 +92,14 @@ public sealed class BatteryInterfaceSystem : EntitySystem
|
||||||
if (!_uiSystem.IsUiOpen(uid, BatteryUiKey.Key))
|
if (!_uiSystem.IsUiOpen(uid, BatteryUiKey.Key))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var currentCharge = _battery.GetCharge((uid, battery));
|
||||||
_uiSystem.SetUiState(
|
_uiSystem.SetUiState(
|
||||||
uid,
|
uid,
|
||||||
BatteryUiKey.Key,
|
BatteryUiKey.Key,
|
||||||
new BatteryBuiState
|
new BatteryBuiState
|
||||||
{
|
{
|
||||||
Capacity = battery.MaxCharge,
|
Capacity = battery.MaxCharge,
|
||||||
Charge = battery.CurrentCharge,
|
Charge = currentCharge,
|
||||||
CanCharge = netBattery.CanCharge,
|
CanCharge = netBattery.CanCharge,
|
||||||
CanDischarge = netBattery.CanDischarge,
|
CanDischarge = netBattery.CanDischarge,
|
||||||
CurrentReceiving = netBattery.CurrentReceiving,
|
CurrentReceiving = netBattery.CurrentReceiving,
|
||||||
|
|
|
||||||
|
|
@ -1,158 +0,0 @@
|
||||||
using Content.Shared.Power;
|
|
||||||
using Content.Shared.Power.Components;
|
|
||||||
using Content.Shared.Power.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Server.Power.EntitySystems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Responsible for <see cref="BatteryComponent"/>.
|
|
||||||
/// Unpredicted equivalent of <see cref="PredictedBatterySystem"/>.
|
|
||||||
/// If you make changes to this make sure to keep the two consistent.
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (delta == 0f)
|
|
||||||
return delta;
|
|
||||||
|
|
||||||
ent.Comp.CurrentCharge = newValue;
|
|
||||||
|
|
||||||
TrySetChargeCooldown(ent.Owner);
|
|
||||||
|
|
||||||
var ev = new ChargeChangedEvent(ent.Comp.CurrentCharge, delta, ent.Comp.MaxCharge);
|
|
||||||
RaiseLocalEvent(ent, ref ev);
|
|
||||||
return delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float UseCharge(Entity<BatteryComponent?> ent, float amount)
|
|
||||||
{
|
|
||||||
if (amount <= 0f || !Resolve(ent, ref ent.Comp) || ent.Comp.CurrentCharge == 0)
|
|
||||||
return 0f;
|
|
||||||
|
|
||||||
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.CurrentCharge - oldCharge, 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;
|
|
||||||
var oldCharge = ent.Comp.CurrentCharge;
|
|
||||||
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.CurrentCharge - oldCharge, ent.Comp.MaxCharge);
|
|
||||||
RaiseLocalEvent(ent, ref ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the battery's current charge.
|
|
||||||
/// </summary>
|
|
||||||
public float GetCharge(Entity<BatteryComponent?> ent)
|
|
||||||
{
|
|
||||||
if (!Resolve(ent, ref ent.Comp, false))
|
|
||||||
return 0f;
|
|
||||||
|
|
||||||
return ent.Comp.CurrentCharge;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets number of remaining uses for the given charge cost.
|
|
||||||
/// </summary>
|
|
||||||
public int GetRemainingUses(Entity<BatteryComponent?> ent, float cost)
|
|
||||||
{
|
|
||||||
if (cost <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!Resolve(ent, ref ent.Comp))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return (int)(ent.Comp.CurrentCharge / cost);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets number of maximum uses at full charge for the given charge cost.
|
|
||||||
/// </summary>
|
|
||||||
public int GetMaxUses(Entity<BatteryComponent?> ent, float cost)
|
|
||||||
{
|
|
||||||
if (cost <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!Resolve(ent, ref ent.Comp))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return (int)(ent.Comp.MaxCharge / cost);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +1,58 @@
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Shared.Cargo;
|
|
||||||
using Content.Shared.Examine;
|
|
||||||
using Content.Shared.Power;
|
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
using Content.Shared.Power.EntitySystems;
|
using Content.Shared.Power.EntitySystems;
|
||||||
using Content.Shared.Rejuvenate;
|
using Content.Shared.Rejuvenate;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Server.Power.EntitySystems;
|
namespace Content.Server.Power.EntitySystems;
|
||||||
|
|
||||||
/// <summary>
|
public sealed class BatterySystem : SharedBatterySystem
|
||||||
/// Responsible for <see cref="BatteryComponent"/>.
|
|
||||||
/// Unpredicted equivalent of <see cref="PredictedBatterySystem"/>.
|
|
||||||
/// If you make changes to this make sure to keep the two consistent.
|
|
||||||
/// </summary>
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed partial class BatterySystem : SharedBatterySystem
|
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<BatteryComponent, ComponentInit>(OnInit);
|
|
||||||
SubscribeLocalEvent<BatteryComponent, ExaminedEvent>(OnExamine);
|
|
||||||
SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnBatteryRejuvenate);
|
|
||||||
SubscribeLocalEvent<PowerNetworkBatteryComponent, RejuvenateEvent>(OnNetBatteryRejuvenate);
|
SubscribeLocalEvent<PowerNetworkBatteryComponent, RejuvenateEvent>(OnNetBatteryRejuvenate);
|
||||||
SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
|
|
||||||
SubscribeLocalEvent<BatteryComponent, ChangeChargeEvent>(OnChangeCharge);
|
|
||||||
SubscribeLocalEvent<BatteryComponent, GetChargeEvent>(OnGetCharge);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync);
|
SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync);
|
||||||
SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync);
|
SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInit(Entity<BatteryComponent> ent, ref ComponentInit args)
|
protected override void OnStartup(Entity<BatteryComponent> ent, ref ComponentStartup args)
|
||||||
{
|
{
|
||||||
DebugTools.Assert(!HasComp<PredictedBatteryComponent>(ent), $"{ent} has both BatteryComponent and PredictedBatteryComponent");
|
// Debug assert to prevent anyone from killing their networking performance by dirtying a battery's charge every single tick.
|
||||||
|
// This checks for components that interact with the power network, have a charge rate that ramps up over time and therefore
|
||||||
|
// have to set the charge in an update loop instead of using a <see cref="RefreshChargeRateEvent"/> subscription.
|
||||||
|
// This is usually the case for APCs, SMES, battery powered turrets or similar.
|
||||||
|
// For those entities you should disable net sync for the battery in your prototype, using
|
||||||
|
/// <code>
|
||||||
|
/// - type: Battery
|
||||||
|
/// netSync: false
|
||||||
|
/// </code>
|
||||||
|
/// This disables networking and prediction for this battery.
|
||||||
|
if (!ent.Comp.NetSyncEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DebugTools.Assert(!HasComp<ApcPowerReceiverBatteryComponent>(ent), $"{ToPrettyString(ent.Owner)} has a predicted battery connected to the power net. Disable net sync!");
|
||||||
|
DebugTools.Assert(!HasComp<PowerNetworkBatteryComponent>(ent), $"{ToPrettyString(ent.Owner)} has a predicted battery connected to the power net. Disable net sync!");
|
||||||
|
DebugTools.Assert(!HasComp<PowerConsumerComponent>(ent), $"{ToPrettyString(ent.Owner)} has a predicted battery connected to the power net. Disable net sync!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnNetBatteryRejuvenate(Entity<PowerNetworkBatteryComponent> ent, ref RejuvenateEvent args)
|
private void OnNetBatteryRejuvenate(Entity<PowerNetworkBatteryComponent> ent, ref RejuvenateEvent args)
|
||||||
{
|
{
|
||||||
ent.Comp.NetworkBattery.CurrentStorage = ent.Comp.NetworkBattery.Capacity;
|
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<BatteryComponent> ent, ref ExaminedEvent args)
|
|
||||||
{
|
|
||||||
if (!args.IsInDetailsRange)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!HasComp<ExaminableBatteryComponent>(ent))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var chargePercentRounded = 0;
|
|
||||||
if (ent.Comp.MaxCharge != 0)
|
|
||||||
chargePercentRounded = (int)(100 * ent.Comp.CurrentCharge / ent.Comp.MaxCharge);
|
|
||||||
|
|
||||||
args.PushMarkup(
|
|
||||||
Loc.GetString(
|
|
||||||
"examinable-battery-component-examine-detail",
|
|
||||||
("percent", chargePercentRounded),
|
|
||||||
("markupPercentColor", "green")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PreSync(NetworkBatteryPreSync ev)
|
private void PreSync(NetworkBatteryPreSync ev)
|
||||||
{
|
{
|
||||||
// Ignoring entity pausing. If the entity was paused, neither component's data should have been changed.
|
// Ignoring entity pausing. If the entity was paused, neither component's data should have been changed.
|
||||||
var enumerator = AllEntityQuery<PowerNetworkBatteryComponent, BatteryComponent>();
|
var enumerator = AllEntityQuery<PowerNetworkBatteryComponent, BatteryComponent>();
|
||||||
while (enumerator.MoveNext(out var netBat, out var bat))
|
while (enumerator.MoveNext(out var uid, out var netBat, out var bat))
|
||||||
{
|
{
|
||||||
DebugTools.Assert(bat.CurrentCharge <= bat.MaxCharge && bat.CurrentCharge >= 0);
|
var currentCharge = GetCharge((uid, bat));
|
||||||
|
DebugTools.Assert(currentCharge <= bat.MaxCharge && currentCharge >= 0);
|
||||||
netBat.NetworkBattery.Capacity = bat.MaxCharge;
|
netBat.NetworkBattery.Capacity = bat.MaxCharge;
|
||||||
netBat.NetworkBattery.CurrentStorage = bat.CurrentCharge;
|
netBat.NetworkBattery.CurrentStorage = currentCharge;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,42 +65,4 @@ public sealed partial class BatterySystem : SharedBatterySystem
|
||||||
SetCharge((uid, bat), netBat.NetworkBattery.CurrentStorage);
|
SetCharge((uid, bat), netBat.NetworkBattery.CurrentStorage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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))
|
|
||||||
{
|
|
||||||
if (!comp.AutoRecharge || IsFull((uid, bat)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (comp.NextAutoRecharge > curTime)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
SetCharge((uid, bat), bat.CurrentCharge + comp.AutoRechargeRate * frameTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using Content.Shared.Pinpointer;
|
||||||
using Content.Shared.Station.Components;
|
using Content.Shared.Station.Components;
|
||||||
using Content.Shared.Power;
|
using Content.Shared.Power;
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
|
using Content.Shared.Power.EntitySystems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
|
|
@ -22,6 +23,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
|
||||||
{
|
{
|
||||||
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
||||||
[Dependency] private readonly SharedMapSystem _sharedMapSystem = default!;
|
[Dependency] private readonly SharedMapSystem _sharedMapSystem = default!;
|
||||||
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
|
|
||||||
// Note: this data does not need to be saved
|
// Note: this data does not need to be saved
|
||||||
private Dictionary<EntityUid, Dictionary<Vector2i, PowerCableChunk>> _gridPowerCableChunks = new();
|
private Dictionary<EntityUid, Dictionary<Vector2i, PowerCableChunk>> _gridPowerCableChunks = new();
|
||||||
|
|
@ -510,7 +512,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
|
||||||
if (effectiveMax == 0)
|
if (effectiveMax == 0)
|
||||||
effectiveMax = 1;
|
effectiveMax = 1;
|
||||||
|
|
||||||
return battery.CurrentCharge / effectiveMax;
|
return _battery.GetCharge((uid, battery)) / effectiveMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetSourcesForNode(EntityUid uid, Node node, out List<PowerMonitoringConsoleEntry> sources)
|
private void GetSourcesForNode(EntityUid uid, Node node, out List<PowerMonitoringConsoleEntry> sources)
|
||||||
|
|
|
||||||
|
|
@ -358,17 +358,18 @@ namespace Content.Server.Power.EntitySystems
|
||||||
|
|
||||||
if (requireBattery)
|
if (requireBattery)
|
||||||
{
|
{
|
||||||
_battery.SetCharge((uid, battery), battery.CurrentCharge - apcBattery.IdleLoad * frameTime);
|
_battery.ChangeCharge((uid, battery), -apcBattery.IdleLoad * frameTime);
|
||||||
}
|
}
|
||||||
// Otherwise try to charge the battery
|
// 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;
|
apcReceiver.Load += apcBattery.BatteryRechargeRate * apcBattery.BatteryRechargeEfficiency;
|
||||||
_battery.SetCharge((uid, battery), battery.CurrentCharge + apcBattery.BatteryRechargeRate * frameTime);
|
_battery.ChangeCharge((uid, battery), apcBattery.BatteryRechargeRate * frameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable / disable the battery if the state changed
|
// Enable / disable the battery if the state changed
|
||||||
var enableBattery = requireBattery && battery.CurrentCharge > 0;
|
var currentCharge = _battery.GetCharge((uid, battery));
|
||||||
|
var enableBattery = requireBattery && currentCharge > 0;
|
||||||
|
|
||||||
if (apcBattery.Enabled != enableBattery)
|
if (apcBattery.Enabled != enableBattery)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ public sealed class RiggableSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ExplosionSystem _explosionSystem = default!;
|
[Dependency] private readonly ExplosionSystem _explosionSystem = default!;
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _predictedBattery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
|
@ -27,7 +27,6 @@ public sealed class RiggableSystem : EntitySystem
|
||||||
SubscribeLocalEvent<RiggableComponent, BeingMicrowavedEvent>(OnMicrowaved);
|
SubscribeLocalEvent<RiggableComponent, BeingMicrowavedEvent>(OnMicrowaved);
|
||||||
SubscribeLocalEvent<RiggableComponent, SolutionContainerChangedEvent>(OnSolutionChanged);
|
SubscribeLocalEvent<RiggableComponent, SolutionContainerChangedEvent>(OnSolutionChanged);
|
||||||
SubscribeLocalEvent<RiggableComponent, ChargeChangedEvent>(OnChargeChanged);
|
SubscribeLocalEvent<RiggableComponent, ChargeChangedEvent>(OnChargeChanged);
|
||||||
SubscribeLocalEvent<RiggableComponent, PredictedBatteryChargeChangedEvent>(OnChargeChanged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRejuvenate(Entity<RiggableComponent> entity, ref RejuvenateEvent args)
|
private void OnRejuvenate(Entity<RiggableComponent> entity, ref RejuvenateEvent args)
|
||||||
|
|
@ -39,16 +38,7 @@ public sealed class RiggableSystem : EntitySystem
|
||||||
{
|
{
|
||||||
if (TryComp<BatteryComponent>(entity, out var batteryComponent))
|
if (TryComp<BatteryComponent>(entity, out var batteryComponent))
|
||||||
{
|
{
|
||||||
if (batteryComponent.CurrentCharge == 0f)
|
var charge = _battery.GetCharge((entity, batteryComponent));
|
||||||
return;
|
|
||||||
|
|
||||||
Explode(entity, batteryComponent.CurrentCharge);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TryComp<PredictedBatteryComponent>(entity, out var predictedBatteryComponent))
|
|
||||||
{
|
|
||||||
var charge = _predictedBattery.GetCharge((entity, predictedBatteryComponent));
|
|
||||||
if (charge == 0f)
|
if (charge == 0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -80,20 +70,7 @@ public sealed class RiggableSystem : EntitySystem
|
||||||
QueueDel(uid);
|
QueueDel(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// non-predicted batteries
|
|
||||||
private void OnChargeChanged(Entity<RiggableComponent> ent, ref ChargeChangedEvent args)
|
private void OnChargeChanged(Entity<RiggableComponent> ent, ref ChargeChangedEvent args)
|
||||||
{
|
|
||||||
if (!ent.Comp.IsRigged)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (args.Charge == 0f)
|
|
||||||
return; // No charge to cause an explosion.
|
|
||||||
|
|
||||||
Explode(ent, args.Charge);
|
|
||||||
}
|
|
||||||
|
|
||||||
// predicted batteries
|
|
||||||
private void OnChargeChanged(Entity<RiggableComponent> ent, ref PredictedBatteryChargeChangedEvent args)
|
|
||||||
{
|
{
|
||||||
if (!ent.Comp.IsRigged)
|
if (!ent.Comp.IsRigged)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ using Content.Server.Power.Components;
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Shared.Power;
|
using Content.Shared.Power;
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
|
using Content.Shared.Power.EntitySystems;
|
||||||
using Content.Shared.Rounding;
|
using Content.Shared.Rounding;
|
||||||
using Content.Shared.SMES;
|
using Content.Shared.SMES;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
@ -14,6 +15,7 @@ internal sealed class SmesSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
|
@ -61,7 +63,8 @@ internal sealed class SmesSystem : EntitySystem
|
||||||
if (!Resolve(uid, ref battery, false))
|
if (!Resolve(uid, ref battery, false))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return ContentHelpers.RoundToLevels(battery.CurrentCharge, battery.MaxCharge, 6);
|
var currentCharge = _battery.GetCharge((uid, battery));
|
||||||
|
return ContentHelpers.RoundToLevels(currentCharge, battery.MaxCharge, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChargeState CalcChargeState(EntityUid uid, PowerNetworkBatteryComponent? netBattery = null)
|
private ChargeState CalcChargeState(EntityUid uid, PowerNetworkBatteryComponent? netBattery = null)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Server.Power.EntitySystems;
|
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
using Content.Shared.Power.EntitySystems;
|
using Content.Shared.Power.EntitySystems;
|
||||||
|
|
@ -10,8 +9,7 @@ namespace Content.Server.Power
|
||||||
[AdminCommand(AdminFlags.Debug)]
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public sealed class SetBatteryPercentCommand : LocalizedEntityCommands
|
public sealed class SetBatteryPercentCommand : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly BatterySystem _batterySystem = default!;
|
[Dependency] private readonly SharedBatterySystem _batterySystem = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _predictedBatterySystem = default!;
|
|
||||||
|
|
||||||
public override string Command => "setbatterypercent";
|
public override string Command => "setbatterypercent";
|
||||||
|
|
||||||
|
|
@ -39,8 +37,6 @@ namespace Content.Server.Power
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent<BatteryComponent>(id, out var battery))
|
if (EntityManager.TryGetComponent<BatteryComponent>(id, out var battery))
|
||||||
_batterySystem.SetCharge((id.Value, battery), battery.MaxCharge * percent / 100);
|
_batterySystem.SetCharge((id.Value, battery), battery.MaxCharge * percent / 100);
|
||||||
else if (EntityManager.TryGetComponent<PredictedBatteryComponent>(id, out var pBattery))
|
|
||||||
_predictedBatterySystem.SetCharge((id.Value, pBattery), pBattery.MaxCharge * percent / 100);
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
shell.WriteLine(Loc.GetString($"cmd-setbatterypercent-battery-not-found", ("id", id)));
|
shell.WriteLine(Loc.GetString($"cmd-setbatterypercent-battery-not-found", ("id", id)));
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ namespace Content.Server.PowerSink
|
||||||
|
|
||||||
_battery.ChangeCharge((entity, battery), networkLoad.NetworkLoad.ReceivingPower * frameTime);
|
_battery.ChangeCharge((entity, battery), networkLoad.NetworkLoad.ReceivingPower * frameTime);
|
||||||
|
|
||||||
var currentBatteryThreshold = battery.CurrentCharge / battery.MaxCharge;
|
var currentBatteryThreshold = _battery.GetChargeLevel((entity, battery));
|
||||||
|
|
||||||
// Check for warning message threshold
|
// Check for warning message threshold
|
||||||
if (!component.SentImminentExplosionWarningMessage &&
|
if (!component.SentImminentExplosionWarningMessage &&
|
||||||
|
|
@ -90,7 +90,7 @@ namespace Content.Server.PowerSink
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for explosion
|
// Check for explosion
|
||||||
if (battery.CurrentCharge < battery.MaxCharge)
|
if (!_battery.IsFull((entity, battery)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (component.ExplosionTime == null)
|
if (component.ExplosionTime == null)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Content.Server.Radio.EntitySystems;
|
||||||
public sealed class JammerSystem : SharedJammerSystem
|
public sealed class JammerSystem : SharedJammerSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
[Dependency] private readonly SharedDeviceNetworkJammerSystem _jammer = default!;
|
[Dependency] private readonly SharedDeviceNetworkJammerSystem _jammer = default!;
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ public sealed class JammerSystem : SharedJammerSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Very important: Make this charge rate based instead of updating every single tick
|
// TODO: Very important: Make this charge rate based instead of updating every single tick
|
||||||
// See PredictedBatteryComponent
|
// See BatteryComponent
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
var query = EntityQueryEnumerator<ActiveRadioJammerComponent, RadioJammerComponent>();
|
var query = EntityQueryEnumerator<ActiveRadioJammerComponent, RadioJammerComponent>();
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using Content.Server.Power.Components;
|
||||||
using Content.Shared.DeviceNetwork;
|
using Content.Shared.DeviceNetwork;
|
||||||
using Content.Shared.DeviceNetwork.Events;
|
using Content.Shared.DeviceNetwork.Events;
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
|
using Content.Shared.Power.EntitySystems;
|
||||||
|
|
||||||
namespace Content.Server.SensorMonitoring;
|
namespace Content.Server.SensorMonitoring;
|
||||||
|
|
||||||
|
|
@ -11,6 +12,7 @@ public sealed class BatterySensorSystem : EntitySystem
|
||||||
public const string DeviceNetworkCommandSyncData = "bat_sync_data";
|
public const string DeviceNetworkCommandSyncData = "bat_sync_data";
|
||||||
|
|
||||||
[Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!;
|
[Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!;
|
||||||
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
|
@ -26,13 +28,14 @@ public sealed class BatterySensorSystem : EntitySystem
|
||||||
{
|
{
|
||||||
case DeviceNetworkCommandSyncData:
|
case DeviceNetworkCommandSyncData:
|
||||||
var battery = Comp<BatteryComponent>(uid);
|
var battery = Comp<BatteryComponent>(uid);
|
||||||
|
var currentCharge = _battery.GetCharge((uid, battery));
|
||||||
var netBattery = Comp<PowerNetworkBatteryComponent>(uid);
|
var netBattery = Comp<PowerNetworkBatteryComponent>(uid);
|
||||||
|
|
||||||
var payload = new NetworkPayload
|
var payload = new NetworkPayload
|
||||||
{
|
{
|
||||||
[DeviceNetworkConstants.Command] = DeviceNetworkCommandSyncData,
|
[DeviceNetworkConstants.Command] = DeviceNetworkCommandSyncData,
|
||||||
[DeviceNetworkCommandSyncData] = new BatterySensorData(
|
[DeviceNetworkCommandSyncData] = new BatterySensorData(
|
||||||
battery.CurrentCharge,
|
currentCharge,
|
||||||
battery.MaxCharge,
|
battery.MaxCharge,
|
||||||
netBattery.CurrentReceiving,
|
netBattery.CurrentReceiving,
|
||||||
netBattery.MaxChargeRate,
|
netBattery.MaxChargeRate,
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
|
||||||
[Dependency] private readonly TriggerSystem _trigger = default!;
|
[Dependency] private readonly TriggerSystem _trigger = default!;
|
||||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly EmagSystem _emag = default!;
|
[Dependency] private readonly EmagSystem _emag = default!;
|
||||||
[Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
|
[Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
|
||||||
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ using Content.Server.Ghost.Roles;
|
||||||
using Content.Server.Ghost.Roles.Components;
|
using Content.Server.Ghost.Roles.Components;
|
||||||
using Content.Server.Mind;
|
using Content.Server.Mind;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.Power.EntitySystems;
|
|
||||||
using Content.Server.Roles;
|
using Content.Server.Roles;
|
||||||
using Content.Server.Spawners.Components;
|
using Content.Server.Spawners.Components;
|
||||||
using Content.Server.Spawners.EntitySystems;
|
using Content.Server.Spawners.EntitySystems;
|
||||||
|
|
@ -23,6 +22,7 @@ using Content.Shared.Mobs;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Power;
|
using Content.Shared.Power;
|
||||||
|
using Content.Shared.Power.EntitySystems;
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
using Content.Shared.Rejuvenate;
|
using Content.Shared.Rejuvenate;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
|
|
@ -52,7 +52,7 @@ public sealed class StationAiSystem : SharedStationAiSystem
|
||||||
[Dependency] private readonly ToggleableGhostRoleSystem _ghostrole = default!;
|
[Dependency] private readonly ToggleableGhostRoleSystem _ghostrole = default!;
|
||||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||||
[Dependency] private readonly DestructibleSystem _destructible = default!;
|
[Dependency] private readonly DestructibleSystem _destructible = default!;
|
||||||
[Dependency] private readonly BatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popups = default!;
|
[Dependency] private readonly SharedPopupSystem _popups = default!;
|
||||||
[Dependency] private readonly StationSystem _station = default!;
|
[Dependency] private readonly StationSystem _station = default!;
|
||||||
|
|
@ -239,6 +239,7 @@ public sealed class StationAiSystem : SharedStationAiSystem
|
||||||
UpdateDamagedAccent(entity);
|
UpdateDamagedAccent(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This should just read the current damage and charge when speaking instead of updating the component all the time even if we don't even use it.
|
||||||
private void UpdateDamagedAccent(Entity<StationAiCoreComponent> ent)
|
private void UpdateDamagedAccent(Entity<StationAiCoreComponent> ent)
|
||||||
{
|
{
|
||||||
if (!TryGetHeld((ent.Owner, ent.Comp), out var held))
|
if (!TryGetHeld((ent.Owner, ent.Comp), out var held))
|
||||||
|
|
@ -248,7 +249,7 @@ public sealed class StationAiSystem : SharedStationAiSystem
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (TryComp<BatteryComponent>(ent, out var battery))
|
if (TryComp<BatteryComponent>(ent, out var battery))
|
||||||
accent.OverrideChargeLevel = battery.CurrentCharge / battery.MaxCharge;
|
accent.OverrideChargeLevel = _battery.GetChargeLevel((ent.Owner, battery));
|
||||||
|
|
||||||
if (TryComp<DamageableComponent>(ent, out var damageable))
|
if (TryComp<DamageableComponent>(ent, out var damageable))
|
||||||
accent.OverrideTotalDamage = damageable.TotalDamage;
|
accent.OverrideTotalDamage = damageable.TotalDamage;
|
||||||
|
|
@ -270,7 +271,7 @@ public sealed class StationAiSystem : SharedStationAiSystem
|
||||||
if (!_proto.TryIndex(_batteryAlert, out var proto))
|
if (!_proto.TryIndex(_batteryAlert, out var proto))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var chargePercent = battery.CurrentCharge / battery.MaxCharge;
|
var chargePercent = _battery.GetChargeLevel((ent.Owner, battery));
|
||||||
var chargeLevel = Math.Round(chargePercent * proto.MaxSeverity);
|
var chargeLevel = Math.Round(chargePercent * proto.MaxSeverity);
|
||||||
|
|
||||||
_alerts.ShowAlert(held.Value, _batteryAlert, (short)Math.Clamp(chargeLevel, 0, proto.MaxSeverity));
|
_alerts.ShowAlert(held.Value, _batteryAlert, (short)Math.Clamp(chargeLevel, 0, proto.MaxSeverity));
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Content.Server.Speech.EntitySystems;
|
||||||
public sealed class DamagedSiliconAccentSystem : EntitySystem
|
public sealed class DamagedSiliconAccentSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
[Dependency] private readonly PowerCellSystem _powerCell = default!;
|
||||||
[Dependency] private readonly DestructibleSystem _destructibleSystem = default!;
|
[Dependency] private readonly DestructibleSystem _destructibleSystem = default!;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Content.Server.Stunnable.Systems
|
||||||
{
|
{
|
||||||
[Dependency] private readonly RiggableSystem _riggableSystem = default!;
|
[Dependency] private readonly RiggableSystem _riggableSystem = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly ItemToggleSystem _itemToggle = default!;
|
[Dependency] private readonly ItemToggleSystem _itemToggle = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
|
|
@ -28,13 +28,13 @@ namespace Content.Server.Stunnable.Systems
|
||||||
SubscribeLocalEvent<StunbatonComponent, ExaminedEvent>(OnExamined);
|
SubscribeLocalEvent<StunbatonComponent, ExaminedEvent>(OnExamined);
|
||||||
SubscribeLocalEvent<StunbatonComponent, SolutionContainerChangedEvent>(OnSolutionChange);
|
SubscribeLocalEvent<StunbatonComponent, SolutionContainerChangedEvent>(OnSolutionChange);
|
||||||
SubscribeLocalEvent<StunbatonComponent, StaminaDamageOnHitAttemptEvent>(OnStaminaHitAttempt);
|
SubscribeLocalEvent<StunbatonComponent, StaminaDamageOnHitAttemptEvent>(OnStaminaHitAttempt);
|
||||||
SubscribeLocalEvent<StunbatonComponent, PredictedBatteryChargeChangedEvent>(OnChargeChanged);
|
SubscribeLocalEvent<StunbatonComponent, ChargeChangedEvent>(OnChargeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStaminaHitAttempt(Entity<StunbatonComponent> entity, ref StaminaDamageOnHitAttemptEvent args)
|
private void OnStaminaHitAttempt(Entity<StunbatonComponent> entity, ref StaminaDamageOnHitAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (!_itemToggle.IsActivated(entity.Owner) ||
|
if (!_itemToggle.IsActivated(entity.Owner) ||
|
||||||
!TryComp<PredictedBatteryComponent>(entity.Owner, out var battery) || !_battery.TryUseCharge((entity.Owner, battery), entity.Comp.EnergyPerUse))
|
!TryComp<BatteryComponent>(entity.Owner, out var battery) || !_battery.TryUseCharge((entity.Owner, battery), entity.Comp.EnergyPerUse))
|
||||||
{
|
{
|
||||||
args.Cancelled = true;
|
args.Cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +47,7 @@ namespace Content.Server.Stunnable.Systems
|
||||||
: Loc.GetString("comp-stunbaton-examined-off");
|
: Loc.GetString("comp-stunbaton-examined-off");
|
||||||
args.PushMarkup(onMsg);
|
args.PushMarkup(onMsg);
|
||||||
|
|
||||||
if (TryComp<PredictedBatteryComponent>(entity.Owner, out var battery))
|
if (TryComp<BatteryComponent>(entity.Owner, out var battery))
|
||||||
{
|
{
|
||||||
var count = _battery.GetRemainingUses((entity.Owner, battery), entity.Comp.EnergyPerUse);
|
var count = _battery.GetRemainingUses((entity.Owner, battery), entity.Comp.EnergyPerUse);
|
||||||
args.PushMarkup(Loc.GetString("melee-battery-examine", ("color", "yellow"), ("count", count)));
|
args.PushMarkup(Loc.GetString("melee-battery-examine", ("color", "yellow"), ("count", count)));
|
||||||
|
|
@ -58,7 +58,7 @@ namespace Content.Server.Stunnable.Systems
|
||||||
{
|
{
|
||||||
base.TryTurnOn(entity, ref args);
|
base.TryTurnOn(entity, ref args);
|
||||||
|
|
||||||
if (!TryComp<PredictedBatteryComponent>(entity, out var battery) || _battery.GetCharge((entity, battery)) < entity.Comp.EnergyPerUse)
|
if (!TryComp<BatteryComponent>(entity, out var battery) || _battery.GetCharge((entity, battery)) < entity.Comp.EnergyPerUse)
|
||||||
{
|
{
|
||||||
args.Cancelled = true;
|
args.Cancelled = true;
|
||||||
if (args.User != null)
|
if (args.User != null)
|
||||||
|
|
@ -79,7 +79,7 @@ namespace Content.Server.Stunnable.Systems
|
||||||
{
|
{
|
||||||
// Explode if baton is activated and rigged.
|
// Explode if baton is activated and rigged.
|
||||||
if (!TryComp<RiggableComponent>(entity, out var riggable) ||
|
if (!TryComp<RiggableComponent>(entity, out var riggable) ||
|
||||||
!TryComp<PredictedBatteryComponent>(entity, out var battery))
|
!TryComp<BatteryComponent>(entity, out var battery))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_itemToggle.IsActivated(entity.Owner) && riggable.IsRigged)
|
if (_itemToggle.IsActivated(entity.Owner) && riggable.IsRigged)
|
||||||
|
|
@ -96,9 +96,9 @@ namespace Content.Server.Stunnable.Systems
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnChargeChanged(Entity<StunbatonComponent> entity, ref PredictedBatteryChargeChangedEvent args)
|
private void OnChargeChanged(Entity<StunbatonComponent> entity, ref ChargeChangedEvent args)
|
||||||
{
|
{
|
||||||
if (TryComp<PredictedBatteryComponent>(entity.Owner, out var battery) &&
|
if (TryComp<BatteryComponent>(entity.Owner, out var battery) &&
|
||||||
_battery.GetCharge((entity.Owner, battery)) < entity.Comp.EnergyPerUse)
|
_battery.GetCharge((entity.Owner, battery)) < entity.Comp.EnergyPerUse)
|
||||||
{
|
{
|
||||||
_itemToggle.TryDeactivate(entity.Owner, predicted: false);
|
_itemToggle.TryDeactivate(entity.Owner, predicted: false);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ public sealed class TeslaCoilSystem : EntitySystem
|
||||||
{
|
{
|
||||||
if (TryComp<BatteryComponent>(coil, out var batteryComponent))
|
if (TryComp<BatteryComponent>(coil, out var batteryComponent))
|
||||||
{
|
{
|
||||||
_battery.SetCharge((coil, batteryComponent), batteryComponent.CurrentCharge + coil.Comp.ChargeFromLightning);
|
_battery.ChangeCharge((coil, batteryComponent), coil.Comp.ChargeFromLightning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,29 +13,20 @@ namespace Content.Server.Xenoarchaeology.Artifact.XAE;
|
||||||
public sealed class XAEChargeBatterySystem : BaseXAESystem<XAEChargeBatteryComponent>
|
public sealed class XAEChargeBatterySystem : BaseXAESystem<XAEChargeBatteryComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly BatterySystem _battery = default!;
|
[Dependency] private readonly BatterySystem _battery = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _predictedBattery = default!;
|
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
|
|
||||||
/// <summary> Pre-allocated and re-used collection.</summary>
|
/// <summary> Pre-allocated and re-used collection.</summary>
|
||||||
private readonly HashSet<Entity<BatteryComponent>> _batteryEntities = new();
|
private readonly HashSet<Entity<BatteryComponent>> _batteryEntities = new();
|
||||||
private readonly HashSet<Entity<PredictedBatteryComponent>> _pBatteryEntities = new();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnActivated(Entity<XAEChargeBatteryComponent> ent, ref XenoArtifactNodeActivatedEvent args)
|
protected override void OnActivated(Entity<XAEChargeBatteryComponent> ent, ref XenoArtifactNodeActivatedEvent args)
|
||||||
{
|
{
|
||||||
_batteryEntities.Clear();
|
_batteryEntities.Clear();
|
||||||
_pBatteryEntities.Clear();
|
|
||||||
|
|
||||||
_lookup.GetEntitiesInRange(args.Coordinates, ent.Comp.Radius, _batteryEntities);
|
_lookup.GetEntitiesInRange(args.Coordinates, ent.Comp.Radius, _batteryEntities);
|
||||||
foreach (var battery in _batteryEntities)
|
foreach (var battery in _batteryEntities)
|
||||||
{
|
{
|
||||||
_battery.SetCharge(battery.AsNullable(), battery.Comp.MaxCharge);
|
_battery.SetCharge(battery.AsNullable(), battery.Comp.MaxCharge);
|
||||||
}
|
}
|
||||||
|
|
||||||
_lookup.GetEntitiesInRange(args.Coordinates, ent.Comp.Radius, _pBatteryEntities);
|
|
||||||
foreach (var pBattery in _pBatteryEntities)
|
|
||||||
{
|
|
||||||
_predictedBattery.SetCharge(pBattery.AsNullable(), pBattery.Comp.MaxCharge);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,17 @@
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
|
using Content.Shared.Power.EntitySystems;
|
||||||
using Content.Shared.PowerCell.Components;
|
using Content.Shared.PowerCell.Components;
|
||||||
|
|
||||||
namespace Content.Shared.Power;
|
namespace Content.Shared.Power;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when a battery's charge or capacity changes (capacity affects relative charge percentage).
|
/// Raised when a battery's charge, charge rate or capacity was updated (capacity affects relative charge percentage).
|
||||||
/// Only raised for entities with <see cref="BatteryComponent"/>.
|
/// If a battery uses <see cref="BatteryComponent.ChargeRate"/> to (dis)charge this is NOT raised every single tick, but only when the charge rate is updated.
|
||||||
|
/// For instantaneous charge changes using <see cref="SharedBatterySystem.SetCharge"/>, <see cref="SharedBatterySystem.ChangeCharge"/> or similar this DOES get raised, but
|
||||||
|
/// you should avoid doing so in update loops if the component has net sync enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public readonly record struct ChargeChangedEvent(float Charge, float Delta, float MaxCharge)
|
public readonly record struct ChargeChangedEvent(float CurrentCharge, float Delta, float CurrentChargeRate, float MaxCharge)
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The new charge of the battery.
|
|
||||||
/// </summary>
|
|
||||||
public readonly float Charge = Charge;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The amount the charge was changed by.
|
|
||||||
/// </summary>
|
|
||||||
public readonly float Delta = Delta;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The maximum charge of the battery.
|
|
||||||
/// </summary>
|
|
||||||
public readonly float MaxCharge = MaxCharge;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when a predicted battery's charge or capacity changes (capacity affects relative charge percentage).
|
|
||||||
/// Unlike <see cref="ChargeChangedEvent"/> this is not raised repeatedly each time the charge changes, but only when the charge rate is changed
|
|
||||||
/// or a charge amount was added or removed instantaneously. The current charge can be inferred from the time of the last update and the charge and
|
|
||||||
/// charge rate at that time.
|
|
||||||
/// Only raised for entities with <see cref="PredictedBatteryComponent"/>.
|
|
||||||
/// </summary>
|
|
||||||
[ByRefEvent]
|
|
||||||
public readonly record struct PredictedBatteryChargeChangedEvent(float CurrentCharge, float Delta, float CurrentChargeRate, float MaxCharge)
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The new charge of the battery.
|
/// The new charge of the battery.
|
||||||
|
|
@ -60,15 +37,14 @@ public readonly record struct PredictedBatteryChargeChangedEvent(float CurrentCh
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when a battery changes its state between full, empty, or neither.
|
/// Raised when a battery changes its state between full, empty, or neither.
|
||||||
/// Used only for <see cref="PredictedBatteryComponent"/>.
|
/// Useful to detect when a battery is empty or fully charged (since ChargeChangedEvent does not get raised every tick for batteries with a constant charge rate).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public record struct PredictedBatteryStateChangedEvent(BatteryState OldState, BatteryState NewState);
|
public record struct BatteryStateChangedEvent(BatteryState OldState, BatteryState NewState);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised to calculate a predicted battery's recharge rate.
|
/// Raised to calculate a predicted battery's recharge rate.
|
||||||
/// Subscribe to this to offset its current charge rate.
|
/// Subscribe to this to offset its current charge rate.
|
||||||
/// Used only for <see cref="PredictedBatteryComponent"/>.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public record struct RefreshChargeRateEvent(float MaxCharge)
|
public record struct RefreshChargeRateEvent(float MaxCharge)
|
||||||
|
|
@ -80,7 +56,7 @@ public record struct RefreshChargeRateEvent(float MaxCharge)
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event that supports multiple battery types.
|
/// Event that supports multiple battery types.
|
||||||
/// Raised when it is necessary to get information about battery charges.
|
/// Raised when it is necessary to get information about battery charges.
|
||||||
/// Works with either <see cref="BatteryComponent"/>, <see cref="PredictedBatteryComponent"/>, or <see cref="PowerCellSlotComponent"/>.
|
/// Works with either <see cref="BatteryComponent"/> or <see cref="PowerCellSlotComponent"/>.
|
||||||
/// If there are multiple batteries then the results will be summed up.
|
/// If there are multiple batteries then the results will be summed up.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
|
|
@ -93,7 +69,7 @@ public record struct GetChargeEvent
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Method event that supports multiple battery types.
|
/// Method event that supports multiple battery types.
|
||||||
/// Raised when it is necessary to change the current battery charge by some value.
|
/// Raised when it is necessary to change the current battery charge by some value.
|
||||||
/// Works with either <see cref="BatteryComponent"/>, <see cref="PredictedBatteryComponent"/>, or <see cref="PowerCellSlotComponent"/>.
|
/// 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.
|
/// If there are multiple batteries then they will be changed in order of subscription until the total value was reached.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,98 @@
|
||||||
using Content.Shared.Power.EntitySystems;
|
using Content.Shared.Power.EntitySystems;
|
||||||
|
using Content.Shared.PowerCell.Components;
|
||||||
using Content.Shared.Guidebook;
|
using Content.Shared.Guidebook;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
namespace Content.Shared.Power.Components;
|
namespace Content.Shared.Power.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Battery node on the pow3r network. Needs other components to connect to actual networks.
|
/// Used for any sort of battery that stores electical power.
|
||||||
/// Use this for batteries that cannot be predicted.
|
/// Can be used as a battery node on the pow3r network. Needs other components to connect to actual networks, see PowerNetworkBatteryComponent.
|
||||||
/// Use <see cref="PredictedBatteryComponent"/> otherwise.
|
/// Also used for power cells using <see cref="PowerCellComponent"/> or battery powered guns with intrinsic battery.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
/// <remarks>
|
||||||
[Virtual]
|
/// IMPORTANT: If your battery has an update loop setting the charge every single tick you should set <see cref="Component.NetSyncEnabled"> to false
|
||||||
|
/// in your prototype to prevent it from getting networked every single tick. However, this will disable prediction.
|
||||||
|
/// This is mostly needed for anything connected to the power network (APCs, SMES, turrets with battery), as their power supply ramps up over time.
|
||||||
|
/// Everything else that only has a constant charge rate (e.g. charging/discharging a battery at a certain wattage) or instantaneous power draw (e.g. shooting a gun) is fine being networked.
|
||||||
|
/// However, you should write your systems to avoid using update loops and instead change the battery's charge rate using <see cref="SharedBatterySystem.RefreshChargeRate"/> and
|
||||||
|
/// the current charge will automatically be inferred if you use <see cref="SharedBatterySystem.GetCharge"/>.
|
||||||
|
/// </remarks>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
|
||||||
[Access(typeof(SharedBatterySystem))]
|
[Access(typeof(SharedBatterySystem))]
|
||||||
public partial class BatteryComponent : Component
|
public sealed partial class BatteryComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum charge of the battery in joules (i.e. watt seconds)
|
/// Maximum charge of the battery in joules (ie. watt seconds)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField, AutoNetworkedField, ViewVariables]
|
||||||
[GuidebookData]
|
[GuidebookData]
|
||||||
public float MaxCharge;
|
public float MaxCharge;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Current charge of the battery in joules (ie. watt seconds)
|
|
||||||
/// </summary>
|
|
||||||
[DataField("startingCharge")] // TODO: rename this datafield to currentCharge
|
|
||||||
public float CurrentCharge;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The price per one joule. Default is 1 speso for 10kJ.
|
/// The price per one joule. Default is 1 speso for 10kJ.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public float PricePerJoule = 0.0001f;
|
public float PricePerJoule = 0.0001f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time stamp of the last networked update.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||||
|
[AutoNetworkedField, AutoPausedField, ViewVariables]
|
||||||
|
public TimeSpan LastUpdate = TimeSpan.Zero;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The intial charge to be set on map init.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public float StartingCharge;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The charge at the last update in joules (i.e. watt seconds).
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField, ViewVariables]
|
||||||
|
public float LastCharge;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current charge rate in watt.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Not a datafield as this is only cached and recalculated on component startup.
|
||||||
|
/// </remarks>
|
||||||
|
[ViewVariables, AutoNetworkedField]
|
||||||
|
public float ChargeRate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current charge state of the battery.
|
||||||
|
/// Used to track state changes for raising <see cref="BatteryStateChangedEvent"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Not a datafield as this is only cached and recalculated in an update loop.
|
||||||
|
/// </remarks>
|
||||||
|
[ViewVariables, AutoNetworkedField]
|
||||||
|
public BatteryState State = BatteryState.Neither;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Charge level status of the battery.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum BatteryState : byte
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Full charge.
|
||||||
|
/// </summary>
|
||||||
|
Full,
|
||||||
|
/// <summary>
|
||||||
|
/// No charge.
|
||||||
|
/// </summary>
|
||||||
|
Empty,
|
||||||
|
/// <summary>
|
||||||
|
/// Neither full nor empty.
|
||||||
|
/// </summary>
|
||||||
|
Neither,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
namespace Content.Shared.Power.Components;
|
namespace Content.Shared.Power.Components;
|
||||||
|
|
@ -5,33 +6,27 @@ namespace Content.Shared.Power.Components;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Self-recharging battery.
|
/// Self-recharging battery.
|
||||||
/// To be used in combination with <see cref="BatteryComponent"/>.
|
/// To be used in combination with <see cref="BatteryComponent"/>.
|
||||||
/// For <see cref="PredictedBatteryComponent"/> use <see cref="PredictedBatterySelfRechargerComponent"/> instead.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, AutoGenerateComponentPause]
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
[AutoGenerateComponentState, AutoGenerateComponentPause]
|
||||||
public sealed partial class BatterySelfRechargerComponent : Component
|
public sealed partial class BatterySelfRechargerComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Is the component currently enabled?
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool AutoRecharge = true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// At what rate does the entity automatically recharge? In watts.
|
/// At what rate does the entity automatically recharge? In watts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField, AutoNetworkedField, ViewVariables]
|
||||||
public float AutoRechargeRate;
|
public float AutoRechargeRate;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How long should the entity stop automatically recharging if charge is used?
|
/// How long should the entity stop automatically recharging if a charge is used?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField, AutoNetworkedField]
|
||||||
public TimeSpan AutoRechargePauseTime = TimeSpan.FromSeconds(0);
|
public TimeSpan AutoRechargePauseTime = TimeSpan.Zero;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Do not auto recharge if this timestamp has yet to happen, set for the auto recharge pause system.
|
/// Do not auto recharge if this timestamp has yet to happen, set for the auto recharge pause system.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||||
[AutoPausedField]
|
[AutoNetworkedField, AutoPausedField, ViewVariables]
|
||||||
public TimeSpan NextAutoRecharge = TimeSpan.FromSeconds(0);
|
public TimeSpan? NextAutoRecharge = TimeSpan.FromSeconds(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ using Robust.Shared.Serialization;
|
||||||
namespace Content.Shared.Power.Components;
|
namespace Content.Shared.Power.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marker component that makes an entity with <see cref="PredictedBatteryComponent"/> update its appearance data for use with visualizers.
|
/// Marker component that makes an entity with <see cref="BatteryComponent"/> update its appearance data for use with visualizers.
|
||||||
/// Also works with an entity with <see cref="PowerCellSlotComponent"/> and will relay the state of the inserted powercell.
|
/// Also works with an entity with <see cref="PowerCellSlotComponent"/> and will relay the state of the inserted powercell.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
public sealed partial class PredictedBatteryVisualsComponent : Component;
|
public sealed partial class BatteryVisualsComponent : Component;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keys for the appearance data.
|
/// Keys for the appearance data.
|
||||||
|
|
@ -37,15 +37,15 @@ public enum BatteryVisuals : byte
|
||||||
public enum BatteryChargingState : byte
|
public enum BatteryChargingState : byte
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// PredictedBatteryComponent.ChargeRate > 0
|
/// BatteryComponent.ChargeRate > 0
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Charging,
|
Charging,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// PredictedBatteryComponent.ChargeRate < 0
|
/// BatteryComponent.ChargeRate < 0
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Decharging,
|
Decharging,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// PredictedBatteryComponent.ChargeRate == 0
|
/// BatteryComponent.ChargeRate == 0
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Constant,
|
Constant,
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ namespace Content.Shared.Power.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allows the charge of a battery to be seen by examination.
|
/// Allows the charge of a battery to be seen by examination.
|
||||||
/// Works with either <see cref="BatteryComponent"/> or <see cref="PredictedBatteryComponent"/>.
|
/// Requires <see cref="BatteryComponent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
public sealed partial class ExaminableBatteryComponent : Component;
|
public sealed partial class ExaminableBatteryComponent : Component;
|
||||||
|
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
using Content.Shared.Power.EntitySystems;
|
|
||||||
using Content.Shared.Guidebook;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
|
|
||||||
namespace Content.Shared.Power.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Predicted equivalent to <see cref="BatteryComponent"/>.
|
|
||||||
/// Use this for electrical power storages that only have a constant charge rate or instantaneous power draw.
|
|
||||||
/// Devices being directly charged by the power network do not fulfill that requirement as their power supply ramps up over time.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// We cannot simply network <see cref="BatteryComponent"/> since it would get dirtied every single tick when it updates.
|
|
||||||
/// This component solves this by requiring a constant charge rate and having the client infer the current charge from the rate
|
|
||||||
/// and the timestamp the charge was last networked at. This can possibly be expanded in the future by adding a second time derivative.
|
|
||||||
/// </remarks>
|
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
|
|
||||||
[Access(typeof(PredictedBatterySystem))]
|
|
||||||
public sealed partial class PredictedBatteryComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Maximum charge of the battery in joules (ie. watt seconds)
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField, ViewVariables]
|
|
||||||
[GuidebookData]
|
|
||||||
public float MaxCharge;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The price per one joule. Default is 1 speso for 10kJ.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public float PricePerJoule = 0.0001f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Time stamp of the last networked update.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
|
||||||
[AutoNetworkedField, AutoPausedField, ViewVariables]
|
|
||||||
public TimeSpan LastUpdate = TimeSpan.Zero;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The intial charge to be set on map init.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public float StartingCharge;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The charge at the last update in joules (i.e. watt seconds).
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField, ViewVariables]
|
|
||||||
public float LastCharge;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current charge rate in watt.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Not a datafield as this is only cached and recalculated on component startup.
|
|
||||||
/// </remarks>
|
|
||||||
[ViewVariables, AutoNetworkedField]
|
|
||||||
public float ChargeRate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current charge state of the battery.
|
|
||||||
/// Used to track state changes for raising <see cref="PredictedBatteryStateChangedEvent"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Not a datafield as this is only cached and recalculated in an update loop.
|
|
||||||
/// </remarks>
|
|
||||||
[ViewVariables, AutoNetworkedField]
|
|
||||||
public BatteryState State = BatteryState.Neither;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Charge level status of the battery.
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public enum BatteryState : byte
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Full charge.
|
|
||||||
/// </summary>
|
|
||||||
Full,
|
|
||||||
/// <summary>
|
|
||||||
/// No charge.
|
|
||||||
/// </summary>
|
|
||||||
Empty,
|
|
||||||
/// <summary>
|
|
||||||
/// Neither full nor empty.
|
|
||||||
/// </summary>
|
|
||||||
Neither,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
|
|
||||||
namespace Content.Shared.Power.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Self-recharging battery.
|
|
||||||
/// To be used in combination with <see cref="PredictedBatteryComponent"/>.
|
|
||||||
/// For <see cref="BatteryComponent"/> use <see cref="BatterySelfRechargerComponent"/> instead.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, NetworkedComponent]
|
|
||||||
[AutoGenerateComponentState, AutoGenerateComponentPause]
|
|
||||||
public sealed partial class PredictedBatterySelfRechargerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// At what rate does the entity automatically recharge? In watts.
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField, ViewVariables]
|
|
||||||
public float AutoRechargeRate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How long should the entity stop automatically recharging if a charge is used?
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public TimeSpan AutoRechargePauseTime = TimeSpan.Zero;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Do not auto recharge if this timestamp has yet to happen, set for the auto recharge pause system.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
|
||||||
[AutoNetworkedField, AutoPausedField, ViewVariables]
|
|
||||||
public TimeSpan? NextAutoRecharge = TimeSpan.FromSeconds(0);
|
|
||||||
}
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Content.Shared.Power.EntitySystems;
|
||||||
|
|
||||||
public sealed class ChargerSystem : EntitySystem
|
public sealed class ChargerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly SharedPowerReceiverSystem _receiver = default!;
|
[Dependency] private readonly SharedPowerReceiverSystem _receiver = default!;
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
|
@ -35,7 +35,7 @@ public sealed class ChargerSystem : EntitySystem
|
||||||
SubscribeLocalEvent<ChargerComponent, EmpPulseEvent>(OnEmpPulse);
|
SubscribeLocalEvent<ChargerComponent, EmpPulseEvent>(OnEmpPulse);
|
||||||
SubscribeLocalEvent<ChargerComponent, EmpDisabledRemovedEvent>(OnEmpRemoved);
|
SubscribeLocalEvent<ChargerComponent, EmpDisabledRemovedEvent>(OnEmpRemoved);
|
||||||
SubscribeLocalEvent<InsideChargerComponent, RefreshChargeRateEvent>(OnRefreshChargeRate);
|
SubscribeLocalEvent<InsideChargerComponent, RefreshChargeRateEvent>(OnRefreshChargeRate);
|
||||||
SubscribeLocalEvent<InsideChargerComponent, PredictedBatteryStateChangedEvent>(OnStatusChanged);
|
SubscribeLocalEvent<InsideChargerComponent, BatteryStateChangedEvent>(OnStatusChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStartup(Entity<ChargerComponent> ent, ref ComponentStartup args)
|
private void OnStartup(Entity<ChargerComponent> ent, ref ComponentStartup args)
|
||||||
|
|
@ -176,7 +176,7 @@ public sealed class ChargerSystem : EntitySystem
|
||||||
|
|
||||||
args.NewChargeRate += chargerComp.ChargeRate;
|
args.NewChargeRate += chargerComp.ChargeRate;
|
||||||
}
|
}
|
||||||
private void OnStatusChanged(Entity<InsideChargerComponent> ent, ref PredictedBatteryStateChangedEvent args)
|
private void OnStatusChanged(Entity<InsideChargerComponent> ent, ref BatteryStateChangedEvent args)
|
||||||
{
|
{
|
||||||
// If the battery is full update the visuals and power draw of the charger.
|
// If the battery is full update the visuals and power draw of the charger.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,182 +0,0 @@
|
||||||
using Content.Shared.Cargo;
|
|
||||||
using Content.Shared.Emp;
|
|
||||||
using Content.Shared.Examine;
|
|
||||||
using Content.Shared.Power.Components;
|
|
||||||
using Content.Shared.Rejuvenate;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Shared.Power.EntitySystems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Responsible for <see cref="PredictedBatteryComponent"/>.
|
|
||||||
/// Predicted equivalent of <see cref="Content.Server.Power.EntitySystems.BatterySystem"/>.
|
|
||||||
/// If you make changes to this make sure to keep the two consistent.
|
|
||||||
/// </summary>
|
|
||||||
public sealed partial class PredictedBatterySystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<PredictedBatteryComponent, ComponentInit>(OnInit);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryComponent, ComponentStartup>(OnStartup);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryComponent, MapInitEvent>(OnMapInit);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryComponent, EmpPulseEvent>(OnEmpPulse);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryComponent, RejuvenateEvent>(OnRejuvenate);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryComponent, ExaminedEvent>(OnExamine);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryComponent, ChangeChargeEvent>(OnChangeCharge);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryComponent, GetChargeEvent>(OnGetCharge);
|
|
||||||
SubscribeLocalEvent<PredictedBatterySelfRechargerComponent, RefreshChargeRateEvent>(OnRefreshChargeRate);
|
|
||||||
SubscribeLocalEvent<PredictedBatterySelfRechargerComponent, ComponentStartup>(OnRechargerStartup);
|
|
||||||
SubscribeLocalEvent<PredictedBatterySelfRechargerComponent, ComponentRemove>(OnRechargerRemove);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryVisualsComponent, PredictedBatteryChargeChangedEvent>(OnVisualsChargeChanged);
|
|
||||||
SubscribeLocalEvent<PredictedBatteryVisualsComponent, PredictedBatteryStateChangedEvent>(OnVisualsStateChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnInit(Entity<PredictedBatteryComponent> ent, ref ComponentInit args)
|
|
||||||
{
|
|
||||||
DebugTools.Assert(!HasComp<BatteryComponent>(ent), $"{ent} has both BatteryComponent and PredictedBatteryComponent");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnStartup(Entity<PredictedBatteryComponent> ent, ref ComponentStartup args)
|
|
||||||
{
|
|
||||||
// In case a recharging component was added before the battery component itself.
|
|
||||||
// Doing this only on map init is not enough because the charge rate is not a datafield, but cached, so it would get lost when reloading the game.
|
|
||||||
// If we would make it a datafield then the integration tests would complain about modifying it before map init.
|
|
||||||
RefreshChargeRate(ent.AsNullable());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMapInit(Entity<PredictedBatteryComponent> ent, ref MapInitEvent args)
|
|
||||||
{
|
|
||||||
SetCharge(ent.AsNullable(), ent.Comp.StartingCharge);
|
|
||||||
RefreshChargeRate(ent.AsNullable());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRejuvenate(Entity<PredictedBatteryComponent> ent, ref RejuvenateEvent args)
|
|
||||||
{
|
|
||||||
SetCharge(ent.AsNullable(), ent.Comp.MaxCharge);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnEmpPulse(Entity<PredictedBatteryComponent> ent, ref EmpPulseEvent args)
|
|
||||||
{
|
|
||||||
args.Affected = true;
|
|
||||||
UseCharge(ent.AsNullable(), args.EnergyConsumption);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnExamine(Entity<PredictedBatteryComponent> ent, ref ExaminedEvent args)
|
|
||||||
{
|
|
||||||
if (!args.IsInDetailsRange)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!HasComp<ExaminableBatteryComponent>(ent))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var chargePercentRounded = 0;
|
|
||||||
var currentCharge = GetCharge(ent.AsNullable());
|
|
||||||
if (ent.Comp.MaxCharge != 0)
|
|
||||||
chargePercentRounded = (int)(100 * currentCharge / ent.Comp.MaxCharge);
|
|
||||||
args.PushMarkup(
|
|
||||||
Loc.GetString(
|
|
||||||
"examinable-battery-component-examine-detail",
|
|
||||||
("percent", chargePercentRounded),
|
|
||||||
("markupPercentColor", "green")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the price for the power contained in an entity's battery.
|
|
||||||
/// </summary>
|
|
||||||
private void CalculateBatteryPrice(Entity<PredictedBatteryComponent> ent, ref PriceCalculationEvent args)
|
|
||||||
{
|
|
||||||
args.Price += GetCharge(ent.AsNullable()) * ent.Comp.PricePerJoule;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnChangeCharge(Entity<PredictedBatteryComponent> ent, ref ChangeChargeEvent args)
|
|
||||||
{
|
|
||||||
if (args.ResidualValue == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.ResidualValue -= ChangeCharge(ent.AsNullable(), args.ResidualValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnGetCharge(Entity<PredictedBatteryComponent> ent, ref GetChargeEvent args)
|
|
||||||
{
|
|
||||||
args.CurrentCharge += GetCharge(ent.AsNullable());
|
|
||||||
args.MaxCharge += ent.Comp.MaxCharge;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRefreshChargeRate(Entity<PredictedBatterySelfRechargerComponent> ent, ref RefreshChargeRateEvent args)
|
|
||||||
{
|
|
||||||
if (_timing.CurTime < ent.Comp.NextAutoRecharge)
|
|
||||||
return; // Still on cooldown
|
|
||||||
|
|
||||||
args.NewChargeRate += ent.Comp.AutoRechargeRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
var curTime = _timing.CurTime;
|
|
||||||
|
|
||||||
// Update self-recharging cooldowns.
|
|
||||||
var rechargerQuery = EntityQueryEnumerator<PredictedBatterySelfRechargerComponent, PredictedBatteryComponent>();
|
|
||||||
while (rechargerQuery.MoveNext(out var uid, out var recharger, out var battery))
|
|
||||||
{
|
|
||||||
if (recharger.NextAutoRecharge == null || curTime < recharger.NextAutoRecharge)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
recharger.NextAutoRecharge = null; // Don't refresh every tick.
|
|
||||||
Dirty(uid, recharger);
|
|
||||||
RefreshChargeRate((uid, battery)); // Cooldown is over, apply the new recharge rate.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raise events when the battery is full or empty so that other systems can react and visuals can get updated.
|
|
||||||
// This is not doing that many calculations, it only has to get the current charge and only raises events if something did change.
|
|
||||||
// If this turns out to be too expensive and shows up on grafana consider updating it less often.
|
|
||||||
var batteryQuery = EntityQueryEnumerator<PredictedBatteryComponent>();
|
|
||||||
while (batteryQuery.MoveNext(out var uid, out var battery))
|
|
||||||
{
|
|
||||||
if (battery.ChargeRate == 0f)
|
|
||||||
continue; // No need to check if it's constant.
|
|
||||||
|
|
||||||
UpdateState((uid, battery));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRechargerStartup(Entity<PredictedBatterySelfRechargerComponent> ent, ref ComponentStartup args)
|
|
||||||
{
|
|
||||||
// In case this component is added after the battery component.
|
|
||||||
RefreshChargeRate(ent.Owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRechargerRemove(Entity<PredictedBatterySelfRechargerComponent> ent, ref ComponentRemove args)
|
|
||||||
{
|
|
||||||
// We use ComponentRemove to make sure this component no longer subscribes to the refresh event.
|
|
||||||
RefreshChargeRate(ent.Owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnVisualsChargeChanged(Entity<PredictedBatteryVisualsComponent> ent, ref PredictedBatteryChargeChangedEvent args)
|
|
||||||
{
|
|
||||||
// Update the appearance data for the charge rate.
|
|
||||||
// We have a separate component for this to not duplicate the networking cost unless we actually use it.
|
|
||||||
var state = BatteryChargingState.Constant;
|
|
||||||
if (args.CurrentChargeRate > 0f)
|
|
||||||
state = BatteryChargingState.Charging;
|
|
||||||
else if (args.CurrentChargeRate < 0f)
|
|
||||||
state = BatteryChargingState.Decharging;
|
|
||||||
|
|
||||||
_appearance.SetData(ent.Owner, BatteryVisuals.Charging, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnVisualsStateChanged(Entity<PredictedBatteryVisualsComponent> ent, ref PredictedBatteryStateChangedEvent args)
|
|
||||||
{
|
|
||||||
// Update the appearance data for the fill level (empty, full, in-between).
|
|
||||||
// We have a separate component for this to not duplicate the networking cost unless we actually use it.
|
|
||||||
_appearance.SetData(ent.Owner, BatteryVisuals.State, args.NewState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,11 +4,11 @@ using JetBrains.Annotations;
|
||||||
namespace Content.Shared.Power.EntitySystems;
|
namespace Content.Shared.Power.EntitySystems;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Responsible for <see cref="PredictedBatteryComponent"/>.
|
/// Responsible for <see cref="BatteryComponent"/>.
|
||||||
/// Predicted equivalent of <see cref="Content.Server.Power.EntitySystems.BatterySystem"/>.
|
/// Predicted equivalent of <see cref="Content.Server.Power.EntitySystems.BatterySystem"/>.
|
||||||
/// If you make changes to this make sure to keep the two consistent.
|
/// If you make changes to this make sure to keep the two consistent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class PredictedBatterySystem
|
public abstract partial class SharedBatterySystem
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changes the battery's charge by the given amount
|
/// Changes the battery's charge by the given amount
|
||||||
|
|
@ -17,7 +17,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The actually changed amount.</returns>
|
/// <returns>The actually changed amount.</returns>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public float ChangeCharge(Entity<PredictedBatteryComponent?> ent, float amount)
|
public float ChangeCharge(Entity<BatteryComponent?> ent, float amount)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp))
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -36,7 +36,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
|
|
||||||
TrySetChargeCooldown(ent.Owner);
|
TrySetChargeCooldown(ent.Owner);
|
||||||
|
|
||||||
var changedEv = new PredictedBatteryChargeChangedEvent(newValue, delta, ent.Comp.ChargeRate, ent.Comp.MaxCharge);
|
var changedEv = new ChargeChangedEvent(newValue, delta, ent.Comp.ChargeRate, ent.Comp.MaxCharge);
|
||||||
RaiseLocalEvent(ent, ref changedEv);
|
RaiseLocalEvent(ent, ref changedEv);
|
||||||
|
|
||||||
// Raise events if the battery status changed between full, empty, or neither.
|
// Raise events if the battery status changed between full, empty, or neither.
|
||||||
|
|
@ -50,7 +50,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The actually changed amount.</returns>
|
/// <returns>The actually changed amount.</returns>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public float UseCharge(Entity<PredictedBatteryComponent?> ent, float amount)
|
public float UseCharge(Entity<BatteryComponent?> ent, float amount)
|
||||||
{
|
{
|
||||||
if (amount <= 0f)
|
if (amount <= 0f)
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
@ -65,7 +65,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>If the full amount was able to be removed.</returns>
|
/// <returns>If the full amount was able to be removed.</returns>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public bool TryUseCharge(Entity<PredictedBatteryComponent?> ent, float amount)
|
public bool TryUseCharge(Entity<BatteryComponent?> ent, float amount)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp, false) || amount > GetCharge(ent))
|
if (!Resolve(ent, ref ent.Comp, false) || amount > GetCharge(ent))
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -78,7 +78,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Sets the battery's charge.
|
/// Sets the battery's charge.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public void SetCharge(Entity<PredictedBatteryComponent?> ent, float value)
|
public void SetCharge(Entity<BatteryComponent?> ent, float value)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp))
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
return;
|
return;
|
||||||
|
|
@ -95,7 +95,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
ent.Comp.LastUpdate = curTime;
|
ent.Comp.LastUpdate = curTime;
|
||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
|
|
||||||
var ev = new PredictedBatteryChargeChangedEvent(newValue, delta, ent.Comp.ChargeRate, ent.Comp.MaxCharge);
|
var ev = new ChargeChangedEvent(newValue, delta, ent.Comp.ChargeRate, ent.Comp.MaxCharge);
|
||||||
RaiseLocalEvent(ent, ref ev);
|
RaiseLocalEvent(ent, ref ev);
|
||||||
|
|
||||||
// Raise events if the battery status changed between full, empty, or neither.
|
// Raise events if the battery status changed between full, empty, or neither.
|
||||||
|
|
@ -106,7 +106,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Sets the battery's maximum charge.
|
/// Sets the battery's maximum charge.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public void SetMaxCharge(Entity<PredictedBatteryComponent?> ent, float value)
|
public void SetMaxCharge(Entity<BatteryComponent?> ent, float value)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp))
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
return;
|
return;
|
||||||
|
|
@ -122,7 +122,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
ent.Comp.LastUpdate = curTime;
|
ent.Comp.LastUpdate = curTime;
|
||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
|
|
||||||
var ev = new PredictedBatteryChargeChangedEvent(ent.Comp.LastCharge, ent.Comp.LastCharge - oldCharge, ent.Comp.ChargeRate, ent.Comp.MaxCharge);
|
var ev = new ChargeChangedEvent(ent.Comp.LastCharge, ent.Comp.LastCharge - oldCharge, ent.Comp.ChargeRate, ent.Comp.MaxCharge);
|
||||||
RaiseLocalEvent(ent, ref ev);
|
RaiseLocalEvent(ent, ref ev);
|
||||||
|
|
||||||
// Raise events if the battery status changed between full, empty, or neither.
|
// Raise events if the battery status changed between full, empty, or neither.
|
||||||
|
|
@ -133,7 +133,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Updates the battery's charge state and sends an event if it changed.
|
/// Updates the battery's charge state and sends an event if it changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public void UpdateState(Entity<PredictedBatteryComponent?> ent)
|
public void UpdateState(Entity<BatteryComponent?> ent)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp))
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
return;
|
return;
|
||||||
|
|
@ -144,7 +144,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
|
|
||||||
var charge = GetCharge(ent);
|
var charge = GetCharge(ent);
|
||||||
|
|
||||||
if (charge == ent.Comp.MaxCharge)
|
if (charge >= ent.Comp.MaxCharge)
|
||||||
newState = BatteryState.Full;
|
newState = BatteryState.Full;
|
||||||
else if (charge == 0f)
|
else if (charge == 0f)
|
||||||
newState = BatteryState.Empty;
|
newState = BatteryState.Empty;
|
||||||
|
|
@ -155,7 +155,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
ent.Comp.State = newState;
|
ent.Comp.State = newState;
|
||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
|
|
||||||
var changedEv = new PredictedBatteryStateChangedEvent(oldState, newState);
|
var changedEv = new BatteryStateChangedEvent(oldState, newState);
|
||||||
RaiseLocalEvent(ent, ref changedEv);
|
RaiseLocalEvent(ent, ref changedEv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Gets the battery's current charge.
|
/// Gets the battery's current charge.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public float GetCharge(Entity<PredictedBatteryComponent?> ent)
|
public float GetCharge(Entity<BatteryComponent?> ent)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp, false))
|
if (!Resolve(ent, ref ent.Comp, false))
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
@ -179,7 +179,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Gets the fraction of charge remaining (0–1).
|
/// Gets the fraction of charge remaining (0–1).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public float GetChargeLevel(Entity<PredictedBatteryComponent?> ent)
|
public float GetChargeLevel(Entity<BatteryComponent?> ent)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp, false))
|
if (!Resolve(ent, ref ent.Comp, false))
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
@ -194,7 +194,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Gets number of remaining uses for the given charge cost.
|
/// Gets number of remaining uses for the given charge cost.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public int GetRemainingUses(Entity<PredictedBatteryComponent?> ent, float cost)
|
public int GetRemainingUses(Entity<BatteryComponent?> ent, float cost)
|
||||||
{
|
{
|
||||||
if (cost <= 0)
|
if (cost <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -209,7 +209,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Gets number of maximum uses at full charge for the given charge cost.
|
/// Gets number of maximum uses at full charge for the given charge cost.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public int GetMaxUses(Entity<PredictedBatteryComponent?> ent, float cost)
|
public int GetMaxUses(Entity<BatteryComponent?> ent, float cost)
|
||||||
{
|
{
|
||||||
if (cost <= 0)
|
if (cost <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -220,13 +220,13 @@ public sealed partial class PredictedBatterySystem
|
||||||
return (int)(ent.Comp.MaxCharge / cost);
|
return (int)(ent.Comp.MaxCharge / cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refreshes the battery's current charge rate by raising a <see cref="RefreshChargeRateEvent"/>.
|
/// Refreshes the battery's current charge rate by raising a <see cref="RefreshChargeRateEvent"/>.
|
||||||
|
/// Subscribe to that event to add to or subtract from the total charge rate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The new charge rate.</returns>
|
/// <returns>The new charge rate.</returns>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public float RefreshChargeRate(Entity<PredictedBatteryComponent?> ent)
|
public float RefreshChargeRate(Entity<BatteryComponent?> ent)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp, false))
|
if (!Resolve(ent, ref ent.Comp, false))
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
@ -241,7 +241,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
|
|
||||||
// Inform other systems about the new rate;
|
// Inform other systems about the new rate;
|
||||||
var changedEv = new PredictedBatteryChargeChangedEvent(ent.Comp.LastCharge, 0f, ent.Comp.ChargeRate, ent.Comp.MaxCharge);
|
var changedEv = new ChargeChangedEvent(ent.Comp.LastCharge, 0f, ent.Comp.ChargeRate, ent.Comp.MaxCharge);
|
||||||
RaiseLocalEvent(ent, ref changedEv);
|
RaiseLocalEvent(ent, ref changedEv);
|
||||||
|
|
||||||
return refreshEv.NewChargeRate;
|
return refreshEv.NewChargeRate;
|
||||||
|
|
@ -252,7 +252,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Uses the cooldown time given in the component.
|
/// Uses the cooldown time given in the component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public void TrySetChargeCooldown(Entity<PredictedBatterySelfRechargerComponent?> ent)
|
public void TrySetChargeCooldown(Entity<BatterySelfRechargerComponent?> ent)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp, false))
|
if (!Resolve(ent, ref ent.Comp, false))
|
||||||
return;
|
return;
|
||||||
|
|
@ -270,7 +270,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Puts the entity's self recharge on cooldown for the specified time.
|
/// Puts the entity's self recharge on cooldown for the specified time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public void SetChargeCooldown(Entity<PredictedBatterySelfRechargerComponent?> ent, TimeSpan cooldown)
|
public void SetChargeCooldown(Entity<BatterySelfRechargerComponent?> ent, TimeSpan cooldown)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp))
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
return;
|
return;
|
||||||
|
|
@ -284,7 +284,7 @@ public sealed partial class PredictedBatterySystem
|
||||||
/// Returns whether the battery is full.
|
/// Returns whether the battery is full.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public bool IsFull(Entity<PredictedBatteryComponent?> ent)
|
public bool IsFull(Entity<BatteryComponent?> ent)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp))
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1,83 +1,177 @@
|
||||||
|
using Content.Shared.Cargo;
|
||||||
using Content.Shared.Emp;
|
using Content.Shared.Emp;
|
||||||
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Power.Components;
|
using Content.Shared.Power.Components;
|
||||||
using JetBrains.Annotations;
|
using Content.Shared.Rejuvenate;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Shared.Power.EntitySystems;
|
namespace Content.Shared.Power.EntitySystems;
|
||||||
|
|
||||||
public abstract class SharedBatterySystem : EntitySystem
|
/// <summary>
|
||||||
|
/// Responsible for <see cref="BatteryComponent"/>.
|
||||||
|
/// </summary>
|
||||||
|
public abstract partial class SharedBatterySystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<BatteryComponent, ComponentStartup>(OnStartup);
|
||||||
|
SubscribeLocalEvent<BatteryComponent, MapInitEvent>(OnMapInit);
|
||||||
SubscribeLocalEvent<BatteryComponent, EmpPulseEvent>(OnEmpPulse);
|
SubscribeLocalEvent<BatteryComponent, EmpPulseEvent>(OnEmpPulse);
|
||||||
|
SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnRejuvenate);
|
||||||
|
SubscribeLocalEvent<BatteryComponent, ExaminedEvent>(OnExamine);
|
||||||
|
SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
|
||||||
|
SubscribeLocalEvent<BatteryComponent, ChangeChargeEvent>(OnChangeCharge);
|
||||||
|
SubscribeLocalEvent<BatteryComponent, GetChargeEvent>(OnGetCharge);
|
||||||
|
SubscribeLocalEvent<BatterySelfRechargerComponent, RefreshChargeRateEvent>(OnRefreshChargeRate);
|
||||||
|
SubscribeLocalEvent<BatterySelfRechargerComponent, ComponentStartup>(OnRechargerStartup);
|
||||||
|
SubscribeLocalEvent<BatterySelfRechargerComponent, ComponentRemove>(OnRechargerRemove);
|
||||||
|
SubscribeLocalEvent<BatteryVisualsComponent, ChargeChangedEvent>(OnVisualsChargeChanged);
|
||||||
|
SubscribeLocalEvent<BatteryVisualsComponent, BatteryStateChangedEvent>(OnVisualsStateChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnStartup(Entity<BatteryComponent> ent, ref ComponentStartup args)
|
||||||
|
{
|
||||||
|
// In case a recharging component was added before the battery component itself.
|
||||||
|
// Doing this only on map init is not enough because the charge rate is not a datafield, but cached, so it would get lost when reloading the game.
|
||||||
|
// If we would make it a datafield then the integration tests would complain about modifying it before map init.
|
||||||
|
// Don't do this in case the battery is not net synced, because then the client would raise events overwriting the networked server state on spawn.
|
||||||
|
if (ent.Comp.NetSyncEnabled)
|
||||||
|
RefreshChargeRate(ent.AsNullable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMapInit(Entity<BatteryComponent> ent, ref MapInitEvent args)
|
||||||
|
{
|
||||||
|
SetCharge(ent.AsNullable(), ent.Comp.StartingCharge);
|
||||||
|
RefreshChargeRate(ent.AsNullable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRejuvenate(Entity<BatteryComponent> ent, ref RejuvenateEvent args)
|
||||||
|
{
|
||||||
|
SetCharge(ent.AsNullable(), ent.Comp.MaxCharge);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmpPulse(Entity<BatteryComponent> ent, ref EmpPulseEvent args)
|
private void OnEmpPulse(Entity<BatteryComponent> ent, ref EmpPulseEvent args)
|
||||||
{
|
{
|
||||||
args.Affected = true;
|
args.Affected = true;
|
||||||
UseCharge(ent.AsNullable(), args.EnergyConsumption);
|
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(ent.Owner);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void OnExamine(Entity<BatteryComponent> ent, ref ExaminedEvent args)
|
||||||
/// Changes the battery's charge by the given amount
|
|
||||||
/// and resets the self-recharge cooldown if it exists.
|
|
||||||
/// A positive value will add charge, a negative value will remove charge.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The actually changed amount.</returns>
|
|
||||||
[PublicAPI]
|
|
||||||
public virtual float ChangeCharge(Entity<BatteryComponent?> ent, float amount)
|
|
||||||
{
|
{
|
||||||
return 0f;
|
if (!args.IsInDetailsRange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!HasComp<ExaminableBatteryComponent>(ent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var chargePercentRounded = 0;
|
||||||
|
var currentCharge = GetCharge(ent.AsNullable());
|
||||||
|
if (ent.Comp.MaxCharge != 0)
|
||||||
|
chargePercentRounded = (int)(100 * currentCharge / ent.Comp.MaxCharge);
|
||||||
|
args.PushMarkup(
|
||||||
|
Loc.GetString(
|
||||||
|
"examinable-battery-component-examine-detail",
|
||||||
|
("percent", chargePercentRounded),
|
||||||
|
("markupPercentColor", "green")
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes the given amount of charge from the battery
|
/// Gets the price for the power contained in an entity's battery.
|
||||||
/// and resets the self-recharge cooldown if it exists.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The actually changed amount.</returns>
|
private void CalculateBatteryPrice(Entity<BatteryComponent> ent, ref PriceCalculationEvent args)
|
||||||
[PublicAPI]
|
|
||||||
public virtual float UseCharge(Entity<BatteryComponent?> ent, float amount)
|
|
||||||
{
|
{
|
||||||
return 0f;
|
args.Price += GetCharge(ent.AsNullable()) * ent.Comp.PricePerJoule;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void OnChangeCharge(Entity<BatteryComponent> ent, ref ChangeChargeEvent args)
|
||||||
/// If sufficient charge is available on the battery, use it. Otherwise, don't.
|
|
||||||
/// Resets the self-recharge cooldown if it exists.
|
|
||||||
/// Always returns false on the client.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>If the full amount was able to be removed.</returns>
|
|
||||||
[PublicAPI]
|
|
||||||
public virtual bool TryUseCharge(Entity<BatteryComponent?> ent, float amount)
|
|
||||||
{
|
{
|
||||||
return false;
|
if (args.ResidualValue == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.ResidualValue -= ChangeCharge(ent.AsNullable(), args.ResidualValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void OnGetCharge(Entity<BatteryComponent> ent, ref GetChargeEvent args)
|
||||||
/// Sets the battery's charge.
|
{
|
||||||
/// </summary>
|
args.CurrentCharge += GetCharge(ent.AsNullable());
|
||||||
[PublicAPI]
|
args.MaxCharge += ent.Comp.MaxCharge;
|
||||||
public virtual void SetCharge(Entity<BatteryComponent?> ent, float value) { }
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void OnRefreshChargeRate(Entity<BatterySelfRechargerComponent> ent, ref RefreshChargeRateEvent args)
|
||||||
/// Sets the battery's maximum charge.
|
{
|
||||||
/// </summary>
|
if (_timing.CurTime < ent.Comp.NextAutoRecharge)
|
||||||
[PublicAPI]
|
return; // Still on cooldown
|
||||||
public virtual void SetMaxCharge(Entity<BatteryComponent?> ent, float value) { }
|
|
||||||
|
|
||||||
/// <summary>
|
args.NewChargeRate += ent.Comp.AutoRechargeRate;
|
||||||
/// Checks if the entity has a self recharge and puts it on cooldown if applicable.
|
}
|
||||||
/// Uses the cooldown time given in the component.
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI]
|
|
||||||
public virtual void TrySetChargeCooldown(Entity<BatterySelfRechargerComponent?> ent) { }
|
|
||||||
|
|
||||||
/// <summary>
|
public override void Update(float frameTime)
|
||||||
/// Puts the entity's self recharge on cooldown for the specified time.
|
{
|
||||||
/// </summary>
|
var curTime = _timing.CurTime;
|
||||||
[PublicAPI]
|
|
||||||
public virtual void SetChargeCooldown(Entity<BatterySelfRechargerComponent?> ent, TimeSpan cooldown) { }
|
// Update self-recharging cooldowns.
|
||||||
|
var rechargerQuery = EntityQueryEnumerator<BatterySelfRechargerComponent, BatteryComponent>();
|
||||||
|
while (rechargerQuery.MoveNext(out var uid, out var recharger, out var battery))
|
||||||
|
{
|
||||||
|
if (recharger.NextAutoRecharge == null || curTime < recharger.NextAutoRecharge)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
recharger.NextAutoRecharge = null; // Don't refresh every tick.
|
||||||
|
Dirty(uid, recharger);
|
||||||
|
RefreshChargeRate((uid, battery)); // Cooldown is over, apply the new recharge rate.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raise events when the battery is full or empty so that other systems can react and visuals can get updated.
|
||||||
|
// This is not doing that many calculations, it only has to get the current charge and only raises events if something did change.
|
||||||
|
// If this turns out to be too expensive and shows up on grafana consider updating it less often.
|
||||||
|
var batteryQuery = EntityQueryEnumerator<BatteryComponent>();
|
||||||
|
while (batteryQuery.MoveNext(out var uid, out var battery))
|
||||||
|
{
|
||||||
|
if (battery.ChargeRate == 0f)
|
||||||
|
continue; // No need to check if it's constant.
|
||||||
|
|
||||||
|
UpdateState((uid, battery));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRechargerStartup(Entity<BatterySelfRechargerComponent> ent, ref ComponentStartup args)
|
||||||
|
{
|
||||||
|
// In case this component is added after the battery component.
|
||||||
|
// Don't do this in case the battery is not net synced, because then the client would raise events overwriting the networked server state on spawn.
|
||||||
|
if (ent.Comp.NetSyncEnabled)
|
||||||
|
RefreshChargeRate(ent.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRechargerRemove(Entity<BatterySelfRechargerComponent> ent, ref ComponentRemove args)
|
||||||
|
{
|
||||||
|
// We use ComponentRemove to make sure this component no longer subscribes to the refresh event.
|
||||||
|
RefreshChargeRate(ent.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnVisualsChargeChanged(Entity<BatteryVisualsComponent> ent, ref ChargeChangedEvent args)
|
||||||
|
{
|
||||||
|
// Update the appearance data for the charge rate.
|
||||||
|
// We have a separate component for this to not duplicate the networking cost unless we actually use it.
|
||||||
|
var state = BatteryChargingState.Constant;
|
||||||
|
if (args.CurrentChargeRate > 0f)
|
||||||
|
state = BatteryChargingState.Charging;
|
||||||
|
else if (args.CurrentChargeRate < 0f)
|
||||||
|
state = BatteryChargingState.Decharging;
|
||||||
|
|
||||||
|
_appearance.SetData(ent.Owner, BatteryVisuals.Charging, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnVisualsStateChanged(Entity<BatteryVisualsComponent> ent, ref BatteryStateChangedEvent args)
|
||||||
|
{
|
||||||
|
// Update the appearance data for the fill level (empty, full, in-between).
|
||||||
|
// We have a separate component for this to not duplicate the networking cost unless we actually use it.
|
||||||
|
_appearance.SetData(ent.Owner, BatteryVisuals.State, args.NewState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace Content.Shared.PowerCell.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This component enables power-cell related interactions (e.g. EntityWhitelists, cell sizes, examine, rigging).
|
/// This component enables power-cell related interactions (e.g. EntityWhitelists, cell sizes, examine, rigging).
|
||||||
/// The actual power functionality is provided by the <see cref="PredictedBatteryComponent"/>.
|
/// The actual power functionality is provided by the <see cref="BatteryComponent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
public sealed partial class PowerCellComponent : Component;
|
public sealed partial class PowerCellComponent : Component;
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ public sealed partial class PowerCellSystem
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public bool TryGetBatteryFromSlot(
|
public bool TryGetBatteryFromSlot(
|
||||||
Entity<PowerCellSlotComponent?> ent,
|
Entity<PowerCellSlotComponent?> ent,
|
||||||
[NotNullWhen(true)] out Entity<PredictedBatteryComponent>? battery)
|
[NotNullWhen(true)] out Entity<BatteryComponent>? battery)
|
||||||
{
|
{
|
||||||
if (!Resolve(ent, ref ent.Comp, false))
|
if (!Resolve(ent, ref ent.Comp, false))
|
||||||
{
|
{
|
||||||
|
|
@ -45,7 +45,7 @@ public sealed partial class PowerCellSystem
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryComp<PredictedBatteryComponent>(slot.Item, out var batteryComp))
|
if (!TryComp<BatteryComponent>(slot.Item, out var batteryComp))
|
||||||
{
|
{
|
||||||
battery = null;
|
battery = null;
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -57,15 +57,15 @@ public sealed partial class PowerCellSystem
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// First tries to get a battery from the entity's power cell slot.
|
/// First tries to get a battery from the entity's power cell slot.
|
||||||
/// If that fails check if the entity itself is a battery with <see cref="PredictedBatteryComponent"/>.
|
/// If that fails check if the entity itself is a battery with <see cref="BatteryComponent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public bool TryGetBatteryFromSlotOrEntity(Entity<PowerCellSlotComponent?> ent, [NotNullWhen(true)] out Entity<PredictedBatteryComponent>? battery)
|
public bool TryGetBatteryFromSlotOrEntity(Entity<PowerCellSlotComponent?> ent, [NotNullWhen(true)] out Entity<BatteryComponent>? battery)
|
||||||
{
|
{
|
||||||
if (TryGetBatteryFromSlot(ent, out battery))
|
if (TryGetBatteryFromSlot(ent, out battery))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (TryComp<PredictedBatteryComponent>(ent, out var batteryComp))
|
if (TryComp<BatteryComponent>(ent, out var batteryComp))
|
||||||
{
|
{
|
||||||
battery = (ent.Owner, batteryComp);
|
battery = (ent.Owner, batteryComp);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -86,13 +86,13 @@ public sealed partial class PowerCellSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// First checks if the entity itself is a battery with <see cref="PredictedBatteryComponent"/>.
|
/// First checks if the entity itself is a battery with <see cref="BatteryComponent"/>.
|
||||||
/// If that fails it will try to get a battery from the entity's power cell slot instead.
|
/// If that fails it will try to get a battery from the entity's power cell slot instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public bool TryGetBatteryFromEntityOrSlot(Entity<PowerCellSlotComponent?> ent, [NotNullWhen(true)] out Entity<PredictedBatteryComponent>? battery)
|
public bool TryGetBatteryFromEntityOrSlot(Entity<PowerCellSlotComponent?> ent, [NotNullWhen(true)] out Entity<BatteryComponent>? battery)
|
||||||
{
|
{
|
||||||
if (TryComp<PredictedBatteryComponent>(ent, out var batteryComp))
|
if (TryComp<BatteryComponent>(ent, out var batteryComp))
|
||||||
{
|
{
|
||||||
battery = (ent.Owner, batteryComp);
|
battery = (ent.Owner, batteryComp);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ public sealed partial class PowerCellSystem
|
||||||
SubscribeLocalEvent<PowerCellSlotComponent, ChangeChargeEvent>(RelayToCell);
|
SubscribeLocalEvent<PowerCellSlotComponent, ChangeChargeEvent>(RelayToCell);
|
||||||
|
|
||||||
SubscribeLocalEvent<PowerCellComponent, EmpAttemptEvent>(RelayToCellSlot); // Prevent the ninja from EMPing its own battery
|
SubscribeLocalEvent<PowerCellComponent, EmpAttemptEvent>(RelayToCellSlot); // Prevent the ninja from EMPing its own battery
|
||||||
SubscribeLocalEvent<PowerCellComponent, PredictedBatteryChargeChangedEvent>(RelayToCellSlot);
|
SubscribeLocalEvent<PowerCellComponent, ChargeChangedEvent>(RelayToCellSlot);
|
||||||
SubscribeLocalEvent<PowerCellComponent, PredictedBatteryStateChangedEvent>(RelayToCellSlot); // For shutting down devices if the battery is empty
|
SubscribeLocalEvent<PowerCellComponent, BatteryStateChangedEvent>(RelayToCellSlot); // For shutting down devices if the battery is empty
|
||||||
SubscribeLocalEvent<PowerCellComponent, RefreshChargeRateEvent>(RelayToCellSlot); // Allow devices to charge/drain inserted batteries
|
SubscribeLocalEvent<PowerCellComponent, RefreshChargeRateEvent>(RelayToCellSlot); // Allow devices to charge/drain inserted batteries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ public sealed partial class PowerCellSystem : EntitySystem
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
[Dependency] private readonly PredictedBatterySystem _battery = default!;
|
[Dependency] private readonly SharedBatterySystem _battery = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
|
|
@ -27,7 +27,7 @@ public sealed partial class PowerCellSystem : EntitySystem
|
||||||
SubscribeLocalEvent<PowerCellSlotComponent, EntInsertedIntoContainerMessage>(OnCellSlotInserted);
|
SubscribeLocalEvent<PowerCellSlotComponent, EntInsertedIntoContainerMessage>(OnCellSlotInserted);
|
||||||
SubscribeLocalEvent<PowerCellSlotComponent, EntRemovedFromContainerMessage>(OnCellSlotRemoved);
|
SubscribeLocalEvent<PowerCellSlotComponent, EntRemovedFromContainerMessage>(OnCellSlotRemoved);
|
||||||
SubscribeLocalEvent<PowerCellSlotComponent, ExaminedEvent>(OnCellSlotExamined);
|
SubscribeLocalEvent<PowerCellSlotComponent, ExaminedEvent>(OnCellSlotExamined);
|
||||||
SubscribeLocalEvent<PowerCellSlotComponent, PredictedBatteryStateChangedEvent>(OnCellSlotStateChanged);
|
SubscribeLocalEvent<PowerCellSlotComponent, BatteryStateChangedEvent>(OnCellSlotStateChanged);
|
||||||
|
|
||||||
SubscribeLocalEvent<PowerCellComponent, ExaminedEvent>(OnCellExamined);
|
SubscribeLocalEvent<PowerCellComponent, ExaminedEvent>(OnCellExamined);
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ public sealed partial class PowerCellSystem : EntitySystem
|
||||||
_battery.RefreshChargeRate(args.Entity);
|
_battery.RefreshChargeRate(args.Entity);
|
||||||
|
|
||||||
// Only update the visuals if we actually use them.
|
// Only update the visuals if we actually use them.
|
||||||
if (!HasComp<PredictedBatteryVisualsComponent>(ent))
|
if (!HasComp<BatteryVisualsComponent>(ent))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Set the data to that of the power cell
|
// Set the data to that of the power cell
|
||||||
|
|
@ -94,7 +94,7 @@ public sealed partial class PowerCellSystem : EntitySystem
|
||||||
_battery.RefreshChargeRate(args.Entity);
|
_battery.RefreshChargeRate(args.Entity);
|
||||||
|
|
||||||
// Only update the visuals if we actually use them.
|
// Only update the visuals if we actually use them.
|
||||||
if (!HasComp<PredictedBatteryVisualsComponent>(ent))
|
if (!HasComp<BatteryVisualsComponent>(ent))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Set the appearance to empty.
|
// Set the appearance to empty.
|
||||||
|
|
@ -103,7 +103,7 @@ public sealed partial class PowerCellSystem : EntitySystem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnCellSlotStateChanged(Entity<PowerCellSlotComponent> ent, ref PredictedBatteryStateChangedEvent args)
|
private void OnCellSlotStateChanged(Entity<PowerCellSlotComponent> ent, ref BatteryStateChangedEvent args)
|
||||||
{
|
{
|
||||||
if (args.NewState != BatteryState.Empty)
|
if (args.NewState != BatteryState.Empty)
|
||||||
return;
|
return;
|
||||||
|
|
@ -123,11 +123,11 @@ public sealed partial class PowerCellSystem : EntitySystem
|
||||||
|
|
||||||
private void OnCellExamined(Entity<PowerCellComponent> ent, ref ExaminedEvent args)
|
private void OnCellExamined(Entity<PowerCellComponent> ent, ref ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (TryComp<PredictedBatteryComponent>(ent, out var battery))
|
if (TryComp<BatteryComponent>(ent, out var battery))
|
||||||
OnBatteryExamined((ent.Owner, battery), ref args);
|
OnBatteryExamined((ent.Owner, battery), ref args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBatteryExamined(Entity<PredictedBatteryComponent> ent, ref ExaminedEvent args)
|
private void OnBatteryExamined(Entity<BatteryComponent> ent, ref ExaminedEvent args)
|
||||||
{
|
{
|
||||||
var chargePercent = _battery.GetChargeLevel(ent.AsNullable()) * 100;
|
var chargePercent = _battery.GetChargeLevel(ent.AsNullable()) * 100;
|
||||||
args.PushMarkup(Loc.GetString("power-cell-component-examine-details", ("currentCharge", $"{chargePercent:F0}")));
|
args.PushMarkup(Loc.GetString("power-cell-component-examine-details", ("currentCharge", $"{chargePercent:F0}")));
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ public sealed partial class ActivatableUISystem
|
||||||
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, ItemToggledEvent>(OnToggled);
|
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, ItemToggledEvent>(OnToggled);
|
||||||
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, BoundUIOpenedEvent>(OnBatteryOpened);
|
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, BoundUIOpenedEvent>(OnBatteryOpened);
|
||||||
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, BoundUIClosedEvent>(OnBatteryClosed);
|
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, BoundUIClosedEvent>(OnBatteryClosed);
|
||||||
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, PredictedBatteryStateChangedEvent>(OnBatteryStateChanged);
|
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, BatteryStateChangedEvent>(OnBatteryStateChanged);
|
||||||
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, ActivatableUIOpenAttemptEvent>(OnBatteryOpenAttempt);
|
SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, ActivatableUIOpenAttemptEvent>(OnBatteryOpenAttempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ public sealed partial class ActivatableUISystem
|
||||||
_toggle.TryDeactivate(uid);
|
_toggle.TryDeactivate(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBatteryStateChanged(Entity<ActivatableUIRequiresPowerCellComponent> ent, ref PredictedBatteryStateChangedEvent args)
|
private void OnBatteryStateChanged(Entity<ActivatableUIRequiresPowerCellComponent> ent, ref BatteryStateChangedEvent args)
|
||||||
{
|
{
|
||||||
// Deactivate when empty.
|
// Deactivate when empty.
|
||||||
if (args.NewState != BatteryState.Empty)
|
if (args.NewState != BatteryState.Empty)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ namespace Content.Shared.Weapons.Ranged.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ammo provider that uses electric charge from a battery to provide ammunition to a weapon.
|
/// Ammo provider that uses electric charge from a battery to provide ammunition to a weapon.
|
||||||
/// This works with both <see cref="BatteryComponent"/> and <see cref="PredictedBatteryComponent"/>
|
/// Works in combination with <see cref="BatteryComponent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
[AutoGenerateComponentState(raiseAfterAutoHandleState: true), AutoGenerateComponentPause]
|
[AutoGenerateComponentState(raiseAfterAutoHandleState: true), AutoGenerateComponentPause]
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ public abstract partial class SharedGunSystem
|
||||||
SubscribeLocalEvent<BatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
|
SubscribeLocalEvent<BatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
|
||||||
SubscribeLocalEvent<BatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
|
SubscribeLocalEvent<BatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
|
||||||
SubscribeLocalEvent<BatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
|
SubscribeLocalEvent<BatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
|
||||||
SubscribeLocalEvent<BatteryAmmoProviderComponent, PredictedBatteryChargeChangedEvent>(OnPredictedChargeChanged);
|
|
||||||
SubscribeLocalEvent<BatteryAmmoProviderComponent, ChargeChangedEvent>(OnChargeChanged);
|
SubscribeLocalEvent<BatteryAmmoProviderComponent, ChargeChangedEvent>(OnChargeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,10 +85,10 @@ public abstract partial class SharedGunSystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TakeCharge(Entity<BatteryAmmoProviderComponent> ent, int shots = 1)
|
public void TakeCharge(Entity<BatteryAmmoProviderComponent> ent, int shots = 1)
|
||||||
{
|
{
|
||||||
// Take charge from either the BatteryComponent, PredictedBatteryComponent or PowerCellSlotComponent.
|
// Take charge from either the BatteryComponent or PowerCellSlotComponent.
|
||||||
var ev = new ChangeChargeEvent(-ent.Comp.FireCost * shots);
|
var ev = new ChangeChargeEvent(-ent.Comp.FireCost * shots);
|
||||||
RaiseLocalEvent(ent, ref ev);
|
RaiseLocalEvent(ent, ref ev);
|
||||||
// UpdateShots is already called by the resulting PredictedBatteryChargeChangedEvent or ChargeChangedEvent
|
// UpdateShots is already called by the resulting ChargeChangedEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
private (EntityUid? Entity, IShootable) GetShootable(BatteryAmmoProviderComponent component, EntityCoordinates coordinates)
|
private (EntityUid? Entity, IShootable) GetShootable(BatteryAmmoProviderComponent component, EntityCoordinates coordinates)
|
||||||
|
|
@ -140,9 +139,8 @@ public abstract partial class SharedGunSystem
|
||||||
UpdateShots(ent);
|
UpdateShots(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For predicted batteries.
|
|
||||||
// If the entity is has a PowerCellSlotComponent then this event is relayed from the power cell to the slot entity.
|
// If the entity is has a PowerCellSlotComponent then this event is relayed from the power cell to the slot entity.
|
||||||
private void OnPredictedChargeChanged(Entity<BatteryAmmoProviderComponent> ent, ref PredictedBatteryChargeChangedEvent args)
|
private void OnChargeChanged(Entity<BatteryAmmoProviderComponent> ent, ref ChargeChangedEvent args)
|
||||||
{
|
{
|
||||||
// Update the visuals and charge counter UI.
|
// Update the visuals and charge counter UI.
|
||||||
UpdateShots(ent);
|
UpdateShots(ent);
|
||||||
|
|
@ -150,14 +148,6 @@ public abstract partial class SharedGunSystem
|
||||||
UpdateNextUpdate(ent, args.CurrentCharge, args.MaxCharge, args.CurrentChargeRate);
|
UpdateNextUpdate(ent, args.CurrentCharge, args.MaxCharge, args.CurrentChargeRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For unpredicted batteries.
|
|
||||||
private void OnChargeChanged(Entity<BatteryAmmoProviderComponent> ent, ref ChargeChangedEvent args)
|
|
||||||
{
|
|
||||||
// Update the visuals and charge counter UI.
|
|
||||||
UpdateShots(ent);
|
|
||||||
// No need to queue an update here since unpredicted batteries already update periodically as they charge/discharge.
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateNextUpdate(Entity<BatteryAmmoProviderComponent> ent, float currentCharge, float maxCharge, float currentChargeRate)
|
private void UpdateNextUpdate(Entity<BatteryAmmoProviderComponent> ent, float currentCharge, float maxCharge, float currentChargeRate)
|
||||||
{
|
{
|
||||||
// Don't queue any updates if charge is constant.
|
// Don't queue any updates if charge is constant.
|
||||||
|
|
@ -179,12 +169,15 @@ public abstract partial class SharedGunSystem
|
||||||
// Shots are only chached, not a DataField, so we need to refresh this when the game is loaded.
|
// Shots are only chached, not a DataField, so we need to refresh this when the game is loaded.
|
||||||
private void OnBatteryStartup(Entity<BatteryAmmoProviderComponent> ent, ref ComponentStartup args)
|
private void OnBatteryStartup(Entity<BatteryAmmoProviderComponent> ent, ref ComponentStartup args)
|
||||||
{
|
{
|
||||||
|
if (_netManager.IsClient && !IsClientSide(ent.Owner))
|
||||||
|
return; // Don't overwrite the server state in cases where the battery is not predicted.
|
||||||
|
|
||||||
UpdateShots(ent);
|
UpdateShots(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current and maximum amount of shots from this entity's battery.
|
/// Gets the current and maximum amount of shots from this entity's battery.
|
||||||
/// This works for BatteryComponent, PredictedBatteryComponent and PowercellSlotComponent.
|
/// This works for BatteryComponent and PowercellSlotComponent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public (int, int) GetShots(Entity<BatteryAmmoProviderComponent> ent)
|
public (int, int) GetShots(Entity<BatteryAmmoProviderComponent> ent)
|
||||||
{
|
{
|
||||||
|
|
@ -197,8 +190,7 @@ public abstract partial class SharedGunSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update loop for refreshing the ammo counter for charging/draining predicted batteries.
|
/// Update loop for refreshing the ammo counter for charging/draining batteries.
|
||||||
/// This is not needed for unpredicted batteries since those already raise ChargeChangedEvent periodically.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateBattery(float frameTime)
|
private void UpdateBattery(float frameTime)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -633,7 +633,7 @@
|
||||||
damage: 35
|
damage: 35
|
||||||
sound: /Audio/Weapons/egloves.ogg
|
sound: /Audio/Weapons/egloves.ogg
|
||||||
- type: LandAtCursor # it deals stamina damage when thrown
|
- type: LandAtCursor # it deals stamina damage when thrown
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1000
|
maxCharge: 1000
|
||||||
startingCharge: 1000
|
startingCharge: 1000
|
||||||
- type: GuideHelp
|
- type: GuideHelp
|
||||||
|
|
|
||||||
|
|
@ -241,10 +241,10 @@
|
||||||
startValue: 0.1
|
startValue: 0.1
|
||||||
endValue: 2.0
|
endValue: 2.0
|
||||||
isLooped: true
|
isLooped: true
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 600 #lights drain 3/s but recharge of 2 makes this 1/s. Therefore 600 is 10 minutes of light.
|
maxCharge: 600 #lights drain 3/s but recharge of 2 makes this 1/s. Therefore 600 is 10 minutes of light.
|
||||||
startingCharge: 600
|
startingCharge: 600
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
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.
|
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
|
- type: entity
|
||||||
|
|
|
||||||
|
|
@ -306,10 +306,10 @@
|
||||||
startValue: 0.1
|
startValue: 0.1
|
||||||
endValue: 2.0
|
endValue: 2.0
|
||||||
isLooped: true
|
isLooped: true
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 600
|
maxCharge: 600
|
||||||
startingCharge: 600
|
startingCharge: 600
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 2
|
autoRechargeRate: 2
|
||||||
- type: Item
|
- type: Item
|
||||||
size: Normal
|
size: Normal
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: DebugLaser
|
proto: DebugLaser
|
||||||
fireCost: 1
|
fireCost: 1
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 1000
|
autoRechargeRate: 1000
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: RedLaser
|
proto: RedLaser
|
||||||
fireCost: 62.5
|
fireCost: 62.5
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1000
|
maxCharge: 1000
|
||||||
startingCharge: 1000
|
startingCharge: 1000
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 40
|
autoRechargeRate: 40
|
||||||
- type: Gun
|
- type: Gun
|
||||||
fireRate: 0.75
|
fireRate: 0.75
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,9 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: WatcherBolt
|
proto: WatcherBolt
|
||||||
fireCost: 50
|
fireCost: 50
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 50
|
autoRechargeRate: 50
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1000
|
maxCharge: 1000
|
||||||
startingCharge: 1000
|
startingCharge: 1000
|
||||||
- type: Gun
|
- type: Gun
|
||||||
|
|
|
||||||
|
|
@ -171,10 +171,10 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: RedLaser
|
proto: RedLaser
|
||||||
fireCost: 140
|
fireCost: 140
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1000
|
maxCharge: 1000
|
||||||
startingCharge: 1000
|
startingCharge: 1000
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 50
|
autoRechargeRate: 50
|
||||||
- type: Gun
|
- type: Gun
|
||||||
fireRate: 0.3
|
fireRate: 0.3
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,9 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: RedLightLaser
|
proto: RedLightLaser
|
||||||
fireCost: 50
|
fireCost: 50
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 50
|
autoRechargeRate: 50
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1000
|
maxCharge: 1000
|
||||||
startingCharge: 1000
|
startingCharge: 1000
|
||||||
- type: Gun
|
- type: Gun
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,11 @@
|
||||||
powerLoad: 500
|
powerLoad: 500
|
||||||
- type: ExtensionCableReceiver
|
- type: ExtensionCableReceiver
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
maxCharge: 300000
|
maxCharge: 300000
|
||||||
startingCharge: 300000
|
startingCharge: 300000
|
||||||
- type: ApcPowerReceiverBattery
|
- type: ApcPowerReceiverBattery
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
components:
|
components:
|
||||||
- type: Item
|
- type: Item
|
||||||
storedRotation: -90
|
storedRotation: -90
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
pricePerJoule: 0.15
|
pricePerJoule: 0.15
|
||||||
- type: PowerCell
|
- type: PowerCell
|
||||||
- type: Explosive
|
- type: Explosive
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
- PowerCell
|
- PowerCell
|
||||||
- type: Riggable
|
- type: Riggable
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
- type: PredictedBatteryVisuals
|
- type: BatteryVisuals
|
||||||
- type: GenericVisualizer
|
- type: GenericVisualizer
|
||||||
visuals:
|
visuals:
|
||||||
enum.BatteryVisuals.State:
|
enum.BatteryVisuals.State:
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
layers:
|
layers:
|
||||||
- state: potato
|
- state: potato
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 70
|
maxCharge: 70
|
||||||
startingCharge: 70
|
startingCharge: 70
|
||||||
- type: Tag
|
- type: Tag
|
||||||
|
|
@ -74,7 +74,7 @@
|
||||||
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 360
|
maxCharge: 360
|
||||||
startingCharge: 360
|
startingCharge: 360
|
||||||
- type: Tag
|
- type: Tag
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 360
|
maxCharge: 360
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@
|
||||||
name: small-capacity nuclear power cell
|
name: small-capacity nuclear power cell
|
||||||
description: A self rechargeable power cell, designed for fast recharge rate at the expense of capacity.
|
description: A self rechargeable power cell, designed for fast recharge rate at the expense of capacity.
|
||||||
components:
|
components:
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 36 # 10 seconds to recharge
|
autoRechargeRate: 36 # 10 seconds to recharge
|
||||||
autoRechargePauseTime: 30
|
autoRechargePauseTime: 30
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@
|
||||||
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 720
|
maxCharge: 720
|
||||||
startingCharge: 720
|
startingCharge: 720
|
||||||
|
|
||||||
|
|
@ -139,7 +139,7 @@
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 720
|
maxCharge: 720
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
|
|
||||||
|
|
@ -157,7 +157,7 @@
|
||||||
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1080
|
maxCharge: 1080
|
||||||
startingCharge: 1080
|
startingCharge: 1080
|
||||||
- type: ReverseEngineering # DeltaV: Upgrade line of high -> hyper -> microreactor
|
- type: ReverseEngineering # DeltaV: Upgrade line of high -> hyper -> microreactor
|
||||||
|
|
@ -178,7 +178,7 @@
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1080
|
maxCharge: 1080
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
|
|
||||||
|
|
@ -196,7 +196,7 @@
|
||||||
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1800
|
maxCharge: 1800
|
||||||
startingCharge: 1800
|
startingCharge: 1800
|
||||||
- type: ReverseEngineering # DeltaV
|
- type: ReverseEngineering # DeltaV
|
||||||
|
|
@ -217,7 +217,7 @@
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1800
|
maxCharge: 1800
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
|
|
||||||
|
|
@ -235,10 +235,10 @@
|
||||||
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 720
|
maxCharge: 720
|
||||||
startingCharge: 720
|
startingCharge: 720
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 12 # takes 1 minute to charge itself back to full
|
autoRechargeRate: 12 # takes 1 minute to charge itself back to full
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|
@ -254,7 +254,7 @@
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|
@ -270,10 +270,10 @@
|
||||||
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1200
|
maxCharge: 1200
|
||||||
startingCharge: 1200
|
startingCharge: 1200
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 40
|
autoRechargeRate: 40
|
||||||
- type: ReverseEngineering # DeltaV
|
- type: ReverseEngineering # DeltaV
|
||||||
difficulty: 4
|
difficulty: 4
|
||||||
|
|
@ -321,7 +321,7 @@
|
||||||
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1400
|
maxCharge: 1400
|
||||||
startingCharge: 1400
|
startingCharge: 1400
|
||||||
|
|
||||||
|
|
@ -339,7 +339,7 @@
|
||||||
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 2700
|
maxCharge: 2700
|
||||||
startingCharge: 2700
|
startingCharge: 2700
|
||||||
|
|
||||||
|
|
@ -357,7 +357,7 @@
|
||||||
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
- map: [ "enum.PowerCellVisualLayers.Unshaded" ]
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 6200
|
maxCharge: 6200
|
||||||
startingCharge: 6200
|
startingCharge: 6200
|
||||||
|
|
||||||
|
|
@ -375,7 +375,7 @@
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1400
|
maxCharge: 1400
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
|
|
||||||
|
|
@ -393,7 +393,7 @@
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|
@ -410,5 +410,5 @@
|
||||||
state: o2
|
state: o2
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,11 @@
|
||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
- type: PowerSink
|
- type: PowerSink
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
maxCharge: 250000000
|
maxCharge: 250000000
|
||||||
pricePerJoule: 0.000009
|
pricePerJoule: 0.000009
|
||||||
- type: ExaminableBattery
|
- type: ExaminableBattery
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
parent: [ HandheldHealthAnalyzerUnpowered, PowerCellSlotSmallItem]
|
parent: [ HandheldHealthAnalyzerUnpowered, PowerCellSlotSmallItem]
|
||||||
suffix: ""
|
suffix: ""
|
||||||
components:
|
components:
|
||||||
- type: PredictedBatteryVisuals
|
- type: BatteryVisuals
|
||||||
- type: PowerCellDraw
|
- type: PowerCellDraw
|
||||||
drawRate: 1.2 #Calculated for 5 minutes on a small cell
|
drawRate: 1.2 #Calculated for 5 minutes on a small cell
|
||||||
- type: ToggleCellDraw
|
- type: ToggleCellDraw
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
maxRange: 256
|
maxRange: 256
|
||||||
followEntity: true
|
followEntity: true
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
- type: PredictedBatteryVisuals
|
- type: BatteryVisuals
|
||||||
- type: GenericVisualizer
|
- type: GenericVisualizer
|
||||||
visuals:
|
visuals:
|
||||||
enum.BatteryVisuals.State:
|
enum.BatteryVisuals.State:
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
- SemiAuto
|
- SemiAuto
|
||||||
soundGunshot:
|
soundGunshot:
|
||||||
path: /Audio/Weapons/Guns/Gunshots/laser.ogg
|
path: /Audio/Weapons/Guns/Gunshots/laser.ogg
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1000
|
maxCharge: 1000
|
||||||
startingCharge: 1000
|
startingCharge: 1000
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
|
|
@ -232,7 +232,7 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: RedLaser
|
proto: RedLaser
|
||||||
fireCost: 62.5
|
fireCost: 62.5
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 500
|
maxCharge: 500
|
||||||
startingCharge: 500
|
startingCharge: 500
|
||||||
- type: Tag
|
- type: Tag
|
||||||
|
|
@ -362,7 +362,7 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: Pulse
|
proto: Pulse
|
||||||
fireCost: 200
|
fireCost: 200
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 2000
|
maxCharge: 2000
|
||||||
startingCharge: 2000
|
startingCharge: 2000
|
||||||
- type: Tag
|
- type: Tag
|
||||||
|
|
@ -404,7 +404,7 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: Pulse
|
proto: Pulse
|
||||||
fireCost: 200
|
fireCost: 200
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 5000
|
maxCharge: 5000
|
||||||
startingCharge: 5000
|
startingCharge: 5000
|
||||||
|
|
||||||
|
|
@ -440,7 +440,7 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: Pulse
|
proto: Pulse
|
||||||
fireCost: 100
|
fireCost: 100
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 40000
|
maxCharge: 40000
|
||||||
startingCharge: 40000
|
startingCharge: 40000
|
||||||
|
|
||||||
|
|
@ -507,7 +507,7 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: AntiParticlesProjectile
|
proto: AntiParticlesProjectile
|
||||||
fireCost: 500
|
fireCost: 500
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 10000
|
maxCharge: 10000
|
||||||
startingCharge: 10000
|
startingCharge: 10000
|
||||||
|
|
||||||
|
|
@ -740,7 +740,7 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: RedMediumLaser
|
proto: RedMediumLaser
|
||||||
fireCost: 100
|
fireCost: 100
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 40
|
autoRechargeRate: 40
|
||||||
- type: MagazineVisuals
|
- type: MagazineVisuals
|
||||||
magState: mag
|
magState: mag
|
||||||
|
|
@ -789,7 +789,7 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: RedMediumLaser
|
proto: RedMediumLaser
|
||||||
fireCost: 100
|
fireCost: 100
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 30
|
autoRechargeRate: 30
|
||||||
- type: MagazineVisuals
|
- type: MagazineVisuals
|
||||||
magState: mag
|
magState: mag
|
||||||
|
|
@ -888,7 +888,7 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: RedMediumLaser
|
proto: RedMediumLaser
|
||||||
fireCost: 100
|
fireCost: 100
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 40
|
autoRechargeRate: 40
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 750
|
price: 750
|
||||||
|
|
@ -937,7 +937,7 @@
|
||||||
sprite: Objects/Weapons/Guns/Battery/inhands_64x.rsi
|
sprite: Objects/Weapons/Guns/Battery/inhands_64x.rsi
|
||||||
heldPrefix: energy
|
heldPrefix: energy
|
||||||
- type: GunRequiresWield #remove when inaccuracy on spreads is fixed
|
- type: GunRequiresWield #remove when inaccuracy on spreads is fixed
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 720 # Delta V - Was 480
|
maxCharge: 720 # Delta V - Was 480
|
||||||
startingCharge: 720
|
startingCharge: 720
|
||||||
- type: BatterySelfRecharger #Delta V - Self recharging not removed
|
- type: BatterySelfRecharger #Delta V - Self recharging not removed
|
||||||
|
|
@ -988,7 +988,7 @@
|
||||||
- proto: BulletDisabler
|
- proto: BulletDisabler
|
||||||
fireCost: 62.5
|
fireCost: 62.5
|
||||||
pacifismAllowedMode: true
|
pacifismAllowedMode: true
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 48
|
autoRechargeRate: 48
|
||||||
autoRechargePauseTime: 10
|
autoRechargePauseTime: 10
|
||||||
|
|
||||||
|
|
@ -1030,7 +1030,7 @@
|
||||||
fireCost: 100
|
fireCost: 100
|
||||||
- proto: BoltTempgunHot
|
- proto: BoltTempgunHot
|
||||||
fireCost: 100
|
fireCost: 100
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1000
|
maxCharge: 1000
|
||||||
startingCharge: 1000
|
startingCharge: 1000
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,11 @@
|
||||||
proto: BulletEnergyTurretLaser
|
proto: BulletEnergyTurretLaser
|
||||||
fireCost: 100
|
fireCost: 100
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
maxCharge: 2000
|
maxCharge: 2000
|
||||||
startingCharge: 2000
|
startingCharge: 2000
|
||||||
- type: ApcPowerReceiverBattery
|
- type: ApcPowerReceiverBattery
|
||||||
|
|
|
||||||
|
|
@ -131,10 +131,10 @@
|
||||||
- type: BatteryAmmoProvider
|
- type: BatteryAmmoProvider
|
||||||
proto: FoodPieBananaCream
|
proto: FoodPieBananaCream
|
||||||
fireCost: 30
|
fireCost: 30
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 90
|
maxCharge: 90
|
||||||
startingCharge: 90
|
startingCharge: 90
|
||||||
- type: PredictedBatterySelfRecharger
|
- type: BatterySelfRecharger
|
||||||
autoRechargeRate: 1
|
autoRechargeRate: 1
|
||||||
- type: AmmoCounter
|
- type: AmmoCounter
|
||||||
- type: Item
|
- type: Item
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
damage: 35
|
damage: 35
|
||||||
sound: /Audio/Weapons/egloves.ogg
|
sound: /Audio/Weapons/egloves.ogg
|
||||||
- type: LandAtCursor # it deals stamina damage when thrown
|
- type: LandAtCursor # it deals stamina damage when thrown
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 360
|
maxCharge: 360
|
||||||
startingCharge: 360
|
startingCharge: 360
|
||||||
- type: UseDelay
|
- type: UseDelay
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
damage: 35
|
damage: 35
|
||||||
sound: /Audio/Weapons/egloves.ogg
|
sound: /Audio/Weapons/egloves.ogg
|
||||||
- type: LandAtCursor # it deals stamina damage when thrown
|
- type: LandAtCursor # it deals stamina damage when thrown
|
||||||
- type: PredictedBattery
|
- type: Battery
|
||||||
maxCharge: 1000
|
maxCharge: 1000
|
||||||
startingCharge: 1000
|
startingCharge: 1000
|
||||||
- type: Item
|
- type: Item
|
||||||
|
|
|
||||||
|
|
@ -458,6 +458,11 @@
|
||||||
- type: ApcPowerReceiver
|
- type: ApcPowerReceiver
|
||||||
- type: ExtensionCableReceiver
|
- type: ExtensionCableReceiver
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
maxCharge: 30000
|
maxCharge: 30000
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
- type: EmergencyLight
|
- type: EmergencyLight
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,11 @@
|
||||||
sprite: Structures/Power/Generation/Tesla/coil.rsi
|
sprite: Structures/Power/Generation/Tesla/coil.rsi
|
||||||
state: coil
|
state: coil
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
maxCharge: 5000000
|
maxCharge: 5000000
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
- type: BatteryDischarger
|
- type: BatteryDischarger
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,11 @@
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
- type: ApcVisuals
|
- type: ApcVisuals
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
maxCharge: 50000
|
maxCharge: 50000
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
- type: ExaminableBattery
|
- type: ExaminableBattery
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,11 @@
|
||||||
sprite: Structures/Power/power.rsi
|
sprite: Structures/Power/power.rsi
|
||||||
state: provider
|
state: provider
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
- type: NodeContainer
|
- type: NodeContainer
|
||||||
nodes:
|
nodes:
|
||||||
input:
|
input:
|
||||||
|
|
@ -104,6 +109,11 @@
|
||||||
sprite: Structures/Power/power.rsi
|
sprite: Structures/Power/power.rsi
|
||||||
state: provider
|
state: provider
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
- type: NodeContainer
|
- type: NodeContainer
|
||||||
nodes:
|
nodes:
|
||||||
input:
|
input:
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,11 @@
|
||||||
- type: Smes
|
- type: Smes
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
startingCharge: 0
|
startingCharge: 0
|
||||||
maxCharge: 8000000
|
maxCharge: 8000000
|
||||||
- type: ExaminableBattery
|
- type: ExaminableBattery
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,11 @@
|
||||||
components:
|
components:
|
||||||
# Core power behavior
|
# Core power behavior
|
||||||
- type: Battery
|
- type: Battery
|
||||||
|
# Very important:
|
||||||
|
# Disable networking to prevent the battery getting continuously dirtied every tick as it interacts with the power network.
|
||||||
|
# This can not be done by changing the charge rate as the power supply ramps up over time.
|
||||||
|
# This disables prediction for this battery.
|
||||||
|
netsync: false
|
||||||
- type: ExaminableBattery
|
- type: ExaminableBattery
|
||||||
- type: NodeContainer
|
- type: NodeContainer
|
||||||
examinable: true
|
examinable: true
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue