forked from SpaceStation14-Shenanigans/Monolith
Change Tax Into Savings (#4021)
This commit is contained in:
@@ -39,6 +39,7 @@ using Robust.Shared.Replays;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Client._NF.Emp.Overlays; // Frontier
|
||||
using Content.Client._Mono.Company; // Mono
|
||||
using Content.Client._Mono.MonoCoins; // Mono
|
||||
|
||||
namespace Content.Client.Entry
|
||||
{
|
||||
@@ -77,6 +78,7 @@ namespace Content.Client.Entry
|
||||
[Dependency] private readonly TitleWindowManager _titleWindowManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
[Dependency] private readonly CompanyManager _companyManager = default!; // Mono
|
||||
[Dependency] private readonly MonoCoinsManager _coinsManager = default!; // Mono
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
@@ -139,7 +141,8 @@ namespace Content.Client.Entry
|
||||
_extendedDisconnectInformation.Initialize();
|
||||
_jobRequirements.Initialize();
|
||||
_playbackMan.Initialize();
|
||||
_companyManager.Initialize();
|
||||
_companyManager.Initialize(); // Mono
|
||||
_coinsManager.Initialize(); // Mono
|
||||
|
||||
//AUTOSCALING default Setup!
|
||||
_configManager.SetCVar("interface.resolutionAutoScaleUpperCutoffX", 1080);
|
||||
|
||||
@@ -25,6 +25,7 @@ using Content.Shared.Chat;
|
||||
using Content.Shared.Players.PlayTimeTracking;
|
||||
using Content.Shared.Players.RateLimiting;
|
||||
using Content.Client._Mono.Company; // Mono
|
||||
using Content.Client._Mono.MonoCoins; // Mono
|
||||
|
||||
namespace Content.Client.IoC
|
||||
{
|
||||
@@ -62,6 +63,7 @@ namespace Content.Client.IoC
|
||||
collection.Register<SharedPlayerRateLimitManager, PlayerRateLimitManager>();
|
||||
collection.Register<TitleWindowManager>();
|
||||
collection.Register<CompanyManager>(); // Mono
|
||||
collection.Register<MonoCoinsManager>(); // Mono
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,11 +43,11 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
[Dependency] private readonly JobRequirementsManager _requirements = default!;
|
||||
[Dependency] private readonly MarkingManager _markings = default!;
|
||||
[Dependency] private readonly CompanyManager _companyManager = default!; // Mono
|
||||
[Dependency] private readonly MonoCoinsManager _monoCoins = default!; // Mono
|
||||
[UISystemDependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
||||
[UISystemDependency] private readonly ClientInventorySystem _inventory = default!;
|
||||
[UISystemDependency] private readonly StationSpawningSystem _spawn = default!;
|
||||
[UISystemDependency] private readonly GuidebookSystem _guide = default!;
|
||||
[UISystemDependency] private readonly MonoCoinsSystem _monoCoins = default!;
|
||||
|
||||
private CharacterSetupGui? _characterSetup;
|
||||
private HumanoidProfileEditor? _profileEditor;
|
||||
@@ -99,7 +99,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
/// <summary>
|
||||
/// Called when MonoCoins balance is updated from the server.
|
||||
/// </summary>
|
||||
private void OnMonoCoinsBalanceUpdated(int balance)
|
||||
private void OnMonoCoinsBalanceUpdated(long balance)
|
||||
{
|
||||
UpdateMonoCoinsDisplay();
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
return;
|
||||
|
||||
var balance = _monoCoins?.GetLastKnownBalance() ?? -1;
|
||||
PreviewPanel.SetMonoCoinsText($"MonoCoins: {balance}");
|
||||
PreviewPanel.SetMonoCoinsText(Loc.GetString("server-currency-text", ("balance", balance)));
|
||||
}
|
||||
|
||||
private LobbyCharacterPreviewPanel? GetLobbyPreview()
|
||||
@@ -229,7 +229,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
PreviewPanel.SetSummaryText(string.Empty);
|
||||
PreviewPanel.SetBankBalanceText(string.Empty); // Frontier
|
||||
PreviewPanel.SetCompanyText(string.Empty); // Company Display
|
||||
PreviewPanel.SetMonoCoinsText("MonoCoins: -1"); // MonoCoins Display
|
||||
PreviewPanel.SetMonoCoinsText("server-currency-loading"); // MonoCoins Display
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Content.Client._Mono.MonoCoins; // Mono
|
||||
using Content.Shared._NF.Bank; // Frontier
|
||||
|
||||
namespace Content.Client.Lobby.UI.Loadouts;
|
||||
@@ -17,6 +18,8 @@ namespace Content.Client.Lobby.UI.Loadouts;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class LoadoutWindow : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly MonoCoinsManager _coins = default!; // Mono
|
||||
|
||||
public event Action<string>? OnNameChanged;
|
||||
public event Action<ProtoId<LoadoutGroupPrototype>, ProtoId<LoadoutPrototype>>? OnLoadoutPressed;
|
||||
public event Action<ProtoId<LoadoutGroupPrototype>, ProtoId<LoadoutPrototype>>? OnLoadoutUnpressed;
|
||||
@@ -86,9 +89,12 @@ public sealed partial class LoadoutWindow : FancyWindow
|
||||
//Frontier - we inject our label here but it needs recalculating every time a new item is selected,
|
||||
//so we add a new method and call it there too.
|
||||
CalculateLoadoutCost(loadout, collection);
|
||||
var accountBalance = _coins.GetLastKnownBalance();
|
||||
// Frontier - update bank balance label text - value should not change.
|
||||
Balance.Margin = new Thickness(5, 2, 5, 5);
|
||||
Balance.Text = Loc.GetString("frontier-loadout-balance", ("balance", BankSystemExtensions.ToSpesoString(Profile.BankBalance)));
|
||||
Balance.Text = Loc.GetString("frontier-loadout-balance",
|
||||
("balance", BankSystemExtensions.ToSpesoString(Profile.BankBalance)),
|
||||
("savings", BankSystemExtensions.ToSpesoString(accountBalance)));
|
||||
}
|
||||
|
||||
public void RefreshLoadouts(RoleLoadout loadout, ICommonSession session, IDependencyCollection collection)
|
||||
|
||||
+12
-14
@@ -6,34 +6,32 @@ namespace Content.Client._Mono.MonoCoins;
|
||||
/// <summary>
|
||||
/// Client-side system for handling MonoCoins balance requests and responses.
|
||||
/// </summary>
|
||||
public sealed class MonoCoinsSystem : EntitySystem
|
||||
public sealed class MonoCoinsManager
|
||||
{
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The last known MonoCoins balance. -1 indicates balance hasn't been fetched yet.
|
||||
/// </summary>
|
||||
private int _lastKnownBalance = -1;
|
||||
private long _lastKnownBalance = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when MonoCoins balance is updated.
|
||||
/// </summary>
|
||||
public event Action<int>? BalanceUpdated;
|
||||
public event Action<long>? BalanceUpdated;
|
||||
|
||||
public override void Initialize()
|
||||
public void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
// Subscribe to network messages
|
||||
SubscribeNetworkEvent<MonoCoinsBalanceResponseMessage>(OnMonoCoinsBalanceResponse);
|
||||
_net.RegisterNetMessage<MsgMonoCoins>(OnBalanceGet);
|
||||
_net.RegisterNetMessage<MsgMonoCoinsRequest>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles MonoCoins balance response from server.
|
||||
/// </summary>
|
||||
private void OnMonoCoinsBalanceResponse(MonoCoinsBalanceResponseMessage message)
|
||||
private void OnBalanceGet(MsgMonoCoins msg)
|
||||
{
|
||||
_lastKnownBalance = message.Balance;
|
||||
_lastKnownBalance = msg.Coins;
|
||||
BalanceUpdated?.Invoke(_lastKnownBalance);
|
||||
}
|
||||
|
||||
@@ -42,15 +40,15 @@ public sealed class MonoCoinsSystem : EntitySystem
|
||||
/// </summary>
|
||||
public void RequestBalance()
|
||||
{
|
||||
var message = new RequestMonoCoinsBalanceMessage();
|
||||
RaiseNetworkEvent(message);
|
||||
var message = new MsgMonoCoinsRequest();
|
||||
_net.ClientSendMessage(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last known MonoCoins balance.
|
||||
/// Returns -1 if balance hasn't been fetched yet.
|
||||
/// </summary>
|
||||
public int GetLastKnownBalance()
|
||||
public long GetLastKnownBalance()
|
||||
{
|
||||
return _lastKnownBalance;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public sealed class BankATMMenuBoundUserInterface : BoundUserInterface
|
||||
return;
|
||||
|
||||
_menu?.SetEnabled(bankState.Enabled);
|
||||
_menu?.SetBalance(bankState.Balance);
|
||||
_menu?.SetDeposit(bankState.Deposit, bankState.DepositUntaxed);
|
||||
_menu?.SetBalance(bankState.Balance, bankState.Savings);
|
||||
_menu?.SetDeposit(bankState.Deposit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Content.Shared._NF.Bank;
|
||||
|
||||
namespace Content.Client.Bank;
|
||||
namespace Content.Client._NF.Bank;
|
||||
|
||||
// Shared is abstract.
|
||||
public sealed partial class BankSystem : SharedBankSystem;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
SetSize="300 330"
|
||||
MinSize="300 330"
|
||||
SetSize="300 350"
|
||||
MinSize="300 350"
|
||||
Resizable="False">
|
||||
<BoxContainer Margin="10 2 10 2" Orientation="Vertical">
|
||||
<PanelContainer VerticalExpand="True" HorizontalExpand="True">
|
||||
@@ -10,82 +10,97 @@
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#35434d" BackgroundColor="#696969"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer VerticalExpand="True" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#303030" BackgroundColor="#0f0f0f"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'bank-atm-menu-balance-label'}"
|
||||
StyleClasses="LabelKeyText"
|
||||
Margin="4 4 4 4"/>
|
||||
<Label Name="BalanceLabel"
|
||||
Text="{Loc 'bank-atm-menu-no-bank'}"
|
||||
Margin="4 4 4 4"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
<LineEdit Name="WithdrawEdit" MinSize="80 0"
|
||||
PlaceHolder="{Loc 'bank-atm-menu-withdraw-amount'}" Margin="2 2"/>
|
||||
<PanelContainer VerticalExpand="False" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#3d3d3d" BackgroundColor="#111111" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<Button Name="WithdrawButton"
|
||||
Text="{Loc 'bank-atm-menu-withdraw-button'}"
|
||||
StyleClasses="ButtonSquare"
|
||||
Margin="4 4 4 4"/>
|
||||
</PanelContainer>
|
||||
<PanelContainer VerticalExpand="False" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="2" BorderColor="#262626" BackgroundColor="#111111" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer VerticalExpand="True" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#303030" BackgroundColor="#0f0f0f"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<PanelContainer VerticalExpand="True" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#303030" BackgroundColor="#0f0f0f"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'bank-atm-menu-balance-label'}"
|
||||
StyleClasses="LabelKeyText"
|
||||
Margin="4 4 4 4"/>
|
||||
<Label Name="BalanceLabel"
|
||||
Text="{Loc 'bank-atm-menu-no-bank'}"
|
||||
Margin="4 4 4 4"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'bank-atm-menu-deposit-label'}"
|
||||
StyleClasses="LabelKeyText"
|
||||
Margin="4 4 4 4"/>
|
||||
<Label Name="DepositLabel"
|
||||
Text="{Loc 'bank-atm-menu-no-deposit'}"
|
||||
Margin="4 4 4 4"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<PanelContainer VerticalExpand="False" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="2" BorderColor="#262626" BackgroundColor="#111111" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer VerticalExpand="True" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer VerticalExpand="True" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#303030" BackgroundColor="#0f0f0f"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'bank-atm-menu-savings-label'}"
|
||||
StyleClasses="LabelKeyText"
|
||||
Margin="4 4 4 4"/>
|
||||
<Label Name="SavingsLabel"
|
||||
Text="{Loc 'bank-atm-menu-no-bank'}"
|
||||
Margin="4 4 4 4"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
<LineEdit Name="WithdrawEdit" MinSize="80 0"
|
||||
PlaceHolder="{Loc 'bank-atm-menu-withdraw-amount'}" Margin="2 2"/>
|
||||
<PanelContainer VerticalExpand="False" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#303030" BackgroundColor="#0f0f0f"/>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#3d3d3d" BackgroundColor="#111111" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<Button Name="WithdrawButton"
|
||||
Text="{Loc 'bank-atm-menu-withdraw-button'}"
|
||||
StyleClasses="ButtonSquare"
|
||||
Margin="4 4 4 4"/>
|
||||
</PanelContainer>
|
||||
<PanelContainer VerticalExpand="False" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="2" BorderColor="#262626" BackgroundColor="#111111" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer VerticalExpand="True" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#303030" BackgroundColor="#0f0f0f"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'bank-atm-menu-deposit-label'}"
|
||||
StyleClasses="LabelKeyText"
|
||||
Margin="4 4 4 4"/>
|
||||
<Label Name="DepositLabel"
|
||||
Text="{Loc 'bank-atm-menu-no-deposit'}"
|
||||
Margin="4 4 4 4"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<PanelContainer VerticalExpand="False" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="2" BorderColor="#262626" BackgroundColor="#111111" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'bank-atm-menu-deposit-label-ut'}"
|
||||
StyleClasses="LabelKeyText"
|
||||
Margin="4 4 4 4"/>
|
||||
<Label Name="DepositLabelUT"
|
||||
Text="{Loc 'bank-atm-menu-no-deposit'}"
|
||||
Margin="4 4 4 4"/>
|
||||
<PanelContainer VerticalExpand="True" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#303030" BackgroundColor="#0f0f0f"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'bank-atm-menu-deposit-label-ut'}"
|
||||
StyleClasses="LabelKeyText"
|
||||
Margin="4 4 4 4"/>
|
||||
<Label Name="DepositLabelUT"
|
||||
Text="{Loc 'bank-atm-menu-no-deposit'}"
|
||||
Margin="4 4 4 4"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<PanelContainer VerticalExpand="False" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#3d3d3d" BackgroundColor="#111111" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<Button Name="DepositButton"
|
||||
Text="{Loc 'bank-atm-menu-deposit-button'}"
|
||||
StyleClasses="ButtonSquare"
|
||||
Margin="4 4 4 4"/>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<PanelContainer VerticalExpand="False" HorizontalExpand="True" Margin="2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="3" BorderColor="#3d3d3d" BackgroundColor="#111111" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<Button Name="DepositButton"
|
||||
Text="{Loc 'bank-atm-menu-deposit-button'}"
|
||||
StyleClasses="ButtonSquare"
|
||||
Margin="4 4 4 4"/>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Client._NF.Bank;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared._NF.Bank;
|
||||
using Robust.Client.AutoGenerated;
|
||||
@@ -9,30 +10,40 @@ namespace Content.Client._NF.Bank.UI;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BankATMMenu : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _ent = default!;
|
||||
private readonly BankSystem _bank;
|
||||
|
||||
public Action? WithdrawRequest;
|
||||
public Action? DepositRequest;
|
||||
public int Amount;
|
||||
public int BankAmount;
|
||||
public BankATMMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
_bank = _ent.System<BankSystem>();
|
||||
|
||||
WithdrawButton.OnPressed += OnWithdrawPressed;
|
||||
DepositButton.OnPressed += OnDepositPressed;
|
||||
Title = Loc.GetString("bank-atm-menu-title");
|
||||
WithdrawEdit.OnTextChanged += OnAmountChanged;
|
||||
}
|
||||
|
||||
public void SetBalance(int amount)
|
||||
public void SetBalance(int amount, long savings)
|
||||
{
|
||||
BalanceLabel.Text = BankSystemExtensions.ToSpesoString(amount);
|
||||
SavingsLabel.Text = BankSystemExtensions.ToSpesoString(savings);
|
||||
BankAmount = amount;
|
||||
}
|
||||
|
||||
public void SetDeposit(int amount, int untaxedAmount)
|
||||
public void SetDeposit(int amount)
|
||||
{
|
||||
DepositButton.Disabled = amount <= 0;
|
||||
if (amount >= 0) // Valid
|
||||
{
|
||||
DepositLabel.Text = BankSystemExtensions.ToSpesoString(amount);
|
||||
DepositLabelUT.Text = BankSystemExtensions.ToSpesoString(untaxedAmount);
|
||||
_bank.GetTaxedDepositAmount(amount, BankAmount, out var afterTax, out var taxedAway);
|
||||
DepositLabel.Text = BankSystemExtensions.ToSpesoString(afterTax);
|
||||
DepositLabelUT.Text = BankSystemExtensions.ToSpesoString(taxedAway);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+2176
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Postgres
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class LongifyMonocoins : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<long>(
|
||||
name: "mono_coins",
|
||||
table: "preference",
|
||||
type: "bigint",
|
||||
nullable: false,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "mono_coins",
|
||||
table: "preference",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
oldClrType: typeof(long),
|
||||
oldType: "bigint");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -820,8 +820,8 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("admin_ooc_color");
|
||||
|
||||
b.Property<int>("MonoCoins")
|
||||
.HasColumnType("integer")
|
||||
b.Property<long>("MonoCoins")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("mono_coins");
|
||||
|
||||
b.Property<int>("SelectedCharacterSlot")
|
||||
|
||||
+2100
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Sqlite
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class LongifyMonocoins : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -774,7 +774,7 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("admin_ooc_color");
|
||||
|
||||
b.Property<int>("MonoCoins")
|
||||
b.Property<long>("MonoCoins")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("mono_coins");
|
||||
|
||||
@@ -1665,7 +1665,7 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
|
||||
b1.HasKey("ConnectionLogId");
|
||||
|
||||
b1.ToTable("connection_log", (string)null);
|
||||
b1.ToTable("connection_log");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("ConnectionLogId")
|
||||
@@ -1710,7 +1710,7 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
|
||||
b1.HasKey("PlayerId");
|
||||
|
||||
b1.ToTable("player", (string)null);
|
||||
b1.ToTable("player");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("PlayerId")
|
||||
@@ -1833,7 +1833,7 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
|
||||
b1.HasKey("ServerBanId");
|
||||
|
||||
b1.ToTable("server_ban", (string)null);
|
||||
b1.ToTable("server_ban");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("ServerBanId")
|
||||
@@ -1910,7 +1910,7 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
|
||||
b1.HasKey("ServerRoleBanId");
|
||||
|
||||
b1.ToTable("server_role_ban", (string)null);
|
||||
b1.ToTable("server_role_ban");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("ServerRoleBanId")
|
||||
|
||||
@@ -401,7 +401,7 @@ namespace Content.Server.Database
|
||||
public Guid UserId { get; set; }
|
||||
public int SelectedCharacterSlot { get; set; }
|
||||
public string AdminOOCColor { get; set; } = null!;
|
||||
public int MonoCoins { get; set; } = 0;
|
||||
public long MonoCoins { get; set; } = 0;
|
||||
public List<Profile> Profiles { get; } = new();
|
||||
}
|
||||
|
||||
|
||||
@@ -393,17 +393,17 @@ namespace Content.Server.Database
|
||||
|
||||
#region MonoCoins
|
||||
|
||||
public async Task<int> GetMonoCoinsAsync(NetUserId userId, CancellationToken cancel = default)
|
||||
public async Task<long> GetMonoCoinsAsync(NetUserId userId, CancellationToken cancel = default)
|
||||
{
|
||||
await using var db = await GetDb(cancel);
|
||||
|
||||
var prefs = await db.DbContext.Preference
|
||||
.SingleOrDefaultAsync(p => p.UserId == userId.UserId, cancel);
|
||||
|
||||
return prefs?.MonoCoins ?? 0;
|
||||
return prefs?.MonoCoins ?? 0l;
|
||||
}
|
||||
|
||||
public async Task SetMonoCoinsAsync(NetUserId userId, int balance, CancellationToken cancel = default)
|
||||
public async Task SetMonoCoinsAsync(NetUserId userId, long balance, CancellationToken cancel = default)
|
||||
{
|
||||
await using var db = await GetDb(cancel);
|
||||
|
||||
@@ -412,12 +412,12 @@ namespace Content.Server.Database
|
||||
|
||||
if (prefs != null)
|
||||
{
|
||||
prefs.MonoCoins = Math.Max(0, balance); // Ensure balance is never negative
|
||||
prefs.MonoCoins = Math.Max(0l, balance); // Ensure balance is never negative
|
||||
await db.DbContext.SaveChangesAsync(cancel);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> AddMonoCoinsAsync(NetUserId userId, int amount, CancellationToken cancel = default)
|
||||
public async Task<long> AddMonoCoinsAsync(NetUserId userId, long amount, CancellationToken cancel = default)
|
||||
{
|
||||
await using var db = await GetDb(cancel);
|
||||
|
||||
@@ -427,7 +427,7 @@ namespace Content.Server.Database
|
||||
if (prefs != null)
|
||||
{
|
||||
prefs.MonoCoins += amount;
|
||||
prefs.MonoCoins = Math.Max(0, prefs.MonoCoins); // Ensure balance is never negative
|
||||
prefs.MonoCoins = Math.Max(0l, prefs.MonoCoins); // Ensure balance is never negative
|
||||
await db.DbContext.SaveChangesAsync(cancel);
|
||||
return prefs.MonoCoins;
|
||||
}
|
||||
@@ -435,23 +435,6 @@ namespace Content.Server.Database
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<bool> TrySubtractMonoCoinsAsync(NetUserId userId, int amount, CancellationToken cancel = default)
|
||||
{
|
||||
await using var db = await GetDb(cancel);
|
||||
|
||||
var prefs = await db.DbContext.Preference
|
||||
.SingleOrDefaultAsync(p => p.UserId == userId.UserId, cancel);
|
||||
|
||||
if (prefs != null && prefs.MonoCoins >= amount)
|
||||
{
|
||||
prefs.MonoCoins -= amount;
|
||||
await db.DbContext.SaveChangesAsync(cancel);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Bans
|
||||
|
||||
@@ -51,10 +51,9 @@ namespace Content.Server.Database
|
||||
#endregion
|
||||
|
||||
#region MonoCoins
|
||||
Task<int> GetMonoCoinsAsync(NetUserId userId, CancellationToken cancel = default);
|
||||
Task SetMonoCoinsAsync(NetUserId userId, int balance, CancellationToken cancel = default);
|
||||
Task<int> AddMonoCoinsAsync(NetUserId userId, int amount, CancellationToken cancel = default);
|
||||
Task<bool> TrySubtractMonoCoinsAsync(NetUserId userId, int amount, CancellationToken cancel = default);
|
||||
Task<long> GetMonoCoinsAsync(NetUserId userId, CancellationToken cancel = default);
|
||||
Task SetMonoCoinsAsync(NetUserId userId, long balance, CancellationToken cancel = default);
|
||||
Task<long> AddMonoCoinsAsync(NetUserId userId, long amount, CancellationToken cancel = default);
|
||||
#endregion
|
||||
|
||||
#region User Ids
|
||||
@@ -519,30 +518,24 @@ namespace Content.Server.Database
|
||||
return RunDbCommand(() => _db.GetPlayerPreferencesAsync(userId, cancel));
|
||||
}
|
||||
|
||||
public Task<int> GetMonoCoinsAsync(NetUserId userId, CancellationToken cancel = default)
|
||||
public Task<long> GetMonoCoinsAsync(NetUserId userId, CancellationToken cancel = default)
|
||||
{
|
||||
DbReadOpsMetric.Inc();
|
||||
return RunDbCommand(() => _db.GetMonoCoinsAsync(userId, cancel));
|
||||
}
|
||||
|
||||
public Task SetMonoCoinsAsync(NetUserId userId, int balance, CancellationToken cancel = default)
|
||||
public Task SetMonoCoinsAsync(NetUserId userId, long balance, CancellationToken cancel = default)
|
||||
{
|
||||
DbWriteOpsMetric.Inc();
|
||||
return RunDbCommand(() => _db.SetMonoCoinsAsync(userId, balance, cancel));
|
||||
}
|
||||
|
||||
public Task<int> AddMonoCoinsAsync(NetUserId userId, int amount, CancellationToken cancel = default)
|
||||
public Task<long> AddMonoCoinsAsync(NetUserId userId, long amount, CancellationToken cancel = default)
|
||||
{
|
||||
DbWriteOpsMetric.Inc();
|
||||
return RunDbCommand(() => _db.AddMonoCoinsAsync(userId, amount, cancel));
|
||||
}
|
||||
|
||||
public Task<bool> TrySubtractMonoCoinsAsync(NetUserId userId, int amount, CancellationToken cancel = default)
|
||||
{
|
||||
DbWriteOpsMetric.Inc();
|
||||
return RunDbCommand(() => _db.TrySubtractMonoCoinsAsync(userId, amount, cancel));
|
||||
}
|
||||
|
||||
public Task AssignUserIdAsync(string name, NetUserId userId)
|
||||
{
|
||||
DbWriteOpsMetric.Inc();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server._Mono.Company; // Mono
|
||||
using Content.Server._Mono.MonoCoins; // Mono
|
||||
using Content.Server._NF.Auth;
|
||||
using Content.Server.Acz;
|
||||
using Content.Server.Administration;
|
||||
@@ -157,6 +158,7 @@ namespace Content.Server.Entry
|
||||
_euiManager.Initialize();
|
||||
|
||||
IoCManager.Resolve<CompanyManager>().Initialize(); // Mono
|
||||
IoCManager.Resolve<MonoCoinsManager>().Initialize(); // Mono
|
||||
IoCManager.Resolve<IGameMapManager>().Initialize();
|
||||
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<GameTicker>().PostInitialize();
|
||||
IoCManager.Resolve<IBanManager>().Initialize();
|
||||
|
||||
@@ -872,7 +872,7 @@ namespace Content.Server.GameTicking
|
||||
// Check if adding this line would exceed field value limit
|
||||
if (currentProfitLength + line.Length + 1 > MaxFieldValueLength - 20 && currentProfitLines.Count > 0)
|
||||
{
|
||||
var fieldName = profitFieldCount == 0 ? "TSF Central Bank" : "TSF Central Bank (continued)";
|
||||
var fieldName = profitFieldCount == 0 ? "Colossus Central Bank" : "Colossus Central Bank (continued)";
|
||||
var fieldValue = string.Join("\n", currentProfitLines);
|
||||
var fieldCharacterCount = fieldName.Length + fieldValue.Length;
|
||||
|
||||
@@ -902,7 +902,7 @@ namespace Content.Server.GameTicking
|
||||
// Add remaining profit lines
|
||||
if (currentProfitLines.Count > 0)
|
||||
{
|
||||
var fieldName = profitFieldCount == 0 ? "TSF Central Bank" : "TSF Central Bank (continued)";
|
||||
var fieldName = profitFieldCount == 0 ? "Colossus Central Bank" : "Colossus Central Bank (continued)";
|
||||
var fieldValue = string.Join("\n", currentProfitLines);
|
||||
var fieldCharacterCount = fieldName.Length + fieldValue.Length;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server._Mono.Company; // Mono
|
||||
using Content.Server._Mono.MonoCoins; // Mono
|
||||
using Content.Server._NF.Auth;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Administration.Logs;
|
||||
@@ -80,6 +81,7 @@ namespace Content.Server.IoC
|
||||
IoCManager.Register<CVarControlManager>();
|
||||
IoCManager.Register<MiniAuthManager>(); //Frontier
|
||||
IoCManager.Register<CompanyManager>(); // Mono
|
||||
IoCManager.Register<MonoCoinsManager>(); // Mono
|
||||
|
||||
IoCManager.Register<DiscordLink>();
|
||||
IoCManager.Register<DiscordChatLink>();
|
||||
|
||||
@@ -27,6 +27,7 @@ using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Server.Spawners.Components;
|
||||
using Content.Shared._NF.Bank.Components; // DeltaV
|
||||
using Content.Server._Mono.MonoCoins; // Mono
|
||||
using Content.Server._NF.Bank; // Frontier
|
||||
using Content.Server.Preferences.Managers; // Frontier
|
||||
using System.Linq;
|
||||
@@ -58,6 +59,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
||||
[Dependency] private readonly InternalEncryptionKeySpawner _internalEncryption = default!; // Goobstation
|
||||
|
||||
[Dependency] private readonly BankSystem _bank = default!; // Frontier
|
||||
[Dependency] private readonly MonoCoinsManager _coins = default!; // Mono
|
||||
private bool _randomizeCharacters;
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -187,8 +189,9 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
||||
{
|
||||
/// Frontier: overwriting EquipRoleLoadout
|
||||
//EquipRoleLoadout(entity.Value, loadout, roleProto!);
|
||||
var initialBankBalance = profile!.BankBalance; //Frontier
|
||||
var bankBalance = profile!.BankBalance; //Frontier
|
||||
long initialBankBalance = profile!.BankBalance; //Frontier
|
||||
initialBankBalance += session == null ? 0l : _coins.GetMonoCoinsBalance(session.UserId) ?? 0l;
|
||||
var bankBalance = initialBankBalance; //Frontier
|
||||
bool hasBalance = false; // Frontier
|
||||
|
||||
// Note: since this is stored per character, we don't have a cached
|
||||
@@ -290,7 +293,8 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
||||
|
||||
if (hasBalance)
|
||||
{
|
||||
_bank.TryBankWithdraw(session!, prefs!, profile!, initialBankBalance - bankBalance, out var newBalance);
|
||||
// also spend long-term currency on this
|
||||
_bank.TryBankWithdraw(session!, prefs!, profile!, (int)(initialBankBalance - bankBalance), out var newBalance, true);
|
||||
}
|
||||
/// End Frontier: overwriting EquipRoleLoadout
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Content.Server._Mono.MonoCoins;
|
||||
public sealed class CurrencyAddCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly MonoCoinsManager _coins = default!;
|
||||
|
||||
public override string Command => "currency:add";
|
||||
|
||||
@@ -29,18 +29,12 @@ public sealed class CurrencyAddCommand : LocalizedCommands
|
||||
|
||||
var playerName = args[0];
|
||||
|
||||
if (!int.TryParse(args[1], out var amount))
|
||||
if (!long.TryParse(args[1], out var amount))
|
||||
{
|
||||
shell.WriteError("Amount must be a valid integer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount <= 0)
|
||||
{
|
||||
shell.WriteError("Amount must be positive.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the player
|
||||
ICommonSession? targetSession = null;
|
||||
foreach (var session in _playerManager.Sessions)
|
||||
@@ -62,7 +56,7 @@ public sealed class CurrencyAddCommand : LocalizedCommands
|
||||
|
||||
try
|
||||
{
|
||||
var newBalance = await _db.AddMonoCoinsAsync(userId, amount);
|
||||
var newBalance = await _coins.AddMonoCoinsAsync(userId, amount);
|
||||
shell.WriteLine($"Added {amount} MonoCoins to {playerName}. New balance: {newBalance}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Content.Server._Mono.MonoCoins;
|
||||
public sealed class CurrencyBalanceCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly MonoCoinsManager _coins = default!;
|
||||
|
||||
public override string Command => "currency:balance";
|
||||
|
||||
@@ -50,8 +50,8 @@ public sealed class CurrencyBalanceCommand : LocalizedCommands
|
||||
|
||||
try
|
||||
{
|
||||
var balance = await _db.GetMonoCoinsAsync(userId);
|
||||
shell.WriteLine($"{playerName} has {balance} MonoCoins");
|
||||
var balance = await _coins.GetMonoCoinsBalanceAsync(userId);
|
||||
shell.WriteLine($"{playerName} has ${balance}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Database;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server._Mono.MonoCoins;
|
||||
|
||||
/// <summary>
|
||||
/// Admin command for subtracting MonoCoins from a player.
|
||||
/// </summary>
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class CurrencySubtractCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
|
||||
public override string Command => "currency:subtract";
|
||||
|
||||
public override async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
shell.WriteError("Usage: currency:subtract <player> <amount>");
|
||||
return;
|
||||
}
|
||||
|
||||
var playerName = args[0];
|
||||
|
||||
if (!int.TryParse(args[1], out var amount))
|
||||
{
|
||||
shell.WriteError("Amount must be a valid integer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount <= 0)
|
||||
{
|
||||
shell.WriteError("Amount must be positive.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the player
|
||||
ICommonSession? targetSession = null;
|
||||
foreach (var session in _playerManager.Sessions)
|
||||
{
|
||||
if (session.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
targetSession = session;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetSession == null)
|
||||
{
|
||||
shell.WriteError($"Player '{playerName}' not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
var userId = targetSession.UserId;
|
||||
|
||||
try
|
||||
{
|
||||
var success = await _db.TrySubtractMonoCoinsAsync(userId, amount);
|
||||
if (success)
|
||||
{
|
||||
var currentBalance = await _db.GetMonoCoinsAsync(userId);
|
||||
shell.WriteLine($"Subtracted {amount} MonoCoins from {playerName}. New balance: {currentBalance}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentBalance = await _db.GetMonoCoinsAsync(userId);
|
||||
shell.WriteError($"Insufficient MonoCoins. {playerName} has {currentBalance} MonoCoins, cannot subtract {amount}.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
shell.WriteError($"Database error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
switch (args.Length)
|
||||
{
|
||||
case 1:
|
||||
var playerNames = _playerManager.Sessions.Select(s => s.Name).ToArray();
|
||||
return CompletionResult.FromOptions(playerNames);
|
||||
case 2:
|
||||
return CompletionResult.FromHint("Amount");
|
||||
default:
|
||||
return CompletionResult.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace Content.Server._Mono.MonoCoins;
|
||||
public sealed class CurrencyTransferCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly MonoCoinsManager _coins = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
|
||||
public override string Command => "currency:transfer";
|
||||
@@ -31,7 +31,7 @@ public sealed class CurrencyTransferCommand : LocalizedCommands
|
||||
|
||||
var targetPlayerName = args[0];
|
||||
|
||||
if (!int.TryParse(args[1], out var amount))
|
||||
if (!long.TryParse(args[1], out var amount))
|
||||
{
|
||||
shell.WriteError("Amount must be a valid integer.");
|
||||
return;
|
||||
@@ -71,7 +71,7 @@ public sealed class CurrencyTransferCommand : LocalizedCommands
|
||||
// Prevent self-transfer
|
||||
if (senderSession.UserId == targetSession.UserId)
|
||||
{
|
||||
shell.WriteError("You cannot transfer MonoCoins to yourself.");
|
||||
shell.WriteError("You cannot transfer currency to yourself.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -81,29 +81,22 @@ public sealed class CurrencyTransferCommand : LocalizedCommands
|
||||
try
|
||||
{
|
||||
// Check if sender has enough MonoCoins
|
||||
var senderBalance = await _db.GetMonoCoinsAsync(senderUserId);
|
||||
var senderBalance = await _coins.GetMonoCoinsBalanceAsync(senderUserId);
|
||||
if (senderBalance < amount)
|
||||
{
|
||||
shell.WriteError($"Insufficient MonoCoins. You have {senderBalance} MonoCoins, cannot transfer {amount}.");
|
||||
shell.WriteError($"Insufficient currency. You have ${senderBalance}, cannot transfer ${amount}.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform the transfer (subtract from sender, add to target)
|
||||
var success = await _db.TrySubtractMonoCoinsAsync(senderUserId, amount);
|
||||
if (!success)
|
||||
{
|
||||
shell.WriteError("Transfer failed. Please try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
var newTargetBalance = await _db.AddMonoCoinsAsync(targetUserId, amount);
|
||||
var newSenderBalance = await _db.GetMonoCoinsAsync(senderUserId);
|
||||
var newSenderBalance = await _coins.AddMonoCoinsAsync(senderUserId, -amount);
|
||||
var newTargetBalance = await _coins.AddMonoCoinsAsync(targetUserId, amount);
|
||||
|
||||
// Notify both players
|
||||
shell.WriteLine($"Successfully transferred {amount} MonoCoins to {targetPlayerName}. New balance: {newSenderBalance}");
|
||||
shell.WriteLine($"Successfully transferred ${amount} to {targetPlayerName}. New balance: ${newSenderBalance}");
|
||||
|
||||
// Notify the target player via chat
|
||||
var notificationMessage = $"Received {amount} MonoCoins from {senderSession.Name}. New balance: {newTargetBalance}";
|
||||
var notificationMessage = $"Received ${amount} from {senderSession.Name}. New balance: ${newTargetBalance}";
|
||||
_chatManager.ChatMessageToOne(
|
||||
ChatChannel.Notifications,
|
||||
notificationMessage,
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Database;
|
||||
using Content.Shared._Mono.MonoCoins;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Content.Server._Mono.MonoCoins;
|
||||
|
||||
/// <summary>
|
||||
/// System that handles MonoCoins balance for players.
|
||||
/// </summary>
|
||||
public sealed class MonoCoinsManager
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
|
||||
private readonly ConcurrentDictionary<NetUserId, long> _cachedBalance = new();
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_net.RegisterNetMessage<MsgMonoCoins>();
|
||||
_net.RegisterNetMessage<MsgMonoCoinsRequest>(OnRequestBalance);
|
||||
_net.Connected += OnConnected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles requests for MonoCoins balance from clients.
|
||||
/// </summary>
|
||||
private async void OnRequestBalance(MsgMonoCoinsRequest msg)
|
||||
{
|
||||
SendBalance(msg.MsgChannel);
|
||||
}
|
||||
|
||||
private async void OnConnected(object? sender, NetChannelArgs e)
|
||||
{
|
||||
SendBalance(e.Channel);
|
||||
}
|
||||
|
||||
private async void SendBalance(INetChannel player)
|
||||
{
|
||||
var balance = await GetMonoCoinsBalanceAsync(player.UserId);
|
||||
var msg = new MsgMonoCoins { Coins = balance };
|
||||
_net.ServerSendMessage(msg, player);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MonoCoins balance for a player from the cache or the database.
|
||||
/// </summary>
|
||||
/// <param name="userId">The player's UserId</param>
|
||||
/// <returns>The player's MonoCoins balance, or 0 if not found</returns>
|
||||
public async Task<long> GetMonoCoinsBalanceAsync(NetUserId userId)
|
||||
{
|
||||
long balance = -1;
|
||||
if (!_cachedBalance.TryGetValue(userId, out balance))
|
||||
{
|
||||
balance = await _db.GetMonoCoinsAsync(userId);
|
||||
_cachedBalance[userId] = balance;
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
|
||||
public long? GetMonoCoinsBalance(NetUserId userId)
|
||||
{
|
||||
_cachedBalance.TryGetValue(userId, out var balance);
|
||||
return balance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the MonoCoins balance for a player in the database.
|
||||
/// </summary>
|
||||
/// <param name="userId">The player's UserId</param>
|
||||
/// <param name="balance">The new balance</param>
|
||||
public async Task SetMonoCoinsBalanceAsync(NetUserId userId, long balance)
|
||||
{
|
||||
var wasBalance = await GetMonoCoinsBalanceAsync(userId);
|
||||
_cachedBalance[userId] = Math.Max(0L, balance);
|
||||
if (_player.TryGetSessionById(userId, out var session)) {
|
||||
SendBalance(session.Channel);
|
||||
}
|
||||
await _db.SetMonoCoinsAsync(userId, balance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds MonoCoins to a player's balance in the database.
|
||||
/// </summary>
|
||||
/// <param name="userId">The player's UserId</param>
|
||||
/// <param name="amount">The amount to add</param>
|
||||
/// <returns>The new balance</returns>
|
||||
public async Task<long> AddMonoCoinsAsync(NetUserId userId, long amount)
|
||||
{
|
||||
var wasBalance = await GetMonoCoinsBalanceAsync(userId);
|
||||
_cachedBalance[userId] = Math.Max(0L, _cachedBalance[userId] + amount);
|
||||
if (_player.TryGetSessionById(userId, out var session)) {
|
||||
SendBalance(session.Channel);
|
||||
}
|
||||
return await _db.AddMonoCoinsAsync(userId, amount);
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Database;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.StationRecords;
|
||||
using Content.Server.StationRecords.Systems;
|
||||
using Content.Shared._Mono.MonoCoins;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server._Mono.MonoCoins;
|
||||
|
||||
/// <summary>
|
||||
/// System that handles MonoCoins balance for players.
|
||||
/// </summary>
|
||||
public sealed class MonoCoinsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||
[Dependency] private readonly StationRecordsSystem _stationRecords = default!;
|
||||
|
||||
private const int RoundEndReward = 10;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
// Subscribe to network messages
|
||||
SubscribeNetworkEvent<RequestMonoCoinsBalanceMessage>(OnRequestMonoCoinsBalance);
|
||||
|
||||
// Subscribe to player events
|
||||
SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetached);
|
||||
|
||||
// Subscribe to round end events
|
||||
SubscribeLocalEvent<RoundEndMessageEvent>(OnRoundEnd);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles requests for MonoCoins balance from clients.
|
||||
/// </summary>
|
||||
private async void OnRequestMonoCoinsBalance(RequestMonoCoinsBalanceMessage message, EntitySessionEventArgs args)
|
||||
{
|
||||
var balance = await GetMonoCoinsBalanceAsync(args.SenderSession.UserId);
|
||||
var response = new MonoCoinsBalanceResponseMessage { Balance = balance };
|
||||
RaiseNetworkEvent(response, args.SenderSession.Channel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a player attaches. Database will handle initialization.
|
||||
/// </summary>
|
||||
private void OnPlayerAttached(PlayerAttachedEvent args)
|
||||
{
|
||||
// Database will handle initialization of MonoCoins balance
|
||||
// No action needed here
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a player detaches. Database persists the balance.
|
||||
/// </summary>
|
||||
private void OnPlayerDetached(PlayerDetachedEvent args)
|
||||
{
|
||||
// Database persists the balance automatically
|
||||
// No action needed here
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MonoCoins balance for a player from the database.
|
||||
/// </summary>
|
||||
/// <param name="userId">The player's UserId</param>
|
||||
/// <returns>The player's MonoCoins balance, or 0 if not found</returns>
|
||||
public async Task<int> GetMonoCoinsBalanceAsync(NetUserId userId)
|
||||
{
|
||||
return await _db.GetMonoCoinsAsync(userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the MonoCoins balance for a player in the database.
|
||||
/// </summary>
|
||||
/// <param name="userId">The player's UserId</param>
|
||||
/// <param name="balance">The new balance</param>
|
||||
public async Task SetMonoCoinsBalanceAsync(NetUserId userId, int balance)
|
||||
{
|
||||
await _db.SetMonoCoinsAsync(userId, balance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds MonoCoins to a player's balance in the database.
|
||||
/// </summary>
|
||||
/// <param name="userId">The player's UserId</param>
|
||||
/// <param name="amount">The amount to add</param>
|
||||
/// <returns>The new balance</returns>
|
||||
public async Task<int> AddMonoCoinsAsync(NetUserId userId, int amount)
|
||||
{
|
||||
return await _db.AddMonoCoinsAsync(userId, amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to subtract MonoCoins from a player's balance in the database.
|
||||
/// </summary>
|
||||
/// <param name="userId">The player's UserId</param>
|
||||
/// <param name="amount">The amount to subtract</param>
|
||||
/// <returns>True if successful, false if insufficient balance</returns>
|
||||
public async Task<bool> TrySubtractMonoCoinsAsync(NetUserId userId, int amount)
|
||||
{
|
||||
return await _db.TrySubtractMonoCoinsAsync(userId, amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a round ends. Awards MonoCoins to players who appear in the station manifest.
|
||||
/// </summary>
|
||||
private async void OnRoundEnd(RoundEndMessageEvent args)
|
||||
{
|
||||
// Award MonoCoins to players who appear in the station manifest
|
||||
var tasks = new List<Task>();
|
||||
|
||||
foreach (var session in _playerManager.Sessions)
|
||||
{
|
||||
// Check if the player appears in any station manifest
|
||||
if (PlayerInManifest(session))
|
||||
{
|
||||
tasks.Add(AwardRoundEndMonoCoins(session));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Debug($"Player {session.Name} ({session.UserId}) not found in station manifest, skipping MonoCoins reward");
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for all database operations to complete
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a player appears in any station manifest by looking for their station record.
|
||||
/// </summary>
|
||||
/// <param name="session">The player session to check</param>
|
||||
/// <returns>True if the player appears in a station manifest, false otherwise</returns>
|
||||
private bool PlayerInManifest(ICommonSession session)
|
||||
{
|
||||
// Get all stations
|
||||
var stations = _stationSystem.GetStations();
|
||||
|
||||
foreach (var station in stations)
|
||||
{
|
||||
// Check if this station has records
|
||||
if (!TryComp<StationRecordsComponent>(station, out var stationRecords))
|
||||
continue;
|
||||
|
||||
// Look for a general station record with the player's character name
|
||||
var records = _stationRecords.GetRecordsOfType<GeneralStationRecord>(station);
|
||||
|
||||
foreach (var (_, record) in records)
|
||||
{
|
||||
// Check if the record name matches the player's character name
|
||||
if (session.AttachedEntity != null &&
|
||||
TryComp<MetaDataComponent>(session.AttachedEntity.Value, out var metaData) &&
|
||||
record.Name.Equals(metaData.EntityName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Awards round end MonoCoins to a specific player.
|
||||
/// </summary>
|
||||
private async Task AwardRoundEndMonoCoins(ICommonSession session)
|
||||
{
|
||||
try
|
||||
{
|
||||
var newBalance = await _db.AddMonoCoinsAsync(session.UserId, RoundEndReward);
|
||||
Logger.Info($"Awarded {RoundEndReward} MonoCoins to player {session.Name} ({session.UserId}). New balance: {newBalance}");
|
||||
|
||||
// Notify the player via chat
|
||||
var notificationMessage = $"Round ended! You earned {RoundEndReward} MonoCoins. Your new balance: {newBalance}";
|
||||
_chatManager.ChatMessageToOne(
|
||||
ChatChannel.Notifications,
|
||||
notificationMessage,
|
||||
notificationMessage,
|
||||
EntityUid.Invalid,
|
||||
false,
|
||||
session.Channel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"Failed to award round end MonoCoins to player {session.Name} ({session.UserId}): {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
* Copyright (c) 2024 New Frontiers Contributors
|
||||
* See AGPLv3.txt for details.
|
||||
*/
|
||||
using Content.Server._Mono.MonoCoins;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Stack;
|
||||
using Content.Shared._NF.Bank.BUI;
|
||||
@@ -45,45 +46,49 @@ public sealed partial class BankSystem
|
||||
|
||||
private void OnWithdraw(EntityUid uid, BankATMComponent component, BankWithdrawMessage args)
|
||||
{
|
||||
|
||||
if (args.Actor is not { Valid : true } player)
|
||||
return;
|
||||
|
||||
// to keep the window stateful
|
||||
GetInsertedCashAmount(component, out var deposit);
|
||||
|
||||
var state = new BankATMMenuInterfaceState(0, 0, false, deposit);
|
||||
|
||||
// check for a bank account
|
||||
if (!TryComp<BankAccountComponent>(player, out var bank))
|
||||
{
|
||||
_log.Info($"{player} has no bank account");
|
||||
ConsolePopup(player, Loc.GetString("bank-atm-menu-no-bank"));
|
||||
PlayDenySound(uid, component);
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(0, false, deposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
GetTaxedDepositAmount(deposit, bank.Balance, out var taxedDeposit); // Mono
|
||||
|
||||
state.Balance = bank.Balance;
|
||||
state.Savings = GetEntSavings(player);
|
||||
|
||||
// check for sufficient funds
|
||||
if (bank.Balance < args.Amount)
|
||||
{
|
||||
ConsolePopup(args.Actor, Loc.GetString("bank-insufficient-funds"));
|
||||
PlayDenySound(uid, component);
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(bank.Balance, true, taxedDeposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.Enabled = true;
|
||||
|
||||
// try to actually withdraw from the bank. Validation happens on the banking system but we still indicate error.
|
||||
if (!TryBankWithdraw(player, args.Amount))
|
||||
{
|
||||
ConsolePopup(args.Actor, Loc.GetString("bank-atm-menu-transaction-denied"));
|
||||
PlayDenySound(uid, component);
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(bank.Balance, true, taxedDeposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.Balance = bank.Balance;
|
||||
|
||||
ConsolePopup(args.Actor, Loc.GetString("bank-atm-menu-withdraw-successful"));
|
||||
PlayConfirmSound(uid, component);
|
||||
_adminLogger.Add(LogType.ATMUsage, LogImpact.Low, $"{ToPrettyString(player):actor} withdrew {args.Amount} from {ToPrettyString(component.Owner)}");
|
||||
@@ -92,8 +97,7 @@ public sealed partial class BankSystem
|
||||
var stackPrototype = _prototypeManager.Index<StackPrototype>(component.CashType);
|
||||
_stackSystem.Spawn(args.Amount, stackPrototype, uid.ToCoordinates());
|
||||
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(bank.Balance, true, taxedDeposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
}
|
||||
|
||||
private void OnDeposit(EntityUid uid, BankATMComponent component, BankDepositMessage args)
|
||||
@@ -105,17 +109,21 @@ public sealed partial class BankSystem
|
||||
// Dynamically knows what kind of cash to look for according to BankATMComponent
|
||||
GetInsertedCashAmount(component, out var deposit);
|
||||
|
||||
var state = new BankATMMenuInterfaceState(0, 0, false, deposit);
|
||||
|
||||
// make sure the user actually has a bank
|
||||
if (!TryComp<BankAccountComponent>(player, out var bank))
|
||||
{
|
||||
_log.Info($"{player} has no bank account");
|
||||
ConsolePopup(args.Actor, Loc.GetString("bank-atm-menu-no-bank"));
|
||||
PlayDenySound(uid, component);
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(0, false, deposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
GetTaxedDepositAmount(deposit, bank.Balance, out var taxedDeposit); // Mono
|
||||
|
||||
state.Balance = bank.Balance;
|
||||
if (_playerManager.TryGetSessionByEntity(player, out var session))
|
||||
state.Savings = _coins.GetMonoCoinsBalance(session.UserId) ?? 0;
|
||||
|
||||
// validating the cash slot was setup correctly in the yaml
|
||||
if (component.CashSlot.ContainerSlot is not BaseContainer cashSlot)
|
||||
@@ -123,8 +131,7 @@ public sealed partial class BankSystem
|
||||
_log.Info($"ATM has no cash slot");
|
||||
ConsolePopup(args.Actor, Loc.GetString("bank-atm-menu-no-bank"));
|
||||
PlayDenySound(uid, component);
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(0, false, taxedDeposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,8 +142,7 @@ public sealed partial class BankSystem
|
||||
_log.Info($"ATM cash slot contains bad stack prototype");
|
||||
ConsolePopup(args.Actor, Loc.GetString("bank-atm-menu-wrong-cash"));
|
||||
PlayDenySound(uid, component);
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(0, false, taxedDeposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -146,8 +152,7 @@ public sealed partial class BankSystem
|
||||
_log.Info($"{stackComponent.StackTypeId} is not {component.CashType}");
|
||||
ConsolePopup(args.Actor, Loc.GetString("bank-atm-menu-wrong-cash"));
|
||||
PlayDenySound(uid, component);
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(0, false, taxedDeposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -161,13 +166,14 @@ public sealed partial class BankSystem
|
||||
deposit -= tax; // Charge the user whether or not the deposit went through.
|
||||
}
|
||||
|
||||
state.Enabled = true;
|
||||
|
||||
// try to deposit the inserted cash into a player's bank acount. Validation happens on the banking system but we still indicate error.
|
||||
if (!TryBankDeposit(player, taxedDeposit))
|
||||
if (!TryBankDeposit(player, deposit))
|
||||
{
|
||||
ConsolePopup(args.Actor, Loc.GetString("bank-atm-menu-transaction-denied"));
|
||||
PlayDenySound(uid, component);
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(bank.Balance, true, taxedDeposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -175,10 +181,14 @@ public sealed partial class BankSystem
|
||||
PlayConfirmSound(uid, component);
|
||||
_adminLogger.Add(LogType.ATMUsage, LogImpact.Low, $"{ToPrettyString(player):actor} deposited {deposit} into {ToPrettyString(component.Owner)}");
|
||||
|
||||
state.Deposit = 0;
|
||||
state.Balance = bank.Balance;
|
||||
if (session != null)
|
||||
state.Savings = _coins.GetMonoCoinsBalance(session.UserId) ?? 0;
|
||||
|
||||
// yeet and delete the stack in the cash slot after success
|
||||
_containerSystem.CleanContainer(cashSlot);
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(bank.Balance, true, 0, 0)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -197,15 +207,16 @@ public sealed partial class BankSystem
|
||||
|
||||
if (!TryComp<BankAccountComponent>(player, out var bank))
|
||||
continue;
|
||||
GetTaxedDepositAmount(deposit, bank.Balance, out var taxedDeposit); // Mono
|
||||
|
||||
BankATMMenuInterfaceState newState;
|
||||
var state = new BankATMMenuInterfaceState(bank.Balance, 0, true, deposit);
|
||||
state.Savings = GetEntSavings(player);
|
||||
|
||||
if (component.CashSlot.ContainerSlot?.ContainedEntity is not { Valid : true } cash)
|
||||
newState = new BankATMMenuInterfaceState(bank.Balance, true, 0, 0); // Mono
|
||||
state.Deposit = 0;
|
||||
else
|
||||
newState = new BankATMMenuInterfaceState(bank.Balance, true, taxedDeposit, deposit); // Mono
|
||||
state.Deposit = deposit;
|
||||
|
||||
_uiSystem.SetUiState(uid, uiComp.Key, newState);
|
||||
_uiSystem.SetUiState(uid, uiComp.Key, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,18 +229,20 @@ public sealed partial class BankSystem
|
||||
|
||||
GetInsertedCashAmount(component, out var deposit);
|
||||
|
||||
var state = new BankATMMenuInterfaceState(0, 0, false, deposit);
|
||||
|
||||
if (!TryComp<BankAccountComponent>(player, out var bank))
|
||||
{
|
||||
_log.Info($"{player} has no bank account");
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(0, false, deposit, deposit)); // Mono
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
return;
|
||||
}
|
||||
|
||||
GetTaxedDepositAmount(deposit, bank.Balance, out var taxedDeposit); // Mono
|
||||
state.Balance = bank.Balance;
|
||||
state.Savings = GetEntSavings(player);
|
||||
|
||||
_uiSystem.SetUiState(uid, args.UiKey,
|
||||
new BankATMMenuInterfaceState(bank.Balance, true, taxedDeposit, deposit)); // Mono
|
||||
state.Enabled = true;
|
||||
_uiSystem.SetUiState(uid, args.UiKey, state);
|
||||
}
|
||||
|
||||
private void GetInsertedCashAmount(BankATMComponent component, out int amount)
|
||||
@@ -253,30 +266,6 @@ public sealed partial class BankSystem
|
||||
return;
|
||||
}
|
||||
|
||||
// Mono start
|
||||
public void GetTaxedDepositAmount(int deposit, int balance, out int amount)
|
||||
{
|
||||
double threshold = _cfg.GetCVar(MonoCVars.DepositThreshold); // Default is 1000000
|
||||
double high_exp = _cfg.GetCVar(MonoCVars.DepositHighExp); // Default is 2
|
||||
|
||||
double deposit_low = Math.Max(Math.Min(deposit, threshold - balance), 0);
|
||||
double deposit_high = Math.Max(0, deposit + Math.Min(balance - threshold, 0));
|
||||
double bank_high = Math.Max(balance, threshold);
|
||||
double adj_exp = high_exp + 1f;
|
||||
var taxedDeposit = 0;
|
||||
if (deposit >= 1)
|
||||
{
|
||||
taxedDeposit = (int)Math.Round(deposit_low + Math.Pow(Math.Pow(bank_high, adj_exp) + deposit_high * adj_exp * Math.Pow(threshold, high_exp), 1f / adj_exp) - bank_high);
|
||||
}
|
||||
else
|
||||
{
|
||||
taxedDeposit = 0;
|
||||
}
|
||||
amount = taxedDeposit;
|
||||
return;
|
||||
}
|
||||
// Mono end
|
||||
|
||||
private void PlayDenySound(EntityUid uid, BankATMComponent component)
|
||||
{
|
||||
_audio.PlayPvs(_audio.GetSound(component.ErrorSound), uid);
|
||||
@@ -292,4 +281,11 @@ public sealed partial class BankSystem
|
||||
if (actor is { Valid: true } player)
|
||||
_popup.PopupEntity(text, player);
|
||||
}
|
||||
|
||||
private long GetEntSavings(EntityUid uid)
|
||||
{
|
||||
if (_playerManager.TryGetSessionByEntity(uid, out var session))
|
||||
return _coins.GetMonoCoinsBalance(session.UserId) ?? 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Threading;
|
||||
using Content.Server._Mono.MonoCoins;
|
||||
using Content.Server.Database;
|
||||
using Content.Server.Preferences.Managers;
|
||||
using Content.Server.GameTicking;
|
||||
@@ -21,6 +22,7 @@ public sealed partial class BankSystem : SharedBankSystem
|
||||
[Dependency] private readonly IServerPreferencesManager _prefsManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly MonoCoinsManager _coins = default!;
|
||||
|
||||
private ISawmill _log = default!;
|
||||
|
||||
@@ -115,7 +117,7 @@ public sealed partial class BankSystem : SharedBankSystem
|
||||
/// <param name="mobUid">The UID that the bank account is connected to, typically the player controlled mob</param>
|
||||
/// <param name="amount">The amount of spesos to remove from the bank account</param>
|
||||
/// <returns>true if the transaction was successful, false if it was not</returns>
|
||||
public bool TryBankDeposit(EntityUid mobUid, int amount)
|
||||
public bool TryBankDeposit(EntityUid mobUid, int amount, bool tax = true)
|
||||
{
|
||||
// Mono start
|
||||
if (!_cfg.GetCVar(MonoCVars.DepositEnabled))
|
||||
@@ -154,11 +156,21 @@ public sealed partial class BankSystem : SharedBankSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TryBankDeposit(session, prefs, profile, amount, out var newBalance))
|
||||
int toSector = amount;
|
||||
int toLongTerm = 0;
|
||||
if (tax)
|
||||
{
|
||||
GetTaxedDepositAmount(amount, bank.Balance, out var afterTax, out var taxedAway);
|
||||
toSector = afterTax;
|
||||
toLongTerm = taxedAway;
|
||||
_ = _coins.AddMonoCoinsAsync(session.UserId, taxedAway);
|
||||
}
|
||||
|
||||
if (TryBankDeposit(session, prefs, profile, toSector, out var newBalance))
|
||||
{
|
||||
bank.Balance = newBalance.Value;
|
||||
Dirty(mobUid, bank);
|
||||
_log.Info($"{mobUid} deposited {amount}");
|
||||
_log.Info($"{mobUid} deposited {amount} (sector: {toSector}, savings: {toLongTerm})");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -174,8 +186,9 @@ public sealed partial class BankSystem : SharedBankSystem
|
||||
/// <param name="profile">The profile of the character whose account is being withdrawn.</param>
|
||||
/// <param name="amount">The number of spesos to be withdrawn.</param>
|
||||
/// <param name="newBalance">The new value of the bank account.</param>
|
||||
/// <param name="spendLongTerm">Whether to also, and preferentially, spend long-term currency.</param>
|
||||
/// <returns>true if the transaction was successful, false if it was not. When successful, newBalance contains the character's new balance.</returns>
|
||||
public bool TryBankWithdraw(ICommonSession session, PlayerPreferences prefs, HumanoidCharacterProfile profile, int amount, [NotNullWhen(true)] out int? newBalance)
|
||||
public bool TryBankWithdraw(ICommonSession session, PlayerPreferences prefs, HumanoidCharacterProfile profile, int amount, [NotNullWhen(true)] out int? newBalance, bool spendLongTerm = false)
|
||||
{
|
||||
newBalance = null; // Default return
|
||||
if (amount <= 0)
|
||||
@@ -185,14 +198,29 @@ public sealed partial class BankSystem : SharedBankSystem
|
||||
}
|
||||
|
||||
int balance = profile.BankBalance;
|
||||
long totalBalance = balance;
|
||||
|
||||
if (balance < amount)
|
||||
if (spendLongTerm)
|
||||
{
|
||||
var longTermBank = _coins.GetMonoCoinsBalance(session.UserId);
|
||||
totalBalance += longTermBank ?? 0l;
|
||||
}
|
||||
|
||||
if (totalBalance < amount)
|
||||
{
|
||||
_log.Info($"TryBankWithdraw: {session.UserId} tried to withdraw {amount}, but has insufficient funds ({balance})");
|
||||
return false;
|
||||
}
|
||||
|
||||
balance -= amount;
|
||||
int leftoverAmount = amount;
|
||||
if (spendLongTerm)
|
||||
{
|
||||
var longTermBalance = totalBalance - balance;
|
||||
var toSpend = (int)Math.Min(longTermBalance, (long)leftoverAmount);
|
||||
leftoverAmount -= toSpend;
|
||||
_ = _coins.AddMonoCoinsAsync(session.UserId, -toSpend);
|
||||
}
|
||||
balance -= leftoverAmount;
|
||||
|
||||
var newProfile = profile.WithBankBalance(balance);
|
||||
var index = prefs.IndexOfCharacter(profile);
|
||||
|
||||
@@ -136,7 +136,7 @@ public sealed class BankCommand : IConsoleCommand
|
||||
// Player is in-game with entity that has bank account - use entity methods which will update the profile
|
||||
if (amount > 0)
|
||||
{
|
||||
success = bankSystem.TryBankDeposit(playerEntity.Value, amount);
|
||||
success = bankSystem.TryBankDeposit(playerEntity.Value, amount, false);
|
||||
if (success)
|
||||
{
|
||||
// Get updated balance after deposit
|
||||
|
||||
@@ -385,7 +385,7 @@ public sealed partial class ShipyardSystem : SharedShipyardSystem
|
||||
sellValue = (int)_pricing.AppraiseGrid((EntityUid)(deed?.ShuttleUid!), LacksPreserveOnSaleComp);
|
||||
|
||||
// Adjust for taxes
|
||||
sellValue = CalculateShipResaleValue((shipyardConsoleUid, component), sellValue, bank.Balance); // Mono - bank.Balance added
|
||||
sellValue = CalculateShipResaleValue((shipyardConsoleUid, component), sellValue);
|
||||
}
|
||||
|
||||
SendPurchaseMessage(shipyardConsoleUid, player, name, component.ShipyardChannel, secret: false);
|
||||
@@ -514,7 +514,7 @@ public sealed partial class ShipyardSystem : SharedShipyardSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var saleResult = TrySellShuttle(stationUid, shuttleUid, uid, bank.Balance, out var bill);
|
||||
var saleResult = TrySellShuttle(stationUid, shuttleUid, uid, out var bill);
|
||||
if (saleResult.Error != ShipyardSaleError.Success)
|
||||
{
|
||||
switch (saleResult.Error)
|
||||
@@ -630,7 +630,7 @@ public sealed partial class ShipyardSystem : SharedShipyardSystem
|
||||
if (deed?.ShuttleUid != null)
|
||||
{
|
||||
sellValue = (int)_pricing.AppraiseGrid((EntityUid)(deed?.ShuttleUid!), LacksPreserveOnSaleComp);
|
||||
sellValue = CalculateShipResaleValue((uid, component), sellValue, bank.Balance); // Mono - bank.Balance added
|
||||
sellValue = CalculateShipResaleValue((uid, component), sellValue);
|
||||
}
|
||||
|
||||
var fullName = deed != null ? GetFullName(deed) : null;
|
||||
@@ -730,7 +730,7 @@ public sealed partial class ShipyardSystem : SharedShipyardSystem
|
||||
if (deed?.ShuttleUid != null)
|
||||
{
|
||||
sellValue = (int)_pricing.AppraiseGrid(deed.ShuttleUid.Value, LacksPreserveOnSaleComp);
|
||||
sellValue = CalculateShipResaleValue((uid, component), sellValue, bank.Balance); // Mono - bank.Balance added
|
||||
sellValue = CalculateShipResaleValue((uid, component), sellValue);
|
||||
}
|
||||
|
||||
var fullName = deed != null ? GetFullName(deed) : null;
|
||||
@@ -982,7 +982,7 @@ public sealed partial class ShipyardSystem : SharedShipyardSystem
|
||||
return _baseSaleRate * taxRate;
|
||||
}
|
||||
|
||||
private int CalculateShipResaleValue(Entity<ShipyardConsoleComponent?> console, int baseAppraisal, int playerBalance) // Mono - playerBalance int
|
||||
private int CalculateShipResaleValue(Entity<ShipyardConsoleComponent?> console, int baseAppraisal)
|
||||
{
|
||||
if (!Resolve(console, ref console.Comp))
|
||||
return 0;
|
||||
@@ -991,8 +991,7 @@ public sealed partial class ShipyardSystem : SharedShipyardSystem
|
||||
if (!console.Comp.IgnoreBaseSaleRate)
|
||||
resaleValue = (int)(_baseSaleRate * resaleValue);
|
||||
var unBalanceTaxedResaleValue = resaleValue - CalculateTotalSalesTax(console.Comp, resaleValue);
|
||||
_bank.GetTaxedDepositAmount(unBalanceTaxedResaleValue, playerBalance, out var taxedOutput);
|
||||
return taxedOutput;
|
||||
return unBalanceTaxedResaleValue;
|
||||
}
|
||||
|
||||
// Calculates total sales tax over all accounts.
|
||||
|
||||
@@ -188,7 +188,7 @@ public sealed partial class ShipyardSystem : SharedShipyardSystem
|
||||
/// <param name="stationUid">The ID of the station that the shuttle is docked to</param>
|
||||
/// <param name="shuttleUid">The grid ID of the shuttle to be appraised and sold</param>
|
||||
/// <param name="consoleUid">The ID of the console being used to sell the ship</param>
|
||||
public ShipyardSaleResult TrySellShuttle(EntityUid stationUid, EntityUid shuttleUid, EntityUid consoleUid, int playerBalance, out int bill) // Mono - int playerBalance
|
||||
public ShipyardSaleResult TrySellShuttle(EntityUid stationUid, EntityUid shuttleUid, EntityUid consoleUid, out int bill)
|
||||
{
|
||||
ShipyardSaleResult result = new ShipyardSaleResult();
|
||||
bill = 0;
|
||||
@@ -259,11 +259,7 @@ public sealed partial class ShipyardSystem : SharedShipyardSystem
|
||||
CleanGrid(shuttleUid, consoleUid);
|
||||
}
|
||||
|
||||
// Mono start
|
||||
var untaxedInput = (int)_pricing.AppraiseGrid(shuttleUid, LacksPreserveOnSaleComp);
|
||||
_bank.GetTaxedDepositAmount(untaxedInput, playerBalance, out var taxedOutput);
|
||||
bill = taxedOutput;
|
||||
// Mono end
|
||||
bill = (int)_pricing.AppraiseGrid(shuttleUid, LacksPreserveOnSaleComp);
|
||||
|
||||
QueueDel(shuttleUid);
|
||||
_sawmill.Info($"Sold shuttle {shuttleUid} for {bill}");
|
||||
|
||||
@@ -1,20 +1,38 @@
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Content.Shared._Mono.MonoCoins;
|
||||
|
||||
/// <summary>
|
||||
/// Message sent by client to request their MonoCoins balance.
|
||||
/// Sent from the server to client to message updated MonoCoins balance.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RequestMonoCoinsBalanceMessage : EntityEventArgs
|
||||
public sealed class MsgMonoCoins : NetMessage
|
||||
{
|
||||
public override MsgGroups MsgGroup => MsgGroups.EntityEvent;
|
||||
|
||||
public long Coins;
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
Coins = buffer.ReadVariableInt64();
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
buffer.WriteVariableInt64(Coins);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Message sent by server in response to MonoCoins balance request.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class MonoCoinsBalanceResponseMessage : EntityEventArgs
|
||||
public sealed class MsgMonoCoinsRequest : NetMessage
|
||||
{
|
||||
public int Balance { get; set; }
|
||||
public override MsgGroups MsgGroup => MsgGroups.EntityEvent;
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@ public sealed class BankATMMenuInterfaceState : BoundUserInterfaceState
|
||||
/// </summary>
|
||||
public int Balance;
|
||||
|
||||
/// <summary>
|
||||
/// Savings of the player using the ATM.
|
||||
/// </summary>
|
||||
public long Savings;
|
||||
|
||||
/// <summary>
|
||||
/// are the buttons enabled
|
||||
/// </summary>
|
||||
@@ -20,16 +25,11 @@ public sealed class BankATMMenuInterfaceState : BoundUserInterfaceState
|
||||
/// </summary>
|
||||
public int Deposit;
|
||||
|
||||
/// <summary>
|
||||
/// how much cash is inserted - without tax calculations - Mono change
|
||||
/// </summary>
|
||||
public int DepositUntaxed;
|
||||
|
||||
public BankATMMenuInterfaceState(int balance, bool enabled, int deposit, int depositUntaxed)
|
||||
public BankATMMenuInterfaceState(int balance, long savings, bool enabled, int deposit)
|
||||
{
|
||||
Balance = balance;
|
||||
Savings = savings;
|
||||
Enabled = enabled;
|
||||
Deposit = deposit;
|
||||
DepositUntaxed = depositUntaxed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public static class BankSystemExtensions
|
||||
/// <param name="symbolOverride">Optionally override the symbol</param>
|
||||
/// <param name="separatorOverride">Optionally override the separator</param>
|
||||
/// <returns></returns>
|
||||
public static string ToCurrencyString(int amount, CultureInfo? culture = null, string? symbolOverride = null, string? separatorOverride = null, CurrencySymbolLocation symbolLocation = CurrencySymbolLocation.Default)
|
||||
public static string ToCurrencyString(long amount, CultureInfo? culture = null, string? symbolOverride = null, string? separatorOverride = null, CurrencySymbolLocation symbolLocation = CurrencySymbolLocation.Default)
|
||||
{
|
||||
culture ??= CultureInfo.CurrentCulture;
|
||||
var numberFormat = (NumberFormatInfo) culture.NumberFormat.Clone();
|
||||
@@ -57,24 +57,23 @@ public static class BankSystemExtensions
|
||||
}
|
||||
|
||||
// Convenience methods for specific currencies.
|
||||
public static string ToIndependentString(int amount, CultureInfo? culture = null)
|
||||
public static string ToIndependentString(long amount, CultureInfo? culture = null)
|
||||
{
|
||||
return ToCurrencyString(amount, culture, symbolOverride: "", symbolLocation: CurrencySymbolLocation.Prefix); //Prefix results in no space, prefer that.
|
||||
}
|
||||
|
||||
public static string ToSpesoString(int amount, CultureInfo? culture = null)
|
||||
public static string ToSpesoString(long amount, CultureInfo? culture = null)
|
||||
{
|
||||
return ToCurrencyString(amount, culture, symbolOverride: "$", symbolLocation: CurrencySymbolLocation.Prefix);
|
||||
}
|
||||
|
||||
public static string ToDoubloonString(int amount, CultureInfo? culture = null)
|
||||
public static string ToDoubloonString(long amount, CultureInfo? culture = null)
|
||||
{
|
||||
return ToCurrencyString(amount, culture, symbolOverride: "DB", symbolLocation: CurrencySymbolLocation.Suffix);
|
||||
}
|
||||
|
||||
public static string ToFMCString(int amount, CultureInfo? culture = null)
|
||||
public static string ToFMCString(long amount, CultureInfo? culture = null)
|
||||
{
|
||||
return ToCurrencyString(amount, culture, symbolOverride: "FMC", symbolLocation: CurrencySymbolLocation.Suffix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Content.Shared._NF.Bank.Components;
|
||||
using Content.Shared._Mono.CCVar;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
@@ -14,6 +16,7 @@ public enum BankATMMenuUiKey : byte
|
||||
|
||||
public abstract partial class SharedBankSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -44,5 +47,28 @@ public abstract partial class SharedBankSystem : EntitySystem
|
||||
{
|
||||
_itemSlotsSystem.RemoveItemSlot(uid, component.CashSlot);
|
||||
}
|
||||
|
||||
public void GetTaxedDepositAmount(int deposit, int balance, out int amount, out int taxedAway)
|
||||
{
|
||||
double threshold = _cfg.GetCVar(MonoCVars.DepositThreshold); // Default is 1000000
|
||||
double high_exp = _cfg.GetCVar(MonoCVars.DepositHighExp); // Default is 2
|
||||
|
||||
double deposit_low = Math.Max(Math.Min(deposit, threshold - balance), 0);
|
||||
double deposit_high = Math.Max(0, deposit + Math.Min(balance - threshold, 0));
|
||||
double bank_high = Math.Max(balance, threshold);
|
||||
double adj_exp = high_exp + 1f;
|
||||
var taxedDeposit = 0;
|
||||
if (deposit >= 1)
|
||||
{
|
||||
taxedDeposit = (int)Math.Round(deposit_low + Math.Pow(Math.Pow(bank_high, adj_exp) + deposit_high * adj_exp * Math.Pow(threshold, high_exp), 1f / adj_exp) - bank_high);
|
||||
}
|
||||
else
|
||||
{
|
||||
taxedDeposit = 0;
|
||||
}
|
||||
amount = taxedDeposit;
|
||||
taxedAway = deposit - amount;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
server-currency-loading = Loading account savings..
|
||||
server-currency-text = Account savings: ${$balance}
|
||||
@@ -1,9 +1,9 @@
|
||||
## UI
|
||||
adventure-list-start = [color=gold]TSF Central Bank[/color]
|
||||
adventure-list-start = [color=gold]Colossus Central Bank[/color]
|
||||
adventure-list-profit = made a total profit of [color=#d19e5e]{$amount}[/color].
|
||||
adventure-list-loss = lost a total of [color=#659cc9]{$amount}[/color].
|
||||
|
||||
adventure-webhook-list-start = TSF Central Bank
|
||||
adventure-webhook-list-start = Colossus Central Bank
|
||||
adventure-webhook-list-high = This Shift's Top Earners:
|
||||
adventure-webhook-list-low = This Shift's Biggest Spenders:
|
||||
adventure-webhook-list-no-entries = No entries found.
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
## UI
|
||||
bank-atm-menu-title = TSF Central Bank
|
||||
bank-atm-menu-title = Colossus Central Bank
|
||||
bank-atm-menu-balance-label = Balance:{" "}
|
||||
bank-atm-menu-savings-label = Savings:{" "}
|
||||
bank-atm-menu-no-bank = No Bank Account!
|
||||
bank-atm-menu-withdraw-button = Withdraw
|
||||
bank-atm-menu-deposit-label = Deposit (Taxed):{" "}
|
||||
bank-atm-menu-deposit-label-ut = Deposit (Untaxed):{" "}
|
||||
bank-atm-menu-deposit-label = Deposit (Sector):{" "}
|
||||
bank-atm-menu-deposit-label-ut = Deposit (Savings):{" "}
|
||||
bank-atm-menu-amount-label = Withdraw:{" "}
|
||||
bank-atm-menu-no-deposit = Empty
|
||||
bank-atm-menu-deposit-button = Deposit
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Base entries
|
||||
guide-entry-nf14 = Frontier Guide
|
||||
guide-entry-bank = TSF Central Bank
|
||||
guide-entry-bank = Colossus Central Bank
|
||||
guide-entry-piloting = Piloting
|
||||
guide-entry-startinggear = Starting Equipment
|
||||
guide-entry-hiring = Hiring Crew
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
frontier-loadout-cost = Total Loadout Cost: {$cost}
|
||||
frontier-loadout-balance = Available Balance: {$balance}
|
||||
frontier-loadout-balance = Available Balance: {$savings} + {$balance}
|
||||
|
||||
Reference in New Issue
Block a user