* nasrano

* Add station budget & salary

* Initial balance

* Vending machine UI

* Pricing for vending machines

* Finish economy

* Eftpos

* Finish eftpos

* Put eftpos into lockers

* Vending machine prices

* Small fixes

* Fix atm UI

* Add atms to maps

* fix

* reset

* Add PDA program

* Maps again

---------

Co-authored-by: Mona Hmiza <>
Co-authored-by: rhailrake <49613070+rhailrake@users.noreply.github.com>
This commit is contained in:
Aviu00
2023-10-02 16:50:02 +09:00
committed by Aviu00
parent 707cdf3afa
commit 16c8b95da4
109 changed files with 2043 additions and 30 deletions

View File

@@ -32,7 +32,7 @@ public sealed class CharacterInfoSystem : EntitySystem
private void OnCharacterInfoEvent(CharacterInfoEvent msg, EntitySessionEventArgs args)
{
var entity = GetEntity(msg.NetEntity);
var data = new CharacterData(entity, msg.JobTitle, msg.Objectives, msg.Briefing, Name(entity));
var data = new CharacterData(entity, msg.JobTitle, msg.Objectives, msg.Briefing, Name(entity), msg.Memory);
OnCharacterUpdate?.Invoke(data);
}
@@ -49,7 +49,8 @@ public sealed class CharacterInfoSystem : EntitySystem
string Job,
Dictionary<string, List<ObjectiveInfo>> Objectives,
string? Briefing,
string EntityName
string EntityName,
Dictionary<string, string> Memory
);
/// <summary>

View File

@@ -105,12 +105,13 @@ public sealed class CharacterUIController : UIController, IOnStateEntered<Gamepl
return;
}
var (entity, job, objectives, briefing, entityName) = data;
var (entity, job, objectives, briefing, entityName, memories) = data;
_window.SpriteView.SetEntity(entity);
_window.NameLabel.Text = entityName;
_window.SubText.Text = job;
_window.Objectives.RemoveAllChildren();
_window.Memories.RemoveAllChildren();
_window.ObjectivesLabel.Visible = objectives.Any();
foreach (var (groupId, conditions) in objectives)
@@ -146,6 +147,26 @@ public sealed class CharacterUIController : UIController, IOnStateEntered<Gamepl
_window.Objectives.AddChild(objectiveControl);
}
//WD EDIT
foreach (var (memoryName, memoryValue) in memories)
{
var memoryControl = new BoxContainer()
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
Modulate = Color.Gray
};
var text = Loc.TryGetString(memoryName, out var t, ("value", memoryValue))
? t
: $"{memoryName}: {memoryValue}";
memoryControl.AddChild(new Label
{
Text = text,
});
_window.Memories.AddChild(memoryControl);
}
//WD EDIT END
if (briefing != null)
{
var briefingControl = new ObjectiveBriefingControl();

View File

@@ -14,6 +14,13 @@
<Label Name="SubText" VerticalAlignment="Top" StyleClasses="LabelSubText" Access="Public"/>
</BoxContainer>
</BoxContainer>
<!-- WD EDIT -->
<Label Text="{Loc 'character-info-memories-label'}" HorizontalAlignment="Center"/>
<BoxContainer Orientation="Vertical" Name="Memories" Access="Public"/>
<cc:Placeholder PlaceholderText="{Loc 'character-info-memories-placeholder-text'}"/>
<!-- WD EDIT END -->
<Label Name="ObjectivesLabel" Access="Public" Text="{Loc 'character-info-objectives-label'}" HorizontalAlignment="Center"/>
<BoxContainer Orientation="Vertical" Name="Objectives" Access="Public"/>
<cc:Placeholder Name="RolePlaceholder" Access="Public" PlaceholderText="{Loc 'character-info-roles-antagonist-text'}"/>

View File

@@ -2,13 +2,14 @@ using Content.Client.VendingMachines.UI;
using Content.Shared.VendingMachines;
using Robust.Client.UserInterface.Controls;
using System.Linq;
using Content.Client.White.Economy.Ui;
namespace Content.Client.VendingMachines
{
public sealed class VendingMachineBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private VendingMachineMenu? _menu;
private VendingMenu? _menu; // WD EDIT
[ViewVariables]
private List<VendingMachineInventoryEntry> _cachedInventory = new();
@@ -26,15 +27,18 @@ namespace Content.Client.VendingMachines
var vendingMachineSys = EntMan.System<VendingMachineSystem>();
_cachedInventory = vendingMachineSys.GetAllInventory(Owner);
// WD EDIT START
var component = EntMan.GetComponent<VendingMachineComponent>(Owner);
_cachedInventory = vendingMachineSys.GetAllInventory(Owner, component);
_menu = new VendingMachineMenu { Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName };
_menu = new VendingMenu { Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName };
_menu.OnClose += Close;
_menu.OnItemSelected += OnItemSelected;
_menu.OnSearchChanged += OnSearchChanged;
_menu.OnWithdraw += SendMessage;
// WD EDIT END
_menu.Populate(_cachedInventory, out _cachedFilteredIndex);
_menu.Populate(_cachedInventory, component.PriceMultiplier, component.Credits);
_menu.OpenCentered();
}
@@ -48,21 +52,23 @@ namespace Content.Client.VendingMachines
_cachedInventory = newState.Inventory;
_menu?.Populate(_cachedInventory, out _cachedFilteredIndex, _menu.SearchBar.Text);
_menu?.Populate(_cachedInventory, newState.PriceMultiplier, newState.Credits);
}
private void OnItemSelected(ItemList.ItemListSelectedEventArgs args)
// WD EDIT START
private void OnItemSelected(int index)
{
if (_cachedInventory.Count == 0)
return;
var selectedItem = _cachedInventory.ElementAtOrDefault(_cachedFilteredIndex.ElementAtOrDefault(args.ItemIndex));
var selectedItem = _cachedInventory.ElementAtOrDefault(index);
if (selectedItem == null)
return;
SendMessage(new VendingMachineEjectMessage(selectedItem.Type, selectedItem.ID));
}
// WD EDIT END
protected override void Dispose(bool disposing)
{
@@ -80,7 +86,7 @@ namespace Content.Client.VendingMachines
private void OnSearchChanged(string? filter)
{
_menu?.Populate(_cachedInventory, out _cachedFilteredIndex, filter);
//_menu?.Populate(_cachedInventory, out _cachedFilteredIndex, filter);
}
}
}

View File

@@ -0,0 +1,8 @@
namespace Content.Client.White.Economy;
public enum ATMVisualLayers : byte
{
Base,
BaseUnshaded
}

View File

@@ -0,0 +1,43 @@
using JetBrains.Annotations;
using Robust.Client.GameObjects;
namespace Content.Client.White.Economy.Ui;
[UsedImplicitly]
public sealed class ATMBui : BoundUserInterface
{
private AtmWindow _window;
public ATMBui(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
_window = new AtmWindow();
}
protected override void Open()
{
base.Open();
_window.OnClose += Close;
_window.OnWithdrawAttempt += SendMessage;
if (State != null)
{
UpdateState(State);
}
_window.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
_window?.UpdateState(state);
}
protected override void Dispose(bool disposing)
{
_window?.Close();
base.Dispose(disposing);
}
}

View File

@@ -0,0 +1,20 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="ATM"
SetSize="400 220"
Resizable="False">
<BoxContainer Name="AuthorizationPage" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer HorizontalAlignment="Center" HorizontalExpand="True" VerticalAlignment="Center" Orientation="Vertical" MinSize="325 160">
<Label Text="NANOTRASEN ATM"/>
<Label Name="BalanceLabel" Visible="False"/>
<controls:HighDivider Name="Divider" Visible="False"/>
<Label Name="StatusLabel"/>
<SliderIntInput Name="WithdrawSlider"/>
<BoxContainer HorizontalExpand="True" VerticalExpand="True" VerticalAlignment="Bottom" Orientation="Horizontal">
<LineEdit Name="PinLineEdit" HorizontalExpand="True" Text="Enter PIN"/>
<Button Name="WithdrawButton" Text="{Loc 'store-ui-default-withdraw-text'}"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,79 @@
using System.Text.RegularExpressions;
using Content.Shared.White.Economy;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client.White.Economy.Ui;
[GenerateTypedNameReferences]
public sealed partial class AtmWindow : DefaultWindow
{
public Action<ATMRequestWithdrawMessage>? OnWithdrawAttempt;
private readonly string _pinPattern = "[^0-9]";
public AtmWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
WithdrawButton.OnButtonDown += args =>
{
if(PinLineEdit.Text.Length != 4) return;
OnWithdrawAttempt?.Invoke(new ATMRequestWithdrawMessage(WithdrawSlider.Value, int.Parse(PinLineEdit.Text)));
};
PinLineEdit.OnTextChanged += _ =>
{
ValidatePin();
};
}
public void UpdateState(BoundUserInterfaceState state)
{
if(state is not ATMBuiState cast) return;
if (!cast.HasCard)
{
StatusLabel.Text = cast.InfoMessage;
BalanceLabel.Visible = false;
Divider.Visible = false;
WithdrawSlider.Visible = false;
PinLineEdit.Visible = false;
WithdrawButton.Visible = false;
return;
}
StatusLabel.Text = cast.InfoMessage;
BalanceLabel.Text = Loc.GetString("atm-ui-balance", ("balance", cast.AccountBalance));
BalanceLabel.Visible = true;
Divider.Visible = true;
WithdrawSlider.Visible = true;
PinLineEdit.Visible = true;
WithdrawButton.Visible = true;
WithdrawSlider.MaxValue = cast.AccountBalance;
WithdrawSlider.Value = Math.Min(WithdrawSlider.Value, cast.AccountBalance);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
WithdrawButton.Disabled = PinLineEdit.Text.Length != 4;
}
private void ValidatePin()
{
var pinText = Regex.Replace(PinLineEdit.Text, _pinPattern, string.Empty);
if (pinText.Length > 4)
{
pinText = pinText[..4];
}
PinLineEdit.Text = pinText;
}
}

View File

@@ -0,0 +1,29 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.White.Economy;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.White.Economy.Ui;
public sealed partial class BankUi : UIFragment
{
private BankUiFragment? _fragment;
public override Control GetUIFragmentRoot()
{
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
{
_fragment = new BankUiFragment();
}
public override void UpdateState(BoundUserInterfaceState state)
{
if (state is not BankCartridgeUiState bankState)
return;
_fragment?.UpdateState(bankState);
}
}

View File

@@ -0,0 +1,12 @@
<ui:BankUiFragment xmlns="https://spacestation14.io"
xmlns:ui="clr-namespace:Content.Client.White.Economy.Ui">
<PanelContainer StyleClasses="BackgroundDark"></PanelContainer>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="8">
<BoxContainer Name="LinkedAccount" Orientation="Vertical" Visible="False">
<RichTextLabel Name="LinkedAccountNameLabel"/>
<RichTextLabel Name="LinkedAccountBalanceLabel"/>
</BoxContainer>
<RichTextLabel Name="NoLinkedAccountLabel" Visible="False"/>
</BoxContainer>
</ui:BankUiFragment>

View File

@@ -0,0 +1,30 @@
using Content.Client.Message;
using Content.Shared.White.Economy;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.White.Economy.Ui;
[GenerateTypedNameReferences]
public sealed partial class BankUiFragment : BoxContainer
{
public BankUiFragment()
{
RobustXamlLoader.Load(this);
}
public void UpdateState(BankCartridgeUiState state)
{
LinkedAccount.Visible = state.AccountLinked;
NoLinkedAccountLabel.Visible = !state.AccountLinked;
if (state.AccountLinked)
{
LinkedAccountNameLabel.SetMarkup(Loc.GetString("eftpos-ui-account-text", ("owner", state.OwnerName)));
LinkedAccountBalanceLabel.SetMarkup(Loc.GetString("atm-ui-balance", ("balance", state.Balance)));
return;
}
NoLinkedAccountLabel.SetMarkup(Loc.GetString("bank-program-ui-no-account"));
}
}

View File

@@ -0,0 +1,41 @@
using JetBrains.Annotations;
using Robust.Client.GameObjects;
namespace Content.Client.White.Economy.Ui;
[UsedImplicitly]
public sealed class EftposBui : BoundUserInterface
{
private readonly EftposWindow _window;
public EftposBui(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
_window = new EftposWindow();
}
protected override void Open()
{
base.Open();
_window.OnClose += Close;
_window.OnCardButtonPressed += SendMessage;
if (State != null)
{
UpdateState(State);
}
_window.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
_window.UpdateState(state);
}
protected override void Dispose(bool disposing)
{
_window.Close();
base.Dispose(disposing);
}
}

View File

@@ -0,0 +1,30 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc 'eftpos-ui-title'}"
Resizable="False"
SetSize="380 120">
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label
Name="AmountLabel"
Text="{Loc 'eftpos-ui-amount-text'}" />
<LineEdit
Name="AmountLineEdit"
PlaceHolder="0"
MinWidth="60"
Access="Public" />
<Button
Name="CardButton"
Access="Public"
HorizontalExpand="True"
HorizontalAlignment="Right"
ToolTip="{Loc 'eftpos-ui-card-lock-desc'}"
Text="{Loc 'eftpos-ui-card-lock-text'}" />
</BoxContainer>
<Label
Name="AccountLabel"
VerticalExpand="True"
VerticalAlignment="Bottom"
Access="Public" />
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,58 @@
using Content.Shared.White.Economy;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.White.Economy.Ui;
[GenerateTypedNameReferences]
public sealed partial class EftposWindow : DefaultWindow
{
public Action<EftposLockMessage>? OnCardButtonPressed;
public EftposWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
AmountLineEdit.OnTextChanged += _ =>
{
if (!int.TryParse(AmountLineEdit.Text, out var result) || result <= 0)
AmountLineEdit.Text = string.Empty;
AmountLineEdit.Text = result.ToString();
};
CardButton.OnPressed += _ =>
{
if (!int.TryParse(AmountLineEdit.Text, out var result) || result < 0)
result = 0;
OnCardButtonPressed?.Invoke(new EftposLockMessage(result));
};
}
public void UpdateState(BoundUserInterfaceState state)
{
if(state is not EftposBuiState eftState)
return;
AmountLineEdit.Text = eftState.Amount == 0 ? string.Empty : eftState.Amount.ToString();
if (eftState.Locked)
{
CardButton.Text = Loc.GetString("eftpos-ui-card-unlock-text");
CardButton.ToolTip = Loc.GetString("eftpos-ui-card-unlock-desc");
AmountLineEdit.Editable = false;
}
else
{
CardButton.Text = Loc.GetString("eftpos-ui-card-lock-text");
CardButton.ToolTip = Loc.GetString("eftpos-ui-card-lock-desc");
AmountLineEdit.Editable = true;
}
AccountLabel.Text = eftState.Owner == string.Empty
? string.Empty
: Loc.GetString("eftpos-ui-account-text", ("owner", eftState.Owner));
}
}

View File

@@ -0,0 +1,13 @@
<Control xmlns="https://spacestation14.io">
<BoxContainer Orientation="Horizontal">
<TextureRect
Name="VendingItemTexture"
Stretch="KeepAspectCentered" />
<Label Name="VendingItemName" HorizontalExpand="True" />
<Button
Name="VendingItemBuyButton"
MinWidth="80"
HorizontalAlignment="Right"
Access="Public" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,22 @@
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.White.Economy.Ui;
[GenerateTypedNameReferences]
public sealed partial class VendingItem : Control
{
public VendingItem(string itemName, string price, Texture? texture = null)
{
RobustXamlLoader.Load(this);
VendingItemName.Text = itemName;
VendingItemBuyButton.Text = price;
// VendingItemBuyButton.Disabled = !canBuy;
VendingItemTexture.Texture = texture;
}
}

View File

@@ -0,0 +1,26 @@
<DefaultWindow xmlns="https://spacestation14.io">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
<Label Name="CreditsLabel" HorizontalExpand="True"/>
<Button
Name="WithdrawButton"
Text="{Loc 'store-ui-default-withdraw-text'}"
HorizontalAlignment="Right"/>
</BoxContainer>
<PanelContainer StyleClasses="HighDivider" />
<Label
Name="OutOfStockLabel"
Visible="False"
Text="{Loc 'vending-machine-component-try-eject-out-of-stock'}"/>
<ScrollContainer
HScrollEnabled="False"
HorizontalExpand="True"
VerticalExpand="True">
<BoxContainer
Name="VendingContents"
Orientation="Vertical"
VerticalExpand="True">
</BoxContainer>
</ScrollContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,88 @@
using System.Numerics;
using Content.Shared.VendingMachines;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.White.Economy.Ui;
[GenerateTypedNameReferences]
public sealed partial class VendingMenu : DefaultWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public event Action<int>? OnItemSelected;
public Action<VendingMachineWithdrawMessage>? OnWithdraw;
public VendingMenu()
{
MinSize = SetSize = new Vector2(250, 150);
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
}
/// <summary>
/// Populates the list of available items on the vending machine interface
/// and sets icons based on their prototypes
/// </summary>
public void Populate(List<VendingMachineInventoryEntry> inventory, double priceMultiplier, int credits)
{
CreditsLabel.Text = Loc.GetString("vending-ui-credits-amount", ("credits", credits));
WithdrawButton.Disabled = credits == 0;
WithdrawButton.OnPressed += _ =>
{
if (credits == 0)
return;
OnWithdraw?.Invoke(new VendingMachineWithdrawMessage());
};
VendingContents.RemoveAllChildren();
if (inventory.Count == 0)
{
OutOfStockLabel.Visible = true;
SetSizeAfterUpdate(OutOfStockLabel.Text?.Length ?? 0);
return;
}
OutOfStockLabel.Visible = false;
var longestEntry = string.Empty;
var spriteSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SpriteSystem>();
for (var i = 0; i < inventory.Count; i++)
{
var entry = inventory[i];
var itemName = entry.ID;
Texture? icon = null;
if (_prototypeManager.TryIndex<EntityPrototype>(entry.ID, out var prototype))
{
itemName = prototype.Name;
icon = spriteSystem.GetPrototypeIcon(prototype).Default;
}
if (itemName.Length > longestEntry.Length)
longestEntry = itemName;
var price = (int) (entry.Price * priceMultiplier);
var vendingItem = new VendingItem($"{itemName} [{entry.Amount}]", $"{price} ¢", icon);
var j = i;
vendingItem.VendingItemBuyButton.OnPressed += _ =>
{
OnItemSelected?.Invoke(j);
};
VendingContents.AddChild(vendingItem);
}
SetSizeAfterUpdate(longestEntry.Length);
}
private void SetSizeAfterUpdate(int longestEntryLength)
{
SetSize = new Vector2(Math.Clamp((longestEntryLength + 10) * 12, 250, 700),
Math.Clamp(VendingContents.ChildCount * 50, 150, 400));
}
}