Skip to content

Commit

Permalink
Add history tab to bounty console (DeltaV-Station#2473)
Browse files Browse the repository at this point in the history
* Add struct for holding historical data on cargo bounties

* Add localisation strings for bounty history

* Add new XAML entry for display bounty history

* Expand cargo bounty menu to include tabs

* Ensure station databases hold historical bounty data

* Add to the bounty history when removing one from active

* Feed bounty history into cargo's bounty system
  • Loading branch information
BarryNorfolk authored Dec 18, 2024
1 parent 93c13b4 commit 600ef0e
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ protected override void UpdateState(BoundUserInterfaceState message)
if (message is not CargoBountyConsoleState state)
return;

_menu?.UpdateEntries(state.Bounties, state.UntilNextSkip);
_menu?.UpdateEntries(state.Bounties, state.History, state.UntilNextSkip);
}
}
23 changes: 23 additions & 0 deletions Content.Client/Cargo/UI/BountyHistoryEntry.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<BoxContainer xmlns="https://spacestation14.io"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
Margin="10 10 10 0"
HorizontalExpand="True"
Visible="True">
<PanelContainer StyleClasses="AngleRect" HorizontalExpand="True">
<BoxContainer Orientation="Vertical"
HorizontalExpand="True">
<BoxContainer Orientation="Horizontal">
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<RichTextLabel Name="RewardLabel"/>
<RichTextLabel Name="ManifestLabel"/>
<RichTextLabel Name="NoticeLabel"/>
</BoxContainer>
<Control MinWidth="10"/>
<BoxContainer Orientation="Vertical" MinWidth="120">
<RichTextLabel Name="StatusLabel" HorizontalAlignment="Right" Margin="0 0 5 0"/>
<RichTextLabel Name="IdLabel" HorizontalAlignment="Right" Margin="0 0 5 0"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</PanelContainer>
</BoxContainer>
54 changes: 54 additions & 0 deletions Content.Client/Cargo/UI/BountyHistoryEntry.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Content.Client.Message;
using Content.Shared.Cargo;
using Content.Shared.Cargo.Prototypes;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

namespace Content.Client.Cargo.UI;

[GenerateTypedNameReferences]
public sealed partial class BountyHistoryEntry : BoxContainer
{
[Dependency] private readonly IPrototypeManager _prototype = default!;

public BountyHistoryEntry(CargoBountyHistoryData bounty)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);

if (!_prototype.TryIndex<CargoBountyPrototype>(bounty.Bounty, out var bountyPrototype))
return;

var items = new List<string>();
foreach (var entry in bountyPrototype.Entries)
{
items.Add(Loc.GetString("bounty-console-manifest-entry",
("amount", entry.Amount),
("item", Loc.GetString(entry.Name))));
}
ManifestLabel.SetMarkup(Loc.GetString("bounty-console-manifest-label", ("item", string.Join(", ", items))));
RewardLabel.SetMarkup(Loc.GetString("bounty-console-reward-label", ("reward", bountyPrototype.Reward)));
IdLabel.SetMarkup(Loc.GetString("bounty-console-id-label", ("id", bounty.Id)));

var stationTime = bounty.Timestamp.ToString("hh\\:mm\\:ss");
if (bounty.ActorName == null)
{
StatusLabel.SetMarkup(Loc.GetString("bounty-console-history-completed-label"));
NoticeLabel.SetMarkup(Loc.GetString("bounty-console-history-notice-completed-label", ("time", stationTime)));
}
else
{
StatusLabel.SetMarkup(Loc.GetString("bounty-console-history-skipped-label"));
NoticeLabel.SetMarkup(Loc.GetString("bounty-console-history-notice-skipped-label",
("id", bounty.ActorName),
("time", stationTime)));
}
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
}
}
29 changes: 20 additions & 9 deletions Content.Client/Cargo/UI/CargoBountyMenu.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,26 @@
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#1B1B1E" />
</PanelContainer.PanelOverride>
<ScrollContainer HScrollEnabled="False"
HorizontalExpand="True"
VerticalExpand="True">
<BoxContainer Name="BountyEntriesContainer"
Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True">
</BoxContainer>
</ScrollContainer>
<TabContainer Name="MasterTabContainer" VerticalExpand="True" HorizontalExpand="True">
<ScrollContainer HScrollEnabled="False"
HorizontalExpand="True"
VerticalExpand="True">
<BoxContainer Name="BountyEntriesContainer"
Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True">
</BoxContainer>
</ScrollContainer>
<ScrollContainer HScrollEnabled="False"
HorizontalExpand="True"
VerticalExpand="True">
<BoxContainer Name="BountyHistoryContainer"
Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True">
</BoxContainer>
</ScrollContainer>
</TabContainer>
</PanelContainer>
<!-- Footer -->
<BoxContainer Orientation="Vertical">
Expand Down
12 changes: 11 additions & 1 deletion Content.Client/Cargo/UI/CargoBountyMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ public CargoBountyMenu()
RobustXamlLoader.Load(this);
}

public void UpdateEntries(List<CargoBountyData> bounties, TimeSpan untilNextSkip)
public void UpdateEntries(List<CargoBountyData> bounties, List<CargoBountyHistoryData> history, TimeSpan untilNextSkip)
{
MasterTabContainer.SetTabTitle(0, Loc.GetString("bounty-console-tab-available-label"));
MasterTabContainer.SetTabTitle(1, Loc.GetString("bounty-console-tab-history-label"));

BountyEntriesContainer.Children.Clear();
foreach (var b in bounties)
{
Expand All @@ -32,5 +35,12 @@ public void UpdateEntries(List<CargoBountyData> bounties, TimeSpan untilNextSkip
{
MinHeight = 10
});

BountyHistoryContainer.Children.Clear();
foreach (var h in history)
{
var entry = new BountyHistoryEntry(h);
BountyHistoryContainer.AddChild(entry);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ public sealed partial class StationCargoBountyDatabaseComponent : Component
[DataField, ViewVariables(VVAccess.ReadWrite)]
public List<CargoBountyData> Bounties = new();

/// <summary>
/// A list of all the bounties that have been completed or
/// skipped for a station.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public List<CargoBountyHistoryData> History = new();

/// <summary>
/// Used to determine unique order IDs
/// </summary>
Expand Down
26 changes: 19 additions & 7 deletions Content.Server/Cargo/Systems/CargoSystem.Bounty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Content.Shared.Cargo.Components;
using Content.Shared.Cargo.Prototypes;
using Content.Shared.Database;
using Content.Shared.IdentityManagement;
using Content.Shared.NameIdentifier;
using Content.Shared.Paper;
using Content.Shared.Stacks;
Expand All @@ -16,6 +17,7 @@
using Robust.Server.Containers;
using Robust.Shared.Containers;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;

namespace Content.Server.Cargo.Systems;
Expand All @@ -25,6 +27,7 @@ public sealed partial class CargoSystem
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly NameIdentifierSystem _nameIdentifier = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSys = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;

[ValidatePrototypeId<NameIdentifierGroupPrototype>]
private const string BountyNameIdentifierGroup = "Bounty";
Expand Down Expand Up @@ -54,7 +57,7 @@ private void OnBountyConsoleOpened(EntityUid uid, CargoBountyConsoleComponent co
return;

var untilNextSkip = bountyDb.NextSkipTime - _timing.CurTime;
_uiSystem.SetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDb.Bounties, untilNextSkip));
_uiSystem.SetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDb.Bounties, bountyDb.History, untilNextSkip));
}

private void OnPrintLabelMessage(EntityUid uid, CargoBountyConsoleComponent component, BountyPrintLabelMessage args)
Expand Down Expand Up @@ -95,13 +98,13 @@ private void OnSkipBountyMessage(EntityUid uid, CargoBountyConsoleComponent comp
return;
}

if (!TryRemoveBounty(station, bounty.Value))
if (!TryRemoveBounty(station, bounty.Value, null, args.Actor))
return;

FillBountyDatabase(station);
db.NextSkipTime = _timing.CurTime + db.SkipDelay;
var untilNextSkip = db.NextSkipTime - _timing.CurTime;
_uiSystem.SetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, untilNextSkip));
_uiSystem.SetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, db.History, untilNextSkip));
_audio.PlayPvs(component.SkipSound, uid);
}

Expand Down Expand Up @@ -434,15 +437,15 @@ public bool TryAddBounty(EntityUid uid, CargoBountyPrototype bounty, StationCarg
}

[PublicAPI]
public bool TryRemoveBounty(EntityUid uid, string dataId, StationCargoBountyDatabaseComponent? component = null)
public bool TryRemoveBounty(EntityUid uid, string dataId, StationCargoBountyDatabaseComponent? component = null, EntityUid? actor = null)
{
if (!TryGetBountyFromId(uid, dataId, out var data, component))
return false;

return TryRemoveBounty(uid, data.Value, component);
return TryRemoveBounty(uid, data.Value, component, actor);
}

public bool TryRemoveBounty(EntityUid uid, CargoBountyData data, StationCargoBountyDatabaseComponent? component = null)
public bool TryRemoveBounty(EntityUid uid, CargoBountyData data, StationCargoBountyDatabaseComponent? component = null, EntityUid? actor = null)
{
if (!Resolve(uid, ref component))
return false;
Expand All @@ -451,6 +454,15 @@ public bool TryRemoveBounty(EntityUid uid, CargoBountyData data, StationCargoBou
{
if (component.Bounties[i].Id == data.Id)
{
string? actorName = default;
if (actor != null)
{
var getIdentityEvent = new TryGetIdentityShortInfoEvent(uid, actor.Value);
RaiseLocalEvent(getIdentityEvent);
actorName = getIdentityEvent.Title;
}

component.History.Add(new CargoBountyHistoryData(data, _gameTiming.CurTime, actorName));
component.Bounties.RemoveAt(i);
return true;
}
Expand Down Expand Up @@ -492,7 +504,7 @@ public void UpdateBountyConsoles()
}

var untilNextSkip = db.NextSkipTime - _timing.CurTime;
_uiSystem.SetUiState((uid, ui), CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, untilNextSkip));
_uiSystem.SetUiState((uid, ui), CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, db.History, untilNextSkip));
}
}

Expand Down
46 changes: 46 additions & 0 deletions Content.Shared/Cargo/CargoBountyHistoryData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Robust.Shared.Serialization;
using Content.Shared.Cargo.Prototypes;
using Robust.Shared.Prototypes;

namespace Content.Shared.Cargo;

/// <summary>
/// A data structure for storing historical information about bounties.
/// </summary>
[DataDefinition, NetSerializable, Serializable]
public readonly partial record struct CargoBountyHistoryData
{
/// <summary>
/// A unique id used to identify the bounty
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string Id { get; init; } = string.Empty;

/// <summary>
/// Optional name of the actor that skipped the bounty.
/// Only set when the bounty has been skipped.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string? ActorName { get; init; } = default;

/// <summary>
/// Time when this bounty was completed or skipped
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Timestamp { get; init; } = TimeSpan.MinValue;

/// <summary>
/// The prototype containing information about the bounty.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField(required: true)]
public ProtoId<CargoBountyPrototype> Bounty { get; init; } = string.Empty;

public CargoBountyHistoryData(CargoBountyData bounty, TimeSpan timestamp, string? actorName)
{
Bounty = bounty.Bounty;
Id = bounty.Id;
ActorName = actorName;
Timestamp = timestamp;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,13 @@ public sealed partial class CargoBountyConsoleComponent : Component
public sealed class CargoBountyConsoleState : BoundUserInterfaceState
{
public List<CargoBountyData> Bounties;
public List<CargoBountyHistoryData> History;
public TimeSpan UntilNextSkip;

public CargoBountyConsoleState(List<CargoBountyData> bounties, TimeSpan untilNextSkip)
public CargoBountyConsoleState(List<CargoBountyData> bounties, List<CargoBountyHistoryData> history, TimeSpan untilNextSkip)
{
Bounties = bounties;
History = history;
UntilNextSkip = untilNextSkip;
}
}
Expand Down
7 changes: 7 additions & 0 deletions Resources/Locale/en-US/cargo/cargo-bounty-console.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ bounty-console-flavor-right = v1.4
bounty-manifest-header = [font size=14][bold]Official cargo bounty manifest[/bold] (ID#{$id})[/font]
bounty-manifest-list-start = Item manifest:
bounty-console-tab-available-label = Available
bounty-console-tab-history-label = History
bounty-console-history-notice-completed-label = {$time} - Completed
bounty-console-history-notice-skipped-label = {$time} - Skipped by {$id}
bounty-console-history-completed-label = [color=limegreen]Completed[/color]
bounty-console-history-skipped-label = [color=red]Skipped[/color]

0 comments on commit 600ef0e

Please sign in to comment.