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..30b44eef493 --- /dev/null +++ b/Content.Shared/DeltaV/Salvage/Systems/MiningVoucherSystem.cs @@ -0,0 +1,93 @@ +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.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!; + [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; + } + + if (!_timing.IsFirstTimePredicted) + return; + + _audio.PlayPredicted(ent.Comp.RedeemSound, target, user); + 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) + { + if (_net.IsClient) + return; + + 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 new file mode 100644 index 00000000000..d7ce62957fd --- /dev/null +++ b/Resources/Locale/en-US/deltav/salvage/mining-voucher.ftl @@ -0,0 +1,36 @@ +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. + +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..d63a3b4e6ad --- /dev/null +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/mining_voucher.yml @@ -0,0 +1,28 @@ +- type: entity + parent: BaseItem + id: MiningVoucher + name: mining voucher + 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: 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 + #- MiningSurvival + #- MiningDrone + - MiningConscription 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 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 00000000000..7609c5538bd Binary files /dev/null and b/Resources/Textures/DeltaV/Objects/Specific/Salvage/voucher.rsi/icon.png differ 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" + } + ] +}