using System;
using Splat;
namespace StarsAssistant.Services;
public class GameEngine
{
///
/// Helper reference to the Game, populated during service registration for the
/// loaded game.
///
// TODO: check for better options here.
public static Game Game { get; set; } = null!;
///
/// Minimum effective value of a planet for purposes of maximum population etc.
///
public const int MinEffectiveValue = 5;
///
/// Normalize a planet value for minimum effetive value.
///
/// Real planet value
/// Effective plante value
public static int EffectivePlanetValue(int value) => (value < MinEffectiveValue) ? MinEffectiveValue : value;
///
/// Compute the maximum regular (non-overcrowded) population on a planet for the active player.
///
/// Real planet value
/// effective maximum population
public static int MaxPopOnPlanetForPlayer(int value) => Game.Player.MaxPopOnPlanet * EffectivePlanetValue(value) / 100;
///
/// Compute population growth for player planets.
///
/// Current population on planet
/// Real planet value
/// population growth per turn
public static int PlanetPopGrowthForPlayer(int currentPop, int value)
{
int maxPop = MaxPopOnPlanetForPlayer(value);
double growth;
if (value < 0)
{
growth = currentPop * value / 1000;
}
else
{
double popRatio = (double) currentPop / maxPop;
if (popRatio <= 0.25)
growth = currentPop * value / 100.0 * Game.Player.GrowthRatePercent / 100.0;
else if (popRatio <= 1)
growth = currentPop * value / 100.0 * Game.Player.GrowthRatePercent / 100.0 * 16.0 / 9.0 * Math.Pow(1.0 - popRatio, 2);
else
growth = currentPop * (popRatio - 1) * 0.04;
}
// round to nearest 100
return ((int) growth) / 100 * 100;
}
///
/// Returns the maximum operable factories on a given player planet for a given value.
///
/// Population on planet
/// Real planet value
/// Maximum operable factories for currentPop
public static int MaxOperableFactoriesForPlayer(int currentPop, int value)
{
int effectivePop = Math.Min(currentPop, MaxPopOnPlanetForPlayer(value));
double tmp = (double) effectivePop / 10000 * Game.Player.FactoryNumberPer10k;
return (int) tmp;
}
///
/// Maximum buildable factories on a player planet with a given value.
///
/// Real Planet Value
/// Maximum buildable factories
public static int MaxBuildableFactoriesForPlayer(int value)
{
double tmp = (double) MaxPopOnPlanetForPlayer(value) / 10000 * Game.Player.FactoryNumberPer10k;
return (int) tmp;
}
///
/// Returns the maximum operable mines on a given player planet for a given value.
///
/// Population on planet
/// Real planet value
/// Maximum operable mines for currentPop
public static int MaxOperableMinesForPlayer(int currentPop, int value)
{
int effectivePop = Math.Min(currentPop, MaxPopOnPlanetForPlayer(value));
double tmp = (double) effectivePop / 10000 * Game.Player.MineNumberPer10k;
return (int) tmp;
}
///
/// Maximum buildable factories on a player planet with a given value.
///
/// Real Planet Value
/// Maximum buildable factories
public static int MaxBuildableMinesForPlayer(int value)
{
double tmp = (double) MaxPopOnPlanetForPlayer(value) / 10000 * Game.Player.MineNumberPer10k;
return (int) tmp;
}
///
/// Ressources produced by population on a player planet with a given value. Takes
/// less effective overcrowding pop into account.
///
/// Current planetary population
/// Real planet value
/// Resources generated by populationa
public static int ResourcesFromPopForPlayer(int currentPop, int value)
{
if (Game.Player.ColonistsPerResource == 0)
return 0;
int maxPop = MaxPopOnPlanetForPlayer(value);
int popFullEfficiency;
int popHalfEfficiency;
if (currentPop <= maxPop) {
popHalfEfficiency = 0;
popFullEfficiency = currentPop;
}
else if (currentPop <= 3 * maxPop) {
popFullEfficiency = maxPop;
popHalfEfficiency = currentPop - maxPop;
}
else {
popFullEfficiency = maxPop;
popHalfEfficiency = 2 * maxPop;
}
int popEffective = popFullEfficiency + (popHalfEfficiency / 2);
return popEffective / Services.Game.Player.ColonistsPerResource;
}
///
/// Ressources generated by factories on a player planet for a given value an
/// population. Takes maximum operable factories into account.
///
/// Current planetary population
/// Number of factories built
/// Real planet value
/// Resources generated by factories
public static int ResourcesFromFactForPlayer(int currentPop, int factories, int value)
{
int maxPop = MaxPopOnPlanetForPlayer(value);
int effectivePop = Math.Min(currentPop, maxPop);
double tmp = (double) effectivePop / 10000 * Game.Player.FactoryNumberPer10k;
int maxOperableFactories = (int) tmp;
int operableFactories = Math.Min(factories, maxOperableFactories);
tmp = (double) operableFactories / 10 * Services.Game.Player.FactoryResPer10;
return (int) tmp;
}
}