Change Tax Into Savings (#4021)

This commit is contained in:
Ilya246
2026-05-19 20:21:40 +04:00
committed by GitHub
parent 2617d0b067
commit 47d92fd030
42 changed files with 4785 additions and 577 deletions
+4 -1
View File
@@ -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);
+2
View File
@@ -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
}
}
}
+4 -4
View File
@@ -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)
@@ -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 -1
View File
@@ -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;
+85 -70
View File
@@ -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>
+15 -4
View File
@@ -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
{
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")
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")
+1 -1
View File
@@ -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();
}
+6 -23
View File
@@ -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
+6 -13
View File
@@ -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();
+2
View File
@@ -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;
+2
View File
@@ -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}");
}
}
}
+54 -58
View File
@@ -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;
}
}
+34 -6
View File
@@ -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);
+1 -1
View File
@@ -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}