336 lines
12 KiB
C#
336 lines
12 KiB
C#
using System.Linq;
|
|
using Content.Client.UserInterface.Controls;
|
|
using Content.Client._NF.Shipyard.BUI;
|
|
using Content.Shared._NF.Bank;
|
|
using Content.Shared._NF.Shipyard.BUI;
|
|
using Content.Shared._NF.Shipyard.Prototypes;
|
|
using Robust.Client.AutoGenerated;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.XAML;
|
|
using Robust.Shared.Prototypes;
|
|
using static Robust.Client.UserInterface.Controls.BaseButton;
|
|
using Robust.Client.Player;
|
|
|
|
namespace Content.Client._NF.Shipyard.UI;
|
|
|
|
[GenerateTypedNameReferences]
|
|
public sealed partial class ShipyardConsoleMenu : FancyWindow
|
|
{
|
|
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
|
[Dependency] private readonly IEntityManager _entMan = default!; // Horizon
|
|
[Dependency] private readonly IPlayerManager _player = default!; // Horizon
|
|
|
|
public event Action<ButtonEventArgs>? OnSellShip;
|
|
public event Action<ButtonEventArgs>? OnOrderApproved;
|
|
private readonly List<VesselSize> _categoryStrings = new();
|
|
private readonly List<VesselClass> _classStrings = new();
|
|
private readonly List<VesselEngine> _engineStrings = new();
|
|
private VesselSize? _category;
|
|
private VesselClass? _class;
|
|
private VesselEngine? _engine;
|
|
|
|
private List<string> _lastAvailableProtos = new();
|
|
private List<string> _lastUnavailableProtos = new();
|
|
private bool _freeListings = false;
|
|
private bool _validId = false;
|
|
private ConfirmButton? _currentlyConfirmingButton = null;
|
|
|
|
public EntityUid Owner = EntityUid.Invalid; // Horizon
|
|
|
|
public ShipyardConsoleMenu()
|
|
{
|
|
RobustXamlLoader.Load(this);
|
|
IoCManager.InjectDependencies(this);
|
|
Title = Loc.GetString("shipyard-console-menu-title");
|
|
SearchBar.OnTextChanged += OnSearchBarTextChanged;
|
|
Categories.OnItemSelected += OnCategoryItemSelected;
|
|
Classes.OnItemSelected += OnClassItemSelected;
|
|
Engines.OnItemSelected += OnEngineItemSelected;
|
|
SellShipButton.OnPressed += (args) => { OnSellShip?.Invoke(args); };
|
|
}
|
|
|
|
|
|
private void OnCategoryItemSelected(OptionButton.ItemSelectedEventArgs args)
|
|
{
|
|
SetCategoryText(args.Id);
|
|
PopulateProducts(_lastAvailableProtos, _lastUnavailableProtos, _freeListings, _validId);
|
|
}
|
|
|
|
private void OnClassItemSelected(OptionButton.ItemSelectedEventArgs args)
|
|
{
|
|
SetClassText(args.Id);
|
|
PopulateProducts(_lastAvailableProtos, _lastUnavailableProtos, _freeListings, _validId);
|
|
}
|
|
|
|
private void OnEngineItemSelected(OptionButton.ItemSelectedEventArgs args)
|
|
{
|
|
SetEngineText(args.Id);
|
|
PopulateProducts(_lastAvailableProtos, _lastUnavailableProtos, _freeListings, _validId);
|
|
}
|
|
|
|
private void OnSearchBarTextChanged(LineEdit.LineEditEventArgs args)
|
|
{
|
|
PopulateProducts(_lastAvailableProtos, _lastUnavailableProtos, _freeListings, _validId);
|
|
}
|
|
|
|
private void SetCategoryText(int id)
|
|
{
|
|
_category = id == 0 ? null : _categoryStrings[id];
|
|
Categories.SelectId(id);
|
|
}
|
|
private void SetClassText(int id)
|
|
{
|
|
_class = id == 0 ? null : _classStrings[id];
|
|
Classes.SelectId(id);
|
|
}
|
|
private void SetEngineText(int id)
|
|
{
|
|
_engine = id == 0 ? null : _engineStrings[id];
|
|
Engines.SelectId(id);
|
|
}
|
|
/// <summary>
|
|
/// Populates the list of products that will actually be shown, using the current filters.
|
|
/// </summary>
|
|
public void PopulateProducts(List<string> availablePrototypes, List<string> unavailablePrototypes, bool free, bool canPurchase)
|
|
{
|
|
Vessels.RemoveAllChildren();
|
|
|
|
var search = SearchBar.Text.Trim().ToLowerInvariant();
|
|
|
|
var newVessels = GetVesselPrototypesFromIds(availablePrototypes);
|
|
AddVesselsToControls(newVessels, search, free, canPurchase);
|
|
|
|
var newUnavailableVessels = GetVesselPrototypesFromIds(unavailablePrototypes);
|
|
AddVesselsToControls(newUnavailableVessels, search, free, false);
|
|
|
|
_lastAvailableProtos = availablePrototypes;
|
|
_lastUnavailableProtos = unavailablePrototypes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a set of prototype IDs, returns a corresponding set of prototypes, ordered by name.
|
|
/// </summary>
|
|
private List<VesselPrototype?> GetVesselPrototypesFromIds(IEnumerable<string> protoIds)
|
|
{
|
|
var vesselList = protoIds.Select(it => _protoManager.TryIndex<VesselPrototype>(it, out var proto) ? proto : null)
|
|
.Where(it => it != null)
|
|
.ToList();
|
|
|
|
vesselList.Sort((x, y) =>
|
|
string.Compare(x!.Name, y!.Name, StringComparison.CurrentCultureIgnoreCase));
|
|
return vesselList;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds all vessels in a given list of prototypes as VesselRows in the UI.
|
|
/// </summary>
|
|
private void AddVesselsToControls(IEnumerable<VesselPrototype?> vessels, string search, bool free, bool canPurchase)
|
|
{
|
|
foreach (var prototype in vessels)
|
|
{
|
|
// Filter any ships
|
|
if (_category != null && !prototype!.Category.Equals(_category))
|
|
continue;
|
|
if (_class != null && !prototype!.Classes.Contains(_class.Value))
|
|
continue;
|
|
if (_engine != null && !prototype!.Engines.Contains(_engine.Value))
|
|
continue;
|
|
if (search.Length > 0 && !prototype!.Name.ToLowerInvariant().Contains(search))
|
|
continue;
|
|
|
|
string priceText;
|
|
if (free)
|
|
priceText = Loc.GetString("shipyard-console-menu-listing-free");
|
|
else
|
|
{
|
|
// Horizon tweak start
|
|
var cost = prototype!.Price;
|
|
foreach (var item in prototype!.CostModifiers)
|
|
item.Modify(_player.LocalEntity, Owner, ref cost, _entMan);
|
|
|
|
priceText = BankSystemExtensions.ToSpesoString(cost);
|
|
|
|
var diff = cost - prototype.Price;
|
|
var percentage = (float)diff / (float)prototype.Price * 100.0f;
|
|
|
|
if (diff != 0)
|
|
priceText += $" ({(diff > 0 ? "+" : "")}{percentage:F1}%)";
|
|
// Horizon tweak end
|
|
}
|
|
|
|
var vesselEntry = new VesselRow
|
|
{
|
|
Vessel = prototype,
|
|
VesselName = { Text = prototype!.Name },
|
|
Purchase = { Text = Loc.GetString("shipyard-console-purchase-available"), Disabled = !canPurchase },
|
|
Guidebook = { Disabled = prototype.GuidebookPage is null, TooltipDelay = 0.2f, ToolTip = prototype.Description },
|
|
Price = { Text = priceText },
|
|
};
|
|
vesselEntry.Purchase.OnConfirming += OnStartConfirmingPurchase;
|
|
vesselEntry.Purchase.OnPressed += (args) => { _currentlyConfirmingButton = null; OnOrderApproved?.Invoke(args); };
|
|
Vessels.AddChild(vesselEntry);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Confirming handler: ensures that only one button is confirming at a time.
|
|
/// </summary>
|
|
private void OnStartConfirmingPurchase(ButtonEventArgs args)
|
|
{
|
|
if (args.Button is not ConfirmButton confirmButton)
|
|
return;
|
|
|
|
if (_currentlyConfirmingButton != null)
|
|
_currentlyConfirmingButton.ClearIsConfirming();
|
|
_currentlyConfirmingButton = confirmButton;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populates the list categories that will actually be shown, using the current filters.
|
|
/// </summary>
|
|
public void PopulateCategories(List<string> availablePrototypes, List<string> unavailablePrototypes)
|
|
{
|
|
_categoryStrings.Clear();
|
|
Categories.Clear();
|
|
|
|
AddCategoriesFromPrototypes(availablePrototypes);
|
|
AddCategoriesFromPrototypes(unavailablePrototypes);
|
|
|
|
_categoryStrings.Sort();
|
|
|
|
// Add "All" category at the top of the list
|
|
_categoryStrings.Insert(0, VesselSize.All);
|
|
|
|
foreach (var str in _categoryStrings)
|
|
{
|
|
Categories.AddItem(Loc.GetString($"shipyard-console-category-{str}"));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds all ship categories from a list of vessel prototypes to the current control's list if they are missing.
|
|
/// </summary>
|
|
private void AddCategoriesFromPrototypes(IEnumerable<string> prototypes)
|
|
{
|
|
foreach (var protoId in prototypes)
|
|
{
|
|
if (!_protoManager.TryIndex<VesselPrototype>(protoId, out var prototype))
|
|
continue;
|
|
|
|
if (!_categoryStrings.Contains(prototype.Category) && prototype.Category != VesselSize.All)
|
|
{
|
|
_categoryStrings.Add(prototype.Category);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populates the list classes that will actually be shown, using the current filters.
|
|
/// </summary>
|
|
public void PopulateClasses(List<string> availablePrototypes, List<string> unavailablePrototypes)
|
|
{
|
|
_classStrings.Clear();
|
|
Classes.Clear();
|
|
|
|
AddClassesFromPrototypes(availablePrototypes);
|
|
AddClassesFromPrototypes(unavailablePrototypes);
|
|
|
|
_classStrings.Sort();
|
|
|
|
// Add "All" category at the top of the list
|
|
_classStrings.Insert(0, VesselClass.All);
|
|
|
|
foreach (var str in _classStrings)
|
|
{
|
|
Classes.AddItem(Loc.GetString($"shipyard-console-class-{str}"));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds all ship classes from a list of vessel prototypes to the current control's list if they are missing.
|
|
/// </summary>
|
|
private void AddClassesFromPrototypes(IEnumerable<string> prototypes)
|
|
{
|
|
foreach (var protoId in prototypes)
|
|
{
|
|
if (!_protoManager.TryIndex<VesselPrototype>(protoId, out var prototype))
|
|
continue;
|
|
|
|
foreach (var cl in prototype.Classes)
|
|
{
|
|
if (!_classStrings.Contains(cl) && cl != VesselClass.All)
|
|
{
|
|
_classStrings.Add(cl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populates the list engines that will actually be shown, using the current filters.
|
|
/// </summary>
|
|
public void PopulateEngines(List<string> availablePrototypes, List<string> unavailablePrototypes)
|
|
{
|
|
_engineStrings.Clear();
|
|
Engines.Clear();
|
|
|
|
AddEnginesFromPrototypes(availablePrototypes);
|
|
AddEnginesFromPrototypes(unavailablePrototypes);
|
|
|
|
_engineStrings.Sort();
|
|
|
|
// Add "All" category at the top of the list
|
|
_engineStrings.Insert(0, VesselEngine.All);
|
|
|
|
foreach (var str in _engineStrings)
|
|
{
|
|
Engines.AddItem(Loc.GetString($"shipyard-console-engine-{str}"));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds all ship engine power type from a list of vessel prototypes to the current control's list if they are missing.
|
|
/// </summary>
|
|
private void AddEnginesFromPrototypes(IEnumerable<string> prototypes)
|
|
{
|
|
foreach (var protoId in prototypes)
|
|
{
|
|
if (!_protoManager.TryIndex<VesselPrototype>(protoId, out var prototype))
|
|
continue;
|
|
|
|
foreach (var cl in prototype.Engines)
|
|
{
|
|
if (!_engineStrings.Contains(cl) && cl != VesselEngine.All)
|
|
{
|
|
_engineStrings.Add(cl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void UpdateState(ShipyardConsoleInterfaceState state)
|
|
{
|
|
BalanceLabel.Text = BankSystemExtensions.ToSpesoString(state.Balance);
|
|
var shipPrice = 0;
|
|
if (!state.FreeListings)
|
|
shipPrice = state.ShipSellValue;
|
|
|
|
ShipAppraisalLabel.Text = $"{BankSystemExtensions.ToSpesoString(shipPrice)} ({state.SellRate * 100.0f:F1}%)";
|
|
SellShipButton.Disabled = state.ShipDeedTitle == null;
|
|
TargetIdButton.Text = state.IsTargetIdPresent
|
|
? Loc.GetString("id-card-console-window-eject-button")
|
|
: Loc.GetString("id-card-console-window-insert-button");
|
|
if (state.ShipDeedTitle != null)
|
|
{
|
|
DeedTitle.Text = state.ShipDeedTitle;
|
|
}
|
|
else
|
|
{
|
|
DeedTitle.Text = $"None";
|
|
}
|
|
_freeListings = state.FreeListings;
|
|
_validId = state.IsTargetIdPresent;
|
|
PopulateProducts(_lastAvailableProtos, _lastUnavailableProtos, _freeListings, _validId);
|
|
}
|
|
}
|