Skip to content

Commit

Permalink
Custom shipyard listings (#808)
Browse files Browse the repository at this point in the history
* Did the deed

* Fix spectre's name tag

* Removed the None ui key

* Typo

* Limit the empress' console to just 3 ships

* Cleanup

* Remove unused name field
  • Loading branch information
Mnemotechnician authored Jan 7, 2024
1 parent 913ef14 commit d381c3c
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ protected override void Open()
_menu.TargetIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent("ShipyardConsole-targetId"));
}

private void Populate(byte uiKey)
private void Populate(List<string> prototypes, string name)
{
if (_menu == null)
return;

_menu.PopulateProducts((ShipyardConsoleUiKey) uiKey);
_menu.PopulateProducts(prototypes, name);
_menu.PopulateCategories();
}

Expand All @@ -61,7 +61,7 @@ protected override void UpdateState(BoundUserInterfaceState state)
Balance = cState.Balance;
ShipSellValue = cState.ShipSellValue;
var castState = (ShipyardConsoleInterfaceState) state;
Populate(castState.UiKey);
Populate(castState.ShipyardPrototypes, castState.ShipyardName);
_menu?.UpdateState(castState);
}

Expand Down
51 changes: 20 additions & 31 deletions Content.Client/Shipyard/UI/ShipyardConsoleMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public sealed partial class ShipyardConsoleMenu : FancyWindow
private readonly List<string> _categoryStrings = new();
private string? _category;

private List<string> _lastProtos = new();
private string _lastType = "";

public ShipyardConsoleMenu(ShipyardConsoleBoundUserInterface owner)
{
RobustXamlLoader.Load(this);
Expand All @@ -38,12 +41,12 @@ public ShipyardConsoleMenu(ShipyardConsoleBoundUserInterface owner)
private void OnCategoryItemSelected(OptionButton.ItemSelectedEventArgs args)
{
SetCategoryText(args.Id);
PopulateProducts((ShipyardConsoleUiKey) _menu.UiKey);
PopulateProducts(_lastProtos, _lastType);
}

private void OnSearchBarTextChanged(LineEdit.LineEditEventArgs args)
{
PopulateProducts((ShipyardConsoleUiKey) _menu.UiKey);
PopulateProducts(_lastProtos, _lastType);
}

private void SetCategoryText(int id)
Expand All @@ -52,59 +55,45 @@ private void SetCategoryText(int id)
Categories.SelectId(id);
}

private void GetPrototypes(out IEnumerable<VesselPrototype> vessels)
{
vessels = _protoManager.EnumeratePrototypes<VesselPrototype>();
}

/// <summary>
/// Populates the list of products that will actually be shown, using the current filters.
/// </summary>
public void PopulateProducts(ShipyardConsoleUiKey uiKey)
public void PopulateProducts(List<string> prototypes, string type)
{
Vessels.RemoveAllChildren();
GetPrototypes(out var vessels);
var vesselList = vessels.ToList();
vesselList.Sort((x, y) =>
string.Compare(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase));

var type = uiKey switch
{
ShipyardConsoleUiKey.Shipyard => "Civilian",
ShipyardConsoleUiKey.Security => "Security",
ShipyardConsoleUiKey.BlackMarket => "BlackMarket",
ShipyardConsoleUiKey.Expedition => "Expedition",
ShipyardConsoleUiKey.Scrap => "Scrap",
_ => "Shipyard",
};
var newVessels = prototypes.Select(it => _protoManager.TryIndex<VesselPrototype>(it, out var proto) ? proto : null)
.Where(it => it != null)
.ToList();

newVessels.Sort((x, y) =>
string.Compare(x!.Name, y!.Name, StringComparison.CurrentCultureIgnoreCase));

var search = SearchBar.Text.Trim().ToLowerInvariant();

foreach (var prototype in vesselList)
foreach (var prototype in newVessels)
{
// filter by type for ui key
if (prototype.Group != type)
{
continue;
}
// if no search or category
// else if search
// else if category and not search
if (search.Length == 0 && _category == null ||
search.Length != 0 && prototype.Name.ToLowerInvariant().Contains(search) ||
search.Length == 0 && _category != null && prototype.Category.Equals(_category))
search.Length != 0 && prototype!.Name.ToLowerInvariant().Contains(search) ||
search.Length == 0 && _category != null && prototype!.Category.Equals(_category))
{
var vesselEntry = new VesselRow
{
Vessel = prototype,
VesselName = { Text = prototype.Name },
VesselName = { Text = prototype!.Name },
Purchase = { ToolTip = prototype.Description, TooltipDelay = 0.2f },
Price = { Text = Loc.GetString("cargo-console-menu-points-amount", ("amount", prototype.Price.ToString())) },
};
vesselEntry.Purchase.OnPressed += (args) => { OnOrderApproved?.Invoke(args); };
Vessels.AddChild(vesselEntry);
}
}

_lastProtos = prototypes;
_lastType = type;
}

/// <summary>
Expand All @@ -114,7 +103,7 @@ public void PopulateCategories()
{
_categoryStrings.Clear();
Categories.Clear();
GetPrototypes(out var vessels);
var vessels = _protoManager.EnumeratePrototypes<VesselPrototype>();
foreach (var prototype in vessels)
{
if (!_categoryStrings.Contains(prototype.Category))
Expand Down
56 changes: 55 additions & 1 deletion Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ private void OnPurchaseMessage(EntityUid uid, ShipyardConsoleComponent component
return;
}

if (!GetAvailableShuttles(uid).Contains(vessel.ID))
{
PlayDenySound(uid, component);
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(player):player} tried to purchase a vessel that was never available.");
return;
}

var name = vessel.Name;
if (vessel.Price <= 0)
return;
Expand Down Expand Up @@ -495,15 +502,62 @@ public bool FoundOrganics(EntityUid uid, EntityQuery<MobStateComponent> mobQuery
return false;
}

/// <summary>
/// Returns all shuttle prototype IDs the given shipyard console can offer.
/// </summary>
public List<string> GetAvailableShuttles(EntityUid uid, ShipyardConsoleUiKey? key = null, ShipyardListingComponent? listing = null)
{
var availableShuttles = new List<string>();

if (key == null && TryComp<UserInterfaceComponent>(uid, out var ui))
{
// Try to find a ui key that is an instance of the shipyard console ui key
foreach (var (k, v) in ui.Interfaces)
{
if (k is ShipyardConsoleUiKey shipyardKey)
{
key = shipyardKey;
break;
}
}
}

// Add all prototypes matching the ui key
if (key != null && key != ShipyardConsoleUiKey.Custom && ShipyardGroupMapping.TryGetValue(key.Value, out var group))
{
var protos = _prototypeManager.EnumeratePrototypes<VesselPrototype>();
foreach (var proto in protos)
{
if (proto.Group == group)
availableShuttles.Add(proto.ID);
}
}

// Add all prototypes specified in ShipyardListing
if (listing != null || TryComp(uid, out listing))
{
foreach (var shuttle in listing.Shuttles)
{
availableShuttles.Add(shuttle);
}
}

return availableShuttles;
}

private void RefreshState(EntityUid uid, int balance, bool access, string? shipDeed, int shipSellValue, bool isTargetIdPresent, ShipyardConsoleUiKey uiKey)
{
var listing = TryComp<ShipyardListingComponent>(uid, out var comp) ? comp : null;

var newState = new ShipyardConsoleInterfaceState(
balance,
access,
shipDeed,
shipSellValue,
isTargetIdPresent,
((byte)uiKey));
((byte)uiKey),
GetAvailableShuttles(uid, uiKey, listing),
uiKey.ToString());

_ui.TrySetUiState(uid, uiKey, newState);
}
Expand Down
9 changes: 8 additions & 1 deletion Content.Shared/Shipyard/BUI/ShipyardConsoleInterfaceState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,26 @@ public sealed class ShipyardConsoleInterfaceState : BoundUserInterfaceState
public readonly bool IsTargetIdPresent;
public readonly byte UiKey;

public readonly List<string> ShipyardPrototypes;
public readonly string ShipyardName;

public ShipyardConsoleInterfaceState(
int balance,
bool accessGranted,
string? shipDeedTitle,
int shipSellValue,
bool isTargetIdPresent,
byte uiKey)
byte uiKey,
List<string> shipyardPrototypes,
string shipyardName)
{
Balance = balance;
AccessGranted = accessGranted;
ShipDeedTitle = shipDeedTitle;
ShipSellValue = shipSellValue;
IsTargetIdPresent = isTargetIdPresent;
UiKey = uiKey;
ShipyardPrototypes = shipyardPrototypes;
ShipyardName = shipyardName;
}
}
17 changes: 17 additions & 0 deletions Content.Shared/Shipyard/Components/ShipyardListingComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Content.Shared.Shipyard.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;

namespace Content.Shared.Shipyard.Components;

/// <summary>
/// When applied to a shipyard console, adds all specified shuttles to the list of sold shuttles.
/// </summary>
[RegisterComponent]
public sealed partial class ShipyardListingComponent : Component
{
/// <summary>
/// All VesselPrototype IDs that should be listed in this shipyard console.
/// </summary>
[ViewVariables, DataField(customTypeSerializer: typeof(PrototypeIdListSerializer<VesselPrototype>))]
public List<string> Shuttles = new();
}
21 changes: 17 additions & 4 deletions Content.Shared/Shipyard/SharedShipyardSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,34 @@

namespace Content.Shared.Shipyard;

// Note: when adding a new ui key, don't forget to modify the dictionary in SharedShipyardSystem
[NetSerializable, Serializable]
public enum ShipyardConsoleUiKey : byte
{
Shipyard,
Security,
BlackMarket,
Expedition,
Scrap
// Syndicate
//Not currently implemented. Could be used in the future to give other factions a variety of shuttle options,
//like nukies, syndicate, or for evac purchases.
Scrap,
// Do not add any ship to this key. Shipyards using it are inherently empty and are populated using the ShipyardListingComponent.
Custom
}

public abstract class SharedShipyardSystem : EntitySystem
{
/// <summary>
/// Maps entries of the <see cref="ShipyardConsoleUiKey"/> enum to how they're specified in shuttle prototype files
/// </summary>
public static readonly Dictionary<ShipyardConsoleUiKey, string> ShipyardGroupMapping = new()
{
{ShipyardConsoleUiKey.Shipyard, "Civilian"},
{ShipyardConsoleUiKey.Security, "Security"},
{ShipyardConsoleUiKey.BlackMarket, "BlackMarket"},
{ShipyardConsoleUiKey.Expedition, "Expedition"},
{ShipyardConsoleUiKey.Scrap, "Scrap"},
{ShipyardConsoleUiKey.Custom, "<DO NOT USE>"}
};

[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;

public override void Initialize()
Expand Down
2 changes: 1 addition & 1 deletion Resources/Maps/Shuttles/empress.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6940,7 +6940,7 @@ entities:
- pos: 15.5,-6.5
parent: 1
type: Transform
- proto: ComputerShipyardSecurity
- proto: EmpressMothershipComputer
entities:
- uid: 118
components:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
interfaces:
- key: enum.ShipyardConsoleUiKey.Shipyard
type: ShipyardConsoleBoundUserInterface
- type: ItemSlots
- type: ItemSlots
- type: ContainerContainer
containers:
ShipyardConsole-targetId: !type:ContainerSlot {}
Expand All @@ -80,6 +80,22 @@
!type:DamageTrigger
damage: 0

# Custom console
- type: entity
id: BaseMothershipComputer
parent: ComputerShipyard
name: mothership console
description: Used on motherships to purchase and sell ships without returning to a station.
components:
- type: ActivatableUI
key: enum.ShipyardConsoleUiKey.Custom
- type: UserInterface
interfaces:
- key: enum.ShipyardConsoleUiKey.Custom
type: ShipyardConsoleBoundUserInterface
- type: ShipyardListing

# Hardcoded consoles
- type: entity
id: ComputerShipyardSecurity
parent: ComputerShipyard
Expand All @@ -100,7 +116,7 @@
- map: ["computerLayerKeyboard"]
state: generic_keyboard
- map: ["computerLayerScreen"]
state: shipyard_security
state: shipyard_security
- map: ["computerLayerKeys"]
state: telesci_key

Expand All @@ -124,7 +140,7 @@
- map: ["computerLayerKeyboard"]
state: generic_keyboard
- map: ["computerLayerScreen"]
state: shipyard_blackmarket
state: shipyard_blackmarket
- map: ["computerLayerKeys"]
state: blackmarket_key
- type: Destructible
Expand Down Expand Up @@ -156,7 +172,7 @@
- map: ["computerLayerKeyboard"]
state: generic_keyboard
- map: ["computerLayerScreen"]
state: shipyard_blackmarket
state: shipyard_blackmarket
- map: ["computerLayerKeys"]
state: blackmarket_key

Expand All @@ -180,7 +196,7 @@
- map: ["computerLayerKeyboard"]
state: generic_keyboard
- map: ["computerLayerScreen"]
state: shipyard_blackmarket
state: shipyard_blackmarket
- map: ["computerLayerKeys"]
state: blackmarket_key

Expand Down Expand Up @@ -281,4 +297,4 @@
description: Used to sell goods loaded onto cargo pallets
components:
- type: MarketModifier
mod: 0.40
mod: 0.40
Loading

0 comments on commit d381c3c

Please sign in to comment.