Freeciv21
Develop your civilization from humble roots to a global empire
islands.cpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPLv3-or-later
2 // SPDX-FileCopyrightText: Freeciv21 authors
3 // SPDX-FileCopyrightText: Freeciv authors
4 // SPDX-FileCopyrightText: Louis Moureaux <m_louis30@yahoo.com>
5 
6 #include "islands.h"
7 
8 // common
9 #include "game.h"
10 #include "map.h"
11 #include "map_types.h"
12 #include "terrain.h"
13 
14 // server/generator
15 #include "height_map.h"
16 #include "mapgen.h"
17 #include "mapgen_topology.h"
18 #include "mapgen_utils.h"
19 #include "temperature_map.h"
20 
21 // utility
22 #include "rand.h"
23 
24 // common variables for generator 2, 3 and 4
25 struct gen234_state {
26  int isleindex, n, e, s, w;
27  long int totalmass;
28 };
29 
30 // define one terrain selection
32  int weight;
33  enum mapgen_terrain_property target;
34  enum mapgen_terrain_property prefer;
35  enum mapgen_terrain_property avoid;
38 };
39 
40 #define SPECLIST_TAG terrain_select
41 #include "speclist.h"
42 // list iterator for terrain_select
43 #define terrain_select_list_iterate(tersel_list, ptersel) \
44  TYPED_LIST_ITERATE(struct terrain_select, tersel_list, ptersel)
45 #define terrain_select_list_iterate_end LIST_ITERATE_END
46 
47 static struct terrain_select *tersel_new(int weight,
48  enum mapgen_terrain_property target,
49  enum mapgen_terrain_property prefer,
50  enum mapgen_terrain_property avoid,
51  int temp_condition,
52  int wet_condition);
53 static void tersel_free(struct terrain_select *ptersel);
54 
55 // terrain selection lists for make_island()
56 static struct {
57  bool init;
58  struct terrain_select_list *forest;
59  struct terrain_select_list *desert;
60  struct terrain_select_list *mountain;
61  struct terrain_select_list *swamp;
62 } island_terrain = {.init = false};
63 
64 static void fill_island(int coast, long int *bucket,
65  const struct terrain_select_list *tersel_list,
66  const struct gen234_state *const pstate);
67 static bool make_island(int islemass, int starters,
68  struct gen234_state *pstate,
69  int min_specific_island_size);
70 static bool create_island(int islemass, struct gen234_state *pstate);
71 
72 static void fill_island_rivers(int coast, long int *bucket,
73  const struct gen234_state *const pstate);
74 
75 static long int checkmass;
76 
80 static void island_terrain_init()
81 {
82  struct terrain_select *ptersel;
83 
84  // forest
85  island_terrain.forest = terrain_select_list_new_full(tersel_free);
86  ptersel =
87  tersel_new(1, MG_FOLIAGE, MG_TROPICAL, MG_DRY, TT_TROPICAL, WC_ALL);
88  terrain_select_list_append(island_terrain.forest, ptersel);
89  ptersel =
90  tersel_new(3, MG_FOLIAGE, MG_TEMPERATE, MG_UNUSED, TT_ALL, WC_ALL);
91  terrain_select_list_append(island_terrain.forest, ptersel);
92  ptersel =
93  tersel_new(1, MG_FOLIAGE, MG_WET, MG_FROZEN, TT_TROPICAL, WC_NDRY);
94  terrain_select_list_append(island_terrain.forest, ptersel);
95  ptersel =
96  tersel_new(1, MG_FOLIAGE, MG_COLD, MG_UNUSED, TT_NFROZEN, WC_ALL);
97  terrain_select_list_append(island_terrain.forest, ptersel);
98 
99  // desert
100  island_terrain.desert = terrain_select_list_new_full(tersel_free);
101  ptersel = tersel_new(3, MG_DRY, MG_TROPICAL, MG_GREEN, TT_HOT, WC_DRY);
102  terrain_select_list_append(island_terrain.desert, ptersel);
103  ptersel =
104  tersel_new(2, MG_DRY, MG_TEMPERATE, MG_GREEN, TT_NFROZEN, WC_DRY);
105  terrain_select_list_append(island_terrain.desert, ptersel);
106  ptersel = tersel_new(1, MG_COLD, MG_DRY, MG_TROPICAL, TT_NHOT, WC_DRY);
107  terrain_select_list_append(island_terrain.desert, ptersel);
108  ptersel = tersel_new(1, MG_FROZEN, MG_DRY, MG_UNUSED, TT_FROZEN, WC_DRY);
109  terrain_select_list_append(island_terrain.desert, ptersel);
110 
111  // mountain
112  island_terrain.mountain = terrain_select_list_new_full(tersel_free);
113  ptersel =
114  tersel_new(2, MG_MOUNTAINOUS, MG_GREEN, MG_UNUSED, TT_ALL, WC_ALL);
115  terrain_select_list_append(island_terrain.mountain, ptersel);
116  ptersel =
117  tersel_new(1, MG_MOUNTAINOUS, MG_UNUSED, MG_GREEN, TT_ALL, WC_ALL);
118  terrain_select_list_append(island_terrain.mountain, ptersel);
119 
120  // swamp
121  island_terrain.swamp = terrain_select_list_new_full(tersel_free);
122  ptersel =
123  tersel_new(1, MG_WET, MG_TROPICAL, MG_FOLIAGE, TT_TROPICAL, WC_NDRY);
124  terrain_select_list_append(island_terrain.swamp, ptersel);
125  ptersel = tersel_new(2, MG_WET, MG_TEMPERATE, MG_FOLIAGE, TT_HOT, WC_NDRY);
126  terrain_select_list_append(island_terrain.swamp, ptersel);
127  ptersel = tersel_new(1, MG_WET, MG_COLD, MG_FOLIAGE, TT_NHOT, WC_NDRY);
128  terrain_select_list_append(island_terrain.swamp, ptersel);
129 
130  island_terrain.init = true;
131 }
132 
136 static void island_terrain_free()
137 {
138  if (!island_terrain.init) {
139  return;
140  }
141 
142  terrain_select_list_destroy(island_terrain.forest);
143  terrain_select_list_destroy(island_terrain.desert);
144  terrain_select_list_destroy(island_terrain.mountain);
145  terrain_select_list_destroy(island_terrain.swamp);
146 
147  island_terrain.init = false;
148 }
149 
156 static bool make_island(int islemass, int starters,
157  struct gen234_state *pstate,
158  int min_specific_island_size)
159 {
160  // int may be only 2 byte !
161  static long int tilefactor, balance, lastplaced;
162  static long int riverbuck, mountbuck, desertbuck, forestbuck, swampbuck;
163  int i;
164 
165  /* The terrain selection lists have to be initialised.
166  * (see island_terrain_init()) */
167  fc_assert_ret_val(island_terrain.init, false);
168 
169  if (islemass == 0) {
170  /* this only runs to initialise static things, not to actually
171  * create an island. */
172  balance = 0;
173  // 0 = none, poles, then isles
174  pstate->isleindex = wld.map.num_continents + 1;
175 
176  checkmass = pstate->totalmass;
177 
178  // caveat: this should really be sent to all players
179  if (pstate->totalmass > 3000) {
180  qInfo(_("High landmass - this may take a few seconds."));
181  }
182 
184  i = (i <= 90) ? 100 : i * 11 / 10;
185  tilefactor = pstate->totalmass / i;
186  riverbuck = -static_cast<long int>(fc_rand(pstate->totalmass));
187  mountbuck = -static_cast<long int>(fc_rand(pstate->totalmass));
188  desertbuck = -static_cast<long int>(fc_rand(pstate->totalmass));
189  forestbuck = -static_cast<long int>(fc_rand(pstate->totalmass));
190  swampbuck = -static_cast<long int>(fc_rand(pstate->totalmass));
191  lastplaced = pstate->totalmass;
192  } else {
193  // makes the islands this big
194  islemass = islemass - balance;
195 
196  if (islemass > lastplaced + 1 + lastplaced / 50) {
197  // don't create big isles we can't place
198  islemass = lastplaced + 1 + lastplaced / 50;
199  }
200 
201  // isle creation does not perform well for nonsquare islands
202  if (islemass > (wld.map.ysize - 6) * (wld.map.ysize - 6)) {
203  islemass = (wld.map.ysize - 6) * (wld.map.ysize - 6);
204  }
205 
206  if (islemass > (wld.map.xsize - 2) * (wld.map.xsize - 2)) {
207  islemass = (wld.map.xsize - 2) * (wld.map.xsize - 2);
208  }
209 
210  i = islemass;
211  if (i <= 0) {
212  return false;
213  }
214  fc_assert_ret_val(starters >= 0, false);
215  qDebug("island %i", pstate->isleindex);
216 
217  /* keep trying to place an island, and decrease the size of
218  * the island we're trying to create until we succeed.
219  * If we get too small, return an error. */
220  while (!create_island(i, pstate)) {
221  if (i < islemass * min_specific_island_size / 100) {
222  return false;
223  }
224  i--;
225  }
226  i++;
227  lastplaced = i;
228  if (i * 10 > islemass) {
229  balance = i - islemass;
230  } else {
231  balance = 0;
232  }
233 
234  qDebug("ini=%d, plc=%d, bal=%ld, tot=%ld", islemass, i, balance,
235  checkmass);
236 
237  i *= tilefactor;
238 
239  riverbuck += river_pct * i;
240  fill_island_rivers(1, &riverbuck, pstate);
241 
242  // forest
243  forestbuck += forest_pct * i;
244  fill_island(60, &forestbuck, island_terrain.forest, pstate);
245 
246  // desert
247  desertbuck += desert_pct * i;
248  fill_island(40, &desertbuck, island_terrain.desert, pstate);
249 
250  // mountain
251  mountbuck += mountain_pct * i;
252  fill_island(20, &mountbuck, island_terrain.mountain, pstate);
253 
254  // swamp
255  swampbuck += swamp_pct * i;
256  fill_island(80, &swampbuck, island_terrain.swamp, pstate);
257 
258  pstate->isleindex++;
260  }
261  return true;
262 }
263 
268 static void initworld(struct gen234_state *pstate)
269 {
270  struct terrain *deepest_ocean =
272 
273  fc_assert(nullptr != deepest_ocean);
274  height_map = new int[MAP_INDEX_SIZE];
275 
276  create_placed_map(); // land tiles which aren't placed yet
277 
278  whole_map_iterate(&(wld.map), ptile)
279  {
280  tile_set_terrain(ptile, deepest_ocean);
281  tile_set_continent(ptile, 0);
282  map_set_placed(ptile); // not a land tile
283  BV_CLR_ALL(ptile->extras);
284  tile_set_owner(ptile, nullptr, nullptr);
285  ptile->extras_owner = nullptr;
286  }
288 
289  if (HAS_POLES) {
290  make_polar();
291  }
292 
293  /* Set poles numbers. After the map is generated continents will
294  * be renumbered. */
295  make_island(0, 0, pstate, 0);
296 }
297 
298 /* This variable is the Default Minimum Specific Island Size,
299  * ie the smallest size we'll typically permit our island, as a % of
300  * the size we wanted. So if we ask for an island of size x, the island
301  * creation will return if it would create an island smaller than
302  * x * DMSIS / 100 */
303 #define DMSIS 10
304 
309 {
310  long int totalweight;
311  struct gen234_state state;
312  struct gen234_state *pstate = &state;
313  int i;
314  bool done = false;
315  int spares = 1;
316  // constant that makes up that an island actually needs additional space
317 
318  /* put 70% of land in big continents,
319  * 20% in medium, and
320  * 10% in small. */
321  int bigfrac = 70, midfrac = 20, smallfrac = 10;
322 
323  if (wld.map.server.landpercent > 85) {
324  qDebug("ISLAND generator: falling back to the next generator");
325  return false;
326  }
327 
328  pstate->totalmass =
329  ((wld.map.ysize - 6 - spares) * wld.map.server.landpercent
330  * (wld.map.xsize - spares))
331  / 100;
332  totalweight = 100 * player_count();
333 
335 
336  while (!done && bigfrac > midfrac) {
337  done = true;
338 
341  }
342 
343  initworld(pstate);
344 
345  // Create one big island for each player.
346  for (i = player_count(); i > 0; i--) {
347  if (!make_island(bigfrac * pstate->totalmass / totalweight, 1, pstate,
348  95)) {
349  /* we couldn't make an island at least 95% as big as we wanted,
350  * and since we're trying hard to be fair, we need to start again,
351  * with all big islands reduced slightly in size.
352  * Take the size reduction from the big islands and add it to the
353  * small islands to keep overall landmass unchanged.
354  * Note that the big islands can get very small if necessary, and
355  * the smaller islands will not exist if we can't place them
356  * easily. */
357  qDebug("Island too small, trying again with all smaller "
358  "islands.");
359  midfrac += bigfrac * 0.01;
360  smallfrac += bigfrac * 0.04;
361  bigfrac *= 0.95;
362  done = false;
363  break;
364  }
365  }
366  }
367 
368  if (bigfrac <= midfrac) {
369  // We could never make adequately big islands.
370  qDebug("ISLAND generator: falling back to the next generator");
371 
372  // init world created this map, destroy it before abort
374  delete[] height_map;
375  height_map = nullptr;
376  return false;
377  }
378 
379  /* Now place smaller islands, but don't worry if they're small,
380  * or even non-existent. One medium and one small per player. */
381  for (i = player_count(); i > 0; i--) {
382  make_island(midfrac * pstate->totalmass / totalweight, 0, pstate, DMSIS);
383  }
384  for (i = player_count(); i > 0; i--) {
385  make_island(smallfrac * pstate->totalmass / totalweight, 0, pstate,
386  DMSIS);
387  }
388 
389  make_plains();
391  delete[] height_map;
392  height_map = nullptr;
393 
394  if (checkmass > wld.map.xsize + wld.map.ysize + totalweight) {
395  qDebug("%ld mass left unplaced", checkmass);
396  }
397 
398  return true;
399 }
400 
406 {
407  int spares = 1;
408  int j = 0;
409  long int islandmass, landmass, size;
410  long int maxmassdiv6 = 20;
411  int bigislands;
412  struct gen234_state state;
413  struct gen234_state *pstate = &state;
414 
415  if (wld.map.server.landpercent > 80) {
416  qDebug("ISLAND generator: falling back to the next generator due "
417  "to landpercent > 80.");
418  return false;
419  }
420 
421  if (wld.map.xsize < 40 || wld.map.ysize < 40) {
422  qDebug("ISLAND generator: falling back to the next generator due "
423  "to unsupported map size.");
424  return false;
425  }
426 
427  pstate->totalmass =
428  (((wld.map.ysize - 6 - spares) * wld.map.server.landpercent
429  * (wld.map.xsize - spares))
430  / 100);
431 
432  bigislands = player_count();
433 
434  landmass =
435  (wld.map.xsize * (wld.map.ysize - 6) * wld.map.server.landpercent)
436  / 100;
437  // subtracting the arctics
438  if (landmass > 3 * wld.map.ysize + player_count() * 3) {
439  landmass -= 3 * wld.map.ysize;
440  }
441 
442  islandmass = (landmass) / (3 * bigislands);
443  if (islandmass < 4 * maxmassdiv6) {
444  islandmass = (landmass) / (2 * bigislands);
445  }
446  if (islandmass < 3 * maxmassdiv6 && player_count() * 2 < landmass) {
447  islandmass = (landmass) / (bigislands);
448  }
449 
450  if (islandmass < 2) {
451  islandmass = 2;
452  }
453  if (islandmass > maxmassdiv6 * 6) {
454  islandmass = maxmassdiv6 * 6; // !PS: let's try this
455  }
456 
457  initworld(pstate);
458 
459  while (pstate->isleindex - 2 <= bigislands && checkmass > islandmass
460  && ++j < 500) {
461  make_island(islandmass, 1, pstate, DMSIS);
462  }
463 
464  if (j == 500) {
465  qInfo(_("Generator 3 didn't place all big islands."));
466  }
467 
468  islandmass = (islandmass * 11) / 8;
470  if (islandmass < 2) {
471  islandmass = 2;
472  }
473 
474  while (checkmass > islandmass && ++j < 1500) {
475  if (j < 1000) {
476  size = fc_rand((islandmass + 1) / 2 + 1) + islandmass / 2;
477  } else {
478  size = fc_rand((islandmass + 1) / 2 + 1);
479  }
480  if (size < 2) {
481  size = 2;
482  }
483 
484  make_island(size, (pstate->isleindex - 2 <= player_count()) ? 1 : 0,
485  pstate, DMSIS);
486  }
487 
488  make_plains();
490  delete[] height_map;
491  height_map = nullptr;
492 
493  if (j == 1500) {
494  qInfo(_("Generator 3 left %li landmass unplaced."), checkmass);
495  } else if (checkmass > wld.map.xsize + wld.map.ysize) {
496  qDebug("%ld mass left unplaced", checkmass);
497  }
498 
499  return true;
500 }
501 
506 {
507  int bigweight = 70;
508  int spares = 1;
509  int i;
510  long int totalweight;
511  struct gen234_state state;
512  struct gen234_state *pstate = &state;
513 
514  // no islands with mass >> sqr(min(xsize,ysize))
515 
516  if (player_count() < 2 || wld.map.server.landpercent > 80) {
517  qDebug("ISLAND generator: falling back to the next generator.");
518  return false;
519  }
520 
521  if (wld.map.server.landpercent > 60) {
522  bigweight = 30;
523  } else if (wld.map.server.landpercent > 40) {
524  bigweight = 50;
525  } else {
526  bigweight = 70;
527  }
528 
529  spares = (wld.map.server.landpercent - 5) / 30;
530 
531  pstate->totalmass =
532  (((wld.map.ysize - 6 - spares) * wld.map.server.landpercent
533  * (wld.map.xsize - spares))
534  / 100);
535 
537  totalweight = (30 + bigweight) * player_count();
538 
539  initworld(pstate);
540 
541  i = player_count() / 2;
542  if ((player_count() % 2) == 1) {
543  make_island(bigweight * 3 * pstate->totalmass / totalweight, 3, pstate,
544  DMSIS);
545  } else {
546  i++;
547  }
548  while ((--i) > 0) {
549  make_island(bigweight * 2 * pstate->totalmass / totalweight, 2, pstate,
550  DMSIS);
551  }
552  for (i = player_count(); i > 0; i--) {
553  make_island(20 * pstate->totalmass / totalweight, 0, pstate, DMSIS);
554  }
555  for (i = player_count(); i > 0; i--) {
556  make_island(10 * pstate->totalmass / totalweight, 0, pstate, DMSIS);
557  }
558  make_plains();
560  delete[] height_map;
561  height_map = nullptr;
562 
563  if (checkmass > wld.map.xsize + wld.map.ysize + totalweight) {
564  qDebug("%ld mass left unplaced", checkmass);
565  }
566 
567  return true;
568 }
569 
575 {
576  // initialise terrain selection lists used by make_island()
578 
579  bool ok = false;
580  switch (wld.map.server.startpos) {
581  case MAPSTARTPOS_2or3:
582  case MAPSTARTPOS_ALL:
583  // 2 or 3 players per isle
585  break;
586  case MAPSTARTPOS_DEFAULT:
587  case MAPSTARTPOS_SINGLE:
588  // Single player per isle.
590  break;
592  // "Variable" single player.
594  break;
595  }
596 
597  // free terrain selection lists used by make_island()
599 
600  return ok;
601 }
602 
603 #undef DMSIS
604 
608 static struct tile *
610 {
611  int xrnd, yrnd;
612 
613  fc_assert_ret_val((pstate->e - pstate->w) > 0, nullptr);
614  fc_assert_ret_val((pstate->e - pstate->w) < wld.map.xsize, nullptr);
615  fc_assert_ret_val((pstate->s - pstate->n) > 0, nullptr);
616  fc_assert_ret_val((pstate->s - pstate->n) < wld.map.ysize, nullptr);
617 
618  xrnd = pstate->w + fc_rand(pstate->e - pstate->w);
619  yrnd = pstate->n + fc_rand(pstate->s - pstate->n);
620 
621  return native_pos_to_tile(&(wld.map), xrnd, yrnd);
622 }
623 
627 static struct terrain_select *tersel_new(int weight,
628  enum mapgen_terrain_property target,
629  enum mapgen_terrain_property prefer,
630  enum mapgen_terrain_property avoid,
631  int temp_condition,
632  int wet_condition)
633 {
634  struct terrain_select *ptersel = new terrain_select;
635 
636  ptersel->weight = weight;
637  ptersel->target = target;
638  ptersel->prefer = prefer;
639  ptersel->avoid = avoid;
640  ptersel->temp_condition = temp_condition;
641  ptersel->wet_condition = wet_condition;
642 
643  return ptersel;
644 }
645 
649 static void tersel_free(struct terrain_select *ptersel)
650 {
651  delete ptersel;
652  ptersel = nullptr;
653 }
654 
658 static void fill_island(int coast, long int *bucket,
659  const struct terrain_select_list *tersel_list,
660  const struct gen234_state *const pstate)
661 {
662  int i, k, capac, total_weight = 0;
663  int ntersel = terrain_select_list_size(tersel_list);
664  long int failsafe;
665 
666  if (*bucket <= 0) {
667  return;
668  }
669 
670  // must have at least one terrain selection given in tersel_list
671  fc_assert_ret(ntersel != 0);
672 
673  capac = pstate->totalmass;
674  i = *bucket / capac;
675  i++;
676  *bucket -= i * capac;
677 
678  k = i;
679  failsafe = i * (pstate->s - pstate->n) * (pstate->e - pstate->w);
680  if (failsafe < 0) {
681  failsafe = -failsafe;
682  }
683 
684  terrain_select_list_iterate(tersel_list, ptersel)
685  {
686  total_weight += ptersel->weight;
687  }
689 
690  if (total_weight <= 0) {
691  return;
692  }
693 
694  while (i > 0 && (failsafe--) > 0) {
695  struct tile *ptile = get_random_map_position_from_state(pstate);
696 
697  if (tile_continent(ptile) != pstate->isleindex || !not_placed(ptile)) {
698  continue;
699  }
700 
701  struct terrain_select *ptersel =
702  terrain_select_list_get(tersel_list, fc_rand(ntersel));
703 
704  if (fc_rand(total_weight) > ptersel->weight) {
705  continue;
706  }
707 
708  if (!tmap_is(ptile, ptersel->temp_condition)
709  || !test_wetness(ptile,
710  static_cast<wetness_c>(ptersel->wet_condition))) {
711  continue;
712  }
713 
714  struct terrain *pterrain =
715  pick_terrain(ptersel->target, ptersel->prefer, ptersel->avoid);
716 
717  /* the first condition helps make terrain more contiguous,
718  the second lets it avoid the coast: */
719  if ((i * 3 > k * 2 || fc_rand(100) < 50
720  || is_terrain_near_tile(ptile, pterrain, false))
721  && (!is_terrain_class_card_near(ptile, TC_OCEAN)
722  || fc_rand(100) < coast)) {
723  tile_set_terrain(ptile, pterrain);
724  map_set_placed(ptile);
725 
726  log_debug("[fill_island] placed terrain '%s' at (%2d,%2d)",
727  terrain_rule_name(pterrain), TILE_XY(ptile));
728  }
729 
730  if (!not_placed(ptile)) {
731  i--;
732  }
733  }
734 }
735 
739 static bool island_river_mouth_suitability(const struct tile *ptile,
740  const struct extra_type *priver)
741 {
742  int num_card_ocean, pct_adj_ocean, num_adj_river;
743 
744  num_card_ocean =
746  pct_adj_ocean =
748  num_adj_river = count_river_type_tile_card(ptile, priver, false);
749 
750  return (num_card_ocean == 1 && pct_adj_ocean <= 35 && num_adj_river == 0);
751 }
752 
757 static bool island_river_suitability(const struct tile *ptile,
758  const struct extra_type *priver)
759 {
760  int pct_adj_ocean, num_card_ocean, pct_adj_river, num_card_river;
761 
762  num_card_river = count_river_type_tile_card(ptile, priver, false);
763  num_card_ocean =
765  pct_adj_ocean =
767  pct_adj_river = count_river_type_near_tile(ptile, priver, true);
768 
769  return (num_card_river == 1 && num_card_ocean == 0 && pct_adj_ocean < 20
770  && pct_adj_river < 35
771  /* The following expression helps with straightness,
772  * ocean avoidance, and reduces forking. */
773  && (pct_adj_river + pct_adj_ocean * 2) < fc_rand(25) + 25);
774 }
775 
779 static void fill_island_rivers(int coast, long int *bucket,
780  const struct gen234_state *const pstate)
781 {
782  long int failsafe, capac, i, k;
783  struct tile *ptile;
784 
785  if (*bucket <= 0) {
786  return;
787  }
788  if (river_type_count <= 0) {
789  return;
790  }
791 
792  capac = pstate->totalmass;
793  i = *bucket / capac;
794  i++;
795  *bucket -= i * capac;
796 
797  // generate 75% more rivers than generator 1
798  i = (i * 175) / 100;
799 
800  k = i;
801  failsafe = i * (pstate->s - pstate->n) * (pstate->e - pstate->w) * 5;
802  if (failsafe < 0) {
803  failsafe = -failsafe;
804  }
805 
806  while (i > 0 && failsafe-- > 0) {
807  struct extra_type *priver;
808 
809  ptile = get_random_map_position_from_state(pstate);
810  if (tile_continent(ptile) != pstate->isleindex
811  || tile_has_river(ptile)) {
812  continue;
813  }
814 
816 
817  if (test_wetness(ptile, WC_DRY) && fc_rand(100) < 50) {
818  // rivers don't like dry locations
819  continue;
820  }
821 
822  if ((island_river_mouth_suitability(ptile, priver)
823  && (fc_rand(100) < coast || i == k))
824  || island_river_suitability(ptile, priver)) {
825  tile_add_extra(ptile, priver);
826  i--;
827  }
828  }
829 }
830 
835 static bool is_near_land(struct tile *ptile)
836 {
837  // Note this function may sometimes be called on land tiles.
838  adjc_iterate(&(wld.map), ptile, tile1)
839  {
840  if (!is_ocean(tile_terrain(tile1))) {
841  return true;
842  }
843  }
845 
846  return false;
847 }
848 
852 static bool place_island(struct gen234_state *pstate)
853 {
854  int i = 0, xcur, ycur, nat_x, nat_y;
855  struct tile *ptile;
856 
857  ptile = rand_map_pos(&(wld.map));
859 
860  // this helps a lot for maps with high landmass
861  for (ycur = pstate->n, xcur = pstate->w;
862  ycur < pstate->s && xcur < pstate->e; ycur++, xcur++) {
863  struct tile *tile0 = native_pos_to_tile(&(wld.map), xcur, ycur);
864  struct tile *tile1 = native_pos_to_tile(
865  &(wld.map), xcur + nat_x - pstate->w, ycur + nat_y - pstate->n);
866 
867  if (!tile0 || !tile1) {
868  return false;
869  }
870  if (hmap(tile0) != 0 && is_near_land(tile1)) {
871  return false;
872  }
873  }
874 
875  for (ycur = pstate->n; ycur < pstate->s; ycur++) {
876  for (xcur = pstate->w; xcur < pstate->e; xcur++) {
877  struct tile *tile0 = native_pos_to_tile(&(wld.map), xcur, ycur);
878  struct tile *tile1 = native_pos_to_tile(
879  &(wld.map), xcur + nat_x - pstate->w, ycur + nat_y - pstate->n);
880 
881  if (!tile0 || !tile1) {
882  return false;
883  }
884  if (hmap(tile0) != 0 && is_near_land(tile1)) {
885  return false;
886  }
887  }
888  }
889 
890  for (ycur = pstate->n; ycur < pstate->s; ycur++) {
891  for (xcur = pstate->w; xcur < pstate->e; xcur++) {
892  if (hmap(native_pos_to_tile(&(wld.map), xcur, ycur)) != 0) {
893  struct tile *tile1 = native_pos_to_tile(
894  &(wld.map), xcur + nat_x - pstate->w, ycur + nat_y - pstate->n);
895 
896  checkmass--;
897  if (checkmass <= 0) {
898  qCritical("mapgen.c: mass doesn't sum up.");
899  return i != 0;
900  }
901 
902  tile_set_terrain(tile1, T_UNKNOWN);
903  map_unset_placed(tile1);
904 
905  tile_set_continent(tile1, pstate->isleindex);
906  i++;
907  }
908  }
909  }
910 
911  pstate->s += nat_y - pstate->n;
912  pstate->e += nat_x - pstate->w;
913  pstate->n = nat_y;
914  pstate->w = nat_x;
915 
916  return i != 0;
917 }
918 
922 static int count_card_adjc_elevated_tiles(struct tile *ptile)
923 {
924  int count = 0;
925 
926  cardinal_adjc_iterate(&(wld.map), ptile, tile1)
927  {
928  if (hmap(tile1) != 0) {
929  count++;
930  }
931  }
933 
934  return count;
935 }
936 
940 static bool create_island(int islemass, struct gen234_state *pstate)
941 {
942  int i, nat_x, nat_y;
943  long int tries = islemass * (2 + islemass / 20) + 99;
944  bool j;
945  struct tile *ptile =
947 
948  memset(height_map, '\0', MAP_INDEX_SIZE * sizeof(*height_map));
950  wld.map.ysize / 2)) = 1;
951 
953  pstate->n = nat_y - 1;
954  pstate->w = nat_x - 1;
955  pstate->s = nat_y + 2;
956  pstate->e = nat_x + 2;
957  i = islemass - 1;
958  while (i > 0 && tries-- > 0) {
959  ptile = get_random_map_position_from_state(pstate);
961 
962  if ((!near_singularity(ptile) || fc_rand(50) < 25) && hmap(ptile) == 0
963  && count_card_adjc_elevated_tiles(ptile) > 0) {
964  hmap(ptile) = 1;
965  i--;
966  if (nat_y >= pstate->s - 1 && pstate->s < wld.map.ysize - 2) {
967  pstate->s++;
968  }
969  if (nat_x >= pstate->e - 1 && pstate->e < wld.map.xsize - 2) {
970  pstate->e++;
971  }
972  if (nat_y <= pstate->n && pstate->n > 2) {
973  pstate->n--;
974  }
975  if (nat_x <= pstate->w && pstate->w > 2) {
976  pstate->w--;
977  }
978  }
979  if (i < islemass / 10) {
980  int xcur, ycur;
981 
982  for (ycur = pstate->n; ycur < pstate->s; ycur++) {
983  for (xcur = pstate->w; xcur < pstate->e; xcur++) {
984  ptile = native_pos_to_tile(&(wld.map), xcur, ycur);
985  if (hmap(ptile) == 0 && i > 0
986  && count_card_adjc_elevated_tiles(ptile) == 4) {
987  hmap(ptile) = 1;
988  i--;
989  }
990  }
991  }
992  }
993  }
994  if (tries <= 0) {
995  qCritical("create_island ended early with %d/%d.", islemass - i,
996  islemass);
997  }
998 
999  tries = map_num_tiles() / 4; // on a 40x60 map, there are 2400 places
1000  while (!(j = place_island(pstate)) && (--tries) > 0) {
1001  // nothing
1002  }
1003  return j;
1004 }
#define BV_CLR_ALL(bv)
Definition: bitvector.h:62
#define _(String)
Definition: fcintl.h:50
static map_landmass * landmass
#define MG_UNUSED
Definition: fracture_map.h:29
int * height_map
Definition: height_map.cpp:23
struct world wld
Definition: game.cpp:48
#define hmap(_tile)
Definition: height_map.h:14
#define terrain_select_list_iterate_end
Definition: islands.cpp:45
bool map_generate_island()
Generate a map with the ISLAND family of generators.
Definition: islands.cpp:574
static bool make_island(int islemass, int starters, struct gen234_state *pstate, int min_specific_island_size)
make an island, fill every tile type except plains note: you have to create big islands first.
Definition: islands.cpp:156
static struct @92 island_terrain
struct terrain_select_list * mountain
Definition: islands.cpp:60
#define DMSIS
Definition: islands.cpp:303
static bool map_generate_island_2or3()
Generator for placing a couple of players to each island.
Definition: islands.cpp:505
static void initworld(struct gen234_state *pstate)
fill ocean and make polar A temperature map is created in map_fractal_generate().
Definition: islands.cpp:268
bool init
Definition: islands.cpp:57
static void fill_island(int coast, long int *bucket, const struct terrain_select_list *tersel_list, const struct gen234_state *const pstate)
Fill an island with different types of terrains; rivers have extra code.
Definition: islands.cpp:658
static struct terrain_select * tersel_new(int weight, enum mapgen_terrain_property target, enum mapgen_terrain_property prefer, enum mapgen_terrain_property avoid, int temp_condition, int wet_condition)
Allocate and initialize new terrain_select structure.
Definition: islands.cpp:627
#define terrain_select_list_iterate(tersel_list, ptersel)
Definition: islands.cpp:43
struct terrain_select_list * forest
Definition: islands.cpp:58
static void island_terrain_init()
Initialize terrain selection lists for make_island().
Definition: islands.cpp:80
static bool place_island(struct gen234_state *pstate)
Finds a place and drop the island created when called with islemass != 0.
Definition: islands.cpp:852
static void island_terrain_free()
Free memory allocated for terrain selection lists.
Definition: islands.cpp:136
struct terrain_select_list * swamp
Definition: islands.cpp:61
static bool is_near_land(struct tile *ptile)
Return TRUE if the ocean position is near land.
Definition: islands.cpp:835
static struct tile * get_random_map_position_from_state(const struct gen234_state *const pstate)
Returns a random position in the rectangle denoted by the given state.
Definition: islands.cpp:609
static void fill_island_rivers(int coast, long int *bucket, const struct gen234_state *const pstate)
Fill an island with rivers.
Definition: islands.cpp:779
static bool island_river_mouth_suitability(const struct tile *ptile, const struct extra_type *priver)
Returns TRUE if ptile is suitable for a river mouth.
Definition: islands.cpp:739
static bool create_island(int islemass, struct gen234_state *pstate)
finds a place and drop the island created when called with islemass != 0
Definition: islands.cpp:940
static bool island_river_suitability(const struct tile *ptile, const struct extra_type *priver)
Returns TRUE if there is a river in a cardinal direction near the tile and the tile is suitable for e...
Definition: islands.cpp:757
static bool map_generate_island_single()
On popular demand, this tries to mimick the generator 3 as best as possible.
Definition: islands.cpp:405
struct terrain_select_list * desert
Definition: islands.cpp:59
static bool map_generate_island_variable()
island base map generators
Definition: islands.cpp:308
static int count_card_adjc_elevated_tiles(struct tile *ptile)
Returns the number of cardinally adjacent tiles have a non-zero elevation.
Definition: islands.cpp:922
static void tersel_free(struct terrain_select *ptersel)
Free resources allocated for terrain_select structure.
Definition: islands.cpp:649
static long int checkmass
Definition: islands.cpp:75
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define log_debug(message,...)
Definition: log.h:65
#define nat_x
#define nat_y
struct tile * rand_map_pos(const struct civ_map *nmap)
Random square anywhere on the map.
Definition: map.cpp:1026
int map_num_tiles()
Returns the total number of (real) positions (or tiles) on the map.
Definition: map.cpp:954
struct tile * native_pos_to_tile(const struct civ_map *nmap, int nat_x, int nat_y)
Return the tile for the given native position.
Definition: map.cpp:416
#define adjc_iterate_end
Definition: map.h:358
#define MAP_INDEX_SIZE
Definition: map.h:91
static const bool C_PERCENT
Definition: map.h:30
static const bool C_NUMBER
Definition: map.h:29
#define cardinal_adjc_iterate_end
Definition: map.h:384
#define adjc_iterate(nmap, center_tile, itr_tile)
Definition: map.h:351
static const bool C_ADJACENT
Definition: map.h:27
#define cardinal_adjc_iterate(nmap, center_tile, itr_tile)
Definition: map.h:380
#define whole_map_iterate(_map, _tile)
Definition: map.h:473
static const bool C_CARDINAL
Definition: map.h:28
#define index_to_native_pos(pnat_x, pnat_y, mindex)
Definition: map.h:111
#define whole_map_iterate_end
Definition: map.h:480
@ MAPSTARTPOS_VARIABLE
Definition: map_types.h:56
@ MAPSTARTPOS_2or3
Definition: map_types.h:54
@ MAPSTARTPOS_ALL
Definition: map_types.h:55
@ MAPSTARTPOS_DEFAULT
Definition: map_types.h:52
@ MAPSTARTPOS_SINGLE
Definition: map_types.h:53
int mountain_pct
Definition: mapgen.cpp:96
void make_polar()
Add frozen tiles in the arctic zone.
Definition: mapgen.cpp:258
int desert_pct
Definition: mapgen.cpp:94
int forest_pct
Definition: mapgen.cpp:93
struct extra_type * river_types[MAX_ROAD_TYPES]
Definition: mapgen.cpp:43
int river_type_count
Definition: mapgen.cpp:44
bool test_wetness(const struct tile *ptile, wetness_c c)
These functions test for conditions used in rand_map_pos_characteristic.
Definition: mapgen.cpp:122
int swamp_pct
Definition: mapgen.cpp:95
int river_pct
Definition: mapgen.cpp:98
void make_plains()
Make_plains converts all not yet placed terrains to plains (tundra, grass) used by generators 2-4.
Definition: mapgen.cpp:377
wetness_c
Definition: mapgen.h:28
@ WC_NDRY
Definition: mapgen.h:28
@ WC_ALL
Definition: mapgen.h:28
@ WC_DRY
Definition: mapgen.h:28
#define HAS_POLES
Definition: mapgen.h:15
bool near_singularity(const struct tile *ptile)
Return TRUE if the map in a typical city radius is SINGULAR.
void map_set_placed(struct tile *ptile)
Mark tile terrain as placed.
bool not_placed(const struct tile *ptile)
Checks if land has not yet been placed on pmap at (x, y)
struct terrain * pick_ocean(int depth, bool frozen)
Picks an ocean terrain to match the given depth.
void create_placed_map()
Create a clean pmap.
void destroy_placed_map()
Free the pmap.
bool placed_map_is_initialized()
Return TRUE if initialized.
struct terrain * pick_terrain(enum mapgen_terrain_property target, enum mapgen_terrain_property prefer, enum mapgen_terrain_property avoid)
Pick a terrain based on the target property and a property to avoid.
void map_unset_placed(struct tile *ptile)
Mark tile terrain as not placed.
int player_count()
Return the number of players.
Definition: player.cpp:739
#define fc_rand(_size)
Definition: rand.h:16
int count_river_type_near_tile(const struct tile *ptile, const struct extra_type *priver, bool percentage)
Count tiles with river of specific type near the tile.
Definition: road.cpp:340
int count_river_type_tile_card(const struct tile *ptile, const struct extra_type *priver, bool percentage)
Count tiles with river of specific type cardinally adjacent to the tile.
Definition: road.cpp:313
size_t size
Definition: specvec.h:64
int xsize
Definition: map_types.h:73
int ysize
Definition: map_types.h:73
int num_continents
Definition: map_types.h:74
struct civ_map::@39::@41 server
int isleindex
Definition: islands.cpp:26
long int totalmass
Definition: islands.cpp:27
int wet_condition
Definition: islands.cpp:37
enum mapgen_terrain_property avoid
Definition: islands.cpp:35
int temp_condition
Definition: islands.cpp:36
enum mapgen_terrain_property target
Definition: islands.cpp:33
enum mapgen_terrain_property prefer
Definition: islands.cpp:34
Definition: tile.h:42
struct civ_map map
Definition: world_object.h:21
bool tmap_is(const struct tile *ptile, temperature_type tt)
Return true if the tile has tt temperature type.
#define TT_NHOT
#define TT_HOT
#define TT_FROZEN
#define TT_TROPICAL
#define TT_ALL
#define TT_NFROZEN
bool is_terrain_class_card_near(const struct tile *ptile, enum terrain_class tclass)
Is there terrain of the given class cardinally near tile? (Does not check ptile itself....
Definition: terrain.cpp:473
const char * terrain_rule_name(const struct terrain *pterrain)
Return the (untranslated) rule name of the terrain.
Definition: terrain.cpp:184
bool is_terrain_near_tile(const struct tile *ptile, const struct terrain *pterrain, bool check_self)
Returns TRUE iff any adjacent tile contains the given terrain.
Definition: terrain.cpp:277
int count_terrain_class_near_tile(const struct tile *ptile, bool cardinal_only, bool percentage, enum terrain_class tclass)
Return the number of adjacent tiles that have given terrain class (not including ptile itself).
Definition: terrain.cpp:517
#define T_UNKNOWN
Definition: terrain.h:51
#define is_ocean(pterrain)
Definition: terrain.h:276
#define TERRAIN_OCEAN_DEPTH_MAXIMUM
Definition: terrain.h:234
void tile_add_extra(struct tile *ptile, const struct extra_type *pextra)
Adds extra to tile.
Definition: tile.cpp:974
void tile_set_terrain(struct tile *ptile, struct terrain *pterrain)
Set the given terrain at the specified tile.
Definition: tile.cpp:114
bool tile_has_river(const struct tile *ptile)
Tile has any river type.
Definition: tile.cpp:876
void tile_set_owner(struct tile *ptile, struct player *pplayer, struct tile *claimer)
Set the owner of a tile (may be nullptr).
Definition: tile.cpp:58
void tile_set_continent(struct tile *ptile, Continent_id val)
Set the continent ID of the tile.
Definition: tile.cpp:388
#define tile_index(_pt_)
Definition: tile.h:70
#define tile_terrain(_tile)
Definition: tile.h:93
#define TILE_XY(ptile)
Definition: tile.h:36
#define tile_continent(_tile)
Definition: tile.h:74