diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/industry.h | 2 | ||||
-rw-r--r-- | src/industry_cmd.cpp | 54 |
2 files changed, 44 insertions, 12 deletions
diff --git a/src/industry.h b/src/industry.h index 1c1637946..9ff0e5403 100644 --- a/src/industry.h +++ b/src/industry.h @@ -146,6 +146,7 @@ void ReleaseDisastersTargetingIndustry(IndustryID); /** Data for managing the number of industries of a single industry type. */ struct IndustryTypeBuildData { uint32 probability; ///< Relative probability of building this industry. + uint16 target_count; ///< Desired number of industries of this type. void GetIndustryTypeData(IndustryType it); }; @@ -156,6 +157,7 @@ struct IndustryTypeBuildData { struct IndustryBuildData { IndustryTypeBuildData builddata[NUM_INDUSTRYTYPES]; ///< Industry build data for every industry type. + void SetupTargetCount(); void TryBuildNewIndustry(); }; diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 156d67d6d..798a484b4 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -2055,26 +2055,56 @@ void IndustryTypeBuildData::GetIndustryTypeData(IndustryType it) this->probability = GetIndustryGamePlayProbability(it); } +/** Decide how many industries of each type are needed. */ +void IndustryBuildData::SetupTargetCount() +{ + for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { + this->builddata[it].GetIndustryTypeData(it); + } + + uint total_amount = GetNumberOfIndustries(); // Desired number of industries. + uint32 total_prob = 0; // Sum of probabilities. + for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { + this->builddata[it].target_count = 0; + total_prob += this->builddata[it].probability; + } + + /* Assign number of industries that should be aimed for, by using the probability as a weight. */ + while (total_amount > 0) { + uint32 r = RandomRange(total_prob); + IndustryType it = 0; + while (r >= this->builddata[it].probability) { + r -= this->builddata[it].probability; + it++; + assert(it < NUM_INDUSTRYTYPES); + } + assert(this->builddata[it].probability > 0); + this->builddata[it].target_count++; + total_amount--; + } +} + /** * Try to create a random industry, during gameplay */ void IndustryBuildData::TryBuildNewIndustry() { - /* Generate a list of all possible industries that can be built. */ - for (IndustryType j = 0; j < NUM_INDUSTRYTYPES; j++) { - this->builddata[j].GetIndustryTypeData(j); - } + this->SetupTargetCount(); + int missing = 0; // Number of industries that need to be build. 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) { - total_prob += chance; + int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it); + missing += difference; + if (difference > 0) { + total_prob += difference; count++; } } + if (missing <= 0 || total_prob == 0) count = 0; // Skip creation of an industry. + 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. */ @@ -2083,13 +2113,13 @@ void IndustryBuildData::TryBuildNewIndustry() 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; + int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it); + if (difference <= 0) continue; // Too many of this kind. if (count == 1) break; - if (r < chance) break; - r -= chance; + if (r < (uint)difference) break; + r -= difference; } - assert(it < NUM_INDUSTRYTYPES); + assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it)); /* Try to create the industry. */ const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false); |