using Content.Shared.Cargo;
using Content.Shared.Damage;
using Content.Shared.Destructible;
-using Content.Shared.DoAfter;
using Content.Shared.Emp;
-using Content.Shared.IdentityManagement;
-using Content.Shared.Popups;
using Content.Shared.Power;
using Content.Shared.Throwing;
using Content.Shared.UserInterface;
using Content.Shared.VendingMachines;
using Content.Shared.Wall;
-using Robust.Shared.Audio;
-using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
-using Robust.Shared.Timing;
namespace Content.Server.VendingMachines
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly PricingSystem _pricing = default!;
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
- [Dependency] private readonly IGameTiming _timing = default!;
private const float WallVendEjectDistanceFromWall = 1f;
SubscribeLocalEvent<VendingMachineComponent, TryVocalizeEvent>(OnTryVocalize);
SubscribeLocalEvent<VendingMachineComponent, ActivatableUIOpenAttemptEvent>(OnActivatableUIOpenAttempt);
-
SubscribeLocalEvent<VendingMachineComponent, VendingMachineSelfDispenseEvent>(OnSelfDispense);
- SubscribeLocalEvent<VendingMachineComponent, RestockDoAfterEvent>(OnDoAfter);
-
SubscribeLocalEvent<VendingMachineRestockComponent, PriceCalculationEvent>(OnPriceCalculation);
}
EjectRandom(uid, throwItem: true, forceEject: false, component);
}
- private void OnDoAfter(EntityUid uid, VendingMachineComponent component, DoAfterEvent args)
- {
- if (args.Handled || args.Cancelled || args.Args.Used == null)
- return;
-
- if (!TryComp<VendingMachineRestockComponent>(args.Args.Used, out var restockComponent))
- {
- Log.Error($"{ToPrettyString(args.Args.User)} tried to restock {ToPrettyString(uid)} with {ToPrettyString(args.Args.Used.Value)} which did not have a VendingMachineRestockComponent.");
- return;
- }
-
- TryRestockInventory(uid, component);
-
- Popup.PopupEntity(Loc.GetString("vending-machine-restock-done-self", ("target", uid)), args.Args.User, args.Args.User, PopupType.Medium);
- var othersFilter = Filter.PvsExcept(args.Args.User);
- Popup.PopupEntity(Loc.GetString("vending-machine-restock-done-others", ("user", Identity.Entity(args.User, EntityManager)), ("target", uid)), args.Args.User, othersFilter, true, PopupType.Medium);
-
- Audio.PlayPvs(restockComponent.SoundRestockDone, uid, AudioParams.Default.WithVolume(-2f).WithVariation(0.2f));
-
- Del(args.Args.Used.Value);
-
- args.Handled = true;
- }
-
/// <summary>
/// Sets the <see cref="VendingMachineComponent.CanShoot"/> property of the vending machine.
/// </summary>
var disabled = EntityQueryEnumerator<EmpDisabledComponent, VendingMachineComponent>();
while (disabled.MoveNext(out var uid, out _, out var comp))
{
- if (comp.NextEmpEject < _timing.CurTime)
+ if (comp.NextEmpEject < Timing.CurTime)
{
EjectRandom(uid, true, false, comp);
comp.NextEmpEject += (5 * comp.EjectDelay);
}
}
- public void TryRestockInventory(EntityUid uid, VendingMachineComponent? vendComponent = null)
- {
- if (!Resolve(uid, ref vendComponent))
- return;
-
- RestockInventoryFromPrototype(uid, vendComponent);
-
- Dirty(uid, vendComponent);
- TryUpdateVisualState((uid, vendComponent));
- }
-
private void OnPriceCalculation(EntityUid uid, VendingMachineRestockComponent component, ref PriceCalculationEvent args)
{
List<double> priceSets = new();
{
args.Affected = true;
args.Disabled = true;
- component.NextEmpEject = _timing.CurTime;
+ component.NextEmpEject = Timing.CurTime;
}
}
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Wires;
-using Robust.Shared.Audio;
namespace Content.Shared.VendingMachines;
return true;
}
+ public void TryRestockInventory(EntityUid uid, VendingMachineComponent? vendComponent = null)
+ {
+ if (!Resolve(uid, ref vendComponent))
+ return;
+
+ RestockInventoryFromPrototype(uid, vendComponent);
+
+ Dirty(uid, vendComponent);
+ TryUpdateVisualState((uid, vendComponent));
+ }
+
private void OnAfterInteract(EntityUid uid, VendingMachineRestockComponent component, AfterInteractEvent args)
{
if (args.Target is not { } target || !args.CanReach || args.Handled)
args.Handled = true;
- var doAfterArgs = new DoAfterArgs(EntityManager, args.User, (float)component.RestockDelay.TotalSeconds, new RestockDoAfterEvent(), target,
- target: target, used: uid)
+ var doAfterArgs = new DoAfterArgs(EntityManager,
+ args.User,
+ component.RestockDelay,
+ new RestockDoAfterEvent(),
+ target,
+ target: target,
+ used: uid)
{
BreakOnMove = true,
BreakOnDamage = true,
return;
var selfMessage = Loc.GetString("vending-machine-restock-start-self", ("target", target));
- var othersMessage = Loc.GetString("vending-machine-restock-start-others", ("user", Identity.Entity(args.User, EntityManager)), ("target", target));
- Popup.PopupPredicted(selfMessage,
- othersMessage,
- uid,
- args.User,
- PopupType.Medium);
+ var othersMessage = Loc.GetString("vending-machine-restock-start-others",
+ ("user", Identity.Entity(args.User, EntityManager)),
+ ("target", target));
+ Popup.PopupPredicted(selfMessage, othersMessage, target, args.User, PopupType.Medium);
+
+
+ if (!Timing.IsFirstTimePredicted)
+ return;
+
+ Audio.Stop(machineComponent.RestockStream);
+ machineComponent.RestockStream = Audio.PlayPredicted(component.SoundRestockStart, target, args.User)?.Entity;
+ }
+
+ private void OnRestockDoAfter(Entity<VendingMachineComponent> ent, ref RestockDoAfterEvent args)
+ {
+ if (args.Cancelled)
+ {
+ // Future predicted ticks can clobber the RestockStream with null while not stopping anything
+ if (Timing.IsFirstTimePredicted)
+ ent.Comp.RestockStream = Audio.Stop(ent.Comp.RestockStream);
+ return;
+ }
+
+ if (args.Handled || args.Used == null)
+ return;
+
+ if (!TryComp<VendingMachineRestockComponent>(args.Used, out var restockComponent))
+ {
+ Log.Error($"{ToPrettyString(args.User)} tried to restock {ToPrettyString(ent)} with {ToPrettyString(args.Used.Value)} which did not have a VendingMachineRestockComponent.");
+ return;
+ }
+
+ TryRestockInventory(ent, ent.Comp);
+
+ var userMessage = Loc.GetString("vending-machine-restock-done-self", ("target", ent));
+ var othersMessage = Loc.GetString("vending-machine-restock-done-others",
+ ("user", Identity.Entity(args.User, EntityManager)),
+ ("target", ent));
+ Popup.PopupPredicted(userMessage, othersMessage, ent, args.User, PopupType.Medium);
+
+ Audio.PlayPredicted(restockComponent.SoundRestockDone, ent, args.User);
- Audio.PlayPredicted(component.SoundRestockStart, uid, args.User);
+ PredictedQueueDel(args.Used.Value);
}
}
SubscribeLocalEvent<VendingMachineComponent, ComponentGetState>(OnVendingGetState);
SubscribeLocalEvent<VendingMachineComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<VendingMachineComponent, GotEmaggedEvent>(OnEmagged);
+ SubscribeLocalEvent<VendingMachineComponent, RestockDoAfterEvent>(OnRestockDoAfter);
SubscribeLocalEvent<VendingMachineRestockComponent, AfterInteractEvent>(OnAfterInteract);
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
public TimeSpan NextEmpEject = TimeSpan.Zero;
+ /// <summary>
+ /// Audio entity used during restock in case the doafter gets canceled.
+ /// </summary>
+ [DataField]
+ public EntityUid? RestockStream;
+
#region Client Visuals
/// <summary>
/// RSI state for when the vending machine is unpowered.
/// <summary>
/// The time (in seconds) that it takes to restock a machine.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("restockDelay")]
+ [DataField]
public TimeSpan RestockDelay = TimeSpan.FromSeconds(5.0f);
/// <summary>
/// What sort of machine inventory does this restock?
/// This is checked against the VendingMachineComponent's pack value.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("canRestock", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<VendingMachineInventoryPrototype>))]
- public HashSet<string> CanRestock = new();
+ [DataField(customTypeSerializer: typeof(PrototypeIdHashSetSerializer<VendingMachineInventoryPrototype>))]
+ public HashSet<string> CanRestock = [];
/// <summary>
/// Sound that plays when starting to restock a machine.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("soundRestockStart")]
+ [DataField]
public SoundSpecifier SoundRestockStart = new SoundPathSpecifier("/Audio/Machines/vending_restock_start.ogg")
{
Params = new AudioParams
/// <summary>
/// Sound that plays when finished restocking a machine.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("soundRestockDone")]
- public SoundSpecifier SoundRestockDone = new SoundPathSpecifier("/Audio/Machines/vending_restock_done.ogg");
+ [DataField]
+ public SoundSpecifier SoundRestockDone = new SoundPathSpecifier("/Audio/Machines/vending_restock_done.ogg",
+ AudioParams.Default.WithVolume(-2f).WithVariation(0.2f));
}
[Serializable, NetSerializable]
-public sealed partial class RestockDoAfterEvent : SimpleDoAfterEvent
-{
-}
+public sealed partial class RestockDoAfterEvent : SimpleDoAfterEvent;