InvestmentMenu.cs
using Sandbox;
using Sandbox.UI;
using Sandbox.UI.Construct;
using SWB.Player;
// The investment table's screen. Shows what you're holding, what you've got
// invested and what that pays per job, with one button to put more in.
//
// Follows the same no-Razor PanelComponent pattern as VendorMenu. Put this
// on the same GameObject as the InvestmentTable and assign Table; it
// creates its own ScreenPanel, so no extra editor wiring.
public sealed class InvestmentMenu : PanelComponent
{
[Property]
public InvestmentTable Table { get; set; }
Label _cashLabel;
Label _investedLabel;
Label _returnLabel;
Panel _depositButton;
Label _depositLabel;
bool _wasOpen = false;
protected override void OnStart()
{
Components.GetOrCreate<ScreenPanel>();
Panel.StyleSheet.Load( "/InvestmentMenu.cs.scss" );
var header = Panel.Add.Panel( "header" );
header.Add.Label( "Investments", "title" );
_cashLabel = header.Add.Label( "", "cash" );
// Holding Use again also closes it, but a visible way out matters
// when the cursor is already up and the menu is covering the
// screen - nothing on screen tells you the hold-to-close trick.
var close = header.Add.Label( "✕", "close" );
close.AddEventListener( "onmousedown", () => Table?.Close() );
var body = Panel.Add.Panel( "body" );
body.Add.Label(
"Money left here is safe. It stays put when you go down, and it "
+ "pays out after every job whether you walk away with the take or not.",
"blurb" );
var stats = body.Add.Panel( "stats" );
var investedRow = stats.Add.Panel( "stat" );
investedRow.Add.Label( "Invested", "statLabel" );
_investedLabel = investedRow.Add.Label( "", "statValue" );
var returnRow = stats.Add.Panel( "stat" );
returnRow.Add.Label( "Pays per job", "statLabel" );
_returnLabel = returnRow.Add.Label( "", "statValue" );
_depositButton = body.Add.Panel( "deposit" );
_depositLabel = _depositButton.Add.Label( "", "depositLabel" );
_depositButton.AddEventListener( "onmousedown", () =>
{
// TryInvest refuses and changes nothing when you can't afford
// it, so the result is all there is to check.
if ( LocalLoadout()?.TryInvest() != true )
return;
Refresh();
} );
}
protected override void OnUpdate()
{
if ( Table is null )
return;
Panel.SetClass( "show", Table.IsOpen );
// Release the cursor so the menu can be clicked - see MenuInput for
// why this works on mouse-look rather than on Mouse.Visible.
if ( Table.IsOpen != _wasOpen )
MenuInput.SetMenuOpen( Table.IsOpen );
_wasOpen = Table.IsOpen;
// Cheap enough to just keep current every frame it's visible -
// there are four labels, and it means a payout landing while the
// menu is open shows up immediately.
if ( Table.IsOpen )
Refresh();
}
void Refresh()
{
var loadout = LocalLoadout();
if ( loadout is null )
return;
_cashLabel.Text = $"${loadout.Cash}";
_investedLabel.Text = $"${loadout.Invested}";
_returnLabel.Text = $"${loadout.DividendPerJob}";
_depositLabel.Text = $"Deposit ${loadout.InvestmentIncrement}";
_depositButton.SetClass( "unaffordable", !loadout.CanAfford( loadout.InvestmentIncrement ) );
}
PlayerLoadout LocalLoadout()
{
return PlayerBase.Local?.Components.Get<PlayerLoadout>();
}
}