diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 865ab6fd31..4ecc6e6a73 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -10,6 +10,7 @@ using Content.Client.Parallax; using Content.Client.Sandbox; using Content.Client.UserInterface; using Content.Shared.GameObjects.Components; +using Content.Shared.GameObjects.Components.Cargo; using Content.Shared.GameObjects.Components.Chemistry; using Content.Shared.GameObjects.Components.Markers; using Content.Shared.GameObjects.Components.Research; @@ -136,7 +137,7 @@ namespace Content.Client factory.Register(); factory.Register(); - + factory.Register(); factory.Register(); prototypes.RegisterIgnore("material"); diff --git a/Content.Client/GameObjects/Components/Cargo/CargoConsoleBoundUserInterface.cs b/Content.Client/GameObjects/Components/Cargo/CargoConsoleBoundUserInterface.cs new file mode 100644 index 0000000000..d98a89173b --- /dev/null +++ b/Content.Client/GameObjects/Components/Cargo/CargoConsoleBoundUserInterface.cs @@ -0,0 +1,132 @@ +using Content.Client.UserInterface.Cargo; +using Content.Shared.GameObjects.Components.Cargo; +using Content.Shared.Prototypes.Cargo; +using Robust.Client.GameObjects.Components.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.ViewVariables; + +namespace Content.Client.GameObjects.Components.Cargo +{ + public class CargoConsoleBoundUserInterface : BoundUserInterface + { + [ViewVariables] + private CargoConsoleMenu _menu; + [ViewVariables] + private CargoConsoleOrderMenu _orderMenu; + + [ViewVariables] + public GalacticMarketComponent Market { get; private set; } + [ViewVariables] + public CargoOrderDatabaseComponent Orders { get; private set; } + [ViewVariables] + public bool RequestOnly { get; private set; } + [ViewVariables] + public int BankId { get; private set; } + [ViewVariables] + public string BankName { get; private set; } + [ViewVariables] + public int BankBalance { get; private set; } + + private CargoProductPrototype _product; + + public CargoConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + base.Open(); + + if (!Owner.Owner.TryGetComponent(out GalacticMarketComponent market) + || !Owner.Owner.TryGetComponent(out CargoOrderDatabaseComponent orders)) return; + + Market = market; + Orders = orders; + + _menu = new CargoConsoleMenu(this); + _orderMenu = new CargoConsoleOrderMenu(); + + _menu.OnClose += Close; + + _menu.Populate(); + + Market.OnDatabaseUpdated += _menu.PopulateProducts; + Market.OnDatabaseUpdated += _menu.PopulateCategories; + Orders.OnDatabaseUpdated += _menu.PopulateOrders; + + _menu.CallShuttleButton.OnPressed += (args) => + { + SendMessage(new SharedCargoConsoleComponent.CargoConsoleShuttleMessage()); + }; + _menu.OnItemSelected += (args) => + { + if (!(args.Button.Parent is CargoProductRow row)) + return; + _product = row.Product; + _orderMenu.Requester.Text = null; + _orderMenu.Reason.Text = null; + _orderMenu.Amount.Value = 1; + _orderMenu.OpenCenteredMinSize(); + }; + _menu.OnOrderApproved += ApproveOrder; + _menu.OnOrderCanceled += RemoveOrder; + _orderMenu.SubmitButton.OnPressed += (args) => + { + AddOrder(); + _orderMenu.Close(); + }; + + _menu.OpenCentered(); + + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + if (!(state is CargoConsoleInterfaceState cstate)) + return; + if (RequestOnly != cstate.RequestOnly) + { + RequestOnly = cstate.RequestOnly; + _menu.UpdateRequestOnly(); + } + BankId = cstate.BankId; + BankName = cstate.BankName; + BankBalance = cstate.BankBalance; + _menu.UpdateBankData(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + Market.OnDatabaseUpdated -= _menu.PopulateProducts; + Market.OnDatabaseUpdated -= _menu.PopulateCategories; + Orders.OnDatabaseUpdated -= _menu.PopulateOrders; + _menu?.Dispose(); + _orderMenu?.Dispose(); + } + + internal void AddOrder() + { + SendMessage(new SharedCargoConsoleComponent.CargoConsoleAddOrderMessage(_orderMenu.Requester.Text, + _orderMenu.Reason.Text, _product.ID, _orderMenu.Amount.Value)); + } + + internal void RemoveOrder(BaseButton.ButtonEventArgs args) + { + if (!(args.Button.Parent.Parent is CargoOrderRow row)) + return; + SendMessage(new SharedCargoConsoleComponent.CargoConsoleRemoveOrderMessage(row.Order.OrderNumber)); + } + + internal void ApproveOrder(BaseButton.ButtonEventArgs args) + { + if (!(args.Button.Parent.Parent is CargoOrderRow row)) + return; + SendMessage(new SharedCargoConsoleComponent.CargoConsoleApproveOrderMessage(row.Order.OrderNumber)); + } + } +} diff --git a/Content.Client/GameObjects/Components/Cargo/CargoOrderDatabaseComponent.cs b/Content.Client/GameObjects/Components/Cargo/CargoOrderDatabaseComponent.cs new file mode 100644 index 0000000000..18b729b8ca --- /dev/null +++ b/Content.Client/GameObjects/Components/Cargo/CargoOrderDatabaseComponent.cs @@ -0,0 +1,56 @@ +using Content.Shared.GameObjects.Components.Cargo; +using Content.Shared.Prototypes.Cargo; +using Robust.Shared.GameObjects; +using System; +using System.Collections.Generic; + +namespace Content.Client.GameObjects.Components.Cargo +{ + [RegisterComponent] + public class CargoOrderDatabaseComponent : SharedCargoOrderDatabaseComponent + { + private List _orders = new List(); + + public IReadOnlyList Orders => _orders; + /// + /// Event called when the database is updated. + /// + public event Action OnDatabaseUpdated; + + // TODO add account selector menu + + /// + /// Removes all orders from the database. + /// + public virtual void Clear() + { + _orders.Clear(); + } + + /// + /// Adds an order to the database. + /// + /// The order to be added. + public virtual void AddOrder(CargoOrderData order) + { + if (!_orders.Contains(order)) + _orders.Add(order); + } + + public override void HandleComponentState(ComponentState curState, ComponentState nextState) + { + base.HandleComponentState(curState, nextState); + if (!(curState is CargoOrderDatabaseState state)) + return; + Clear(); + if (state.Orders == null) + return; + foreach (var order in state.Orders) + { + AddOrder(order); + } + + OnDatabaseUpdated?.Invoke(); + } + } +} diff --git a/Content.Client/GameObjects/Components/Cargo/GalacticMarketComponent.cs b/Content.Client/GameObjects/Components/Cargo/GalacticMarketComponent.cs new file mode 100644 index 0000000000..bb29dfd1d4 --- /dev/null +++ b/Content.Client/GameObjects/Components/Cargo/GalacticMarketComponent.cs @@ -0,0 +1,38 @@ +using Content.Shared.GameObjects.Components.Cargo; +using Content.Shared.Prototypes.Cargo; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using System; + +namespace Content.Client.GameObjects.Components.Cargo +{ + [RegisterComponent] + public class GalacticMarketComponent : SharedGalacticMarketComponent + { +#pragma warning disable CS0649 + [Dependency] private IPrototypeManager _prototypeManager; +#pragma warning restore + + /// + /// Event called when the database is updated. + /// + public event Action OnDatabaseUpdated; + + public override void HandleComponentState(ComponentState curState, ComponentState nextState) + { + base.HandleComponentState(curState, nextState); + if (!(curState is GalacticMarketState state)) + return; + _products.Clear(); + foreach (var productId in state.Products) + { + if (!_prototypeManager.TryIndex(productId, out CargoProductPrototype product)) + continue; + _products.Add(product); + } + + OnDatabaseUpdated?.Invoke(); + } + } +} diff --git a/Content.Client/UserInterface/Cargo/CargoConsoleMenu.cs b/Content.Client/UserInterface/Cargo/CargoConsoleMenu.cs new file mode 100644 index 0000000000..9db6b0a7ac --- /dev/null +++ b/Content.Client/UserInterface/Cargo/CargoConsoleMenu.cs @@ -0,0 +1,465 @@ +using Content.Client.GameObjects.Components.Cargo; +using Content.Shared.Prototypes.Cargo; +using Robust.Client.Graphics; +using Robust.Client.Graphics.Drawing; +using Robust.Client.Interfaces.ResourceManagement; +using Robust.Client.ResourceManagement; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.Utility; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Maths; +using Robust.Shared.Utility; +using System; +using System.Collections.Generic; +using Content.Client.Utility; + +namespace Content.Client.UserInterface.Cargo +{ + public class CargoConsoleMenu : SS14Window + { +#pragma warning disable 649 + [Dependency] private readonly ILocalizationManager _loc; + [Dependency] private readonly IResourceCache _resourceCache; +#pragma warning restore 649 + + protected override Vector2? CustomSize => (400, 600); + + public CargoConsoleBoundUserInterface Owner { get; private set; } + + public event Action OnItemSelected; + public event Action OnOrderApproved; + public event Action OnOrderCanceled; + + private List _categoryStrings = new List(); + + private Label _accountNameLabel { get; set; } + private Label _pointsLabel { get; set; } + private Label _shuttleStatusLabel { get; set; } + private VBoxContainer _requests { get; set; } + private VBoxContainer _orders { get; set; } + private OptionButton _categories { get; set; } + private LineEdit _searchBar { get; set; } + + public VBoxContainer Products { get; set; } + public Button CallShuttleButton { get; set; } + public Button PermissionsButton { get; set; } + + private string _category = null; + + public CargoConsoleMenu(CargoConsoleBoundUserInterface owner) + { + IoCManager.InjectDependencies(this); + Owner = owner; + + if (Owner.RequestOnly) + Title = _loc.GetString("Cargo Request Console"); + else + Title = _loc.GetString("Cargo Shuttle Console"); + + var rows = new VBoxContainer + { + MarginTop = 0 + }; + + var accountName = new HBoxContainer() + { + MarginTop = 0 + }; + var accountNameLabel = new Label { + Text = _loc.GetString("Account Name: "), + StyleClasses = { NanoStyle.StyleClassLabelKeyText } + }; + _accountNameLabel = new Label { + Text = "None" //Owner.Bank.Account.Name + }; + accountName.AddChild(accountNameLabel); + accountName.AddChild(_accountNameLabel); + rows.AddChild(accountName); + + var points = new HBoxContainer(); + var pointsLabel = new Label + { + Text = _loc.GetString("Points: "), + StyleClasses = { NanoStyle.StyleClassLabelKeyText } + }; + _pointsLabel = new Label + { + Text = "0" //Owner.Bank.Account.Balance.ToString() + }; + points.AddChild(pointsLabel); + points.AddChild(_pointsLabel); + rows.AddChild(points); + + var shuttleStatus = new HBoxContainer(); + var shuttleStatusLabel = new Label + { + Text = _loc.GetString("Shuttle Status: "), + StyleClasses = { NanoStyle.StyleClassLabelKeyText } + }; + _shuttleStatusLabel = new Label + { + Text = _loc.GetString("Away") // Shuttle.Status + }; + shuttleStatus.AddChild(shuttleStatusLabel); + shuttleStatus.AddChild(_shuttleStatusLabel); + rows.AddChild(shuttleStatus); + + var buttons = new HBoxContainer(); + CallShuttleButton = new Button() + { + Text = _loc.GetString("Call Shuttle"), + TextAlign = Button.AlignMode.Center, + SizeFlagsHorizontal = SizeFlags.FillExpand + }; + PermissionsButton = new Button() + { + Text = _loc.GetString("Permissions"), + TextAlign = Button.AlignMode.Center + }; + buttons.AddChild(CallShuttleButton); + buttons.AddChild(PermissionsButton); + rows.AddChild(buttons); + + var category = new HBoxContainer(); + _categories = new OptionButton + { + Prefix = _loc.GetString("Categories: "), + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 1 + }; + _searchBar = new LineEdit + { + PlaceHolder = _loc.GetString("Search"), + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 1 + }; + category.AddChild(_categories); + category.AddChild(_searchBar); + rows.AddChild(category); + + var products = new ScrollContainer() + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 6 + }; + Products = new VBoxContainer() + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsVertical = SizeFlags.FillExpand + }; + products.AddChild(Products); + rows.AddChild(products); + + var requestsAndOrders = new PanelContainer + { + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 6, + PanelOverride = new StyleBoxFlat { BackgroundColor = Color.Black } + }; + var orderScrollBox = new ScrollContainer + { + SizeFlagsVertical = SizeFlags.FillExpand + }; + var rAndOVBox = new VBoxContainer(); + var requestsLabel = new Label { Text = _loc.GetString("Requests") }; + _requests = new VBoxContainer // replace with scroll box so that approval buttons can be added + { + StyleClasses = { "transparentItemList" }, + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 1, + }; + var ordersLabel = new Label { Text = _loc.GetString("Orders") }; + _orders = new VBoxContainer + { + StyleClasses = { "transparentItemList" }, + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 1, + }; + rAndOVBox.AddChild(requestsLabel); + rAndOVBox.AddChild(_requests); + rAndOVBox.AddChild(ordersLabel); + rAndOVBox.AddChild(_orders); + orderScrollBox.AddChild(rAndOVBox); + requestsAndOrders.AddChild(orderScrollBox); + rows.AddChild(requestsAndOrders); + + rows.AddChild(new TextureButton + { + SizeFlagsVertical = SizeFlags.FillExpand, + }); + Contents.AddChild(rows); + + CallShuttleButton.OnPressed += OnCallShuttleButtonPressed; + _searchBar.OnTextChanged += OnSearchBarTextChanged; + _categories.OnItemSelected += OnCategoryItemSelected; + } + + private void OnCallShuttleButtonPressed(BaseButton.ButtonEventArgs args) + { + } + + private void OnCategoryItemSelected(OptionButton.ItemSelectedEventArgs args) + { + SetCategoryText(args.Id); + PopulateProducts(); + } + + private void OnSearchBarTextChanged(LineEdit.LineEditEventArgs args) + { + PopulateProducts(); + } + + private void SetCategoryText(int id) + { + if (id == 0) + _category = null; + else + _category = _categoryStrings[id]; + _categories.SelectId(id); + } + + /// + /// Populates the list of products that will actually be shown, using the current filters. + /// + public void PopulateProducts() + { + Products.RemoveAllChildren(); + + var search = _searchBar.Text.Trim().ToLowerInvariant(); + foreach (var prototype in Owner.Market.Products) + { + // 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))) + { + var button = new CargoProductRow(); + button.Product = prototype; + button.ProductName.Text = prototype.Name; + button.PointCost.Text = prototype.PointCost.ToString(); + button.Icon.Texture = prototype.Icon.Frame0(); + button.MainButton.OnPressed += (args) => + { + OnItemSelected?.Invoke(args); + }; + Products.AddChild(button); + } + } + } + + /// + /// Populates the list of products that will actually be shown, using the current filters. + /// + public void PopulateCategories() + { + _categoryStrings.Clear(); + _categories.Clear(); + + _categoryStrings.Add(_loc.GetString("All")); + + var search = _searchBar.Text.Trim().ToLowerInvariant(); + foreach (var prototype in Owner.Market.Products) + { + if (!_categoryStrings.Contains(prototype.Category)) + { + _categoryStrings.Add(_loc.GetString(prototype.Category)); + } + } + _categoryStrings.Sort(); + foreach (var str in _categoryStrings) + { + _categories.AddItem(str); + } + } + + /// + /// Populates the list of orders and requests. + /// + public void PopulateOrders() + { + _orders.RemoveAllChildren(); + _requests.RemoveAllChildren(); + + foreach (var order in Owner.Orders.Orders) + { + var row = new CargoOrderRow(); + row.Order = order; + row.Icon.Texture = Owner.Market.GetProduct(order.ProductId).Icon.Frame0(); + row.ProductName.Text = $"{Owner.Market.GetProduct(order.ProductId).Name} (x{order.Amount}) by {order.Requester}"; + row.Description.Text = $"Reasons: {order.Reason}"; + row.Cancel.OnPressed += (args) => { OnOrderCanceled?.Invoke(args); }; + if (order.Approved) + { + row.Approve.Visible = false; + row.Cancel.Visible = false; + _orders.AddChild(row); + } + else + { + if (Owner.RequestOnly) + row.Approve.Visible = false; + else + row.Approve.OnPressed += (args) => { OnOrderApproved?.Invoke(args); }; + _requests.AddChild(row); + } + } + } + + public void Populate() + { + PopulateProducts(); + PopulateCategories(); + PopulateOrders(); + } + + public void UpdateBankData() + { + _accountNameLabel.Text = Owner.BankName; + _pointsLabel.Text = Owner.BankBalance.ToString(); + } + + /// + /// Show/Hide Call Shuttle button and Approve buttons + /// + public void UpdateRequestOnly() + { + CallShuttleButton.Visible = !Owner.RequestOnly; + foreach (CargoOrderRow row in _requests.Children) + { + row.Approve.Visible = !Owner.RequestOnly; + } + } + } + + internal class CargoProductRow : PanelContainer + { + public CargoProductPrototype Product { get; set; } + public TextureRect Icon { get; private set; } + public Button MainButton { get; private set; } + public Label ProductName { get; private set; } + public Label PointCost { get; private set; } + + public CargoProductRow() + { + SizeFlagsHorizontal = SizeFlags.FillExpand; + + MainButton = new Button + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsVertical = SizeFlags.FillExpand + }; + AddChild(MainButton); + + var hBox = new HBoxContainer + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + MouseFilter = MouseFilterMode.Ignore + }; + + Icon = new TextureRect + { + CustomMinimumSize = new Vector2(32.0f, 32.0f), + MouseFilter = MouseFilterMode.Ignore, + RectClipContent = true + }; + hBox.AddChild(Icon); + + ProductName = new Label + { + SizeFlagsHorizontal = SizeFlags.FillExpand + }; + hBox.AddChild(ProductName); + + var panel = new PanelContainer + { + PanelOverride = new StyleBoxFlat { BackgroundColor = new Color(37, 37, 42) }, + MouseFilter = MouseFilterMode.Ignore + }; + PointCost = new Label + { + CustomMinimumSize = new Vector2(40.0f, 32.0f), + Align = Label.AlignMode.Right + }; + panel.AddChild(PointCost); + hBox.AddChild(panel); + + AddChild(hBox); + } + } + + internal class CargoOrderRow : PanelContainer + { +#pragma warning disable 649 + [Dependency] readonly IResourceCache _resourceCache; +#pragma warning restore 649 + + public CargoOrderData Order { get; set; } + public TextureRect Icon { get; private set; } + public Label ProductName { get; private set; } + public Label Description { get; private set; } + public BaseButton Approve { get; private set; } + public BaseButton Cancel { get; private set; } + + public CargoOrderRow() + { + SizeFlagsHorizontal = SizeFlags.FillExpand; + + var hBox = new HBoxContainer + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + MouseFilter = MouseFilterMode.Ignore + }; + + Icon = new TextureRect + { + CustomMinimumSize = new Vector2(32.0f, 32.0f), + MouseFilter = MouseFilterMode.Ignore, + RectClipContent = true + }; + hBox.AddChild(Icon); + + var vBox = new VBoxContainer + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsVertical = SizeFlags.FillExpand + }; + ProductName = new Label + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + StyleClasses = { NanoStyle.StyleClassLabelSubText }, + ClipText = true + }; + Description = new Label + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + StyleClasses = { NanoStyle.StyleClassLabelSubText }, + ClipText = true + }; + vBox.AddChild(ProductName); + vBox.AddChild(Description); + hBox.AddChild(vBox); + + Approve = new Button + { + Text = "Approve", + StyleClasses = { NanoStyle.StyleClassLabelSubText } + }; + hBox.AddChild(Approve); + + Cancel = new Button + { + Text = "Cancel", + StyleClasses = { NanoStyle.StyleClassLabelSubText } + }; + hBox.AddChild(Cancel); + + AddChild(hBox); + } + } +} diff --git a/Content.Client/UserInterface/Cargo/CargoConsoleOrderMenu.cs b/Content.Client/UserInterface/Cargo/CargoConsoleOrderMenu.cs new file mode 100644 index 0000000000..5a90e37850 --- /dev/null +++ b/Content.Client/UserInterface/Cargo/CargoConsoleOrderMenu.cs @@ -0,0 +1,66 @@ +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Maths; +using System; +using System.Collections.Generic; + +namespace Content.Client.UserInterface.Cargo +{ + class CargoConsoleOrderMenu : SS14Window + { +#pragma warning disable 649 + [Dependency] private readonly ILocalizationManager _loc; +#pragma warning restore 649 + + public LineEdit Requester { get; set; } + public LineEdit Reason { get; set; } + public SpinBox Amount { get; set; } + public Button SubmitButton { get; set; } + + public CargoConsoleOrderMenu() + { + IoCManager.InjectDependencies(this); + + Title = _loc.GetString("Order Form"); + + var vBox = new VBoxContainer(); + var gridContainer = new GridContainer { Columns = 2 }; + + var requesterLabel = new Label { Text = _loc.GetString("Name:") }; + Requester = new LineEdit(); + gridContainer.AddChild(requesterLabel); + gridContainer.AddChild(Requester); + + var reasonLabel = new Label { Text = _loc.GetString("Reason:") }; + Reason = new LineEdit(); + gridContainer.AddChild(reasonLabel); + gridContainer.AddChild(Reason); + + var amountLabel = new Label { Text = _loc.GetString("Amount:") }; + Amount = new SpinBox + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + Value = 1 + }; + Amount.SetButtons(new List() { -100, -10, -1 }, new List() { 1, 10, 100 }); + Amount.IsValid = (n) => { + return (n > 0); + }; + gridContainer.AddChild(amountLabel); + gridContainer.AddChild(Amount); + + vBox.AddChild(gridContainer); + + SubmitButton = new Button() + { + Text = _loc.GetString("OK"), + TextAlign = Button.AlignMode.Center, + }; + vBox.AddChild(SubmitButton); + + Contents.AddChild(vBox); + } + } +} diff --git a/Content.Client/UserInterface/Cargo/GalacticBankSelectionMenu.cs b/Content.Client/UserInterface/Cargo/GalacticBankSelectionMenu.cs new file mode 100644 index 0000000000..28ad546ddd --- /dev/null +++ b/Content.Client/UserInterface/Cargo/GalacticBankSelectionMenu.cs @@ -0,0 +1,69 @@ + +using Content.Client.GameObjects.Components.Cargo; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Maths; +using System; +using static Robust.Client.UserInterface.Controls.ItemList; + +namespace Content.Client.UserInterface.Cargo +{ + public class GalacticBankSelectionMenu : SS14Window + { + private ItemList _accounts; + private int _accountCount = 0; + private string[] _accountNames = new string[] { }; + private int[] _accountIds = new int[] { }; + private int _selectedAccountId = -1; + +#pragma warning disable 649 + [Dependency] private readonly ILocalizationManager _loc; +#pragma warning restore 649 + + protected override Vector2? CustomSize => (300, 300); + + public CargoConsoleBoundUserInterface Owner; + + public GalacticBankSelectionMenu() + { + IoCManager.InjectDependencies(this); + + Title = _loc.GetString("Galactic Bank Selection"); + + _accounts = new ItemList() { SelectMode = ItemList.ItemListSelectMode.Single }; + + var margin = new MarginContainer() + { + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsHorizontal = SizeFlags.FillExpand, + MarginTop = 5f, + MarginLeft = 5f, + MarginRight = -5f, + MarginBottom = -5f, + }; + + margin.AddChild(_accounts); + + Contents.AddChild(margin); + } + + public void Populate(int accountCount, string[] accountNames, int[] accountIds, int selectedAccountId) + { + _accountCount = accountCount; + _accountNames = accountNames; + _accountIds = accountIds; + _selectedAccountId = selectedAccountId; + + _accounts.Clear(); + for (var i = 0; i < _accountCount; i++) + { + var id = _accountIds[i]; + _accounts.AddItem($"ID: {id} || {_accountNames[i]}"); + if (id == _selectedAccountId) + _accounts[id].Selected = true; + } + } + } +} diff --git a/Content.Client/UserInterface/NanoStyle.cs b/Content.Client/UserInterface/NanoStyle.cs index e39316414a..a76adff12d 100644 --- a/Content.Client/UserInterface/NanoStyle.cs +++ b/Content.Client/UserInterface/NanoStyle.cs @@ -15,6 +15,7 @@ namespace Content.Client.UserInterface public const string StyleClassLabelHeading = "LabelHeading"; public const string StyleClassLabelHeadingBigger = "LabelHeadingBigger"; public const string StyleClassLabelSubText = "LabelSubText"; + public const string StyleClassLabelKeyText = "LabelKeyText"; public const string StyleClassLabelSecondaryColor = "LabelSecondaryColor"; public const string StyleClassLabelBig = "LabelBig"; public const string StyleClassButtonBig = "ButtonBig"; @@ -36,6 +37,7 @@ namespace Content.Client.UserInterface var resCache = IoCManager.Resolve(); var notoSans10 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 10); var notoSans12 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 12); + var notoSansBold12 = resCache.GetFont("/Nano/NotoSans/NotoSans-Bold.ttf", 12); var notoSansDisplayBold14 = resCache.GetFont("/Fonts/NotoSansDisplay/NotoSansDisplay-Bold.ttf", 14); var notoSans16 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 16); var notoSansBold16 = resCache.GetFont("/Nano/NotoSans/NotoSans-Bold.ttf", 16); @@ -170,6 +172,9 @@ namespace Content.Client.UserInterface var itemListItemBackground = new StyleBoxFlat {BackgroundColor = new Color(55, 55, 68)}; itemListItemBackground.SetContentMarginOverride(StyleBox.Margin.Vertical, 2); itemListItemBackground.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4); + var itemListItemBackgroundTransparent = new StyleBoxFlat { BackgroundColor = Color.Transparent }; + itemListItemBackgroundTransparent.SetContentMarginOverride(StyleBox.Margin.Vertical, 2); + itemListItemBackgroundTransparent.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4); // NanoHeading var nanoHeadingTex = resCache.GetTexture("/Nano/nanoheading.svg.96dpi.png"); @@ -429,6 +434,18 @@ namespace Content.Client.UserInterface itemListBackgroundSelected) }), + new StyleRule(new SelectorElement(typeof(ItemList), new []{"transparentItemList"}, null, null), new[] + { + new StyleProperty(ItemList.StylePropertyBackground, + new StyleBoxFlat {BackgroundColor = Color.Transparent}), + new StyleProperty(ItemList.StylePropertyItemBackground, + itemListItemBackgroundTransparent), + new StyleProperty(ItemList.StylePropertyDisabledItemBackground, + itemListItemBackgroundDisabled), + new StyleProperty(ItemList.StylePropertySelectedItemBackground, + itemListBackgroundSelected) + }), + // Tree new StyleRule(new SelectorElement(typeof(Tree), null, null, null), new[] { @@ -475,12 +492,18 @@ namespace Content.Client.UserInterface new StyleProperty(Label.StylePropertyFontColor, Color.DarkGray), }), - new StyleRule(new SelectorElement(typeof(Label), new[] {StyleClassLabelSecondaryColor}, null, null), - new[] - { - new StyleProperty(Label.StylePropertyFont, notoSans12), - new StyleProperty(Label.StylePropertyFontColor, Color.DarkGray), - }), + // Label Key + new StyleRule(new SelectorElement(typeof(Label), new []{StyleClassLabelKeyText}, null, null), new [] + { + new StyleProperty(Label.StylePropertyFont, notoSansBold12), + new StyleProperty(Label.StylePropertyFontColor, NanoGold) + }), + + new StyleRule(new SelectorElement(typeof(Label), new[] {StyleClassLabelSecondaryColor}, null, null), new[] + { + new StyleProperty(Label.StylePropertyFont, notoSans12), + new StyleProperty(Label.StylePropertyFontColor, Color.DarkGray), + }), // Big Button new StyleRule(new SelectorElement(typeof(Button), new[] {StyleClassButtonBig}, null, null), new[] diff --git a/Content.Server/Cargo/CargoBankAccount.cs b/Content.Server/Cargo/CargoBankAccount.cs new file mode 100644 index 0000000000..a7244f4ed7 --- /dev/null +++ b/Content.Server/Cargo/CargoBankAccount.cs @@ -0,0 +1,20 @@ +using System; + +namespace Content.Server.Cargo +{ + public class CargoBankAccount : ICargoBankAccount + { + public int Id { get; } + + public string Name { get; } + + public int Balance { get; set; } + + public CargoBankAccount(int id, string name, int balance) + { + Id = id; + Name = name; + Balance = balance; + } + } +} diff --git a/Content.Server/Cargo/CargoOrderDataManager.cs b/Content.Server/Cargo/CargoOrderDataManager.cs new file mode 100644 index 0000000000..a9b05dba06 --- /dev/null +++ b/Content.Server/Cargo/CargoOrderDataManager.cs @@ -0,0 +1,99 @@ +using Content.Server.GameObjects.Components.Cargo; +using Content.Shared.Prototypes.Cargo; +using System; +using System.Collections.Generic; + +namespace Content.Server.Cargo +{ + public class CargoOrderDataManager : ICargoOrderDataManager + { + private readonly Dictionary _accounts = new Dictionary(); + private readonly List _components = new List(); + + public CargoOrderDataManager() + { + CreateAccount(0); + } + + public void CreateAccount(int id) + { + _accounts.Add(id, new CargoOrderDatabase(id)); + } + + public bool TryGetAccount(int id, out CargoOrderDatabase account) + { + if (_accounts.TryGetValue(id, out var _account)) + { + account = _account; + return true; + } + account = null; + return false; + } + + /// + /// Adds an order to the database. + /// + /// The person who requested the item. + /// The reason the product was requested. + /// The ID of the product requested. + /// The amount of the products requested. + /// The ID of the bank account paying for the order. + /// Whether the order will be bought when the orders are processed. + public virtual void AddOrder(int id, string requester, string reason, string productId, int amount, int payingAccountId) + { + if (amount < 1 || !TryGetAccount(id, out var account)) + return; + account.AddOrder(requester, reason, productId, amount, payingAccountId); + SyncComponentsWithId(id); + } + + public void RemoveOrder(int id, int orderNumber) + { + if (!TryGetAccount(id, out var account)) + return; + account.RemoveOrder(orderNumber); + SyncComponentsWithId(id); + } + + public void ApproveOrder(int id, int orderNumber) + { + if (!TryGetAccount(id, out var account)) + return; + account.ApproveOrder(orderNumber); + SyncComponentsWithId(id); + } + + private void SyncComponentsWithId(int id) + { + foreach (var component in _components) + { + if (!component.ConnectedToDatabase || component.Database.Id != id) + continue; + component.Dirty(); + } + } + + public List RemoveAndGetApprovedFrom(CargoOrderDatabase database) + { + var approvedOrders = database.SpliceApproved(); + SyncComponentsWithId(database.Id); + return approvedOrders; + } + + public void AddComponent(CargoOrderDatabaseComponent component) + { + if (_components.Contains(component)) + return; + _components.Add(component); + component.Database = _accounts[0]; + } + + public List GetOrdersFromAccount(int accountId) + { + if (!TryGetAccount(accountId, out var account)) + return null; + return account.GetOrders(); + } + } +} diff --git a/Content.Server/Cargo/CargoOrderDatabase.cs b/Content.Server/Cargo/CargoOrderDatabase.cs new file mode 100644 index 0000000000..9f8ee35ad5 --- /dev/null +++ b/Content.Server/Cargo/CargoOrderDatabase.cs @@ -0,0 +1,104 @@ +using Content.Shared.Prototypes.Cargo; +using System.Collections.Generic; +using System.Linq; + +namespace Content.Server.Cargo +{ + public class CargoOrderDatabase + { + private Dictionary _orders = new Dictionary(); + private int _orderNumber = 0; + + public CargoOrderDatabase(int id) + { + Id = id; + } + + public int Id { get; private set; } + + /// + /// Removes all orders from the database. + /// + public void Clear() + { + _orders.Clear(); + } + + /// + /// Returns a list of all orders. + /// + /// A list of orders + public List GetOrders() + { + return _orders.Values.ToList(); + } + + public bool TryGetOrder(int id, out CargoOrderData order) + { + if (_orders.TryGetValue(id, out var _order)) + { + order = _order; + return true; + } + order = null; + return false; + } + + public List SpliceApproved() + { + var orders = _orders.Values.Where(order => order.Approved).ToList(); + foreach (var order in orders) + _orders.Remove(order.OrderNumber); + return orders; + } + + /// + /// Adds an order to the database. + /// + /// The person who requested the item. + /// The reason the product was requested. + /// The ID of the product requested. + /// The amount of the products requested. + /// The ID of the bank account paying for the order. + /// Whether the order will be bought when the orders are processed. + public void AddOrder(string requester, string reason, string productId, int amount, int payingAccountId) + { + var order = new CargoOrderData(_orderNumber, requester, reason, productId, amount, payingAccountId); + if (Contains(order)) + return; + _orders.Add(_orderNumber, order); + _orderNumber += 1; + } + + /// + /// Removes an order from the database. + /// + /// The order to be removed. + /// Whether it could be removed or not + public bool RemoveOrder(int orderNumber) + { + return _orders.Remove(orderNumber); + } + + /// + /// Approves an order in the database. + /// + /// The order to be approved. + public void ApproveOrder(int orderNumber) + { + if (!_orders.TryGetValue(orderNumber, out var order)) + return; + order.Approved = true; + } + + /// + /// Returns whether the database contains the order or not. + /// + /// The order to check + /// Whether the database contained the order or not. + public bool Contains(CargoOrderData order) + { + return _orders.ContainsValue(order); + } + } +} diff --git a/Content.Server/Cargo/GalacticBankManager.cs b/Content.Server/Cargo/GalacticBankManager.cs new file mode 100644 index 0000000000..1fbcb81ddb --- /dev/null +++ b/Content.Server/Cargo/GalacticBankManager.cs @@ -0,0 +1,109 @@ +using Content.Server.GameObjects.Components.Cargo; +using Robust.Shared.Timing; +using System; +using System.Collections.Generic; + +namespace Content.Server.Cargo +{ + public class GalacticBankManager : IGalacticBankManager + { + private readonly float DELAY = 10f; + private readonly int POINT_INCREASE = 10; + + private int _index = 0; + private float _timer = 10f; + private readonly Dictionary _accounts = new Dictionary(); + private readonly List _components = new List(); + + public GalacticBankManager() + { + CreateBankAccount("Orbital Monitor IV Station", 100000); + } + + public IEnumerable GetAllBankAccounts() + { + return _accounts.Values; + } + + public void Shutdown() + { + throw new System.NotImplementedException(); + } + + public void CreateBankAccount(string name, int balance = 0) + { + var account = new CargoBankAccount(_index, name, balance); + _accounts.Add(_index, account); + _index += 1; + } + + public CargoBankAccount GetBankAccount(int id) + { + return _accounts[id]; + } + + public bool TryGetBankAccount(int id, out CargoBankAccount account) + { + if (_accounts.TryGetValue(id, out var _account)) + { + account = _account; + return true; + } + account = null; + return false; + } + + public void Update(FrameEventArgs frameEventArgs) + { + _timer += frameEventArgs.DeltaSeconds; + if (_timer < DELAY) + return; + _timer -= DELAY; + foreach (var account in GetAllBankAccounts()) + { + account.Balance += POINT_INCREASE; + } + SyncComponents(); + } + + private void SyncComponents() + { + foreach (var component in _components) + { + var account = GetBankAccount(component.BankId); + if (account == null) + continue; + component.SetState(account.Id, account.Name, account.Balance); + } + } + + private void SyncComponentsWithId(int id) + { + var account = GetBankAccount(id); + foreach (var component in _components) + { + if (component.BankId != id) + continue; + component.SetState(account.Id, account.Name, account.Balance); + } + } + + public void AddComponent(CargoConsoleComponent component) + { + if (_components.Contains(component)) + return; + _components.Add(component); + } + + public bool ChangeBalance(int id, int n) + { + if (!TryGetBankAccount(id, out var account)) + return false; + if (account.Balance + n < 0) + return false; + account.Balance += n; + SyncComponentsWithId(account.Id); + return true; + } + } +} diff --git a/Content.Server/Cargo/ICargoBankAccount.cs b/Content.Server/Cargo/ICargoBankAccount.cs new file mode 100644 index 0000000000..998f846c99 --- /dev/null +++ b/Content.Server/Cargo/ICargoBankAccount.cs @@ -0,0 +1,11 @@ +using System; + +namespace Content.Server.Cargo +{ + public interface ICargoBankAccount + { + int Id { get; } + string Name { get; } + int Balance { get; } + } +} diff --git a/Content.Server/Cargo/ICargoOrderDataManager.cs b/Content.Server/Cargo/ICargoOrderDataManager.cs new file mode 100644 index 0000000000..4c4f5cbbe7 --- /dev/null +++ b/Content.Server/Cargo/ICargoOrderDataManager.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Content.Server.GameObjects.Components.Cargo; +using Content.Shared.Prototypes.Cargo; + +namespace Content.Server.Cargo +{ + public interface ICargoOrderDataManager + { + bool TryGetAccount(int id, out CargoOrderDatabase account); + void AddOrder(int id, string requester, string reason, string productId, int amount, int payingAccountId); + void RemoveOrder(int id, int orderNumber); + void ApproveOrder(int id, int orderNumber); + void AddComponent(CargoOrderDatabaseComponent component); + List GetOrdersFromAccount(int accountId); + List RemoveAndGetApprovedFrom(CargoOrderDatabase database); + } +} diff --git a/Content.Server/Cargo/IGalacticBankManager.cs b/Content.Server/Cargo/IGalacticBankManager.cs new file mode 100644 index 0000000000..a6853f04ff --- /dev/null +++ b/Content.Server/Cargo/IGalacticBankManager.cs @@ -0,0 +1,20 @@ +using Content.Server.GameObjects.Components.Cargo; +using Robust.Shared.Timing; +using System.Collections.Generic; + +namespace Content.Server.Cargo +{ + public interface IGalacticBankManager + { + IEnumerable GetAllBankAccounts(); + + void Shutdown(); + void Update(FrameEventArgs frameEventArgs); + + void CreateBankAccount(string name, int balance); + CargoBankAccount GetBankAccount(int id); + void AddComponent(CargoConsoleComponent cargoConsoleComponent); + bool TryGetBankAccount(int id, out CargoBankAccount account); + bool ChangeBalance(int id, int n); + } +} diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index 46fa5e311f..adb7442ad3 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -1,4 +1,5 @@ -using Content.Server.Chat; +using Content.Server.Cargo; +using Content.Server.Chat; using Content.Server.GameTicking; using Content.Server.Interfaces; using Content.Server.Interfaces.Chat; @@ -50,6 +51,8 @@ namespace Content.Server IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); + IoCManager.Register(); if (TestingCallbacks != null) { var cast = (ServerModuleTestingCallbacks) TestingCallbacks; @@ -83,6 +86,14 @@ namespace Content.Server base.Update(level, frameEventArgs); _gameTicker.Update(frameEventArgs); + switch (level) + { + case ModUpdateLevel.PreEngine: + { + IoCManager.Resolve().Update(frameEventArgs); + break; + } + } } } } diff --git a/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs b/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs new file mode 100644 index 0000000000..a2e21dec1a --- /dev/null +++ b/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs @@ -0,0 +1,133 @@ +using Content.Server.Cargo; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Components.Cargo; +using Content.Shared.Prototypes.Cargo; +using Robust.Server.GameObjects.Components.UserInterface; +using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Content.Server.GameObjects.Components.Cargo +{ + [RegisterComponent] + [ComponentReference(typeof(IActivate))] + public class CargoConsoleComponent : SharedCargoConsoleComponent, IActivate + { +#pragma warning disable 649 + [Dependency] private readonly IGalacticBankManager _galacticBankManager; + [Dependency] private readonly ICargoOrderDataManager _cargoOrderDataManager; +#pragma warning restore 649 + + [ViewVariables] + public int Points = 1000; + + private BoundUserInterface _userInterface; + + [ViewVariables] + public GalacticMarketComponent Market { get; private set; } + [ViewVariables] + public CargoOrderDatabaseComponent Orders { get; private set; } + [ViewVariables] + public int BankId { get; private set; } + + private bool _requestOnly = false; + + public override void Initialize() + { + base.Initialize(); + Market = Owner.GetComponent(); + Orders = Owner.GetComponent(); + _userInterface = Owner.GetComponent().GetBoundUserInterface(CargoConsoleUiKey.Key); + _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + _galacticBankManager.AddComponent(this); + BankId = 0; + } + + /// + /// Reads data from YAML + /// + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _requestOnly, "requestOnly", false); + } + + private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg) + { + var message = serverMsg.Message; + if (!Orders.ConnectedToDatabase) + return; + switch (message) + { + case CargoConsoleAddOrderMessage msg: + { + if (msg.Amount <= 0) + break; + _cargoOrderDataManager.AddOrder(Orders.Database.Id, msg.Requester, msg.Reason, msg.ProductId, msg.Amount, BankId); + break; + } + case CargoConsoleRemoveOrderMessage msg: + { + _cargoOrderDataManager.RemoveOrder(Orders.Database.Id, msg.OrderNumber); + break; + } + case CargoConsoleApproveOrderMessage msg: + { + if (_requestOnly || + !Orders.Database.TryGetOrder(msg.OrderNumber, out var order)) + break; + _prototypeManager.TryIndex(order.ProductId, out CargoProductPrototype product); + if (product == null) + break; + if (!_galacticBankManager.ChangeBalance(BankId, (-product.PointCost) * order.Amount)) + break; + _cargoOrderDataManager.ApproveOrder(Orders.Database.Id, msg.OrderNumber); + break; + } + case CargoConsoleShuttleMessage _: + { + var approvedOrders = _cargoOrderDataManager.RemoveAndGetApprovedFrom(Orders.Database); + // TODO replace with shuttle code + + // TEMPORARY loop for spawning stuff on top of console + foreach (var order in approvedOrders) + { + if (!_prototypeManager.TryIndex(order.ProductId, out CargoProductPrototype product)) + continue; + for (var i = 0; i < order.Amount; i++) + { + Owner.EntityManager.SpawnEntityAt(product.Product, Owner.Transform.GridPosition); + } + } + break; + } + } + } + + void IActivate.Activate(ActivateEventArgs eventArgs) + { + if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + { + return; + } + + _userInterface.Open(actor.playerSession); + } + + /// + /// Sync bank account information + /// + public void SetState(int id, string name, int balance) + { + _userInterface.SetState(new CargoConsoleInterfaceState(_requestOnly, id, name, balance)); + } + } +} diff --git a/Content.Server/GameObjects/Components/Cargo/CargoOrderDatabaseComponent.cs b/Content.Server/GameObjects/Components/Cargo/CargoOrderDatabaseComponent.cs new file mode 100644 index 0000000000..54013b302c --- /dev/null +++ b/Content.Server/GameObjects/Components/Cargo/CargoOrderDatabaseComponent.cs @@ -0,0 +1,30 @@ +using Content.Server.Cargo; +using Content.Shared.GameObjects.Components.Cargo; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Server.GameObjects.Components.Cargo +{ + [RegisterComponent] + public class CargoOrderDatabaseComponent : SharedCargoOrderDatabaseComponent + { +#pragma warning disable 649 + [Dependency] private readonly ICargoOrderDataManager _cargoOrderDataManager; +#pragma warning restore 649 + + public CargoOrderDatabase Database { get; set; } + public bool ConnectedToDatabase => Database != null; + + public override void Initialize() + { + _cargoOrderDataManager.AddComponent(this); + } + + public override ComponentState GetComponentState() + { + if (!ConnectedToDatabase) + return new CargoOrderDatabaseState(null); + return new CargoOrderDatabaseState(Database.GetOrders()); + } + } +} diff --git a/Content.Server/GameObjects/Components/Cargo/GalacticMarketComponent.cs b/Content.Server/GameObjects/Components/Cargo/GalacticMarketComponent.cs new file mode 100644 index 0000000000..5f4ff15e26 --- /dev/null +++ b/Content.Server/GameObjects/Components/Cargo/GalacticMarketComponent.cs @@ -0,0 +1,19 @@ +using Content.Shared.GameObjects.Components.Cargo; +using Robust.Shared.GameObjects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Content.Server.GameObjects.Components.Cargo +{ + [RegisterComponent] + public class GalacticMarketComponent : SharedGalacticMarketComponent + { + public override ComponentState GetComponentState() + { + return new GalacticMarketState(GetProductIdList()); + } + } +} diff --git a/Content.Shared/GameObjects/Components/Cargo/SharedCargoConsoleComponent.cs b/Content.Shared/GameObjects/Components/Cargo/SharedCargoConsoleComponent.cs new file mode 100644 index 0000000000..887c94f4be --- /dev/null +++ b/Content.Shared/GameObjects/Components/Cargo/SharedCargoConsoleComponent.cs @@ -0,0 +1,106 @@ +using Content.Shared.Prototypes.Cargo; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Content.Shared.GameObjects.Components.Cargo +{ + public class SharedCargoConsoleComponent : Component + { +#pragma warning disable CS0649 + [Dependency] + protected IPrototypeManager _prototypeManager; +#pragma warning restore + + public sealed override string Name => "CargoConsole"; + + /// + /// Sends away or requests shuttle + /// + [Serializable, NetSerializable] + public class CargoConsoleShuttleMessage : BoundUserInterfaceMessage + { + public CargoConsoleShuttleMessage() + { + } + } + + /// + /// Add order to database. + /// + [Serializable, NetSerializable] + public class CargoConsoleAddOrderMessage : BoundUserInterfaceMessage + { + public string Requester; + public string Reason; + public string ProductId; + public int Amount; + + public CargoConsoleAddOrderMessage(string requester, string reason, string productId, int amount) + { + Requester = requester; + Reason = reason; + ProductId = productId; + Amount = amount; + } + } + + /// + /// Remove order from database. + /// + [Serializable, NetSerializable] + public class CargoConsoleRemoveOrderMessage : BoundUserInterfaceMessage + { + public int OrderNumber; + + public CargoConsoleRemoveOrderMessage(int orderNumber) + { + OrderNumber = orderNumber; + } + } + + /// + /// Set order in database as approved. + /// + [Serializable, NetSerializable] + public class CargoConsoleApproveOrderMessage : BoundUserInterfaceMessage + { + public int OrderNumber; + + public CargoConsoleApproveOrderMessage(int orderNumber) + { + OrderNumber = orderNumber; + } + } + + [NetSerializable, Serializable] + public enum CargoConsoleUiKey + { + Key + } + } + + [NetSerializable, Serializable] + public class CargoConsoleInterfaceState : BoundUserInterfaceState + { + public readonly bool RequestOnly; + public readonly int BankId; + public readonly string BankName; + public readonly int BankBalance; + + public CargoConsoleInterfaceState(bool requestOnly, int bankId, string bankName, int bankBalance) + { + RequestOnly = requestOnly; + BankId = bankId; + BankName = bankName; + BankBalance = bankBalance; + } + } +} diff --git a/Content.Shared/GameObjects/Components/Cargo/SharedCargoOrderDatabaseComponent.cs b/Content.Shared/GameObjects/Components/Cargo/SharedCargoOrderDatabaseComponent.cs new file mode 100644 index 0000000000..9a4898e888 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Cargo/SharedCargoOrderDatabaseComponent.cs @@ -0,0 +1,25 @@ +using Content.Shared.Prototypes.Cargo; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; +using System; +using System.Collections.Generic; + +namespace Content.Shared.GameObjects.Components.Cargo +{ + public class SharedCargoOrderDatabaseComponent : Component + { + public sealed override string Name => "CargoOrderDatabase"; + public sealed override uint? NetID => ContentNetIDs.CARGO_ORDER_DATABASE; + public sealed override Type StateType => typeof(CargoOrderDatabaseState); + } + + [NetSerializable, Serializable] + public class CargoOrderDatabaseState : ComponentState + { + public readonly List Orders; + public CargoOrderDatabaseState(List orders) : base(ContentNetIDs.CARGO_ORDER_DATABASE) + { + Orders = orders; + } + } +} diff --git a/Content.Shared/GameObjects/Components/Cargo/SharedGalacticMarketComponent.cs b/Content.Shared/GameObjects/Components/Cargo/SharedGalacticMarketComponent.cs new file mode 100644 index 0000000000..f2be864dc6 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Cargo/SharedGalacticMarketComponent.cs @@ -0,0 +1,97 @@ +using Content.Shared.Prototypes.Cargo; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Content.Shared.GameObjects.Components.Cargo +{ + public class SharedGalacticMarketComponent : Component, IEnumerable + { + public sealed override string Name => "GalacticMarket"; + public sealed override uint? NetID => ContentNetIDs.GALACTIC_MARKET; + public sealed override Type StateType => typeof(GalacticMarketState); + + protected List _products = new List(); + + /// + /// A read-only list of products. + /// + public IReadOnlyList Products => _products; + + public IEnumerator GetEnumerator() + { + return _products.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Returns a product from the string id; + /// + /// Product + public CargoProductPrototype GetProduct(string productId) + { + var prototypeManager = IoCManager.Resolve(); + if (!prototypeManager.TryIndex(productId, out CargoProductPrototype product) || !_products.Contains(product)) + { + return null; + } + return product; + } + + /// + /// Returns a list with the IDs of all products. + /// + /// A list of product IDs + public List GetProductIdList() + { + List productIds = new List(); + + foreach (var product in _products) + { + productIds.Add(product.ID); + } + + return productIds; + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + if (serializer.Reading) + { + var products = serializer.ReadDataField("products", new List()); + var prototypeManager = IoCManager.Resolve(); + foreach (var id in products) + { + if (!prototypeManager.TryIndex(id, out CargoProductPrototype product)) + continue; + _products.Add(product); + } + } + else if (serializer.Writing) + { + var products = GetProductIdList(); + serializer.DataField(ref products, "products", new List()); + } + } + } + + [Serializable, NetSerializable] + public class GalacticMarketState : ComponentState + { + public List Products; + public GalacticMarketState(List technologies) : base(ContentNetIDs.GALACTIC_MARKET) + { + Products = technologies; + } + } +} diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index 33f0c986e5..7fd98c5eb2 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -32,5 +32,7 @@ public const uint OVERLAYEFFECTS = 1027; public const uint STOMACH = 1028; public const uint ITEMCOOLDOWN = 1029; + public const uint CARGO_ORDER_DATABASE = 1030; + public const uint GALACTIC_MARKET = 1031; } } diff --git a/Content.Shared/Prototypes/Cargo/CargoOrderData.cs b/Content.Shared/Prototypes/Cargo/CargoOrderData.cs new file mode 100644 index 0000000000..0882db8e0d --- /dev/null +++ b/Content.Shared/Prototypes/Cargo/CargoOrderData.cs @@ -0,0 +1,34 @@ +using Robust.Shared.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Content.Shared.Prototypes.Cargo +{ + [NetSerializable, Serializable] + public class CargoOrderData + { + public int OrderNumber; + public string Requester; + // public String RequesterRank; // TODO Figure out how to get Character ID card data + // public int RequesterId; + public string Reason; + public string ProductId; + public int Amount; + public int PayingAccountId; + public bool Approved; + + public CargoOrderData(int orderNumber, string requester, string reason, string productId, int amount, int payingAccountId) + { + OrderNumber = orderNumber; + Requester = requester; + Reason = reason; + ProductId = productId; + Amount = amount; + PayingAccountId = payingAccountId; + Approved = false; + } + } +} diff --git a/Content.Shared/Prototypes/Cargo/CargoProductPrototype.cs b/Content.Shared/Prototypes/Cargo/CargoProductPrototype.cs new file mode 100644 index 0000000000..57b1aedc76 --- /dev/null +++ b/Content.Shared/Prototypes/Cargo/CargoProductPrototype.cs @@ -0,0 +1,111 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; +using System; +using YamlDotNet.RepresentationModel; + +namespace Content.Shared.Prototypes.Cargo +{ + [NetSerializable, Serializable, Prototype("cargoProduct")] + public class CargoProductPrototype : IPrototype, IIndexedPrototype + { + private string _id; + private string _name; + private string _description; + private SpriteSpecifier _icon; + private string _product; + private int _pointCost; + private string _category; + private string _group; + + [ViewVariables] + public string ID => _id; + + /// + /// Product name. + /// + [ViewVariables] + public string Name + { + get + { + if (_name.Trim().Length != 0) + return _name; + var protoMan = IoCManager.Resolve(); + if (protoMan == null) + return _name; + protoMan.TryIndex(_product, out EntityPrototype prototype); + if (prototype?.Name != null) + _name = prototype.Name; + return _name; + } + } + + /// + /// Short description of the product. + /// + [ViewVariables] + public string Description + { + get + { + if (_description.Trim().Length != 0) + return _description; + var protoMan = IoCManager.Resolve(); + if (protoMan == null) + return _description; + protoMan.TryIndex(_product, out EntityPrototype prototype); + if (prototype?.Description != null) + _description = prototype.Description; + return _description; + } + } + + /// + /// Texture path used in the CargoConsole GUI. + /// + [ViewVariables] + public SpriteSpecifier Icon => _icon; + + /// + /// The prototype name of the product. + /// + [ViewVariables] + public string Product => _product; + + /// + /// The point cost of the product. + /// + [ViewVariables] + public int PointCost => _pointCost; + + /// + /// The prototype category of the product. (e.g. Engineering, Medical) + /// + [ViewVariables] + public string Category => _category; + + /// + /// The prototype group of the product. (e.g. Contraband) + /// + [ViewVariables] + public string Group => _group; + + public void LoadFrom(YamlMappingNode mapping) + { + var serializer = YamlObjectSerializer.NewReader(mapping); + + serializer.DataField(ref _name, "name", string.Empty); + serializer.DataField(ref _id, "id", string.Empty); + serializer.DataField(ref _description, "description", string.Empty); + serializer.DataField(ref _icon, "icon", SpriteSpecifier.Invalid); + serializer.DataField(ref _product, "product", null); + serializer.DataField(ref _pointCost, "cost", 0); + serializer.DataField(ref _category, "category", string.Empty); + serializer.DataField(ref _group, "group", string.Empty); + } + } +} diff --git a/Resources/Maps/stationstation.yml b/Resources/Maps/stationstation.yml index dab579989d..62b310727a 100644 --- a/Resources/Maps/stationstation.yml +++ b/Resources/Maps/stationstation.yml @@ -1833,7 +1833,7 @@ entities: pos: -5.5,-0.5 rot: -1.5707963267949 rad type: Transform -- type: computerPowerMonitoring +- type: computerSupplyRequest uid: 153 components: - grid: 0 @@ -1846,7 +1846,7 @@ entities: mask: 19 bounds: -0.5,-0.25,0.5,0.25 type: Collidable -- type: computerAlert +- type: computerSupplyOrdering uid: 154 components: - grid: 0 diff --git a/Resources/Prototypes/Cargo/products.yml b/Resources/Prototypes/Cargo/products.yml new file mode 100644 index 0000000000..9c71c056f6 --- /dev/null +++ b/Resources/Prototypes/Cargo/products.yml @@ -0,0 +1,33 @@ +- type: cargoProduct + name: "Dice" + id: cargo.dice + description: Some dice + icon: + sprite: Objects/Fun/dice.rsi + state: d2020 + product: d20 + cost: 20 + category: Other + group: market + +- type: cargoProduct + name: "Medkit" + id: cargo.Medkit + description: Everything you need to patch someone up. + icon: Objects/Medical/medkit_r.png + product: Medkit + cost: 200 + category: Medical + group: market + +- type: cargoProduct + name: "Flashlight" + id: cargo.flashlight + description: Shine a light in the dark + icon: + sprite: Objects/Tools/flashlight.rsi + state: lantern_off + product: FlashlightLantern + cost: 3000 + category: Engineering + group: market \ No newline at end of file diff --git a/Resources/Prototypes/Entities/buildings/computers.yml b/Resources/Prototypes/Entities/buildings/computers.yml index ccf64ae12b..6a9edb3410 100644 --- a/Resources/Prototypes/Entities/buildings/computers.yml +++ b/Resources/Prototypes/Entities/buildings/computers.yml @@ -69,14 +69,38 @@ - type: entity id: computerSupplyOrdering parent: computerBase - name: Supply Ordering Computer + name: Cargo Ordering Computer components: - type: Appearance visuals: - type: ComputerVisualizer2D key: tech_key screen: supply + - type: CargoConsole + - type: CargoOrderDatabase + - type: GalacticMarket + static: true + products: + - cargo.dice + - cargo.flashlight + - cargo.Medkit + - type: UserInterface + interfaces: + - key: enum.CargoConsoleUiKey.Key + type: CargoConsoleBoundUserInterface +- type: entity + id: computerSupplyRequest + parent: computerSupplyOrdering + name: Cargo Request Computer + components: + - type: Appearance + visuals: + - type: ComputerVisualizer2D + key: tech_key + screen: request + - type: CargoConsole + requestOnly: true - type: entity id: computerMedicalRecords diff --git a/RobustToolbox b/RobustToolbox index 89f6a0917a..da440bbf28 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 89f6a0917a8109fe3d2a5b69590208c2d5696a9c +Subproject commit da440bbf28b931862c18b133daaa24634a20f784