Gun + PKA fixes (#16244)
This commit is contained in:
@@ -62,7 +62,9 @@ public sealed partial class GunSystem
|
|||||||
// share as much code as possible
|
// share as much code as possible
|
||||||
if (!Timing.IsFirstTimePredicted ||
|
if (!Timing.IsFirstTimePredicted ||
|
||||||
!TryComp<AmmoCounterComponent>(uid, out var clientComp))
|
!TryComp<AmmoCounterComponent>(uid, out var clientComp))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
UpdateAmmoCount(uid, clientComp);
|
UpdateAmmoCount(uid, clientComp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
using Robust.Shared.Audio;
|
|
||||||
|
|
||||||
namespace Content.Server.Weapons.Ranged.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Responsible for handling recharging a basic entity ammo provider over time.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed class RechargeBasicEntityAmmoComponent : Component
|
|
||||||
{
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("minRechargeCooldown")]
|
|
||||||
public float MinRechargeCooldown = 30f;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("maxRechargeCooldown")]
|
|
||||||
public float MaxRechargeCooldown = 45f;
|
|
||||||
|
|
||||||
[DataField("rechargeSound")]
|
|
||||||
public SoundSpecifier RechargeSound = new SoundPathSpecifier("/Audio/Magic/forcewall.ogg")
|
|
||||||
{
|
|
||||||
Params = AudioParams.Default.WithVolume(-5f)
|
|
||||||
};
|
|
||||||
|
|
||||||
[DataField("accumulatedFrametime")]
|
|
||||||
public float AccumulatedFrameTime;
|
|
||||||
/// <summary>
|
|
||||||
/// Number of seconds until the next recharge.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float NextRechargeTime = 0f;
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
using Content.Server.Weapons.Ranged.Components;
|
|
||||||
using Content.Shared.Examine;
|
|
||||||
using Content.Shared.Weapons.Ranged.Components;
|
|
||||||
using Content.Shared.Weapons.Ranged.Systems;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
|
|
||||||
namespace Content.Server.Weapons.Ranged.Systems;
|
|
||||||
|
|
||||||
public sealed class RechargeBasicEntityAmmoSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
|
||||||
[Dependency] private readonly SharedGunSystem _gun = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<RechargeBasicEntityAmmoComponent, ComponentInit>(OnInit);
|
|
||||||
SubscribeLocalEvent<RechargeBasicEntityAmmoComponent, ExaminedEvent>(OnExamined);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
base.Update(frameTime);
|
|
||||||
|
|
||||||
foreach (var (recharge, ammo) in
|
|
||||||
EntityQuery<RechargeBasicEntityAmmoComponent, BasicEntityAmmoProviderComponent>())
|
|
||||||
{
|
|
||||||
if (ammo.Count is null || ammo.Count == ammo.Capacity)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
recharge.AccumulatedFrameTime += frameTime;
|
|
||||||
|
|
||||||
if (recharge.AccumulatedFrameTime < recharge.NextRechargeTime)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
recharge.AccumulatedFrameTime -= recharge.NextRechargeTime;
|
|
||||||
UpdateCooldown(recharge);
|
|
||||||
|
|
||||||
|
|
||||||
if (_gun.UpdateBasicEntityAmmoCount(ammo.Owner, ammo.Count.Value + 1, ammo))
|
|
||||||
{
|
|
||||||
SoundSystem.Play(recharge.RechargeSound.GetSound(), Filter.Pvs(recharge.Owner), recharge.Owner,
|
|
||||||
recharge.RechargeSound.Params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnInit(EntityUid uid, RechargeBasicEntityAmmoComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
UpdateCooldown(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnExamined(EntityUid uid, RechargeBasicEntityAmmoComponent component, ExaminedEvent args)
|
|
||||||
{
|
|
||||||
if (!TryComp<BasicEntityAmmoProviderComponent>(uid, out var ammo)
|
|
||||||
|| ammo.Count == ammo.Capacity)
|
|
||||||
{
|
|
||||||
args.PushMarkup(Loc.GetString("recharge-basic-entity-ammo-full"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var timeLeft = component.NextRechargeTime - component.AccumulatedFrameTime;
|
|
||||||
args.PushMarkup(Loc.GetString("recharge-basic-entity-ammo-can-recharge", ("seconds", Math.Round(timeLeft, 1))));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateCooldown(RechargeBasicEntityAmmoComponent component)
|
|
||||||
{
|
|
||||||
component.NextRechargeTime = _random.NextFloat(component.MinRechargeCooldown, component.MaxRechargeCooldown);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Shared.Weapons.Ranged.Components;
|
namespace Content.Shared.Weapons.Ranged.Components;
|
||||||
@@ -9,7 +8,7 @@ namespace Content.Shared.Weapons.Ranged.Components;
|
|||||||
/// Simply provides a certain capacity of entities that cannot be reloaded through normal means and have
|
/// Simply provides a certain capacity of entities that cannot be reloaded through normal means and have
|
||||||
/// no special behavior like cycling, magazine
|
/// no special behavior like cycling, magazine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, AutoGenerateComponentState]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
public sealed partial class BasicEntityAmmoProviderComponent : AmmoProviderComponent
|
public sealed partial class BasicEntityAmmoProviderComponent : AmmoProviderComponent
|
||||||
{
|
{
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
|
namespace Content.Shared.Weapons.Ranged.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Responsible for handling recharging a basic entity ammo provider over time.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
public sealed partial class RechargeBasicEntityAmmoComponent : Component
|
||||||
|
{
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("rechargeCooldown")]
|
||||||
|
[AutoNetworkedField]
|
||||||
|
public float RechargeCooldown = 1.5f;
|
||||||
|
|
||||||
|
[DataField("rechargeSound")]
|
||||||
|
[AutoNetworkedField]
|
||||||
|
public SoundSpecifier RechargeSound = new SoundPathSpecifier("/Audio/Magic/forcewall.ogg")
|
||||||
|
{
|
||||||
|
Params = AudioParams.Default.WithVolume(-5f)
|
||||||
|
};
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite),
|
||||||
|
DataField("nextCharge", customTypeSerializer:typeof(TimeOffsetSerializer)),
|
||||||
|
AutoNetworkedField]
|
||||||
|
public TimeSpan? NextCharge;
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Weapons.Ranged.Components;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Weapons.Ranged.Systems;
|
||||||
|
|
||||||
|
public sealed class RechargeBasicEntityAmmoSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly INetManager _netManager = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly SharedGunSystem _gun = default!;
|
||||||
|
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<RechargeBasicEntityAmmoComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||||
|
SubscribeLocalEvent<RechargeBasicEntityAmmoComponent, MapInitEvent>(OnInit);
|
||||||
|
SubscribeLocalEvent<RechargeBasicEntityAmmoComponent, ExaminedEvent>(OnExamined);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnpaused(EntityUid uid, RechargeBasicEntityAmmoComponent component, ref EntityUnpausedEvent args)
|
||||||
|
{
|
||||||
|
if (component.NextCharge == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.NextCharge = component.NextCharge.Value + args.PausedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
var query = EntityQueryEnumerator<RechargeBasicEntityAmmoComponent, BasicEntityAmmoProviderComponent>();
|
||||||
|
|
||||||
|
while (query.MoveNext(out var uid, out var recharge, out var ammo))
|
||||||
|
{
|
||||||
|
if (ammo.Count is null || ammo.Count == ammo.Capacity || recharge.NextCharge == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (recharge.NextCharge > _timing.CurTime)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_gun.UpdateBasicEntityAmmoCount(uid, ammo.Count.Value + 1, ammo))
|
||||||
|
{
|
||||||
|
if (_netManager.IsClient && _timing.IsFirstTimePredicted)
|
||||||
|
_audio.Play(recharge.RechargeSound, Filter.Local(), uid, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ammo.Count == ammo.Capacity)
|
||||||
|
{
|
||||||
|
recharge.NextCharge = null;
|
||||||
|
Dirty(recharge);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
recharge.NextCharge = recharge.NextCharge.Value + TimeSpan.FromSeconds(recharge.RechargeCooldown);
|
||||||
|
Dirty(recharge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInit(EntityUid uid, RechargeBasicEntityAmmoComponent component, MapInitEvent args)
|
||||||
|
{
|
||||||
|
component.NextCharge = _timing.CurTime;
|
||||||
|
Dirty(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExamined(EntityUid uid, RechargeBasicEntityAmmoComponent component, ExaminedEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<BasicEntityAmmoProviderComponent>(uid, out var ammo)
|
||||||
|
|| ammo.Count == ammo.Capacity ||
|
||||||
|
component.NextCharge == null)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("recharge-basic-entity-ammo-full"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeLeft = component.NextCharge + _metadata.GetPauseTime(uid) - _timing.CurTime;
|
||||||
|
args.PushMarkup(Loc.GetString("recharge-basic-entity-ammo-can-recharge", ("seconds", Math.Round(timeLeft.Value.TotalSeconds, 1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset(EntityUid uid, RechargeBasicEntityAmmoComponent? recharge = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref recharge, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (recharge.NextCharge == null || recharge.NextCharge < _timing.CurTime)
|
||||||
|
{
|
||||||
|
recharge.NextCharge = _timing.CurTime + TimeSpan.FromSeconds(recharge.RechargeCooldown);
|
||||||
|
Dirty(recharge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,12 +8,12 @@ public abstract partial class SharedGunSystem
|
|||||||
{
|
{
|
||||||
protected virtual void InitializeBasicEntity()
|
protected virtual void InitializeBasicEntity()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, ComponentInit>(OnBasicEntityInit);
|
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, MapInitEvent>(OnBasicEntityMapInit);
|
||||||
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, TakeAmmoEvent>(OnBasicEntityTakeAmmo);
|
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, TakeAmmoEvent>(OnBasicEntityTakeAmmo);
|
||||||
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, GetAmmoCountEvent>(OnBasicEntityAmmoCount);
|
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, GetAmmoCountEvent>(OnBasicEntityAmmoCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBasicEntityInit(EntityUid uid, BasicEntityAmmoProviderComponent component, ComponentInit args)
|
private void OnBasicEntityMapInit(EntityUid uid, BasicEntityAmmoProviderComponent component, MapInitEvent args)
|
||||||
{
|
{
|
||||||
if (component.Count is null)
|
if (component.Count is null)
|
||||||
{
|
{
|
||||||
@@ -26,7 +26,7 @@ public abstract partial class SharedGunSystem
|
|||||||
|
|
||||||
private void OnBasicEntityTakeAmmo(EntityUid uid, BasicEntityAmmoProviderComponent component, TakeAmmoEvent args)
|
private void OnBasicEntityTakeAmmo(EntityUid uid, BasicEntityAmmoProviderComponent component, TakeAmmoEvent args)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < args.Shots; i++)
|
for (var i = 0; i < args.Shots; i++)
|
||||||
{
|
{
|
||||||
if (component.Count <= 0)
|
if (component.Count <= 0)
|
||||||
return;
|
return;
|
||||||
@@ -40,6 +40,7 @@ public abstract partial class SharedGunSystem
|
|||||||
args.Ammo.Add((ent, EnsureComp<AmmoComponent>(ent)));
|
args.Ammo.Add((ent, EnsureComp<AmmoComponent>(ent)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_recharge.Reset(uid);
|
||||||
UpdateBasicEntityAppearance(uid, component);
|
UpdateBasicEntityAppearance(uid, component);
|
||||||
Dirty(component);
|
Dirty(component);
|
||||||
}
|
}
|
||||||
@@ -73,6 +74,7 @@ public abstract partial class SharedGunSystem
|
|||||||
component.Count = count;
|
component.Count = count;
|
||||||
Dirty(component);
|
Dirty(component);
|
||||||
UpdateBasicEntityAppearance(uid, component);
|
UpdateBasicEntityAppearance(uid, component);
|
||||||
|
UpdateAmmoCount(uid);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
|||||||
[Dependency] protected readonly DamageableSystem Damageable = default!;
|
[Dependency] protected readonly DamageableSystem Damageable = default!;
|
||||||
[Dependency] protected readonly ExamineSystemShared Examine = default!;
|
[Dependency] protected readonly ExamineSystemShared Examine = default!;
|
||||||
[Dependency] private readonly ItemSlotsSystem _slots = default!;
|
[Dependency] private readonly ItemSlotsSystem _slots = default!;
|
||||||
|
[Dependency] private readonly RechargeBasicEntityAmmoSystem _recharge = default!;
|
||||||
[Dependency] protected readonly SharedActionsSystem Actions = default!;
|
[Dependency] protected readonly SharedActionsSystem Actions = default!;
|
||||||
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
||||||
[Dependency] private readonly SharedCombatModeSystem _combatMode = default!;
|
[Dependency] private readonly SharedCombatModeSystem _combatMode = default!;
|
||||||
@@ -243,6 +244,9 @@ public abstract partial class SharedGunSystem : EntitySystem
|
|||||||
shots++;
|
shots++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NextFire has been touched regardless so need to dirty the gun.
|
||||||
|
Dirty(gun);
|
||||||
|
|
||||||
// Get how many shots we're actually allowed to make, due to clip size or otherwise.
|
// Get how many shots we're actually allowed to make, due to clip size or otherwise.
|
||||||
// Don't do this in the loop so we still reset NextFire.
|
// Don't do this in the loop so we still reset NextFire.
|
||||||
switch (gun.SelectedMode)
|
switch (gun.SelectedMode)
|
||||||
@@ -288,7 +292,6 @@ public abstract partial class SharedGunSystem : EntitySystem
|
|||||||
// May cause prediction issues? Needs more tweaking
|
// May cause prediction issues? Needs more tweaking
|
||||||
gun.NextFire = TimeSpan.FromSeconds(Math.Max(lastFire.TotalSeconds + SafetyNextFire, gun.NextFire.TotalSeconds));
|
gun.NextFire = TimeSpan.FromSeconds(Math.Max(lastFire.TotalSeconds + SafetyNextFire, gun.NextFire.TotalSeconds));
|
||||||
Audio.PlayPredicted(gun.SoundEmpty, gunUid, user);
|
Audio.PlayPredicted(gun.SoundEmpty, gunUid, user);
|
||||||
Dirty(gun);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
sprite: Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi
|
sprite: Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi
|
||||||
size: 30
|
size: 30
|
||||||
- type: Gun
|
- type: Gun
|
||||||
fireRate: 1
|
fireRate: 0.75
|
||||||
selectedMode: SemiAuto
|
selectedMode: SemiAuto
|
||||||
availableModes:
|
availableModes:
|
||||||
- SemiAuto
|
- SemiAuto
|
||||||
@@ -24,8 +24,7 @@
|
|||||||
True: { visible: False }
|
True: { visible: False }
|
||||||
False: { visible: True }
|
False: { visible: True }
|
||||||
- type: RechargeBasicEntityAmmo
|
- type: RechargeBasicEntityAmmo
|
||||||
minRechargeCooldown: 1.5
|
rechargeCooldown: 1
|
||||||
maxRechargeCooldown: 1.5
|
|
||||||
rechargeSound:
|
rechargeSound:
|
||||||
path: /Audio/Weapons/Guns/MagIn/kinetic_reload.ogg
|
path: /Audio/Weapons/Guns/MagIn/kinetic_reload.ogg
|
||||||
- type: BasicEntityAmmoProvider
|
- type: BasicEntityAmmoProvider
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
- type: AmmoCounter
|
- type: AmmoCounter
|
||||||
# All staves recharge. Wands are not.
|
# All staves recharge. Wands are not.
|
||||||
- type: RechargeBasicEntityAmmo
|
- type: RechargeBasicEntityAmmo
|
||||||
|
rechargeCooldown: 30
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- WizardStaff
|
- WizardStaff
|
||||||
|
|||||||
Reference in New Issue
Block a user