diff options
-rw-r--r-- | src/industry.h | 9 | ||||
-rw-r--r-- | src/industry_cmd.cpp | 68 |
2 files changed, 49 insertions, 28 deletions
diff --git a/src/industry.h b/src/industry.h index cdf9d0c78..1c1637946 100644 --- a/src/industry.h +++ b/src/industry.h @@ -143,10 +143,19 @@ void ReleaseDisastersTargetingIndustry(IndustryID); #define FOR_ALL_INDUSTRIES_FROM(var, start) FOR_ALL_ITEMS_FROM(Industry, industry_index, var, start) #define FOR_ALL_INDUSTRIES(var) FOR_ALL_INDUSTRIES_FROM(var, 0) +/** Data for managing the number of industries of a single industry type. */ +struct IndustryTypeBuildData { + uint32 probability; ///< Relative probability of building this industry. + + void GetIndustryTypeData(IndustryType it); +}; + /** * Data for managing the number and type of industries in the game. */ struct IndustryBuildData { + IndustryTypeBuildData builddata[NUM_INDUSTRYTYPES]; ///< Industry build data for every industry type. + void TryBuildNewIndustry(); }; diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 6b19bc447..156d67d6d 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -1871,6 +1871,8 @@ static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *forc */ static uint16 GetIndustryGamePlayProbability(IndustryType it) { + if (_settings_game.difficulty.number_industries == 0) return 0; + const IndustrySpec *ind_spc = GetIndustrySpec(it); byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape]; if (!ind_spc->enabled || chance == 0 || ind_spc->num_table == 0 || @@ -2043,48 +2045,58 @@ void Industry::RecomputeProductionMultipliers() this->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF); } -/** Simple helper that will collect data for the generation of industries */ -struct ProbabilityHelper { - uint16 prob; ///< probability - IndustryType ind; ///< Industry id. -}; + +/** + * Set the #probability field for the industry type \a it for a running game. + * @param it Industry type. + */ +void IndustryTypeBuildData::GetIndustryTypeData(IndustryType it) +{ + this->probability = GetIndustryGamePlayProbability(it); +} /** * Try to create a random industry, during gameplay */ void IndustryBuildData::TryBuildNewIndustry() { - uint num = 0; - ProbabilityHelper cumulative_probs[NUM_INDUSTRYTYPES]; // probability collector - uint16 probability_max = 0; - /* Generate a list of all possible industries that can be built. */ for (IndustryType j = 0; j < NUM_INDUSTRYTYPES; j++) { - uint16 chance = GetIndustryGamePlayProbability(j); + this->builddata[j].GetIndustryTypeData(j); + } + + uint count = 0; // Number of industry types eligible for build. + uint32 total_prob = 0; // Sum of probabilities. + for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { + uint32 chance = this->builddata[it].probability; if (chance > 0) { - probability_max += chance; - /* adds the result for this industry */ - cumulative_probs[num].ind = j; - cumulative_probs[num++].prob = probability_max; + total_prob += chance; + count++; } } - /* Abort if there is no industry buildable */ - if (probability_max == 0) return; + if (count >= 1) { + /* Pick a weighted random industry to build. + * For the case that count == 1, there is no need to draw a random number. */ + IndustryType it; + /* Select an industry type to build (weighted random). */ + uint32 r = 0; // Initialized to silence the compiler. + if (count > 1) r = RandomRange(total_prob); + for (it = 0; it < NUM_INDUSTRYTYPES; it++) { + uint32 chance = this->builddata[it].probability; + if (chance == 0) continue; + if (count == 1) break; + if (r < chance) break; + r -= chance; + } + assert(it < NUM_INDUSTRYTYPES); - /* Find a random type, with maximum being what has been evaluate above*/ - IndustryType rndtype = RandomRange(probability_max); - IndustryType j; - for (j = 0; j < NUM_INDUSTRYTYPES; j++) { - /* and choose the index of the industry that matches as close as possible this random type */ - if (cumulative_probs[j].prob >= rndtype) break; + /* Try to create the industry. */ + const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false); + if (ind != NULL) { + AdvertiseIndustryOpening(ind); + } } - - /* try to create 2000 times this industry */ - const Industry *ind = PlaceIndustry(cumulative_probs[j].ind, IACT_RANDOMCREATION, false); - if (ind == NULL) return; - - AdvertiseIndustryOpening(ind); } /** |