From d791d965702e7f1a376c58a75451a900adee1b04 Mon Sep 17 00:00:00 2001 From: deltanedas <@deltanedas:kde.org> Date: Sun, 22 Dec 2024 14:25:32 +0000 Subject: [PATCH 1/4] add mining voucher --- .../en-US/deltav/salvage/mining-voucher.ftl | 28 +++++++ .../DeltaV/Catalog/mining_voucher.yml | 70 ++++++++++++++++++ .../Objects/Specific/mining_voucher.yml | 21 ++++++ .../Specific/Salvage/voucher.rsi/icon.png | Bin 0 -> 532 bytes .../Specific/Salvage/voucher.rsi/meta.json | 14 ++++ 5 files changed, 133 insertions(+) create mode 100644 Resources/Locale/en-US/deltav/salvage/mining-voucher.ftl create mode 100644 Resources/Prototypes/DeltaV/Catalog/mining_voucher.yml create mode 100644 Resources/Prototypes/DeltaV/Entities/Objects/Specific/mining_voucher.yml create mode 100644 Resources/Textures/DeltaV/Objects/Specific/Salvage/voucher.rsi/icon.png create mode 100644 Resources/Textures/DeltaV/Objects/Specific/Salvage/voucher.rsi/meta.json diff --git a/Resources/Locale/en-US/deltav/salvage/mining-voucher.ftl b/Resources/Locale/en-US/deltav/salvage/mining-voucher.ftl new file mode 100644 index 00000000000..b88bbd43c0a --- /dev/null +++ b/Resources/Locale/en-US/deltav/salvage/mining-voucher.ftl @@ -0,0 +1,28 @@ +mining-voucher-crusher-name = Crusher Kit +mining-voucher-crusher-description = + Contains a kinetic crusher and a pocket fire extinguisher. + The crusher is a versatile melee mining tool capable both of mining and fighting local fauna, however it is difficult to use effectively for anyone but most skilled and/or suicidal miners. + +mining-voucher-extraction-name = Extraction and Rescue Kit +mining-voucher-extraction-description = + Contains a fulton beacon and 20 fultons, which allows you to send minerals, items and dead bodies back home without having to use the mining shuttle. +#And as a bonus, you get 30 marker beacons to help you better mark your path. + +mining-voucher-resonator-name = Resonator Kit +mining-voucher-resonator-description = + Contains a resonator and a pocket fire extinguisher. + The resonator is a handheld device that creates small fields of energy that resonate until they detonate, crushing rock. + It does increased damage in low pressure. + +mining-voucher-survival-name = Survival Capsule and Explorer's Webbing +mining-voucher-survival-description = + Contains an explorer's webbing, which allows you to carry even more mining equipment, and a spare shelter capsule to go with it. + +mining-voucher-minebot-name = Minebot Kit +mining-voucher-minebot-description = + Contains a little minebot companion that helps you in storing ore and hunting wildlife. + Also comes with an upgraded industrial welding tool, a welding mask and a KA modkit that allows shots to pass through the minebot. + +mining-voucher-conscription-name = Mining Conscription Kit +mining-voucher-conscription-description = + Contains a whole new mining starter kit for one crewmember, including a proto-kinetic accelerator, mineral scanner, ID card and other useful gear. diff --git a/Resources/Prototypes/DeltaV/Catalog/mining_voucher.yml b/Resources/Prototypes/DeltaV/Catalog/mining_voucher.yml new file mode 100644 index 00000000000..ac654f6cd29 --- /dev/null +++ b/Resources/Prototypes/DeltaV/Catalog/mining_voucher.yml @@ -0,0 +1,70 @@ +- type: thiefBackpackSet + id: MiningCrusher + name: mining-voucher-crusher-name + description: mining-voucher-crusher-description + sprite: + sprite: Objects/Weapons/Melee/crusher.rsi + state: icon + content: + - WeaponCrusher + - FireExtinguisherMini + +- type: thiefBackpackSet + id: MiningExtraction + name: mining-voucher-extraction-name + description: mining-voucher-extraction-description + sprite: + sprite: Objects/Tools/fulton.rsi + state: extraction_pack + content: + - Fulton + - Fulton + - FultonBeacon + # TODO: 30 marker beacons + +# TODO: resonator +#- type: thiefBackpackSet +# id: MiningResonator +# name: mining-voucher-resonator-name +# description: mining-voucher-resonator-description +# sprite: +# sprite: DeltaV/Objects/Weapons/Ranged/resonator.rsi +# state: icon +# content: +# - Resonator +# - FireExtinguisherMini + +# TODO: bluespace shelter capsule so this isnt a scam +#- type: thiefBackpackSet +# id: MiningSurvival +# name: mining-voucher-survival-name +# description: mining-voucher-survival-description +# sprite: +# sprite: Clothing/Belt/salvagewebbing.rsi +# state: icon +# content: +# - ClothingBeltSalvageWebbing + +# TODO: mining drone +#- type: thiefBackpackSet +# id: MiningDrone +# name: mining-voucher-minebot-name +# description: mining-voucher-minebot-description +# sprite: +# sprite: ... +# state: icon +# content: +# - mining drone... +# - WelderIndustrial +# - ClothingHeadHatWelding +# - drone passthrough ka modkit + +- type: thiefBackpackSet + id: MiningConscription + name: mining-voucher-conscription-name + description: mining-voucher-conscription-description + sprite: + sprite: Clothing/Back/Duffels/salvage.rsi + state: icon + content: + - ClothingBackpackDuffelSalvageConscription diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/mining_voucher.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/mining_voucher.yml new file mode 100644 index 00000000000..1288ad24e44 --- /dev/null +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/mining_voucher.yml @@ -0,0 +1,21 @@ +# TODO: use it on the vendor to redeem instead of teleporting gear into your hands lmao +- type: entity + parent: ToolboxThief + id: MiningVoucher + name: mining voucher + description: A token to redeem a piece of equipment. Bluespace delivery teleports it to you! + components: + - type: Sprite + sprite: DeltaV/Objects/Specific/Salvage/voucher.rsi + state: icon + - type: Item + size: Tiny + - type: ThiefUndeterminedBackpack + maxSelectedSets: 1 + possibleSets: + - MiningCrusher + - MiningExtraction + #- MiningResonator + #- MiningSurvival + #- MiningDrone + - MiningConscription diff --git a/Resources/Textures/DeltaV/Objects/Specific/Salvage/voucher.rsi/icon.png b/Resources/Textures/DeltaV/Objects/Specific/Salvage/voucher.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7609c5538bdd2b28e84dfb841504d566f2d10a7b GIT binary patch literal 532 zcmV+v0_**WP)F6XU=$2CaNxiJ6uz;F>VFWXm3>UaD3au4rP^yKFJ$K?=;9f0gp zWbpCvD+ohWnBkd`CdCe6BGvckj`$E2ljHypkXm^HO!Lc% zfibc}_<*7D!C8~!1j|B9@PmBsCKk=`>Hii6`Ag3j9v-{LaNSA??g)?rKv)wfF3-aO z#t*;zV1PN|?48?;6emJw0cjwa&an5xQ=kQ?4uJuX#V`O9XMFvZ!I*&o78;C1IRNBh zf0EewnrVFrP{*GWr+AV22q=w!fX3~Q3^#yuH-jRW zFL3EP&U8R>zJ)~%xAIEs0siT Wsq8b_6#xAI0000Nu* literal 0 HcmV?d00001 diff --git a/Resources/Textures/DeltaV/Objects/Specific/Salvage/voucher.rsi/meta.json b/Resources/Textures/DeltaV/Objects/Specific/Salvage/voucher.rsi/meta.json new file mode 100644 index 00000000000..9f0adf9de70 --- /dev/null +++ b/Resources/Textures/DeltaV/Objects/Specific/Salvage/voucher.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/0c2ef51b146affd639db68e71b3576cf83ff3f0f/icons/obj/mining.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + } + ] +} From 0eba78a2fa4e9480163e60812d3462eaa1bfce38 Mon Sep 17 00:00:00 2001 From: deltanedas <@deltanedas:kde.org> Date: Sun, 22 Dec 2024 14:25:34 +0000 Subject: [PATCH 2/4] give salvs a mining voucher --- .../Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml b/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml index 83f1ec96111..910fc6937ce 100644 --- a/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml +++ b/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml @@ -25,6 +25,6 @@ jumpsuit: ClothingUniformJumpsuitSalvageSpecialist #id: SalvagePDA # DeltaV: different PDAs in loadouts ears: ClothingHeadsetCargo - #storage: - #back: - #- Stuff + storage: # DeltaV: Add mining voucher + back: + - MiningVoucher From ebe926e67bb5d9fc594eac25109786cb8e9a96ec Mon Sep 17 00:00:00 2001 From: deltanedas <@deltanedas:kde.org> Date: Sun, 22 Dec 2024 15:44:11 +0000 Subject: [PATCH 3/4] add custom UI for it --- .../UI/MiningVoucherBoundUserInterface.cs | 27 ++++++ .../DeltaV/Salvage/UI/MiningVoucherMenu.xaml | 10 +++ .../Salvage/UI/MiningVoucherMenu.xaml.cs | 59 +++++++++++++ .../Components/MiningVoucherComponent.cs | 40 +++++++++ .../DeltaV/Salvage/MiningVoucherUI.cs | 18 ++++ .../Salvage/Systems/MiningVoucherSystem.cs | 83 +++++++++++++++++++ .../en-US/deltav/salvage/mining-voucher.ftl | 16 +++- .../Objects/Specific/mining_voucher.yml | 19 +++-- 8 files changed, 262 insertions(+), 10 deletions(-) create mode 100644 Content.Client/DeltaV/Salvage/UI/MiningVoucherBoundUserInterface.cs create mode 100644 Content.Client/DeltaV/Salvage/UI/MiningVoucherMenu.xaml create mode 100644 Content.Client/DeltaV/Salvage/UI/MiningVoucherMenu.xaml.cs create mode 100644 Content.Shared/DeltaV/Salvage/Components/MiningVoucherComponent.cs create mode 100644 Content.Shared/DeltaV/Salvage/MiningVoucherUI.cs create mode 100644 Content.Shared/DeltaV/Salvage/Systems/MiningVoucherSystem.cs diff --git a/Content.Client/DeltaV/Salvage/UI/MiningVoucherBoundUserInterface.cs b/Content.Client/DeltaV/Salvage/UI/MiningVoucherBoundUserInterface.cs new file mode 100644 index 00000000000..342e9073760 --- /dev/null +++ b/Content.Client/DeltaV/Salvage/UI/MiningVoucherBoundUserInterface.cs @@ -0,0 +1,27 @@ +using Content.Shared.DeltaV.Salvage; +using Robust.Client.UserInterface; + +namespace Content.Client.DeltaV.Salvage.UI; + +public sealed class MiningVoucherBoundUserInterface : BoundUserInterface +{ + [ViewVariables] + private MiningVoucherMenu? _menu; + + public MiningVoucherBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + base.Open(); + + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); + _menu.OnSelected += i => + { + SendMessage(new MiningVoucherSelectMessage(i)); + Close(); + }; + } +} diff --git a/Content.Client/DeltaV/Salvage/UI/MiningVoucherMenu.xaml b/Content.Client/DeltaV/Salvage/UI/MiningVoucherMenu.xaml new file mode 100644 index 00000000000..d6115f9ed72 --- /dev/null +++ b/Content.Client/DeltaV/Salvage/UI/MiningVoucherMenu.xaml @@ -0,0 +1,10 @@ + + + + diff --git a/Content.Client/DeltaV/Salvage/UI/MiningVoucherMenu.xaml.cs b/Content.Client/DeltaV/Salvage/UI/MiningVoucherMenu.xaml.cs new file mode 100644 index 00000000000..35b08194110 --- /dev/null +++ b/Content.Client/DeltaV/Salvage/UI/MiningVoucherMenu.xaml.cs @@ -0,0 +1,59 @@ +using Content.Client.UserInterface.Controls; +using Content.Shared.DeltaV.Salvage.Components; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; +using System.Numerics; + +namespace Content.Client.DeltaV.Salvage.UI; + +[GenerateTypedNameReferences] +public sealed partial class MiningVoucherMenu : RadialMenu +{ + [Dependency] private readonly IEntityManager _entMan = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + + private readonly SpriteSystem _sprite; + + public event Action? OnSelected; + + public MiningVoucherMenu() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + _sprite = _entMan.System(); + } + + public void SetEntity(EntityUid owner) + { + if (!_entMan.TryGetComponent(owner, out var comp)) + return; + + for (int i = 0; i < comp.Kits.Count; i++) + { + var index = i; // copy so the closure doesn't borrow it + var kit = _proto.Index(comp.Kits[i]); + var button = new RadialMenuTextureButton() + { + StyleClasses = { "RadialMenuButton" }, + SetSize = new Vector2(64f, 64f), + ToolTip = Loc.GetString(kit.Description) + }; + button.AddChild(new TextureRect() + { + VerticalAlignment = VAlignment.Center, + HorizontalAlignment = HAlignment.Center, + Texture = _sprite.Frame0(kit.Sprite), + TextureScale = new Vector2(2f, 2f) + }); + + button.OnPressed += _ => OnSelected?.Invoke(index); + + Main.AddChild(button); + } + } +} diff --git a/Content.Shared/DeltaV/Salvage/Components/MiningVoucherComponent.cs b/Content.Shared/DeltaV/Salvage/Components/MiningVoucherComponent.cs new file mode 100644 index 00000000000..3198bea7a01 --- /dev/null +++ b/Content.Shared/DeltaV/Salvage/Components/MiningVoucherComponent.cs @@ -0,0 +1,40 @@ +using Content.Shared.DeltaV.Salvage.Systems; +using Content.Shared.Thief; +using Content.Shared.Whitelist; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.DeltaV.Salvage.Components; + +/// +/// Thief toolbox except it uses a radial menu and has to be redeemed at the salvage vendor. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(MiningVoucherSystem))] +[AutoGenerateComponentState] +public sealed partial class MiningVoucherComponent : Component +{ + /// + /// Vendor must match this whitelist to be redeemed. + /// + [DataField(required: true)] + public EntityWhitelist VendorWhitelist; + + /// + /// The kits that can be selected. + /// + [DataField(required: true)] + public List> Kits = new(); + + /// + /// The index of the selected kit. + /// + [DataField, AutoNetworkedField] + public int? Selected; + + /// + /// Sound to play when redeeming the voucher. + /// + [DataField] + public SoundSpecifier? RedeemSound = new SoundPathSpecifier("/Audio/Machines/twobeep.ogg"); +} diff --git a/Content.Shared/DeltaV/Salvage/MiningVoucherUI.cs b/Content.Shared/DeltaV/Salvage/MiningVoucherUI.cs new file mode 100644 index 00000000000..a9591a12e13 --- /dev/null +++ b/Content.Shared/DeltaV/Salvage/MiningVoucherUI.cs @@ -0,0 +1,18 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.DeltaV.Salvage; + +/// +/// Message for a mining voucher kit to be selected. +/// +[Serializable, NetSerializable] +public sealed class MiningVoucherSelectMessage(int index) : BoundUserInterfaceMessage +{ + public readonly int Index = index; +} + +[Serializable, NetSerializable] +public enum MiningVoucherUiKey : byte +{ + Key +} diff --git a/Content.Shared/DeltaV/Salvage/Systems/MiningVoucherSystem.cs b/Content.Shared/DeltaV/Salvage/Systems/MiningVoucherSystem.cs new file mode 100644 index 00000000000..b5d5a00472d --- /dev/null +++ b/Content.Shared/DeltaV/Salvage/Systems/MiningVoucherSystem.cs @@ -0,0 +1,83 @@ +using Content.Shared.DeltaV.Salvage.Components; +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Power.EntitySystems; +using Content.Shared.Whitelist; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; + +namespace Content.Shared.DeltaV.Salvage.Systems; + +public sealed class MiningVoucherSystem : EntitySystem +{ + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedPowerReceiverSystem _power = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAfterInteract); + Subs.BuiEvents(MiningVoucherUiKey.Key, subs => + { + subs.Event(OnSelect); + }); + } + + private void OnAfterInteract(Entity ent, ref AfterInteractEvent args) + { + if (args.Target is not {} target) + return; + + if (_whitelist.IsWhitelistFail(ent.Comp.VendorWhitelist, target)) + return; + + var user = args.User; + args.Handled = true; + + if (ent.Comp.Selected is not {} index) + { + _popup.PopupClient(Loc.GetString("mining-voucher-select-first"), target, user); + return; + } + + if (!_power.IsPowered(target)) + { + _popup.PopupClient(Loc.GetString("mining-voucher-vendor-unpowered", ("vendor", target)), target, user); + return; + } + + _audio.PlayPvs(ent.Comp.RedeemSound, target); + Redeem(ent, index, user); + } + + private void OnSelect(Entity ent, ref MiningVoucherSelectMessage args) + { + var index = args.Index; + if (index < 0 || index >= ent.Comp.Kits.Count) + return; + + var user = args.Actor; + var kit = _proto.Index(ent.Comp.Kits[index]); + var name = Loc.GetString(kit.Name); + _popup.PopupEntity(Loc.GetString("mining-voucher-selected", ("kit", name)), user, user); + + ent.Comp.Selected = index; + Dirty(ent); + } + + public void Redeem(Entity ent, int index, EntityUid user) + { + var kit = _proto.Index(ent.Comp.Kits[index]); + var xform = Transform(ent); + foreach (var id in kit.Content) + { + SpawnNextToOrDrop(id, ent, xform); + } + + QueueDel(ent); + } +} diff --git a/Resources/Locale/en-US/deltav/salvage/mining-voucher.ftl b/Resources/Locale/en-US/deltav/salvage/mining-voucher.ftl index b88bbd43c0a..d7ce62957fd 100644 --- a/Resources/Locale/en-US/deltav/salvage/mining-voucher.ftl +++ b/Resources/Locale/en-US/deltav/salvage/mining-voucher.ftl @@ -1,17 +1,24 @@ +mining-voucher-select-first = Select a kit to redeem first! +mining-voucher-unpowered = {CAPITALIZE(THE($vendor))} is unpowered! +mining-voucher-selected = Selected {$kit}! + mining-voucher-crusher-name = Crusher Kit mining-voucher-crusher-description = Contains a kinetic crusher and a pocket fire extinguisher. - The crusher is a versatile melee mining tool capable both of mining and fighting local fauna, however it is difficult to use effectively for anyone but most skilled and/or suicidal miners. + The crusher is a versatile melee mining tool capable both of mining and fighting local fauna. + However, it is difficult to use effectively for anyone but most skilled and/or suicidal miners. mining-voucher-extraction-name = Extraction and Rescue Kit mining-voucher-extraction-description = - Contains a fulton beacon and 20 fultons, which allows you to send minerals, items and dead bodies back home without having to use the mining shuttle. + Contains a fulton beacon and 20 fultons, which allows you to send minerals, + items and dead bodies back home without having to use the mining shuttle. #And as a bonus, you get 30 marker beacons to help you better mark your path. mining-voucher-resonator-name = Resonator Kit mining-voucher-resonator-description = Contains a resonator and a pocket fire extinguisher. - The resonator is a handheld device that creates small fields of energy that resonate until they detonate, crushing rock. + The resonator is a handheld device that creates small fields + of energy that resonate until they detonate, crushing rock. It does increased damage in low pressure. mining-voucher-survival-name = Survival Capsule and Explorer's Webbing @@ -25,4 +32,5 @@ mining-voucher-minebot-description = mining-voucher-conscription-name = Mining Conscription Kit mining-voucher-conscription-description = - Contains a whole new mining starter kit for one crewmember, including a proto-kinetic accelerator, mineral scanner, ID card and other useful gear. + Contains a whole new mining starter kit for one crewmember, including + a proto-kinetic accelerator, mineral scanner, ID card and other useful gear. diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/mining_voucher.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/mining_voucher.yml index 1288ad24e44..d63a3b4e6ad 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/mining_voucher.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/mining_voucher.yml @@ -1,18 +1,25 @@ -# TODO: use it on the vendor to redeem instead of teleporting gear into your hands lmao - type: entity - parent: ToolboxThief + parent: BaseItem id: MiningVoucher name: mining voucher - description: A token to redeem a piece of equipment. Bluespace delivery teleports it to you! + description: A token to redeem a piece of equipment. Insert into your salvage vendor to redeem it. components: - type: Sprite sprite: DeltaV/Objects/Specific/Salvage/voucher.rsi state: icon - type: Item size: Tiny - - type: ThiefUndeterminedBackpack - maxSelectedSets: 1 - possibleSets: + - type: ActivatableUI + key: enum.MiningVoucherUiKey.Key + - type: UserInterface + interfaces: + enum.MiningVoucherUiKey.Key: + type: MiningVoucherBoundUserInterface + - type: MiningVoucher + vendorWhitelist: # it's the only mining points vendor :) + components: + - PointsVendor + kits: - MiningCrusher - MiningExtraction #- MiningResonator From 3cf41ef3c842afccba153377d7c5392ccf0f8b94 Mon Sep 17 00:00:00 2001 From: deltanedas <@deltanedas:kde.org> Date: Sun, 22 Dec 2024 15:57:52 +0000 Subject: [PATCH 4/4] predict redeeming properly --- .../DeltaV/Salvage/Systems/MiningVoucherSystem.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Content.Shared/DeltaV/Salvage/Systems/MiningVoucherSystem.cs b/Content.Shared/DeltaV/Salvage/Systems/MiningVoucherSystem.cs index b5d5a00472d..30b44eef493 100644 --- a/Content.Shared/DeltaV/Salvage/Systems/MiningVoucherSystem.cs +++ b/Content.Shared/DeltaV/Salvage/Systems/MiningVoucherSystem.cs @@ -4,13 +4,17 @@ using Content.Shared.Power.EntitySystems; using Content.Shared.Whitelist; using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; using Robust.Shared.Prototypes; +using Robust.Shared.Timing; namespace Content.Shared.DeltaV.Salvage.Systems; public sealed class MiningVoucherSystem : EntitySystem { [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; @@ -50,7 +54,10 @@ private void OnAfterInteract(Entity ent, ref AfterIntera return; } - _audio.PlayPvs(ent.Comp.RedeemSound, target); + if (!_timing.IsFirstTimePredicted) + return; + + _audio.PlayPredicted(ent.Comp.RedeemSound, target, user); Redeem(ent, index, user); } @@ -71,6 +78,9 @@ private void OnSelect(Entity ent, ref MiningVoucherSelec public void Redeem(Entity ent, int index, EntityUid user) { + if (_net.IsClient) + return; + var kit = _proto.Index(ent.Comp.Kits[index]); var xform = Transform(ent); foreach (var id in kit.Content)