mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 21:48:58 +03:00
# Description Title, it replaces the eshield in the BSO's loadout. I had to tweak the values to be a little less... extreme. Also made EMP immune untill somebody ports the eshield changes fully, as right now, the eshield is emp immune, so why would the greatshield be disabled by it. Also, added a way to smart-equip the shield from your belt, if you've already taken out the mace (which can also be put in the belt slot by itself just like a stun baton.) --- <details><summary><h1>Media</h1></summary> <p> [Video of the stamina damage of the mace, and the shield health & recharge.](https://github.com/user-attachments/assets/8b98dda2-e7ab-4b4d-be41-6f0c247b3e10) </p> </details> --- # Changelog 🆑 BramvanZijp - add: Added the BSO's Greatshield and Atrocity (Mace) as a primary weapon option. - remove: The Energy Shield has been removed from the BSO's loadout. --------- Signed-off-by: BramvanZijp <56019239+BramvanZijp@users.noreply.github.com> Co-authored-by: VMSolidus <evilexecutive@gmail.com> (cherry picked from commit d1cc81ca03a35ecd5cf38d280b20b54c1bc63536)
269 lines
10 KiB
C#
269 lines
10 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using Content.Server.Cargo.Systems;
|
|
using Content.Server.Emp;
|
|
using Content.Shared.Emp;
|
|
using Content.Server.Power.Components;
|
|
using Content.Shared.Examine;
|
|
using Content.Shared.Rejuvenate;
|
|
using Content.Shared.Timing;
|
|
using JetBrains.Annotations;
|
|
using Robust.Shared.Containers;
|
|
using Robust.Shared.Utility;
|
|
using Robust.Shared.Timing;
|
|
|
|
namespace Content.Server.Power.EntitySystems
|
|
{
|
|
[UsedImplicitly]
|
|
public sealed class BatterySystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly SharedContainerSystem _containers = default!; // WD EDIT
|
|
[Dependency] protected readonly IGameTiming Timing = default!;
|
|
|
|
private const string CellContainer = "cell_slot";
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<ExaminableBatteryComponent, ExaminedEvent>(OnExamine);
|
|
SubscribeLocalEvent<PowerNetworkBatteryComponent, RejuvenateEvent>(OnNetBatteryRejuvenate);
|
|
SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnBatteryRejuvenate);
|
|
SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
|
|
SubscribeLocalEvent<BatteryComponent, EmpPulseEvent>(OnEmpPulse);
|
|
|
|
SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync);
|
|
SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync);
|
|
}
|
|
|
|
private void OnNetBatteryRejuvenate(EntityUid uid, PowerNetworkBatteryComponent component, RejuvenateEvent args)
|
|
{
|
|
component.NetworkBattery.CurrentStorage = component.NetworkBattery.Capacity;
|
|
}
|
|
|
|
private void OnBatteryRejuvenate(EntityUid uid, BatteryComponent component, RejuvenateEvent args)
|
|
{
|
|
SetCharge(uid, component.MaxCharge, component);
|
|
}
|
|
|
|
private void OnExamine(EntityUid uid, ExaminableBatteryComponent component, ExaminedEvent args)
|
|
{
|
|
if (!TryComp<BatteryComponent>(uid, out var batteryComponent))
|
|
return;
|
|
if (args.IsInDetailsRange)
|
|
{
|
|
var effectiveMax = batteryComponent.MaxCharge;
|
|
if (effectiveMax == 0)
|
|
effectiveMax = 1;
|
|
var chargeFraction = batteryComponent.CurrentCharge / effectiveMax;
|
|
var chargePercentRounded = (int) (chargeFraction * 100);
|
|
args.PushMarkup(
|
|
Loc.GetString(
|
|
"examinable-battery-component-examine-detail",
|
|
("percent", chargePercentRounded),
|
|
("markupPercentColor", "green")
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
private void PreSync(NetworkBatteryPreSync ev)
|
|
{
|
|
// Ignoring entity pausing. If the entity was paused, neither component's data should have been changed.
|
|
var enumerator = AllEntityQuery<PowerNetworkBatteryComponent, BatteryComponent>();
|
|
while (enumerator.MoveNext(out var netBat, out var bat))
|
|
{
|
|
DebugTools.Assert(bat.CurrentCharge <= bat.MaxCharge && bat.CurrentCharge >= 0);
|
|
netBat.NetworkBattery.Capacity = bat.MaxCharge;
|
|
netBat.NetworkBattery.CurrentStorage = bat.CurrentCharge;
|
|
}
|
|
}
|
|
|
|
private void PostSync(NetworkBatteryPostSync ev)
|
|
{
|
|
// Ignoring entity pausing. If the entity was paused, neither component's data should have been changed.
|
|
var enumerator = AllEntityQuery<PowerNetworkBatteryComponent, BatteryComponent>();
|
|
while (enumerator.MoveNext(out var uid, out var netBat, out var bat))
|
|
{
|
|
SetCharge(uid, netBat.NetworkBattery.CurrentStorage, bat);
|
|
}
|
|
}
|
|
|
|
public override void Update(float frameTime)
|
|
{
|
|
var query = EntityQueryEnumerator<BatterySelfRechargerComponent, BatteryComponent>();
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the price for the power contained in an entity's battery.
|
|
/// </summary>
|
|
private void CalculateBatteryPrice(EntityUid uid, BatteryComponent component, ref PriceCalculationEvent args)
|
|
{
|
|
args.Price += component.CurrentCharge * component.PricePerJoule;
|
|
}
|
|
|
|
private void OnEmpPulse(EntityUid uid, BatteryComponent component, ref EmpPulseEvent args)
|
|
{
|
|
args.Affected = true;
|
|
args.Disabled = 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)
|
|
{
|
|
if (value <= 0 || !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
|
|
return 0;
|
|
|
|
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;
|
|
}
|
|
|
|
public void SetMaxCharge(EntityUid uid, float value, BatteryComponent? battery = null)
|
|
{
|
|
if (!Resolve(uid, ref battery))
|
|
return;
|
|
|
|
var old = battery.MaxCharge;
|
|
battery.MaxCharge = Math.Max(value, 0);
|
|
battery.CurrentCharge = Math.Min(battery.CurrentCharge, battery.MaxCharge);
|
|
if (MathHelper.CloseTo(battery.MaxCharge, old))
|
|
return;
|
|
|
|
var ev = new ChargeChangedEvent(battery.CurrentCharge, battery.MaxCharge);
|
|
RaiseLocalEvent(uid, ref ev);
|
|
}
|
|
|
|
public void SetCharge(EntityUid uid, float value, BatteryComponent? battery = null)
|
|
{
|
|
if (!Resolve(uid, ref battery))
|
|
return;
|
|
|
|
var old = battery.CurrentCharge;
|
|
battery.CurrentCharge = MathHelper.Clamp(value, 0, battery.MaxCharge);
|
|
if (MathHelper.CloseTo(battery.CurrentCharge, old))
|
|
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.
|
|
/// </summary>
|
|
public bool TryUseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
|
|
{
|
|
if (!Resolve(uid, ref battery, false) || value > battery.CurrentCharge)
|
|
return false;
|
|
|
|
UseCharge(uid, value, battery);
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Like SetCharge, but checks for conditions like EmpDisabled before executing
|
|
/// </summary>
|
|
public bool TrySetCharge(EntityUid uid, float value, BatteryComponent? battery = null)
|
|
{
|
|
if (!Resolve(uid, ref battery, false) || TryComp<EmpDisabledComponent>(uid, out var emp))
|
|
return false;
|
|
|
|
SetCharge(uid, value, battery);
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns whether the battery is at least 99% charged, basically full.
|
|
/// </summary>
|
|
public bool IsFull(EntityUid uid, BatteryComponent? battery = null)
|
|
{
|
|
if (!Resolve(uid, ref battery))
|
|
return false;
|
|
|
|
return battery.CurrentCharge / battery.MaxCharge >= 0.99f;
|
|
}
|
|
|
|
// WD EDIT START
|
|
public bool TryGetBatteryComponent(EntityUid uid, [NotNullWhen(true)] out BatteryComponent? battery,[NotNullWhen(true)] out EntityUid? batteryUid)
|
|
{
|
|
if (TryComp(uid, out battery))
|
|
{
|
|
batteryUid = uid;
|
|
return true;
|
|
}
|
|
|
|
if (!_containers.TryGetContainer(uid, CellContainer, out var container)
|
|
|| container is not ContainerSlot slot)
|
|
{
|
|
battery = null;
|
|
batteryUid = null;
|
|
return false;
|
|
}
|
|
|
|
batteryUid = slot.ContainedEntity;
|
|
|
|
if (batteryUid != null)
|
|
return TryComp(batteryUid, out battery);
|
|
|
|
battery = null;
|
|
return false;
|
|
}
|
|
// WD EDIT END
|
|
}
|
|
}
|