Skip to content

Commit 6a1af0d

Browse files
committed
Merge branch 'ValidPrinter' of https://github.com/Smugman/Delta-v into ValidPrinter
2 parents 517a9a0 + a17966b commit 6a1af0d

File tree

48 files changed

+1048
-62
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1048
-62
lines changed

Content.Client/Crayon/CrayonSystem.cs

+11
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ protected override void FrameUpdate(FrameEventArgs args)
5757
}
5858

5959
_parent.UIUpdateNeeded = false;
60+
61+
// Frontier: unlimited crayon, Delta V Port
62+
if (_parent.Capacity == int.MaxValue)
63+
{
64+
_label.SetMarkup(Robust.Shared.Localization.Loc.GetString("crayon-drawing-label-unlimited",
65+
("color", _parent.Color),
66+
("state", _parent.SelectedState)));
67+
return;
68+
}
69+
// End Frontier, Delta V Port
70+
6071
_label.SetMarkup(Robust.Shared.Localization.Loc.GetString("crayon-drawing-label",
6172
("color",_parent.Color),
6273
("state",_parent.SelectedState),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
using Content.Shared.DeltaV.VendingMachines;
2+
using Content.Shared.VendingMachines;
3+
using Robust.Client.Animations;
4+
using Robust.Client.GameObjects;
5+
6+
namespace Content.Client.DeltaV.VendingMachines;
7+
8+
public sealed class ShopVendorSystem : SharedShopVendorSystem
9+
{
10+
[Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!;
11+
[Dependency] private readonly AppearanceSystem _appearance = default!;
12+
13+
public override void Initialize()
14+
{
15+
base.Initialize();
16+
17+
SubscribeLocalEvent<ShopVendorComponent, AppearanceChangeEvent>(OnAppearanceChange);
18+
SubscribeLocalEvent<ShopVendorComponent, AnimationCompletedEvent>(OnAnimationCompleted);
19+
}
20+
21+
// copied from vending machines because its not reusable in other systems :)
22+
private void OnAnimationCompleted(Entity<ShopVendorComponent> ent, ref AnimationCompletedEvent args)
23+
{
24+
UpdateAppearance((ent, ent.Comp));
25+
}
26+
27+
private void OnAppearanceChange(Entity<ShopVendorComponent> ent, ref AppearanceChangeEvent args)
28+
{
29+
UpdateAppearance((ent, ent.Comp, args.Sprite));
30+
}
31+
32+
private void UpdateAppearance(Entity<ShopVendorComponent, SpriteComponent?> ent)
33+
{
34+
if (!Resolve(ent, ref ent.Comp2))
35+
return;
36+
37+
if (!_appearance.TryGetData<VendingMachineVisualState>(ent, VendingMachineVisuals.VisualState, out var state))
38+
state = VendingMachineVisualState.Normal;
39+
40+
var sprite = ent.Comp2;
41+
SetLayerState(VendingMachineVisualLayers.Base, ent.Comp1.OffState, sprite);
42+
SetLayerState(VendingMachineVisualLayers.Screen, ent.Comp1.ScreenState, sprite);
43+
switch (state)
44+
{
45+
case VendingMachineVisualState.Normal:
46+
SetLayerState(VendingMachineVisualLayers.BaseUnshaded, ent.Comp1.NormalState, sprite);
47+
break;
48+
49+
case VendingMachineVisualState.Deny:
50+
if (ent.Comp1.LoopDenyAnimation)
51+
SetLayerState(VendingMachineVisualLayers.BaseUnshaded, ent.Comp1.DenyState, sprite);
52+
else
53+
PlayAnimation(ent, VendingMachineVisualLayers.BaseUnshaded, ent.Comp1.DenyState, ent.Comp1.DenyDelay, sprite);
54+
break;
55+
56+
case VendingMachineVisualState.Eject:
57+
PlayAnimation(ent, VendingMachineVisualLayers.BaseUnshaded, ent.Comp1.EjectState, ent.Comp1.EjectDelay, sprite);
58+
break;
59+
60+
case VendingMachineVisualState.Broken:
61+
HideLayers(sprite);
62+
SetLayerState(VendingMachineVisualLayers.Base, ent.Comp1.BrokenState, sprite);
63+
break;
64+
65+
case VendingMachineVisualState.Off:
66+
HideLayers(sprite);
67+
break;
68+
}
69+
}
70+
71+
private static void SetLayerState(VendingMachineVisualLayers layer, string? state, SpriteComponent sprite)
72+
{
73+
if (state == null)
74+
return;
75+
76+
sprite.LayerSetVisible(layer, true);
77+
sprite.LayerSetAutoAnimated(layer, true);
78+
sprite.LayerSetState(layer, state);
79+
}
80+
81+
private void PlayAnimation(EntityUid uid, VendingMachineVisualLayers layer, string? state, TimeSpan time, SpriteComponent sprite)
82+
{
83+
if (state == null || _animationPlayer.HasRunningAnimation(uid, state))
84+
return;
85+
86+
var animation = GetAnimation(layer, state, time);
87+
sprite.LayerSetVisible(layer, true);
88+
_animationPlayer.Play(uid, animation, state);
89+
}
90+
91+
private static Animation GetAnimation(VendingMachineVisualLayers layer, string state, TimeSpan time)
92+
{
93+
return new Animation
94+
{
95+
Length = time,
96+
AnimationTracks =
97+
{
98+
new AnimationTrackSpriteFlick
99+
{
100+
LayerKey = layer,
101+
KeyFrames =
102+
{
103+
new AnimationTrackSpriteFlick.KeyFrame(state, 0f)
104+
}
105+
}
106+
}
107+
};
108+
}
109+
110+
private static void HideLayers(SpriteComponent sprite)
111+
{
112+
HideLayer(VendingMachineVisualLayers.BaseUnshaded, sprite);
113+
HideLayer(VendingMachineVisualLayers.Screen, sprite);
114+
}
115+
116+
private static void HideLayer(VendingMachineVisualLayers layer, SpriteComponent sprite)
117+
{
118+
if (!sprite.LayerMapTryGet(layer, out var actualLayer))
119+
return;
120+
121+
sprite.LayerSetVisible(actualLayer, false);
122+
}
123+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using Content.Shared.DeltaV.VendingMachines;
2+
using Robust.Client.UserInterface;
3+
4+
namespace Content.Client.DeltaV.VendingMachines.UI;
5+
6+
public sealed class ShopVendorBoundUserInterface : BoundUserInterface
7+
{
8+
[ViewVariables]
9+
private ShopVendorWindow? _window;
10+
11+
public ShopVendorBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
12+
{
13+
}
14+
15+
protected override void Open()
16+
{
17+
base.Open();
18+
19+
_window = this.CreateWindow<ShopVendorWindow>();
20+
_window.SetEntity(Owner);
21+
_window.OpenCenteredLeft();
22+
_window.Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName;
23+
_window.OnItemSelected += index => SendMessage(new ShopVendorPurchaseMessage(index));
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<BoxContainer xmlns="https://spacestation14.io"
2+
Orientation="Horizontal"
3+
HorizontalExpand="True"
4+
SeparationOverride="4">
5+
<EntityPrototypeView
6+
Name="ItemPrototype"
7+
Margin="4 0 0 0"
8+
HorizontalAlignment="Center"
9+
VerticalAlignment="Center"
10+
MinSize="32 32"/>
11+
<Label Name="NameLabel" SizeFlagsStretchRatio="3" HorizontalExpand="True" ClipText="True"/>
12+
<Label Name="CostLabel" SizeFlagsStretchRatio="3" HorizontalAlignment="Right" Margin="8 0"/>
13+
</BoxContainer>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Robust.Client.AutoGenerated;
2+
using Robust.Client.UserInterface.Controls;
3+
using Robust.Client.UserInterface.XAML;
4+
using Robust.Shared.Prototypes;
5+
6+
namespace Content.Client.DeltaV.VendingMachines.UI;
7+
8+
[GenerateTypedNameReferences]
9+
public sealed partial class ShopVendorItem : BoxContainer
10+
{
11+
public ShopVendorItem(EntProtoId entProto, string text, uint cost)
12+
{
13+
RobustXamlLoader.Load(this);
14+
15+
ItemPrototype.SetPrototype(entProto);
16+
17+
NameLabel.Text = text;
18+
19+
CostLabel.Text = cost.ToString();
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<controls:FancyWindow
2+
xmlns="https://spacestation14.io"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
5+
MinHeight="210">
6+
<BoxContainer Name="MainContainer" Orientation="Vertical">
7+
<BoxContainer Orientation="Horizontal">
8+
<LineEdit Name="SearchBar" PlaceHolder="{Loc 'vending-machine-component-search-filter'}" HorizontalExpand="True" Margin="4 4"/>
9+
<Label Name="BalanceLabel" Margin="4 4"/>
10+
</BoxContainer>
11+
<controls:SearchListContainer Name="VendingContents" VerticalExpand="True" Margin="4 4"/>
12+
<!-- Footer -->
13+
<BoxContainer Orientation="Vertical">
14+
<PanelContainer StyleClasses="LowDivider" />
15+
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
16+
<Label Text="{Loc 'shop-vendor-flavor-left'}" StyleClasses="WindowFooterText" />
17+
<Label Text="{Loc 'shop-vendor-flavor-right'}" StyleClasses="WindowFooterText"
18+
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
19+
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
20+
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19"/>
21+
</BoxContainer>
22+
</BoxContainer>
23+
</BoxContainer>
24+
</controls:FancyWindow>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using Content.Client.UserInterface.Controls;
2+
using Content.Shared.DeltaV.VendingMachines;
3+
using Content.Shared.Stacks;
4+
using Robust.Client.AutoGenerated;
5+
using Robust.Client.Graphics;
6+
using Robust.Client.Player;
7+
using Robust.Client.UserInterface;
8+
using Robust.Client.UserInterface.Controls;
9+
using Robust.Client.UserInterface.XAML;
10+
using Robust.Shared.Prototypes;
11+
using Robust.Shared.Timing;
12+
using System.Numerics;
13+
14+
namespace Content.Client.DeltaV.VendingMachines.UI;
15+
16+
[GenerateTypedNameReferences]
17+
public sealed partial class ShopVendorWindow : FancyWindow
18+
{
19+
[Dependency] private readonly IComponentFactory _factory = default!;
20+
[Dependency] private readonly IEntityManager _entMan = default!;
21+
[Dependency] private readonly IPlayerManager _player = default!;
22+
[Dependency] private readonly IPrototypeManager _proto = default!;
23+
private readonly ShopVendorSystem _vendor;
24+
25+
/// <summary>
26+
/// Event fired with the listing index to purchase.
27+
/// </summary>
28+
public event Action<int>? OnItemSelected;
29+
30+
private EntityUid _owner;
31+
private readonly StyleBoxFlat _style = new() { BackgroundColor = new Color(70, 73, 102) };
32+
private readonly StyleBoxFlat _styleBroke = new() { BackgroundColor = Color.FromHex("#303133") };
33+
private readonly List<ListContainerButton> _buttons = new();
34+
private uint _balance = 1;
35+
36+
public ShopVendorWindow()
37+
{
38+
RobustXamlLoader.Load(this);
39+
IoCManager.InjectDependencies(this);
40+
41+
_vendor = _entMan.System<ShopVendorSystem>();
42+
43+
VendingContents.SearchBar = SearchBar;
44+
VendingContents.DataFilterCondition += DataFilterCondition;
45+
VendingContents.GenerateItem += GenerateButton;
46+
VendingContents.ItemKeyBindDown += (args, data) => OnItemSelected?.Invoke(((ShopVendorListingData) data).Index);
47+
}
48+
49+
public void SetEntity(EntityUid owner)
50+
{
51+
_owner = owner;
52+
53+
if (!_entMan.TryGetComponent<ShopVendorComponent>(owner, out var comp))
54+
return;
55+
56+
var pack = _proto.Index(comp.Pack);
57+
Populate(pack.Listings);
58+
59+
UpdateBalance();
60+
}
61+
62+
private void UpdateBalance(uint balance)
63+
{
64+
if (_balance == balance)
65+
return;
66+
67+
_balance = balance;
68+
69+
BalanceLabel.Text = Loc.GetString("shop-vendor-balance", ("points", balance));
70+
71+
// disable items that are too expensive to buy
72+
foreach (var button in _buttons)
73+
{
74+
if (button.Data is ShopVendorListingData data)
75+
button.Disabled = data.Cost > balance;
76+
77+
button.StyleBoxOverride = button.Disabled ? _styleBroke : _style;
78+
}
79+
}
80+
81+
private void UpdateBalance()
82+
{
83+
if (_player.LocalEntity is {} user)
84+
UpdateBalance(_vendor.GetBalance(_owner, user));
85+
}
86+
87+
private bool DataFilterCondition(string filter, ListData data)
88+
{
89+
if (data is not ShopVendorListingData { Text: var text })
90+
return false;
91+
92+
if (string.IsNullOrEmpty(filter))
93+
return true;
94+
95+
return text.Contains(filter, StringComparison.CurrentCultureIgnoreCase);
96+
}
97+
98+
private void GenerateButton(ListData data, ListContainerButton button)
99+
{
100+
if (data is not ShopVendorListingData cast)
101+
return;
102+
103+
_buttons.Add(button);
104+
button.AddChild(new ShopVendorItem(cast.ItemId, cast.Text, cast.Cost));
105+
106+
button.ToolTip = cast.Text;
107+
button.Disabled = cast.Cost > _balance;
108+
button.StyleBoxOverride = button.Disabled ? _styleBroke : _style;
109+
}
110+
111+
public void Populate(List<ShopListing> listings)
112+
{
113+
var longestEntry = string.Empty;
114+
var listData = new List<ShopVendorListingData>();
115+
for (var i = 0; i < listings.Count; i++)
116+
{
117+
var listing = listings[i];
118+
var proto = _proto.Index(listing.Id);
119+
var text = proto.Name;
120+
if (proto.TryGetComponent<StackComponent>(out var stack, _factory) && stack.Count > 1)
121+
{
122+
text += " ";
123+
text += Loc.GetString("shop-vendor-stack-suffix", ("count", stack.Count));
124+
}
125+
listData.Add(new ShopVendorListingData(i, listing.Id, text, listing.Cost));
126+
}
127+
128+
_buttons.Clear();
129+
VendingContents.PopulateList(listData);
130+
SetSizeAfterUpdate(longestEntry.Length, listings.Count);
131+
}
132+
133+
private void SetSizeAfterUpdate(int longestEntryLength, int contentCount)
134+
{
135+
SetSize = new Vector2(Math.Clamp((longestEntryLength + 2) * 12, 250, 400),
136+
Math.Clamp(contentCount * 50, 150, 350));
137+
}
138+
139+
protected override void FrameUpdate(FrameEventArgs args)
140+
{
141+
base.FrameUpdate(args);
142+
143+
UpdateBalance();
144+
}
145+
}
146+
147+
public record ShopVendorListingData(int Index, EntProtoId ItemId, string Text, uint Cost) : ListData;

Content.Server/Crayon/CrayonSystem.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,14 @@ private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, Aft
7373
if (component.UseSound != null)
7474
_audio.PlayPvs(component.UseSound, uid, AudioParams.Default.WithVariation(0.125f));
7575

76-
// Decrease "Ammo"
77-
component.Charges--;
78-
Dirty(uid, component);
76+
// Frontier: check if crayon is infinite, Delta V Port
77+
if (component.Charges != int.MaxValue)
78+
{
79+
// Decrease "Ammo"
80+
component.Charges--;
81+
Dirty(uid, component);
82+
}
83+
// End Frontier, Delta V Port
7984

8085
_adminLogger.Add(LogType.CrayonDraw, LogImpact.Low, $"{EntityManager.ToPrettyString(args.User):user} drew a {component.Color:color} {component.SelectedState}");
8186
args.Handled = true;

0 commit comments

Comments
 (0)