// Species enumeration used by every per-species table in the strategic sim, plus the // handful of per-species constants the executable carries itself (not the data files). // // The index order is the one the save format and the per-species arrays use; note that // index 4 is the independent/NPC race, which the growth and capacity formulas treat // specially (no imperial growth, capacity scaled by INDSYS_IMPERIAL_POPULATION_MOD). // CONFIDENCE: high. #pragma once namespace sots::sim { enum class Species : int { Human = 0, Hiver = 1, Tarkas = 2, Liir = 3, NPC = 4, Zuul = 5, Morrigi = 6, }; constexpr int kSpeciesCount = 7; constexpr bool IsNpcSpecies(Species s) { return s == Species::NPC; } // Per-species constants that live in the engine's own species table rather than in the // data files. Only the fields whose readers are known are exposed here. struct SpeciesConstants { double incomeFactor = 1.0; // multiplies a system's money income (Zuul 1.1, Morrigi 0.8) double hazardCostFactor = 1.0; // multiplies the suitability money cost (Zuul 0.7) bool systemBonusEligible = true; // long-stability system bonus accrues (Zuul never) // The species' base resource demand and resource-output factor -- the two fields the // output term's harvest summand reads, off the SYSTEM OWNER's species rather than the // colony's population species. Unlike the three above, these come from the DATA FILES; // the values here are the ones measured live on VM140 for the three species the corpus // exercises (Human, Tarkas, Zuul) and are 0/10 for the rest, which is UNVERIFIED for // Hiver, Liir and Morrigi. Getting the Zuul pair wrong costs a Zuul colony exactly // 400 output points -- 2000 money -- which is how it was found. int resourceDemand = 0; // SpeciesDef +0x4c double resourceOutput = 10.0; // SpeciesDef +0x50 // The per-species multiplier on every carrying capacity (the helper at 0x0053bb00 off the // same SpeciesDef). Also a DATA FILE value. 1.0 for Human is MEASURED, not assumed, and // not from the data files either: Gamma Cephei's imperial `pbon` of 1e9 never drains -- // and the bonus apply returns exactly when `Pop >= MaxPop` -- while its `Pop` of 1e9 never // shrinks, and the imperial apply shrinks exactly when `pop > cap`. The two behaviours // bracket the capacity at exactly `Size x 1e8 x 1.0`, which forces this factor to 1.0 for // a Human colony at its ideal suitability. UNVERIFIED for every other species. double growthFactor = 1.0; // SpeciesDef, read by MaxPopGeneric }; // CONFIDENCE: high on the first three fields (read with their constants and their // consumers); the two resource fields are data-file values, measured not read. constexpr SpeciesConstants ConstantsOf(Species s) { switch (s) { case Species::Zuul: return SpeciesConstants{1.1, 0.7, false, 10, 40.0}; case Species::Morrigi: return SpeciesConstants{0.8, 1.0, true, 0, 10.0}; default: return SpeciesConstants{1.0, 1.0, true, 0, 10.0}; } } } // namespace sots::sim