Improve paper stamping experience (#17135)

This commit is contained in:
eoineoineoin
2023-08-13 19:28:10 +01:00
committed by GitHub
parent ae2dcc8aba
commit 4ccc8a04be
28 changed files with 629 additions and 202 deletions

View File

@@ -1,4 +1,4 @@
using Content.Client.Eui;
using Content.Client.Eui;
using Content.Shared.Eui;
using Content.Shared.Fax;
using JetBrains.Annotations;
@@ -15,7 +15,8 @@ public sealed class AdminFaxEui : BaseEui
_window = new AdminFaxWindow();
_window.OnClose += () => SendMessage(new AdminFaxEuiMsg.Close());
_window.OnFollowFax += uid => SendMessage(new AdminFaxEuiMsg.Follow(uid));
_window.OnMessageSend += args => SendMessage(new AdminFaxEuiMsg.Send(args.uid, args.title, args.from, args.message, args.stamp));
_window.OnMessageSend += args => SendMessage(new AdminFaxEuiMsg.Send(args.uid, args.title,
args.stampedBy, args.message, args.stampSprite, args.stampColor));
}
public override void Opened()

View File

@@ -1,4 +1,4 @@
<DefaultWindow xmlns="https://spacestation14.io"
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc admin-fax-title}"
MinWidth="400">
<BoxContainer Orientation="Vertical" VerticalExpand="True">
@@ -21,6 +21,8 @@
<Control MinWidth="5" />
<OptionButton Name="StampSelector" HorizontalExpand="True" />
</BoxContainer>
<Label Text="{Loc admin-fax-stamp-color}" />
<ColorSelectorSliders Margin="12 0 0 0" Name="StampColorSelector" Color="#BB3232"/>
<Control MinHeight="10" />
<Button Name="SendButton" Text="{Loc admin-fax-send}"></Button>
</BoxContainer>

View File

@@ -1,4 +1,4 @@
using Content.Shared.Fax;
using Content.Shared.Fax;
using Robust.Client.AutoGenerated;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
@@ -13,7 +13,7 @@ public sealed partial class AdminFaxWindow : DefaultWindow
{
private const string StampsRsiPath = "/Textures/Objects/Misc/bureaucracy.rsi";
public Action<(EntityUid uid, string title, string from, string message, string stamp)>? OnMessageSend;
public Action<(EntityUid uid, string title, string stampedBy, string message, string stampSprite, Color stampColor)>? OnMessageSend;
public Action<EntityUid>? OnFollowFax;
public AdminFaxWindow()
@@ -28,6 +28,9 @@ public sealed partial class AdminFaxWindow : DefaultWindow
FollowButton.OnPressed += FollowFax;
SendButton.OnPressed += SendMessage;
// Don't use this, but ColorSelectorSliders requires it:
StampColorSelector.OnColorChanged += (Color) => {};
var loc = IoCManager.Resolve<ILocalizationManager>();
MessageEdit.Placeholder = new Rope.Leaf(loc.GetString("admin-fax-message-placeholder")); // TextEdit work only with Nodes
}
@@ -90,6 +93,7 @@ public sealed partial class AdminFaxWindow : DefaultWindow
return;
var from = FromEdit.Text;
OnMessageSend?.Invoke((faxUid.Value, title, from, message, stamp));
var stampColor = StampColorSelector.Color;
OnMessageSend?.Invoke((faxUid.Value, title, from, message, stamp, stampColor));
}
}

View File

@@ -5,8 +5,8 @@ using Robust.Shared.Input;
using Robust.Shared.Utility;
using static Content.Shared.Paper.SharedPaperComponent;
namespace Content.Client.Paper.UI
{
namespace Content.Client.Paper.UI;
[UsedImplicitly]
public sealed class PaperBoundUserInterface : BoundUserInterface
{
@@ -35,7 +35,7 @@ namespace Content.Client.Paper.UI
if (EntMan.TryGetComponent<PaperVisualsComponent>(Owner, out var visuals))
{
_window.InitVisuals(visuals);
_window.InitVisuals(Owner, visuals);
}
_window.OpenCentered();
@@ -68,4 +68,3 @@ namespace Content.Client.Paper.UI
_window?.Dispose();
}
}
}

View File

@@ -20,7 +20,8 @@
<TextEdit Name="Input" StyleClasses="PaperLineEdit" Access="Public" />
</PanelContainer>
</BoxContainer>
<BoxContainer Name="StampDisplay" Orientation="Vertical" VerticalAlignment="Bottom" Margin="6"/>
<paper:StampCollection Name="StampDisplay" VerticalAlignment="Bottom" Margin="6"/>
</PanelContainer>
</ScrollContainer>
</PanelContainer>

View File

@@ -44,8 +44,11 @@ namespace Content.Client.Paper.UI
/// Initialize this UI according to <code>visuals</code> Initializes
/// textures, recalculates sizes, and applies some layout rules.
/// </summary>
public void InitVisuals(PaperVisualsComponent visuals)
public void InitVisuals(EntityUid entity, PaperVisualsComponent visuals)
{
// Randomize the placement of any stamps based on the entity UID
// so that there's some variety in different papers.
StampDisplay.PlacementSeed = (int)entity;
var resCache = IoCManager.Resolve<IResourceCache>();
// Initialize the background:
@@ -206,9 +209,10 @@ namespace Content.Client.Paper.UI
BlankPaperIndicator.Visible = !isEditing && state.Text.Length == 0;
StampDisplay.RemoveAllChildren();
StampDisplay.RemoveStamps();
foreach(var stamper in state.StampedBy)
{
StampDisplay.AddChild(new StampWidget{ Stamper = stamper });
StampDisplay.AddStamp(new StampWidget{ StampInfo = stamper });
}
}
@@ -220,7 +224,7 @@ namespace Content.Client.Paper.UI
/// </summary>
protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
{
var mode = DragMode.Move;
var mode = DragMode.None;
// Be quite generous with resize margins:
if (relativeMousePos.Y < DRAG_MARGIN_SIZE)
@@ -241,6 +245,10 @@ namespace Content.Client.Paper.UI
mode |= DragMode.Right;
}
if((mode & _allowedResizeModes) == DragMode.None)
{
return DragMode.Move;
}
return mode & _allowedResizeModes;
}
}

View File

@@ -0,0 +1,5 @@
<paper:StampCollection xmlns="https://spacestation14.io"
xmlns:paper="clr-namespace:Content.Client.Paper.UI"
MinSize="150 150">
</paper:StampCollection>

View File

@@ -0,0 +1,98 @@
using System.Numerics;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Random;
namespace Content.Client.Paper.UI;
[GenerateTypedNameReferences]
public sealed partial class StampCollection : Container
{
private List<StampWidget> _stamps = new();
/// Seed for random number generator to place stamps deterministically
public int PlacementSeed;
public StampCollection()
{
RobustXamlLoader.Load(this);
}
/// <summary>
/// Remove any stamps from the page
/// </summary>
public void RemoveStamps()
{
_stamps.Clear();
InvalidateArrange();
}
/// <summary>
/// Adds a stamp to the display; will perform
/// automatic layout.
/// </summary>
public void AddStamp(StampWidget s)
{
_stamps.Add(s);
AddChild(s);
}
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var random = new Random(PlacementSeed);
var r = (finalSize * 0.5f).Length();
var dtheta = -MathHelper.DegreesToRadians(90);
var theta0 = random.Next(0, 3) * dtheta;
var thisCenter = PixelSizeBox.TopLeft + finalSize * UIScale * 0.5f;
// Here's where we lay out the stamps. The first stamp goes in the
// center of this container; subsequent stamps will chose an angle
// (theta) to place the center of the stamp. The stamp is moved out
// as far as it can in that direction, taking the size and
// orientation of the stamp into account.
for (var i = 0; i < _stamps.Count; i++)
{
var stampOrientation = MathHelper.DegreesToRadians((random.NextFloat() - 0.5f) * 10.0f) ;
_stamps[i].Orientation = stampOrientation;
var theta = theta0 + dtheta * 0.5f + dtheta * i + (i > 4 ? MathF.Log(1 + i / 4) * dtheta : 0); // There is probably a better way to lay these out, to minimize overlaps
var childCenterOnCircle = thisCenter;
if (i > 0)
{
// First stamp can go in the center. Subsequent stamps have to find space.
childCenterOnCircle += new Vector2(MathF.Cos(theta), MathF.Sin(theta)) * r * UIScale;
}
var childHeLocal = _stamps[i].DesiredPixelSize * 0.5f;
var c = childHeLocal * MathF.Abs(MathF.Cos(stampOrientation));
var s = childHeLocal * MathF.Abs(MathF.Sin(stampOrientation));
var childHePage = new Vector2(c.X + s.Y, s.X + c.Y);
var controlBox = new UIBox2(PixelSizeBox.TopLeft, PixelSizeBox.TopLeft + finalSize * UIScale);
var clampedCenter = Clamp(Shrink(controlBox, childHePage), childCenterOnCircle);
var finalPosition = clampedCenter - childHePage;
var finalPositionAsInt = new Vector2i((int)finalPosition.X, (int)finalPosition.Y);
_stamps[i].ArrangePixel(new UIBox2i(finalPositionAsInt, finalPositionAsInt + _stamps[i].DesiredPixelSize));
}
return finalSize;
}
/// <summary>
/// Shrink a UIBox2 by a half extents, moving both the top-left and
/// bottom-right closer together.
/// </summary>
private UIBox2 Shrink(UIBox2 box, Vector2 shrinkHe)
{
return new UIBox2(box.TopLeft + shrinkHe, box.BottomRight - shrinkHe);
}
/// <summary>
/// Returns the input vector clamped to be within the UIBox
/// </summary>
private Vector2 Clamp(UIBox2 box, Vector2 point)
{
return Vector2.Min(box.BottomRight, Vector2.Max(box.TopLeft, point));
}
}

View File

@@ -0,0 +1,2 @@
<paper:StampLabel xmlns="https://spacestation14.io"
xmlns:paper="clr-namespace:Content.Client.Paper.UI" />

View File

@@ -0,0 +1,56 @@
using System.Numerics;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Paper.UI;
[GenerateTypedNameReferences]
public sealed partial class StampLabel : Label
{
/// A scale that's applied to the text to ensure it
/// fits in the allowed space.
private Vector2 _textScaling = Vector2.One;
/// Shader used to draw the stamps
private ShaderInstance? _stampShader;
/// Allows an additional orientation to be applied to
/// this control.
public float Orientation = 0.0f;
public StampLabel()
{
RobustXamlLoader.Load(this);
var prototypes = IoCManager.Resolve<IPrototypeManager>();
_stampShader = prototypes.Index<ShaderPrototype>("PaperStamp").InstanceUnique();
}
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var desiredTextSize = base.MeasureOverride(availableSize);
var clampedScale = Vector2.Min(availableSize / desiredTextSize, Vector2.One);
var keepAspectRatio = MathF.Min(clampedScale.X, clampedScale.Y);
const float shimmerReduction = 0.1f;
_textScaling = Vector2.One * MathF.Round(keepAspectRatio / shimmerReduction) * shimmerReduction;
return desiredTextSize;
}
protected override void Draw(DrawingHandleScreen handle)
{
var offset = new Vector2(PixelPosition.X * MathF.Cos(Orientation) - PixelPosition.Y * MathF.Sin(Orientation),
PixelPosition.Y * MathF.Cos(Orientation) + PixelPosition.X * MathF.Sin(Orientation));
_stampShader?.SetParameter("objCoord", GlobalPosition * UIScale * new Vector2(1, -1));
handle.UseShader(_stampShader);
handle.SetTransform(GlobalPixelPosition - PixelPosition + offset, Orientation, _textScaling);
base.Draw(handle);
// Restore a sane transform+shader
handle.SetTransform(Matrix3.Identity);
handle.UseShader(null);
}
}

View File

@@ -4,22 +4,7 @@
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:paper="clr-namespace:Content.Client.Paper.UI" HorizontalAlignment="Center" Margin="6">
<BoxContainer Orientation="Vertical">
<PanelContainer>
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="{x:Static style:StyleNano.DangerousRedFore}" />
</PanelContainer.PanelOverride>
<Control MinSize="3 3" />
</PanelContainer>
<Label Name="StampedByLabel" StyleClasses="LabelHeadingBigger" FontColorOverride="{x:Static style:StyleNano.DangerousRedFore}" Margin="12 6 12 6"/>
<PanelContainer>
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="{x:Static style:StyleNano.DangerousRedFore}" />
</PanelContainer.PanelOverride>
<Control MinSize="3 3" />
</PanelContainer>
</BoxContainer>
<paper:StampLabel Name="StampedByLabel" StyleClasses="LabelHeadingBigger"
FontColorOverride="{x:Static style:StyleNano.DangerousRedFore}"
Margin="12 6 12 6"/>
</paper:StampWidget>

View File

@@ -1,23 +1,59 @@
using System.Numerics;
using Content.Shared.Paper;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
using Robust.Shared.Prototypes;
namespace Content.Client.Paper.UI;
namespace Content.Client.Paper.UI
{
[GenerateTypedNameReferences]
public sealed partial class StampWidget : Container
public sealed partial class StampWidget : PanelContainer
{
public string? Stamper {
get => StampedByLabel.Text;
set => StampedByLabel.Text = value;
private StyleBoxTexture _borderTexture;
private ShaderInstance? _stampShader;
public float Orientation
{
get => StampedByLabel.Orientation;
set => StampedByLabel.Orientation = value;
}
public StampDisplayInfo StampInfo {
set {
StampedByLabel.Text = Loc.GetString(value.StampedName);
StampedByLabel.FontColorOverride = value.StampedColor;
ModulateSelfOverride = value.StampedColor;
}
}
public StampWidget()
{
RobustXamlLoader.Load(this);
}
var resCache = IoCManager.Resolve<IResourceCache>();
var borderImage = resCache.GetResource<TextureResource>(
"/Textures/Interface/Paper/paper_stamp_border.svg.96dpi.png");
_borderTexture = new StyleBoxTexture {
Texture = borderImage,
};
_borderTexture.SetPatchMargin(StyleBoxTexture.Margin.All, 7.0f);
PanelOverride = _borderTexture;
var prototypes = IoCManager.Resolve<IPrototypeManager>();
_stampShader = prototypes.Index<ShaderPrototype>("PaperStamp").InstanceUnique();
}
protected override void Draw(DrawingHandleScreen handle)
{
_stampShader?.SetParameter("objCoord", GlobalPosition * UIScale * new Vector2(1, -1));
handle.UseShader(_stampShader);
handle.SetTransform(GlobalPosition * UIScale, Orientation, Vector2.One);
base.Draw(handle);
// Restore a sane transform+shader
handle.SetTransform(Matrix3.Identity);
handle.UseShader(null);
}
}

View File

@@ -1,9 +1,10 @@
using Content.Server.DeviceNetwork.Components;
using Content.Server.DeviceNetwork.Components;
using Content.Server.EUI;
using Content.Server.Ghost.Components;
using Content.Shared.Eui;
using Content.Shared.Fax;
using Content.Shared.Follower;
using Content.Shared.Paper;
namespace Content.Server.Fax.AdminUI;
@@ -53,7 +54,8 @@ public sealed class AdminFaxEui : BaseEui
}
case AdminFaxEuiMsg.Send sendData:
{
var printout = new FaxPrintout(sendData.Content, sendData.Title, null, sendData.StampState, new() { sendData.From });
var printout = new FaxPrintout(sendData.Content, sendData.Title, null, sendData.StampState,
new() { new StampDisplayInfo { StampedName = sendData.From, StampedColor = sendData.StampColor } });
_faxSystem.Receive(sendData.Target, printout);
break;
}

View File

@@ -1,4 +1,5 @@
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Paper;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -136,18 +137,18 @@ public sealed class FaxPrintout
public string? StampState { get; }
[DataField("stampedBy")]
public List<string> StampedBy { get; } = new();
public List<StampDisplayInfo> StampedBy { get; } = new();
private FaxPrintout()
{
}
public FaxPrintout(string content, string name, string? prototypeId = null, string? stampState = null, List<string>? stampedBy = null)
public FaxPrintout(string content, string name, string? prototypeId = null, string? stampState = null, List<StampDisplayInfo>? stampedBy = null)
{
Content = content;
Name = name;
PrototypeId = prototypeId ?? "";
StampState = stampState;
StampedBy = stampedBy ?? new List<string>();
StampedBy = stampedBy ?? new List<StampDisplayInfo>();
}
}

View File

@@ -16,6 +16,7 @@ using Content.Shared.Emag.Components;
using Content.Shared.Emag.Systems;
using Content.Shared.Fax;
using Content.Shared.Interaction;
using Content.Shared.Paper;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
@@ -272,7 +273,7 @@ public sealed class FaxSystem : EntitySystem
return;
args.Data.TryGetValue(FaxConstants.FaxPaperStampStateData, out string? stampState);
args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List<string>? stampedBy);
args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List<StampDisplayInfo>? stampedBy);
args.Data.TryGetValue(FaxConstants.FaxPaperPrototypeData, out string? prototypeId);
var printout = new FaxPrintout(content, name, prototypeId, stampState, stampedBy);
@@ -461,9 +462,9 @@ public sealed class FaxSystem : EntitySystem
// Apply stamps
if (printout.StampState != null)
{
foreach (var stampedBy in printout.StampedBy)
foreach (var stamp in printout.StampedBy)
{
_paperSystem.TryStamp(printed, stampedBy, printout.StampState);
_paperSystem.TryStamp(printed, stamp, printout.StampState);
}
}
}

View File

@@ -5,6 +5,7 @@ using Content.Server.Fax;
using Content.Server.Paper;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Paper;
using Robust.Shared.Random;
using Robust.Shared.Utility;
@@ -66,7 +67,11 @@ namespace Content.Server.Nuke
Loc.GetString("nuke-codes-fax-paper-name"),
null,
"paper_stamp-centcom",
new() { Loc.GetString("stamp-component-stamped-name-centcom") });
new List<StampDisplayInfo>
{
new StampDisplayInfo { StampedName = Loc.GetString("stamp-component-stamped-name-centcom"), StampedColor = Color.FromHex("#BB3232") },
}
);
_faxSystem.Receive(faxEnt, printout, null, fax);
wasSent = true;

View File

@@ -1,8 +1,8 @@
using Content.Shared.Paper;
using Robust.Shared.GameStates;
namespace Content.Server.Paper
{
namespace Content.Server.Paper;
[NetworkedComponent, RegisterComponent]
public sealed class PaperComponent : SharedPaperComponent
{
@@ -14,11 +14,11 @@ namespace Content.Server.Paper
public int ContentSize { get; set; } = 6000;
[DataField("stampedBy")]
public List<string> StampedBy { get; set; } = new();
public List<StampDisplayInfo> StampedBy { get; set; } = new();
/// <summary>
/// Stamp to be displayed on the paper, state from beauracracy.rsi
/// </summary>
[DataField("stampState")]
public string? StampState { get; set; }
}
}

View File

@@ -1,3 +1,4 @@
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Popups;
using Content.Server.UserInterface;
@@ -90,7 +91,7 @@ namespace Content.Server.Paper
if (paperComp.StampedBy.Count > 0)
{
var commaSeparated = string.Join(", ", paperComp.StampedBy);
var commaSeparated = string.Join(", ", paperComp.StampedBy.Select(s => Loc.GetString(s.StampedName)));
args.PushMarkup(
Loc.GetString(
"paper-component-examine-detail-stamped-by", ("paper", uid), ("stamps", commaSeparated))
@@ -114,13 +115,15 @@ namespace Content.Server.Paper
}
// If a stamp, attempt to stamp paper
if (TryComp<StampComponent>(args.Used, out var stampComp) && TryStamp(uid, stampComp.StampedName, stampComp.StampState, paperComp))
if (TryComp<StampComponent>(args.Used, out var stampComp) && TryStamp(uid, GetStampInfo(stampComp), stampComp.StampState, paperComp))
{
// successfully stamped, play popup
var stampPaperOtherMessage = Loc.GetString("paper-component-action-stamp-paper-other", ("user", Identity.Entity(args.User, EntityManager)), ("target", Identity.Entity(args.Target, EntityManager)), ("stamp", args.Used));
_popupSystem.PopupEntity(stampPaperOtherMessage, args.User, Filter.PvsExcept(args.User, entityManager: EntityManager), true);
var stampPaperOtherMessage = Loc.GetString("paper-component-action-stamp-paper-other",
("user", args.User), ("target", args.Target), ("stamp", args.Used));
var stampPaperSelfMessage = Loc.GetString("paper-component-action-stamp-paper-self", ("target", Identity.Entity(args.Target, EntityManager)), ("stamp", args.Used));
_popupSystem.PopupEntity(stampPaperOtherMessage, args.User, Filter.PvsExcept(args.User, entityManager: EntityManager), true);
var stampPaperSelfMessage = Loc.GetString("paper-component-action-stamp-paper-self",
("target", args.Target), ("stamp", args.Used));
_popupSystem.PopupEntity(stampPaperSelfMessage, args.User, args.User);
_audio.PlayPvs(stampComp.Sound, uid);
@@ -129,6 +132,14 @@ namespace Content.Server.Paper
}
}
private StampDisplayInfo GetStampInfo(StampComponent stamp)
{
return new StampDisplayInfo {
StampedName = stamp.StampedName,
StampedColor = stamp.StampedColor
};
}
private void OnInputTextMessage(EntityUid uid, PaperComponent paperComp, PaperInputTextMessage args)
{
if (string.IsNullOrEmpty(args.Text))
@@ -161,17 +172,19 @@ namespace Content.Server.Paper
/// <summary>
/// Accepts the name and state to be stamped onto the paper, returns true if successful.
/// </summary>
public bool TryStamp(EntityUid uid, string stampName, string stampState, PaperComponent? paperComp = null)
public bool TryStamp(EntityUid uid, StampDisplayInfo stampInfo, string spriteStampState, PaperComponent? paperComp = null)
{
if (!Resolve(uid, ref paperComp))
return false;
if (!paperComp.StampedBy.Contains(Loc.GetString(stampName)))
if (!paperComp.StampedBy.Contains(stampInfo))
{
paperComp.StampedBy.Add(Loc.GetString(stampName));
paperComp.StampedBy.Add(stampInfo);
if (paperComp.StampState == null && TryComp<AppearanceComponent>(uid, out var appearance))
{
paperComp.StampState = stampState;
paperComp.StampState = spriteStampState;
// Would be nice to be able to display multiple sprites on the paper
// but most of the existing images overlap
_appearance.SetData(uid, PaperVisuals.Stamp, paperComp.StampState, appearance);
}
}

View File

@@ -1,4 +1,4 @@
using Content.Shared.Eui;
using Content.Shared.Eui;
using Robust.Shared.Serialization;
namespace Content.Shared.Fax;
@@ -55,14 +55,16 @@ public static class AdminFaxEuiMsg
public string From { get; }
public string Content { get; }
public string StampState { get; }
public Color StampColor { get; }
public Send(EntityUid target, string title, string from, string content, string stamp)
public Send(EntityUid target, string title, string from, string content, string stamp, Color stampColor)
{
Target = target;
Title = title;
From = from;
Content = content;
StampState = stamp;
StampColor = stampColor;
}
}
}

View File

@@ -1,17 +1,17 @@
using Robust.Shared.Serialization;
namespace Content.Shared.Paper
{
namespace Content.Shared.Paper;
public abstract class SharedPaperComponent : Component
{
[Serializable, NetSerializable]
public sealed class PaperBoundUserInterfaceState : BoundUserInterfaceState
{
public readonly string Text;
public readonly List<string> StampedBy;
public readonly List<StampDisplayInfo> StampedBy;
public readonly PaperAction Mode;
public PaperBoundUserInterfaceState(string text, List<string> stampedBy, PaperAction mode = PaperAction.Read)
public PaperBoundUserInterfaceState(string text, List<StampDisplayInfo> stampedBy, PaperAction mode = PaperAction.Read)
{
Text = text;
StampedBy = stampedBy;
@@ -57,4 +57,3 @@ namespace Content.Shared.Paper
Written
}
}
}

View File

@@ -1,7 +1,29 @@
using Robust.Shared.Serialization;
using Robust.Shared.Audio;
namespace Content.Shared.Paper
namespace Content.Shared.Paper;
/// <summary>
/// Set of required information to draw a stamp in UIs, where
/// representing the state of the stamp at the point in time
/// when it was applied to a paper. These fields mirror the
/// equivalent in the component.
/// </summary>
[DataDefinition, Serializable, NetSerializable]
public struct StampDisplayInfo
{
StampDisplayInfo(string s)
{
StampedName = s;
}
[DataField("stampedName")]
public string StampedName;
[DataField("stampedColor")]
public Color StampedColor;
};
[RegisterComponent]
public sealed class StampComponent : Component
{
@@ -16,10 +38,15 @@ namespace Content.Shared.Paper
[DataField("stampState")]
public string StampState { get; set; } = "paper_stamp-generic";
/// <summary>
/// The color of the ink used by the stamp in UIs
/// </summary>
[DataField("stampedColor")]
public Color StampedColor = Color.FromHex("#BB3232"); // StyleNano.DangerousRedFore
[DataField("sound")]
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Items/Stamp/thick_stamp_sub.ogg")
{
Params = AudioParams.Default.WithVolume(-2f).WithMaxDistance(5f)
};
}
}

View File

@@ -1,4 +1,4 @@
# Command
# Command
cmd-faxui-desc = Open admin window for sending faxes
cmd-faxui-help = Usage: faxui
@@ -7,7 +7,8 @@ admin-fax-title = Admin Fax Manager
admin-fax-fax = Fax:
admin-fax-follow = Follow
admin-fax-title-placeholder = Paper name...
admin-fax-from-placeholder = From who...
admin-fax-from-placeholder = Stamped by...
admin-fax-message-placeholder = Your message here...
admin-fax-stamp = Stamp:
admin-fax-stamp = Stamp icon:
admin-fax-stamp-color = Stamp color:
admin-fax-send = Send

View File

@@ -91310,7 +91310,8 @@ entities:
type: Transform
- stampState: paper_stamp-syndicate
stampedBy:
- Syndicate
- stampedName: stamp-component-stamped-name-syndicate
stampedColor: '#850000'
content: >-
Operative, i have succeeded in the mission and this is the remainder of the evidence. I am hiding it behind this wall and escaping ASAP.

View File

@@ -421,6 +421,7 @@
- type: Stamp
stampedName: stamp-component-stamped-name-default
stampState: "paper_stamp-generic"
stampedColor: "#a23e3e"
sound:
path: /Audio/Items/Stamp/thick_stamp_sub.ogg
params:
@@ -454,6 +455,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-captain
stampedColor: "#3681bb"
stampState: "paper_stamp-cap"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -466,6 +468,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-centcom
stampedColor: "#006600"
stampState: "paper_stamp-centcom"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -478,6 +481,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-chaplain
stampedColor: "#d70601"
stampState: "paper_stamp-chaplain"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -490,6 +494,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-clown
stampedColor: "#ff33cc"
stampState: "paper_stamp-clown"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -505,6 +510,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-ce
stampedColor: "#c69b17"
stampState: "paper_stamp-ce"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -517,6 +523,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-cmo
stampedColor: "#33ccff"
stampState: "paper_stamp-cmo"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -529,6 +536,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-hop
stampedColor: "#6ec0ea"
stampState: "paper_stamp-hop"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -541,6 +549,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-hos
stampedColor: "#cc0000"
stampState: "paper_stamp-hos"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -553,6 +562,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-mime
stampedColor: "#777777"
stampState: "paper_stamp-mime"
# TODO remove sound from mime's rubber stamp
- type: Sprite
@@ -566,6 +576,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-qm
stampedColor: "#a23e3e"
stampState: "paper_stamp-qm"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -578,6 +589,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-rd
stampedColor: "#1f66a0"
stampState: "paper_stamp-rd"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -590,6 +602,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-trader
stampedColor: "#000000"
stampState: "paper_stamp-trader"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -602,6 +615,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-syndicate
stampedColor: "#850000"
stampState: "paper_stamp-syndicate"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -614,6 +628,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-warden
stampedColor: "#5b0000"
stampState: "paper_stamp-warden"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -626,6 +641,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-approved
stampedColor: "#00be00"
stampState: "paper_stamp-ok"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
@@ -638,6 +654,7 @@
components:
- type: Stamp
stampedName: stamp-component-stamped-name-denied
stampedColor: "#a23e3e"
stampState: "paper_stamp-deny"
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi

View File

@@ -71,3 +71,8 @@
id: Stealth
kind: source
path: "/Textures/Shaders/stealth.swsl"
- type: shader
id: PaperStamp
kind: source
path: "/Textures/Shaders/paperstamp.swsl"

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="35.0625"
height="34"
viewBox="0 0 35.0625 34"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="paper_stamp_border.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
inkscape:export-filename="paper_stamp_border.svg.96dpi.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8">
<inkscape:path-effect
effect="powerclip"
id="path-effect302"
is_visible="true"
lpeversion="1"
inverse="true"
flatten="false"
hide_clip="false"
message="Use fill-rule evenodd on &lt;b&gt;fill and stroke&lt;/b&gt; dialog if no flatten result after convert clip to paths." />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath298">
<rect
x="2.6084003"
y="2.5943766"
width="26.783199"
height="26.811247"
rx="4.1848745"
fill="#ffffff"
id="rect300"
style="display:none;stroke-width:0.837413"
d="M 6.7932749,2.5943766 H 25.206725 c 2.318421,0 4.184875,1.866454 4.184875,4.1848745 V 25.220749 c 0,2.31842 -1.866454,4.184874 -4.184875,4.184874 H 6.7932749 c -2.3184205,0 -4.1848746,-1.866454 -4.1848746,-4.184874 V 6.7792511 c 0,-2.3184205 1.8664541,-4.1848745 4.1848746,-4.1848745 z" />
<path
id="lpe_path-effect302"
style="stroke-width:0.837413"
class="powerclip"
d="M -5,-5 H 37 V 37 H -5 Z M 6.7932749,2.5943766 c -2.3184205,0 -4.1848746,1.866454 -4.1848746,4.1848745 V 25.220749 c 0,2.31842 1.8664541,4.184874 4.1848746,4.184874 H 25.206725 c 2.318421,0 4.184875,-1.866454 4.184875,-4.184874 V 6.7792511 c 0,-2.3184205 -1.866454,-4.1848745 -4.184875,-4.1848745 z" />
</clipPath>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1916"
inkscape:window-height="1034"
id="namedview6"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="15.527471"
inkscape:cx="6.7300077"
inkscape:cy="17.16313"
inkscape:window-x="0"
inkscape:window-y="44"
inkscape:window-maximized="0"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1" />
<path
x="0"
y="0"
width="32"
height="32"
rx="5"
fill="#ffffff"
id="rect2"
clip-path="url(#clipPath298)"
inkscape:path-effect="#path-effect302"
d="m 5,0 h 22 c 2.77,0 5,2.23 5,5 v 22 c 0,2.77 -2.23,5 -5,5 H 5 C 2.23,32 0,29.77 0,27 V 5 C 0,2.23 2.23,0 5,0 Z"
sodipodi:type="rect"
transform="translate(1,1)" />
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

View File

@@ -0,0 +1,53 @@
// Object position in screen space. Allows the noise to
// have a constant screen-space size, without being
// affected by the widget layout/position.
uniform highp vec2 objCoord;
// Magic, well-known 2d random function; makes perlin-like noise
highp vec2 random(highp vec2 uv){
uv = vec2( dot(uv, vec2(127.1,311.7) ),
dot(uv, vec2(269.5,183.3) ) );
return -1.0 + 2.0 * fract(sin(uv) * 43758.5453123);
}
highp float noise(highp vec2 uv) {
highp vec2 uv_i = floor(uv);
highp vec2 uv_f = fract(uv);
highp vec2 t = smoothstep(0.0, 1.0, uv_f);
// Sample the random function and run a bilinear filter to smooth it out
highp float tl = dot( random(uv_i + vec2(0.0,0.0) ), uv_f - vec2(0.0,0.0) );
highp float tr = dot( random(uv_i + vec2(1.0,0.0) ), uv_f - vec2(1.0,0.0) );
highp float bl = dot( random(uv_i + vec2(0.0,1.0) ), uv_f - vec2(0.0,1.0) );
highp float br = dot( random(uv_i + vec2(1.0,1.0) ), uv_f - vec2(1.0,1.0) );
highp float tA = mix( tl, tr, t.x );
highp float tB = mix( bl, br, t.x );
return mix( tA, tB, t.y ) + 0.5;
}
void fragment() {
// Stamps have orientation, and the texture sampling is nearest
// pixel, so run a bilinear filter to smooth out the edges.
{
highp vec4 tl = texture2D(TEXTURE, UV);
highp vec4 tr = texture2D(TEXTURE, UV + vec2(TEXTURE_PIXEL_SIZE.x, 0.0));
highp vec4 bl = texture2D(TEXTURE, UV + vec2(0.0, TEXTURE_PIXEL_SIZE.y));
highp vec4 br = texture2D(TEXTURE, UV + TEXTURE_PIXEL_SIZE);
highp vec2 textureSize = 1.0 / TEXTURE_PIXEL_SIZE;
highp vec2 f = fract( UV * textureSize );
highp vec4 tA = mix( tl, tr, f.x );
highp vec4 tB = mix( bl, br, f.x );
COLOR = mix( tA, tB, f.y );
}
// Add a bit of noise to mimic imperfect contact with the paper
{
float stampNoise = noise((FRAGCOORD.xy - objCoord) * vec2(0.03, 0.03)) *
noise((FRAGCOORD.xy - objCoord) * vec2(0.08, 0.08));
COLOR.a *= min(0.9, 0.4 + smoothstep(0.05, 0.3, stampNoise));
}
}