From bda5f8248fec17960c290e5e07ff2ccfa1666541 Mon Sep 17 00:00:00 2001 From: eoineoineoin Date: Tue, 17 Jan 2023 08:32:46 +0000 Subject: [PATCH] Improve Paper UI, allow an to entity configure how it's UI looks (#13494) Co-authored-by: Eoin Mcloughlin --- .../Paper/UI/PaperBoundUserInterface.cs | 14 +- .../Paper/UI/PaperVisualsComponent.cs | 95 ++++++- Content.Client/Paper/UI/PaperWindow.xaml | 39 ++- Content.Client/Paper/UI/PaperWindow.xaml.cs | 220 ++++++++++++++- Content.Client/Paper/UI/StampWidget.xaml | 31 +++ Content.Client/Paper/UI/StampWidget.xaml.cs | 23 ++ Content.Client/Stylesheets/StyleNano.cs | 18 ++ .../Cargo/Components/CargoTelepadComponent.cs | 2 +- .../Cargo/Systems/CargoSystem.Shuttle.cs | 2 +- Content.Server/Fax/FaxConstants.cs | 3 +- Content.Server/Fax/FaxMachineComponent.cs | 14 +- Content.Server/Fax/FaxSystem.cs | 20 +- Content.Server/Nuke/NukeCodePaperSystem.cs | 5 +- Content.Server/Paper/PaperSystem.cs | 2 +- .../Cargo/Components/CargoShuttleComponent.cs | 9 + Content.Shared/Paper/SharedPaperComponent.cs | 4 +- .../Locale/en-US/paper/paper-component.ftl | 2 + .../Entities/Objects/Misc/books.yml | 6 +- .../Entities/Objects/Misc/paper.yml | 100 ++++++- .../Machines/Computers/computers.yml | 1 + .../Machines/Medical/disease_diagnoser.yml | 33 ++- .../Textures/Interface/Nano/lined_paper.svg | 77 ++++++ .../Interface/Nano/lined_paper.svg.96dpi.png | Bin 0 -> 152 bytes .../Interface/Paper/paper_background_book.svg | 143 ++++++++++ .../Paper/paper_background_book.svg.96dpi.png | Bin 0 -> 635 bytes .../Paper/paper_background_default.svg | 70 +++++ .../paper_background_default.svg.96dpi.png | Bin 0 -> 1109 bytes .../Paper/paper_background_dotmatrix.svg | 214 +++++++++++++++ .../paper_background_dotmatrix.svg.96dpi.png | Bin 0 -> 702 bytes .../Paper/paper_background_perforated.svg | 73 +++++ .../paper_background_perforated.svg.96dpi.png | Bin 0 -> 206 bytes .../Paper/paper_content_dotmatrix.svg | 91 +++++++ .../paper_content_dotmatrix.svg.96dpi.png | Bin 0 -> 176 bytes .../Interface/Paper/paper_content_lined.svg | 77 ++++++ .../Paper/paper_content_lined.svg.96dpi.png | Bin 0 -> 153 bytes .../Paper/paper_heading_artifact_analyzer.svg | 256 ++++++++++++++++++ ...er_heading_artifact_analyzer.svg.96dpi.png | Bin 0 -> 5657 bytes .../Paper/paper_heading_captains_thoughts.svg | 187 +++++++++++++ ...er_heading_captains_thoughts.svg.96dpi.png | Bin 0 -> 7596 bytes .../Paper/paper_heading_cargo_invoice.svg | 233 ++++++++++++++++ .../paper_heading_cargo_invoice.svg.96dpi.png | Bin 0 -> 5181 bytes .../Interface/Paper/paper_heading_virus.svg | 177 ++++++++++++ .../Paper/paper_heading_virus.svg.96dpi.png | Bin 0 -> 5097 bytes .../Objects/Misc/bureaucracy.rsi/meta.json | 18 +- .../Misc/bureaucracy.rsi/paper_dotmatrix.png | Bin 0 -> 215 bytes .../bureaucracy.rsi/paper_dotmatrix_words.png | Bin 0 -> 321 bytes .../Misc/bureaucracy.rsi/paper_receipt.png | Bin 0 -> 202 bytes .../bureaucracy.rsi/paper_receipt_words.png | Bin 0 -> 264 bytes 48 files changed, 2212 insertions(+), 47 deletions(-) create mode 100644 Content.Client/Paper/UI/StampWidget.xaml create mode 100644 Content.Client/Paper/UI/StampWidget.xaml.cs create mode 100644 Resources/Textures/Interface/Nano/lined_paper.svg create mode 100644 Resources/Textures/Interface/Nano/lined_paper.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_background_book.svg create mode 100644 Resources/Textures/Interface/Paper/paper_background_book.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_background_default.svg create mode 100644 Resources/Textures/Interface/Paper/paper_background_default.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_background_dotmatrix.svg create mode 100644 Resources/Textures/Interface/Paper/paper_background_dotmatrix.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_background_perforated.svg create mode 100644 Resources/Textures/Interface/Paper/paper_background_perforated.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_content_dotmatrix.svg create mode 100644 Resources/Textures/Interface/Paper/paper_content_dotmatrix.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_content_lined.svg create mode 100644 Resources/Textures/Interface/Paper/paper_content_lined.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_heading_artifact_analyzer.svg create mode 100644 Resources/Textures/Interface/Paper/paper_heading_artifact_analyzer.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_heading_captains_thoughts.svg create mode 100644 Resources/Textures/Interface/Paper/paper_heading_captains_thoughts.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_heading_cargo_invoice.svg create mode 100644 Resources/Textures/Interface/Paper/paper_heading_cargo_invoice.svg.96dpi.png create mode 100644 Resources/Textures/Interface/Paper/paper_heading_virus.svg create mode 100644 Resources/Textures/Interface/Paper/paper_heading_virus.svg.96dpi.png create mode 100644 Resources/Textures/Objects/Misc/bureaucracy.rsi/paper_dotmatrix.png create mode 100644 Resources/Textures/Objects/Misc/bureaucracy.rsi/paper_dotmatrix_words.png create mode 100644 Resources/Textures/Objects/Misc/bureaucracy.rsi/paper_receipt.png create mode 100644 Resources/Textures/Objects/Misc/bureaucracy.rsi/paper_receipt_words.png diff --git a/Content.Client/Paper/UI/PaperBoundUserInterface.cs b/Content.Client/Paper/UI/PaperBoundUserInterface.cs index b6804c1238..1088aee02b 100644 --- a/Content.Client/Paper/UI/PaperBoundUserInterface.cs +++ b/Content.Client/Paper/UI/PaperBoundUserInterface.cs @@ -19,14 +19,18 @@ namespace Content.Client.Paper.UI protected override void Open() { base.Open(); - _window = new PaperWindow - { - Title = IoCManager.Resolve().GetComponent(Owner.Owner).EntityName, - }; + var entityMgr = IoCManager.Resolve(); + + _window = new PaperWindow(); _window.OnClose += Close; _window.Input.OnTextEntered += Input_OnTextEntered; - _window.OpenCentered(); + if (entityMgr.TryGetComponent(Owner.Owner, out var visuals)) + { + _window.InitVisuals(visuals); + } + + _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Paper/UI/PaperVisualsComponent.cs b/Content.Client/Paper/UI/PaperVisualsComponent.cs index 38c987e7a6..fb6126b77e 100644 --- a/Content.Client/Paper/UI/PaperVisualsComponent.cs +++ b/Content.Client/Paper/UI/PaperVisualsComponent.cs @@ -1,6 +1,99 @@ -namespace Content.Client.Paper; +namespace Content.Client.Paper; [RegisterComponent] public sealed class PaperVisualsComponent : Component { + /// + /// The path to the image which will be used as a background for the paper itself + /// + [DataField("backgroundImagePath")] + public string? BackgroundImagePath; + + /// + /// An optional patch to configure tiling stretching of the background. Used to set + /// the PatchMargin in a StyleBoxTexture + /// + [DataField("backgroundPatchMargin")] + public Box2 BackgroundPatchMargin = default; + + /// + /// Modulate the background image by this color. Can be used to add colorful + /// variants of images, without having to create new textures. + /// + [DataField("backgroundModulate")] + public Color BackgroundModulate = Color.White; + + /// + /// Should the background image tile, or be streched? Sets StyleBoxTexture.StrechMode + /// + [DataField("backgroundImageTile")] + public bool BackgroundImageTile = false; + + /// + /// An additional scale to apply to the background image + /// + [DataField("backgroundScale")] + public Vector2 BackgroundScale = Vector2.One; + + /// + /// A path to an image which will be used as a header on the paper + /// + [DataField("headerImagePath")] + public string? HeaderImagePath; + + /// + /// Modulate the header image by this color + /// + [DataField("headerImageModulate")] + public Color HeaderImageModulate = Color.White; + + /// + /// Any additional margin to add around the header + /// + [DataField("headerMargin")] + public Box2 HeaderMargin = default; + + /// + /// Path to an image to use as the background to the "content" of the paper + /// The header and actual written text will use this as a background. The + /// image will be tiled vertically with the property that the bottom of the + /// written text will line up with the bottom of this image. + /// + [DataField("contentImagePath")] + public string? ContentImagePath; + + /// + /// Modulate the content image by this color + /// + [DataField("contentImageModulate")] + public Color ContentImageModulate = Color.White; + + /// + /// An additional margin around the content (including header) + /// + [DataField("contentMargin")] + public Box2 ContentMargin = default; + + /// + /// The number of lines that the content image represents. The + /// content image will be vertically tiled after this many lines + /// of text. + /// + [DataField("contentImageNumLines")] + public int ContentImageNumLines = 1; + + /// + /// Modulate the style's font by this color + /// + [DataField("fontAccentColor")] + public Color FontAccentColor = new Color(0x25, 0x25, 0x2a); + + /// + /// This can enforce that your paper has a limited area to write in. + /// If you wish to constrain only one direction, the other direction + /// can be unlimited by specifying a value of zero. + /// This will be scaled according to UI scale. + /// + [DataField("maxWritableArea")] + public Vector2? MaxWritableArea = null; } diff --git a/Content.Client/Paper/UI/PaperWindow.xaml b/Content.Client/Paper/UI/PaperWindow.xaml index f1b875c228..60f4e36e00 100644 --- a/Content.Client/Paper/UI/PaperWindow.xaml +++ b/Content.Client/Paper/UI/PaperWindow.xaml @@ -1,10 +1,31 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Content.Client/Paper/UI/PaperWindow.xaml.cs b/Content.Client/Paper/UI/PaperWindow.xaml.cs index ee99882c20..218a3c2d7e 100644 --- a/Content.Client/Paper/UI/PaperWindow.xaml.cs +++ b/Content.Client/Paper/UI/PaperWindow.xaml.cs @@ -1,6 +1,7 @@ -using Content.Shared.Paper; +using Content.Shared.Paper; using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface.Controls; +using Robust.Client.Graphics; +using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Utility; @@ -8,22 +9,223 @@ using Robust.Shared.Utility; namespace Content.Client.Paper.UI { [GenerateTypedNameReferences] - public sealed partial class PaperWindow : DefaultWindow + public sealed partial class PaperWindow : BaseWindow { + // + // Size of resize handles around the paper + private const int DRAG_MARGIN_SIZE = 16; + + // We keep a reference to the paper content texture that we create + // so that we can modify it later. + private StyleBoxTexture _paperContentTex = new(); + + // The number of lines that the content image represents. + // See PaperVisualsComponent.ContentImageNumLines. + private float _paperContentLineScale = 1.0f; + + // If paper limits the size in one or both axes, it'll affect whether + // we're able to resize this UI or not. Default to everything enabled: + private DragMode _allowedResizeModes = ~DragMode.None; + public PaperWindow() { RobustXamlLoader.Load(this); + + // We can't configure the RichTextLabel contents from xaml, so do it here: + BlankPaperIndicator.SetMessage(Loc.GetString("paper-ui-blank-page-message")); + + // Hook up the close button: + CloseButton.OnPressed += _ => Close(); } + /// + /// Initialize this UI according to visuals Initializes + /// textures, recalculates sizes, and applies some layout rules. + /// + public void InitVisuals(PaperVisualsComponent visuals) + { + var resCache = IoCManager.Resolve(); + + /// Initialize the background: + PaperBackground.ModulateSelfOverride = visuals.BackgroundModulate; + var backgroundImage = visuals.BackgroundImagePath != null? resCache.GetResource(visuals.BackgroundImagePath) : null; + if (backgroundImage != null) + { + var backgroundImageMode = visuals.BackgroundImageTile ? StyleBoxTexture.StretchMode.Tile : StyleBoxTexture.StretchMode.Stretch; + var backgroundPatchMargin = visuals.BackgroundPatchMargin; + PaperBackground.PanelOverride = new StyleBoxTexture + { + Texture = backgroundImage, + TextureScale = visuals.BackgroundScale, + Mode = backgroundImageMode, + PatchMarginLeft = backgroundPatchMargin.Left, + PatchMarginBottom = backgroundPatchMargin.Bottom, + PatchMarginRight = backgroundPatchMargin.Right, + PatchMarginTop = backgroundPatchMargin.Top + }; + + } + else + { + PaperBackground.PanelOverride = null; + } + + + // Then the header: + if (visuals.HeaderImagePath != null) + { + HeaderImage.TexturePath = visuals.HeaderImagePath; + HeaderImage.MinSize = HeaderImage.TextureNormal?.Size ?? Vector2.Zero; + } + + HeaderImage.ModulateSelfOverride = visuals.HeaderImageModulate; + HeaderImage.Margin = new Thickness(visuals.HeaderMargin.Left, visuals.HeaderMargin.Top, + visuals.HeaderMargin.Right, visuals.HeaderMargin.Bottom); + + + PaperContent.ModulateSelfOverride = visuals.ContentImageModulate; + WrittenTextLabel.ModulateSelfOverride = visuals.FontAccentColor; + + var contentImage = visuals.ContentImagePath != null ? resCache.GetResource(visuals.ContentImagePath) : null; + if (contentImage != null) + { + // Setup the paper content texture, but keep a reference to it, as we can't set + // some font-related properties here. We'll fix those up later, in Draw() + _paperContentTex = new StyleBoxTexture + { + Texture = contentImage, + Mode = StyleBoxTexture.StretchMode.Tile, + }; + PaperContent.PanelOverride = _paperContentTex; + _paperContentLineScale = visuals.ContentImageNumLines; + } + + PaperContent.Margin = new Thickness( + visuals.ContentMargin.Left, visuals.ContentMargin.Top, + visuals.ContentMargin.Right, visuals.ContentMargin.Bottom); + + if (visuals.MaxWritableArea != null) + { + var a = (Vector2)visuals.MaxWritableArea; + // Paper has requested that this has a maximum area that you can write on. + // So, we'll make the window non-resizable and fix the size of the content. + // Ideally, would like to be able to allow resizing only one direction. + ScrollingContents.MinSize = Vector2.Zero; + ScrollingContents.MinSize = (Vector2)(a); + + if (a.X > 0.0f) + { + ScrollingContents.MaxWidth = a.X; + _allowedResizeModes &= ~(DragMode.Left | DragMode.Right); + + // Since this dimension has been specified by the user, we + // need to undo the SetSize which was configured in the xaml. + // Controls use NaNs to indicate unset for this value. + // This is leaky - there should be a method for this + SetWidth = float.NaN; + } + + if (a.Y > 0.0f) + { + ScrollingContents.MaxHeight = a.Y; + _allowedResizeModes &= ~(DragMode.Top | DragMode.Bottom); + SetHeight = float.NaN; + } + } + } + + /// + /// Control interface. We'll mostly rely on the children to do the drawing + /// but in order to get lines on paper to match up with the rich text labels, + /// we need to do a small calculation to sync them up. + /// + protected override void Draw(DrawingHandleScreen handle) + { + // Now do the deferred setup of the written area. At the point + // that InitVisuals runs, the label hasn't had it's style initialized + // so we need to get some info out now: + if (WrittenTextLabel.TryGetStyleProperty("font", out var font)) + { + float fontLineHeight = font.GetLineHeight(UIScale); + // This positions the texture so the font baseline is on the bottom: + _paperContentTex.ExpandMarginTop = font.GetDescent(UIScale); + // And this scales the texture so that it's a single text line: + var scaleY = (_paperContentLineScale * fontLineHeight) / _paperContentTex.Texture?.Height ?? fontLineHeight; + _paperContentTex.TextureScale = new Vector2(1, scaleY); + + // Now, we might need to add some padding to the text to ensure + // that, even if a header is specified, the text will line up with + // where the content image expects the font to be rendered (i.e., + // adjusting the height of the header image shouldn't cause the + // text to be offset from a line) + { + var headerHeight = HeaderImage.Size.Y + HeaderImage.Margin.Top + HeaderImage.Margin.Bottom; + var headerInLines = headerHeight / (fontLineHeight * _paperContentLineScale); + var paddingRequiredInLines = (float)Math.Ceiling(headerInLines) - headerInLines; + var verticalMargin = fontLineHeight * paddingRequiredInLines * _paperContentLineScale; + TextAlignmentPadding.Margin = new Thickness(0.0f, verticalMargin, 0.0f, 0.0f); + } + } + + base.Draw(handle); + } + + /// + /// Initialize the paper contents, i.e. the text typed by the + /// user and any stamps that have peen put on the page. + /// public void Populate(SharedPaperComponent.PaperBoundUserInterfaceState state) { - if (state.Mode == SharedPaperComponent.PaperAction.Write) - { - Input.Visible = true; - } + bool isEditing = state.Mode == SharedPaperComponent.PaperAction.Write; + InputContainer.Visible = isEditing; + var msg = new FormattedMessage(); - msg.AddMarkupPermissive(state.Text); - Label.SetMessage(msg); + // Remove any newlines from the end of the message. There can be a trailing + // new line at the end of user input, and we would like to display the input + // box immediately on the next line. + msg.AddMarkupPermissive(state.Text.TrimEnd('\r', '\n')); + WrittenTextLabel.SetMessage(msg); + WrittenTextLabel.Visible = state.Text.Length > 0; + + BlankPaperIndicator.Visible = !isEditing && state.Text.Length == 0; + + StampDisplay.RemoveAllChildren(); + foreach(var stamper in state.StampedBy) + { + StampDisplay.AddChild(new StampWidget{ Stamper = stamper }); + } + } + + /// + /// BaseWindow interface. Allow users to drag UI around by grabbing + /// anywhere on the page (like FancyWindow) but try to calculate + /// reasonable dragging bounds because this UI can have round corners, + /// and it can be hard to judge where to click to resize. + /// + protected override DragMode GetDragModeFor(Vector2 relativeMousePos) + { + var mode = DragMode.Move; + + // Be quite generous with resize margins: + if (relativeMousePos.Y < DRAG_MARGIN_SIZE) + { + mode |= DragMode.Top; + } + else if (relativeMousePos.Y > Size.Y - DRAG_MARGIN_SIZE) + { + mode |= DragMode.Bottom; + } + + if (relativeMousePos.X < DRAG_MARGIN_SIZE) + { + mode |= DragMode.Left; + } + else if (relativeMousePos.X > Size.X - DRAG_MARGIN_SIZE) + { + mode |= DragMode.Right; + } + + return mode & _allowedResizeModes; } } } diff --git a/Content.Client/Paper/UI/StampWidget.xaml b/Content.Client/Paper/UI/StampWidget.xaml new file mode 100644 index 0000000000..5aeb9788fd --- /dev/null +++ b/Content.Client/Paper/UI/StampWidget.xaml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + diff --git a/Content.Client/Paper/UI/StampWidget.xaml.cs b/Content.Client/Paper/UI/StampWidget.xaml.cs new file mode 100644 index 0000000000..a6c6b3232c --- /dev/null +++ b/Content.Client/Paper/UI/StampWidget.xaml.cs @@ -0,0 +1,23 @@ +using Content.Shared.Paper; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Utility; + +namespace Content.Client.Paper.UI +{ + [GenerateTypedNameReferences] + public sealed partial class StampWidget : Container + { + public string? Stamper { + get => StampedByLabel.Text; + set => StampedByLabel.Text = value; + } + + public StampWidget() + { + RobustXamlLoader.Load(this); + } + } +} diff --git a/Content.Client/Stylesheets/StyleNano.cs b/Content.Client/Stylesheets/StyleNano.cs index cb937b0c5c..b329f0d550 100644 --- a/Content.Client/Stylesheets/StyleNano.cs +++ b/Content.Client/Stylesheets/StyleNano.cs @@ -485,6 +485,14 @@ namespace Content.Client.Stylesheets }; insetBack.SetPatchMargin(StyleBox.Margin.All, 10); + // Default paper background: + var paperBackground = new StyleBoxTexture + { + Texture = resCache.GetTexture("/Textures/Interface/Paper/paper_background_default.svg.96dpi.png"), + Modulate = Color.FromHex("#eaedde"), // A light cream + }; + paperBackground.SetPatchMargin(StyleBox.Margin.All, 16.0f); + var contextMenuExpansionTexture = resCache.GetTexture("/Textures/Interface/VerbIcons/group.svg.192dpi.png"); var verbMenuConfirmationTexture = resCache.GetTexture("/Textures/Interface/VerbIcons/group.svg.192dpi.png"); @@ -1323,6 +1331,16 @@ namespace Content.Client.Stylesheets .Prop(Control.StylePropertyModulateSelf, Color.FromHex("#753131")), // --- + // The default look of paper in UIs. Pages can have components which override this + Element().Class("PaperDefaultBorder") + .Prop(PanelContainer.StylePropertyPanel, paperBackground), + Element().Class("PaperWrittenText") + .Prop(Label.StylePropertyFont, notoSans12) + .Prop(Control.StylePropertyModulateSelf, Color.FromHex("#111111")), + + Element().Class("PaperLineEdit") + .Prop(LineEdit.StylePropertyStyleBox, new StyleBoxEmpty()), + // Red Button --- Element [DataField("printerOutput", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string PrinterOutput = "Paper"; + public string PrinterOutput = "PaperCargoInvoice"; [DataField("receiverPort", customTypeSerializer: typeof(PrototypeIdSerializer))] public string ReceiverPort = "OrderReceiver"; diff --git a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs index 8e1e6d89b8..e29ef550d1 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs @@ -465,7 +465,7 @@ public sealed partial class CargoSystem return; // spawn a piece of paper. - var printed = EntityManager.SpawnEntity("Paper", coordinates); + var printed = EntityManager.SpawnEntity(component.PrinterOutput, coordinates); if (!TryComp(printed, out var paper)) return; diff --git a/Content.Server/Fax/FaxConstants.cs b/Content.Server/Fax/FaxConstants.cs index 6ca12c4e52..102510bd46 100644 --- a/Content.Server/Fax/FaxConstants.cs +++ b/Content.Server/Fax/FaxConstants.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Fax; +namespace Content.Server.Fax; public static class FaxConstants { @@ -23,6 +23,7 @@ public static class FaxConstants public const string FaxNameData = "fax_data_name"; public const string FaxPaperNameData = "fax_data_title"; + public const string FaxPaperPrototypeData = "fax_data_prototype"; public const string FaxPaperContentData = "fax_data_content"; public const string FaxPaperStampStateData = "fax_data_stamp_state"; public const string FaxPaperStampedByData = "fax_data_stamped_by"; diff --git a/Content.Server/Fax/FaxMachineComponent.cs b/Content.Server/Fax/FaxMachineComponent.cs index 1e7b8adc1a..07402aefc8 100644 --- a/Content.Server/Fax/FaxMachineComponent.cs +++ b/Content.Server/Fax/FaxMachineComponent.cs @@ -1,5 +1,7 @@ using Content.Shared.Containers.ItemSlots; using Robust.Shared.Audio; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Fax; @@ -33,21 +35,21 @@ public sealed class FaxMachineComponent : Component [ViewVariables(VVAccess.ReadWrite)] [DataField("responsePings")] public bool ResponsePings { get; set; } = true; - + /// /// Should admins be notified on message receive /// [ViewVariables(VVAccess.ReadWrite)] [DataField("notifyAdmins")] public bool NotifyAdmins { get; set; } = false; - + /// /// Should that fax receive nuke codes send by admins. Probably should be captain fax only /// [ViewVariables(VVAccess.ReadWrite)] [DataField("receiveNukeCodes")] public bool ReceiveNukeCodes { get; set; } = false; - + /// /// Is fax was emaaged /// @@ -134,16 +136,20 @@ public sealed class FaxPrintout [DataField("content")] public string Content { get; } + [DataField("prototypeId", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string PrototypeId { get; } + [DataField("stampState")] public string? StampState { get; } [DataField("stampedBy")] public List StampedBy { get; } - public FaxPrintout(string content, string name, string? stampState = null, List? stampedBy = null) + public FaxPrintout(string content, string name, string? prototypeId, string? stampState = null, List? stampedBy = null) { Content = content; Name = name; + PrototypeId = prototypeId ?? ""; StampState = stampState; StampedBy = stampedBy ?? new List(); } diff --git a/Content.Server/Fax/FaxSystem.cs b/Content.Server/Fax/FaxSystem.cs index 362941286f..810ff7890d 100644 --- a/Content.Server/Fax/FaxSystem.cs +++ b/Content.Server/Fax/FaxSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Administration; +using Content.Server.Administration; using Content.Server.Administration.Managers; using Content.Server.Chat.Managers; using Content.Server.DeviceNetwork; @@ -275,8 +275,9 @@ public sealed class FaxSystem : EntitySystem args.Data.TryGetValue(FaxConstants.FaxPaperStampStateData, out string? stampState); args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List? stampedBy); + args.Data.TryGetValue(FaxConstants.FaxPaperPrototypeData, out string? prototypeId); - var printout = new FaxPrintout(content, name, stampState, stampedBy); + var printout = new FaxPrintout(content, name, prototypeId, stampState, stampedBy); Receive(uid, printout, args.SenderAddress); break; @@ -397,12 +398,21 @@ public sealed class FaxSystem : EntitySystem { FaxConstants.FaxPaperContentData, paper.Content }, }; + if (metadata.EntityPrototype != null) + { + /// todo: Ideally, we could just make a copy of the whole entity when it's + /// faxed, in order to preserve visuals, etc.. This functionality isn't + /// available yet, so we'll pass along the originating prototypeId and fall + /// back to "Paper" in SpawnPaperFromQueue if we can't find one here. + payload[FaxConstants.FaxPaperPrototypeData] = metadata.EntityPrototype.ID; + } + if (paper.StampState != null) { payload[FaxConstants.FaxPaperStampStateData] = paper.StampState; payload[FaxConstants.FaxPaperStampedByData] = paper.StampedBy; } - + _deviceNetworkSystem.QueuePacket(uid, component.DestinationFaxAddress, payload); _adminLogger.Add(LogType.Action, LogImpact.Low, $"{(sender != null ? ToPrettyString(sender.Value) : "Unknown"):user} sent fax from \"{component.FaxName}\" {ToPrettyString(uid)} to {faxName} ({component.DestinationFaxAddress}): {paper.Content}"); @@ -442,7 +452,9 @@ public sealed class FaxSystem : EntitySystem return; var printout = component.PrintingQueue.Dequeue(); - var printed = EntityManager.SpawnEntity("Paper", Transform(uid).Coordinates); + + var entityToSpawn = printout.PrototypeId.Length == 0 ? "Paper" : printout.PrototypeId; + var printed = EntityManager.SpawnEntity(entityToSpawn, Transform(uid).Coordinates); if (TryComp(printed, out var paper)) { diff --git a/Content.Server/Nuke/NukeCodePaperSystem.cs b/Content.Server/Nuke/NukeCodePaperSystem.cs index d8546170da..28467e1e3a 100644 --- a/Content.Server/Nuke/NukeCodePaperSystem.cs +++ b/Content.Server/Nuke/NukeCodePaperSystem.cs @@ -57,6 +57,7 @@ namespace Content.Server.Nuke var printout = new FaxPrintout( paperContent, Loc.GetString("nuke-codes-fax-paper-name"), + null, "paper_stamp-cent", new() { Loc.GetString("stamp-component-stamped-name-centcom") }); _faxSystem.Receive(fax.Owner, printout, null, fax); @@ -84,9 +85,9 @@ namespace Content.Server.Nuke { return false; } - + var owningStation = station ?? _station.GetOwningStation(uid); - + // Find the first nuke that matches the passed location. foreach (var nuke in EntityQuery()) { diff --git a/Content.Server/Paper/PaperSystem.cs b/Content.Server/Paper/PaperSystem.cs index 11213ffc38..c763a51d6f 100644 --- a/Content.Server/Paper/PaperSystem.cs +++ b/Content.Server/Paper/PaperSystem.cs @@ -166,7 +166,7 @@ namespace Content.Server.Paper if (!Resolve(uid, ref paperComp)) return; - _uiSystem.GetUiOrNull(uid, PaperUiKey.Key)?.SetState(new PaperBoundUserInterfaceState(paperComp.Content, paperComp.Mode)); + _uiSystem.GetUiOrNull(uid, PaperUiKey.Key)?.SetState(new PaperBoundUserInterfaceState(paperComp.Content, paperComp.StampedBy, paperComp.Mode)); } } } diff --git a/Content.Shared/Cargo/Components/CargoShuttleComponent.cs b/Content.Shared/Cargo/Components/CargoShuttleComponent.cs index 5e85babab0..d3c5b693cd 100644 --- a/Content.Shared/Cargo/Components/CargoShuttleComponent.cs +++ b/Content.Shared/Cargo/Components/CargoShuttleComponent.cs @@ -1,4 +1,6 @@ using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Cargo.Components; @@ -28,4 +30,11 @@ public sealed class CargoShuttleComponent : Component /// [DataField("station")] public EntityUid? Station; + + /// + /// The paper-type prototype to spawn with the order information. + /// + [DataField("printerOutput", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string PrinterOutput = "PaperCargoInvoice"; + } diff --git a/Content.Shared/Paper/SharedPaperComponent.cs b/Content.Shared/Paper/SharedPaperComponent.cs index ecc4a455ef..0518cbd4df 100644 --- a/Content.Shared/Paper/SharedPaperComponent.cs +++ b/Content.Shared/Paper/SharedPaperComponent.cs @@ -8,11 +8,13 @@ namespace Content.Shared.Paper public sealed class PaperBoundUserInterfaceState : BoundUserInterfaceState { public readonly string Text; + public readonly List StampedBy; public readonly PaperAction Mode; - public PaperBoundUserInterfaceState(string text, PaperAction mode = PaperAction.Read) + public PaperBoundUserInterfaceState(string text, List stampedBy, PaperAction mode = PaperAction.Read) { Text = text; + StampedBy = stampedBy; Mode = mode; } } diff --git a/Resources/Locale/en-US/paper/paper-component.ftl b/Resources/Locale/en-US/paper/paper-component.ftl index 61acdc22eb..d10201b4cf 100644 --- a/Resources/Locale/en-US/paper/paper-component.ftl +++ b/Resources/Locale/en-US/paper/paper-component.ftl @@ -1,6 +1,8 @@ ### UI +paper-ui-blank-page-message = This page intentionally left blank + # Shown when paper with words examined details paper-component-examine-detail-has-words = {CAPITALIZE(THE($paper))} has something written on it. # Shown when paper with stamps examined diff --git a/Resources/Prototypes/Entities/Objects/Misc/books.yml b/Resources/Prototypes/Entities/Objects/Misc/books.yml index fce7cf0d47..a567e99ce4 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/books.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/books.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity name: book parent: BaseItem id: BookBase @@ -21,6 +21,10 @@ - type: Tag tags: - Book + - type: PaperVisuals + backgroundImagePath: "/Textures/Interface/Paper/paper_background_book.svg.96dpi.png" + backgroundPatchMargin: 23.0, 16.0, 14.0, 15.0 + contentMargin: 20.0, 20.0, 20.0, 20.0 - type: entity parent: BookBase diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index cbb7ddba32..2e84055151 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -32,6 +32,102 @@ - type: PaperVisuals - type: Recyclable +- type: entity + name: office paper + parent: Paper + id: PaperOffice + description: 'A plain sheet of office paper.' + components: + - type: PaperVisuals + backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png" + contentImagePath: "/Textures/Interface/Paper/paper_content_lined.svg.96dpi.png" + backgroundPatchMargin: 16.0, 16.0, 16.0, 16.0 + contentMargin: 16.0, 16.0, 16.0, 16.0 + +- type: entity + name: artifact analyzer printout + parent: Paper + id: PaperArtifactAnalyzer + description: 'The readout of a device forgotten to time' + components: + - type: Sprite + sprite: Objects/Misc/bureaucracy.rsi + netsync: false + layers: + - state: paper_dotmatrix + - state: paper_dotmatrix_words + map: ["enum.PaperVisualLayers.Writing"] + visible: false + - state: paper_stamp-generic + map: ["enum.PaperVisualLayers.Stamp"] + visible: false + - type: PaperVisuals + headerImagePath: "/Textures/Interface/Paper/paper_heading_artifact_analyzer.svg.96dpi.png" + headerMargin: 0.0, 0.0, 0.0, 16.0 + backgroundImagePath: "/Textures/Interface/Paper/paper_background_dotmatrix.svg.96dpi.png" + backgroundImageTile: true + backgroundPatchMargin: 37.0, 0.0, 37.0, 0.0 + contentImagePath: "/Textures/Interface/Paper/paper_content_dotmatrix.svg.96dpi.png" + contentImageNumLines: 2 + contentMargin: 16.0, 16.0, 16.0, 0.0 + # Make this a wide dot-matrix printer + maxWritableArea: 400.0, 0.0 + +- type: entity + name: captain's thoughts + parent: Paper + id: PaperCaptainsThoughts + description: "A page of the captain's journal. In luxurious lavender." + components: + - type: Sprite + sprite: Objects/Misc/bureaucracy.rsi + netsync: false + layers: + - state: paper + color: "#e6e6fa" + - state: paper_words + map: ["enum.PaperVisualLayers.Writing"] + color: "#e6e6fa" + visible: false + - state: paper_stamp-generic + map: ["enum.PaperVisualLayers.Stamp"] + visible: false + - type: PaperVisuals + headerImagePath: "/Textures/Interface/Paper/paper_heading_captains_thoughts.svg.96dpi.png" + backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png" + backgroundModulate: "#e6e6fa" + backgroundPatchMargin: 16.0, 16.0, 16.0, 16.0 + contentMargin: 32.0, 16.0, 32.0, 0.0 + +- type: entity + name: cargo invoice + parent: Paper + id: PaperCargoInvoice + description: 'A single unit of bureaucracy.' + components: + - type: Sprite + sprite: Objects/Misc/bureaucracy.rsi + netsync: false + layers: + - state: paper + color: "#f7e574" + - state: paper_words + map: ["enum.PaperVisualLayers.Writing"] + color: "#f7e574" + visible: false + - state: paper_stamp-generic + map: ["enum.PaperVisualLayers.Stamp"] + visible: false + - type: PaperVisuals + backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png" + contentImagePath: "/Textures/Interface/Paper/paper_content_lined.svg.96dpi.png" + backgroundModulate: "#f7e574" + contentImageModulate: "#f7e574" + backgroundPatchMargin: 16.0, 16.0, 16.0, 16.0 + contentMargin: 16.0, 16.0, 16.0, 16.0 + headerImagePath: "/Textures/Interface/Paper/paper_heading_cargo_invoice.svg.96dpi.png" + headerMargin: 0.0, 12.0, 0.0, 0.0 + - type: entity parent: Paper id: PaperWritten @@ -171,11 +267,11 @@ contents: - id: Paper prob: 0.5 - - id: Paper + - id: PaperOffice prob: 0.4 - id: Paper prob: 0.3 - - id: Paper + - id: PaperOffice prob: 0.2 - id: Paper prob: 0.2 diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index 8ca4861ead..f2a3362645 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -370,6 +370,7 @@ state: tech_key - type: ResearchClient - type: AnalysisConsole + reportEntityId: PaperArtifactAnalyzer - type: DeviceList - type: DeviceNetwork deviceNetId: Wired diff --git a/Resources/Prototypes/Entities/Structures/Machines/Medical/disease_diagnoser.yml b/Resources/Prototypes/Entities/Structures/Machines/Medical/disease_diagnoser.yml index 5e56846135..958e3f798d 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Medical/disease_diagnoser.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Medical/disease_diagnoser.yml @@ -17,10 +17,39 @@ netsync: false - type: DiseaseDiagnoser - type: DiseaseMachine - machineOutput: Paper + machineOutput: DiagnosisReportPaper - type: Appearance - type: DiseaseMachineVisuals idleState: icon runningState: running - type: Machine - board: DiagnoserMachineCircuitboard \ No newline at end of file + board: DiagnoserMachineCircuitboard + +- type: entity + name: disease diagnoser report + parent: Paper + id: DiagnosisReportPaper + description: 'A chilling medical receipt.' + components: + - type: Sprite + sprite: Objects/Misc/bureaucracy.rsi + netsync: false + layers: + - state: paper_receipt + - state: paper_receipt_words + map: ["enum.PaperVisualLayers.Writing"] + visible: false + - state: paper_stamp-generic + map: ["enum.PaperVisualLayers.Stamp"] + visible: false + - type: PaperVisuals + backgroundImagePath: "/Textures/Interface/Paper/paper_background_perforated.svg.96dpi.png" + headerImagePath: "/Textures/Interface/Paper/paper_heading_virus.svg.96dpi.png" + headerMargin: 0.0, 0.0, 0.0, 6.0 + backgroundImageTile: true + backgroundPatchMargin: 0.0, 6.0, 0.0, 6.0 + contentMargin: 12.0, 0.0, 12.0, 0.0 + # This is a narrow piece of paper + maxWritableArea: 128.0, 0.0 + + diff --git a/Resources/Textures/Interface/Nano/lined_paper.svg b/Resources/Textures/Interface/Nano/lined_paper.svg new file mode 100644 index 0000000000..86185ed457 --- /dev/null +++ b/Resources/Textures/Interface/Nano/lined_paper.svg @@ -0,0 +1,77 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/Resources/Textures/Interface/Nano/lined_paper.svg.96dpi.png b/Resources/Textures/Interface/Nano/lined_paper.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..d57adb5f50a20a9fe377c4ca373f6c4ae0ff7346 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!3HFi66di4Db50q$YKTtzQZ8Qcszea3Q$n8 z#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD=%PZ!4!jfu&Beto@K&nCoh u`tI+ZB`eYsRIakAP3n=qYOt!YONv2EiL+(vwN7QA1_n=8KbLh*2~7ZN>@DE{ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Paper/paper_background_book.svg b/Resources/Textures/Interface/Paper/paper_background_book.svg new file mode 100644 index 0000000000..fab991b462 --- /dev/null +++ b/Resources/Textures/Interface/Paper/paper_background_book.svg @@ -0,0 +1,143 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/Textures/Interface/Paper/paper_background_book.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_background_book.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..b0e9c06fe22406be10c0710a2141a68ec5e7c4c3 GIT binary patch literal 635 zcmV->0)+jEP)00009a7bBm000id z000id0mpBsWB>pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10tiV& zK~z|U?U+Gp(_k3KfA9My=3ow`LJox?RFM^A*NG_e;6MZ~UIb;{{04eSM?(r;1ikbd zY=R$PB7#uZS5Vl76R8K?Mn`&Cx|KlUp;o()7DuFS4*nsK_xV3h_>sIkc@lB^{=io0Ona zR+1zyeBWPdwOZD=Vdx@CX(b2(fXAbN?mITF72o%tjuu4%19VVW zZ5x0v472PD+Q5Vm0K{>eX&0@J{nmf5vq~FSl1zQ!B-+5jqoZl|p*FBj+uHz0nTha2 z3s|q$<3qa*fc>kVrSx^C6KoiU?CkE+-rOYY_fbmWI8IjTTd{EMX0EZPcCm8i8Yv~V zZR0o&rfH__;n?F;=JIe+tNrtNY~6L;gQE4Z6T>h(C|H9PLaf&7^>0utu=Pfx@p7~% z3fNk?Tz)bh(EY)C0@OXvdzChHfyKaU!!R17J(bq1z`6{7LwyF`o2I$py6(ZWf}ev~ Vj`8`!X`uiB002ovPDHLkV1htXC&T~% literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Paper/paper_background_default.svg b/Resources/Textures/Interface/Paper/paper_background_default.svg new file mode 100644 index 0000000000..fcd323253a --- /dev/null +++ b/Resources/Textures/Interface/Paper/paper_background_default.svg @@ -0,0 +1,70 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/Resources/Textures/Interface/Paper/paper_background_default.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_background_default.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..6a4c35bea357f0bc5da57904c345f406018e617c GIT binary patch literal 1109 zcmeAS@N?(olHy`uVBq!ia0vp^tsu<71|&;wS=#_9&H|6fVg?4=77%8gmz~VJ{nvN$ckXW!ZnoDX-aqrFEX}Gk)_9p_!m{5t znBTC;y~taC>~BEtoA?J>AJhvZcd*Q1K3BfIe~odHh-`wG1=|_M+sA({pVg82K%_wC zhtQ1=;%=wJn=G7Og0?#na zXXwAXZ)eDj^#=kI64#2~$#JacNGnekn0?ysflfinTJbeoms|L3Zog5M4%E5k(i_8P z?DHkWj`9?+?f8D~{L(}J*!YYJG$ebHW~D9NRa{iOazlJW?H64;_Uj_@NdnPl^&b5F z$NRUs%W~Fa*;}*HGX09~3LG^*aCxa(P~rWHHUCTBfB2}xw(+Vhs}2AE^_qQCXS?ct zVl!#)*L=VgcPHqxaOo~4z661+Hw@px5B$3{c||B+$boy8f>(ro3ppUXba}w)H|rYO zz5Ex3Rc;8r{?-0~?Nar?>@_8?qIVRB&z@W!t1Z#m6sR$52`APyQ{?FTh4HLqyJm%iFHk7*slZEyd@kES)e zuvOd$OZ50&;HF@n0SRR zpV{khV|_8BVN~aRX#|aHEGLF9p?2+^LeX_3VaP; zSUzA`XJ|Hge#2s(o6cX>ls~`9bXMuf<=YlhPFZ?>u3aa|lJll)kLv>i1MlJ{=kod7 z2OMX~3%}ND%dx#< y-`4wkq0~*Sg5I?Lf68b78b06E|N3#wgZlHyE2~ZQ+JNN)1B0ilpUXO@geCw=f9#_G literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Paper/paper_background_dotmatrix.svg b/Resources/Textures/Interface/Paper/paper_background_dotmatrix.svg new file mode 100644 index 0000000000..79ef1d6a7b --- /dev/null +++ b/Resources/Textures/Interface/Paper/paper_background_dotmatrix.svg @@ -0,0 +1,214 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/Textures/Interface/Paper/paper_background_dotmatrix.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_background_dotmatrix.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..c1bee72561553ca9ffe7479bc6e5b89dc71ea1c7 GIT binary patch literal 702 zcmV;v0zv(WP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10!v9m zK~!jg?U~PN6hRP&zfAVv!QERFR|67|;G?+y$;qQ22s!!!ik|eGmO$nGJ9Z7mDsh8lmkn}*(w?x|?B;6{e)XBP?#i1Iux&{f6C6*EzQRS=Tc*6T0=A*{?UK#J2hAaK-m?O>-O~BL5FVN4 z!drDpP6#dETpvjLgqH6xlf7xV@mAGg&oVlP&})BQv6iC_bK{L=*a4we^eZC(gns)z z|M#BS)?u!^u?%}-;GELt*ubtUZ!BQ%4V?ecyU1MIewZt7>@Rr(_-X{ON_d&(lq+v6 k!@e6ihw#BQw_JID1DJ>jn1___U;qFB07*qoM6N<$f@cg%WB>pF literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Paper/paper_background_perforated.svg b/Resources/Textures/Interface/Paper/paper_background_perforated.svg new file mode 100644 index 0000000000..128947fd87 --- /dev/null +++ b/Resources/Textures/Interface/Paper/paper_background_perforated.svg @@ -0,0 +1,73 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Resources/Textures/Interface/Paper/paper_background_perforated.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_background_perforated.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..932a52118ba716ecd949b2600624570436cada08 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@)1s;*b3=DjSL74G){)!Z!pk#?_ zL`iUdT1k0gQ7S`udAVL@UUqSEVnM22eo^}DcQ#T$MbVxvjv*Qor(X2tYcSw&y|{e# zHA&gB>(?7EW^n7OCbFnMRCe$ad$%I4mZjqX&kh4-s~N2JJDB2jFlHE*c|KpHdEU>x x$Yk-(dpuGH=PPCK%zN#aU2XHFRhFTI@tWxm=?OQQfwnL(c)I$ztaD0e0st=pL+bzl literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Paper/paper_content_dotmatrix.svg b/Resources/Textures/Interface/Paper/paper_content_dotmatrix.svg new file mode 100644 index 0000000000..f231334c19 --- /dev/null +++ b/Resources/Textures/Interface/Paper/paper_content_dotmatrix.svg @@ -0,0 +1,91 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Resources/Textures/Interface/Paper/paper_content_dotmatrix.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_content_dotmatrix.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..c1a4f866c9ae74053fefca243a3b88921cbd4e72 GIT binary patch literal 176 zcmeAS@N?(olHy`uVBq!ia0vp^JV30#!3HGNq-U-IQk(@Ik;M!Qe1}1p@p%4<6riAF ziEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0wvo-U3d7QM+e-`_v2XA@!& z*6ccY>A;Ww|NlEaTN22t?8?l|%-pQ1DJ9|QvnIvj<&XQhb|zaBLk_QClVM=UyvoPN T`62ip&>#j+S3j3^P6 + + + + + image/svg+xml + + + + + + + + + diff --git a/Resources/Textures/Interface/Paper/paper_content_lined.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_content_lined.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..3ebe3fe088eb9d17d147c491ca89eb1e4d61282c GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!3HFi66di4Db50q$YKTtzQZ8Qcszea3Q$n8 z#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD=XPZ!4!jfu&B{{R19&nCoh v`t9y|&%pBsJXZ1gs7TtcN(^BZHDzEpCd+m1R8jy?0|SGntDnm{r-UW|Z-y*v literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Paper/paper_heading_artifact_analyzer.svg b/Resources/Textures/Interface/Paper/paper_heading_artifact_analyzer.svg new file mode 100644 index 0000000000..71836e855c --- /dev/null +++ b/Resources/Textures/Interface/Paper/paper_heading_artifact_analyzer.svg @@ -0,0 +1,256 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/Textures/Interface/Paper/paper_heading_artifact_analyzer.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_heading_artifact_analyzer.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..1276f0938f180693ba1c4e2546faba4324bbf94b GIT binary patch literal 5657 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Paper/paper_heading_captains_thoughts.svg b/Resources/Textures/Interface/Paper/paper_heading_captains_thoughts.svg new file mode 100644 index 0000000000..e52ca49143 --- /dev/null +++ b/Resources/Textures/Interface/Paper/paper_heading_captains_thoughts.svg @@ -0,0 +1,187 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/Textures/Interface/Paper/paper_heading_captains_thoughts.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_heading_captains_thoughts.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..1ce991aaad4475bbbe20650924361162a91cccd5 GIT binary patch literal 7596 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 O0000 +image/svg+xml diff --git a/Resources/Textures/Interface/Paper/paper_heading_cargo_invoice.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_heading_cargo_invoice.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..52e36314b1a818f6a6550475582465d44b2114c8 GIT binary patch literal 5181 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 + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/Textures/Interface/Paper/paper_heading_virus.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_heading_virus.svg.96dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..24a6bc63880403418af4d9a2f845566594be13b1 GIT binary patch literal 5097 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 TM^;Q600000NkvXXu0mjf>cxz? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/bureaucracy.rsi/paper_receipt.png b/Resources/Textures/Objects/Misc/bureaucracy.rsi/paper_receipt.png new file mode 100644 index 0000000000000000000000000000000000000000..70c7237ffc57a6976db19e70e995ea081b7936be GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}EuJopArY-_ zuNd+*8wj{u6g;K)LGk+E80PyEpNh@qIw|6~k+*Zgv(n2q;`MksI&1__X536)c9CP! z#It<6pUw%-cQ9jaIFU9Z*y_#FDeKR_tZTGQ^5bN9)uHCh`1|SnZ*LjH0~(n0IB(qf zFTP=CvSzBrBJPtPN_&5Culs&p>D;!C6UuuSy;j=Y>|k8G3g{jNPgg&ebxsLQ0ONpA AE&u=k literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/bureaucracy.rsi/paper_receipt_words.png b/Resources/Textures/Objects/Misc/bureaucracy.rsi/paper_receipt_words.png new file mode 100644 index 0000000000000000000000000000000000000000..78d138a870c04ed0d424cb275960b4afbf53ef7c GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}hdf;zLn2z= zPT9!YV!-3N-_M*SvRf^<<({Mh^90RH24ZR5F^x?NEJ_M3R8;mK`_=pR?F~i|*T8uk zf={JtkFCDSBKY*+&gOL|KTngAn8Vy)W6^$YMzdVZ M>FVdQ&MBb@0Eb&>00000 literal 0 HcmV?d00001