Rework the HoS's Energy Shotgun (Varying energy consumption depending on fire-mode + re-adds a toned down self recharge.) (#32104)

* Rebalance HoS's Energy Shotgun

* SLIGHTLY Up the max charge so the gun properly recharges all of its charges, which matters a lot more with the self charge cooldown system.

* Prevent recharge cooldown if 0 power is used.

* Makes the clientside HUD actually update to reflect the changes in firecost and thus max/current charges.

* Properly fix that recharging to just under full issue instead of applying a budget fix to only the eshotgun.

* Clean up the client ammo UI fix.

* Update the self recharger component to comply with maintainer request.

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* Remove code that was made redundant by a hotfix from another PR.

* Make the recharge pause on EMP, document things where needed, clean up code as per maintainer request, add a note to make the code better when power is moved to shared.

* Fix another internal issue

* Code cleanup + fix the rapid recharge verb to remove pause.

* cleanup

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
BramvanZijp
2024-12-11 17:21:04 +01:00
committed by GitHub
parent 5ba868af79
commit ce9fc82382
7 changed files with 114 additions and 11 deletions

View File

@@ -77,6 +77,7 @@ public sealed partial class GunSystem : SharedGunSystem
base.Initialize(); base.Initialize();
UpdatesOutsidePrediction = true; UpdatesOutsidePrediction = true;
SubscribeLocalEvent<AmmoCounterComponent, ItemStatusCollectMessage>(OnAmmoCounterCollect); SubscribeLocalEvent<AmmoCounterComponent, ItemStatusCollectMessage>(OnAmmoCounterCollect);
SubscribeLocalEvent<AmmoCounterComponent, UpdateClientAmmoEvent>(OnUpdateClientAmmo);
SubscribeAllEvent<MuzzleFlashEvent>(OnMuzzleFlash); SubscribeAllEvent<MuzzleFlashEvent>(OnMuzzleFlash);
// Plays animated effects on the client. // Plays animated effects on the client.
@@ -86,6 +87,11 @@ public sealed partial class GunSystem : SharedGunSystem
InitializeSpentAmmo(); InitializeSpentAmmo();
} }
private void OnUpdateClientAmmo(EntityUid uid, AmmoCounterComponent ammoComp, ref UpdateClientAmmoEvent args)
{
UpdateAmmoCount(uid, ammoComp);
}
private void OnMuzzleFlash(MuzzleFlashEvent args) private void OnMuzzleFlash(MuzzleFlashEvent args)
{ {
var gunUid = GetEntity(args.Uid); var gunUid = GetEntity(args.Uid);

View File

@@ -204,6 +204,7 @@ public sealed partial class AdminVerbSystem
var recharger = EnsureComp<BatterySelfRechargerComponent>(args.Target); var recharger = EnsureComp<BatterySelfRechargerComponent>(args.Target);
recharger.AutoRecharge = true; recharger.AutoRecharge = true;
recharger.AutoRechargeRate = battery.MaxCharge; // Instant refill. recharger.AutoRechargeRate = battery.MaxCharge; // Instant refill.
recharger.AutoRechargePause = false; // No delay.
}, },
Impact = LogImpact.Medium, Impact = LogImpact.Medium,
Message = Loc.GetString("admin-trick-infinite-battery-object-description"), Message = Loc.GetString("admin-trick-infinite-battery-object-description"),
@@ -603,6 +604,7 @@ public sealed partial class AdminVerbSystem
recharger.AutoRecharge = true; recharger.AutoRecharge = true;
recharger.AutoRechargeRate = battery.MaxCharge; // Instant refill. recharger.AutoRechargeRate = battery.MaxCharge; // Instant refill.
recharger.AutoRechargePause = false; // No delay.
} }
}, },
Impact = LogImpact.Extreme, Impact = LogImpact.Extreme,

View File

@@ -1,3 +1,5 @@
using System;
namespace Content.Server.Power.Components namespace Content.Server.Power.Components
{ {
/// <summary> /// <summary>
@@ -6,8 +8,29 @@ namespace Content.Server.Power.Components
[RegisterComponent] [RegisterComponent]
public sealed partial class BatterySelfRechargerComponent : Component public sealed partial class BatterySelfRechargerComponent : Component
{ {
[ViewVariables(VVAccess.ReadWrite)] [DataField("autoRecharge")] public bool AutoRecharge { get; set; } /// <summary>
/// Does the entity auto recharge?
/// </summary>
[DataField] public bool AutoRecharge;
[ViewVariables(VVAccess.ReadWrite)] [DataField("autoRechargeRate")] public float AutoRechargeRate { get; set; } /// <summary>
/// At what rate does the entity automatically recharge?
/// </summary>
[DataField] public float AutoRechargeRate;
/// <summary>
/// Should this entity stop automatically recharging if a charge is used?
/// </summary>
[DataField] public bool AutoRechargePause = false;
/// <summary>
/// How long should the entity stop automatically recharging if a charge is used?
/// </summary>
[DataField] public float AutoRechargePauseTime = 0f;
/// <summary>
/// Do not auto recharge if this timestamp has yet to happen, set for the auto recharge pause system.
/// </summary>
[DataField] public TimeSpan NextAutoRecharge = TimeSpan.FromSeconds(0f);
} }
} }

View File

@@ -3,14 +3,18 @@ using Content.Server.Emp;
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Rejuvenate; using Content.Shared.Rejuvenate;
using Content.Shared.Timing;
using JetBrains.Annotations; 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
{ {
[UsedImplicitly] [UsedImplicitly]
public sealed class BatterySystem : EntitySystem public sealed class BatterySystem : EntitySystem
{ {
[Dependency] protected readonly IGameTiming Timing = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@@ -84,6 +88,14 @@ namespace Content.Server.Power.EntitySystems
while (query.MoveNext(out var uid, out var comp, out var batt)) while (query.MoveNext(out var uid, out var comp, out var batt))
{ {
if (!comp.AutoRecharge) continue; if (!comp.AutoRecharge) continue;
if (batt.IsFullyCharged) continue;
if (comp.AutoRechargePause)
{
if (comp.NextAutoRecharge > Timing.CurTime)
continue;
}
SetCharge(uid, batt.CurrentCharge + comp.AutoRechargeRate * frameTime, batt); SetCharge(uid, batt.CurrentCharge + comp.AutoRechargeRate * frameTime, batt);
} }
} }
@@ -100,6 +112,8 @@ namespace Content.Server.Power.EntitySystems
{ {
args.Affected = true; args.Affected = true;
UseCharge(uid, args.EnergyConsumption, component); UseCharge(uid, args.EnergyConsumption, component);
// Apply a cooldown to the entity's self recharge if needed to avoid it immediately self recharging after an EMP.
TrySetChargeCooldown(uid);
} }
public float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null) public float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
@@ -110,6 +124,10 @@ namespace Content.Server.Power.EntitySystems
var newValue = Math.Clamp(0, battery.CurrentCharge - value, battery.MaxCharge); var newValue = Math.Clamp(0, battery.CurrentCharge - value, battery.MaxCharge);
var delta = newValue - battery.CurrentCharge; var delta = newValue - battery.CurrentCharge;
battery.CurrentCharge = newValue; battery.CurrentCharge = newValue;
// Apply a cooldown to the entity's self recharge if needed.
TrySetChargeCooldown(uid);
var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge); var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
RaiseLocalEvent(uid, ref ev); RaiseLocalEvent(uid, ref ev);
return delta; return delta;
@@ -139,11 +157,47 @@ namespace Content.Server.Power.EntitySystems
battery.CurrentCharge = MathHelper.Clamp(value, 0, battery.MaxCharge); battery.CurrentCharge = MathHelper.Clamp(value, 0, battery.MaxCharge);
if (MathHelper.CloseTo(battery.CurrentCharge, old) && if (MathHelper.CloseTo(battery.CurrentCharge, old) &&
!(old != battery.CurrentCharge && battery.CurrentCharge == battery.MaxCharge)) !(old != battery.CurrentCharge && battery.CurrentCharge == battery.MaxCharge))
{
return; return;
}
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>
/// Checks if the entity has a self recharge and puts it on cooldown if applicable.
/// </summary>
public void TrySetChargeCooldown(EntityUid uid, float value = -1)
{
if (!TryComp<BatterySelfRechargerComponent>(uid, out var batteryself))
return;
if (!batteryself.AutoRechargePause)
return;
// If no answer or a negative is given for value, use the default from AutoRechargePauseTime.
if (value < 0)
value = batteryself.AutoRechargePauseTime;
if (Timing.CurTime + TimeSpan.FromSeconds(value) <= batteryself.NextAutoRecharge)
return;
SetChargeCooldown(uid, batteryself.AutoRechargePauseTime, batteryself);
}
/// <summary>
/// Puts the entity's self recharge on cooldown for the specified time.
/// </summary>
public void SetChargeCooldown(EntityUid uid, float value, BatterySelfRechargerComponent? batteryself = null)
{
if (!Resolve(uid, ref batteryself))
return;
if (value >= 0)
batteryself.NextAutoRecharge = Timing.CurTime + TimeSpan.FromSeconds(value);
else
batteryself.NextAutoRecharge = Timing.CurTime;
}
/// <summary> /// <summary>
/// If sufficient charge is available on the battery, use it. Otherwise, don't. /// If sufficient charge is available on the battery, use it. Otherwise, don't.

View File

@@ -0,0 +1,4 @@
namespace Content.Shared.Weapons.Ranged.Events;
[ByRefEvent]
public readonly record struct UpdateClientAmmoEvent();

View File

@@ -5,6 +5,7 @@ using Content.Shared.Interaction;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Verbs; using Content.Shared.Verbs;
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.Shared.Weapons.Ranged.Systems; namespace Content.Shared.Weapons.Ranged.Systems;
@@ -99,13 +100,21 @@ public sealed class BatteryWeaponFireModesSystem : EntitySystem
component.CurrentFireMode = index; component.CurrentFireMode = index;
Dirty(uid, component); Dirty(uid, component);
if (TryComp(uid, out ProjectileBatteryAmmoProviderComponent? projectileBatteryAmmoProvider)) if (TryComp(uid, out ProjectileBatteryAmmoProviderComponent? projectileBatteryAmmoProviderComponent))
{ {
if (!_prototypeManager.TryIndex<EntityPrototype>(fireMode.Prototype, out var prototype)) if (!_prototypeManager.TryIndex<EntityPrototype>(fireMode.Prototype, out var prototype))
return; return;
projectileBatteryAmmoProvider.Prototype = fireMode.Prototype; // TODO: Have this get the info directly from the batteryComponent when power is moved to shared.
projectileBatteryAmmoProvider.FireCost = fireMode.FireCost; var OldFireCost = projectileBatteryAmmoProviderComponent.FireCost;
projectileBatteryAmmoProviderComponent.Prototype = fireMode.Prototype;
projectileBatteryAmmoProviderComponent.FireCost = fireMode.FireCost;
float FireCostDiff = (float)fireMode.FireCost / (float)OldFireCost;
projectileBatteryAmmoProviderComponent.Shots = (int)Math.Round(projectileBatteryAmmoProviderComponent.Shots/FireCostDiff);
projectileBatteryAmmoProviderComponent.Capacity = (int)Math.Round(projectileBatteryAmmoProviderComponent.Capacity/FireCostDiff);
Dirty(uid, projectileBatteryAmmoProviderComponent);
var updateClientAmmoEvent = new UpdateClientAmmoEvent();
RaiseLocalEvent(uid, ref updateClientAmmoEvent);
if (user != null) if (user != null)
{ {

View File

@@ -740,15 +740,15 @@
path: /Audio/Weapons/Guns/Gunshots/laser_cannon.ogg path: /Audio/Weapons/Guns/Gunshots/laser_cannon.ogg
- type: ProjectileBatteryAmmoProvider - type: ProjectileBatteryAmmoProvider
proto: BulletLaserSpread proto: BulletLaserSpread
fireCost: 100 fireCost: 150
- type: BatteryWeaponFireModes - type: BatteryWeaponFireModes
fireModes: fireModes:
- proto: BulletLaserSpread - proto: BulletLaserSpread
fireCost: 100 fireCost: 150
- proto: BulletLaserSpreadNarrow - proto: BulletLaserSpreadNarrow
fireCost: 100 fireCost: 200
- proto: BulletDisablerSmgSpread - proto: BulletDisablerSmgSpread
fireCost: 100 fireCost: 120
- type: Item - type: Item
size: Large size: Large
shape: shape:
@@ -762,5 +762,10 @@
stealGroup: WeaponEnergyShotgun stealGroup: WeaponEnergyShotgun
- type: GunRequiresWield #remove when inaccuracy on spreads is fixed - type: GunRequiresWield #remove when inaccuracy on spreads is fixed
- type: Battery - type: Battery
maxCharge: 800 maxCharge: 1200
startingCharge: 800 startingCharge: 1200
- type: BatterySelfRecharger
autoRecharge: true
autoRechargeRate: 24
autoRechargePause: true
autoRechargePauseTime: 10