/// </summary>
[ByRefEvent]
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;
+ }
+ }
}
SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnBatteryRejuvenate);
SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
SubscribeLocalEvent<BatteryComponent, EmpPulseEvent>(OnEmpPulse);
+ SubscribeLocalEvent<BatteryComponent, ChangeChargeEvent>(OnChangeCharge);
+ SubscribeLocalEvent<BatteryComponent, GetChargeEvent>(OnGetCharge);
SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync);
SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync);
TrySetChargeCooldown(uid);
}
- public float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+ private void OnChangeCharge(Entity<BatteryComponent> entity, ref ChangeChargeEvent args)
{
- if (value <= 0 || !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
- return 0;
+ if (args.ResidualValue == 0)
+ return;
- var newValue = Math.Clamp(0, battery.CurrentCharge - value, battery.MaxCharge);
- var delta = newValue - battery.CurrentCharge;
- battery.CurrentCharge = newValue;
+ args.ResidualValue -= ChangeCharge(entity, args.ResidualValue);
+ }
- // Apply a cooldown to the entity's self recharge if needed.
- TrySetChargeCooldown(uid);
+ private void OnGetCharge(Entity<BatteryComponent> entity, ref GetChargeEvent args)
+ {
+ args.CurrentCharge += entity.Comp.CurrentCharge;
+ args.MaxCharge += entity.Comp.MaxCharge;
+ }
- var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
- RaiseLocalEvent(uid, ref ev);
- return delta;
+ public float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+ {
+ if (value <= 0 || !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
+ return 0;
+
+ return ChangeCharge(uid, -value, battery);
}
public void SetMaxCharge(EntityUid uid, float value, BatteryComponent? battery = null)
var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
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>
/// Checks if the entity has a self recharge and puts it on cooldown if applicable.
/// </summary>
SubscribeLocalEvent<PowerCellSlotComponent, ExaminedEvent>(OnCellSlotExamined);
// funny
SubscribeLocalEvent<PowerCellSlotComponent, BeingMicrowavedEvent>(OnSlotMicrowaved);
+
+ SubscribeLocalEvent<PowerCellSlotComponent, GetChargeEvent>(OnGetCharge);
+ SubscribeLocalEvent<PowerCellSlotComponent, ChangeChargeEvent>(OnChangeCharge);
}
private void OnSlotMicrowaved(EntityUid uid, PowerCellSlotComponent component, BeingMicrowavedEvent args)
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);
+ }
}
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;
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
+ SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
// Projectile
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
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)
{
- if (!TryComp<BatteryComponent>(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)
}
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<T>(Entity<T> 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"),
return null;
}
- protected override void TakeCharge(EntityUid uid, BatteryAmmoProviderComponent component)
+ protected override void TakeCharge(Entity<BatteryAmmoProviderComponent> entity)
{
- // Will raise ChargeChangedEvent
- _battery.UseCharge(uid, component.FireCost);
+ var ev = new ChangeChargeEvent(-entity.Comp.FireCost);
+ RaiseLocalEvent(entity, ref ev);
}
}
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using Robust.Shared.Containers;
+using Content.Server.PowerCell;
namespace Content.Server.Weapons.Ranged.Systems;
[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;
component.Shots--;
}
- TakeCharge(uid, component);
+ TakeCharge((uid, component));
UpdateBatteryAppearance(uid, component);
Dirty(uid, component);
}
/// <summary>
/// Update the battery (server-only) whenever fired.
/// </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)
- type: Appearance
- type: PowerCellVisuals
- type: Riggable
- - type: HitscanBatteryAmmoProvider
- proto: RedLightLaser
- fireCost: 50
- type: entity
name: potato battery
- type: Tag
tags:
- PowerCage
- - type: HitscanBatteryAmmoProvider
- proto: RedShuttleLaser
- fireCost: 150
- type: ClothingSpeedModifier
walkModifier: 0.8
sprintModifier: 0.8
- 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
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
containers:
machine_board: !type:Container
machine_parts: !type:Container
- gun_magazine: !type:ContainerSlot
+ cell_slot: !type:ContainerSlot
- type: Destructible
thresholds:
- trigger:
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
tags:
- PowerCell
- PowerCellSmall
- - type: MagazineAmmoProvider
+ - type: HitscanBatteryAmmoProvider
+ proto: RedLightLaser
+ fireCost: 50
- type: entity
id: ShuttleGunPerforator
containers:
machine_board: !type:Container
machine_parts: !type:Container
- gun_magazine: !type:ContainerSlot
+ cell_slot: !type:ContainerSlot
- type: Destructible
thresholds:
- trigger:
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