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

View File

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

View File

@@ -1,3 +1,5 @@
using System;
namespace Content.Server.Power.Components
{
/// <summary>
@@ -6,8 +8,29 @@ namespace Content.Server.Power.Components
[RegisterComponent]
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.Shared.Examine;
using Content.Shared.Rejuvenate;
using Content.Shared.Timing;
using JetBrains.Annotations;
using Robust.Shared.Utility;
using Robust.Shared.Timing;
namespace Content.Server.Power.EntitySystems
{
[UsedImplicitly]
public sealed class BatterySystem : EntitySystem
{
[Dependency] protected readonly IGameTiming Timing = default!;
public override void Initialize()
{
base.Initialize();
@@ -84,6 +88,14 @@ namespace Content.Server.Power.EntitySystems
while (query.MoveNext(out var uid, out var comp, out var batt))
{
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);
}
}
@@ -100,6 +112,8 @@ namespace Content.Server.Power.EntitySystems
{
args.Affected = true;
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)
@@ -110,6 +124,10 @@ namespace Content.Server.Power.EntitySystems
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;
@@ -139,11 +157,47 @@ namespace Content.Server.Power.EntitySystems
battery.CurrentCharge = MathHelper.Clamp(value, 0, battery.MaxCharge);
if (MathHelper.CloseTo(battery.CurrentCharge, old) &&
!(old != battery.CurrentCharge && battery.CurrentCharge == battery.MaxCharge))
{
return;
}
var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
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>
/// 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.Verbs;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.Prototypes;
namespace Content.Shared.Weapons.Ranged.Systems;
@@ -99,13 +100,21 @@ public sealed class BatteryWeaponFireModesSystem : EntitySystem
component.CurrentFireMode = index;
Dirty(uid, component);
if (TryComp(uid, out ProjectileBatteryAmmoProviderComponent? projectileBatteryAmmoProvider))
if (TryComp(uid, out ProjectileBatteryAmmoProviderComponent? projectileBatteryAmmoProviderComponent))
{
if (!_prototypeManager.TryIndex<EntityPrototype>(fireMode.Prototype, out var prototype))
return;
projectileBatteryAmmoProvider.Prototype = fireMode.Prototype;
projectileBatteryAmmoProvider.FireCost = fireMode.FireCost;
// TODO: Have this get the info directly from the batteryComponent when power is moved to shared.
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)
{

View File

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