diff --git a/Content.Server/Power/Components/BatteryComponent.cs b/Content.Server/Power/Components/BatteryComponent.cs
index 860b7b219a..96571bcca3 100644
--- a/Content.Server/Power/Components/BatteryComponent.cs
+++ b/Content.Server/Power/Components/BatteryComponent.cs
@@ -38,4 +38,30 @@ namespace Content.Server.Power.Components
///
[ByRefEvent]
public readonly record struct ChargeChangedEvent(float Charge, float MaxCharge);
+
+ ///
+ /// Raised when it is necessary to get information about battery charges.
+ ///
+ [ByRefEvent]
+ public sealed class GetChargeEvent : EntityEventArgs
+ {
+ public float CurrentCharge;
+ public float MaxCharge;
+ }
+
+ ///
+ /// Raised when it is necessary to change the current battery charge to a some value.
+ ///
+ [ByRefEvent]
+ public sealed class ChangeChargeEvent : EntityEventArgs
+ {
+ public float OriginalValue;
+ public float ResidualValue;
+
+ public ChangeChargeEvent(float value)
+ {
+ OriginalValue = value;
+ ResidualValue = value;
+ }
+ }
}
diff --git a/Content.Server/Power/EntitySystems/BatterySystem.cs b/Content.Server/Power/EntitySystems/BatterySystem.cs
index 89e3ed2c1f..a0ce3ddaad 100644
--- a/Content.Server/Power/EntitySystems/BatterySystem.cs
+++ b/Content.Server/Power/EntitySystems/BatterySystem.cs
@@ -24,6 +24,8 @@ namespace Content.Server.Power.EntitySystems
SubscribeLocalEvent(OnBatteryRejuvenate);
SubscribeLocalEvent(CalculateBatteryPrice);
SubscribeLocalEvent(OnEmpPulse);
+ SubscribeLocalEvent(OnChangeCharge);
+ SubscribeLocalEvent(OnGetCharge);
SubscribeLocalEvent(PreSync);
SubscribeLocalEvent(PostSync);
@@ -116,21 +118,26 @@ namespace Content.Server.Power.EntitySystems
TrySetChargeCooldown(uid);
}
+ private void OnChangeCharge(Entity entity, ref ChangeChargeEvent args)
+ {
+ if (args.ResidualValue == 0)
+ return;
+
+ args.ResidualValue -= ChangeCharge(entity, args.ResidualValue);
+ }
+
+ private void OnGetCharge(Entity entity, ref GetChargeEvent args)
+ {
+ args.CurrentCharge += entity.Comp.CurrentCharge;
+ args.MaxCharge += entity.Comp.MaxCharge;
+ }
+
public float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
{
- if (value <= 0 || !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
+ if (value <= 0 || !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
return 0;
- var newValue = Math.Clamp(0, battery.CurrentCharge - value, battery.MaxCharge);
- var delta = newValue - battery.CurrentCharge;
- battery.CurrentCharge = newValue;
-
- // Apply a cooldown to the entity's self recharge if needed.
- TrySetChargeCooldown(uid);
-
- var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
- RaiseLocalEvent(uid, ref ev);
- return delta;
+ return ChangeCharge(uid, -value, battery);
}
public void SetMaxCharge(EntityUid uid, float value, BatteryComponent? battery = null)
@@ -164,6 +171,26 @@ namespace Content.Server.Power.EntitySystems
var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
RaiseLocalEvent(uid, ref ev);
}
+
+ ///
+ /// Changes the current battery charge by some value
+ ///
+ public float ChangeCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+ {
+ if (!Resolve(uid, ref battery))
+ return 0;
+
+ var newValue = Math.Clamp(0, battery.CurrentCharge + value, battery.MaxCharge);
+ var delta = newValue - battery.CurrentCharge;
+ battery.CurrentCharge = newValue;
+
+ TrySetChargeCooldown(uid);
+
+ var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
+ RaiseLocalEvent(uid, ref ev);
+ return delta;
+ }
+
///
/// Checks if the entity has a self recharge and puts it on cooldown if applicable.
///
diff --git a/Content.Server/PowerCell/PowerCellSystem.cs b/Content.Server/PowerCell/PowerCellSystem.cs
index f7b4cf0249..01767d6c41 100644
--- a/Content.Server/PowerCell/PowerCellSystem.cs
+++ b/Content.Server/PowerCell/PowerCellSystem.cs
@@ -42,6 +42,9 @@ public sealed partial class PowerCellSystem : SharedPowerCellSystem
SubscribeLocalEvent(OnCellSlotExamined);
// funny
SubscribeLocalEvent(OnSlotMicrowaved);
+
+ SubscribeLocalEvent(OnGetCharge);
+ SubscribeLocalEvent(OnChangeCharge);
}
private void OnSlotMicrowaved(EntityUid uid, PowerCellSlotComponent component, BeingMicrowavedEvent args)
@@ -244,4 +247,20 @@ public sealed partial class PowerCellSystem : SharedPowerCellSystem
args.PushMarkup(Loc.GetString("power-cell-component-examine-details-no-battery"));
}
}
+
+ private void OnGetCharge(Entity entity, ref GetChargeEvent args)
+ {
+ if (!TryGetBatteryFromSlot(entity, out var batteryUid, out _))
+ return;
+
+ RaiseLocalEvent(batteryUid.Value, ref args);
+ }
+
+ private void OnChangeCharge(Entity entity, ref ChangeChargeEvent args)
+ {
+ if (!TryGetBatteryFromSlot(entity, out var batteryUid, out _))
+ return;
+
+ RaiseLocalEvent(batteryUid.Value, ref args);
+ }
}
diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs
index ad4bb714d9..1cb19f0755 100644
--- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs
+++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs
@@ -2,9 +2,11 @@ using Content.Server.Power.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Events;
using Content.Shared.FixedPoint;
+using Content.Shared.PowerCell.Components;
using Content.Shared.Projectiles;
using Content.Shared.Weapons.Ranged;
using Content.Shared.Weapons.Ranged.Components;
+using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.Prototypes;
namespace Content.Server.Weapons.Ranged.Systems;
@@ -19,29 +21,36 @@ public sealed partial class GunSystem
SubscribeLocalEvent(OnBatteryStartup);
SubscribeLocalEvent(OnBatteryChargeChange);
SubscribeLocalEvent(OnBatteryDamageExamine);
+ SubscribeLocalEvent(OnPowerCellChanged);
// Projectile
SubscribeLocalEvent(OnBatteryStartup);
SubscribeLocalEvent(OnBatteryChargeChange);
SubscribeLocalEvent(OnBatteryDamageExamine);
+ SubscribeLocalEvent(OnPowerCellChanged);
}
- private void OnBatteryStartup(EntityUid uid, BatteryAmmoProviderComponent component, ComponentStartup args)
+ private void OnBatteryStartup(Entity entity, ref ComponentStartup args) where T : BatteryAmmoProviderComponent
{
- UpdateShots(uid, component);
+ UpdateShots(entity, entity.Comp);
}
- private void OnBatteryChargeChange(EntityUid uid, BatteryAmmoProviderComponent component, ref ChargeChangedEvent args)
+ private void OnBatteryChargeChange(Entity entity, ref ChargeChangedEvent args) where T : BatteryAmmoProviderComponent
{
- UpdateShots(uid, component, args.Charge, args.MaxCharge);
+ UpdateShots(entity, entity.Comp, args.Charge, args.MaxCharge);
+ }
+
+ private void OnPowerCellChanged(Entity entity, ref PowerCellChangedEvent args) where T : BatteryAmmoProviderComponent
+ {
+ UpdateShots(entity, entity.Comp);
}
private void UpdateShots(EntityUid uid, BatteryAmmoProviderComponent component)
{
- if (!TryComp(uid, out var battery))
- return;
+ var ev = new GetChargeEvent();
+ RaiseLocalEvent(uid, ref ev);
- UpdateShots(uid, component, battery.CurrentCharge, battery.MaxCharge);
+ UpdateShots(uid, component, ev.CurrentCharge, ev.MaxCharge);
}
private void UpdateShots(EntityUid uid, BatteryAmmoProviderComponent component, float charge, float maxCharge)
@@ -55,18 +64,24 @@ public sealed partial class GunSystem
}
component.Shots = shots;
- component.Capacity = maxShots;
+
+ if (maxShots > 0)
+ component.Capacity = maxShots;
+
UpdateBatteryAppearance(uid, component);
+
+ var updateAmmoEv = new UpdateClientAmmoEvent();
+ RaiseLocalEvent(uid, ref updateAmmoEv);
}
- private void OnBatteryDamageExamine(EntityUid uid, BatteryAmmoProviderComponent component, ref DamageExamineEvent args)
+ private void OnBatteryDamageExamine(Entity entity, ref DamageExamineEvent args) where T : BatteryAmmoProviderComponent
{
- var damageSpec = GetDamage(component);
+ var damageSpec = GetDamage(entity.Comp);
if (damageSpec == null)
return;
- var damageType = component switch
+ var damageType = entity.Comp switch
{
HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"),
ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"),
@@ -103,9 +118,9 @@ public sealed partial class GunSystem
return null;
}
- protected override void TakeCharge(EntityUid uid, BatteryAmmoProviderComponent component)
+ protected override void TakeCharge(Entity entity)
{
- // Will raise ChargeChangedEvent
- _battery.UseCharge(uid, component.FireCost);
+ var ev = new ChangeChargeEvent(-entity.Comp.FireCost);
+ RaiseLocalEvent(entity, ref ev);
}
}
diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs
index b8d488b575..b862281725 100644
--- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs
+++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs
@@ -22,6 +22,7 @@ using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using Robust.Shared.Containers;
+using Content.Server.PowerCell;
namespace Content.Server.Weapons.Ranged.Systems;
@@ -34,6 +35,7 @@ public sealed partial class GunSystem : SharedGunSystem
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
[Dependency] private readonly StaminaSystem _stamina = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
+ [Dependency] private readonly PowerCellSystem _powerCell = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
private const float DamagePitchVariation = 0.05f;
diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Battery.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Battery.cs
index d6e741fed6..ea865fced6 100644
--- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Battery.cs
+++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Battery.cs
@@ -67,7 +67,7 @@ public abstract partial class SharedGunSystem
component.Shots--;
}
- TakeCharge(uid, component);
+ TakeCharge((uid, component));
UpdateBatteryAppearance(uid, component);
Dirty(uid, component);
}
@@ -81,9 +81,9 @@ public abstract partial class SharedGunSystem
///
/// Update the battery (server-only) whenever fired.
///
- protected virtual void TakeCharge(EntityUid uid, BatteryAmmoProviderComponent component)
+ protected virtual void TakeCharge(Entity entity)
{
- UpdateAmmoCount(uid, prediction: false);
+ UpdateAmmoCount(entity, prediction: false);
}
protected void UpdateBatteryAppearance(EntityUid uid, BatteryAmmoProviderComponent component)
diff --git a/Resources/Prototypes/Entities/Objects/Power/powercells.yml b/Resources/Prototypes/Entities/Objects/Power/powercells.yml
index 8ca2ba7b11..15d15cc6ac 100644
--- a/Resources/Prototypes/Entities/Objects/Power/powercells.yml
+++ b/Resources/Prototypes/Entities/Objects/Power/powercells.yml
@@ -33,9 +33,6 @@
- type: Appearance
- type: PowerCellVisuals
- type: Riggable
- - type: HitscanBatteryAmmoProvider
- proto: RedLightLaser
- fireCost: 50
- type: entity
name: potato battery
@@ -290,9 +287,6 @@
- type: Tag
tags:
- PowerCage
- - type: HitscanBatteryAmmoProvider
- proto: RedShuttleLaser
- fireCost: 150
- type: ClothingSpeedModifier
walkModifier: 0.8
sprintModifier: 0.8
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
index 47f8e8496c..427af659f3 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
@@ -42,10 +42,12 @@
- SemiAuto
soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/laser.ogg
- - type: MagazineAmmoProvider
+ - type: HitscanBatteryAmmoProvider
+ proto: RedLightLaser
+ fireCost: 50
- type: ItemSlots
slots:
- gun_magazine:
+ cell_slot:
name: Magazine
startingItem: PowerCellSmall
insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg
@@ -54,12 +56,14 @@
tags:
- PowerCell
- PowerCellSmall
+ - type: PowerCellSlot
+ cellSlotId: cell_slot
- type: Appearance
- type: StaticPrice
price: 500
- type: ContainerContainer
containers:
- gun_magazine: !type:ContainerSlot
+ cell_slot: !type:ContainerSlot
- type: entity
id: BaseWeaponBatterySmall
diff --git a/Resources/Prototypes/Entities/Structures/Shuttles/cannons.yml b/Resources/Prototypes/Entities/Structures/Shuttles/cannons.yml
index 1926b3e874..f056a48f0d 100644
--- a/Resources/Prototypes/Entities/Structures/Shuttles/cannons.yml
+++ b/Resources/Prototypes/Entities/Structures/Shuttles/cannons.yml
@@ -56,7 +56,7 @@
containers:
machine_board: !type:Container
machine_parts: !type:Container
- gun_magazine: !type:ContainerSlot
+ cell_slot: !type:ContainerSlot
- type: Destructible
thresholds:
- trigger:
@@ -80,9 +80,11 @@
zeroVisible: true
- type: Machine
board: ShuttleGunSvalinnMachineGunCircuitboard
+ - type: PowerCellSlot
+ cellSlotId: cell_slot
- type: ItemSlots
slots:
- gun_magazine:
+ cell_slot:
name: Magazine
insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg
ejectSound: /Audio/Weapons/Guns/MagOut/batrifle_magout.ogg
@@ -90,7 +92,9 @@
tags:
- PowerCell
- PowerCellSmall
- - type: MagazineAmmoProvider
+ - type: HitscanBatteryAmmoProvider
+ proto: RedLightLaser
+ fireCost: 50
- type: entity
id: ShuttleGunPerforator
@@ -110,7 +114,7 @@
containers:
machine_board: !type:Container
machine_parts: !type:Container
- gun_magazine: !type:ContainerSlot
+ cell_slot: !type:ContainerSlot
- type: Destructible
thresholds:
- trigger:
@@ -133,16 +137,20 @@
zeroVisible: true
- type: Machine
board: ShuttleGunPerforatorCircuitboard
+ - type: PowerCellSlot
+ cellSlotId: cell_slot
- type: ItemSlots
slots:
- gun_magazine:
+ cell_slot:
name: Magazine
insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg
ejectSound: /Audio/Weapons/Guns/MagOut/batrifle_magout.ogg
whitelist:
tags:
- PowerCage
- - type: MagazineAmmoProvider
+ - type: HitscanBatteryAmmoProvider
+ proto: RedShuttleLaser
+ fireCost: 150
# ---- Launchers ----
# naming: EXP (Explosion) + conventional power + suffix (g for Grenade, c for RPG Cartridge) + Name