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