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); int growth; if (value < 0) { growth = currentPop * value / 1000; } else { double popRatio = (double) currentPop / maxPop; if (popRatio <= 0.25) { growth = currentPop * Game.Player.GrowthRatePercent / 100 * value / 100; } else if (popRatio < 1) { double factor = Math.Pow(1.0 - popRatio, 2); growth = currentPop * Game.Player.GrowthRatePercent / 100 * value / 100 * 16 / 9; growth = (int) ((double) growth * factor); } else { double factor = 0.04 * (popRatio - 1); growth = (int) ((double) currentPop * factor); } } // round down by 100 return 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; } }