2024-09-24 20:32:13 +00:00
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
using System.Reactive.Disposables;
|
2024-09-25 17:01:49 +00:00
|
|
|
using System.Reactive.Linq;
|
2024-09-24 20:32:13 +00:00
|
|
|
using Microsoft.EntityFrameworkCore;
|
2024-10-13 20:26:29 +00:00
|
|
|
using DynamicData;
|
2024-09-24 20:32:13 +00:00
|
|
|
using ReactiveUI;
|
2024-09-25 17:01:49 +00:00
|
|
|
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;
|
2024-09-25 17:01:49 +00:00
|
|
|
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);
|
|
|
|
|
2024-10-13 20:26:29 +00:00
|
|
|
FleetManager fm = Locator.Current.GetService<FleetManager>()!;
|
|
|
|
|
2024-10-19 18:05:12 +00:00
|
|
|
_fleetSummaryChanges = fm.FleetSummariesByDestination
|
2024-10-13 20:26:29 +00:00
|
|
|
.Connect()
|
|
|
|
.Watch(Name)
|
|
|
|
.Log(this, "fleetSummaryChange", change => $"{Name}: {change.Reason}: {change.Previous} => {change.Current}")
|
|
|
|
;
|
|
|
|
|
2024-11-17 12:19:22 +00:00
|
|
|
_enRoutePopulationHelper = _fleetSummaryChanges
|
2024-10-13 20:26:29 +00:00
|
|
|
.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-10-13 20:26:29 +00:00
|
|
|
;
|
|
|
|
|
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-10-13 20:26:29 +00:00
|
|
|
|
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;
|
|
|
|
|
2024-09-25 17:01:49 +00:00
|
|
|
[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-09-25 17:01:49 +00:00
|
|
|
|
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-10-13 20:26:29 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
|
}
|