BatteryWeaponPowerCell tweaks (#33500)

* BatteryWeaponPowerCell tweaks

* add update ammo ev & shuttle guns tweaks

* MilonPL requested changes

* revert changes in OnPowerCellChanged

* Add events to get charge info & change current charge

---------

Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
This commit is contained in:
Kirus59
2025-04-29 04:12:25 +03:00
committed by GitHub
parent a8054c37b1
commit 8c38aa3742
9 changed files with 138 additions and 43 deletions

View File

@@ -38,4 +38,30 @@ namespace Content.Server.Power.Components
/// </summary> /// </summary>
[ByRefEvent] [ByRefEvent]
public readonly record struct ChargeChangedEvent(float Charge, float MaxCharge); public readonly record struct ChargeChangedEvent(float Charge, float MaxCharge);
/// <summary>
/// Raised when it is necessary to get information about battery charges.
/// </summary>
[ByRefEvent]
public sealed class GetChargeEvent : EntityEventArgs
{
public float CurrentCharge;
public float MaxCharge;
}
/// <summary>
/// Raised when it is necessary to change the current battery charge to a some value.
/// </summary>
[ByRefEvent]
public sealed class ChangeChargeEvent : EntityEventArgs
{
public float OriginalValue;
public float ResidualValue;
public ChangeChargeEvent(float value)
{
OriginalValue = value;
ResidualValue = value;
}
}
} }

View File

@@ -24,6 +24,8 @@ namespace Content.Server.Power.EntitySystems
SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnBatteryRejuvenate); SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnBatteryRejuvenate);
SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice); SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
SubscribeLocalEvent<BatteryComponent, EmpPulseEvent>(OnEmpPulse); SubscribeLocalEvent<BatteryComponent, EmpPulseEvent>(OnEmpPulse);
SubscribeLocalEvent<BatteryComponent, ChangeChargeEvent>(OnChangeCharge);
SubscribeLocalEvent<BatteryComponent, GetChargeEvent>(OnGetCharge);
SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync); SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync);
SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync); SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync);
@@ -116,21 +118,26 @@ namespace Content.Server.Power.EntitySystems
TrySetChargeCooldown(uid); TrySetChargeCooldown(uid);
} }
private void OnChangeCharge(Entity<BatteryComponent> entity, ref ChangeChargeEvent args)
{
if (args.ResidualValue == 0)
return;
args.ResidualValue -= ChangeCharge(entity, args.ResidualValue);
}
private void OnGetCharge(Entity<BatteryComponent> entity, ref GetChargeEvent args)
{
args.CurrentCharge += entity.Comp.CurrentCharge;
args.MaxCharge += entity.Comp.MaxCharge;
}
public float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null) 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; return 0;
var newValue = Math.Clamp(0, battery.CurrentCharge - value, battery.MaxCharge); return ChangeCharge(uid, -value, battery);
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;
} }
public void SetMaxCharge(EntityUid uid, float value, BatteryComponent? battery = null) 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); var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
RaiseLocalEvent(uid, ref ev); RaiseLocalEvent(uid, ref ev);
} }
/// <summary>
/// Changes the current battery charge by some value
/// </summary>
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;
}
/// <summary> /// <summary>
/// Checks if the entity has a self recharge and puts it on cooldown if applicable. /// Checks if the entity has a self recharge and puts it on cooldown if applicable.
/// </summary> /// </summary>

View File

@@ -42,6 +42,9 @@ public sealed partial class PowerCellSystem : SharedPowerCellSystem
SubscribeLocalEvent<PowerCellSlotComponent, ExaminedEvent>(OnCellSlotExamined); SubscribeLocalEvent<PowerCellSlotComponent, ExaminedEvent>(OnCellSlotExamined);
// funny // funny
SubscribeLocalEvent<PowerCellSlotComponent, BeingMicrowavedEvent>(OnSlotMicrowaved); SubscribeLocalEvent<PowerCellSlotComponent, BeingMicrowavedEvent>(OnSlotMicrowaved);
SubscribeLocalEvent<PowerCellSlotComponent, GetChargeEvent>(OnGetCharge);
SubscribeLocalEvent<PowerCellSlotComponent, ChangeChargeEvent>(OnChangeCharge);
} }
private void OnSlotMicrowaved(EntityUid uid, PowerCellSlotComponent component, BeingMicrowavedEvent args) 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")); args.PushMarkup(Loc.GetString("power-cell-component-examine-details-no-battery"));
} }
} }
private void OnGetCharge(Entity<PowerCellSlotComponent> entity, ref GetChargeEvent args)
{
if (!TryGetBatteryFromSlot(entity, out var batteryUid, out _))
return;
RaiseLocalEvent(batteryUid.Value, ref args);
}
private void OnChangeCharge(Entity<PowerCellSlotComponent> entity, ref ChangeChargeEvent args)
{
if (!TryGetBatteryFromSlot(entity, out var batteryUid, out _))
return;
RaiseLocalEvent(batteryUid.Value, ref args);
}
} }

View File

@@ -2,9 +2,11 @@ using Content.Server.Power.Components;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.Damage.Events; using Content.Shared.Damage.Events;
using Content.Shared.FixedPoint; using Content.Shared.FixedPoint;
using Content.Shared.PowerCell.Components;
using Content.Shared.Projectiles; using Content.Shared.Projectiles;
using Content.Shared.Weapons.Ranged; using Content.Shared.Weapons.Ranged;
using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Server.Weapons.Ranged.Systems; namespace Content.Server.Weapons.Ranged.Systems;
@@ -19,29 +21,36 @@ public sealed partial class GunSystem
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup); SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange); SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine); SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
// Projectile // Projectile
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup); SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange); SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine); SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
} }
private void OnBatteryStartup(EntityUid uid, BatteryAmmoProviderComponent component, ComponentStartup args) private void OnBatteryStartup<T>(Entity<T> 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<T>(Entity<T> 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<T>(Entity<T> entity, ref PowerCellChangedEvent args) where T : BatteryAmmoProviderComponent
{
UpdateShots(entity, entity.Comp);
} }
private void UpdateShots(EntityUid uid, BatteryAmmoProviderComponent component) private void UpdateShots(EntityUid uid, BatteryAmmoProviderComponent component)
{ {
if (!TryComp<BatteryComponent>(uid, out var battery)) var ev = new GetChargeEvent();
return; 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) private void UpdateShots(EntityUid uid, BatteryAmmoProviderComponent component, float charge, float maxCharge)
@@ -55,18 +64,24 @@ public sealed partial class GunSystem
} }
component.Shots = shots; component.Shots = shots;
component.Capacity = maxShots;
if (maxShots > 0)
component.Capacity = maxShots;
UpdateBatteryAppearance(uid, component); UpdateBatteryAppearance(uid, component);
var updateAmmoEv = new UpdateClientAmmoEvent();
RaiseLocalEvent(uid, ref updateAmmoEv);
} }
private void OnBatteryDamageExamine(EntityUid uid, BatteryAmmoProviderComponent component, ref DamageExamineEvent args) private void OnBatteryDamageExamine<T>(Entity<T> entity, ref DamageExamineEvent args) where T : BatteryAmmoProviderComponent
{ {
var damageSpec = GetDamage(component); var damageSpec = GetDamage(entity.Comp);
if (damageSpec == null) if (damageSpec == null)
return; return;
var damageType = component switch var damageType = entity.Comp switch
{ {
HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"), HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"),
ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"), ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"),
@@ -103,9 +118,9 @@ public sealed partial class GunSystem
return null; return null;
} }
protected override void TakeCharge(EntityUid uid, BatteryAmmoProviderComponent component) protected override void TakeCharge(Entity<BatteryAmmoProviderComponent> entity)
{ {
// Will raise ChargeChangedEvent var ev = new ChangeChargeEvent(-entity.Comp.FireCost);
_battery.UseCharge(uid, component.FireCost); RaiseLocalEvent(entity, ref ev);
} }
} }

View File

@@ -22,6 +22,7 @@ using Robust.Shared.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Content.Server.PowerCell;
namespace Content.Server.Weapons.Ranged.Systems; 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 SharedColorFlashEffectSystem _color = default!;
[Dependency] private readonly StaminaSystem _stamina = default!; [Dependency] private readonly StaminaSystem _stamina = default!;
[Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly PowerCellSystem _powerCell = default!;
[Dependency] private readonly SharedMapSystem _map = default!; [Dependency] private readonly SharedMapSystem _map = default!;
private const float DamagePitchVariation = 0.05f; private const float DamagePitchVariation = 0.05f;

View File

@@ -67,7 +67,7 @@ public abstract partial class SharedGunSystem
component.Shots--; component.Shots--;
} }
TakeCharge(uid, component); TakeCharge((uid, component));
UpdateBatteryAppearance(uid, component); UpdateBatteryAppearance(uid, component);
Dirty(uid, component); Dirty(uid, component);
} }
@@ -81,9 +81,9 @@ public abstract partial class SharedGunSystem
/// <summary> /// <summary>
/// Update the battery (server-only) whenever fired. /// Update the battery (server-only) whenever fired.
/// </summary> /// </summary>
protected virtual void TakeCharge(EntityUid uid, BatteryAmmoProviderComponent component) protected virtual void TakeCharge(Entity<BatteryAmmoProviderComponent> entity)
{ {
UpdateAmmoCount(uid, prediction: false); UpdateAmmoCount(entity, prediction: false);
} }
protected void UpdateBatteryAppearance(EntityUid uid, BatteryAmmoProviderComponent component) protected void UpdateBatteryAppearance(EntityUid uid, BatteryAmmoProviderComponent component)

View File

@@ -33,9 +33,6 @@
- type: Appearance - type: Appearance
- type: PowerCellVisuals - type: PowerCellVisuals
- type: Riggable - type: Riggable
- type: HitscanBatteryAmmoProvider
proto: RedLightLaser
fireCost: 50
- type: entity - type: entity
name: potato battery name: potato battery
@@ -290,9 +287,6 @@
- type: Tag - type: Tag
tags: tags:
- PowerCage - PowerCage
- type: HitscanBatteryAmmoProvider
proto: RedShuttleLaser
fireCost: 150
- type: ClothingSpeedModifier - type: ClothingSpeedModifier
walkModifier: 0.8 walkModifier: 0.8
sprintModifier: 0.8 sprintModifier: 0.8

View File

@@ -42,10 +42,12 @@
- SemiAuto - SemiAuto
soundGunshot: soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/laser.ogg path: /Audio/Weapons/Guns/Gunshots/laser.ogg
- type: MagazineAmmoProvider - type: HitscanBatteryAmmoProvider
proto: RedLightLaser
fireCost: 50
- type: ItemSlots - type: ItemSlots
slots: slots:
gun_magazine: cell_slot:
name: Magazine name: Magazine
startingItem: PowerCellSmall startingItem: PowerCellSmall
insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg
@@ -54,12 +56,14 @@
tags: tags:
- PowerCell - PowerCell
- PowerCellSmall - PowerCellSmall
- type: PowerCellSlot
cellSlotId: cell_slot
- type: Appearance - type: Appearance
- type: StaticPrice - type: StaticPrice
price: 500 price: 500
- type: ContainerContainer - type: ContainerContainer
containers: containers:
gun_magazine: !type:ContainerSlot cell_slot: !type:ContainerSlot
- type: entity - type: entity
id: BaseWeaponBatterySmall id: BaseWeaponBatterySmall

View File

@@ -56,7 +56,7 @@
containers: containers:
machine_board: !type:Container machine_board: !type:Container
machine_parts: !type:Container machine_parts: !type:Container
gun_magazine: !type:ContainerSlot cell_slot: !type:ContainerSlot
- type: Destructible - type: Destructible
thresholds: thresholds:
- trigger: - trigger:
@@ -80,9 +80,11 @@
zeroVisible: true zeroVisible: true
- type: Machine - type: Machine
board: ShuttleGunSvalinnMachineGunCircuitboard board: ShuttleGunSvalinnMachineGunCircuitboard
- type: PowerCellSlot
cellSlotId: cell_slot
- type: ItemSlots - type: ItemSlots
slots: slots:
gun_magazine: cell_slot:
name: Magazine name: Magazine
insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg
ejectSound: /Audio/Weapons/Guns/MagOut/batrifle_magout.ogg ejectSound: /Audio/Weapons/Guns/MagOut/batrifle_magout.ogg
@@ -90,7 +92,9 @@
tags: tags:
- PowerCell - PowerCell
- PowerCellSmall - PowerCellSmall
- type: MagazineAmmoProvider - type: HitscanBatteryAmmoProvider
proto: RedLightLaser
fireCost: 50
- type: entity - type: entity
id: ShuttleGunPerforator id: ShuttleGunPerforator
@@ -110,7 +114,7 @@
containers: containers:
machine_board: !type:Container machine_board: !type:Container
machine_parts: !type:Container machine_parts: !type:Container
gun_magazine: !type:ContainerSlot cell_slot: !type:ContainerSlot
- type: Destructible - type: Destructible
thresholds: thresholds:
- trigger: - trigger:
@@ -133,16 +137,20 @@
zeroVisible: true zeroVisible: true
- type: Machine - type: Machine
board: ShuttleGunPerforatorCircuitboard board: ShuttleGunPerforatorCircuitboard
- type: PowerCellSlot
cellSlotId: cell_slot
- type: ItemSlots - type: ItemSlots
slots: slots:
gun_magazine: cell_slot:
name: Magazine name: Magazine
insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg
ejectSound: /Audio/Weapons/Guns/MagOut/batrifle_magout.ogg ejectSound: /Audio/Weapons/Guns/MagOut/batrifle_magout.ogg
whitelist: whitelist:
tags: tags:
- PowerCage - PowerCage
- type: MagazineAmmoProvider - type: HitscanBatteryAmmoProvider
proto: RedShuttleLaser
fireCost: 150
# ---- Launchers ---- # ---- Launchers ----
# naming: EXP (Explosion) + conventional power + suffix (g for Grenade, c for RPG Cartridge) + Name # naming: EXP (Explosion) + conventional power + suffix (g for Grenade, c for RPG Cartridge) + Name