From afe588d506303993f0bfacb62f5d9050c70ca126 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Fri, 27 Dec 2024 03:06:17 +0000 Subject: [PATCH 1/9] salvage points shop (#2510) * add conscription bag * add gar mesons * remove salvage vendor restock * add code for shop vendors * make salvage vendor a shop vendor * ui fixes * :trollface: * update locker and vendor inventory * add mining hardsuit for 3k --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../VendingMachines/ShopVendorSystem.cs | 123 ++++++++++++ .../UI/ShopVendorBoundUserInterface.cs | 25 +++ .../VendingMachines/UI/ShopVendorItem.xaml | 13 ++ .../VendingMachines/UI/ShopVendorItem.xaml.cs | 21 ++ .../VendingMachines/UI/ShopVendorWindow.xaml | 24 +++ .../UI/ShopVendorWindow.xaml.cs | 147 ++++++++++++++ .../VendingMachines/ShopVendorSystem.cs | 47 +++++ .../VendingMachines/PointsVendorComponent.cs | 9 + .../VendingMachines/SharedShopVendorSystem.cs | 181 ++++++++++++++++++ .../VendingMachines/ShopInventoryPrototype.cs | 23 +++ .../VendingMachines/ShopVendorComponent.cs | 96 ++++++++++ .../DeltaV/VendingMachines/ShopVendorUI.cs | 9 + .../deltav/vending-machines/shop-vendor.ftl | 4 + Resources/Migrations/deltaMigrations.yml | 3 + .../Catalog/Cargo/cargo_vending.yml | 18 +- .../Catalog/Fills/Crates/vending.yml | 18 +- .../VendingMachines/Inventories/salvage.yml | 8 +- .../Fills/Items/Backpacks/duffelbag.yml | 18 ++ .../DeltaV/Catalog/Fills/Lockers/cargo.yml | 7 +- .../Inventories/salvage_points.yml | 53 +++++ .../DeltaV/Entities/Clothing/Eyes/glasses.yml | 8 + Resources/Prototypes/DeltaV/Wires/layouts.yml | 8 + .../Objects/Specific/Salvage/ore_bag.yml | 2 +- .../Service/vending_machine_restock.yml | 1 + .../Structures/Machines/vending_machines.yml | 27 ++- 25 files changed, 860 insertions(+), 33 deletions(-) create mode 100644 Content.Client/DeltaV/VendingMachines/ShopVendorSystem.cs create mode 100644 Content.Client/DeltaV/VendingMachines/UI/ShopVendorBoundUserInterface.cs create mode 100644 Content.Client/DeltaV/VendingMachines/UI/ShopVendorItem.xaml create mode 100644 Content.Client/DeltaV/VendingMachines/UI/ShopVendorItem.xaml.cs create mode 100644 Content.Client/DeltaV/VendingMachines/UI/ShopVendorWindow.xaml create mode 100644 Content.Client/DeltaV/VendingMachines/UI/ShopVendorWindow.xaml.cs create mode 100644 Content.Server/DeltaV/VendingMachines/ShopVendorSystem.cs create mode 100644 Content.Shared/DeltaV/VendingMachines/PointsVendorComponent.cs create mode 100644 Content.Shared/DeltaV/VendingMachines/SharedShopVendorSystem.cs create mode 100644 Content.Shared/DeltaV/VendingMachines/ShopInventoryPrototype.cs create mode 100644 Content.Shared/DeltaV/VendingMachines/ShopVendorComponent.cs create mode 100644 Content.Shared/DeltaV/VendingMachines/ShopVendorUI.cs create mode 100644 Resources/Locale/en-US/deltav/vending-machines/shop-vendor.ftl create mode 100644 Resources/Prototypes/DeltaV/Catalog/Fills/Items/Backpacks/duffelbag.yml create mode 100644 Resources/Prototypes/DeltaV/Catalog/VendingMachines/Inventories/salvage_points.yml diff --git a/Content.Client/DeltaV/VendingMachines/ShopVendorSystem.cs b/Content.Client/DeltaV/VendingMachines/ShopVendorSystem.cs new file mode 100644 index 00000000000..3b7f5744421 --- /dev/null +++ b/Content.Client/DeltaV/VendingMachines/ShopVendorSystem.cs @@ -0,0 +1,123 @@ +using Content.Shared.DeltaV.VendingMachines; +using Content.Shared.VendingMachines; +using Robust.Client.Animations; +using Robust.Client.GameObjects; + +namespace Content.Client.DeltaV.VendingMachines; + +public sealed class ShopVendorSystem : SharedShopVendorSystem +{ + [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!; + [Dependency] private readonly AppearanceSystem _appearance = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAppearanceChange); + SubscribeLocalEvent(OnAnimationCompleted); + } + + // copied from vending machines because its not reusable in other systems :) + private void OnAnimationCompleted(Entity ent, ref AnimationCompletedEvent args) + { + UpdateAppearance((ent, ent.Comp)); + } + + private void OnAppearanceChange(Entity ent, ref AppearanceChangeEvent args) + { + UpdateAppearance((ent, ent.Comp, args.Sprite)); + } + + private void UpdateAppearance(Entity ent) + { + if (!Resolve(ent, ref ent.Comp2)) + return; + + if (!_appearance.TryGetData(ent, VendingMachineVisuals.VisualState, out var state)) + state = VendingMachineVisualState.Normal; + + var sprite = ent.Comp2; + SetLayerState(VendingMachineVisualLayers.Base, ent.Comp1.OffState, sprite); + SetLayerState(VendingMachineVisualLayers.Screen, ent.Comp1.ScreenState, sprite); + switch (state) + { + case VendingMachineVisualState.Normal: + SetLayerState(VendingMachineVisualLayers.BaseUnshaded, ent.Comp1.NormalState, sprite); + break; + + case VendingMachineVisualState.Deny: + if (ent.Comp1.LoopDenyAnimation) + SetLayerState(VendingMachineVisualLayers.BaseUnshaded, ent.Comp1.DenyState, sprite); + else + PlayAnimation(ent, VendingMachineVisualLayers.BaseUnshaded, ent.Comp1.DenyState, ent.Comp1.DenyDelay, sprite); + break; + + case VendingMachineVisualState.Eject: + PlayAnimation(ent, VendingMachineVisualLayers.BaseUnshaded, ent.Comp1.EjectState, ent.Comp1.EjectDelay, sprite); + break; + + case VendingMachineVisualState.Broken: + HideLayers(sprite); + SetLayerState(VendingMachineVisualLayers.Base, ent.Comp1.BrokenState, sprite); + break; + + case VendingMachineVisualState.Off: + HideLayers(sprite); + break; + } + } + + private static void SetLayerState(VendingMachineVisualLayers layer, string? state, SpriteComponent sprite) + { + if (state == null) + return; + + sprite.LayerSetVisible(layer, true); + sprite.LayerSetAutoAnimated(layer, true); + sprite.LayerSetState(layer, state); + } + + private void PlayAnimation(EntityUid uid, VendingMachineVisualLayers layer, string? state, TimeSpan time, SpriteComponent sprite) + { + if (state == null || _animationPlayer.HasRunningAnimation(uid, state)) + return; + + var animation = GetAnimation(layer, state, time); + sprite.LayerSetVisible(layer, true); + _animationPlayer.Play(uid, animation, state); + } + + private static Animation GetAnimation(VendingMachineVisualLayers layer, string state, TimeSpan time) + { + return new Animation + { + Length = time, + AnimationTracks = + { + new AnimationTrackSpriteFlick + { + LayerKey = layer, + KeyFrames = + { + new AnimationTrackSpriteFlick.KeyFrame(state, 0f) + } + } + } + }; + } + + private static void HideLayers(SpriteComponent sprite) + { + HideLayer(VendingMachineVisualLayers.BaseUnshaded, sprite); + HideLayer(VendingMachineVisualLayers.Screen, sprite); + } + + private static void HideLayer(VendingMachineVisualLayers layer, SpriteComponent sprite) + { + if (!sprite.LayerMapTryGet(layer, out var actualLayer)) + return; + + sprite.LayerSetVisible(actualLayer, false); + } +} diff --git a/Content.Client/DeltaV/VendingMachines/UI/ShopVendorBoundUserInterface.cs b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorBoundUserInterface.cs new file mode 100644 index 00000000000..6122aa9ee1e --- /dev/null +++ b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorBoundUserInterface.cs @@ -0,0 +1,25 @@ +using Content.Shared.DeltaV.VendingMachines; +using Robust.Client.UserInterface; + +namespace Content.Client.DeltaV.VendingMachines.UI; + +public sealed class ShopVendorBoundUserInterface : BoundUserInterface +{ + [ViewVariables] + private ShopVendorWindow? _window; + + public ShopVendorBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + base.Open(); + + _window = this.CreateWindow(); + _window.SetEntity(Owner); + _window.OpenCenteredLeft(); + _window.Title = EntMan.GetComponent(Owner).EntityName; + _window.OnItemSelected += index => SendMessage(new ShopVendorPurchaseMessage(index)); + } +} diff --git a/Content.Client/DeltaV/VendingMachines/UI/ShopVendorItem.xaml b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorItem.xaml new file mode 100644 index 00000000000..4708db20aa9 --- /dev/null +++ b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorItem.xaml @@ -0,0 +1,13 @@ + + + diff --git a/Content.Client/DeltaV/VendingMachines/UI/ShopVendorItem.xaml.cs b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorItem.xaml.cs new file mode 100644 index 00000000000..4a3c9c4efe5 --- /dev/null +++ b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorItem.xaml.cs @@ -0,0 +1,21 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; + +namespace Content.Client.DeltaV.VendingMachines.UI; + +[GenerateTypedNameReferences] +public sealed partial class ShopVendorItem : BoxContainer +{ + public ShopVendorItem(EntProtoId entProto, string text, uint cost) + { + RobustXamlLoader.Load(this); + + ItemPrototype.SetPrototype(entProto); + + NameLabel.Text = text; + + CostLabel.Text = cost.ToString(); + } +} diff --git a/Content.Client/DeltaV/VendingMachines/UI/ShopVendorWindow.xaml b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorWindow.xaml new file mode 100644 index 00000000000..cfc7f4a4a2c --- /dev/null +++ b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorWindow.xaml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/Content.Client/DeltaV/VendingMachines/UI/ShopVendorWindow.xaml.cs b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorWindow.xaml.cs new file mode 100644 index 00000000000..2b9c4df87a0 --- /dev/null +++ b/Content.Client/DeltaV/VendingMachines/UI/ShopVendorWindow.xaml.cs @@ -0,0 +1,147 @@ +using Content.Client.UserInterface.Controls; +using Content.Shared.DeltaV.VendingMachines; +using Content.Shared.Stacks; +using Robust.Client.AutoGenerated; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using System.Numerics; + +namespace Content.Client.DeltaV.VendingMachines.UI; + +[GenerateTypedNameReferences] +public sealed partial class ShopVendorWindow : FancyWindow +{ + [Dependency] private readonly IComponentFactory _factory = default!; + [Dependency] private readonly IEntityManager _entMan = default!; + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + private readonly ShopVendorSystem _vendor; + + /// + /// Event fired with the listing index to purchase. + /// + public event Action? OnItemSelected; + + private EntityUid _owner; + private readonly StyleBoxFlat _style = new() { BackgroundColor = new Color(70, 73, 102) }; + private readonly StyleBoxFlat _styleBroke = new() { BackgroundColor = Color.FromHex("#303133") }; + private readonly List _buttons = new(); + private uint _balance = 1; + + public ShopVendorWindow() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + _vendor = _entMan.System(); + + VendingContents.SearchBar = SearchBar; + VendingContents.DataFilterCondition += DataFilterCondition; + VendingContents.GenerateItem += GenerateButton; + VendingContents.ItemKeyBindDown += (args, data) => OnItemSelected?.Invoke(((ShopVendorListingData) data).Index); + } + + public void SetEntity(EntityUid owner) + { + _owner = owner; + + if (!_entMan.TryGetComponent(owner, out var comp)) + return; + + var pack = _proto.Index(comp.Pack); + Populate(pack.Listings); + + UpdateBalance(); + } + + private void UpdateBalance(uint balance) + { + if (_balance == balance) + return; + + _balance = balance; + + BalanceLabel.Text = Loc.GetString("shop-vendor-balance", ("points", balance)); + + // disable items that are too expensive to buy + foreach (var button in _buttons) + { + if (button.Data is ShopVendorListingData data) + button.Disabled = data.Cost > balance; + + button.StyleBoxOverride = button.Disabled ? _styleBroke : _style; + } + } + + private void UpdateBalance() + { + if (_player.LocalEntity is {} user) + UpdateBalance(_vendor.GetBalance(_owner, user)); + } + + private bool DataFilterCondition(string filter, ListData data) + { + if (data is not ShopVendorListingData { Text: var text }) + return false; + + if (string.IsNullOrEmpty(filter)) + return true; + + return text.Contains(filter, StringComparison.CurrentCultureIgnoreCase); + } + + private void GenerateButton(ListData data, ListContainerButton button) + { + if (data is not ShopVendorListingData cast) + return; + + _buttons.Add(button); + button.AddChild(new ShopVendorItem(cast.ItemId, cast.Text, cast.Cost)); + + button.ToolTip = cast.Text; + button.Disabled = cast.Cost > _balance; + button.StyleBoxOverride = button.Disabled ? _styleBroke : _style; + } + + public void Populate(List listings) + { + var longestEntry = string.Empty; + var listData = new List(); + for (var i = 0; i < listings.Count; i++) + { + var listing = listings[i]; + var proto = _proto.Index(listing.Id); + var text = proto.Name; + if (proto.TryGetComponent(out var stack, _factory) && stack.Count > 1) + { + text += " "; + text += Loc.GetString("shop-vendor-stack-suffix", ("count", stack.Count)); + } + listData.Add(new ShopVendorListingData(i, listing.Id, text, listing.Cost)); + } + + _buttons.Clear(); + VendingContents.PopulateList(listData); + SetSizeAfterUpdate(longestEntry.Length, listings.Count); + } + + private void SetSizeAfterUpdate(int longestEntryLength, int contentCount) + { + SetSize = new Vector2(Math.Clamp((longestEntryLength + 2) * 12, 250, 400), + Math.Clamp(contentCount * 50, 150, 350)); + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + UpdateBalance(); + } +} + +public record ShopVendorListingData(int Index, EntProtoId ItemId, string Text, uint Cost) : ListData; diff --git a/Content.Server/DeltaV/VendingMachines/ShopVendorSystem.cs b/Content.Server/DeltaV/VendingMachines/ShopVendorSystem.cs new file mode 100644 index 00000000000..d3e99bfcf83 --- /dev/null +++ b/Content.Server/DeltaV/VendingMachines/ShopVendorSystem.cs @@ -0,0 +1,47 @@ +using Content.Server.Advertise; +using Content.Server.Advertise.Components; +using Content.Shared.DeltaV.VendingMachines; + +namespace Content.Server.DeltaV.VendingMachines; + +public sealed class ShopVendorSystem : SharedShopVendorSystem +{ + [Dependency] private readonly SpeakOnUIClosedSystem _speakOnUIClosed = default!; + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + var now = Timing.CurTime; + while (query.MoveNext(out var uid, out var comp, out var xform)) + { + var ent = (uid, comp); + var dirty = false; + if (comp.Ejecting is {} ejecting && now > comp.NextEject) + { + Spawn(ejecting, xform.Coordinates); + comp.Ejecting = null; + dirty = true; + } + + if (comp.Denying && now > comp.NextDeny) + { + comp.Denying = false; + dirty = true; + } + + if (dirty) + { + Dirty(uid, comp); + UpdateVisuals(ent); + } + } + } + + protected override void AfterPurchase(Entity ent) + { + if (TryComp(ent, out var speak)) + _speakOnUIClosed.TrySetFlag((ent.Owner, speak)); + } +} diff --git a/Content.Shared/DeltaV/VendingMachines/PointsVendorComponent.cs b/Content.Shared/DeltaV/VendingMachines/PointsVendorComponent.cs new file mode 100644 index 00000000000..d505215a469 --- /dev/null +++ b/Content.Shared/DeltaV/VendingMachines/PointsVendorComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.DeltaV.VendingMachines; + +/// +/// Makes a use mining points to buy items. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class PointsVendorComponent : Component; diff --git a/Content.Shared/DeltaV/VendingMachines/SharedShopVendorSystem.cs b/Content.Shared/DeltaV/VendingMachines/SharedShopVendorSystem.cs new file mode 100644 index 00000000000..464711c32ab --- /dev/null +++ b/Content.Shared/DeltaV/VendingMachines/SharedShopVendorSystem.cs @@ -0,0 +1,181 @@ +using Content.Shared.Access.Systems; +using Content.Shared.DeltaV.Salvage.Systems; +using Content.Shared.Destructible; +using Content.Shared.Popups; +using Content.Shared.Power; +using Content.Shared.Power.EntitySystems; +using Content.Shared.UserInterface; +using Content.Shared.VendingMachines; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Shared.DeltaV.VendingMachines; + +public abstract class SharedShopVendorSystem : EntitySystem +{ + [Dependency] private readonly AccessReaderSystem _access = default!; + [Dependency] private readonly MiningPointsSystem _points = default!; + [Dependency] protected readonly IGameTiming Timing = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPointLightSystem _light = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedPowerReceiverSystem _power = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnPointsBalance); + SubscribeLocalEvent(OnPointsPurchase); + + SubscribeLocalEvent(OnPowerChanged); + SubscribeLocalEvent(OnBreak); + SubscribeLocalEvent(OnOpenAttempt); + Subs.BuiEvents(VendingMachineUiKey.Key, subs => + { + subs.Event(OnPurchase); + }); + } + + #region Public API + + public uint GetBalance(EntityUid uid, EntityUid user) + { + var ev = new ShopVendorBalanceEvent(user); + RaiseLocalEvent(uid, ref ev); + return ev.Balance; + } + + #endregion + + #region Balance adapters + + private void OnPointsBalance(Entity ent, ref ShopVendorBalanceEvent args) + { + args.Balance = _points.TryFindIdCard(args.User)?.Comp?.Points ?? 0; + } + + private void OnPointsPurchase(Entity ent, ref ShopVendorPurchaseEvent args) + { + if (_points.TryFindIdCard(args.User) is {} idCard && _points.RemovePoints(idCard, args.Cost)) + args.Paid = true; + } + + #endregion + + private void OnPowerChanged(Entity ent, ref PowerChangedEvent args) + { + UpdateVisuals(ent); + } + + private void OnBreak(Entity ent, ref BreakageEventArgs args) + { + ent.Comp.Broken = true; + UpdateVisuals(ent); + } + + private void OnOpenAttempt(Entity ent, ref ActivatableUIOpenAttemptEvent args) + { + if (ent.Comp.Broken) + args.Cancel(); + } + + private void OnPurchase(Entity ent, ref ShopVendorPurchaseMessage args) + { + if (ent.Comp.Ejecting != null || ent.Comp.Broken || !_power.IsPowered(ent.Owner)) + return; + + var pack = _proto.Index(ent.Comp.Pack); + if (args.Index < 0 || args.Index >= pack.Listings.Count) + return; + + var user = args.Actor; + if (!_access.IsAllowed(user, ent)) + { + Deny(ent, user); + return; + } + + var listing = pack.Listings[args.Index]; + var ev = new ShopVendorPurchaseEvent(user, listing.Cost); + RaiseLocalEvent(ent, ref ev); + if (!ev.Paid) + { + Deny(ent, user); + return; + } + + ent.Comp.Ejecting = listing.Id; + ent.Comp.NextEject = Timing.CurTime + ent.Comp.EjectDelay; + Dirty(ent); + + _audio.PlayPvs(ent.Comp.PurchaseSound, ent); + UpdateVisuals(ent); + + Log.Debug($"Player {ToPrettyString(user):user} purchased {listing.Id} from {ToPrettyString(ent):vendor}"); + + AfterPurchase(ent); + } + + protected virtual void AfterPurchase(Entity ent) + { + } + + private void Deny(Entity ent, EntityUid user) + { + _popup.PopupClient(Loc.GetString("vending-machine-component-try-eject-access-denied"), ent, user); + if (ent.Comp.Denying) + return; + + ent.Comp.Denying = true; + ent.Comp.NextDeny = Timing.CurTime + ent.Comp.DenyDelay; + Dirty(ent); + + _audio.PlayPvs(ent.Comp.DenySound, ent); + UpdateVisuals(ent); + } + + protected void UpdateVisuals(Entity ent) + { + var state = VendingMachineVisualState.Normal; + var lit = true; + if (ent.Comp.Broken) + { + state = VendingMachineVisualState.Broken; + lit = false; + } + else if (ent.Comp.Ejecting != null) + { + state = VendingMachineVisualState.Eject; + } + else if (ent.Comp.Denying) + { + state = VendingMachineVisualState.Deny; + } + else if (!_power.IsPowered(ent.Owner)) + { + state = VendingMachineVisualState.Off; + lit = true; + } + + _light.SetEnabled(ent, lit); + _appearance.SetData(ent, VendingMachineVisuals.VisualState, state); + } +} + +/// +/// Raised on a shop vendor to get its current balance. +/// A currency component sets Balance to whatever it is. +/// +[ByRefEvent] +public record struct ShopVendorBalanceEvent(EntityUid User, uint Balance = 0); + +/// +/// Raised on a shop vendor when trying to purchase an item. +/// A currency component sets Paid to true if the user successfully paid for it. +/// +[ByRefEvent] +public record struct ShopVendorPurchaseEvent(EntityUid User, uint Cost, bool Paid = false); diff --git a/Content.Shared/DeltaV/VendingMachines/ShopInventoryPrototype.cs b/Content.Shared/DeltaV/VendingMachines/ShopInventoryPrototype.cs new file mode 100644 index 00000000000..3b04c0d0490 --- /dev/null +++ b/Content.Shared/DeltaV/VendingMachines/ShopInventoryPrototype.cs @@ -0,0 +1,23 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.DeltaV.VendingMachines; + +/// +/// Similar to VendingMachineInventoryPrototype but for . +/// +[Prototype] +public sealed class ShopInventoryPrototype : IPrototype +{ + [IdDataField] + public string ID { get; private set; } = default!; + + /// + /// The item listings for sale. + /// + [DataField(required: true)] + public List Listings = new(); +} + +[DataRecord, Serializable] +public record struct ShopListing(EntProtoId Id, uint Cost); diff --git a/Content.Shared/DeltaV/VendingMachines/ShopVendorComponent.cs b/Content.Shared/DeltaV/VendingMachines/ShopVendorComponent.cs new file mode 100644 index 00000000000..1de2c5476ed --- /dev/null +++ b/Content.Shared/DeltaV/VendingMachines/ShopVendorComponent.cs @@ -0,0 +1,96 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.DeltaV.VendingMachines; + +/// +/// A vending machine that sells items for a currency controlled by events. +/// Does not need restocking. +/// Another component must handle and to work. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(SharedShopVendorSystem))] +[AutoGenerateComponentState, AutoGenerateComponentPause] +public sealed partial class ShopVendorComponent : Component +{ + /// + /// The inventory prototype to sell. + /// + [DataField(required: true)] + public ProtoId Pack; + + [DataField, AutoNetworkedField] + public bool Broken; + + [DataField, AutoNetworkedField] + public bool Denying; + + /// + /// Item being ejected, or null if it isn't. + /// + [DataField, AutoNetworkedField] + public EntProtoId? Ejecting; + + /// + /// How long to wait before flashing denied again. + /// + [DataField] + public TimeSpan DenyDelay = TimeSpan.FromSeconds(2); + + /// + /// How long to wait before another item can be bought + /// + [DataField] + public TimeSpan EjectDelay = TimeSpan.FromSeconds(1.2); + + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextDeny; + + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextEject; + + [DataField] + public SoundSpecifier PurchaseSound = new SoundPathSpecifier("/Audio/Machines/machine_vend.ogg") + { + Params = new AudioParams + { + Volume = -4f, + Variation = 0.15f + } + }; + + [DataField] + public SoundSpecifier DenySound = new SoundPathSpecifier("/Audio/Machines/custom_deny.ogg") + { + Params = new AudioParams + { + Volume = -2f + } + }; + + #region Visuals + + [DataField] + public bool LoopDenyAnimation = true; + + [DataField] + public string? OffState; + + [DataField] + public string? ScreenState; + + [DataField] + public string? NormalState; + + [DataField] + public string? DenyState; + + [DataField] + public string? EjectState; + + [DataField] + public string? BrokenState; + + #endregion +} diff --git a/Content.Shared/DeltaV/VendingMachines/ShopVendorUI.cs b/Content.Shared/DeltaV/VendingMachines/ShopVendorUI.cs new file mode 100644 index 00000000000..9f288d9d322 --- /dev/null +++ b/Content.Shared/DeltaV/VendingMachines/ShopVendorUI.cs @@ -0,0 +1,9 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.DeltaV.VendingMachines; + +[Serializable, NetSerializable] +public sealed class ShopVendorPurchaseMessage(int index) : BoundUserInterfaceMessage +{ + public readonly int Index = index; +} diff --git a/Resources/Locale/en-US/deltav/vending-machines/shop-vendor.ftl b/Resources/Locale/en-US/deltav/vending-machines/shop-vendor.ftl new file mode 100644 index 00000000000..361d1dc71cb --- /dev/null +++ b/Resources/Locale/en-US/deltav/vending-machines/shop-vendor.ftl @@ -0,0 +1,4 @@ +shop-vendor-balance = Balance: {$points} +shop-vendor-stack-suffix = x{$count} +shop-vendor-flavor-left = All payments are secure +shop-vendor-flavor-right = v1.2 diff --git a/Resources/Migrations/deltaMigrations.yml b/Resources/Migrations/deltaMigrations.yml index 18a7472447d..d0c682215f9 100644 --- a/Resources/Migrations/deltaMigrations.yml +++ b/Resources/Migrations/deltaMigrations.yml @@ -128,3 +128,6 @@ SuitStorageSec: SuitStorageSecDeltaV LightBulbMaintenanceRed: DimLightBulb PoweredSmallLightMaintenanceRed: PoweredDimSmallLight AlwaysPoweredSmallLightMaintenanceRed: PoweredDimSmallLight + +# 2024-12-22 +VendingMachineRestockSalvageEquipment: null diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml index d43dc856f21..a3263dde32b 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml @@ -148,15 +148,15 @@ category: cargoproduct-category-name-service group: market -- type: cargoProduct - id: CrateVendingMachineRestockSalvageEquipment - icon: - sprite: Objects/Specific/Service/vending_machine_restock.rsi - state: base - product: CrateVendingMachineRestockSalvageEquipmentFilled - cost: 1000 - category: cargoproduct-category-name-engineering - group: market +#- type: cargoProduct # DeltaV: Salvage vendor doesn't have stock anymore +# id: CrateVendingMachineRestockSalvageEquipment +# icon: +# sprite: Objects/Specific/Service/vending_machine_restock.rsi +# state: base +# product: CrateVendingMachineRestockSalvageEquipmentFilled +# cost: 1000 +# category: cargoproduct-category-name-engineering +# group: market - type: cargoProduct id: CrateVendingMachineRestockSecTech diff --git a/Resources/Prototypes/Catalog/Fills/Crates/vending.yml b/Resources/Prototypes/Catalog/Fills/Crates/vending.yml index 378f8cb7588..606d538541e 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/vending.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/vending.yml @@ -140,15 +140,15 @@ - id: VendingMachineRestockRobustSoftdrinks amount: 2 -- type: entity - id: CrateVendingMachineRestockSalvageEquipmentFilled - parent: CrateGenericSteel - name: Salvage restock crate - description: Contains a restock box for the salvage vendor. - components: - - type: StorageFill - contents: - - id: VendingMachineRestockSalvageEquipment +#- type: entity # DeltaV: Salvage vendor doesn't have stock anymore +# id: CrateVendingMachineRestockSalvageEquipmentFilled +# parent: CrateGenericSteel +# name: Salvage restock crate +# description: Contains a restock box for the salvage vendor. +# components: +# - type: StorageFill +# contents: +# - id: VendingMachineRestockSalvageEquipment - type: entity id: CrateVendingMachineRestockSecTechFilled diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/salvage.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/salvage.yml index fc681630e66..7761453327a 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/salvage.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/salvage.yml @@ -3,14 +3,10 @@ startingInventory: Crowbar: 2 Pickaxe: 4 - OreBag: 4 # DeltaV - more ore bags, was 2 + OreBag: 4 Flare: 4 FlashlightLantern: 2 - Floodlight: 2 # DeltaV - upstream removed them HandheldGPSBasic: 2 RadioHandheld: 2 - #WeaponGrapplingGun: 2 # DeltaV - removed from vendor due to physics funkiness + WeaponGrapplingGun: 4 WeaponProtoKineticAccelerator: 4 - SeismicCharge: 2 # DeltaV - upstream removed - FultonBeacon: 1 # DeltaV - upstream removed - Fulton: 2 # DeltaV - upstream removed diff --git a/Resources/Prototypes/DeltaV/Catalog/Fills/Items/Backpacks/duffelbag.yml b/Resources/Prototypes/DeltaV/Catalog/Fills/Items/Backpacks/duffelbag.yml new file mode 100644 index 00000000000..eb0684b396f --- /dev/null +++ b/Resources/Prototypes/DeltaV/Catalog/Fills/Items/Backpacks/duffelbag.yml @@ -0,0 +1,18 @@ +- type: entity + parent: ClothingBackpackDuffelSalvage + id: ClothingBackpackDuffelSalvageConscription + name: mining conscription kit + description: A duffel bag containing everything a crewmember needs to support a shaft miner in the field. + components: + - type: StorageFill + contents: + - id: ClothingEyesGlassesMeson + - id: MineralScanner + - id: OreBag + - id: ClothingUniformJumpsuitSalvageSpecialist + - id: EncryptionKeyCargo + - id: ClothingMaskGasExplorer + - id: SalvageIDCard + - id: WeaponProtoKineticAccelerator + - id: SurvivalKnife + - id: FlashlightSeclite diff --git a/Resources/Prototypes/DeltaV/Catalog/Fills/Lockers/cargo.yml b/Resources/Prototypes/DeltaV/Catalog/Fills/Lockers/cargo.yml index 62f45b5aaf4..da266059d9c 100644 --- a/Resources/Prototypes/DeltaV/Catalog/Fills/Lockers/cargo.yml +++ b/Resources/Prototypes/DeltaV/Catalog/Fills/Lockers/cargo.yml @@ -3,9 +3,12 @@ id: LockerFillSalvageSpecialistDeltaV table: !type:AllSelector children: - - id: SeismicCharge - - id: SeismicCharge - id: OreBag + - id: Pickaxe + - id: WeaponProtoKineticAccelerator + - id: FlashlightSeclite + - id: ClothingEyesGlassesMeson + # TODO: bluespace shelter capsule - id: ClothingShoesBootsWinterMiner - id: JetpackMiniFilled # replaces fire extinguisher - id: ClothingNeckSalvager diff --git a/Resources/Prototypes/DeltaV/Catalog/VendingMachines/Inventories/salvage_points.yml b/Resources/Prototypes/DeltaV/Catalog/VendingMachines/Inventories/salvage_points.yml new file mode 100644 index 00000000000..c1558ca8e50 --- /dev/null +++ b/Resources/Prototypes/DeltaV/Catalog/VendingMachines/Inventories/salvage_points.yml @@ -0,0 +1,53 @@ +- type: shopInventory + id: SalvageVendorInventory + listings: + # TODO: marker beacons 1/10/30 for 10 each + - id: DrinkWhiskeyBottleFull + cost: 100 + - id: DrinkAbsintheBottleFull + cost: 100 + - id: CigarGold + cost: 150 + - id: Soap + cost: 200 + - id: SeismicCharge + cost: 250 + - id: WeaponGrapplingGun + cost: 300 + # TODO: laser pointer 300, toy facehugger 300 + # TODO: stabilizing serum for 400 + - id: FultonBeacon + cost: 400 + # TODO: bluespace shelter capsule for 400 + - id: ClothingEyesGlassesGarMeson + cost: 500 + - id: ClothingBeltSalvageWebbing + cost: 500 + - id: MedkitBruteFilled + cost: 600 + - id: MedkitBurnFilled + cost: 600 + # TODO: salvage 5g, 3 implants and a locator for 600 + # TODO: wormhole jaunter for 750 + - id: WeaponCrusher + cost: 750 + - id: WeaponProtoKineticAccelerator + cost: 750 + - id: AdvancedMineralScanner + cost: 800 + # TODO: resonator for 800 + - id: Fulton + cost: 1000 + # TODO: lazarus injector for 1k + - id: ClothingBackpackDuffelSalvageConscription + cost: 1500 + - id: SpaceCash1000 + cost: 2000 + # TODO: super resonator for 2500 + # TODO: jump boots for 2500 + - id: ClothingOuterHardsuitSalvage + cost: 3000 + # TODO: luxury shelter capsule for 3k + # TODO: luxury elite bar capsule for 10k + # TODO: pka mods + # TODO: mining drone stuff diff --git a/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/glasses.yml index 01fb7dadafd..bf7fc3cf3d0 100644 --- a/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/glasses.yml +++ b/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/glasses.yml @@ -94,3 +94,11 @@ sprite: DeltaV/Clothing/Eyes/Glasses/interdynechemgoogles.rsi - type: Clothing sprite: DeltaV/Clothing/Eyes/Glasses/interdynechemgoogles.rsi + +- type: entity + parent: ClothingEyesGlassesGar + id: ClothingEyesGlassesGarMeson + name: gar mesons + description: Do the impossible, see the invisible! + components: + - type: EyeProtection diff --git a/Resources/Prototypes/DeltaV/Wires/layouts.yml b/Resources/Prototypes/DeltaV/Wires/layouts.yml index fd1e77dc898..90d781119a8 100644 --- a/Resources/Prototypes/DeltaV/Wires/layouts.yml +++ b/Resources/Prototypes/DeltaV/Wires/layouts.yml @@ -7,3 +7,11 @@ - !type:DoorBoltLightWireAction - !type:LogWireAction - !type:AiInteractWireAction + +- type: wireLayout + id: ShopVendor + wires: + - !type:AiInteractWireAction + - !type:PowerWireAction + - !type:AccessWireAction + - !type:LogWireAction diff --git a/Resources/Prototypes/Entities/Objects/Specific/Salvage/ore_bag.yml b/Resources/Prototypes/Entities/Objects/Specific/Salvage/ore_bag.yml index 0306a7dc147..9b0a4361f9f 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Salvage/ore_bag.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Salvage/ore_bag.yml @@ -17,7 +17,7 @@ slots: - belt - type: Item - size: Ginormous + size: Huge # DeltaV: Was Ginormous, lets it fit in conscription bag - type: Storage maxItemSize: Normal grid: diff --git a/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml b/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml index c7851aff88d..1254e95fc07 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml @@ -361,6 +361,7 @@ - state: refill_sec - type: entity + abstract: true # DeltaV: Salvage vendor doesn't have stock anymore parent: BaseVendingMachineRestock id: VendingMachineRestockSalvageEquipment name: Salvage Vendor restock box diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 7b88556d195..3ecb065518a 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -1356,12 +1356,12 @@ name: Salvage Vendor description: A dwarf's best friend! components: - - type: VendingMachine - pack: SalvageEquipmentInventory - offState: off - brokenState: broken - normalState: normal-unshaded - denyState: deny-unshaded + #- type: VendingMachine # DeltaV: Use mining points instead of limited stock + # pack: SalvageEquipmentInventory + # offState: off + # brokenState: broken + # normalState: normal-unshaded + # denyState: deny-unshaded - type: Sprite sprite: Structures/Machines/VendingMachines/mining.rsi layers: @@ -1376,6 +1376,21 @@ radius: 1.5 energy: 1.6 color: "#b89f25" + - type: ShopVendor # DeltaV + pack: SalvageVendorInventory + offState: off + brokenState: broken + normalState: normal-unshaded + denyState: deny-unshaded + - type: PointsVendor # DeltaV + - type: UserInterface # DeltaV: Replace vending machine BUI with shop vendor + interfaces: + enum.VendingMachineUiKey.Key: + type: ShopVendorBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface + - type: Wires # DeltaV: Use shop vendor wires layout + layoutId: ShopVendor - type: AccessReader access: [["Salvage"]] - type: GuideHelp From ae03a72d1bc0a4e458814ed4b9d2b8a2df965f43 Mon Sep 17 00:00:00 2001 From: Delta-V bot <135767721+DeltaV-Bot@users.noreply.github.com> Date: Fri, 27 Dec 2024 04:06:36 +0100 Subject: [PATCH 2/9] Automatic changelog update --- Resources/Changelog/DeltaVChangelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/DeltaVChangelog.yml b/Resources/Changelog/DeltaVChangelog.yml index 512652efe4c..be0148cf567 100644 --- a/Resources/Changelog/DeltaVChangelog.yml +++ b/Resources/Changelog/DeltaVChangelog.yml @@ -1,11 +1,4 @@ Entries: -- author: KittenColony - changes: - - message: Added Several new cigarette brands. - type: Add - id: 320 - time: '2024-04-19T02:51:31.0000000+00:00' - url: https://github.com/DeltaV-Station/Delta-v/pull/931 - author: NullWanderer changes: - message: Merged upstream @@ -3838,3 +3831,12 @@ id: 819 time: '2024-12-26T22:52:11.0000000+00:00' url: https://github.com/DeltaV-Station/Delta-v/pull/2536 +- author: deltanedas + changes: + - message: The Salvage Vendor now lets you buy cool things for mining points. + type: Add + - message: The old salvage gear now comes in the lockers. + type: Tweak + id: 820 + time: '2024-12-27T03:06:17.0000000+00:00' + url: https://github.com/DeltaV-Station/Delta-v/pull/2510 From 9a22c09da63d8c32327363602caf0728ce25a295 Mon Sep 17 00:00:00 2001 From: Avalon Date: Fri, 27 Dec 2024 10:05:15 -0500 Subject: [PATCH 3/9] Port Magic Crayon From Frontier (#2410) * ART * Update clown.yml * Loadout fixes, time req * loadout bgone * Fixes, moved things * fixoneoops * More fixes * CRAFTING WORKS! * Flipped slashes * UNTOUCHED! AT LAST * Fix comment * Mailladd * Webedit ops Signed-off-by: Avalon * untroll indent Signed-off-by: deltanedas <39013340+deltanedas@users.noreply.github.com> --------- Signed-off-by: Avalon Signed-off-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> --- Content.Client/Crayon/CrayonSystem.cs | 11 +++++ Content.Server/Crayon/CrayonSystem.cs | 11 +++-- .../en-US/_NF/crayon/crayon-component.ftl | 5 ++ .../Catalog/Fills/Items/toolboxes.yml | 2 + .../Prototypes/Catalog/Fills/Lockers/misc.yml | 2 + .../Entities/Objects/Specific/Mail/mail.yml | 2 + .../Objects/Specific/Mail/mail_civilian.yml | 2 + .../_NF/Entities/Objects/Fun/magic_crayon.yml | 31 ++++++++++++ .../Recipes/Crafting/Graphs/magic_crayon.yml | 28 +++++++++++ .../_NF/Recipes/Crafting/magic_crayon.yml | 10 ++++ .../Fun/magic_crayon.rsi/icon-inhand-left.png | Bin 0 -> 204 bytes .../magic_crayon.rsi/icon-inhand-right.png | Bin 0 -> 203 bytes .../_NF/Objects/Fun/magic_crayon.rsi/icon.png | Bin 0 -> 282 bytes .../Objects/Fun/magic_crayon.rsi/meta.json | 46 ++++++++++++++++++ 14 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 Resources/Locale/en-US/_NF/crayon/crayon-component.ftl create mode 100644 Resources/Prototypes/_NF/Entities/Objects/Fun/magic_crayon.yml create mode 100644 Resources/Prototypes/_NF/Recipes/Crafting/Graphs/magic_crayon.yml create mode 100644 Resources/Prototypes/_NF/Recipes/Crafting/magic_crayon.yml create mode 100644 Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/icon-inhand-left.png create mode 100644 Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/icon-inhand-right.png create mode 100644 Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/icon.png create mode 100644 Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/meta.json diff --git a/Content.Client/Crayon/CrayonSystem.cs b/Content.Client/Crayon/CrayonSystem.cs index dc039794813..84749cf1f1b 100644 --- a/Content.Client/Crayon/CrayonSystem.cs +++ b/Content.Client/Crayon/CrayonSystem.cs @@ -57,6 +57,17 @@ protected override void FrameUpdate(FrameEventArgs args) } _parent.UIUpdateNeeded = false; + + // Frontier: unlimited crayon, Delta V Port + if (_parent.Capacity == int.MaxValue) + { + _label.SetMarkup(Robust.Shared.Localization.Loc.GetString("crayon-drawing-label-unlimited", + ("color", _parent.Color), + ("state", _parent.SelectedState))); + return; + } + // End Frontier, Delta V Port + _label.SetMarkup(Robust.Shared.Localization.Loc.GetString("crayon-drawing-label", ("color",_parent.Color), ("state",_parent.SelectedState), diff --git a/Content.Server/Crayon/CrayonSystem.cs b/Content.Server/Crayon/CrayonSystem.cs index 4257c436c23..e69d0f177a3 100644 --- a/Content.Server/Crayon/CrayonSystem.cs +++ b/Content.Server/Crayon/CrayonSystem.cs @@ -73,9 +73,14 @@ private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, Aft if (component.UseSound != null) _audio.PlayPvs(component.UseSound, uid, AudioParams.Default.WithVariation(0.125f)); - // Decrease "Ammo" - component.Charges--; - Dirty(uid, component); + // Frontier: check if crayon is infinite, Delta V Port + if (component.Charges != int.MaxValue) + { + // Decrease "Ammo" + component.Charges--; + Dirty(uid, component); + } + // End Frontier, Delta V Port _adminLogger.Add(LogType.CrayonDraw, LogImpact.Low, $"{EntityManager.ToPrettyString(args.User):user} drew a {component.Color:color} {component.SelectedState}"); args.Handled = true; diff --git a/Resources/Locale/en-US/_NF/crayon/crayon-component.ftl b/Resources/Locale/en-US/_NF/crayon/crayon-component.ftl new file mode 100644 index 00000000000..146559f00a5 --- /dev/null +++ b/Resources/Locale/en-US/_NF/crayon/crayon-component.ftl @@ -0,0 +1,5 @@ + +## Entity + +crayon-drawing-label-unlimited = Drawing: [color={$color}]{$state}[/color] + diff --git a/Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml b/Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml index c484fee13f1..ba2b91df007 100644 --- a/Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml +++ b/Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml @@ -85,6 +85,8 @@ amount: 2 - id: CrayonMime - id: CrayonRainbow + - id: CrayonMagic # Delta V - A construction graph was made, but still can find in the wild + prob: .10 - type: entity id: ToolboxMechanicalFilled diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml index 4c0a9826de7..00a9e25fc6e 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml @@ -134,6 +134,8 @@ children: - id: StrangePill prob: 0.20 + - id: CrayonMagic # Delta V - Just another way to get it + prob: .01 # Tools - !type:NestedSelector tableId: MaintToolsTable diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml index 09b3a8ae88f..6ea56a91842 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml @@ -1555,6 +1555,8 @@ - type: Mail contents: - id: CrayonBox + - id: CrayonMagic + - prob: .10 - type: entity parent: BaseMail diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_civilian.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_civilian.yml index ffc5801fc3b..5c0248f02fd 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_civilian.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_civilian.yml @@ -178,6 +178,8 @@ - id: CrayonBox - id: Paper maxAmount: 3 + - id: CrayonMagic + - prob: .2 - type: entity parent: BaseMail diff --git a/Resources/Prototypes/_NF/Entities/Objects/Fun/magic_crayon.yml b/Resources/Prototypes/_NF/Entities/Objects/Fun/magic_crayon.yml new file mode 100644 index 00000000000..35ac44cdcf5 --- /dev/null +++ b/Resources/Prototypes/_NF/Entities/Objects/Fun/magic_crayon.yml @@ -0,0 +1,31 @@ +- type: entity + parent: CrayonRainbow + id: CrayonMagic + name: magic crayon + description: Specially blended with bluespace crystals and certified non-toxic. + components: + - type: Sprite + sprite: _NF/Objects/Fun/magic_crayon.rsi + state: icon + - type: Item + sprite: _NF/Objects/Fun/magic_crayon.rsi + heldPrefix: icon + - type: Tag # Removing trash & recyclable + tags: + - Write + - Crayon + - type: Crayon + capacity: 2147483647 # int.MaxValue, infinite charges + - type: FlavorProfile + flavors: + - chewy + - magical + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: Nothing + Quantity: 100 + - type: Construction + graph: magic_crayon + node: magicCrayon diff --git a/Resources/Prototypes/_NF/Recipes/Crafting/Graphs/magic_crayon.yml b/Resources/Prototypes/_NF/Recipes/Crafting/Graphs/magic_crayon.yml new file mode 100644 index 00000000000..5d5c4836781 --- /dev/null +++ b/Resources/Prototypes/_NF/Recipes/Crafting/Graphs/magic_crayon.yml @@ -0,0 +1,28 @@ +- type: constructionGraph + id: magic_crayon + start: start + graph: + - node: start + edges: + - to: magicCrayon + steps: + - material: Bluespace + amount: 1 + - tag: CrayonRed + name: red crayon + icon: + sprite: Objects/Fun/crayons.rsi + state: red + - tag: CrayonGreen + name: green crayon + icon: + sprite: Objects/Fun/crayons.rsi + state: green + - tag: CrayonBlue + name: blue crayon + icon: + sprite: Objects/Fun/crayons.rsi + state: blue + doAfter: 5 + - node: magicCrayon + entity: CrayonMagic diff --git a/Resources/Prototypes/_NF/Recipes/Crafting/magic_crayon.yml b/Resources/Prototypes/_NF/Recipes/Crafting/magic_crayon.yml new file mode 100644 index 00000000000..cb26164f471 --- /dev/null +++ b/Resources/Prototypes/_NF/Recipes/Crafting/magic_crayon.yml @@ -0,0 +1,10 @@ +- type: construction + name: Magic Crayon + id: CrayonMagic + graph: magic_crayon + startNode: start + targetNode: magicCrayon + category: construction-category-misc + description: A crayon that lasts forever! Pretty too + icon: { sprite: _NF/Objects/Fun/magic_crayon.rsi, state: icon } + objectType: Item diff --git a/Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/icon-inhand-left.png b/Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/icon-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..a88404f0b202b9e258fa00a6f96b8050115f52a9 GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^2|(Py!3-o1GtKD$QbGYfA+A9B7Q=srh5t(aG5jm$ z|IfsKP?W7C$S;`TzYY*S=}ia)iX?lwIEG|2zP-7T_kaNhi$l-bzv1VYChqUJ zq*AWCX(3CkD8q;B#pl27J@-}eUikUX{MtSjGMl2TeFg6IUjXX2TXk6PPsMe%Bv3hnr>mdKI;Vst08%nbKmY&$ literal 0 HcmV?d00001 diff --git a/Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/icon-inhand-right.png b/Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/icon-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..c337641453062383276b3656a5dc5c51dfa0db23 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^2|(Py!3-o1GtKD$QbGYfA+A80Vd1}94FCTX^OyW% z_|L?|Z5)vY6l5z2@(X6r`LFZ;zxCrhIiN_Ar;B4qM&sLCJ9!Tn@Gv|4yj}k^rE!Mq z1hswHyp3AE4xtPOJfrUK?-zZRK4ZS_ll}?&=da&7fBl4bMR^8>zH9dX`tSEDnKW&1 y^p@W9-ejRMBg29BFIlS?85pKWE1SE0c*8V3k>Tn5BWJ}xuJUyCb6Mw<&;$U=o=Ecm literal 0 HcmV?d00001 diff --git a/Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/icon.png b/Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c520ae932500b2757cd8b4ced4aeb6d3e4ef40ac GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!3-pya`gKGDct~{5LX~Q)A$U7@tK(n{}~ov zVqo~+wq2BA`}<=(Y%8A0Uayq-|A}E0P;@fGEe3`M@8_8UHSm`N`2{olM*&ZJ=Pd(D z^?JHEhGaCpy>$8$@nJHL#E$=kopU0tg)~^Lo?dq8lHa9hRnJT789y<9lKmw5 zsqmFFPx$=@7QfkkFV8pFf6UDPd-T2H*~@>gy?yD~%epUiFYEl@KhNCX^j-5s_=WWg z=Bs#4QmMUI)leGz_gB)(zwVEI^Dp_X>G^;EgfIWOft127`Ca)h)IBfNn;!~i;g#0a R1iGAo!PC{xWt~$(69CTof<6EM literal 0 HcmV?d00001 diff --git a/Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/meta.json b/Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/meta.json new file mode 100644 index 00000000000..21fc89b91f5 --- /dev/null +++ b/Resources/Textures/_NF/Objects/Fun/magic_crayon.rsi/meta.json @@ -0,0 +1,46 @@ +{ + "version": 1, + "license": "CC-BY-SA-4.0", + "copyright": "Taken from tgstation and modified by Swept at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24, tweaked by Ubaser and whatston3 (GitHub)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "icon-inhand-left", + "directions": 4, + "delays": [ + [ 0.2, 0.2, 0.2 ], + [ 0.2, 0.2, 0.2 ], + [ 0.2, 0.2, 0.2 ], + [ 0.2, 0.2, 0.2 ] + ] + }, + { + "name": "icon-inhand-right", + "directions": 4, + "delays": [ + [ 0.2, 0.2, 0.2 ], + [ 0.2, 0.2, 0.2 ], + [ 0.2, 0.2, 0.2 ], + [ 0.2, 0.2, 0.2 ] + ] + } + ] +} + From c9abaf30ca6fabed58ffd6d927978a0aae036c24 Mon Sep 17 00:00:00 2001 From: Stop-Signs Date: Fri, 27 Dec 2024 22:02:22 -0600 Subject: [PATCH 4/9] Fix mag shaders for ICEE (#2547) Yikes --- .../Battery/cold_cannon.rsi/mag-unshaded-1.png | Bin 306 -> 168 bytes .../Battery/cold_cannon.rsi/mag-unshaded-2.png | Bin 318 -> 183 bytes .../Battery/cold_cannon.rsi/mag-unshaded-3.png | Bin 351 -> 192 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/DeltaV/Objects/Weapons/Guns/Battery/cold_cannon.rsi/mag-unshaded-1.png b/Resources/Textures/DeltaV/Objects/Weapons/Guns/Battery/cold_cannon.rsi/mag-unshaded-1.png index e900d13598e3b50b1c91cb46a2d4efd074a476e0..b002ca792426d10efdbf6535ae8dd30ce82dc75b 100644 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}iJmTwArbD$ zDG~_>EDn4#?y*WRVR3VY5p8uGE9Tq%`2Wn2nXU9UH;=jRThDI-C#5c|&KG>m{NFJt upNUse!s~~pS$_)el{|Yi?QYHt3|?W}ikIgtumoDh;OXk;vd$@?i2(pV3Ngq4 literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|-gvq=hE&A8 zow`x5DL{lpUUb3@=9MfiY*!NWML0HczI=aBu3*i>`v%3u*^JM3=AX9@`H{}?|1T>8 z4~O~zmP4!${3mc4G!`)VD8w+tF{%NDKwQQO))@@KP!*yHK-oDC-&vNOFWmY#@^V#J z^tE?;cE7(E`{U!S_4O~`SFgKu?46A@L%DcZ{rtN}85GnS7?T#16-p$O8x8?TlsW!s5pm3kkF**(@LbV*$Nv5;wEDn4#?y*WRVR3VY5p9kfUuyoW&#P~I_{@=+O@Nn4!OWS{K5(A0m*76F=p(-l z{5Rh&ZfG#&t8vE~`|}^vE(kcumnxjfStN3C(^-R84HpF@cpKpaBg4iiqKf4Pq9Cgo PJYD@<);T3KF)#oC^P@T{ literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|zInPhhE&A8 zow`u)P=E+ayw-sw>^d1NTO9OxLJgexO&qutE+j}sbu4T$kgRzUUno6!hwr;@pLTQY z-}T|WKJ$f!4=i&Wb};;7ncE=D;eUX$h5Lc#1E5d^lb=EigFmDC1C~R=1xyc_D!42d z)h{SDUM`Qxi~qWBebz4j>tABpS@RMmi@z}6Uic$sRp0Yh>(5Jld;S0K#_U7$UrW?C ziZMwY@L`g2(DwLj+K|`qESupj!`bT$yBKG!XDnehiD!Pnma&iR0`G+y-UZSNeo8r* fI}oMN-e!@gqnQ^|H82DiJYD@<);T3KF)#oC>lJw7 diff --git a/Resources/Textures/DeltaV/Objects/Weapons/Guns/Battery/cold_cannon.rsi/mag-unshaded-3.png b/Resources/Textures/DeltaV/Objects/Weapons/Guns/Battery/cold_cannon.rsi/mag-unshaded-3.png index 78b1d7ca2945f3fe6535d5a68cbebc3d3d8d937b..4db42745468b3ec563152e7718b9e1ff2da14a7e 100644 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}6`n4RArbD$ zDG~_>EDn4#?y*WRVR3VY5p8uGE9Tq%kPlgW&nDx*g1mahn4L{G6c`@eH`#jpwdX14 z1FVdQ&MBdZfdK%4kU?<( literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z#XVgdLn`9l zPTk0R$U(%pzAS-tiWt|c4NTk{n6nj@B`~IWIJz?C9^uNIq41)~#k2U(rZ4wHJ(tX> z{r1~a_+*Pqy!$^={qFNq7hVft%2cr znaDi_hl!guv$0rgU;KfMv1`g)Q-uRNWn0ZT0+zg4!^n8?&t;ucLK6c60I}DD761SM From 1704c56aad87c2946201d1efd109b2e9939a8d6c Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 28 Dec 2024 05:28:56 +0000 Subject: [PATCH 5/9] unnerf mining rig (#2511) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Resources/Prototypes/Entities/Clothing/Belt/belts.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml index 5dccfda8ad0..ae2af636384 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml @@ -699,10 +699,10 @@ sprite: Clothing/Belt/salvagewebbing.rsi - type: Clothing sprite: Clothing/Belt/salvagewebbing.rsi - - type: Storage # Delta-V - Split Inventory + - type: Storage # Delta-V - Split Inventory, but same total size grid: - - 0,0,2,1 - - 4,0,7,1 + - 0,0,3,1 + - 5,0,8,1 - type: entity parent: [ClothingBeltStorageBase, ContentsExplosionResistanceBase, BaseSyndicateContraband] From 07da7ec901c745cae304bb97d604bf37a588d32e Mon Sep 17 00:00:00 2001 From: Dvir <39403717+dvir001@users.noreply.github.com> Date: Sat, 28 Dec 2024 07:35:10 +0200 Subject: [PATCH 6/9] Diona immune to FTL Knockdown (#2543) * Strong * Update ShuttleSystem.FasterThanLight.cs Signed-off-by: Dvir <39403717+dvir001@users.noreply.github.com> --------- Signed-off-by: Dvir <39403717+dvir001@users.noreply.github.com> --- .../Shuttles/Systems/ShuttleSystem.FasterThanLight.cs | 4 +++- .../Shuttles/Components/FTLKnockdownImmuneComponent.cs | 9 +++++++++ Resources/Prototypes/Entities/Mobs/Species/diona.yml | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Content.Server/_NF/Shuttles/Components/FTLKnockdownImmuneComponent.cs diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index b550db93ed6..c43b8aced3d 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; +using Content.Server._NF.Shuttles.Components; // Frontier: FTL knockdown immunity using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; using Content.Server.Station.Events; @@ -631,7 +632,8 @@ private void DoTheDinosaur(TransformComponent xform) if (!_statusQuery.TryGetComponent(child, out var status)) continue; - _stuns.TryParalyze(child, _hyperspaceKnockdownTime, true, status); + if (!HasComp(child)) // Frontier: FTL knockdown immunity + _stuns.TryParalyze(child, _hyperspaceKnockdownTime, true, status); // If the guy we knocked down is on a spaced tile, throw them too if (grid != null) diff --git a/Content.Server/_NF/Shuttles/Components/FTLKnockdownImmuneComponent.cs b/Content.Server/_NF/Shuttles/Components/FTLKnockdownImmuneComponent.cs new file mode 100644 index 00000000000..678e89f0c5f --- /dev/null +++ b/Content.Server/_NF/Shuttles/Components/FTLKnockdownImmuneComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Server._NF.Shuttles.Components; + +/// +/// Denotes an entity as being immune from knockdown on FTL +/// +[RegisterComponent] +public sealed partial class FTLKnockdownImmuneComponent : Component +{ +} diff --git a/Resources/Prototypes/Entities/Mobs/Species/diona.yml b/Resources/Prototypes/Entities/Mobs/Species/diona.yml index 7c12787a8c5..979c0981f8c 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/diona.yml @@ -117,6 +117,7 @@ - type: MovementSpeedModifier # DeltaV baseWalkSpeed: 1.0 baseSprintSpeed: 3.0 + - type: FTLKnockdownImmune # Frontier - type: entity parent: BaseSpeciesDummy From 36db57202552fc772eaa6bfa9d561dea44dc1344 Mon Sep 17 00:00:00 2001 From: Delta-V bot <135767721+DeltaV-Bot@users.noreply.github.com> Date: Sat, 28 Dec 2024 06:35:30 +0100 Subject: [PATCH 7/9] Automatic changelog update --- Resources/Changelog/DeltaVChangelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/DeltaVChangelog.yml b/Resources/Changelog/DeltaVChangelog.yml index be0148cf567..c1e024a8dc8 100644 --- a/Resources/Changelog/DeltaVChangelog.yml +++ b/Resources/Changelog/DeltaVChangelog.yml @@ -1,11 +1,4 @@ Entries: -- author: NullWanderer - changes: - - message: Merged upstream - type: Add - id: 321 - time: '2024-04-22T17:25:33.0000000+00:00' - url: https://github.com/DeltaV-Station/Delta-v/pull/1119 - author: Velcroboy changes: - message: Tweaked the inventories of unlocked Booze-O-Mats @@ -3840,3 +3833,10 @@ id: 820 time: '2024-12-27T03:06:17.0000000+00:00' url: https://github.com/DeltaV-Station/Delta-v/pull/2510 +- author: dvir001 + changes: + - message: Diona are now immune to the force of an FTL jump. + type: Add + id: 821 + time: '2024-12-28T05:35:11.0000000+00:00' + url: https://github.com/DeltaV-Station/Delta-v/pull/2543 From a81253969669f8116fa2b48280e45320bd00d514 Mon Sep 17 00:00:00 2001 From: Mono <182929384+Monotheonist@users.noreply.github.com> Date: Sat, 28 Dec 2024 02:25:02 -0400 Subject: [PATCH 8/9] Anti-LOOC fighting rule (#2534) awesome new rule --- .../Guidebook/DeltaV/Rules/CommunityRules/A2_Community.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/ServerInfo/Guidebook/DeltaV/Rules/CommunityRules/A2_Community.xml b/Resources/ServerInfo/Guidebook/DeltaV/Rules/CommunityRules/A2_Community.xml index 4813ff1f62b..c28fdcab698 100644 --- a/Resources/ServerInfo/Guidebook/DeltaV/Rules/CommunityRules/A2_Community.xml +++ b/Resources/ServerInfo/Guidebook/DeltaV/Rules/CommunityRules/A2_Community.xml @@ -4,7 +4,8 @@ - Use English as your primary method of communication within the game and Delta-V servers. - Do not spam or advertise on our server. - Be respectful towards other members and avoid making others uncomfortable. + - Usage of LOOC and OOC channels to denigrate other players' in-game conduct is specifically forbidden. Utilize the Ahelp relay for these concerns. - We have a zero tolerance policy for racism, sexism, homophobia, violence, threats, hate speech, slurs, and other forms of bigotry, discrimination, and harassment. - Slurs and terms that use real or implied mental or physical disability to mock or denigrate members or their in-game characters are also strictly prohibited. [color=#ff0000]Failure to comply with this rule will result in community removal.[/color] + - Slurs and terms that use real or implied mental or physical disability to mock or denigrate members or their in-game characters are also strictly prohibited. [color=#ff0000]Failure to comply with this rule will result in community removal.[/color] - The denigration of other player characters through reference to their species, status as a cyborg, or discriminatory comparison to a nonsophont species is strictly forbidden. From 7708763991340e946fdb733307bc135184ceaf1f Mon Sep 17 00:00:00 2001 From: Delta-V bot <135767721+DeltaV-Bot@users.noreply.github.com> Date: Sat, 28 Dec 2024 07:25:21 +0100 Subject: [PATCH 9/9] Automatic changelog update --- Resources/Changelog/DeltaVChangelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/DeltaVChangelog.yml b/Resources/Changelog/DeltaVChangelog.yml index c1e024a8dc8..de4b520ea76 100644 --- a/Resources/Changelog/DeltaVChangelog.yml +++ b/Resources/Changelog/DeltaVChangelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Velcroboy - changes: - - message: Tweaked the inventories of unlocked Booze-O-Mats - type: Tweak - id: 322 - time: '2024-04-23T21:50:33.0000000+00:00' - url: https://github.com/DeltaV-Station/Delta-v/pull/1127 - author: Adrian16199 changes: - message: Paramedic void suit, elite syndicate hardsuit, blood-red commander/normal @@ -3840,3 +3833,10 @@ id: 821 time: '2024-12-28T05:35:11.0000000+00:00' url: https://github.com/DeltaV-Station/Delta-v/pull/2543 +- author: Monotheonist + changes: + - message: Tweaks Community Rule 2 to prevent flaming in LOOC. + type: Tweak + id: 822 + time: '2024-12-28T06:25:03.0000000+00:00' + url: https://github.com/DeltaV-Station/Delta-v/pull/2534