Freeciv21
Develop your civilization from humble roots to a global empire
fair_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 "fair_islands.h"
7 
8 // common
9 #include "fc_types.h"
10 #include "map.h"
11 #include "nation.h"
12 
13 // server/generator
14 #include "mapgen.h"
15 #include "mapgen_utils.h"
16 
17 // utility
18 #include "rand.h"
19 
24  FTF_NONE = 0,
25  FTF_ASSIGNED = 1 << 0,
26  FTF_OCEAN = 1 << 1,
27  FTF_STARTPOS = 1 << 2,
28  FTF_NO_RESOURCE = 1 << 3,
29  FTF_HAS_HUT = 1 << 4,
30  FTF_NO_HUT = 1 << 5
31 };
32 
33 struct fair_tile {
34  enum fair_tile_flag flags;
35  struct terrain *pterrain;
37  bv_extras extras;
39 };
40 
41 typedef void (*fair_geometry_func)(int *x, int *y);
45 };
46 
50 static inline void fair_map_destroy(struct fair_tile *pmap)
51 {
52  delete[] pmap;
53 }
54 
58 static inline void fair_map_tile_pos(struct fair_tile *pmap,
59  struct fair_tile *ptile, int *x, int *y)
60 {
61  index_to_map_pos(x, y, ptile - pmap);
62 }
63 
67 static inline struct fair_tile *fair_map_pos_tile(struct fair_tile *pmap,
68  int x, int y)
69 {
70  int nat_x, nat_y;
71 
72  MAP_TO_NATIVE_POS(&nat_x, &nat_y, x, y);
73 
74  // Wrap in X and Y directions, as needed.
75  if (nat_x < 0 || nat_x >= wld.map.xsize) {
76  if (current_topo_has_flag(TF_WRAPX)) {
78  } else {
79  return nullptr;
80  }
81  }
82  if (nat_y < 0 || nat_y >= wld.map.ysize) {
83  if (current_topo_has_flag(TF_WRAPY)) {
85  } else {
86  return nullptr;
87  }
88  }
89 
91 }
92 
96 static inline struct fair_tile *fair_map_tile_step(struct fair_tile *pmap,
97  struct fair_tile *ptile,
98  enum direction8 dir)
99 {
100  int x, y, dx, dy;
101 
102  fair_map_tile_pos(pmap, ptile, &x, &y);
103  DIRSTEP(dx, dy, dir);
104  return fair_map_pos_tile(pmap, x + dx, y + dy);
105 }
106 
111 static inline bool fair_map_tile_border(struct fair_tile *pmap,
112  struct fair_tile *ptile, int dist)
113 {
114  int nat_x, nat_y;
115 
116  index_to_native_pos(&nat_x, &nat_y, ptile - pmap);
117 
118  if (!current_topo_has_flag(TF_WRAPX)
119  && (nat_x < dist || nat_x >= wld.map.xsize - dist)) {
120  return true;
121  }
122 
123  if (MAP_IS_ISOMETRIC) {
124  dist *= 2;
125  }
126 
127  if (!current_topo_has_flag(TF_WRAPY)
128  && (nat_y < dist || nat_y >= wld.map.ysize - dist)) {
129  return true;
130  }
131 
132  return false;
133 }
134 
138 static int fair_team_placement_closest(const void *a, const void *b)
139 {
140  const struct iter_index *index1 = static_cast<const iter_index *>(a),
141  *index2 = static_cast<const iter_index *>(b);
142 
143  return index1->dist - index2->dist;
144 }
145 
149 static int fair_team_placement_horizontal(const void *a, const void *b)
150 {
151  const struct iter_index *index1 = static_cast<const iter_index *>(a),
152  *index2 = static_cast<const iter_index *>(b);
153  // Map vector to natural vector (Y axis).
154  int diff = (MAP_IS_ISOMETRIC ? abs(index1->dx + index1->dy)
155  - abs(index2->dx + index2->dy)
156  : abs(index1->dy) - abs(index2->dy));
157 
158  return (diff != 0 ? diff : index1->dist - index2->dist);
159 }
160 
164 static int fair_team_placement_vertical(const void *a, const void *b)
165 {
166  const struct iter_index *index1 = static_cast<const iter_index *>(a),
167  *index2 = static_cast<const iter_index *>(b);
168  // Map vector to natural vector (X axis).
169  int diff = (MAP_IS_ISOMETRIC ? abs(index1->dx - index1->dy)
170  - abs(index2->dx - index2->dy)
171  : abs(index1->dx) - abs(index2->dx));
172 
173  return (diff != 0 ? diff : index1->dist - index2->dist);
174 }
175 
179 static void fair_do_symetry1(int *x, int *y) { *x = -*x; }
180 
184 static void fair_do_symetry2(int *x, int *y) { *y = -*y; }
185 
189 static void fair_do_hex_symetry1(int *x, int *y) { *x = -(*x + *y); }
190 
194 static void fair_do_hex_symetry2(int *x, int *y)
195 {
196  *x = -*x;
197  *y = -*y;
198 }
199 
203 static void fair_do_iso_hex_symetry1(int *x, int *y) { *y = *x - *y; }
204 
205 #define fair_do_iso_hex_symetry2 fair_do_rotation
206 
210 static void fair_do_rotation(int *x, int *y)
211 {
212  int z = *x;
213 
214  *x = *y;
215  *y = z;
216 }
217 
221 static void fair_do_hex_rotation(int *x, int *y)
222 {
223  int z = *x + *y;
224 
225  *x = -*y;
226  *y = z;
227 }
228 
232 static void fair_do_iso_hex_rotation(int *x, int *y)
233 {
234  int z = *x - *y;
235 
236  *y = *x;
237  *x = z;
238 }
239 
243 static void fair_do_geometry(const struct fair_geometry_data *data, int *x,
244  int *y)
245 {
246  int i;
247 
248  for (i = 0; i < data->transform_num; i++) {
249  data->transform[i](x, y);
250  }
251 }
252 
256 static void fair_geometry_rand(struct fair_geometry_data *data)
257 {
258  int i = 0;
259 
260  if (!current_topo_has_flag(TF_HEX)) {
261  if (fc_rand(100) < 50) {
262  data->transform[i++] = fair_do_symetry1;
263  }
264  if (fc_rand(100) < 50) {
265  data->transform[i++] = fair_do_symetry2;
266  }
267  if (fc_rand(100) < 50) {
268  data->transform[i++] = fair_do_rotation;
269  }
270  } else if (!current_topo_has_flag(TF_ISO)) {
271  int steps;
272 
273  if (fc_rand(100) < 50) {
274  data->transform[i++] = fair_do_hex_symetry1;
275  }
276  if (fc_rand(100) < 50) {
277  data->transform[i++] = fair_do_hex_symetry2;
278  }
279  // Rotations have 2 steps on hexgonal topologies.
280  for (steps = fc_rand(99) % 3; steps > 0; steps--) {
281  data->transform[i++] = fair_do_hex_rotation;
282  }
283  } else {
284  int steps;
285 
286  if (fc_rand(100) < 50) {
287  data->transform[i++] = fair_do_iso_hex_symetry1;
288  }
289  if (fc_rand(100) < 50) {
290  data->transform[i++] = fair_do_iso_hex_symetry2;
291  }
292  // Rotations have 2 steps on hexgonal topologies.
293  for (steps = fc_rand(99) % 3; steps > 0; steps--) {
294  data->transform[i++] = fair_do_iso_hex_rotation;
295  }
296  }
297  fc_assert(i <= ARRAY_SIZE(data->transform));
298  data->transform_num = i;
299 }
300 
307 static bool fair_map_copy(struct fair_tile *ptarget, int tx, int ty,
308  struct fair_tile *psource,
309  const struct fair_geometry_data *data,
310  int startpos_team_id)
311 {
312  int sdx = wld.map.xsize / 2, sdy = wld.map.ysize / 2;
313  struct fair_tile *smax_tile = psource + MAP_INDEX_SIZE;
314  struct fair_tile *pstile, *pttile;
315  int x, y;
316 
317  // Check.
318  for (pstile = psource; pstile < smax_tile; pstile++) {
319  if (pstile->flags == FTF_NONE) {
320  continue;
321  }
322 
323  // Do translation and eventually other transformations.
324  fair_map_tile_pos(psource, pstile, &x, &y);
325  x -= sdx;
326  y -= sdy;
327  fair_do_geometry(data, &x, &y);
328  x += tx;
329  y += ty;
330  pttile = fair_map_pos_tile(ptarget, x, y);
331  if (pttile == nullptr) {
332  return false; // Limit of the map.
333  }
334  if (pttile->flags & FTF_ASSIGNED) {
335  if (pstile->flags & FTF_ASSIGNED || !(pttile->flags & FTF_OCEAN)
336  || !(pstile->flags & FTF_OCEAN)) {
337  return false; // Already assigned for another usage.
338  }
339  } else if (pttile->flags & FTF_OCEAN && !(pstile->flags & FTF_OCEAN)) {
340  return false; // We clearly want a sea tile here.
341  }
342  if ((pttile->flags & FTF_NO_RESOURCE && pstile->presource != nullptr)
343  || (pstile->flags & FTF_NO_RESOURCE
344  && pttile->presource != nullptr)) {
345  return false; // Resource disallowed there.
346  }
347  if ((pttile->flags & FTF_NO_HUT && pstile->flags & FTF_HAS_HUT)
348  || (pstile->flags & FTF_NO_HUT && pttile->flags & FTF_HAS_HUT)) {
349  return false; // Resource disallowed there.
350  }
351  }
352 
353  // Copy.
354  for (pstile = psource; pstile < smax_tile; pstile++) {
355  if (pstile->flags == FTF_NONE) {
356  continue;
357  }
358 
359  // Do translation and eventually other transformations.
360  fair_map_tile_pos(psource, pstile, &x, &y);
361  x -= sdx;
362  y -= sdy;
363  fair_do_geometry(data, &x, &y);
364  x += tx;
365  y += ty;
366  pttile = fair_map_pos_tile(ptarget, x, y);
367  fc_assert_ret_val(pttile != nullptr, false);
368  pttile->flags =
369  static_cast<fair_tile_flag>(pttile->flags | pstile->flags);
370  if (pstile->pterrain != nullptr) {
371  pttile->pterrain = pstile->pterrain;
372  pttile->presource = pstile->presource;
373  pttile->extras = pstile->extras;
374  }
375  if (pstile->flags & FTF_STARTPOS) {
377  }
378  }
379  return true; // Looks ok.
380 }
381 
386 static bool fair_map_place_island_rand(struct fair_tile *ptarget,
387  struct fair_tile *psource)
388 {
389  struct fair_geometry_data geometry;
390  int i, r, x, y;
391 
392  fair_geometry_rand(&geometry);
393 
394  // Try random positions.
395  for (i = 0; i < 10; i++) {
396  r = fc_rand(MAP_INDEX_SIZE);
397  index_to_map_pos(&x, &y, r);
398  if (fair_map_copy(ptarget, x, y, psource, &geometry, -1)) {
399  return true;
400  }
401  }
402 
403  // Try hard placement.
404  r = fc_rand(MAP_INDEX_SIZE);
405  for (i = (r + 1) % MAP_INDEX_SIZE; i != r; i = (i + 1) % MAP_INDEX_SIZE) {
406  index_to_map_pos(&x, &y, i);
407  if (fair_map_copy(ptarget, x, y, psource, &geometry, -1)) {
408  return true;
409  }
410  }
411 
412  // Impossible placement.
413  return false;
414 }
415 
421  struct fair_tile *ptarget, int tx, int ty, struct fair_tile *psource,
422  const struct iter_index *outwards_indices, int startpos_team_id)
423 {
424  struct fair_geometry_data geometry;
425  int i, x, y;
426 
427  fair_geometry_rand(&geometry);
428 
429  /* Iterate positions, beginning by a random index of the outwards
430  * indices. */
433  x = tx + outwards_indices[i].dx;
434  y = ty + outwards_indices[i].dy;
435  if (normalize_map_pos(&(wld.map), &x, &y)
436  && fair_map_copy(ptarget, x, y, psource, &geometry,
437  startpos_team_id)) {
438  return true;
439  }
440  }
441 
442  // Impossible placement.
443  return false;
444 }
445 
450 {
451  struct fair_tile *pftile, *pftile2;
452  struct extra_type **r;
453  int i, j;
454 
455  for (i = 0; i < MAP_INDEX_SIZE; i++) {
456  pftile = pmap + i;
457  if (pftile->flags == FTF_NONE || pftile->flags & FTF_NO_RESOURCE
458  || fc_rand(1000) >= wld.map.server.riches) {
459  continue;
460  }
461 
462  if (pftile->flags & FTF_OCEAN) {
463  bool land_around = false;
464 
465  for (j = 0; j < wld.map.num_valid_dirs; j++) {
466  pftile2 = fair_map_tile_step(pmap, pftile, wld.map.valid_dirs[j]);
467  if (pftile2 != nullptr && pftile2->flags & FTF_ASSIGNED
468  && !(pftile2->flags & FTF_OCEAN)) {
469  land_around = true;
470  break;
471  }
472  }
473  if (!land_around) {
474  continue;
475  }
476  }
477 
478  j = 0;
479  for (r = pftile->pterrain->resources; *r != nullptr; r++) {
480  if (fc_rand(++j) == 0) {
481  pftile->presource = *r;
482  }
483  }
484  /* Note that 'pftile->presource' might be nullptr if there is no suitable
485  * resource for the terrain. */
486  if (pftile->presource != nullptr) {
487  pftile->flags =
488  static_cast<fair_tile_flag>(pftile->flags | FTF_NO_RESOURCE);
489  for (j = 0; j < wld.map.num_valid_dirs; j++) {
490  pftile2 = fair_map_tile_step(pmap, pftile, wld.map.valid_dirs[j]);
491  if (pftile2 != nullptr) {
492  pftile2->flags =
493  static_cast<fair_tile_flag>(pftile2->flags | FTF_NO_RESOURCE);
494  }
495  }
496 
497  BV_SET(pftile->extras, extra_index(pftile->presource));
498  }
499  }
500 }
501 
505 static void fair_map_make_huts(struct fair_tile *pmap)
506 {
507  struct fair_tile *pftile;
508  struct tile *pvtile = tile_virtual_new(nullptr);
509  struct extra_type *phut;
510  int i, j, k;
511 
512  for (i = wld.map.server.huts * map_num_tiles() / 1000, j = 0;
513  i > 0 && j < map_num_tiles() * 2; j++) {
514  k = fc_rand(MAP_INDEX_SIZE);
515  pftile = pmap + k;
516  while (pftile->flags & FTF_NO_HUT) {
517  pftile++;
518  if (pftile - pmap == MAP_INDEX_SIZE) {
519  pftile = pmap;
520  }
521  if (pftile - pmap == k) {
522  break;
523  }
524  }
525  if (pftile->flags & FTF_NO_HUT) {
526  break; // Cannot make huts anymore.
527  }
528 
529  i--;
530  if (pftile->pterrain == nullptr) {
531  continue; // Not an used tile.
532  }
533 
534  pvtile->index = pftile - pmap;
535  tile_set_terrain(pvtile, pftile->pterrain);
536  tile_set_resource(pvtile, pftile->presource);
537  pvtile->extras = pftile->extras;
538 
539  phut = rand_extra_for_tile(pvtile, EC_HUT, true);
540  if (phut != nullptr) {
541  tile_add_extra(pvtile, phut);
542  pftile->extras = pvtile->extras;
543  pftile->flags =
544  static_cast<fair_tile_flag>(pftile->flags | FTF_HAS_HUT);
545  square_iterate(&(wld.map), index_to_tile(&(wld.map), pftile - pmap), 3,
546  ptile)
547  {
548  pmap[tile_index(ptile)].flags = static_cast<fair_tile_flag>(
549  pmap[tile_index(ptile)].flags | FTF_NO_HUT);
550  }
552  }
553  }
554 
555  tile_virtual_destroy(pvtile);
556 }
557 
561 static struct fair_tile *fair_map_island_new(int size, int startpos_num)
562 {
563  enum {
564  FT_GRASSLAND,
565  FT_FOREST,
566  FT_DESERT,
567  FT_HILL,
568  FT_MOUNTAIN,
569  FT_SWAMP,
570  FT_COUNT
571  };
572  struct {
573  int count;
574  enum mapgen_terrain_property target;
575  enum mapgen_terrain_property prefer;
576  enum mapgen_terrain_property avoid;
577  } terrain[FT_COUNT] = {
578  {0, MG_TEMPERATE, MG_GREEN, MG_MOUNTAINOUS},
579  {0, MG_FOLIAGE, MG_TEMPERATE, MG_UNUSED},
580  {0, MG_DRY, MG_TEMPERATE, MG_GREEN},
581  {0, MG_MOUNTAINOUS, MG_GREEN, MG_UNUSED},
582  {0, MG_MOUNTAINOUS, MG_UNUSED, MG_GREEN},
583  {0, MG_WET, MG_TEMPERATE, MG_FOLIAGE},
584  };
585 
586  struct fair_tile *pisland;
587  struct fair_tile *land_tiles[1000];
588  struct fair_tile *pftile, *pftile2, *pftile3;
589  int fantasy;
590  const int sea_around_island =
591  (startpos_num > 0 ? CITY_MAP_DEFAULT_RADIUS : 1);
592  const int sea_around_island_sq =
593  (startpos_num > 0 ? CITY_MAP_DEFAULT_RADIUS_SQ : 2);
594  int i, j, k;
595 
596  size = CLIP(startpos_num, size, ARRAY_SIZE(land_tiles));
597  fantasy = (size * 2) / 5;
598  pisland = new fair_tile[MAP_INDEX_SIZE]();
599  pftile = fair_map_pos_tile(pisland, wld.map.xsize / 2, wld.map.ysize / 2);
600  fc_assert(!fair_map_tile_border(pisland, pftile, sea_around_island));
601  pftile->flags = static_cast<fair_tile_flag>(pftile->flags | FTF_ASSIGNED);
602  land_tiles[0] = pftile;
603  i = 1;
604 
605  log_debug("Generating an island with %d land tiles [fantasy=%d].", size,
606  fantasy);
607 
608  // Make land.
609  while (i < fantasy) {
610  pftile = land_tiles[fc_rand(i)];
611 
612  for (j = 0; j < wld.map.num_valid_dirs; j++) {
613  pftile2 = fair_map_tile_step(pisland, pftile, wld.map.valid_dirs[j]);
614  fc_assert(pftile2 != nullptr);
615  if (fair_map_tile_border(pisland, pftile2, sea_around_island)) {
616  continue;
617  }
618 
619  if (pftile2->flags == FTF_NONE) {
620  pftile2->flags = FTF_ASSIGNED;
621  land_tiles[i++] = pftile2;
622  if (i == fantasy) {
623  break;
624  }
625  }
626  }
627  }
628  while (i < size) {
629  pftile = land_tiles[i - fc_rand(fantasy) - 1];
630  pftile2 = fair_map_tile_step(
631  pisland, pftile,
633  fc_assert(pftile2 != nullptr);
634  if (fair_map_tile_border(pisland, pftile2, sea_around_island)) {
635  continue;
636  }
637 
638  if (pftile2->flags == FTF_NONE) {
639  pftile2->flags = FTF_ASSIGNED;
640  land_tiles[i++] = pftile2;
641  }
642  }
643  fc_assert(i == size);
644 
645  // Add start positions.
646  for (i = 0; i < startpos_num;) {
647  pftile = land_tiles[fc_rand(size - fantasy)];
648  fc_assert(pftile->flags & FTF_ASSIGNED);
649  if (!(pftile->flags & FTF_STARTPOS)) {
650  pftile->flags =
651  static_cast<fair_tile_flag>(pftile->flags | FTF_STARTPOS);
652  i++;
653  }
654  }
655 
656  // Make terrain.
657  terrain[FT_GRASSLAND].count = size - startpos_num;
658  terrain[FT_FOREST].count = ((forest_pct + jungle_pct) * size) / 100;
659  terrain[FT_DESERT].count = (desert_pct * size) / 100;
660  terrain[FT_HILL].count = (mountain_pct * size) / 150;
661  terrain[FT_MOUNTAIN].count = (mountain_pct * size) / 300;
662  terrain[FT_SWAMP].count = (swamp_pct * size) / 100;
663 
664  j = FT_GRASSLAND;
665  for (i = 0; i < size; i++) {
666  pftile = land_tiles[i];
667 
668  if (pftile->flags & FTF_STARTPOS) {
669  pftile->pterrain = pick_terrain_by_flag(TER_STARTER);
670  } else {
671  if (terrain[j].count == 0 || fc_rand(100) < 70) {
672  do {
673  j = fc_rand(FT_COUNT);
674  } while (terrain[j].count == 0);
675  }
676  pftile->pterrain = pick_terrain(terrain[j].target, terrain[j].prefer,
677  terrain[j].avoid);
678  terrain[j].count--;
679  }
680  }
681 
682  // Make sea around the island.
683  for (i = 0; i < size; i++) {
685  index_to_tile(&(wld.map), land_tiles[i] - pisland),
686  sea_around_island_sq, ptile)
687  {
688  pftile = pisland + tile_index(ptile);
689 
690  if (pftile->flags == FTF_NONE) {
691  pftile->flags = FTF_OCEAN;
692  // No ice around island
693  pftile->pterrain =
696  false);
697  if (startpos_num > 0) {
698  pftile->flags =
699  static_cast<fair_tile_flag>(pftile->flags | FTF_ASSIGNED);
700  }
701  }
702  }
704  }
705 
706  // Make rivers.
707  if (river_type_count > 0) {
708  struct extra_type *priver;
709  struct fair_tile *pend;
710  int n = ((river_pct * size * wld.map.num_cardinal_dirs
712  / 200);
713  int length_max = 3, length, l;
714  enum direction8 dir;
715  int extra_idx;
716  int dirs_num;
717  bool cardinal_only;
718  bool connectable_river_around, ocean_around;
719  int river_around;
720  bool finished;
721 
722  for (i = 0; i < n; i++) {
723  pftile = land_tiles[fc_rand(size)];
724  if (!terrain_has_flag(pftile->pterrain, TER_CAN_HAVE_RIVER)) {
725  continue;
726  }
727 
729  extra_idx = extra_index(priver);
730  if (BV_ISSET(pftile->extras, extra_idx)) {
731  continue;
732  }
733  cardinal_only = is_cardinal_only_road(priver);
734 
735  river_around = 0;
736  connectable_river_around = false;
737  ocean_around = false;
738  for (j = 0; j < wld.map.num_valid_dirs; j++) {
739  pftile2 = fair_map_tile_step(pisland, pftile, wld.map.valid_dirs[j]);
740  if (pftile2 == nullptr) {
741  continue;
742  }
743 
744  if (pftile2->flags & FTF_OCEAN) {
745  ocean_around = true;
746  break;
747  } else if (BV_ISSET(pftile2->extras, extra_idx)) {
748  river_around++;
749  if (!cardinal_only || is_cardinal_dir(wld.map.valid_dirs[j])) {
750  connectable_river_around = true;
751  }
752  }
753  }
754  if (ocean_around || river_around > 1
755  || (river_around == 1 && !connectable_river_around)) {
756  continue;
757  }
758 
759  if (connectable_river_around) {
760  log_debug("Adding river at (%d, %d)",
761  index_to_map_pos_x(pftile - pisland),
762  index_to_map_pos_y(pftile - pisland));
763  BV_SET(pftile->extras, extra_idx);
764  continue;
765  }
766 
767  // Check a river in one direction.
768  pend = nullptr;
769  length = -1;
770  dir = direction8_invalid();
771  dirs_num = 0;
772  for (j = 0; j < wld.map.num_valid_dirs; j++) {
773  if (cardinal_only && !is_cardinal_dir(wld.map.valid_dirs[j])) {
774  continue;
775  }
776 
777  finished = false;
778  pftile2 = pftile;
779  for (l = 2; l < length_max; l++) {
780  pftile2 =
781  fair_map_tile_step(pisland, pftile2, wld.map.valid_dirs[j]);
782  if (pftile2 == nullptr
783  || !terrain_has_flag(pftile2->pterrain, TER_CAN_HAVE_RIVER)) {
784  break;
785  }
786 
787  river_around = 0;
788  connectable_river_around = false;
789  ocean_around = false;
790  for (k = 0; k < wld.map.num_valid_dirs; k++) {
791  if (wld.map.valid_dirs[k]
792  == DIR_REVERSE(wld.map.valid_dirs[j])) {
793  continue;
794  }
795 
796  pftile3 =
797  fair_map_tile_step(pisland, pftile2, wld.map.valid_dirs[k]);
798  if (pftile3 == nullptr) {
799  continue;
800  }
801 
802  if (pftile3->flags & FTF_OCEAN) {
803  if (!cardinal_only || is_cardinal_dir(wld.map.valid_dirs[k])) {
804  ocean_around = true;
805  }
806  } else if (BV_ISSET(pftile3->extras, extra_idx)) {
807  river_around++;
808  if (!cardinal_only || is_cardinal_dir(wld.map.valid_dirs[k])) {
809  connectable_river_around = true;
810  }
811  }
812  }
813  if (river_around > 1 && !connectable_river_around) {
814  break;
815  } else if (ocean_around || connectable_river_around) {
816  finished = true;
817  break;
818  }
819  }
820  if (finished && fc_rand(++dirs_num) == 0) {
821  dir = wld.map.valid_dirs[j];
822  pend = pftile2;
823  length = l;
824  }
825  }
826  if (pend == nullptr) {
827  continue;
828  }
829 
830  log_debug("Make river from (%d, %d) to (%d, %d) [dir=%s, length=%d]",
831  index_to_map_pos_x(pftile - pisland),
832  index_to_map_pos_y(pftile - pisland),
833  index_to_map_pos_x(pend - pisland),
834  index_to_map_pos_y(pend - pisland), direction8_name(dir),
835  length);
836  for (;;) {
837  BV_SET(pftile->extras, extra_idx);
838  length--;
839  if (pftile == pend) {
840  fc_assert(length == 0);
841  break;
842  }
843  pftile = fair_map_tile_step(pisland, pftile, dir);
844  fc_assert(pftile != nullptr);
845  }
846  }
847  }
848 
849  if (startpos_num > 0) {
850  /* Islands with start positions must have the same resources and the
851  * same huts. Other ones don't matter. */
852 
853  // Make resources.
854  if (wld.map.server.riches > 0) {
855  fair_map_make_resources(pisland);
856  }
857 
858  // Make huts.
859  if (wld.map.server.huts > 0) {
860  fair_map_make_huts(pisland);
861  }
862 
863  /* Make sure there will be no more resources and huts on assigned
864  * tiles. */
865  for (i = 0; i < MAP_INDEX_SIZE; i++) {
866  pftile = pisland + i;
867  if (pftile->flags & FTF_ASSIGNED) {
868  pftile->flags = static_cast<fair_tile_flag>(
869  pftile->flags | (FTF_NO_RESOURCE | FTF_NO_HUT));
870  }
871  }
872  }
873 
874  return pisland;
875 }
876 
881 {
882  struct terrain *deepest_ocean =
884  struct fair_tile *pmap, *pisland;
885  int playermass, islandmass1, islandmass2, islandmass3;
886  int min_island_size = wld.map.server.tinyisles ? 1 : 2;
887  int players_per_island = 1;
888  int teams_num = 0, team_players_num = 0, single_players_num = 0;
889  int i, iter = CLIP(1, 100000 / map_num_tiles(), 10);
890  bool done = false;
891 
892  teams_iterate(pteam)
893  {
894  i = player_list_size(team_members(pteam));
895  fc_assert(0 < i);
896  if (i == 1) {
897  single_players_num++;
898  } else {
899  teams_num++;
900  team_players_num += i;
901  }
902  }
904  fc_assert(team_players_num + single_players_num == player_count());
905 
906  // Take in account the 'startpos' setting.
907  if (wld.map.server.startpos == MAPSTARTPOS_DEFAULT
908  && wld.map.server.team_placement == TEAM_PLACEMENT_CONTINENT) {
909  wld.map.server.startpos = MAPSTARTPOS_ALL;
910  }
911 
912  switch (wld.map.server.startpos) {
913  case MAPSTARTPOS_2or3: {
914  bool maybe2 = (0 == player_count() % 2);
915  bool maybe3 = (0 == player_count() % 3);
916 
917  if (wld.map.server.team_placement != TEAM_PLACEMENT_DISABLED) {
918  teams_iterate(pteam)
919  {
920  i = player_list_size(team_members(pteam));
921  if (i > 1) {
922  if (0 != i % 2) {
923  maybe2 = false;
924  }
925  if (0 != i % 3) {
926  maybe3 = false;
927  }
928  }
929  }
931  }
932 
933  if (maybe3) {
934  players_per_island = 3;
935  } else if (maybe2) {
936  players_per_island = 2;
937  }
938  } break;
939  case MAPSTARTPOS_ALL:
940  if (wld.map.server.team_placement == TEAM_PLACEMENT_CONTINENT) {
941  teams_iterate(pteam)
942  {
943  i = player_list_size(team_members(pteam));
944  if (i > 1) {
945  if (players_per_island == 1) {
946  players_per_island = i;
947  } else if (i != players_per_island) {
948  /* Every team doesn't have the same number of players. Cannot
949  * consider this option. */
950  players_per_island = 1;
951  wld.map.server.team_placement = TEAM_PLACEMENT_CLOSEST;
952  break;
953  }
954  }
955  }
957  }
958  break;
959  case MAPSTARTPOS_DEFAULT:
960  case MAPSTARTPOS_SINGLE:
962  break;
963  }
964  if (players_per_island == 1) {
965  wld.map.server.startpos = MAPSTARTPOS_SINGLE;
966  }
967 
968  whole_map_iterate(&(wld.map), ptile)
969  {
970  tile_set_terrain(ptile, deepest_ocean);
971  tile_set_continent(ptile, 0);
972  BV_CLR_ALL(ptile->extras);
973  tile_set_owner(ptile, nullptr, nullptr);
974  ptile->extras_owner = nullptr;
975  }
977 
978  i = 0;
979  if (HAS_POLES) {
980  make_polar();
981 
982  whole_map_iterate(&(wld.map), ptile)
983  {
984  if (tile_terrain(ptile) != deepest_ocean) {
985  i++;
986  }
987  }
989  }
990 
991  if (wld.map.server.mapsize == MAPSIZE_PLAYER) {
992  playermass = wld.map.server.tilesperplayer - i / player_count();
993  } else {
994  playermass = ((map_num_tiles() * wld.map.server.landpercent - i)
995  / (player_count() * 100));
996  }
997  islandmass1 = (players_per_island * playermass * 7) / 10;
998  if (islandmass1 < min_island_size) {
999  islandmass1 = min_island_size;
1000  }
1001  islandmass2 = (playermass * 2) / 10;
1002  if (islandmass2 < min_island_size) {
1003  islandmass2 = min_island_size;
1004  }
1005  islandmass3 = playermass / 10;
1006  if (islandmass3 < min_island_size) {
1007  islandmass3 = min_island_size;
1008  }
1009 
1010  qDebug("Creating a map with fair island generator");
1011  log_debug("max iterations=%d", iter);
1012  log_debug("players_per_island=%d", players_per_island);
1013  log_debug("team_placement=%s",
1014  team_placement_name(wld.map.server.team_placement));
1015  log_debug("teams_num=%d, team_players_num=%d, single_players_num=%d",
1016  teams_num, team_players_num, single_players_num);
1017  log_debug("playermass=%d, islandmass1=%d, islandmass2=%d, islandmass3=%d",
1018  playermass, islandmass1, islandmass2, islandmass3);
1019 
1020  pmap = new fair_tile[MAP_INDEX_SIZE]();
1021 
1022  while (--iter >= 0) {
1023  done = true;
1024 
1025  whole_map_iterate(&(wld.map), ptile)
1026  {
1027  struct fair_tile *pftile = pmap + tile_index(ptile);
1028 
1029  if (tile_terrain(ptile) != deepest_ocean) {
1030  pftile->flags = static_cast<fair_tile_flag>(
1031  pftile->flags | (FTF_ASSIGNED | FTF_NO_HUT));
1032  adjc_iterate(&(wld.map), ptile, atile)
1033  {
1034  struct fair_tile *aftile = pmap + tile_index(atile);
1035 
1036  if (!(aftile->flags & FTF_ASSIGNED)
1037  && tile_terrain(atile) == deepest_ocean) {
1038  aftile->flags =
1039  static_cast<fair_tile_flag>(aftile->flags | FTF_OCEAN);
1040  }
1041  }
1043  }
1044  pftile->pterrain = tile_terrain(ptile);
1045  pftile->presource = tile_resource(ptile);
1046  pftile->extras = *tile_extras(ptile);
1047  }
1049 
1050  // Create main player island.
1051  log_debug("Making main island.");
1052  pisland = fair_map_island_new(islandmass1, players_per_island);
1053 
1054  log_debug("Place main islands on the map.");
1055  i = 0;
1056 
1057  if (wld.map.server.team_placement != TEAM_PLACEMENT_DISABLED
1058  && team_players_num > 0) {
1059  // Do team placement.
1060  struct iter_index
1061  outwards_indices[wld.map.num_iterate_outwards_indices];
1062  int start_x[teams_num], start_y[teams_num];
1063  int dx = 0, dy = 0;
1064  int j, k;
1065 
1066  // Build outwards_indices.
1067  memcpy(outwards_indices, wld.map.iterate_outwards_indices,
1068  sizeof(outwards_indices));
1069  switch (wld.map.server.team_placement) {
1070  case TEAM_PLACEMENT_DISABLED:
1071  fc_assert(wld.map.server.team_placement != TEAM_PLACEMENT_DISABLED);
1072  break;
1073  case TEAM_PLACEMENT_CLOSEST:
1074  case TEAM_PLACEMENT_CONTINENT:
1075  for (j = 0; j < wld.map.num_iterate_outwards_indices; j++) {
1076  // We want square distances for comparing.
1077  outwards_indices[j].dist = map_vector_to_sq_distance(
1078  outwards_indices[j].dx, outwards_indices[j].dy);
1079  }
1080  qsort(outwards_indices, wld.map.num_iterate_outwards_indices,
1081  sizeof(outwards_indices[0]), fair_team_placement_closest);
1082  break;
1083  case TEAM_PLACEMENT_HORIZONTAL:
1084  qsort(outwards_indices, wld.map.num_iterate_outwards_indices,
1085  sizeof(outwards_indices[0]), fair_team_placement_horizontal);
1086  break;
1087  case TEAM_PLACEMENT_VERTICAL:
1088  qsort(outwards_indices, wld.map.num_iterate_outwards_indices,
1089  sizeof(outwards_indices[0]), fair_team_placement_vertical);
1090  break;
1091  }
1092 
1093  // Make start point for teams.
1094  if (current_topo_has_flag(TF_WRAPX)) {
1095  dx = fc_rand(wld.map.xsize);
1096  }
1097  if (current_topo_has_flag(TF_WRAPY)) {
1098  dy = fc_rand(wld.map.ysize);
1099  }
1100  for (j = 0; j < teams_num; j++) {
1101  start_x[j] = (wld.map.xsize * (2 * j + 1)) / (2 * teams_num) + dx;
1102  start_y[j] = (wld.map.ysize * (2 * j + 1)) / (2 * teams_num) + dy;
1103  if (current_topo_has_flag(TF_WRAPX)) {
1104  start_x[j] = FC_WRAP(start_x[j], wld.map.xsize);
1105  }
1106  if (current_topo_has_flag(TF_WRAPY)) {
1107  start_y[j] = FC_WRAP(start_y[j], wld.map.ysize);
1108  }
1109  }
1110  // Randomize.
1111  array_shuffle(start_x, teams_num);
1112  array_shuffle(start_y, teams_num);
1113 
1114  j = 0;
1115  teams_iterate(pteam)
1116  {
1117  int members_count = player_list_size(team_members(pteam));
1118  int team_id;
1119  int x, y;
1120 
1121  if (members_count <= 1) {
1122  continue;
1123  }
1124  team_id = team_number(pteam);
1125 
1126  NATIVE_TO_MAP_POS(&x, &y, start_x[j], start_y[j]);
1127  qDebug("Team %d (%s) will start on (%d, %d)", team_id,
1128  team_rule_name(pteam), x, y);
1129 
1130  for (k = 0; k < members_count; k += players_per_island) {
1131  if (!fair_map_place_island_team(pmap, x, y, pisland,
1132  outwards_indices, team_id)) {
1133  qDebug("Failed to place island number %d for team %d (%s).", k,
1134  team_id, team_rule_name(pteam));
1135  done = false;
1136  break;
1137  }
1138  }
1139  if (!done) {
1140  break;
1141  }
1142  i += k;
1143  j++;
1144  }
1146 
1147  fc_assert(!done || i == team_players_num);
1148  }
1149 
1150  if (done) {
1151  // Place last player islands.
1152  for (; i < player_count(); i += players_per_island) {
1153  if (!fair_map_place_island_rand(pmap, pisland)) {
1154  qDebug("Failed to place island number %d.", i);
1155  done = false;
1156  break;
1157  }
1158  }
1159  fc_assert(!done || i == player_count());
1160  }
1161  fair_map_destroy(pisland);
1162 
1163  if (done) {
1164  log_debug("Create and place small islands on the map.");
1165  for (i = 0; i < player_count(); i++) {
1166  pisland = fair_map_island_new(islandmass2, 0);
1167  if (!fair_map_place_island_rand(pmap, pisland)) {
1168  qDebug("Failed to place small island2 number %d.", i);
1169  done = false;
1170  fair_map_destroy(pisland);
1171  break;
1172  }
1173  fair_map_destroy(pisland);
1174  }
1175  }
1176  if (done) {
1177  for (i = 0; i < player_count(); i++) {
1178  pisland = fair_map_island_new(islandmass3, 0);
1179  if (!fair_map_place_island_rand(pmap, pisland)) {
1180  qDebug("Failed to place small island3 number %d.", i);
1181  done = false;
1182  fair_map_destroy(pisland);
1183  break;
1184  }
1185  fair_map_destroy(pisland);
1186  }
1187  }
1188 
1189  if (done) {
1190  break;
1191  }
1192 
1194  pmap = new fair_tile[MAP_INDEX_SIZE]();
1195 
1196  // Decrease land mass, for better chances.
1197  islandmass1 = (islandmass1 * 99) / 100;
1198  if (islandmass1 < min_island_size) {
1199  islandmass1 = min_island_size;
1200  }
1201  islandmass2 = (islandmass2 * 99) / 100;
1202  if (islandmass2 < min_island_size) {
1203  islandmass2 = min_island_size;
1204  }
1205  islandmass3 = (islandmass3 * 99) / 100;
1206  if (islandmass3 < min_island_size) {
1207  islandmass3 = min_island_size;
1208  }
1209  }
1210 
1211  if (!done) {
1212  qDebug("Failed to create map after %d iterations.", iter);
1213  wld.map.server.generator = MAPGEN_ISLAND;
1214  return false;
1215  }
1216 
1217  // Finalize the map.
1218  for (i = 0; i < MAP_INDEX_SIZE; i++) {
1219  // Mark all tiles as assigned, for adding resources and huts.
1220  pmap[i].flags =
1221  static_cast<fair_tile_flag>(pmap[i].flags | FTF_ASSIGNED);
1222  }
1223  if (wld.map.server.riches > 0) {
1225  }
1226  if (wld.map.server.huts > 0) {
1228  }
1229 
1230  // Apply the map.
1231  log_debug("Applying the map...");
1232  whole_map_iterate(&(wld.map), ptile)
1233  {
1234  struct fair_tile *pftile = pmap + tile_index(ptile);
1235 
1236  fc_assert(pftile->pterrain != nullptr);
1237  tile_set_terrain(ptile, pftile->pterrain);
1238  ptile->extras = pftile->extras;
1239  tile_set_resource(ptile, pftile->presource);
1240  if (pftile->flags & FTF_STARTPOS) {
1241  struct startpos *psp = map_startpos_new(ptile);
1242 
1243  if (pftile->startpos_team_id != -1) {
1245  team_members(team_by_number(pftile->startpos_team_id)), pplayer)
1246  {
1247  startpos_allow(psp, nation_of_player(pplayer));
1248  }
1250  } else {
1251  startpos_allows_all(psp);
1252  }
1253  }
1254  }
1256 
1257  wld.map.server.have_resources = true;
1258  wld.map.server.have_huts = true;
1259 
1261 
1262  qDebug("Fair island map created with success!");
1263  return true;
1264 }
#define BV_CLR_ALL(bv)
Definition: bitvector.h:62
#define BV_SET(bv, bit)
Definition: bitvector.h:44
bool BV_ISSET(const BV &bv, int bit)
Definition: bitvector.h:37
#define CITY_MAP_DEFAULT_RADIUS
Definition: city.h:51
#define CITY_MAP_DEFAULT_RADIUS_SQ
Definition: city.h:55
struct extra_type * rand_extra_for_tile(struct tile *ptile, enum extra_cause cause, bool generated)
Return random extra type for given cause that is native to the tile.
Definition: extras.cpp:242
#define extra_index(_e_)
Definition: extras.h:163
static int fair_team_placement_vertical(const void *a, const void *b)
Compare two iter_index values for doing vertical team placement.
static struct fair_tile * fair_map_pos_tile(struct fair_tile *pmap, int x, int y)
Get the tile at the position ('x', 'y').
static void fair_do_symetry2(int *x, int *y)
Symetry matrix.
static void fair_map_make_resources(struct fair_tile *pmap)
Add resources on 'pmap'.
static void fair_do_iso_hex_symetry1(int *x, int *y)
Symetry matrix for hexgonal-isometric topology.
static void fair_geometry_rand(struct fair_geometry_data *data)
Push random transformations to 'data'.
void(* fair_geometry_func)(int *x, int *y)
static void fair_do_geometry(const struct fair_geometry_data *data, int *x, int *y)
Perform transformations defined into 'data' to position ('x', 'y').
static void fair_map_destroy(struct fair_tile *pmap)
Free a map.
static bool fair_map_tile_border(struct fair_tile *pmap, struct fair_tile *ptile, int dist)
Returns whether 'ptile' is at least at 'dist' tiles (in real distance) to the border.
static void fair_map_tile_pos(struct fair_tile *pmap, struct fair_tile *ptile, int *x, int *y)
Get the coordinates of tile 'ptile'.
static void fair_do_hex_symetry1(int *x, int *y)
Symetry matrix for hexagonal topologies.
static void fair_do_hex_symetry2(int *x, int *y)
Symetry matrix for hexagonal topologies.
static struct fair_tile * fair_map_tile_step(struct fair_tile *pmap, struct fair_tile *ptile, enum direction8 dir)
Get the next tile in direction 'dir'.
#define fair_do_iso_hex_symetry2
static int fair_team_placement_horizontal(const void *a, const void *b)
Compare two iter_index values for doing horizontal team placement.
static struct fair_tile * fair_map_island_new(int size, int startpos_num)
Generate a map where an island would be placed in the center.
static void fair_do_rotation(int *x, int *y)
Rotation matrix, also symetry matrix for hexagonal-isometric topology.
static bool fair_map_place_island_rand(struct fair_tile *ptarget, struct fair_tile *psource)
Attempts to copy 'psource' to 'ptarget' at a random position, with random geometric effects.
static void fair_map_make_huts(struct fair_tile *pmap)
Add huts on 'pmap'.
bool map_generate_fair_islands()
Build a map using generator 'FAIR'.
static int fair_team_placement_closest(const void *a, const void *b)
Compare two iter_index values for doing closest team placement.
static void fair_do_iso_hex_rotation(int *x, int *y)
Rotation matrix for hexgonal-isometric topology.
static bool fair_map_place_island_team(struct fair_tile *ptarget, int tx, int ty, struct fair_tile *psource, const struct iter_index *outwards_indices, int startpos_team_id)
Attempts to copy 'psource' to 'ptarget' as close as possible of position 'x', 'y' for players of the ...
static bool fair_map_copy(struct fair_tile *ptarget, int tx, int ty, struct fair_tile *psource, const struct fair_geometry_data *data, int startpos_team_id)
Copy 'psource' on 'ptarget' at position ('tx', 'ty'), performing transformations defined into 'data'.
static void fair_do_symetry1(int *x, int *y)
Symetry matrix.
static void fair_do_hex_rotation(int *x, int *y)
Rotation matrix for hexgonal topology.
fair_tile_flag
Fair island generator types.
@ FTF_NONE
@ FTF_NO_RESOURCE
@ FTF_HAS_HUT
@ FTF_ASSIGNED
@ FTF_OCEAN
@ FTF_STARTPOS
@ FTF_NO_HUT
#define MG_UNUSED
Definition: fracture_map.h:29
struct world wld
Definition: game.cpp:48
#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
int map_num_tiles()
Returns the total number of (real) positions (or tiles) on the map.
Definition: map.cpp:954
bool startpos_allows_all(const struct startpos *psp)
Returns TRUE if any nation can start here.
Definition: map.cpp:1439
int map_vector_to_sq_distance(int dx, int dy)
Return the sq_distance for a given vector.
Definition: map.cpp:583
struct startpos * map_startpos_new(struct tile *ptile)
Create a new start position at the given tile and return it.
Definition: map.cpp:1531
bool is_cardinal_dir(enum direction8 dir)
Returns TRUE iff the given direction is a cardinal one.
Definition: map.cpp:1255
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Return the tile for the given index position.
Definition: map.cpp:429
bool startpos_allow(struct startpos *psp, struct nation_type *pnation)
Allow the nation to start at the start position.
Definition: map.cpp:1385
bool normalize_map_pos(const struct civ_map *nmap, int *x, int *y)
If the position is real, it will be normalized and TRUE will be returned.
Definition: map.cpp:919
#define current_topo_has_flag(flag)
Definition: map.h:37
#define native_pos_to_index(nat_x, nat_y)
Definition: map.h:108
#define adjc_iterate_end
Definition: map.h:358
static int index_to_map_pos_y(int mindex)
Definition: map.h:616
#define MAP_INDEX_SIZE
Definition: map.h:91
#define square_iterate(nmap, center_tile, radius, tile_itr)
Definition: map.h:312
#define MAP_IS_ISOMETRIC
Definition: map.h:32
#define adjc_iterate(nmap, center_tile, itr_tile)
Definition: map.h:351
#define MAP_TO_NATIVE_POS(pnat_x, pnat_y, map_x, map_y)
Definition: map.h:123
#define NATIVE_TO_MAP_POS(pmap_x, pmap_y, nat_x, nat_y)
Definition: map.h:118
#define square_iterate_end
Definition: map.h:315
#define circle_iterate(nmap, center_tile, sq_radius, tile_itr)
Definition: map.h:322
static int index_to_map_pos_x(int mindex)
Definition: map.h:607
#define whole_map_iterate(_map, _tile)
Definition: map.h:473
#define DIR_REVERSE(dir)
Definition: map.h:487
#define index_to_native_pos(pnat_x, pnat_y, mindex)
Definition: map.h:111
#define whole_map_iterate_end
Definition: map.h:480
#define index_to_map_pos(pmap_x, pmap_y, mindex)
Definition: map.h:164
#define circle_iterate_end
Definition: map.h:325
#define DIRSTEP(dest_x, dest_y, dir)
Definition: map.h:170
@ MAPSIZE_PLAYER
Definition: map_types.h:36
@ MAPGEN_ISLAND
Definition: map_types.h:46
@ 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 jungle_pct
Definition: mapgen.cpp:97
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
int swamp_pct
Definition: mapgen.cpp:95
int river_pct
Definition: mapgen.cpp:98
#define HAS_POLES
Definition: mapgen.h:15
#define pmap(_tile)
struct terrain * pick_ocean(int depth, bool frozen)
Picks an ocean terrain to match the given depth.
struct terrain * pick_terrain_by_flag(enum terrain_flag_id flag)
Return a random terrain that has the specified flag.
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.
struct nation_type * nation_of_player(const struct player *pplayer)
Return the nation of a player.
Definition: nation.cpp:419
int player_count()
Return the number of players.
Definition: player.cpp:739
#define player_list_iterate(playerlist, pplayer)
Definition: player.h:541
#define player_list_iterate_end
Definition: player.h:543
#define fc_rand(_size)
Definition: rand.h:16
bool is_cardinal_only_road(const struct extra_type *pextra)
Is extra cardinal only road.
Definition: road.cpp:421
void array_shuffle(int *array, int n)
Randomize the elements of an array using the Fisher-Yates shuffle.
Definition: shared.cpp:1228
#define CLIP(lower, current, upper)
Definition: shared.h:51
#define ARRAY_SIZE(x)
Definition: shared.h:79
#define FC_WRAP(value, range)
Definition: shared.h:59
size_t size
Definition: specvec.h:64
int xsize
Definition: map_types.h:73
int ysize
Definition: map_types.h:73
enum direction8 valid_dirs[8]
Definition: map_types.h:69
int num_iterate_outwards_indices
Definition: map_types.h:72
int num_cardinal_dirs
Definition: map_types.h:70
int num_valid_dirs
Definition: map_types.h:70
struct iter_index * iterate_outwards_indices
Definition: map_types.h:71
enum direction8 cardinal_dirs[8]
Definition: map_types.h:69
struct civ_map::@39::@41 server
fair_geometry_func transform[4]
bv_extras extras
struct terrain * pterrain
enum fair_tile_flag flags
int startpos_team_id
struct extra_type * presource
int dist
Definition: city.h:83
int dx
Definition: city.h:83
int dy
Definition: city.h:83
struct extra_type ** resources
Definition: terrain.h:190
Definition: tile.h:42
int index
Definition: tile.h:43
bv_extras extras
Definition: tile.h:47
struct civ_map map
Definition: world_object.h:21
struct team * team_by_number(const int team_id)
Return struct team pointer for the given team index.
Definition: team.cpp:373
const char * team_rule_name(const struct team *pteam)
Returns the name (untranslated) of the team.
Definition: team.cpp:383
int team_number(const struct team *pteam)
Return the team index/number/id.
Definition: team.cpp:364
const struct player_list * team_members(const struct team *pteam)
Returns the member list of the team.
Definition: team.cpp:427
#define teams_iterate_end
Definition: team.h:76
#define teams_iterate(_pteam)
Definition: team.h:71
#define TERRAIN_OCEAN_DEPTH_MINIMUM
Definition: terrain.h:233
#define TERRAIN_OCEAN_DEPTH_MAXIMUM
Definition: terrain.h:234
#define terrain_has_flag(terr, flag)
Definition: terrain.h:260
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
void tile_virtual_destroy(struct tile *vtile)
Frees all memory used by the virtual tile, including freeing virtual units in the tile's unit list an...
Definition: tile.cpp:1051
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_resource(struct tile *ptile, struct extra_type *presource)
Set the given resource at the specified tile.
Definition: tile.cpp:355
void tile_set_continent(struct tile *ptile, Continent_id val)
Set the continent ID of the tile.
Definition: tile.cpp:388
struct tile * tile_virtual_new(const struct tile *ptile)
Returns a virtual tile.
Definition: tile.cpp:997
#define tile_index(_pt_)
Definition: tile.h:70
#define tile_resource(_tile)
Definition: tile.h:84
#define tile_terrain(_tile)
Definition: tile.h:93
static const bv_extras * tile_extras(const struct tile *ptile)
Definition: tile.h:102