This commit is contained in:
pathetic meowmeow
2025-03-15 12:24:23 -04:00
committed by GitHub
parent c7022ae7c5
commit 4576555e5b
20 changed files with 937 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Client.CartridgeLoader.Cartridges;
public sealed class NanoTaskCartridgeSystem : SharedNanoTaskCartridgeSystem;

View File

@@ -0,0 +1,32 @@
<Control xmlns="https://spacestation14.io" xmlns:system="clr-namespace:System;assembly=System.Runtime">
<BoxContainer Name="MainContainer"
Orientation="Horizontal"
SetWidth="250">
<Button Name="MainButton"
HorizontalExpand="True"
VerticalExpand="True"
StyleClasses="ButtonSquare"
Margin="-1 0 0 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
Margin="-5 0 0 0">
<Label Name="TaskLabel"
StyleClasses="LabelSubText" />
<Label Name="TaskForLabel"
StyleClasses="LabelSubText"
Margin="0 -5 0 0" />
</BoxContainer>
</BoxContainer>
</Button>
<Button Name="DoneButton"
VerticalExpand="True"
Text="{Loc 'nano-task-ui-done'}">
<Button.StyleClasses>
<system:String>ButtonSmall</system:String>
<system:String>OpenLeft</system:String>
</Button.StyleClasses>
</Button>
</BoxContainer>
</Control>

View File

@@ -0,0 +1,33 @@
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Maths;
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Client.CartridgeLoader.Cartridges;
/// <summary>
/// Represents a single control for a single NanoTask item
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class NanoTaskItemControl : Control
{
public Action<int>? OnMainPressed;
public Action<int>? OnDonePressed;
public NanoTaskItemControl(NanoTaskItemAndId item)
{
RobustXamlLoader.Load(this);
TaskLabel.Text = item.Data.Description;
TaskLabel.FontColorOverride = Color.White;
TaskForLabel.Text = item.Data.TaskIsFor;
MainButton.OnPressed += _ => OnMainPressed?.Invoke(item.Id);
DoneButton.OnPressed += _ => OnDonePressed?.Invoke(item.Id);
MainButton.Disabled = item.Data.IsTaskDone;
DoneButton.Text = item.Data.IsTaskDone ? Loc.GetString("nano-task-ui-revert-done") : Loc.GetString("nano-task-ui-done");
}
}

View File

@@ -0,0 +1,67 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc nano-task-ui-item-title}"
MinSize="300 300">
<PanelContainer StyleClasses="AngleRect">
<BoxContainer Orientation="Vertical" Margin="4">
<!-- Task Description Input -->
<BoxContainer Orientation="Vertical" Margin="0 4">
<Label Text="{Loc nano-task-ui-description-label}"
StyleClasses="LabelHeading" />
<PanelContainer StyleClasses="ButtonSquare">
<LineEdit Name="DescriptionInput"
PlaceHolder="{Loc nano-task-ui-description-placeholder}" />
</PanelContainer>
</BoxContainer>
<!-- Task Requester Input -->
<BoxContainer Orientation="Vertical" Margin="0 4">
<Label Text="{Loc nano-task-ui-requester-label}"
StyleClasses="LabelHeading" />
<PanelContainer StyleClasses="ButtonSquare">
<LineEdit Name="RequesterInput"
PlaceHolder="{Loc nano-task-ui-requester-placeholder}" />
</PanelContainer>
</BoxContainer>
<!-- Severity Buttons -->
<BoxContainer Orientation="Horizontal"
HorizontalAlignment="Center"
Margin="0 8 0 0">
<Button Name="LowButton"
Text="{Loc nano-task-ui-priority-low}"
StyleClasses="OpenRight"
MinSize="60 0" />
<Button Name="MediumButton"
Text="{Loc nano-task-ui-priority-medium}"
StyleClasses="ButtonSquare"
MinSize="60 0" />
<Button Name="HighButton"
Text="{Loc nano-task-ui-priority-high}"
StyleClasses="OpenLeft"
MinSize="60 0" />
</BoxContainer>
<!-- Verb Buttons -->
<BoxContainer Orientation="Horizontal"
HorizontalAlignment="Right"
Margin="0 8 0 0">
<Button Name="CancelButton"
Text="{Loc nano-task-ui-cancel}"
StyleClasses="OpenRight"
MinSize="60 0" />
<Button Name="DeleteButton"
Text="{Loc nano-task-ui-delete}"
StyleClasses="ButtonSquare"
MinSize="60 0" />
<Button Name="PrintButton"
Text="{Loc nano-task-ui-print}"
StyleClasses="ButtonSquare"
MinSize="60 0" />
<Button Name="SaveButton"
Text="{Loc nano-task-ui-save}"
StyleClasses="OpenLeft"
MinSize="60 0" />
</BoxContainer>
</BoxContainer>
</PanelContainer>
</DefaultWindow>

View File

@@ -0,0 +1,109 @@
using System.Linq;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Client.UserInterface.Controls;
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Client.CartridgeLoader.Cartridges;
/// <summary>
/// Popup displayed to edit a NanoTask item
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class NanoTaskItemPopup : DefaultWindow
{
private readonly ButtonGroup _priorityGroup = new();
private int? _editingTaskId = null;
public Action<int, NanoTaskItem>? TaskSaved;
public Action<int>? TaskDeleted;
public Action<NanoTaskItem>? TaskCreated;
public Action<NanoTaskItem>? TaskPrinted;
private NanoTaskItem MakeItem()
{
return new(
description: DescriptionInput.Text,
taskIsFor: RequesterInput.Text,
isTaskDone: false,
priority: _priorityGroup.Pressed switch {
var item when item == LowButton => NanoTaskPriority.Low,
var item when item == MediumButton => NanoTaskPriority.Medium,
var item when item == HighButton => NanoTaskPriority.High,
_ => NanoTaskPriority.Medium,
}
);
}
public NanoTaskItemPopup()
{
RobustXamlLoader.Load(this);
LowButton.Group = _priorityGroup;
MediumButton.Group = _priorityGroup;
HighButton.Group = _priorityGroup;
CancelButton.OnPressed += _ => Close();
DeleteButton.OnPressed += _ =>
{
if (_editingTaskId is int id)
{
TaskDeleted?.Invoke(id);
}
};
PrintButton.OnPressed += _ =>
{
TaskPrinted?.Invoke(MakeItem());
};
SaveButton.OnPressed += _ =>
{
if (_editingTaskId is int id)
{
TaskSaved?.Invoke(id, MakeItem());
}
else
{
TaskCreated?.Invoke(MakeItem());
}
};
DescriptionInput.OnTextChanged += args =>
{
if (args.Text.Length > NanoTaskItem.MaximumStringLength)
DescriptionInput.Text = args.Text[..NanoTaskItem.MaximumStringLength];
};
RequesterInput.OnTextChanged += args =>
{
if (args.Text.Length > NanoTaskItem.MaximumStringLength)
RequesterInput.Text = args.Text[..NanoTaskItem.MaximumStringLength];
};
}
public void SetEditingTaskId(int? id)
{
_editingTaskId = id;
DeleteButton.Visible = id is not null;
}
public void ResetInputs(NanoTaskItem? item)
{
if (item is NanoTaskItem task)
{
var button = task.Priority switch {
NanoTaskPriority.High => HighButton,
NanoTaskPriority.Medium => MediumButton,
NanoTaskPriority.Low => LowButton,
};
button.Pressed = true;
DescriptionInput.Text = task.Description;
RequesterInput.Text = task.TaskIsFor;
}
else
{
MediumButton.Pressed = true;
DescriptionInput.Text = "";
RequesterInput.Text = "";
}
}
}

View File

@@ -0,0 +1,82 @@
using System.Linq;
using Content.Client.UserInterface.Fragments;
using Content.Shared.CartridgeLoader;
using Content.Shared.CartridgeLoader.Cartridges;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.CartridgeLoader.Cartridges;
/// <summary>
/// UI fragment responsible for displaying NanoTask controls in a PDA and coordinating with the NanoTaskCartridgeSystem for state
/// </summary>
public sealed partial class NanoTaskUi : UIFragment
{
private NanoTaskUiFragment? _fragment;
private NanoTaskItemPopup? _popup;
public override Control GetUIFragmentRoot()
{
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
{
_fragment = new NanoTaskUiFragment();
_popup = new NanoTaskItemPopup();
_fragment.NewTask += () =>
{
_popup.ResetInputs(null);
_popup.SetEditingTaskId(null);
_popup.OpenCentered();
};
_fragment.OpenTask += id =>
{
if (_fragment.Tasks.Find(task => task.Id == id) is not NanoTaskItemAndId task)
return;
_popup.ResetInputs(task.Data);
_popup.SetEditingTaskId(task.Id);
_popup.OpenCentered();
};
_fragment.ToggleTaskCompletion += id =>
{
if (_fragment.Tasks.Find(task => task.Id == id) is not NanoTaskItemAndId task)
return;
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskUpdateTask(new(id, new(
description: task.Data.Description,
taskIsFor: task.Data.TaskIsFor,
isTaskDone: !task.Data.IsTaskDone,
priority: task.Data.Priority
))))));
};
_popup.TaskSaved += (id, data) =>
{
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskUpdateTask(new(id, data)))));
_popup.Close();
};
_popup.TaskDeleted += id =>
{
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskDeleteTask(id))));
_popup.Close();
};
_popup.TaskCreated += data =>
{
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskAddTask(data))));
_popup.Close();
};
_popup.TaskPrinted += data =>
{
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskPrintTask(data))));
};
}
public override void UpdateState(BoundUserInterfaceState state)
{
if (state is not NanoTaskUiState nanoTaskState)
return;
_fragment?.UpdateState(nanoTaskState.Tasks);
}
}

View File

@@ -0,0 +1,58 @@
<cartridges:NanoTaskUiFragment xmlns:cartridges="clr-namespace:Content.Client.CartridgeLoader.Cartridges"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns="https://spacestation14.io" Margin="1 0 2 0">
<PanelContainer StyleClasses="BackgroundDark"></PanelContainer>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<ScrollContainer HorizontalExpand="True" VerticalExpand="True">
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical" Margin="8" SeparationOverride="8">
<!-- Heading for High Priority Items -->
<BoxContainer Orientation="Horizontal">
<PanelContainer SetWidth="7" Margin="0 0 8 0">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#e93d58"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<Label Name="HighPriority" StyleClasses="LabelHeading"/>
</BoxContainer>
<!-- Location for High Priority Items -->
<GridContainer Name="HighContainer"
HorizontalExpand="True"
Access="Public"
Columns="2" />
<!-- Heading for Medium Priority Items -->
<BoxContainer Orientation="Horizontal">
<PanelContainer SetWidth="7" Margin="0 0 8 0">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#ef973c"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<Label Name="MediumPriority" StyleClasses="LabelHeading"/>
</BoxContainer>
<!-- Location for Medium Priority Items -->
<GridContainer Name="MediumContainer"
HorizontalExpand="True"
Access="Public"
Columns="2" />
<!-- Location for Low Priority Items -->
<BoxContainer Orientation="Horizontal">
<PanelContainer SetWidth="7" Margin="0 0 8 0">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#3dd425"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<Label Name="LowPriority" StyleClasses="LabelHeading"/>
</BoxContainer>
<!-- Location for Low Priority Items -->
<GridContainer Name="LowContainer"
HorizontalExpand="True"
Access="Public"
Columns="2" />
<Button Name="NewTaskButton" Text="{Loc 'nano-task-ui-new-task'}" HorizontalAlignment="Right"/>
</BoxContainer>
</ScrollContainer>
</BoxContainer>
</cartridges:NanoTaskUiFragment>

View File

@@ -0,0 +1,52 @@
using System.Linq;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Client.CartridgeLoader.Cartridges;
/// <summary>
/// Class displaying the main UI of NanoTask
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class NanoTaskUiFragment : BoxContainer
{
public Action<int>? OpenTask;
public Action<int>? ToggleTaskCompletion;
public Action? NewTask;
public List<NanoTaskItemAndId> Tasks = new();
public NanoTaskUiFragment()
{
RobustXamlLoader.Load(this);
Orientation = LayoutOrientation.Vertical;
HorizontalExpand = true;
VerticalExpand = true;
NewTaskButton.OnPressed += _ => NewTask?.Invoke();
}
public void UpdateState(List<NanoTaskItemAndId> tasks)
{
Tasks = tasks;
HighContainer.RemoveAllChildren();
MediumContainer.RemoveAllChildren();
LowContainer.RemoveAllChildren();
HighPriority.Text = Loc.GetString("nano-task-ui-heading-high-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.High)));
MediumPriority.Text = Loc.GetString("nano-task-ui-heading-medium-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.Medium)));
LowPriority.Text = Loc.GetString("nano-task-ui-heading-low-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.Low)));
foreach (var task in tasks)
{
var container = task.Data.Priority switch {
NanoTaskPriority.High => HighContainer,
NanoTaskPriority.Medium => MediumContainer,
NanoTaskPriority.Low => LowContainer,
};
var control = new NanoTaskItemControl(task);
container.AddChild(control);
control.OnMainPressed += id => OpenTask?.Invoke(id);
control.OnDonePressed += id => ToggleTaskCompletion?.Invoke(id);
}
}
}

View File

@@ -0,0 +1,151 @@
using Content.Shared.CartridgeLoader.Cartridges;
using Content.Shared.CartridgeLoader;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Paper;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.CartridgeLoader.Cartridges;
/// <summary>
/// Server-side class implementing the core UI logic of NanoTask
/// </summary>
public sealed class NanoTaskCartridgeSystem : SharedNanoTaskCartridgeSystem
{
[Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly PaperSystem _paper = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<NanoTaskCartridgeComponent, CartridgeMessageEvent>(OnUiMessage);
SubscribeLocalEvent<NanoTaskCartridgeComponent, CartridgeUiReadyEvent>(OnUiReady);
SubscribeLocalEvent<NanoTaskCartridgeComponent, CartridgeRemovedEvent>(OnCartridgeRemoved);
SubscribeLocalEvent<NanoTaskInteractionComponent, InteractUsingEvent>(OnInteractUsing);
}
private void OnCartridgeRemoved(Entity<NanoTaskCartridgeComponent> ent, ref CartridgeRemovedEvent args)
{
if (!_cartridgeLoader.HasProgram<NanoTaskCartridgeComponent>(args.Loader))
{
RemComp<NanoTaskInteractionComponent>(args.Loader);
}
}
private void OnInteractUsing(Entity<NanoTaskInteractionComponent> ent, ref InteractUsingEvent args)
{
if (!_cartridgeLoader.TryGetProgram<NanoTaskCartridgeComponent>(ent.Owner, out var uid, out var program))
{
return;
}
if (!EntityManager.TryGetComponent<NanoTaskPrintedComponent>(args.Used, out var printed))
{
return;
}
if (printed.Task is NanoTaskItem item)
{
program.Tasks.Add(new(program.Counter++, printed.Task));
args.Handled = true;
EntityManager.DeleteEntity(args.Used);
UpdateUiState(new Entity<NanoTaskCartridgeComponent>(uid.Value, program), ent.Owner);
}
}
/// <summary>
/// This gets called when the ui fragment needs to be updated for the first time after activating
/// </summary>
private void OnUiReady(Entity<NanoTaskCartridgeComponent> ent, ref CartridgeUiReadyEvent args)
{
UpdateUiState(ent, args.Loader);
}
private void SetupPrintedTask(EntityUid uid, NanoTaskItem item)
{
PaperComponent? paper = null;
NanoTaskPrintedComponent? printed = null;
if (!Resolve(uid, ref paper, ref printed))
return;
printed.Task = item;
var msg = new FormattedMessage();
msg.AddText(Loc.GetString("nano-task-printed-description", ("description", item.Description)));
msg.PushNewline();
msg.AddText(Loc.GetString("nano-task-printed-requester", ("requester", item.TaskIsFor)));
msg.PushNewline();
msg.AddText(item.Priority switch {
NanoTaskPriority.High => Loc.GetString("nano-task-printed-high-priority"),
NanoTaskPriority.Medium => Loc.GetString("nano-task-printed-medium-priority"),
NanoTaskPriority.Low => Loc.GetString("nano-task-printed-low-priority"),
_ => "",
});
_paper.SetContent((uid, paper), msg.ToMarkup());
}
/// <summary>
/// The ui messages received here get wrapped by a CartridgeMessageEvent and are relayed from the <see cref="CartridgeLoaderSystem"/>
/// </summary>
/// <remarks>
/// The cartridge specific ui message event needs to inherit from the CartridgeMessageEvent
/// </remarks>
private void OnUiMessage(Entity<NanoTaskCartridgeComponent> ent, ref CartridgeMessageEvent args)
{
if (args is not NanoTaskUiMessageEvent message)
return;
switch (message.Payload)
{
case NanoTaskAddTask task:
if (!task.Item.Validate())
return;
ent.Comp.Tasks.Add(new(ent.Comp.Counter++, task.Item));
break;
case NanoTaskUpdateTask task:
{
if (!task.Item.Data.Validate())
return;
var idx = ent.Comp.Tasks.FindIndex(t => t.Id == task.Item.Id);
if (idx != -1)
ent.Comp.Tasks[idx] = task.Item;
break;
}
case NanoTaskDeleteTask task:
ent.Comp.Tasks.RemoveAll(t => t.Id == task.Id);
break;
case NanoTaskPrintTask task:
{
if (!task.Item.Validate())
return;
if (_timing.CurTime < ent.Comp.NextPrintAllowedAfter)
return;
ent.Comp.NextPrintAllowedAfter = _timing.CurTime + ent.Comp.PrintDelay;
var printed = Spawn("PaperNanoTaskItem", Transform(message.Actor).Coordinates);
_hands.PickupOrDrop(message.Actor, printed);
_audio.PlayPvs(new SoundPathSpecifier("/Audio/Machines/printer.ogg"), ent.Owner);
SetupPrintedTask(printed, task.Item);
break;
}
}
UpdateUiState(ent, GetEntity(args.LoaderUid));
}
private void UpdateUiState(Entity<NanoTaskCartridgeComponent> ent, EntityUid loaderUid)
{
var state = new NanoTaskUiState(ent.Comp.Tasks);
_cartridgeLoader.UpdateCartridgeUiState(loaderUid, state);
}
}

View File

@@ -0,0 +1,42 @@
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Shared.CartridgeLoader.Cartridges;
/// <summary>
/// Component that indicates a PDA cartridge as containing the NanoTask program
/// </summary>
[RegisterComponent, AutoGenerateComponentPause]
public sealed partial class NanoTaskCartridgeComponent : Component
{
/// <summary>
/// The list of tasks
/// </summary>
[DataField]
public List<NanoTaskItemAndId> Tasks = new();
/// <summary>
/// counter for generating task IDs
/// </summary>
[DataField]
public int Counter = 1;
/// <summary>
/// When the user can print again
/// </summary>
[DataField, AutoPausedField]
public TimeSpan NextPrintAllowedAfter = TimeSpan.Zero;
/// <summary>
/// How long in between each time the user can print out a task
/// </summary>
[DataField]
public TimeSpan PrintDelay = TimeSpan.FromSeconds(5);
}
/// <summary>
/// Component attached to the PDA a NanoTask cartridge is inserted into for interaction handling
/// </summary>
[RegisterComponent]
public sealed partial class NanoTaskInteractionComponent : Component
{
}

View File

@@ -0,0 +1,16 @@
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Shared.CartridgeLoader.Cartridges;
/// <summary>
/// Component attached to a piece of paper to indicate that it was printed from NanoTask and can be inserted back into it
/// </summary>
[RegisterComponent]
public sealed partial class NanoTaskPrintedComponent : Component
{
/// <summary>
/// The task that this item holds
/// </summary>
[DataField]
public NanoTaskItem? Task;
}

View File

@@ -0,0 +1,91 @@
using Robust.Shared.Serialization;
namespace Content.Shared.CartridgeLoader.Cartridges;
/// <summary>
/// Base UI message for NanoTask interactions
/// </summary>
public interface INanoTaskUiMessagePayload
{
}
/// <summary>
/// Dispatched when a new task is created
/// </summary>
[Serializable, NetSerializable, DataRecord]
public sealed class NanoTaskAddTask : INanoTaskUiMessagePayload
{
/// <summary>
/// The newly created task
/// </summary>
public readonly NanoTaskItem Item;
public NanoTaskAddTask(NanoTaskItem item)
{
Item = item;
}
}
/// <summary>
/// Dispatched when an existing task is modified
/// </summary>
[Serializable, NetSerializable, DataRecord]
public sealed class NanoTaskUpdateTask : INanoTaskUiMessagePayload
{
/// <summary>
/// The task that was updated and its ID
/// </summary>
public readonly NanoTaskItemAndId Item;
public NanoTaskUpdateTask(NanoTaskItemAndId item)
{
Item = item;
}
}
/// <summary>
/// Dispatched when an existing task is deleted
/// </summary>
[Serializable, NetSerializable, DataRecord]
public sealed class NanoTaskDeleteTask : INanoTaskUiMessagePayload
{
/// <summary>
/// The ID of the task to delete
/// </summary>
public readonly int Id;
public NanoTaskDeleteTask(int id)
{
Id = id;
}
}
/// <summary>
/// Dispatched when a task is requested to be printed
/// </summary>
[Serializable, NetSerializable, DataRecord]
public sealed class NanoTaskPrintTask : INanoTaskUiMessagePayload
{
/// <summary>
/// The NanoTask to print
/// </summary>
public readonly NanoTaskItem Item;
public NanoTaskPrintTask(NanoTaskItem item)
{
Item = item;
}
}
/// <summary>
/// Cartridge message event carrying the NanoTask UI messages
/// </summary>
[Serializable, NetSerializable]
public sealed class NanoTaskUiMessageEvent : CartridgeMessageEvent
{
public readonly INanoTaskUiMessagePayload Payload;
public NanoTaskUiMessageEvent(INanoTaskUiMessagePayload payload)
{
Payload = payload;
}
}

View File

@@ -0,0 +1,88 @@
using Robust.Shared.Serialization;
namespace Content.Shared.CartridgeLoader.Cartridges;
/// <summary>
/// The priority assigned to a NanoTask item
/// </summary>
[Serializable, NetSerializable]
public enum NanoTaskPriority : byte
{
High,
Medium,
Low,
};
/// <summary>
/// The data relating to a single NanoTask item, but not its identifier
/// </summary>
[Serializable, NetSerializable, DataRecord]
public sealed class NanoTaskItem
{
/// <summary>
/// The maximum length of the Description and TaskIsFor fields
/// </summary>
public static int MaximumStringLength = 30;
/// <summary>
/// The task description, i.e. "Bake a cake"
/// </summary>
public readonly string Description;
/// <summary>
/// Who the task is for, i.e. "Cargo"
/// </summary>
public readonly string TaskIsFor;
/// <summary>
/// If the task is marked as done or not
/// </summary>
public readonly bool IsTaskDone;
/// <summary>
/// The task's marked priority
/// </summary>
public readonly NanoTaskPriority Priority;
public NanoTaskItem(string description, string taskIsFor, bool isTaskDone, NanoTaskPriority priority)
{
Description = description;
TaskIsFor = taskIsFor;
IsTaskDone = isTaskDone;
Priority = priority;
}
public bool Validate()
{
return Description.Length <= MaximumStringLength && TaskIsFor.Length <= MaximumStringLength;
}
};
/// <summary>
/// Pairs a NanoTask item and its identifier
/// </summary>
[Serializable, NetSerializable, DataRecord]
public sealed class NanoTaskItemAndId
{
public readonly int Id;
public readonly NanoTaskItem Data;
public NanoTaskItemAndId(int id, NanoTaskItem data)
{
Id = id;
Data = data;
}
};
/// <summary>
/// The UI state of the NanoTask
/// </summary>
[Serializable, NetSerializable]
public sealed class NanoTaskUiState : BoundUserInterfaceState
{
public List<NanoTaskItemAndId> Tasks;
public NanoTaskUiState(List<NanoTaskItemAndId> tasks)
{
Tasks = tasks;
}
}

View File

@@ -0,0 +1,19 @@
using Content.Shared.CartridgeLoader;
using Content.Shared.CartridgeLoader.Cartridges;
namespace Content.Shared.CartridgeLoader.Cartridges;
public abstract class SharedNanoTaskCartridgeSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<NanoTaskCartridgeComponent, CartridgeAddedEvent>(OnCartridgeAdded);
}
private void OnCartridgeAdded(Entity<NanoTaskCartridgeComponent> ent, ref CartridgeAddedEvent args)
{
EnsureComp<NanoTaskInteractionComponent>(args.Loader);
}
}

View File

@@ -2,6 +2,7 @@ device-pda-slot-component-slot-name-cartridge = Cartridge
default-program-name = Program
notekeeper-program-name = Notekeeper
nano-task-program-name = NanoTask
news-read-program-name = Station news
crew-manifest-program-name = Crew manifest
@@ -28,6 +29,47 @@ astro-nav-program-name = AstroNav
med-tek-program-name = MedTek
# NanoTask cartridge
nano-task-ui-heading-high-priority-tasks =
{ $amount ->
[zero] No High Priority Tasks
[one] 1 High Priority Task
*[other] {$amount} High Priority Tasks
}
nano-task-ui-heading-medium-priority-tasks =
{ $amount ->
[zero] No Medium Priority Tasks
[one] 1 Medium Priority Task
*[other] {$amount} Medium Priority Tasks
}
nano-task-ui-heading-low-priority-tasks =
{ $amount ->
[zero] No Low Priority Tasks
[one] 1 Low Priority Task
*[other] {$amount} Low Priority Tasks
}
nano-task-ui-done = Done
nano-task-ui-revert-done = Undo
nano-task-ui-priority-low = Low
nano-task-ui-priority-medium = Medium
nano-task-ui-priority-high = High
nano-task-ui-cancel = Cancel
nano-task-ui-print = Print
nano-task-ui-delete = Delete
nano-task-ui-save = Save
nano-task-ui-new-task = New Task
nano-task-ui-description-label = Description:
nano-task-ui-description-placeholder = Get something important
nano-task-ui-requester-label = Requester:
nano-task-ui-requester-placeholder = John Nanotrasen
nano-task-ui-item-title = Edit Task
nano-task-printed-description = Description: {$description}
nano-task-printed-requester = Requester: {$requester}
nano-task-printed-high-priority = Priority: High
nano-task-printed-medium-priority = Priority: Medium
nano-task-printed-low-priority = Priority: Low
# Wanted list cartridge
wanted-list-program-name = Wanted list
wanted-list-label-no-records = It's all right, cowboy

View File

@@ -16,6 +16,25 @@
state: book_icon
- type: NotekeeperCartridge
- type: entity
parent: BaseItem
id: NanoTaskCartridge
name: NanoTask cartridge
description: A program that allows you to keep a list of tasks to do.
components:
- type: Sprite
sprite: Objects/Devices/cartridge.rsi
state: cart-nav
- type: Cartridge
programName: nano-task-program-name
icon:
sprite: Interface/Misc/program_icons.rsi
state: nano_task
- type: UIFragment
ui: !type:NanoTaskUi
- type: NanoTaskCartridge
- type: entity
parent: BaseItem
id: NewsReaderCartridge

View File

@@ -80,6 +80,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
cartridgeSlot:
priority: -1
@@ -130,6 +131,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- WantedListCartridge
@@ -143,6 +145,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- MedTekCartridge
@@ -492,6 +495,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- AstroNavCartridge
@@ -840,6 +844,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- WantedListCartridge
- LogProbeCartridge
@@ -908,6 +913,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- MedTekCartridge
- WantedListCartridge
@@ -932,6 +938,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- LogProbeCartridge
- WantedListCartridge
@@ -1054,6 +1061,7 @@
uiKey: enum.PdaUiKey.Key
preinstalled:
- NotekeeperCartridge
- NanoTaskCartridge
- type: entity
parent: BaseSecurityPDA
@@ -1080,6 +1088,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- MedTekCartridge
- WantedListCartridge
@@ -1250,6 +1259,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- WantedListCartridge
- LogProbeCartridge
@@ -1277,6 +1287,7 @@
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- WantedListCartridge
- MedTekCartridge
@@ -1423,6 +1434,7 @@
uiKey: enum.PdaUiKey.Key
preinstalled:
- NotekeeperCartridge
- NanoTaskCartridge
- MedTekCartridge
- type: entity

View File

@@ -196,6 +196,21 @@
headerImagePath: "/Textures/Interface/Paper/paper_heading_cargo_invoice.svg.96dpi.png"
headerMargin: 0.0, 12.0, 0.0, 0.0
- type: entity
id: PaperNanoTaskItem
parent: Paper
name: NanoTask item
description: A printed NanoTask item. Can be inserted into your PDA to add it to your tasks.
components:
- type: Tag
tags:
- Document
- Trash
- Paper
- type: StaticPrice
price: 0
- type: NanoTaskPrinted
- type: entity
id: PaperCargoBountyManifest
parent: PaperCargoInvoice

View File

@@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "news_read by Misha_Unity, crew_manifest by Phill101",
"copyright": "news_read by Misha_Unity, crew_manifest by Phill101, nano_task by Janet Blackquill <uhhadd@gmail.com>",
"size": {
"x": 32,
"y": 32
@@ -12,6 +12,9 @@
},
{
"name": "crew_manifest"
},
{
"name": "nano_task"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B