summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/industry_cmd.cpp128
1 files changed, 80 insertions, 48 deletions
diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp
index 7738fc305..bc85373e8 100644
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -1764,75 +1764,107 @@ static Industry *CreateNewIndustry(TileIndex tile, IndustryType type)
return CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, OWNER_NONE);
}
-enum {
- NB_NUMOFINDUSTRY = 11,
- NB_DIFFICULTY_LEVEL = 5,
-};
+/**
+ * Compute the appearance probability for an industry during map creation.
+ * @param it Industrytype to compute for
+ * @param force_at_least_one Returns whether at least one instance should be forced on map creation
+ * @return relative probability for the industry to appear
+ */
+static uint32 GetScaledIndustryProbability(IndustryType it, bool *force_at_least_one)
+{
+ const IndustrySpec *ind_spc = GetIndustrySpec(it);
+ uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16; // * 16 to increase precision
+ if (!ind_spc->enabled || chance == 0 || ind_spc->num_table == 0 ||
+ !CheckIfCallBackAllowsAvailability(it, IACT_MAPGENERATION) || _settings_game.difficulty.number_industries == 0) {
+ *force_at_least_one = false;
+ return 0;
+ } else {
+ /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
+ * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
+ chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(chance) : ScaleByMapSize(chance);
+
+ *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION);
+ return chance;
+ }
+}
-static const byte _numof_industry_table[NB_DIFFICULTY_LEVEL][NB_NUMOFINDUSTRY] = {
- /* difficulty settings for number of industries */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // none
- {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // very low
- {0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5}, // low
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, // normal
- {0, 2, 3, 4, 6, 7, 8, 9, 10, 10, 10}, // high
+/** Number of industries on a 256x256 map */
+static const byte _numof_industry_table[]= {
+ 0, // none
+ 10, // very low
+ 25, // low
+ 55, // normal
+ 80, // high
};
-/** This function is the one who really do the creation work
- * of random industries during game creation
+/**
+ * Try to build a industry on the map.
* @param type IndustryType of the desired industry
- * @param amount of industries that need to be built */
-static void PlaceInitialIndustry(IndustryType type, uint amount)
+ * @param try_hard Try very hard to find a place. (Used to place at least one industry per type)
+ */
+static void PlaceInitialIndustry(IndustryType type, bool try_hard)
{
CompanyID old_company = _current_company;
_current_company = OWNER_NONE;
- for (; amount > 0; amount--) {
- IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
+ IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
- for (uint i = 0; i < 2000; i++) {
- if (CreateNewIndustry(RandomTile(), type) != NULL) break;
- }
+ for (uint i = 0; i < (try_hard ? 10000 : 2000); i++) {
+ if (CreateNewIndustry(RandomTile(), type) != NULL) break;
}
_current_company = old_company;
}
-/** This function will create ramdon industries during game creation.
- * It will scale the amount of industries by map size as well as difficulty level */
+/**
+ * This function will create random industries during game creation.
+ * It will scale the amount of industries by mapsize and difficulty level.
+ */
void GenerateIndustries()
{
- uint total_amount = 0;
- uint industry_counts[NUM_INDUSTRYTYPES];
- memset(industry_counts, 0, sizeof(industry_counts));
-
- /* Find the total amount of industries */
- if (_settings_game.difficulty.number_industries > 0) {
- for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
- const IndustrySpec *ind_spc = GetIndustrySpec(it);
-
- uint8 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape];
- if (ind_spc->enabled && chance > 0 && ind_spc->num_table > 0 && CheckIfCallBackAllowsAvailability(it, IACT_MAPGENERATION)) {
- /* once the chance of appearance is determind, it have to be scaled by
- * the difficulty level. The "chance" in question is more an index into
- * the _numof_industry_table,in fact */
- uint num = (chance > NB_NUMOFINDUSTRY) ? chance : _numof_industry_table[_settings_game.difficulty.number_industries][chance];
-
- /* These are always placed next to the coastline, so we scale by the perimeter instead. */
- num = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(num) : ScaleByMapSize(num);
- industry_counts[it] = num;
- total_amount += num;
- }
- }
+ assert(_settings_game.difficulty.number_industries < lengthof(_numof_industry_table));
+ uint total_amount = ScaleByMapSize(_numof_industry_table[_settings_game.difficulty.number_industries]);
+
+ /* Do not create any industries? */
+ if (total_amount == 0) return;
+
+ uint32 industry_probs[NUM_INDUSTRYTYPES];
+ bool force_at_least_one[NUM_INDUSTRYTYPES];
+ uint32 total_prob = 0;
+ uint num_forced = 0;
+
+ for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
+ industry_probs[it] = GetScaledIndustryProbability(it, force_at_least_one + it);
+ total_prob += industry_probs[it];
+ if (force_at_least_one[it]) num_forced++;
+ }
+
+ if (total_prob == 0 || total_amount < num_forced) {
+ /* Only place the forced ones */
+ total_amount = num_forced;
}
SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount);
- if (_settings_game.difficulty.number_industries > 0) {
- for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
- /* Once the number of industries has been determined, let's really create them. */
- if (industry_counts[it] > 0) PlaceInitialIndustry(it, industry_counts[it]);
+ /* Try to build one industry per type independent of any probabilities */
+ for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
+ if (force_at_least_one[it]) {
+ assert(total_amount > 0);
+ total_amount--;
+ PlaceInitialIndustry(it, true);
+ }
+ }
+
+ /* Add the remaining industries according to their probabilities */
+ for (uint i = 0; i < total_amount; i++) {
+ uint32 r = RandomRange(total_prob);
+ IndustryType it = 0;
+ while (it < NUM_INDUSTRYTYPES && r > industry_probs[it]) {
+ r -= industry_probs[it];
+ it++;
}
+ assert(it < NUM_INDUSTRYTYPES && industry_probs[it] > 0);
+ PlaceInitialIndustry(it, false);
}
}