Spending/Upgrades/BaseUpgrades.cs
using System;
using System.Numerics;
namespace PlanetMeat;
[Group( "Planet Meat - Upgrades" ), Title( "Base Upgrade" ), Icon( "settings_suggest" )]
public abstract class BaseUpgrade : Component, IPurchaseableUpgrade
{
public UpgradeCategory Category => this.FindNearestUpwards<UpgradeCategory>();
public string CategoryIdent => Category?.Ident ?? "";
[Property] public double CostOffset { get; set; } = 1.0;
[Property] public double CostStep { get; set; } = 1.0;
public virtual double NextCost => CostStep * Rank + CostOffset;
public int Rank
{
get;
private set
{
field = value;
OnRankChanged();
}
} = 0;
[Property] public string Ident { get; set; } = "";
[Property] protected virtual string RequiredTech { get; set; } = "";
private bool _needsTechCheck = true;
private bool HasTech
{
get
{
if ( _needsTechCheck )
{
_needsTechCheck = false;
field = Research.Current.HasTech( RequiredTech );
}
return field;
}
}
public virtual bool Visible => HasTech;
public virtual bool Purchaseable => true;
protected override void OnStart()
{
base.OnStart();
OnRankChanged();
}
protected override void OnDestroy()
{
Rank = 0;
base.OnDestroy();
}
public bool TryPurchase()
{
if ( Purchaseable && Bank.Current.GetAccount( "goop" ).TrySpend( NextCost ) )
{
Rank++;
return true;
}
return false;
}
public abstract string GetDisplayedEffectAt( int rank );
public string DisplayedCurrentEffect => GetDisplayedEffectAt( Rank );
public string DisplayedNextEffect => GetDisplayedEffectAt( Rank + 1 );
public string AdvancementText => DisplayedCurrentEffect + " -> " + DisplayedNextEffect;
public string DisplayName => "upgrade." + Ident + ".title";
protected abstract void OnRankChanged();
}
public abstract class BaseEffectUpgrade<T> : BaseUpgrade where T : IAdditionOperators<T, T, T>, IComparable<T>, IConvertible, IMinMaxValue<T>, ISubtractionOperators<T, T, T>
{
[Property] public string ImprovementIdent { get; set; } = "";
protected BaseEffectImprovement<T> ImprovementBasis => Research.Current.GetImprovement( ImprovementIdent ) is BaseEffectImprovement<T> imp ? imp : null;
protected override string RequiredTech
{
get
{
var imp = ImprovementBasis;
return imp is null ? base.RequiredTech : imp.RequiredTech;
}
set => base.RequiredTech = value;
}
protected abstract T EffectBase { get; }
protected abstract T GetEffectAt( int rank );
public T CurrentEffect => GetEffectAt( Rank );
public bool IsIncrease => GetEffectAt( Rank ).CompareTo( GetEffectAt( Rank + 1 ) ) < 0;
public virtual T ImprovementEffect => Research.Current.GetImprovementEffect<T>( ImprovementIdent );
public virtual T EffectMax
{
get
{
var imp = ImprovementBasis;
return imp is null ? default : imp.EffectMax;
}
}
protected virtual T EffectPerRank
{
get
{
var imp = ImprovementBasis;
return imp is null ? default : imp.EffectPerRank;
}
}
public virtual bool HasCap => EffectMax.CompareTo( default ) > 0;
protected virtual bool IsUnderCap => OverallEffect.CompareTo( EffectMax ) < 0;
public override bool Purchaseable => base.Purchaseable && IsIncrease && (!HasCap || IsUnderCap);
protected T OverallEffect => GetOveralEffect( Rank );
protected T GetOveralEffect( int rank ) => EffectBase.AddCapped( GetEffectAt( rank ) );
protected int DecimalPlaces => ImprovementBasis is FloatEffectImprovement p ? p.DecimalPlaces : FloatEffectImprovement.DEFAULT_DECIMAL_PLACES;
public override string GetDisplayedEffectAt( int rank )
{
var effect = GetOveralEffect( rank );
if ( effect is double d )
return LargeNumberString.ToCompact( d );
if ( effect is float f )
return f.ToNString( DecimalPlaces );
return effect.ToString();
}
}
public abstract class BaseComponentUpgrade<C, T> : BaseEffectUpgrade<T> where T : ISubtractionOperators<T, T, T>, IAdditionOperators<T, T, T>, IComparable<T>, IConvertible, IMinMaxValue<T>
{
protected C TargetComponent => field ??= this.FindNearestUpwards<C>();
}
public abstract class BaseAggregateUpgrade<C, T> : BaseComponentUpgrade<C, T> where T : ISubtractionOperators<T, T, T>, IAdditionOperators<T, T, T>, IComparable<T>, IConvertible, IMinMaxValue<T>
{
private ValueAggregator<T> Aggregate => field ??= FindAggregate;
protected abstract ValueAggregator<T> FindAggregate { get; }
protected override T EffectBase
{
get
{
var agg = Aggregate;
return agg is null ? default : agg.Without( this );
}
}
protected override void OnRankChanged()
{
Aggregate?.SetContribution( this, CurrentEffect );
}
}
public abstract class IntAggregateUpgrade<C> : BaseAggregateUpgrade<C, int>
{
protected override int GetEffectAt( int rank ) => EffectPerRank.MultiplyCapped( rank );
}
public abstract class FloatAggregateUpgrade<C> : BaseAggregateUpgrade<C, float>
{
protected override bool IsUnderCap => FloatEffectImprovement.TestCap( OverallEffect, EffectMax );
protected override float GetEffectAt( int rank ) => EffectPerRank.MultiplyCapped( rank );
}
public abstract class DoubleAggregateUpgrade<C> : BaseAggregateUpgrade<C, double>
{
protected override double GetEffectAt( int rank ) => EffectPerRank.MultiplyCapped( rank );
}
public abstract class PercentageAggregateUpgrade<C> : FloatAggregateUpgrade<C>
{
public override string GetDisplayedEffectAt( int rank ) => PercentageEffectImprovement.GetDisplayedPercentage( GetOveralEffect( rank ), DecimalPlaces );
}