Spending/Bank.cs
using System;
using System.Text.Json.Nodes;
namespace PlanetMeat;
public sealed class Bank : GameObjectSystem<Bank>
{
const double MAX_CAPACITY = 1E250;
public class Account : ISaveTarget
{
private double Amount
{
get;
set
{
field = value;
_roundedAmount = Math.Round( value );
}
} = 0.0;
private double _roundedAmount = 0.0;
public double Funds => HasCap ? double.Min( _roundedAmount, Capacity ) : _roundedAmount;
public string BountyImprovementIdent { get; set; } = "";
public ValueAggregator<float> AggregateBounty => field ??= ValueAggregator<float>.FromImprovement( BountyImprovementIdent );
private double _capacity = 1000;
public double CapacityModifier { get; set; } = 0;
public double Capacity => double.Min( _capacity + CapacityModifier, MAX_CAPACITY );
public Currency Currency { get; set; } = null;
public bool HasCap => Capacity >= 0;
public bool AtCap => Amount >= Capacity;
public string DisplayText
{
get
{
var amt = LargeNumberString.ToCompact( Funds );
return HasCap ? (amt + "/" + LargeNumberString.ToCompact( Capacity )) : amt;
}
}
public void Clear() => Amount = 0.0;
public int Hash => HashCode.Combine( Amount, Capacity );
public JsonNode NextSave => Amount;
public Account( Currency c, double cap = -1 )
{
Currency = c;
_capacity = cap;
}
public Account( Currency c, double startAmount, double cap )
{
Currency = c;
_capacity = cap;
Amount = startAmount;
}
public double AfterSpending( double cost ) => Amount - cost;
public void Spend( double cost ) => Amount = AfterSpending( cost );
public bool CanAfford( double cost ) => Funds >= cost;
public bool TrySpend( double cost )
{
if ( CanAfford( cost ) )
{
Spend( cost );
return true;
}
return false;
}
public double AfterProfiting( double profit, bool exceedCap = false )
{
if ( HasCap && Amount > Capacity )
return Amount;
return Amount.AddCapped( profit, HasCap && !exceedCap ? Capacity : double.MaxValue );
}
public void Profit( double profit, bool exceedCap = false ) => Amount = AfterProfiting( profit, exceedCap );
public void Bounty( double bounty )
{
if ( AggregateBounty is not null )
Profit( bounty.MultiplyCapped( AggregateBounty.Total ) );
else
Profit( bounty );
}
public void IncreaseCap( double amt )
{
if ( HasCap )
_capacity = _capacity.AddCapped( amt );
}
public void DecreaseCap( double amt )
{
if ( HasCap )
_capacity -= amt;
}
public void LoadFromSave( JsonNode save )
{
Amount = save.GetValue<double>();
}
public void ClearSave()
{
Amount = 0.0;
}
}
private Dictionary<string, Account> Accounts { get; set; } = null;
private Dictionary<string, Dictionary<string, double>> CapacityProviders { get; set; } = [];
public Bank( Scene scene ) : base( scene )
{
Accounts = new()
{
["goop"] = new( ResourceLibrary.Get<Currency>( "bank/goop.bux" ), 0 ) { BountyImprovementIdent = "goop_bounty" },
["meat"] = new( ResourceLibrary.Get<Currency>( "bank/meat.bux" ) ),
};
}
public Account GetAccount( string id ) => Accounts.GetValueOrDefault( id, null );
public bool CanAffordBatch( IDictionary<string, double> costs, double multiplier = 1.0 ) => costs.All( c => GetAccount( c.Key )?.CanAfford( c.Value.MultiplyCapped( multiplier ) ) ?? false );
public void SpendBatch( IDictionary<string, double> costs, double multiplier = 1.0 )
{
foreach ( var (currency, cost) in costs )
GetAccount( currency )?.Spend( cost.MultiplyCapped( multiplier ) );
}
public bool TrySpendBatch( IDictionary<string, double> costs, double multiplier = 1.0 )
{
if ( CanAffordBatch( costs, multiplier ) )
{
SpendBatch( costs, multiplier );
return true;
}
return false;
}
public void ProfitBatch( IDictionary<string, double> payments, double multiplier = 1.0 )
{
foreach ( var (currency, profit) in payments )
GetAccount( currency )?.Profit( profit.MultiplyCapped( multiplier ) );
}
private bool TryGetAccountProvidedAmount( string id, string account, out double provided )
{
provided = 0.0;
return CapacityProviders.TryGetValue( id, out var extantCaps ) && extantCaps.TryGetValue( account, out provided );
}
public double GetCapacityWithout( string id, string account )
{
TryGetAccountProvidedAmount( id, account, out var provided );
return GetAccount( account ).Capacity - provided;
}
public void SetProvidedCapacity( string id, string account, double cap, double multiplier = 1.0 )
{
var bank = GetAccount( account );
if ( TryGetAccountProvidedAmount( id, account, out var extandProvided ) )
bank.CapacityModifier -= extandProvided;
var multed = cap.MultiplyCapped( multiplier );
bank.CapacityModifier += multed;
CapacityProviders.GetOrCreate( id )[account] = multed;
}
private void ClearProvidedCapacity( string id )
{
if ( CapacityProviders.TryGetValue( id, out var extantCaps ) )
{
foreach ( var (currency, provided) in extantCaps )
GetAccount( currency ).CapacityModifier -= provided;
}
CapacityProviders.Remove( id );
}
public void ReplaceProvidedCapacity( string id, Dictionary<string, double> caps, double multiplier = 1.0 )
{
ClearProvidedCapacity( id );
var finalCaps = new Dictionary<string, double>( caps );
foreach ( var (currency, provided) in caps )
{
var multed = provided.MultiplyCapped( multiplier );
finalCaps[currency] = multed;
GetAccount( currency ).CapacityModifier += multed;
}
CapacityProviders[id] = finalCaps;
}
public void RemoveProvidedCapacity( string id )
{
ClearProvidedCapacity( id );
CapacityProviders.Remove( id );
}
}