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:
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Content.Shared.Weapons.Ranged.Events;
|
||||||
|
|
||||||
|
[ByRefEvent]
|
||||||
|
public readonly record struct UpdateClientAmmoEvent();
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user