[Freeciv-Dev] (PR#10201) PATCH: generator characteristics evolution, bes
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: |
undisclosed-recipients: ; |
Subject: |
[Freeciv-Dev] (PR#10201) PATCH: generator characteristics evolution, best handled temperature and relief. |
From: |
"Marcelo Burda" <mburda@xxxxxxxxx> |
Date: |
Wed, 22 Sep 2004 02:34:23 -0700 |
Reply-to: |
rt@xxxxxxxxxxx |
<URL: http://rt.freeciv.org/Ticket/Display.html?id=10201 >
LAST CHANGES
A lot
initialize wetness and rivers are joined to the generalized
characteristic code.
the charcateristic are finished, evidently this need tuning but it is
ok for now.
diff -ruN -Xfreeciv/diff_ignore freeciv/common/map.h freeciv_/common/map.h
--- freeciv/common/map.h 2004-09-20 18:42:30.000000000 +0200
+++ freeciv_/common/map.h 2004-09-22 08:42:36.000000000 +0200
@@ -536,6 +536,30 @@
#define cardinal_adjc_dir_iterate_end adjc_dirlist_iterate_end
+/****************************************************************************
+ This iterator behaves like adjc_iterate or cardinal_adjc_iterate depending
+ on the value of card_only.
+****************************************************************************/
+#define variable_adjc_iterate(center_x, center_y, x_itr, y_itr, card_only) \
+{ \
+ enum direction8 *_dirlist; \
+ int _total; \
+ \
+ if (card_only) { \
+ _dirlist = map.cardinal_dirs; \
+ _total = map.num_cardinal_dirs; \
+ } else { \
+ _dirlist = map.valid_dirs; \
+ _total = map.num_valid_dirs; \
+ } \
+ \
+ adjc_dirlist_iterate(center_x, center_y, x_itr, y_itr, \
+ _dir, _dirlist, _total) {
+
+#define variable_adjc_iterate_end \
+ } adjc_dirlist_iterate_end; \
+}
+
/* Iterate through all tiles adjacent to a tile using the given list of
* directions. dir_itr is the directional value, (center_x, center_y) is
* the center tile (which must be normalized), and (x_itr, y_itr) is the
diff -ruN -Xfreeciv/diff_ignore freeciv/common/terrain.c
freeciv_/common/terrain.c
--- freeciv/common/terrain.c 2004-09-09 23:32:20.000000000 +0200
+++ freeciv_/common/terrain.c 2004-09-22 08:42:36.000000000 +0200
@@ -131,31 +131,6 @@
}
/****************************************************************************
- This iterator behaves like adjc_iterate or cardinal_adjc_iterate depending
- on the value of card_only.
-****************************************************************************/
-#define variable_adjc_iterate(center_x, center_y, x_itr, y_itr, card_only) \
-{ \
- enum direction8 *_dirlist; \
- int _total; \
- \
- if (card_only) { \
- _dirlist = map.cardinal_dirs; \
- _total = map.num_cardinal_dirs; \
- } else { \
- _dirlist = map.valid_dirs; \
- _total = map.num_valid_dirs; \
- } \
- \
- adjc_dirlist_iterate(center_x, center_y, x_itr, y_itr, \
- _dir, _dirlist, _total) {
-
-#define variable_adjc_iterate_end \
- } adjc_dirlist_iterate_end; \
-}
-
-
-/****************************************************************************
Returns TRUE iff any adjacent tile contains the given terrain.
****************************************************************************/
bool is_terrain_near_tile(int map_x, int map_y, Terrain_type_id t)
Les fichiers binaires freeciv/manual/civmanual et freeciv_/manual/civmanual
sont différents.
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/characteristics.c
freeciv_/server/generator/characteristics.c
--- freeciv/server/generator/characteristics.c 1970-01-01 01:00:00.000000000
+0100
+++ freeciv_/server/generator/characteristics.c 2004-09-22 11:30:43.000000000
+0200
@@ -0,0 +1,900 @@
+/**********************************************************************
+ Copyright (C) 1996-2004 The Freeciv Project Team
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+***********************************************************************/
+#include "config.h"
+#include "log.h"
+#include "map.h"
+#include "rand.h"
+
+#include "utilities.h"
+#include "characteristics.h"
+#include "height_map.h"
+#include "mapgen_topology.h"
+
+#define RIVERS_MAXTRIES 32767
+enum river_map_type {RS_BLOCKED = 0, RS_RIVER = 1};
+
+static characteristic_type *characteristic_map;
+
+characteristic_type CM_TRUE, CM_FALSE;
+characteristic_type CM_FLAT, CM_HILLY, CM_ABRUPT,
+ CM_NFLAT;
+characteristic_type CM_FROZEN, CM_COLD, CM_TEMPERATE, CM_TROPICAL,
+ CM_NFROZEN, CM_ALL, CM_NHOT, CM_HOT;
+characteristic_type CM_OCEANIC, CM_WET, CM_MEDIUM, CM_DRY,
+ CM_NWET, CM_NDRY;
+characteristic_type CM_RIVER;
+/**************************************************************************
+ return TRUE if initialized
+*************************************************************************/
+bool characteristics_are_initialized(void)
+{
+ return characteristic_map != NULL;
+}
+
+/****************************************************************************
+ create the map and initialize CM_XXX
+****************************************************************************/
+void create_characteristics(void)
+{
+ assert( !characteristics_are_initialized());
+ characteristic_map = fc_malloc (sizeof(characteristic_type) * MAX_MAP_INDEX);
+ whole_map_iterate_index(i) {
+ BV_CLR_ALL(characteristic_map[i]);
+ BV_SET(characteristic_map[i], CB_TRUE);
+ }whole_map_iterate_index_end;
+
+
+ BV_CLR_ALL(CM_TRUE);
+ BV_SET(CM_TRUE, CB_TRUE);
+ BV_CLR_ALL(CM_FALSE);
+
+ /* initialize constant values of relief */
+ BV_CLR_ALL(CM_FLAT);
+ BV_SET(CM_FLAT, CB_FLAT);
+ BV_CLR_ALL(CM_HILLY);
+ BV_SET(CM_HILLY, CB_HILLY);
+ BV_CLR_ALL(CM_ABRUPT);
+ BV_SET(CM_ABRUPT, CB_ABRUPT);
+ BV_CLR_ALL(CM_NFLAT);
+ BV_SET(CM_NFLAT, CB_HILLY);
+ BV_SET(CM_NFLAT, CB_ABRUPT);
+
+ /* inizialize constant value of temperature */
+ BV_CLR_ALL(CM_FROZEN);
+ BV_SET(CM_FROZEN, CB_FROZEN);
+ BV_CLR_ALL(CM_COLD);
+ BV_SET(CM_COLD, CB_COLD);
+ BV_CLR_ALL(CM_TEMPERATE);
+ BV_SET(CM_TEMPERATE, CB_TEMPERATE);
+ BV_CLR_ALL(CM_TROPICAL);
+ BV_SET(CM_TROPICAL, CB_TROPICAL);
+
+ BV_CLR_ALL(CM_NFROZEN);
+ BV_SET(CM_NFROZEN, CB_COLD);
+ BV_SET(CM_NFROZEN, CB_TEMPERATE);
+ BV_SET(CM_NFROZEN, CB_TROPICAL);
+
+ BV_CLR_ALL(CM_ALL);
+ BV_SET(CM_ALL, CB_FROZEN);
+ BV_SET(CM_ALL, CB_COLD);
+ BV_SET(CM_ALL, CB_TEMPERATE);
+ BV_SET(CM_ALL, CB_TROPICAL);
+
+ BV_CLR_ALL(CM_NHOT);
+ BV_SET(CM_NHOT, CB_FROZEN);
+ BV_SET(CM_NHOT, CB_COLD);
+
+ BV_CLR_ALL(CM_HOT);
+ BV_SET(CM_HOT, CB_TEMPERATE);
+ BV_SET(CM_HOT, CB_TROPICAL);
+
+ BV_CLR_ALL(CM_OCEANIC);
+ BV_SET(CM_OCEANIC, CB_OCEANIC);
+ BV_CLR_ALL(CM_WET);
+ BV_SET(CM_WET, CB_WET);
+ BV_CLR_ALL(CM_MEDIUM);
+ BV_SET(CM_MEDIUM, CB_MEDIUM);
+ BV_CLR_ALL(CM_DRY);
+ BV_SET(CM_DRY, CB_DRY);
+
+ BV_CLR_ALL(CM_NWET);
+ BV_SET(CM_NWET, CB_MEDIUM);
+ BV_SET(CM_NWET, CB_DRY);
+
+ BV_CLR_ALL(CM_NDRY);
+ BV_SET(CM_NDRY, CB_MEDIUM);
+ BV_SET(CM_NDRY, CB_WET);
+
+ BV_CLR_ALL(CM_RIVER);
+ BV_SET(CM_RIVER, CB_RIVER);
+
+}
+
+/****************************************************************************
+ Free the map
+****************************************************************************/
+void destroy_characteristics(void)
+{
+ assert(characteristics_are_initialized());
+ free(characteristic_map);
+ characteristic_map = NULL;
+}
+/***************************************************************************
+ Test the characteristic of a index position on map
+ ***************************************************************************/
+
+bool is_characteristic(int i, characteristic_type mask )
+{
+ return BV_CHECK_MASK(characteristic_map[i], mask);
+}
+
+/******************************************************************
+ Return the number of tiles adjacent to the given place with the right
+ characteristic mask.
+ ******************************************************************/
+int count_characteristic_near(int i, bool cardinal_only, bool percentage
+ ,characteristic_type mask)
+{
+ int count = 0, total = 0, x, y;
+
+ index_to_map_pos(&x, &y, i);
+ variable_adjc_iterate(x, y, x1, y1, cardinal_only) {
+ if (is_characteristic(map_pos_to_index(x1,y1), mask)) {
+ count++;
+ }
+ total++;
+ } variable_adjc_iterate_end;
+
+ if (percentage) {
+ count = count * 100 / total;
+ }
+ return count;
+}
+/****************************************************************************
+ set all tiles in placed_map when this has the right CM_XXX mask
+****************************************************************************/
+static void set_all_mask_placed(characteristic_type mask)
+{
+ whole_map_iterate(x, y) {
+ if (is_characteristic(map_pos_to_index(x,y),mask)) {
+ map_set_placed(x, y);
+ }
+ } whole_map_iterate_end;
+}
+
+/*************************************************************************
+ set CB_OCEANIC in thiles will be oceans
+ ************************************************************************/
+void characteristics_initialize_shores(void)
+{
+ if (HAS_POLES) {
+ normalize_hmap_poles();
+ }
+ hmap_shore_level = (hmap_max_level * (100 - map.landpercent)) / 100;
+ whole_map_iterate_index(i) {
+ if (height_map[i] < hmap_shore_level) {
+ BV_SET(characteristic_map[i], CB_OCEANIC);
+ }
+ } whole_map_iterate_index_end;
+ if (HAS_POLES) {
+ renormalize_hmap_poles();
+ }
+}
+
+/*************************************************************************
+ if separatepoles is set, return false if this tile has to keep ocean
+************************************************************************/
+static bool ok_for_separate_poles(int index)
+{
+ int x, y;
+ if (!map.separatepoles) {
+ return TRUE;
+ }
+ index_to_map_pos(&x, &y, index);
+ adjc_iterate(x, y, x1, y1) {
+ if(!is_characteristic(map_pos_to_index(x1, y1), CM_OCEANIC) &&
+ (map_colatitude(x1, y1) > 2 * ICE_BASE_LEVEL)) {
+ return FALSE;
+ }
+ } adjc_iterate_end;
+ return TRUE;
+}
+
+/****************************************************************************
+ Place untextured land at the poles. This is used by generators 1 and 5
+ on tiles-sets with not forzen oceans
+****************************************************************************/
+void characteristics_initialize_extra_polar_land(void)
+{
+ whole_map_iterate_index(i) {
+ if ((colatitude(i) <= 2 * ICE_BASE_LEVEL) &&
+ ok_for_separate_poles(i)) {
+ BV_CLR(characteristic_map[i], CB_OCEANIC);
+ }
+ } whole_map_iterate_index_end;
+}
+
+/**************************************************************************
+ we don't want huge flat areas,
+ so we put in a hill here and there, where it gets too flat
+
+ Return TRUE if the terrain at the given map position is too flat. This
+ means that all the terrain for 2 squares around it are only flat.
+****************************************************************************/
+static bool terrain_is_too_flat(int index, int thill, int my_height)
+{
+ int higher_than_me = 0, x, y;
+
+ index_to_map_pos(&x, &y, index);
+ square_iterate(x, y, 2, x1, y1) {
+ if (hmap(x1, y1) > thill) {
+ return FALSE;
+ }
+ if (hmap(x1, y1) > my_height) {
+ if (map_distance(x, y, x1, y1) == 1) {
+ return FALSE;
+ }
+ if (++higher_than_me > 2) {
+ return FALSE;
+ }
+ }
+ } square_iterate_end;
+
+ if ((thill - hmap_shore_level) * higher_than_me >
+ (my_height - hmap_shore_level) * 4) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**************************************************************************
+ we don't want huge areas of hill/mountains,
+ so we put in a plains here and there, where it gets too heigh
+
+ Return TRUE if the terrain at the given map position is too heigh.
+****************************************************************************/
+static bool terrain_is_too_high(int index, int thill, int my_height)
+{
+ int x, y;
+
+ index_to_map_pos(&x, &y, index);
+ square_iterate(x, y, 1, x1, y1) {
+ if (hmap(x1, y1) + (hmap_max_level - hmap_mountain_level) / 5 < thill) {
+ return FALSE;
+ }
+ } square_iterate_end;
+ return TRUE;
+}
+
+/**************************************************************************
+ make_relief() will convert all squares that are higher than thill to
+ mountains and hills. Note that thill will be adjusted according to
+ the map.steepness value, so increasing map.steepness will result in
+ more hilly and abrupts maps.
+**************************************************************************/
+void characteristics_initialize_relief(void)
+{
+ /* Calculate the mountain level. map.mountains specifies the percentage
+ * of land that is turned into hills and mountains. */
+ hmap_mountain_level = ((hmap_max_level - hmap_shore_level)
+ * (100 - map.steepness)) / 100 + hmap_shore_level;
+
+ whole_map_iterate_index(i) {
+ if (!is_characteristic(i, CM_OCEANIC) &&
+ ((hmap_mountain_level < height_map[i] &&
+ (myrand(10) > 5
+ || !terrain_is_too_high(i, hmap_mountain_level, height_map[i])))
+ || terrain_is_too_flat(i, hmap_mountain_level, height_map[i]))) {
+ /* Randomly place hills and mountains on "high" tiles. */
+ if (myrand(100) > 70) {
+ BV_SET(characteristic_map[i], CB_ABRUPT);
+ } else {
+ BV_SET(characteristic_map[i], CB_HILLY);
+ }
+ } else {
+ BV_SET(characteristic_map[i], CB_FLAT);
+ }
+ } whole_map_iterate_index_end;
+}
+
+/***************************************************************************
+ * create_tmap initialize the temperature_map
+ * if arg is FALSE, create a dumy tmap == map_colattitude
+ * to be used if hmap or oceans are not placed gen 2-4
+ ***************************************************************************/
+void characteristics_initialize_temperature(bool real)
+{
+ int temperature[MAX_MAP_INDEX];
+
+ whole_map_iterate_index(i) {
+
+ /* the base temperature is equal to base map_colatitude */
+ int t = colatitude(i) ;
+ if (!real) {
+ temperature[i] = t;
+ } else {
+ /* height land can be 30% collest */
+ float height = - 0.3 * MAX(0, height_map[i] - hmap_shore_level)
+ / (hmap_max_level - hmap_shore_level);
+ /* near ocean temperature can be 15 % more "temperate" */
+ float temperate = 0.15 * (map.temperature / 100 - t / MAX_COLATITUDE) *
+ 2 * MIN (50 ,
+ count_characteristic_near(i, FALSE, TRUE, CM_OCEANIC)) /
+ 100;
+
+ temperature[i] = t * (1.0 + temperate) * (1.0 + height);
+ }
+ } whole_map_iterate_index_end;
+ /* adjust to get well sizes frequencies */
+ /* Notice: if colatitude is load from a scenario never call adjust has
+ scenario maybe has a odd colatitude ditribution and adjust will
+ brack it */
+ adjust_int_map(temperature, MAX_COLATITUDE);
+ /* now simplify to 4 base values */
+ whole_map_iterate_index(i) {
+ int t = temperature[i];
+
+ /* first if is a hack to avoid some ugly effect,
+ TODO: think if there is a best way, veriffy off by one in colatitude */
+ if (colatitude(i) < 2 * ICE_BASE_LEVEL) {
+ BV_SET(characteristic_map[i], CB_FROZEN);
+ }
+
+ else if (t >= TROPICAL_LEVEL ) {
+ BV_SET(characteristic_map[i], CB_TROPICAL);
+ } else if (t >= COLD_LEVEL) {
+ BV_SET(characteristic_map[i], CB_TEMPERATE);
+ } else if (t >= 2 * ICE_BASE_LEVEL) {
+ BV_SET(characteristic_map[i], CB_COLD);
+ } else {
+ BV_SET(characteristic_map[i], CB_FROZEN);
+ }
+ } whole_map_iterate_index_end;
+}
+/***************************************************************************
+ Passed as data to rand_map_pos_filtered() by rand_map_pos_characteristic()
+***************************************************************************/
+struct DataFilter {
+ characteristic_type c1, c2, c3;
+};
+
+/****************************************************************************
+ A filter function to be passed to rand_map_pos_filtered(). See
+ rand_map_pos_characteristic for more explanation.
+****************************************************************************/
+static bool condition_filter(int x, int y, void *data)
+{
+ struct DataFilter *filter = data;
+ int index = map_pos_to_index(x, y);
+
+ return not_placed(index)
+ && is_characteristic(index, filter->c1)
+ && is_characteristic(index, filter->c2)
+ && is_characteristic(index, filter->c3);
+}
+
+/****************************************************************************
+ Return random map coordinates which have some conditions and which are
+ not yet placed on pmap.
+ Returns FALSE if there is no such position.
+****************************************************************************/
+bool rand_index_characteristic(int *index, characteristic_type c1,
+ characteristic_type c2, characteristic_type c3 )
+{
+ struct DataFilter filter;
+ int x, y;
+
+ filter.c1 = c1;
+ filter.c2 = c2;
+ filter.c3 = c3;
+ if (rand_map_pos_filtered(&x, &y, &filter, condition_filter)) {
+ *index = map_pos_to_index(x, y);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_blocked(int index, int *river_map)
+{
+ if (TEST_BIT(river_map[index], RS_BLOCKED))
+ return 1;
+
+ /* any un-blocked? */
+ index_cardinal_adjc_dir_iterate(index, index1, dir) {
+ if (!TEST_BIT(river_map[index1], RS_BLOCKED))
+ return 0;
+ } index_cardinal_adjc_dir_iterate_end;
+
+ return 1; /* none non-blocked |- all blocked */
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_rivergrid(int index,int *river_map)
+{
+ return (count_characteristic_near(index, TRUE, FALSE, CM_RIVER)
+ > 1) ? 1 : 0;
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_highlands(int index,int *river_map)
+{
+ return ((is_characteristic(index, CM_HILLY) ? 1 : 0) +
+ (is_characteristic(index, CM_ABRUPT) ? 2 : 0));
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_adjacent_ocean(int index,int *river_map)
+{
+ return 100 - count_characteristic_near(index, TRUE, TRUE, CM_OCEANIC);
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_adjacent_river(int index,int *river_map)
+{
+ return 100 - count_characteristic_near(index, TRUE, TRUE, CM_RIVER);
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_adjacent_highlands(int index,int *river_map)
+{
+ return (count_characteristic_near(index, TRUE, TRUE, CM_HILLY)
+ + 2 * count_characteristic_near(index, TRUE, TRUE, CM_ABRUPT));
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_height_map(int index,int *river_map)
+{
+ return height_map[index];
+}
+
+/*********************************************************************
+ Called from make_river. Marks all directions as blocked. -Erik Sigra
+*********************************************************************/
+static void river_blockmark(int index,int *river_map)
+{
+ freelog(LOG_DEBUG, "Blockmarking (%d) and adjacent tiles.",
+ index);
+
+ river_map[index] |= (1u << RS_BLOCKED);
+
+ index_cardinal_adjc_dir_iterate(index, index1, dir) {
+ river_map[index1] |= (1u << RS_BLOCKED);
+ } index_cardinal_adjc_dir_iterate_end;
+}
+
+struct test_func {
+ int (*func)(int, int*);
+ bool fatal;
+};
+
+#define NUM_TEST_FUNCTIONS 7
+static struct test_func test_funcs[NUM_TEST_FUNCTIONS] = {
+ {river_test_blocked, TRUE},
+ {river_test_rivergrid, TRUE},
+ {river_test_highlands, FALSE},
+ {river_test_adjacent_ocean, FALSE},
+ {river_test_adjacent_river, FALSE},
+ {river_test_adjacent_highlands, FALSE},
+ {river_test_height_map, FALSE}
+};
+
+/********************************************************************
+ Makes a river starting at (x, y). Returns 1 if it succeeds.
+ Return 0 if it fails. The river is stored in river_map.
+
+ How to make a river path look natural
+ =====================================
+ Rivers always flow down. Thus rivers are best implemented on maps
+ where every tile has an explicit height value. However, Freeciv has a
+ flat map. But there are certain things that help the user imagine
+ differences in height between tiles. The selection of direction for
+ rivers should confirm and even amplify the user's image of the map's
+ topology.
+
+ To decide which direction the river takes, the possible directions
+ are tested in a series of test until there is only 1 direction
+ left. Some tests are fatal. This means that they can sort away all
+ remaining directions. If they do so, the river is aborted. Here
+ follows a description of the test series.
+
+ * Falling into itself: fatal
+ (river_test_blocked)
+ This is tested by looking up in the river_map array if a tile or
+ every tile surrounding the tile is marked as blocked. A tile is
+ marked as blocked if it belongs to the current river or has been
+ evaluated in a previous iteration in the creation of the current
+ river.
+
+ Possible values:
+ 0: Is not falling into itself.
+ 1: Is falling into itself.
+
+ * Forming a 4-river-grid: optionally fatal
+ (river_test_rivergrid)
+ A minimal 4-river-grid is formed when an intersection in the map
+ grid is surrounded by 4 river tiles. There can be larger river
+ grids consisting of several overlapping minimal 4-river-grids.
+
+ Possible values:
+ 0: Is not forming a 4-river-grid.
+ 1: Is forming a 4-river-grid.
+
+ * Highlands:
+ (river_test_highlands)
+ Rivers must not flow up in mountains or hills if there are
+ alternatives.
+
+ Possible values:
+ 0: Is not hills and not mountains.
+ 1: Is hills.
+ 2: Is mountains.
+
+ * Adjacent ocean:
+ (river_test_adjacent_ocean)
+ Rivers must flow down to coastal areas when possible:
+
+ Possible values: 0-100
+
+ * Adjacent river:
+ (river_test_adjacent_river)
+ Rivers must flow down to areas near other rivers when possible:
+
+ Possible values: 0-100
+
+ * Adjacent highlands:
+ (river_test_adjacent_highlands)
+ Rivers must not flow towards highlands if there are alternatives.
+
+ * height_map:
+ (river_test_height_map)
+ Rivers must flow in the direction which takes it to the tile with
+ the lowest value on the height_map.
+
+ Possible values:
+ n: height_map[...]
+
+ If these rules haven't decided the direction, the random number
+ generator gets the desicion. -Erik Sigra
+*********************************************************************/
+static bool make_river(int index, int *river_map)
+{
+ /* Comparison value for each tile surrounding the current tile. It is
+ * the suitability to continue a river to the tile in that direction;
+ * lower is better. However rivers may only run in cardinal directions;
+ * the other directions are ignored entirely. */
+ int rd_comparison_val[8];
+
+ bool rd_direction_is_valid[8];
+ int num_valid_directions, func_num, direction;
+
+ while (TRUE) {
+ /* Mark the current tile as river. */
+ river_map[index] |= (1u << RS_RIVER);
+ freelog(LOG_DEBUG,
+ "The tile at (%d) has been marked as river in river_map.\n",
+ index);
+
+ /* Test if the river is done. */
+ /* We arbitrarily make rivers end at the poles. */
+ if (count_characteristic_near(index, TRUE, TRUE, CM_RIVER)
+ + count_characteristic_near(index, TRUE, TRUE, CM_OCEANIC) > 0
+ || (is_characteristic(index, CM_FROZEN)
+ && is_characteristic(index, CM_FLAT))) {
+
+ freelog(LOG_DEBUG,
+ "The river ended at (%d).\n", index);
+ return TRUE;
+ }
+
+ /* Else choose a direction to continue the river. */
+ freelog(LOG_DEBUG,
+ "The river did not end at (%d). Evaluating directions...\n",
+ index);
+
+ /* Mark all available cardinal directions as available. */
+ memset(rd_direction_is_valid, 0, sizeof(rd_direction_is_valid));
+ index_cardinal_adjc_dir_iterate(index, index1, dir) {
+ rd_direction_is_valid[dir] = TRUE;
+ if (0 == index1) continue; /* silence warning */
+ } index_cardinal_adjc_dir_iterate_end;
+
+ /* Test series that selects a direction for the river. */
+ for (func_num = 0; func_num < NUM_TEST_FUNCTIONS; func_num++) {
+ int best_val = -1;
+
+ /* first get the tile values for the function */
+ index_cardinal_adjc_dir_iterate(index, index1, dir) {
+
+ if (rd_direction_is_valid[dir]) {
+ rd_comparison_val[dir] =
+ (test_funcs[func_num].func) (index1 , river_map);
+ if (best_val == -1) {
+ best_val = rd_comparison_val[dir];
+ } else {
+ best_val = MIN(rd_comparison_val[dir], best_val);
+ }
+ }
+ } index_cardinal_adjc_dir_iterate_end;
+ assert(best_val != -1);
+
+ /* should we abort? */
+ if (best_val > 0 && test_funcs[func_num].fatal) {
+ return FALSE;
+ }
+
+ /* mark the less attractive directions as invalid */
+ index_cardinal_adjc_dir_iterate(index, index1, dir) {
+ if (rd_direction_is_valid[dir]) {
+ if (rd_comparison_val[dir] != best_val) {
+ rd_direction_is_valid[dir] = FALSE;
+ }
+ }
+ if (index == index1) continue; /* silence warning */
+ } index_cardinal_adjc_dir_iterate_end;
+ }
+
+ /* Directions evaluated with all functions. Now choose the best
+ direction before going to the next iteration of the while loop */
+ num_valid_directions = 0;
+ index_cardinal_adjc_dir_iterate(index, index1, dir) {
+ if (rd_direction_is_valid[dir]) {
+ num_valid_directions++;
+ }
+ if (index == index1) continue; /* silence warning */
+ } index_cardinal_adjc_dir_iterate_end;
+
+ if (num_valid_directions == 0) {
+ return FALSE; /* river aborted */
+ }
+
+ /* One or more valid directions: choose randomly. */
+ freelog(LOG_DEBUG, "mapgen.c: Had to let the random number"
+ " generator select a direction for a river.");
+ direction = myrand(num_valid_directions);
+ freelog(LOG_DEBUG, "mapgen.c: direction: %d", direction);
+
+ /* Find the direction that the random number generator selected. */
+ index_cardinal_adjc_dir_iterate(index, index1, dir) {
+
+ if (rd_direction_is_valid[dir]) {
+ if (direction > 0) {
+ direction--;
+ } else {
+ river_blockmark(index1, river_map);
+ index = index1;
+ break;
+ }
+ }
+ } index_cardinal_adjc_dir_iterate_end;
+ assert(direction == 0);
+
+ } /* end while; (Make a river.) */
+}
+
+/**************************************************************************
+ Calls make_river until there are enough river tiles on the map. It stops
+ when it has tried to create RIVERS_MAXTRIES rivers. -Erik Sigra
+**************************************************************************/
+static void make_rivers(int river_pct, int *river_probability)
+{
+ int river_map[MAX_MAP_INDEX], index;
+
+ /* Formula to make the river density similar om different sized maps. Avoids
+ too few rivers on large maps and too many rivers on small maps. */
+ int desirable_riverlength =
+ river_pct *
+ /* The size of the map (poles counted in river_pct). */
+ map_num_tiles() *
+ /* Rivers need to be on land only. */
+ map.landpercent /
+ /* Adjustment value. Tested by me. Gives no rivers with 'set
+ rivers 0', gives a reasonable amount of rivers with default
+ settings and as many rivers as possible with 'set rivers 100'. */
+ 5325;
+
+ /* The number of river tiles that have been set. */
+ int current_riverlength = 0;
+
+ /* Counts the number of iterations (should increase with 1 during
+ every iteration of the main loop in this function).
+ Is needed to stop a potentially infinite loop. */
+ int iteration_counter = 0;
+
+ create_placed_map(); /* needed bu rand_map_characteristic */
+ set_all_mask_placed(CM_OCEANIC);
+
+ /* The main loop in this function. */
+ while (current_riverlength < desirable_riverlength
+ && iteration_counter < RIVERS_MAXTRIES) {
+
+ if (!rand_index_characteristic(&index,
+ CM_NFROZEN, CM_TRUE, CM_TRUE)) {
+ break; /* mo more spring places */
+ }
+
+ /* Check if it is suitable to start a river on the current tile.
+ */
+ if ((myrand(100) < river_probability[index])
+ /* Don't start a river on a tile is surrounded by > 1 river +
+ ocean tile. */
+ && (count_characteristic_near(index, TRUE, FALSE, CM_RIVER)
+ + count_characteristic_near(index, TRUE, FALSE, CM_OCEANIC) <= 1)
+
+ /* Don't start a river on a tile that is surrounded by hills or
+ mountains unless it is hard to find somewhere else to start
+ it. */
+ && (count_characteristic_near(index,TRUE, TRUE, CM_ABRUPT)
+ + count_characteristic_near(index, TRUE, TRUE, CM_HILLY) < 90
+ || (iteration_counter > RIVERS_MAXTRIES / 10 * 5))
+
+ /* Don't start a river on hills unless it is hard to find
+ somewhere else to start it. */
+ && (!is_characteristic(index, CM_HILLY)
+ || (iteration_counter > RIVERS_MAXTRIES / 10 * 6))
+
+ /* Don't start a river on mountains unless it is hard to find
+ somewhere else to start it. */
+ && (!is_characteristic(index, CM_ABRUPT)
+ || (iteration_counter > RIVERS_MAXTRIES / 10 * 7))
+ ) {
+
+ /* Reset river_map before making a new river. */
+ whole_map_iterate_index(i) {
+ river_map[i] = 0;
+ } whole_map_iterate_index_end;
+
+ freelog(LOG_DEBUG,
+ "Found a suitable starting tile for a river at (%d)."
+ " Starting to make it.",
+ index);
+
+ /* Try to make a river. If it is OK, apply it to the map. */
+ if (make_river(index, river_map)) {
+ whole_map_iterate(x1, y1) {
+ if (TEST_BIT(river_map[map_pos_to_index(x1, y1)], RS_RIVER)) {
+ BV_SET(characteristic_map[map_pos_to_index(x1, y1)], CB_RIVER);
+ current_riverlength++;
+ map_set_placed(x1, y1);
+ /* reduce probability near a river */
+ circle_iterate(x1, y1, 4, x2, y2) {
+ river_probability[map_pos_to_index(x2, y2)] *= 0.9;
+ } circle_iterate_end;
+ freelog(LOG_DEBUG, "Applied a river to (%d).",
+ map_pos_to_index(x1, y1));
+ }
+ } whole_map_iterate_end;
+ }
+ else {
+ freelog(LOG_DEBUG,
+ "mapgen.c: A river failed. It might have gotten stuck in a helix.");
+ }
+ } /* end if; */
+ iteration_counter++;
+ freelog(LOG_DEBUG,
+ "current_riverlength: %d; desirable_riverlength: %d; iteration_counter:
%d",
+ current_riverlength, desirable_riverlength, iteration_counter);
+ } /* end while; */
+
+ destroy_placed_map();
+}
+
+/**************************************************************************
+ Change the values of the integer map, so that they contain ranking of each
+ tile scaled to [0 .. int_map_max]. on tiles with the right characteristics
+**************************************************************************/
+static void adjust_int_map_masks(int *int_map, int int_map_max,
+ characteristic_type mask,characteristic_type Nmask )
+{
+ int minval = 1000000000, maxval = -1000000000, total = 0;
+
+ /* Determine minimum and maximum value. */
+ whole_map_iterate_masks_index(j, mask, Nmask) {
+ maxval = MAX(maxval, int_map[j]);
+ minval = MIN(minval, int_map[j]);
+ total++;
+ } whole_map_iterate_masks_index_end;
+
+ {
+ int const size = 1 + maxval - minval;
+ int i, count = 0, frequencies[size];
+
+ INITIALIZE_ARRAY(frequencies, size, 0);
+
+ /* Translate value so the minimum value is 0
+ and count the number of occurencies of all values to initialize the
+ frequencies[] */
+ whole_map_iterate_masks_index(j, mask, Nmask) {
+ int_map[j] = (int_map[j] - minval);
+ frequencies[int_map[j]]++;
+ } whole_map_iterate_masks_index_end ;
+
+ /* create the linearize function as "incremental" frequencies */
+ for(i = 0; i < size; i++) {
+ count += frequencies[i];
+ frequencies[i] = (count * int_map_max) / total;
+ }
+
+ /* apply the linearize function */
+ whole_map_iterate_masks_index(j, mask, Nmask) {
+ int_map[j] = frequencies[int_map[j]];
+ } whole_map_iterate_masks_index_end;
+ }
+}
+
+
+#define colatitude_is_dry(i) \
+ (colatitude((i)) <= DRY_MAX_LEVEL \
+ && colatitude((i)) > DRY_MIN_LEVEL)
+
+void characteristics_initialize_wetness(int river_pct)
+{
+ int wetness[MAX_MAP_INDEX];
+ /* there wetness[] means the probability to start a river*/
+ whole_map_iterate_index(i) {
+ if (colatitude_is_dry(i)) {
+ wetness[i] = 70;
+ } else {
+ wetness[i] = 100;
+ }
+ } whole_map_iterate_index_end;
+
+ make_rivers(river_pct, wetness);
+
+ /* now wetness[] means amount of water */
+ whole_map_iterate_index(i) {
+ float dry_bonus = colatitude_is_dry(i) ? 1 : 0;
+ float tropical_bonus = (colatitude(i) > TROPICAL_LEVEL) ? 1 : 0;
+ float height_bonus = MAX(0, (height_map[i] - hmap_shore_level))
+ / (hmap_max_level - hmap_shore_level);
+ float river_bonus = is_characteristic(i, CM_RIVER) ? 1 : 0;
+ float ocean_bonus = is_characteristic(i, CM_OCEANIC) ? 1 : 0;
+
+ wetness[i] = (100 - 10 * dry_bonus + 5 * tropical_bonus)
+ * (100 + 30 * river_bonus + 20 * ocean_bonus)
+ * (100 + 30 * height_bonus) / 100;
+ } whole_map_iterate_index_end;
+
+ smooth_int_map(wetness, FALSE);
+ adjust_int_map_masks(wetness, 1000, CM_FLAT, CM_OCEANIC);
+ adjust_int_map_masks(wetness, 1000, CM_HILLY, CM_OCEANIC);
+ adjust_int_map_masks(wetness, 1000, CM_ABRUPT, CM_OCEANIC);
+
+ whole_map_iterate_index(i) {
+ if (is_characteristic(i, CM_OCEANIC)) {
+ continue;
+ }
+ if (wetness[i] < 300) {
+ BV_SET(characteristic_map[i], CB_DRY);
+ } else if(wetness[i] < 700){
+ BV_SET(characteristic_map[i], CB_MEDIUM);
+ } else {
+ BV_SET(characteristic_map[i], CB_WET);
+ }
+ } whole_map_iterate_index_end;
+}
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/characteristics.h
freeciv_/server/generator/characteristics.h
--- freeciv/server/generator/characteristics.h 1970-01-01 01:00:00.000000000
+0100
+++ freeciv_/server/generator/characteristics.h 2004-09-22 11:30:54.000000000
+0200
@@ -0,0 +1,84 @@
+/**********************************************************************
+ Copyright (C) 1996-2004 - The Freeciv Project Team,
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+***********************************************************************/
+#ifndef FC__CHARACTERISTICS_H
+#define FC__CHARACTERISTICS_H
+
+BV_DEFINE(characteristic_type, 13);
+typedef enum {CB_TRUE = 0,
+ CB_RIVER,
+ CB_FROZEN , CB_COLD , CB_TEMPERATE, CB_TROPICAL,
+ CB_OCEANIC, CB_WET , CB_MEDIUM , CB_DRY ,
+ CB_FLAT, CB_HILLY, CB_ABRUPT} characteristic_bits;
+
+/* test for CM_TRUE mask is all the time TRUE,
+ * test for CM_FALSE mask is FALSE!
+ */
+extern characteristic_type CM_TRUE, CM_FALSE;
+extern characteristic_type CM_FLAT, CM_HILLY, CM_ABRUPT,
+ CM_NFLAT;
+extern characteristic_type CM_FROZEN, CM_COLD, CM_TEMPERATE, CM_TROPICAL,
+ CM_NFROZEN, CM_ALL, CM_NHOT, CM_HOT;
+/*
+ CM_NFROZEN == (CM_COLD | CM_TEMPERATE | CM_TROPICAL)
+ CM_ALL == (CM_FROZEN | CM_NFROZEN)
+ CM_NHOT == (CM_FROZEN | CM_COLD)
+ CM_HOT == (CM_TEMPERATE, CM_TROPICAL)
+ */
+
+extern characteristic_type CM_OCEANIC, CM_WET, CM_MEDIUM, CM_DRY,
+ CM_NWET, CM_NDRY;
+extern characteristic_type CM_RIVER;
+
+bool characteristics_are_initialized(void);
+void create_characteristics(void);
+void destroy_characteristics(void);
+
+bool is_characteristic(int index, characteristic_type mask );
+int count_characteristic_near(int index , bool cardinal_only, bool percentage,
+ characteristic_type mask);
+
+bool rand_index_characteristic(int *index, characteristic_type c1,
+ characteristic_type c2,characteristic_type c3 );
+
+void characteristics_initialize_shores(void);
+void characteristics_initialize_extra_polar_land(void);
+void characteristics_initialize_relief(void);
+void characteristics_initialize_temperature(bool real);
+void characteristics_initialize_wetness(int river_pct);
+
+/*
+ * little iterator on indexes
+ */
+#define index_cardinal_adjc_dir_iterate(index, index1, dir) \
+ { \
+ int _x, _y; \
+ index_to_map_pos(&_x, &_y, (index)); \
+ cardinal_adjc_dir_iterate(_x, _y, _x1, _y1, dir) { \
+ const int index1 = map_pos_to_index(_x1, _y1);
+
+#define index_cardinal_adjc_dir_iterate_end \
+ } cardinal_adjc_dir_iterate_end; }
+
+/*
+ iterate on tile with the right mask and with not the Nmask
+*/
+
+#define whole_map_iterate_masks_index(i, mask, Nmask) \
+ whole_map_iterate_index(i) { \
+ if(is_characteristic(i, Nmask) || !is_characteristic(i, mask)) { \
+ continue; \
+ }
+
+#define whole_map_iterate_masks_index_end } whole_map_iterate_index_end
+
+#endif /* FC__CHARACTERISTICS_H */
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/Makefile.am
freeciv_/server/generator/Makefile.am
--- freeciv/server/generator/Makefile.am 2004-09-16 11:53:11.000000000
+0200
+++ freeciv_/server/generator/Makefile.am 2004-09-22 08:42:36.000000000
+0200
@@ -14,5 +14,5 @@
height_map.h \
startpos.c \
startpos.h \
- temperature_map.c \
- temperature_map.h
+ characteristics.h \
+ characteristics.c
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/mapgen.c
freeciv_/server/generator/mapgen.c
--- freeciv/server/generator/mapgen.c 2004-09-22 08:39:29.000000000 +0200
+++ freeciv_/server/generator/mapgen.c 2004-09-22 11:02:27.000000000 +0200
@@ -36,9 +36,8 @@
#include "height_map.h"
#include "mapgen_topology.h"
#include "startpos.h"
-#include "temperature_map.h"
#include "utilities.h"
-
+#include "characteristics.h"
/* Old-style terrain enumeration: deprecated. */
enum {
@@ -56,17 +55,6 @@
static void mapgenerator4(void);
static void adjust_terrain_param(void);
-#define RIVERS_MAXTRIES 32767
-enum river_map_type {RS_BLOCKED = 0, RS_RIVER = 1};
-
-/* Array needed to mark tiles as blocked to prevent a river from
- falling into itself, and for storing rivers temporarly.
- A value of 1 means blocked.
- A value of 2 means river. -Erik Sigra */
-static int *river_map;
-
-#define HAS_POLES (map.temperature < 70 && !map.alltemperate )
-
/* These are the old parameters of terrains types in %
TODO: they depend on the hardcoded terrains */
static int forest_pct = 0;
@@ -76,272 +64,45 @@
static int jungle_pct = 0;
static int river_pct = 0;
-/****************************************************************************
- * Conditions used mainly in rand_map_pos_characteristic()
- ****************************************************************************/
-/* WETNESS */
-
-/* necessary condition of deserts placement */
-#define map_pos_is_dry(x, y) \
- (map_colatitude((x), (y)) <= DRY_MAX_LEVEL \
- && map_colatitude((x), (y)) > DRY_MIN_LEVEL \
- && count_ocean_near_tile((x), (y), FALSE, TRUE) <= 35)
-typedef enum { WC_ALL = 200, WC_DRY, WC_NDRY } wetness_c;
-
-/* MISCELANEOUS (OTHER CONDITIONS) */
-
-/* necessary condition of swamp placement */
-static int hmap_low_level = 0;
-#define ini_hmap_low_level() \
-{ \
-hmap_low_level = (4 * swamp_pct * \
- (hmap_max_level - hmap_shore_level)) / 100 + hmap_shore_level; \
-}
-/* should be used after having hmap_low_level initialized */
-#define map_pos_is_low(x, y) ((hmap((x), (y)) < hmap_low_level))
-
-typedef enum { MC_NONE, MC_LOW, MC_NLOW } miscellaneous_c;
-
-/***************************************************************************
- These functions test for conditions used in rand_map_pos_characteristic
-***************************************************************************/
-
-/***************************************************************************
- Checks if the given location satisfy some wetness condition
-***************************************************************************/
-static bool test_wetness(int x, int y, wetness_c c)
-{
- switch(c) {
- case WC_ALL:
- return TRUE;
- case WC_DRY:
- return map_pos_is_dry(x, y);
- case WC_NDRY:
- return !map_pos_is_dry(x, y);
- }
- assert(0);
- return FALSE;
-}
-
-/***************************************************************************
- Checks if the given location satisfy some miscellaneous condition
-***************************************************************************/
-static bool test_miscellaneous(int x, int y, miscellaneous_c c)
-{
- switch(c) {
- case MC_NONE:
- return TRUE;
- case MC_LOW:
- return map_pos_is_low(x, y);
- case MC_NLOW:
- return !map_pos_is_low(x, y);
- }
- assert(0);
- return FALSE;
-}
-
-/***************************************************************************
- Passed as data to rand_map_pos_filtered() by rand_map_pos_characteristic()
-***************************************************************************/
-struct DataFilter {
- wetness_c wc;
- temperature_type tc;
- miscellaneous_c mc;
-};
-
-/****************************************************************************
- A filter function to be passed to rand_map_pos_filtered(). See
- rand_map_pos_characteristic for more explanation.
-****************************************************************************/
-static bool condition_filter(int map_x, int map_y, void *data)
-{
- struct DataFilter *filter = data;
-
- return not_placed(map_x, map_y)
- && tmap_is(map_x, map_y, filter->tc)
- && test_wetness(map_x, map_y, filter->wc)
- && test_miscellaneous(map_x, map_y, filter->mc) ;
-}
-
-/****************************************************************************
- Return random map coordinates which have some conditions and which are
- not yet placed on pmap.
- Returns FALSE if there is no such position.
-****************************************************************************/
-static bool rand_map_pos_characteristic(int *map_x, int *map_y,
- wetness_c wc,
- temperature_type tc,
- miscellaneous_c mc )
-{
- struct DataFilter filter;
-
- filter.wc = wc;
- filter.tc = tc;
- filter.mc = mc;
- return rand_map_pos_filtered(map_x, map_y, &filter, condition_filter);
-}
-
-/**************************************************************************
- we don't want huge areas of grass/plains,
- so we put in a hill here and there, where it gets too 'clean'
-
- Return TRUE if the terrain at the given map position is "clean". This
- means that all the terrain for 2 squares around it is not mountain or hill.
-****************************************************************************/
-static bool terrain_is_too_flat(int map_x, int map_y,int thill, int my_height)
-{
- int higher_than_me = 0;
- square_iterate(map_x, map_y, 2, x1, y1) {
- if (hmap(x1, y1) > thill) {
- return FALSE;
- }
- if (hmap(x1, y1) > my_height) {
- if (map_distance(map_x, map_y, x1, y1) == 1) {
- return FALSE;
- }
- if (++higher_than_me > 2) {
- return FALSE;
- }
- }
- } square_iterate_end;
-
- if ((thill - hmap_shore_level) * higher_than_me >
- (my_height - hmap_shore_level) * 4) {
- return FALSE;
- }
- return TRUE;
-}
/**************************************************************************
- we don't want huge areas of hill/mountains,
- so we put in a plains here and there, where it gets too 'heigh'
-
- Return TRUE if the terrain at the given map position is too heigh.
-****************************************************************************/
-static bool terrain_is_too_high(int map_x, int map_y,int thill, int my_height)
-{
- square_iterate(map_x, map_y, 1, x1, y1) {
- if (hmap(x1, y1) + (hmap_max_level - hmap_mountain_level) / 5 < thill) {
- return FALSE;
- }
- } square_iterate_end;
- return TRUE;
-}
-
-/**************************************************************************
- make_relief() will convert all squares that are higher than thill to
- mountains and hills. Note that thill will be adjusted according to
- the map.steepness value, so increasing map.mountains will result in
- more hills and mountains.
+ Recursively generate terrains.
**************************************************************************/
-static void make_relief(void)
+static void place_terrain(int index, int diff,
+ Terrain_type_id ter, int *to_be_placed,
+ characteristic_type wcm,
+ characteristic_type tcm,
+ characteristic_type mcm)
{
- /* Calculate the mountain level. map.mountains specifies the percentage
- * of land that is turned into hills and mountains. */
- hmap_mountain_level = ((hmap_max_level - hmap_shore_level)
- * (100 - map.steepness)) / 100 + hmap_shore_level;
- whole_map_iterate(x, y) {
- if (not_placed(x,y) &&
- ((hmap_mountain_level < hmap(x, y) &&
- (myrand(10) > 5
- || !terrain_is_too_high(x, y, hmap_mountain_level, hmap(x, y))))
- || terrain_is_too_flat(x, y, hmap_mountain_level, hmap(x, y)))) {
- /* Randomly place hills and mountains on "high" tiles. But don't
- * put hills near the poles (they're too green). */
- if (myrand(100) > 70 || tmap_is(x, y, TT_NHOT)) {
- map_set_terrain(x, y, T_MOUNTAINS);
- map_set_placed(x, y);
- } else {
- map_set_terrain(x, y, T_HILLS);
- map_set_placed(x, y);
- }
- }
- } whole_map_iterate_end;
-}
+ int x, y;
-/****************************************************************************
- Add arctic and tundra squares in the arctic zone (that is, the coolest
- 10% of the map). We also texture the pole (adding arctic, tundra, and
- mountains). This is used in generators 2-4.
-****************************************************************************/
-static void make_polar(void)
-{
- whole_map_iterate(map_x, map_y) {
- if (tmap_is(map_x, map_y, TT_FROZEN )
- ||
- (tmap_is(map_x, map_y, TT_COLD ) &&
- (myrand(10) > 7) &&
- is_temperature_type_near(map_x, map_y, TT_FROZEN))) {
- map_set_terrain(map_x, map_y, T_ARCTIC);
- }
- } whole_map_iterate_end;
-}
-
-/*************************************************************************
- if separatepoles is set, return false if this tile has to keep ocean
-************************************************************************/
-static bool ok_for_separate_poles(int x, int y)
-{
- if (!map.separatepoles) {
- return TRUE;
- }
- adjc_iterate(x, y, x1, y1) {
- if (!is_ocean(map_get_terrain(x1, y1)) &&
- map_get_continent(x1, y1 ) != 0) {
- return FALSE;
- }
- } adjc_iterate_end;
- return TRUE;
-}
-
-/****************************************************************************
- Place untextured land at the poles. This is used by generators 1 and 5.
-****************************************************************************/
-static void make_polar_land(void)
-{
- assign_continent_numbers();
- whole_map_iterate(map_x, map_y) {
- if ((tmap_is(map_x, map_y, TT_FROZEN ) &&
- ok_for_separate_poles(map_x, map_y))
- ||
- (tmap_is(map_x, map_y, TT_COLD ) &&
- (myrand(10) > 7) &&
- is_temperature_type_near(map_x, map_y, TT_FROZEN) &&
- ok_for_separate_poles(map_x, map_y))) {
- map_set_terrain(map_x, map_y, T_UNKNOWN);
- map_set_continent(map_x, map_y, 0);
- }
- } whole_map_iterate_end;
-}
-
-/**************************************************************************
- Recursively generate terrains.
-**************************************************************************/
-static void place_terrain(int x, int y, int diff,
- Terrain_type_id ter, int *to_be_placed,
- wetness_c wc,
- temperature_type tc,
- miscellaneous_c mc)
-{
+ index_to_map_pos(&x, &y, index);
if (*to_be_placed <= 0) {
return;
}
- assert(not_placed(x, y));
+ assert(map_not_placed(x, y));
map_set_terrain(x, y, ter);
+ if (is_characteristic(index, CM_RIVER)) {
+ map_set_special(x, y, S_RIVER);
+ }
map_set_placed(x, y);
(*to_be_placed)--;
cardinal_adjc_iterate(x, y, x1, y1) {
- int Delta = abs(map_colatitude(x1, y1) - map_colatitude(x, y)) / L_UNIT
- + abs(hmap(x1, y1) - (hmap(x, y))) / H_UNIT;
- if (not_placed(x1, y1)
- && tmap_is(x1, y1, tc)
- && test_wetness(x1, y1, wc)
- && test_miscellaneous(x1, y1, mc)
+ int index1 = map_pos_to_index(x1, y1);
+ int Delta = abs(colatitude(index1) - colatitude(index)) / L_UNIT
+ + abs(height_map[index1] - (height_map[index])) / H_UNIT;
+ if (not_placed(index1)
+ && is_characteristic(index1, tcm)
+ && is_characteristic(index1, wcm)
+ && is_characteristic(index1, mcm)
+ && (is_characteristic(index1, CM_RIVER)
+ ? terrain_has_flag(ter, TER_CAN_HAVE_RIVER) : TRUE)
&& Delta < diff
&& myrand(10) > 4) {
- place_terrain(x1, y1, diff - 1 - Delta, ter, to_be_placed, wc, tc, mc);
+ place_terrain(index1, diff - 1 - Delta, ter,
+ to_be_placed, wcm, tcm, mcm);
}
} cardinal_adjc_iterate_end;
}
@@ -350,12 +111,15 @@
a simple function that adds plains grassland or tundra to the
current location.
**************************************************************************/
-static void make_plain(int x, int y, int *to_be_placed )
+static void make_plain(int index, int *to_be_placed )
{
+ int x, y;
+
+ index_to_map_pos(&x, &y, index);
/* in cold place we get tundra instead */
- if (tmap_is(x, y, TT_FROZEN)) {
+ if (is_characteristic(index, CM_FROZEN)) {
map_set_terrain(x, y, T_ARCTIC);
- } else if (tmap_is(x, y, TT_COLD)) {
+ } else if (is_characteristic(index, CM_COLD)) {
map_set_terrain(x, y, T_TUNDRA);
} else {
if (myrand(100) > 50) {
@@ -364,6 +128,9 @@
map_set_terrain(x, y, T_PLAINS);
}
}
+ if (is_characteristic(index, CM_RIVER)) {
+ map_set_special(x, y, S_RIVER);
+ }
map_set_placed(x, y);
(*to_be_placed)--;
}
@@ -375,22 +142,23 @@
static void make_plains(void)
{
int to_be_placed;
- whole_map_iterate(x, y) {
- if (not_placed(x, y)) {
+ whole_map_iterate_index(i) {
+ if (not_placed(i)) {
to_be_placed = 1;
- make_plain(x, y, &to_be_placed);
+ make_plain(i, &to_be_placed);
}
- } whole_map_iterate_end;
+ } whole_map_iterate_index_end;
}
+
/**************************************************************************
This place randomly a cluster of terrains with some characteristics
**************************************************************************/
#define PLACE_ONE_TYPE(count, alternate, ter, wc, tc, mc, weight) \
if((count) > 0) { \
- int x, y; \
+ int index; \
/* Place some terrains */ \
- if (rand_map_pos_characteristic(&x, &y, (wc), (tc), (mc))) { \
- place_terrain(x, y, (weight), (ter), &(count), (wc),(tc), (mc)); \
+ if (rand_index_characteristic(&index, (wc), (tc), (mc))) { \
+ place_terrain(index, (weight), (ter), &(count), (wc),(tc), (mc)); \
} else { \
/* If rand_map_pos_temperature returns FALSE we may as well stop*/ \
/* looking for this time and go to alternate type. */ \
@@ -416,12 +184,33 @@
int plains_count = 0;
int swamps_count = 0;
+ create_placed_map();
+
whole_map_iterate(x, y) {
- if (not_placed(x,y)) {
- total++;
+ int index = map_pos_to_index(x, y);
+
+ if (is_characteristic(index, CM_OCEANIC)) {
+ map_set_placed(x, y);
+ map_set_terrain(x, y, T_OCEAN);
+ } else if (is_characteristic(index, CM_HILLY)) {
+ map_set_placed(x, y);
+ map_set_terrain(x, y, T_HILLS);
+ /* hack for terrains-set, where hills are too green */
+ if (is_characteristic(index, CM_FROZEN)) {
+ map_set_terrain(x, y, T_MOUNTAINS);
+ }
+ } else if (is_characteristic(index, CM_ABRUPT)) {
+ map_set_placed(x, y);
+ map_set_terrain(x, y, T_MOUNTAINS);
}
} whole_map_iterate_end;
+ whole_map_iterate_index(i) {
+ if (not_placed(i)) {
+ total++;
+ }
+ } whole_map_iterate_index_end;
+
forests_count = total * forest_pct / (100 - mountain_pct);
jungles_count = total * jungle_pct / (100 - mountain_pct);
@@ -436,23 +225,23 @@
do {
PLACE_ONE_TYPE(forests_count , plains_count, T_FOREST,
- WC_ALL, TT_NFROZEN, MC_NONE, 60);
+ CM_ALL, CM_NFROZEN, CM_FLAT, 60);
PLACE_ONE_TYPE(jungles_count, forests_count , T_JUNGLE,
- WC_ALL, TT_TROPICAL, MC_NONE, 50);
+ CM_ALL, CM_TROPICAL, CM_FLAT, 50);
PLACE_ONE_TYPE(swamps_count, forests_count , T_SWAMP,
- WC_NDRY, TT_HOT, MC_LOW, 50);
+ CM_WET, CM_HOT, CM_FLAT, 30);
PLACE_ONE_TYPE(deserts_count, alt_deserts_count , T_DESERT,
- WC_DRY, TT_NFROZEN, MC_NLOW, 80);
+ CM_DRY, CM_HOT, CM_FLAT, 80);
PLACE_ONE_TYPE(alt_deserts_count, plains_count , T_DESERT,
- WC_ALL, TT_NFROZEN, MC_NLOW, 40);
+ CM_NWET, CM_NFROZEN, CM_FLAT, 40);
/* make the plains and tundras */
if (plains_count > 0) {
- int x, y;
+ int index;
/* Don't use any restriction here ! */
- if (rand_map_pos_characteristic(&x, &y, WC_ALL, TT_ALL, MC_NONE)){
- make_plain(x,y, &plains_count);
+ if (rand_index_characteristic(&index, CM_ALL, CM_ALL, CM_ALL)){
+ make_plain(index, &plains_count);
} else {
/* If rand_map_pos_temperature returns FALSE we may as well stop
* looking for plains. */
@@ -462,491 +251,8 @@
} while (forests_count > 0 || jungles_count > 0
|| deserts_count > 0 || alt_deserts_count > 0
|| plains_count > 0 || swamps_count > 0 );
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_blocked(int x, int y)
-{
- if (TEST_BIT(rmap(x, y), RS_BLOCKED))
- return 1;
-
- /* any un-blocked? */
- cardinal_adjc_iterate(x, y, x1, y1) {
- if (!TEST_BIT(rmap(x1, y1), RS_BLOCKED))
- return 0;
- } cardinal_adjc_iterate_end;
-
- return 1; /* none non-blocked |- all blocked */
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_rivergrid(int x, int y)
-{
- return (count_special_near_tile(x, y, TRUE, FALSE, S_RIVER) > 1) ? 1 : 0;
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_highlands(int x, int y)
-{
- return (((map_get_terrain(x, y) == T_HILLS) ? 1 : 0) +
- ((map_get_terrain(x, y) == T_MOUNTAINS) ? 2 : 0));
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_ocean(int x, int y)
-{
- return 100 - count_ocean_near_tile(x, y, TRUE, TRUE);
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_river(int x, int y)
-{
- return 100 - count_special_near_tile(x, y, TRUE, TRUE, S_RIVER);
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_highlands(int x, int y)
-{
- return (count_terrain_near_tile(x, y, TRUE, TRUE, T_HILLS)
- + 2 * count_terrain_near_tile(x, y, TRUE, TRUE, T_MOUNTAINS));
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_swamp(int x, int y)
-{
- return (map_get_terrain(x, y) != T_SWAMP) ? 1 : 0;
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_swamp(int x, int y)
-{
- return 100 - count_terrain_near_tile(x, y, TRUE, TRUE, T_SWAMP);
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_height_map(int x, int y)
-{
- return hmap(x, y);
-}
-/*********************************************************************
- Called from make_river. Marks all directions as blocked. -Erik Sigra
-*********************************************************************/
-static void river_blockmark(int x, int y)
-{
- freelog(LOG_DEBUG, "Blockmarking (%d, %d) and adjacent tiles.",
- x, y);
-
- rmap(x, y) |= (1u << RS_BLOCKED);
-
- cardinal_adjc_iterate(x, y, x1, y1) {
- rmap(x1, y1) |= (1u << RS_BLOCKED);
- } cardinal_adjc_iterate_end;
-}
-
-struct test_func {
- int (*func)(int, int);
- bool fatal;
-};
-
-#define NUM_TEST_FUNCTIONS 9
-static struct test_func test_funcs[NUM_TEST_FUNCTIONS] = {
- {river_test_blocked, TRUE},
- {river_test_rivergrid, TRUE},
- {river_test_highlands, FALSE},
- {river_test_adjacent_ocean, FALSE},
- {river_test_adjacent_river, FALSE},
- {river_test_adjacent_highlands, FALSE},
- {river_test_swamp, FALSE},
- {river_test_adjacent_swamp, FALSE},
- {river_test_height_map, FALSE}
-};
-
-/********************************************************************
- Makes a river starting at (x, y). Returns 1 if it succeeds.
- Return 0 if it fails. The river is stored in river_map.
-
- How to make a river path look natural
- =====================================
- Rivers always flow down. Thus rivers are best implemented on maps
- where every tile has an explicit height value. However, Freeciv has a
- flat map. But there are certain things that help the user imagine
- differences in height between tiles. The selection of direction for
- rivers should confirm and even amplify the user's image of the map's
- topology.
-
- To decide which direction the river takes, the possible directions
- are tested in a series of test until there is only 1 direction
- left. Some tests are fatal. This means that they can sort away all
- remaining directions. If they do so, the river is aborted. Here
- follows a description of the test series.
-
- * Falling into itself: fatal
- (river_test_blocked)
- This is tested by looking up in the river_map array if a tile or
- every tile surrounding the tile is marked as blocked. A tile is
- marked as blocked if it belongs to the current river or has been
- evaluated in a previous iteration in the creation of the current
- river.
-
- Possible values:
- 0: Is not falling into itself.
- 1: Is falling into itself.
-
- * Forming a 4-river-grid: optionally fatal
- (river_test_rivergrid)
- A minimal 4-river-grid is formed when an intersection in the map
- grid is surrounded by 4 river tiles. There can be larger river
- grids consisting of several overlapping minimal 4-river-grids.
-
- Possible values:
- 0: Is not forming a 4-river-grid.
- 1: Is forming a 4-river-grid.
-
- * Highlands:
- (river_test_highlands)
- Rivers must not flow up in mountains or hills if there are
- alternatives.
-
- Possible values:
- 0: Is not hills and not mountains.
- 1: Is hills.
- 2: Is mountains.
-
- * Adjacent ocean:
- (river_test_adjacent_ocean)
- Rivers must flow down to coastal areas when possible:
-
- Possible values: 0-100
-
- * Adjacent river:
- (river_test_adjacent_river)
- Rivers must flow down to areas near other rivers when possible:
-
- Possible values: 0-100
-
- * Adjacent highlands:
- (river_test_adjacent_highlands)
- Rivers must not flow towards highlands if there are alternatives.
-
- * Swamps:
- (river_test_swamp)
- Rivers must flow down in swamps when possible.
-
- Possible values:
- 0: Is swamps.
- 1: Is not swamps.
-
- * Adjacent swamps:
- (river_test_adjacent_swamp)
- Rivers must flow towards swamps when possible.
-
- * height_map:
- (river_test_height_map)
- Rivers must flow in the direction which takes it to the tile with
- the lowest value on the height_map.
-
- Possible values:
- n: height_map[...]
-
- If these rules haven't decided the direction, the random number
- generator gets the desicion. -Erik Sigra
-*********************************************************************/
-static bool make_river(int x, int y)
-{
- /* Comparison value for each tile surrounding the current tile. It is
- * the suitability to continue a river to the tile in that direction;
- * lower is better. However rivers may only run in cardinal directions;
- * the other directions are ignored entirely. */
- int rd_comparison_val[8];
-
- bool rd_direction_is_valid[8];
- int num_valid_directions, func_num, direction;
-
- while (TRUE) {
- /* Mark the current tile as river. */
- rmap(x, y) |= (1u << RS_RIVER);
- freelog(LOG_DEBUG,
- "The tile at (%d, %d) has been marked as river in river_map.\n",
- x, y);
-
- /* Test if the river is done. */
- /* We arbitrarily make rivers end at the poles. */
- if (count_special_near_tile(x, y, TRUE, TRUE, S_RIVER) > 0
- || count_ocean_near_tile(x, y, TRUE, TRUE) > 0
- || (map_get_terrain(x, y) == T_ARCTIC
- && map_colatitude(x, y) < 0.8 * COLD_LEVEL)) {
-
- freelog(LOG_DEBUG,
- "The river ended at (%d, %d).\n", x, y);
- return TRUE;
- }
-
- /* Else choose a direction to continue the river. */
- freelog(LOG_DEBUG,
- "The river did not end at (%d, %d). Evaluating directions...\n",
- x, y);
-
- /* Mark all available cardinal directions as available. */
- memset(rd_direction_is_valid, 0, sizeof(rd_direction_is_valid));
- cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
- rd_direction_is_valid[dir] = TRUE;
- } cardinal_adjc_dir_iterate_end;
-
- /* Test series that selects a direction for the river. */
- for (func_num = 0; func_num < NUM_TEST_FUNCTIONS; func_num++) {
- int best_val = -1;
-
- /* first get the tile values for the function */
- cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
- if (rd_direction_is_valid[dir]) {
- rd_comparison_val[dir] = (test_funcs[func_num].func) (x1, y1);
- if (best_val == -1) {
- best_val = rd_comparison_val[dir];
- } else {
- best_val = MIN(rd_comparison_val[dir], best_val);
- }
- }
- } cardinal_adjc_dir_iterate_end;
- assert(best_val != -1);
-
- /* should we abort? */
- if (best_val > 0 && test_funcs[func_num].fatal) {
- return FALSE;
- }
-
- /* mark the less attractive directions as invalid */
- cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
- if (rd_direction_is_valid[dir]) {
- if (rd_comparison_val[dir] != best_val) {
- rd_direction_is_valid[dir] = FALSE;
- }
- }
- } cardinal_adjc_dir_iterate_end;
- }
-
- /* Directions evaluated with all functions. Now choose the best
- direction before going to the next iteration of the while loop */
- num_valid_directions = 0;
- cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
- if (rd_direction_is_valid[dir]) {
- num_valid_directions++;
- }
- } cardinal_adjc_dir_iterate_end;
-
- if (num_valid_directions == 0) {
- return FALSE; /* river aborted */
- }
-
- /* One or more valid directions: choose randomly. */
- freelog(LOG_DEBUG, "mapgen.c: Had to let the random number"
- " generator select a direction for a river.");
- direction = myrand(num_valid_directions);
- freelog(LOG_DEBUG, "mapgen.c: direction: %d", direction);
-
- /* Find the direction that the random number generator selected. */
- cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
- if (rd_direction_is_valid[dir]) {
- if (direction > 0) {
- direction--;
- } else {
- river_blockmark(x, y);
- x = x1;
- y = y1;
- break;
- }
- }
- } cardinal_adjc_dir_iterate_end;
- assert(direction == 0);
-
- } /* end while; (Make a river.) */
-}
-
-/**************************************************************************
- Calls make_river until there are enough river tiles on the map. It stops
- when it has tried to create RIVERS_MAXTRIES rivers. -Erik Sigra
-**************************************************************************/
-static void make_rivers(void)
-{
- int x, y; /* The coordinates. */
-
- /* Formula to make the river density similar om different sized maps. Avoids
- too few rivers on large maps and too many rivers on small maps. */
- int desirable_riverlength =
- river_pct *
- /* The size of the map (poles counted in river_pct). */
- map_num_tiles() *
- /* Rivers need to be on land only. */
- map.landpercent /
- /* Adjustment value. Tested by me. Gives no rivers with 'set
- rivers 0', gives a reasonable amount of rivers with default
- settings and as many rivers as possible with 'set rivers 100'. */
- 5325;
-
- /* The number of river tiles that have been set. */
- int current_riverlength = 0;
-
- int i; /* Loop variable. */
-
- /* Counts the number of iterations (should increase with 1 during
- every iteration of the main loop in this function).
- Is needed to stop a potentially infinite loop. */
- int iteration_counter = 0;
-
- create_placed_map(); /* needed bu rand_map_characteristic */
- set_all_ocean_tiles_placed();
-
- river_map = fc_malloc(sizeof(int) * MAX_MAP_INDEX);
-
- /* The main loop in this function. */
- while (current_riverlength < desirable_riverlength
- && iteration_counter < RIVERS_MAXTRIES) {
-
- if (!rand_map_pos_characteristic(&x, &y,
- WC_ALL, TT_NFROZEN, MC_NLOW)) {
- break; /* mo more spring places */
- }
-
- /* Check if it is suitable to start a river on the current tile.
- */
- if (
- /* Don't start a river on ocean. */
- !is_ocean(map_get_terrain(x, y))
-
- /* Don't start a river on river. */
- && !map_has_special(x, y, S_RIVER)
-
- /* Don't start a river on a tile is surrounded by > 1 river +
- ocean tile. */
- && (count_special_near_tile(x, y, TRUE, FALSE, S_RIVER)
- + count_ocean_near_tile(x, y, TRUE, FALSE) <= 1)
-
- /* Don't start a river on a tile that is surrounded by hills or
- mountains unless it is hard to find somewhere else to start
- it. */
- && (count_terrain_near_tile(x, y, TRUE, TRUE, T_HILLS)
- + count_terrain_near_tile(x, y, TRUE, TRUE, T_MOUNTAINS) < 90
- || iteration_counter == RIVERS_MAXTRIES / 10 * 5)
-
- /* Don't start a river on hills unless it is hard to find
- somewhere else to start it. */
- && (map_get_terrain(x, y) != T_HILLS
- || iteration_counter == RIVERS_MAXTRIES / 10 * 6)
-
- /* Don't start a river on mountains unless it is hard to find
- somewhere else to start it. */
- && (map_get_terrain(x, y) != T_MOUNTAINS
- || iteration_counter == RIVERS_MAXTRIES / 10 * 7)
-
- /* Don't start a river on arctic unless it is hard to find
- somewhere else to start it. */
- && (map_get_terrain(x, y) != T_ARCTIC
- || iteration_counter == RIVERS_MAXTRIES / 10 * 8)
-
- /* Don't start a river on desert unless it is hard to find
- somewhere else to start it. */
- && (map_get_terrain(x, y) != T_DESERT
- || iteration_counter == RIVERS_MAXTRIES / 10 * 9)) {
-
- /* Reset river_map before making a new river. */
- for (i = 0; i < map.xsize * map.ysize; i++) {
- river_map[i] = 0;
- }
-
- freelog(LOG_DEBUG,
- "Found a suitable starting tile for a river at (%d, %d)."
- " Starting to make it.",
- x, y);
-
- /* Try to make a river. If it is OK, apply it to the map. */
- if (make_river(x, y)) {
- whole_map_iterate(x1, y1) {
- if (TEST_BIT(rmap(x1, y1), RS_RIVER)) {
- Terrain_type_id t = map_get_terrain(x1, y1);
-
- if (!terrain_has_flag(t, TER_CAN_HAVE_RIVER)) {
- /* We have to change the terrain to put a river here. */
- t = get_flag_terrain(TER_CAN_HAVE_RIVER);
- map_set_terrain(x1, y1, t);
- }
- map_set_special(x1, y1, S_RIVER);
- current_riverlength++;
- map_set_placed(x1, y1);
- freelog(LOG_DEBUG, "Applied a river to (%d, %d).", x1, y1);
- }
- } whole_map_iterate_end;
- }
- else {
- freelog(LOG_DEBUG,
- "mapgen.c: A river failed. It might have gotten stuck in a
helix.");
- }
- } /* end if; */
- iteration_counter++;
- freelog(LOG_DEBUG,
- "current_riverlength: %d; desirable_riverlength: %d;
iteration_counter: %d",
- current_riverlength, desirable_riverlength, iteration_counter);
- } /* end while; */
- free(river_map);
destroy_placed_map();
- river_map = NULL;
-}
-
-/**************************************************************************
- make land simply does it all based on a generated heightmap
- 1) with map.landpercent it generates a ocean/grassland map
- 2) it then calls the above functions to generate the different terrains
-**************************************************************************/
-static void make_land(void)
-{
-
- if (HAS_POLES) {
- normalize_hmap_poles();
- }
- hmap_shore_level = (hmap_max_level * (100 - map.landpercent)) / 100;
- ini_hmap_low_level();
- whole_map_iterate(x, y) {
- map_set_terrain(x, y, T_UNKNOWN); /* set as oceans count is used */
- if (hmap(x, y) < hmap_shore_level) {
- map_set_terrain(x, y, T_OCEAN);
- }
- } whole_map_iterate_end;
- if (HAS_POLES) {
- renormalize_hmap_poles();
- }
-
- create_tmap(TRUE); /* base temperature map, need hmap and oceans */
-
- if (HAS_POLES) { /* this is a hack to terrains set with not frizzed oceans*/
- make_polar_land(); /* make extra land at poles*/
- }
-
- create_placed_map(); /* here it means land terrains to be placed */
- set_all_ocean_tiles_placed();
- make_relief(); /* base relief on map */
- make_terrains(); /* place all exept mountains and hill */
- destroy_placed_map();
-
- make_rivers(); /* use a new placed_map. destroy older before call */
-
- assign_continent_numbers();
}
/**************************************************************************
@@ -986,6 +292,32 @@
}
/**************************************************************************
+ Convert parameters from the server into terrains percents parameters for
+ the generators
+**************************************************************************/
+static void adjust_terrain_param(void)
+{
+ int polar = 2 * ICE_BASE_LEVEL * map.landpercent / MAX_COLATITUDE ;
+ float factor = (100.0 - polar - map.steepness * 0.8 ) / 10000;
+
+
+ mountain_pct = factor * map.steepness * 90;
+
+ /* 40 % if wetness == 50 & */
+ forest_pct = factor * (map.wetness * 60 + 1000) ;
+ jungle_pct = forest_pct * (MAX_COLATITUDE - TROPICAL_LEVEL) /
+ (MAX_COLATITUDE * 2);
+ forest_pct -= jungle_pct;
+
+ /* 3 - 11 % */
+ river_pct = (100 - polar) * (3 + map.wetness / 12) / 100;
+
+ /* 6 % if wetness == 50 && temperature == 50 */
+ swamp_pct = factor * (map.wetness * 6 + map.temperature * 6);
+ desert_pct = factor * (map.temperature * 10 + (100 - map.wetness) * 10) ;
+}
+
+/**************************************************************************
See stdinhand.c for information on map generation methods.
FIXME: Some continent numbers are unused at the end of this function, fx
@@ -1032,23 +364,54 @@
make_random_hmap(1 + SQSIZE);
}
- /* if hmap only generator make anything else */
- if (map.generator == 1 || map.generator == 5) {
- make_land();
+ /* if hmap only generator make anything else
+ *
+ * TO DO: height map scenario
+ */
+ if ((map.generator == 1) || (map.generator == 5)) {
+ create_characteristics();
+ /*
+ * Second step, Initialize generalized terrains characteristics
+ */
+ characteristics_initialize_shores();
+ /* this is a hack to terrains-set with not frozen oceans*/
+ if (HAS_POLES) {
+ characteristics_initialize_extra_polar_land();
+ }
+ characteristics_initialize_temperature(TRUE);
+ characteristics_initialize_relief();
+ characteristics_initialize_wetness(river_pct); /* and rivers */
+
+ /*
+ * 3 step, place terrians
+ */
+ make_terrains(); /* and rivers */
+
+ assign_continent_numbers();
+
free(height_map);
height_map = NULL;
}
+ /*
+ * TODO rm it
+ */
if (!map.tinyisles) {
remove_tiny_islands();
}
+
} else {
assign_continent_numbers();
}
-
- if (!temperature_is_initialized()) {
- create_tmap(FALSE);
- }
-
+ /*
+ * 4 Place specials and huts
+ */
+
+ /* initialize needed characteristics if not yet done, */
+ if (!characteristics_are_initialized()) {
+ create_characteristics();
+ characteristics_initialize_temperature(FALSE);
+ }
+
/* some scenarios already provide specials */
if (!map.have_specials) {
add_specials(map.riches);
@@ -1058,35 +421,9 @@
make_huts(map.huts);
}
+ destroy_characteristics();
/* restore previous random state: */
set_myrand_state(rstate);
- destroy_tmap();
-}
-
-/**************************************************************************
- Convert parameters from the server into terrains percents parameters for
- the generators
-**************************************************************************/
-static void adjust_terrain_param(void)
-{
- int polar = 2 * ICE_BASE_LEVEL * map.landpercent / MAX_COLATITUDE ;
- float factor = (100.0 - polar - map.steepness * 0.8 ) / 10000;
-
-
- mountain_pct = factor * map.steepness * 90;
-
- /* 40 % if wetness == 50 & */
- forest_pct = factor * (map.wetness * 60 + 1000) ;
- jungle_pct = forest_pct * (MAX_COLATITUDE - TROPICAL_LEVEL) /
- (MAX_COLATITUDE * 2);
- forest_pct -= jungle_pct;
-
- /* 3 - 11 % */
- river_pct = (100 - polar) * (3 + map.wetness / 12) / 100;
-
- /* 6 % if wetness == 50 && temperature == 50 */
- swamp_pct = factor * (map.wetness * 6 + map.temperature * 6);
- desert_pct = factor * (map.temperature * 10 + (100 - map.wetness) * 10) ;
}
/****************************************************************************
@@ -1110,7 +447,7 @@
**************************************************************************/
static void make_huts(int number)
{
- int x, y, count = 0;
+ int x, y, index, count = 0;
create_placed_map(); /* here it means placed huts */
@@ -1118,7 +455,8 @@
/* Add a hut. But not on a polar area, on an ocean, or too close to
* another hut. */
- if (rand_map_pos_characteristic(&x, &y, WC_ALL, TT_NFROZEN, MC_NONE)) {
+ if (rand_index_characteristic(&index, CM_ALL, CM_NFROZEN, CM_ALL)) {
+ index_to_map_pos(&x, &y, index);
if (is_ocean(map_get_terrain(x, y))) {
map_set_placed(x, y); /* not good for a hut */
} else {
@@ -1184,6 +522,20 @@
map.have_specials = TRUE;
}
+/****************************************************************************
+ Add arctic and tundra squares in the arctic zone (that is, the coolest
+ 10% of the map). We also texture the pole (adding arctic, tundra, and
+ mountains). This is used in generators 2-4.
+****************************************************************************/
+static void make_polar(void)
+{
+ whole_map_iterate(x, y) {
+ if (is_characteristic(map_pos_to_index(x, y), CM_FROZEN )) {
+ map_set_terrain(x, y, T_ARCTIC);
+ }
+ } whole_map_iterate_end;
+}
+
/**************************************************************************
common variables for generator 2, 3 and 4
**************************************************************************/
@@ -1249,7 +601,7 @@
get_random_map_position_from_state(&x, &y, pstate);
if (map_get_continent(x, y) == pstate->isleindex &&
- not_placed(x, y)) {
+ map_not_placed(x, y)) {
/* the first condition helps make terrain more contiguous,
the second lets it avoid the coast: */
@@ -1273,7 +625,7 @@
map_set_placed(x, y);
}
}
- if (!not_placed(x,y)) i--;
+ if (!map_not_placed(x,y)) i--;
}
}
}
@@ -1304,7 +656,7 @@
while (i > 0 && (failsafe--) > 0) {
get_random_map_position_from_state(&x, &y, pstate);
if (map_get_continent(x, y) == pstate->isleindex
- && not_placed(x, y)) {
+ && map_not_placed(x, y)) {
/* the first condition helps make terrain more contiguous,
the second lets it avoid the coast: */
@@ -1632,7 +984,8 @@
height_map = fc_malloc(sizeof(int) * map.ysize * map.xsize);
islands = fc_malloc((MAP_NCONT+1)*sizeof(struct isledata));
create_placed_map(); /* land tiles which aren't placed yet */
- create_tmap(FALSE);
+ create_characteristics();
+ characteristics_initialize_temperature(FALSE);
whole_map_iterate(x, y) {
map_set_terrain(x, y, T_OCEAN);
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/mapgen_topology.c
freeciv_/server/generator/mapgen_topology.c
--- freeciv/server/generator/mapgen_topology.c 2004-09-17 11:14:01.000000000
+0200
+++ freeciv_/server/generator/mapgen_topology.c 2004-09-22 08:42:36.000000000
+0200
@@ -29,6 +29,14 @@
functions instead (x,y) coordinate to place terrains
colatitude is 0 at poles and MAX_COLATITUDE at equator
****************************************************************************/
+int colatitude (int index)
+{
+ int x, y;
+
+ index_to_map_pos( &x, &y, index);
+ return map_colatitude(x, y);
+}
+
int map_colatitude(int map_x, int map_y)
{
double x, y;
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/mapgen_topology.h
freeciv_/server/generator/mapgen_topology.h
--- freeciv/server/generator/mapgen_topology.h 2004-09-16 11:53:11.000000000
+0200
+++ freeciv_/server/generator/mapgen_topology.h 2004-09-22 08:42:36.000000000
+0200
@@ -45,6 +45,9 @@
extern int ice_base_colatitude;
#define ICE_BASE_LEVEL ice_base_colatitude
+#define HAS_POLES (map.temperature < 70 && !map.alltemperate)
+
+int colatitude (int index);
int map_colatitude(int map_x, int map_y);
bool near_singularity(int map_x, int map_y);
void generator_init_topology(bool autosize);
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/utilities.c
freeciv_/server/generator/utilities.c
--- freeciv/server/generator/utilities.c 2004-09-22 08:39:29.000000000
+0200
+++ freeciv_/server/generator/utilities.c 2004-09-22 08:42:36.000000000
+0200
@@ -57,11 +57,16 @@
#define pmap(x, y) (placed_map[map_pos_to_index(x, y)])
/* Checks if land has not yet been placed on pmap at (x, y) */
-bool not_placed(int x, int y)
+bool map_not_placed(int x, int y)
{
return !pmap((x), (y));
}
+bool not_placed(int index)
+{
+ return !placed_map[index];
+}
+
/* set has placed or not placed position in the pmap */
void map_set_placed(int x, int y)
{
@@ -137,6 +142,7 @@
} whole_map_iterate_index_end;
}
}
+
bool normalize_nat_pos(int *x, int *y)
{
int map_x, map_y;
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/utilities.h
freeciv_/server/generator/utilities.h
--- freeciv/server/generator/utilities.h 2004-09-22 08:39:29.000000000
+0200
+++ freeciv_/server/generator/utilities.h 2004-09-22 08:42:36.000000000
+0200
@@ -81,11 +81,13 @@
void destroy_placed_map(void);
void map_set_placed(int x, int y);
void map_unset_placed(int x, int y);
-bool not_placed(int x, int y);
+bool map_not_placed(int x, int y);
+bool not_placed(int index);
bool placed_map_is_initialized(void);
void set_all_ocean_tiles_placed(void) ;
void set_placed_near_pos(int map_x, int map_y, int dist);
+
#endif /* FC__UTILITIES_H */
|
|