sa/Stars Assistant/ViewModels/PlayerPlanetViewModel.cs

271 lines
9.6 KiB
C#
Raw Normal View History

2024-09-24 20:32:13 +00:00
using System.Collections.ObjectModel;
using System.Reactive.Disposables;
using System.Reactive.Linq;
2024-09-24 20:32:13 +00:00
using Microsoft.EntityFrameworkCore;
using DynamicData;
2024-09-24 20:32:13 +00:00
using ReactiveUI;
using ReactiveUI.SourceGenerators;
2024-09-24 20:32:13 +00:00
using StarsAssistant.Services;
using Splat;
2024-10-19 18:05:12 +00:00
using StarsAssistant.Model;
2024-09-24 20:32:13 +00:00
namespace StarsAssistant.ViewModels;
public partial class PlayerPlanetViewModel : ViewModelBase
{
private readonly Model.Planet Planet;
2024-10-19 18:05:12 +00:00
private readonly Services.Game Game;
private readonly IObservable<Change<FleetSummaryByDestination, string>> _fleetSummaryChanges;
2024-09-24 20:32:13 +00:00
public PlayerPlanetViewModel(Model.Planet planet)
{
2024-10-19 18:05:12 +00:00
Game = Locator.Current.GetService<Services.Game>()!;
2024-09-24 20:32:13 +00:00
2024-10-19 18:05:12 +00:00
if (planet.OwnerId != Services.Game.Player.Name)
2024-09-24 20:32:13 +00:00
throw new InvalidOperationException("PlayerPlanet ViewModels can only be created for player planets.");
Planet = planet;
PopulationTargetPercent = planet.PopulationTargetPercent;
_populationTargetHelper = this
.WhenAnyValue(vm => vm.PopulationTargetPercent)
.Select(popTgt => this.MaxPopulation * popTgt / 10000 * 100)
.ToProperty(this, vm => vm.PopulationTarget);
2024-09-24 20:32:13 +00:00
2024-09-26 20:18:50 +00:00
_populationToShipHelper = this
.WhenAnyValue(vm => vm.PopulationTarget)
.Select(popToShip => this.ComputePopulationToShip())
.ToProperty(this, vm => vm.PopulationToShip);
_targetFactoriesHelper = this
.WhenAnyValue(vm => vm.PopulationTarget)
.Select(tgtFact => GameEngine.MaxOperableFactoriesForPlayer(_populationTarget, Value))
.ToProperty(this, vm => vm.TargetFactories);
_remainingFactoriesHelper = this
.WhenAnyValue(vm => vm.TargetFactories)
.Select(factRem => Factories < _targetFactories ? _targetFactories - Factories : 0)
.ToProperty(this, vm => vm.RemainingFactories);
_factoryGermaniumDeltaHelper = this
2024-11-17 12:19:22 +00:00
.WhenAnyValue(vm => vm.RemainingFactories,
vm => vm.EnRouteGermanium,
vm => vm.SurfaceGermanium,
(remFact, gerEnRoute, surGer) => remFact)
2024-09-26 20:18:50 +00:00
.Select(gerCost => ComputeFactoryGermaniumDelta())
.ToProperty(this, vm => vm.FactoryGermaniumDelta);
_remainingMinesHelper = this
.WhenAnyValue(vm => vm.PopulationTarget)
.Select(remMines => Math.Max(0, GameEngine.MaxOperableMinesForPlayer(_populationTarget, Value) - Mines))
.ToProperty(this, vm => vm.RemainingMines);
FleetManager fm = Locator.Current.GetService<FleetManager>()!;
2024-10-19 18:05:12 +00:00
_fleetSummaryChanges = fm.FleetSummariesByDestination
.Connect()
.Watch(Name)
.Log(this, "fleetSummaryChange", change => $"{Name}: {change.Reason}: {change.Previous} => {change.Current}")
;
2024-11-17 12:19:22 +00:00
_enRoutePopulationHelper = _fleetSummaryChanges
.Select(change => change.Reason != ChangeReason.Remove ? change.Current.TotalColonists : 0)
2024-11-17 12:19:22 +00:00
.Log(this, "EnRoutePopulation", pop => $"{Name}: {pop}")
.ToProperty(this, vm => vm.EnRoutePopulation)
;
2024-11-17 12:19:22 +00:00
_enRouteIroniumHelper = _fleetSummaryChanges
.Select(change => change.Reason != ChangeReason.Remove ? change.Current.TotalIronium : 0)
.Log(this, "EnRouteIronium", ironium => $"{Name}: {ironium}")
.ToProperty(this, vm => vm.EnRouteIronium)
;
_enRouteBoraniumHelper = _fleetSummaryChanges
.Select(change => change.Reason != ChangeReason.Remove ? change.Current.TotalBoranium : 0)
.Log(this, "EnRouteBoranium", boranium => $"{Name}: {boranium}")
.ToProperty(this, vm => vm.EnRouteBoranium)
;
_enRouteGermaniumHelper = _fleetSummaryChanges
.Select(change => change.Reason != ChangeReason.Remove ? change.Current.TotalGermanium : 0)
.Log(this, "EnRouteGermanium", germanium => $"{Name}: {germanium}")
.ToProperty(this, vm => vm.EnRouteGermanium)
;
2024-09-24 20:32:13 +00:00
this.WhenActivated((CompositeDisposable disposables) =>
{
2024-11-17 12:19:22 +00:00
disposables.Add(_enRoutePopulationHelper);
disposables.Add(_enRouteIroniumHelper);
disposables.Add(_enRouteBoraniumHelper);
disposables.Add(_enRouteGermaniumHelper);
2024-09-24 20:32:13 +00:00
// /* handle activation */
// Disposable
// .Create(() => { /* handle deactivation */ })
// .DisposeWith(disposables);
});
}
#region Database Properties
public string Name => Planet.Name;
public string Owner => Planet.OwnerId;
public string StarbaseType => Planet.StarbaseType;
public int Population => Planet.Population ?? 0;
public int Value => Planet.Value ?? 0;
public int Mines => Planet.Mines ?? 0;
public int Factories => Planet.Factories ?? 0;
public decimal DefPercent => Planet.DefPercent ?? 0;
public int SurfaceIronium => Planet.SurfaceIronium ?? 0;
public int SurfaceBoranium => Planet.SurfaceBoranium ?? 0;
public int SurfaceGermanium => Planet.SurfaceGermanium ?? 0;
public int MRIronium => Planet.MRIronium ?? 0;
public int MRBoranium => Planet.MRBoranium ?? 0;
public int MRGermanium => Planet.MRGermanium ?? 0;
public int MCIronium => Planet.MCIronium ?? 0;
public int MCBoranium => Planet.MCBoranium ?? 0;
public int MCGermanium => Planet.MCGermanium ?? 0;
public int Resources => Planet.Resources ?? 0;
public decimal Gravity => Planet.Gravity ?? 0;
public decimal Temperature => Planet.Temperature ?? 0;
public decimal Radiation => Planet.Radiation ?? 0;
public decimal GravityOrig => Planet.GravityOrig ?? 0;
public decimal TemperatureOrig => Planet.TemperatureOrig ?? 0;
public decimal RadiationOrig => Planet.RadiationOrig ?? 0;
public int MaxTerraforming => Planet.MaxTerraforming ?? 0;
public int CapacityPercent => Planet.CapacityPercent ?? 0;
public int ScanRange => Planet.ScanRange ?? 0;
public int PenScanRange => Planet.PenScanRange ?? 0;
public int Driver => Planet.Driver ?? 0;
public int DriverWarp => Planet.DriverWarp ?? 0;
public string RouteTarget => Planet.RouteTarget;
public int GateRange => Planet.GateRange ?? 0;
public int GateMass => Planet.GateMass ?? 0;
public int PctDamage => Planet.PctDamage ?? 0;
[Reactive]
private int _populationTargetPercent;
2024-09-24 20:32:13 +00:00
#endregion
#region Derived Properties
public int EffectiveValue => GameEngine.EffectivePlanetValue(Value);
public int MaxPopulation => GameEngine.MaxPopOnPlanetForPlayer(Value);
public int PopulationGrowth => GameEngine.PlanetPopGrowthForPlayer(Population, Value);
2024-11-17 12:19:22 +00:00
public int PopulationT1 => Population + PopulationGrowth + EnRoutePopulation;
2024-09-26 20:18:50 +00:00
2024-09-24 20:32:13 +00:00
public int BuildableFactories => GameEngine.MaxBuildableFactoriesForPlayer(Value);
public int BuildableMines => GameEngine.MaxBuildableMinesForPlayer(Value);
public int OperableFactories => GameEngine.MaxOperableFactoriesForPlayer(Population, Value);
public int OperableMines => GameEngine.MaxOperableMinesForPlayer(Population, Value);
public int ResourcesFromPopulation => GameEngine.ResourcesFromPopForPlayer(Population, Value);
public int ResourcesFromFactories => GameEngine.ResourcesFromFactForPlayer(Population, Factories, Value);
2024-09-26 20:18:50 +00:00
public int AvailableIronium => MRIronium + SurfaceIronium;
public int AvailableBoranium => MRBoranium + SurfaceBoranium;
public int AvailableGermanium => MRGermanium + SurfaceGermanium;
2024-11-17 12:19:22 +00:00
[ObservableAsProperty] private int _populationTarget;
[ObservableAsProperty] private int _populationToShip;
[ObservableAsProperty] private int _targetFactories;
2024-11-17 12:19:22 +00:00
[ObservableAsProperty] private int _remainingFactories;
2024-09-26 20:18:50 +00:00
2024-11-17 12:19:22 +00:00
[ObservableAsProperty] private int _factoryGermaniumDelta;
2024-09-26 20:18:50 +00:00
2024-11-17 12:19:22 +00:00
[ObservableAsProperty] private int _remainingMines;
2024-09-26 20:18:50 +00:00
2024-11-17 12:19:22 +00:00
[ObservableAsProperty] private int _enRoutePopulation;
2024-09-26 20:18:50 +00:00
2024-11-17 12:19:22 +00:00
[ObservableAsProperty] private int _enRouteIronium;
2024-09-26 20:18:50 +00:00
2024-11-17 12:19:22 +00:00
[ObservableAsProperty] private int _enRouteBoranium;
2024-11-17 12:19:22 +00:00
[ObservableAsProperty] private int _enRouteGermanium;
2024-09-26 20:18:50 +00:00
#endregion
#region Helper functions
private int ComputePopulationToShip()
{
if (Population >= _populationTarget)
return Population - _populationTarget;
if (PopulationT1 < _populationTarget)
return PopulationT1 - _populationTarget;
return 0;
}
private int ComputeFactoryGermaniumDelta()
{
int gerReq = GameEngine.FactoryGermaniumCostForPlayer(_remainingFactories);
if (gerReq < AvailableGermanium)
return Math.Max(0, SurfaceGermanium - gerReq);
2024-11-17 12:19:22 +00:00
// When extrapolating to T1, we take the available Germanium
// this turn (surface + MR), add MR a second time (the mines
// will yield it next turn as well) and add the inbound shipping
// as this will be available next turn as well. That#s the basis
// for the Germanium requirement in the next turn. We will top
// it out at 0, as we don't have any Germanium available this
// turn, and we don't want to show a projected surplus here
// (we can't pull it off the planet in this turn anyway).
return Math.Min(
AvailableGermanium + EnRouteGermanium + MRGermanium - gerReq
, 0);
2024-10-02 18:18:00 +00:00
}
2024-11-17 12:19:22 +00:00
2024-09-24 20:32:13 +00:00
#endregion
}