[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: |
Mon, 25 Oct 2004 11:43:54 -0700 |
Reply-to: |
rt@xxxxxxxxxxx |
<URL: http://rt.freeciv.org/Ticket/Display.html?id=10201 >
diff -ruN -Xfreeciv/diff_ignore freeciv/common/map.h freeciv_/common/map.h
--- freeciv/common/map.h 2004-10-22 17:33:03.000000000 +0200
+++ freeciv_/common/map.h 2004-10-25 18:11:34.000000000 +0200
@@ -512,7 +512,30 @@
#define circle_iterate_end \
} \
} square_dxy_iterate_end; \
-}
+}
+
+/****************************************************************************
+ This iterator behaves like adjc_iterate or cardinal_adjc_iterate depending
+ on the value of card_only.
+****************************************************************************/
+#define variable_adjc_iterate(center_tile, itr_tile, 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_tile, itr_tile, _dir, _dirlist, _total) {
+
+#define variable_adjc_iterate_end \
+ } adjc_dirlist_iterate_end; \
+}
/* Iterate through all map positions adjacent to the given center map
* position, with normalization. The order of positions is unspecified. */
diff -ruN -Xfreeciv/diff_ignore freeciv/common/terrain.c
freeciv_/common/terrain.c
--- freeciv/common/terrain.c 2004-09-29 07:50:48.000000000 +0200
+++ freeciv_/common/terrain.c 2004-10-25 18:11:34.000000000 +0200
@@ -131,30 +131,6 @@
}
/****************************************************************************
- This iterator behaves like adjc_iterate or cardinal_adjc_iterate depending
- on the value of card_only.
-****************************************************************************/
-#define variable_adjc_iterate(center_tile, itr_tile, 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_tile, itr_tile, _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(const struct tile *ptile, Terrain_type_id t)
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-10-25 18:11:34.000000000
+0200
@@ -0,0 +1,958 @@
+/**********************************************************************
+ 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_OR, CM_AND, CM_NOT, CM_NOT_PLACED;
+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;
+
+
+void characteristics_initialize_shores(bool real);
+void characteristics_initialize_extra_polar_land(void);
+void characteristics_initialize_relief(void);
+void characteristics_initialize_temperature(bool real);
+void characteristics_initialize_wetness(void);
+
+#define MAX_PILE 8
+characteristic_type *pile[MAX_PILE];
+int pile_count = -1;
+
+/********************************************************************
+ push a pointer on pile
+*********************************************************************/
+static void push_pile(characteristic_type *p)
+{
+ assert(pile_count < MAX_PILE - 1);
+ pile[++pile_count] = p;
+}
+
+/********************************************************************
+ pop a pointer from pile
+*********************************************************************/
+static characteristic_type *pop_pile(void)
+{
+assert(pile_count >= 0);
+ return pile[pile_count--];
+}
+
+/********************************************************************
+ evaluate a condition in RPN
+*********************************************************************/
+bool characteristic_condition(const struct tile *ptile,
+ characteristic_type **null_ended_array)
+{
+ bool arg1 = FALSE, arg2 = FALSE;
+ while (NULL != *null_ended_array) {
+ if (&CM_NOT == *null_ended_array) {
+ arg1 = is_characteristic(ptile, *pop_pile());
+ push_pile((!arg1)? &CM_TRUE: &CM_FALSE);
+ } else if (&CM_NOT_PLACED == *null_ended_array) {
+ push_pile(not_placed(ptile) ? &CM_TRUE: &CM_FALSE);
+ } else if (&CM_AND == *null_ended_array) {
+ arg1 = is_characteristic(ptile, *pop_pile());
+ arg2 = is_characteristic(ptile, *pop_pile());
+ push_pile((arg1 && arg2) ? &CM_TRUE: &CM_FALSE);
+ } else if (&CM_OR == *null_ended_array) {
+ arg1 = is_characteristic(ptile, *pop_pile());
+ arg2 = is_characteristic(ptile, *pop_pile());
+ push_pile((arg1 || arg2) ? &CM_TRUE: &CM_FALSE);
+ } else {
+ push_pile(*null_ended_array);
+ }
+ null_ended_array++;
+ }
+ assert(0 == pile_count);
+ pile_count--;
+ return is_characteristic(ptile, *pile[0]);
+}
+
+/********************************************************************
+ evaluate a condition in RPN
+*********************************************************************/
+bool filter_characteristic(const struct tile *ptile, const void *data)
+{
+ data_filter_chracteristic_type *pdata =
+ (data_filter_chracteristic_type *) data;
+ return characteristic_condition(ptile, pdata->null_ended_array);
+}
+
+/**************************************************************************
+ return TRUE if initialized
+*************************************************************************/
+bool characteristics_are_initialized(void)
+{
+ return characteristic_map != NULL;
+}
+
+/****************************************************************************
+ create the map and initialize CM_XXX
+ call other inizialize methodes
+ if has_height_map is FALSE only initialize temperature with not height map
+ (hack for gen 2-4, and for loaded maps with not hut or spetials)
+****************************************************************************/
+void create_characteristics(bool has_height_map)
+{
+ assert( !characteristics_are_initialized());
+ characteristic_map = fc_malloc (sizeof(characteristic_type) * MAX_MAP_INDEX);
+ whole_map_iterate(i) {
+ BV_CLR_ALL(characteristic_map[i->index]);
+ BV_SET(characteristic_map[i->index], CB_TRUE);
+ }whole_map_iterate_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);
+
+
+ if (has_height_map) {
+ /* now initialize the oceanic tiles and the shore_level */
+ characteristics_initialize_shores(TRUE);
+ /* this is a hack to terrains-set with not frozen oceans*/
+ if (HAS_POLES) {
+ characteristics_initialize_extra_polar_land();
+ }
+ /*
+ initialize the temperature and relief characteristics, these call
+ need, other the height map and colatitude, to known the oceanics
+ tiles and the shore_level
+ */
+ characteristics_initialize_relief();
+ characteristics_initialize_temperature(TRUE);
+
+ /*
+ now initialize wetness, this call need other characteristics to be
+ initilaized.
+ */
+ characteristics_initialize_wetness(); /* and rivers */
+
+ } else {
+ characteristics_initialize_shores(FALSE);
+ characteristics_initialize_temperature(FALSE);
+ }
+}
+
+/****************************************************************************
+ 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(const struct tile *ptile, characteristic_type mask )
+{
+ return BV_CHECK_MASK(characteristic_map[ptile->index], mask);
+}
+
+/******************************************************************
+ Return the number of tiles adjacent to the given place with the right
+ characteristic mask.
+ ******************************************************************/
+int count_characteristic_near(const struct tile *ptile, bool cardinal_only,
+ bool percentage
+ ,characteristic_type mask)
+{
+ int count = 0, total = 0;
+
+ variable_adjc_iterate(ptile, ptile1, cardinal_only) {
+ if (is_characteristic(ptile1, 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(i) {
+ if (is_characteristic(i, mask)) {
+ map_set_placed(i);
+ }
+ } whole_map_iterate_end;
+}
+
+/*************************************************************************
+ set CB_OCEANIC in thiles will be oceans
+ ************************************************************************/
+void characteristics_initialize_shores(bool real)
+{
+ if (real) {
+ if (HAS_POLES) {
+ normalize_hmap_poles();
+ }
+ hmap_shore_level = (hmap_max_level * (100 - map.landpercent)) / 100;
+ whole_map_iterate(i) {
+ if (height_map[i->index] < hmap_shore_level) {
+ BV_SET(characteristic_map[i->index], CB_OCEANIC);
+ }
+ }
+ whole_map_iterate_end;
+ if (HAS_POLES) {
+ renormalize_hmap_poles();
+ }
+ } else {
+ whole_map_iterate(ptile) {
+ if (is_ocean(map_get_terrain(ptile))) {
+ BV_SET(characteristic_map[ptile->index], CB_OCEANIC);
+ }
+ } whole_map_iterate_end;
+ }
+}
+
+/*************************************************************************
+ if separatepoles is set, return false if this tile has to keep ocean
+************************************************************************/
+static bool ok_for_separate_poles(const struct tile *ptile)
+{
+ if (!map.separatepoles) {
+ return TRUE;
+ }
+ adjc_iterate(ptile, ptile1) {
+ if(!is_characteristic(ptile1, CM_OCEANIC) &&
+ (map_colatitude(ptile1) > 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(i) {
+ if ((map_colatitude(i) <= 2 * ICE_BASE_LEVEL) &&
+ ok_for_separate_poles(i)) {
+ BV_CLR(characteristic_map[i->index], CB_OCEANIC);
+ }
+ } whole_map_iterate_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 map_is_too_flat(const struct tile *ptile,
+ int thill, int my_height)
+{
+ int higher_than_me = 0;
+
+ square_iterate(ptile, 2, ptile1) {
+ if (hmap(ptile1) > thill) {
+ return FALSE;
+ }
+ if (hmap(ptile1) > my_height) {
+ if (map_distance(ptile, ptile1) == 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 map_is_too_high(const struct tile *ptile,
+ int thill, int my_height)
+{
+ square_iterate(ptile, 1, ptile1) {
+ if (hmap(ptile1) + (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(i) {
+ if (!is_characteristic(i, CM_OCEANIC) &&
+ ((hmap_mountain_level < height_map[i->index] &&
+ (myrand(10) > 5
+ || !map_is_too_high(i, hmap_mountain_level, height_map[i->index])))
+ || map_is_too_flat(i, hmap_mountain_level, height_map[i->index]))) {
+ /* Randomly place hills and mountains on "high" tiles. */
+ if (myrand(100) > 70) {
+ BV_SET(characteristic_map[i->index], CB_ABRUPT);
+ } else {
+ BV_SET(characteristic_map[i->index], CB_HILLY);
+ }
+ } else {
+ BV_SET(characteristic_map[i->index], CB_FLAT);
+ }
+ } whole_map_iterate_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(i) {
+
+ /* the base temperature is equal to base map_colatitude */
+ int t = map_colatitude(i) ;
+ if (!real) {
+ temperature[i->index] = t;
+ } else {
+ /* height land can be 30% collest */
+ float height = - 0.3 * MAX(0, height_map[i->index] - 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->index] = t * (1.0 + temperate) * (1.0 + height);
+ }
+ } whole_map_iterate_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 */
+ if (!map.alltemperate) {
+ adjust_int_map(temperature, MAX_COLATITUDE);
+ }
+ /* now simplify to 4 base values */
+ whole_map_iterate(i) {
+ int t = temperature[i->index];
+
+ /* 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 (map_colatitude(i) < 2 * ICE_BASE_LEVEL) {
+ BV_SET(characteristic_map[i->index], CB_FROZEN);
+ }
+
+ else if (t >= TROPICAL_LEVEL ) {
+ BV_SET(characteristic_map[i->index], CB_TROPICAL);
+ } else if (t >= COLD_LEVEL) {
+ BV_SET(characteristic_map[i->index], CB_TEMPERATE);
+ } else if (t >= 2 * ICE_BASE_LEVEL) {
+ BV_SET(characteristic_map[i->index], CB_COLD);
+ } else {
+ BV_SET(characteristic_map[i->index], CB_FROZEN);
+ }
+ } whole_map_iterate_end;
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_blocked(const struct tile *ptile, int *river_map)
+{
+ if (TEST_BIT(river_map[ptile->index], RS_BLOCKED))
+ return 1;
+
+ /* any un-blocked? */
+ cardinal_adjc_iterate(ptile, ptile1) {
+ if (!TEST_BIT(river_map[ptile1->index], 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(const struct tile *ptile, int *river_map)
+{
+ return (count_characteristic_near(ptile, TRUE, FALSE, CM_RIVER)
+ > 1) ? 1 : 0;
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_highlands(const struct tile *ptile, int *river_map)
+{
+ return ((is_characteristic(ptile, CM_HILLY) ? 1 : 0) +
+ (is_characteristic(ptile, CM_ABRUPT) ? 2 : 0));
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_adjacent_ocean(const struct tile *ptile, int *river_map)
+{
+ return 100 - count_characteristic_near(ptile, TRUE, TRUE, CM_OCEANIC);
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_adjacent_river(const struct tile *ptile, int *river_map)
+{
+ return 100 - count_characteristic_near(ptile, TRUE, TRUE, CM_RIVER);
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_adjacent_highlands(const struct tile *ptile,
+ int *river_map)
+{
+ return (count_characteristic_near(ptile, TRUE, TRUE, CM_HILLY)
+ + 2 * count_characteristic_near(ptile, TRUE, TRUE, CM_ABRUPT));
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_height_map(const struct tile *ptile, int *river_map)
+{
+ return height_map[ptile->index];
+}
+
+/*********************************************************************
+ Called from make_river. Marks all directions as blocked. -Erik Sigra
+*********************************************************************/
+static void river_blockmark(const struct tile *ptile, int *river_map)
+{
+ freelog(LOG_DEBUG, "Blockmarking (%d) and adjacent tiles.",
+ ptile->index);
+
+ river_map[ptile->index] |= (1u << RS_BLOCKED);
+
+ cardinal_adjc_iterate(ptile, ptile1) {
+ river_map[ptile1->index] |= (1u << RS_BLOCKED);
+ } cardinal_adjc_iterate_end;
+}
+
+struct test_func {
+ int (*func)(const struct tile *, 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(struct tile *ptile, 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[ptile->index] |= (1u << RS_RIVER);
+ freelog(LOG_DEBUG,
+ "The tile at (%d) has been marked as river in river_map.\n",
+ ptile->index);
+
+ /* Test if the river is done. */
+ /* We arbitrarily make rivers end at the poles. */
+ if (count_characteristic_near(ptile, TRUE, TRUE, CM_RIVER)
+ + count_characteristic_near(ptile, TRUE, TRUE, CM_OCEANIC) > 0
+ || (is_characteristic(ptile, CM_FROZEN)
+ && is_characteristic(ptile, CM_FLAT))) {
+
+ freelog(LOG_DEBUG,
+ "The river ended at (%d).\n", ptile->index);
+ return TRUE;
+ }
+
+ /* Else choose a direction to continue the river. */
+ freelog(LOG_DEBUG,
+ "The river did not end at (%d). Evaluating directions...\n",
+ ptile->index);
+
+ /* Mark all available cardinal directions as available. */
+ memset(rd_direction_is_valid, 0, sizeof(rd_direction_is_valid));
+ cardinal_adjc_dir_iterate(ptile, ptile1, 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(ptile, ptile1, dir) {
+
+ if (rd_direction_is_valid[dir]) {
+ rd_comparison_val[dir] =
+ (test_funcs[func_num].func) (ptile1 , river_map);
+ 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(ptile, ptile1, 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(ptile, ptile1, 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(ptile, ptile1, dir) {
+ if (rd_direction_is_valid[dir]) {
+ if (direction > 0) {
+ direction--;
+ } else {
+ river_blockmark(ptile1, river_map);
+ ptile = ptile1;
+ 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(int *river_probability)
+{
+ int river_map[MAX_MAP_INDEX];
+ int polar = 2 * ICE_BASE_LEVEL * map.landpercent / MAX_COLATITUDE ;
+ /* magic math to evaluater river_pct 3 - 11 % */
+ int river_pct = (100 - polar) * (3 + map.wetness / 12) / 100;
+
+ /* 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) {
+ characteristic_type *condition[] = {&CM_NFROZEN, NULL};
+ data_filter_chracteristic_type data;
+ struct tile *ptile ;
+
+ data.null_ended_array = condition;
+ ptile = rand_map_pos_filtered((void *)&data, filter_characteristic);
+
+ if (NULL == ptile) {
+ break; /* mo more spring places */
+ }
+
+ /* Check if it is suitable to start a river on the current tile.
+ */
+ if ((myrand(100) < river_probability[ptile->index])
+ /* Don't start a river on a tile is surrounded by > 1 river +
+ ocean tile. */
+ && (count_characteristic_near(ptile, TRUE, FALSE, CM_RIVER)
+ + count_characteristic_near(ptile, 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(ptile, TRUE, TRUE, CM_ABRUPT)
+ + count_characteristic_near(ptile, 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(ptile, 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(ptile, CM_ABRUPT)
+ || (iteration_counter > RIVERS_MAXTRIES / 10 * 7))
+ ) {
+
+ /* Reset river_map before making a new river. */
+ whole_map_iterate(i) {
+ river_map[i->index] = 0;
+ } whole_map_iterate_end;
+
+ freelog(LOG_DEBUG,
+ "Found a suitable starting tile for a river at (%d)."
+ " Starting to make it.",
+ ptile->index);
+
+ /* Try to make a river. If it is OK, apply it to the map. */
+ if (make_river(ptile, river_map)) {
+ whole_map_iterate(ptile1) {
+ if (TEST_BIT(river_map[ptile1->index], RS_RIVER)) {
+ BV_SET(characteristic_map[ptile1->index], CB_RIVER);
+ current_riverlength++;
+ map_set_placed(ptile1);
+ /* reduce probability near a river */
+ circle_iterate(ptile1, 4, ptile2) {
+ river_probability[ptile2->index] *= 0.9;
+ } circle_iterate_end;
+ freelog(LOG_DEBUG, "Applied a river to (%d).",
+ ptile1->index);
+ }
+ } 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();
+}
+
+#define colatitude_is_dry(i) \
+ (map_colatitude((i)) <= DRY_MAX_LEVEL \
+ && map_colatitude((i)) > DRY_MIN_LEVEL)
+
+void characteristics_initialize_wetness()
+{
+ int wetness[MAX_MAP_INDEX];
+
+ /* there wetness[] means the probability to start a river*/
+ whole_map_iterate(i) {
+ if (colatitude_is_dry(i)) {
+ wetness[i->index] = 70;
+ } else {
+ wetness[i->index] = 100;
+ }
+ } whole_map_iterate_end;
+
+ make_rivers(wetness);
+
+ /* now wetness[] means amount of water */
+ whole_map_iterate(i) {
+ float dry_bonus = colatitude_is_dry(i) ? 1 : 0;
+ float tropical_bonus = (map_colatitude(i) > TROPICAL_LEVEL) ? 1 : 0;
+ float height_bonus = MAX(0, (height_map[i->index] - 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->index] = (100 - 10 * dry_bonus + 5 * tropical_bonus)
+ * (100 + 30 * river_bonus + 20 * ocean_bonus)
+ * (100 + 30 * height_bonus) / 100;
+ } whole_map_iterate_end;
+
+ smooth_int_map(wetness, FALSE);
+ {
+ data_filter_chracteristic_type data;
+ characteristic_type CM_AVOID;
+
+ BV_CLR_ALL(CM_AVOID);
+ BV_SET(CM_AVOID, CB_FROZEN);
+ BV_SET(CM_AVOID, CB_OCEANIC);
+ {
+ characteristic_type *condition[]
+ = {&CM_OCEANIC, &CM_NOT, &CM_FROZEN, &CM_AND, NULL};
+ data.null_ended_array = condition;
+ adjust_int_map_filtered(wetness, 1000, (void *)&data,
+ filter_characteristic);
+ }
+ {
+ characteristic_type *condition[]
+ = {&CM_AVOID, &CM_NOT, &CM_FLAT, &CM_AND, NULL};
+ data.null_ended_array = condition;
+ adjust_int_map_filtered(wetness, 1000, (void *)&data,
+ filter_characteristic);
+ }
+ {
+ characteristic_type *condition[]
+ = {&CM_AVOID, &CM_NOT, &CM_HILLY, &CM_AND, NULL};
+ data.null_ended_array = condition;
+ adjust_int_map_filtered(wetness, 1000, (void *)&data,
+ filter_characteristic);
+ }
+ {
+ characteristic_type *condition[]
+ = {&CM_AVOID, &CM_NOT, &CM_ABRUPT, &CM_AND, NULL};
+ data.null_ended_array = condition;
+ adjust_int_map_filtered(wetness, 1000, (void *)&data,
+ filter_characteristic);
+ }
+ }
+ whole_map_iterate(i) {
+ if (is_characteristic(i, CM_OCEANIC)) {
+ continue;
+ }
+ if (wetness[i->index] < 300) {
+ BV_SET(characteristic_map[i->index], CB_DRY);
+ } else if(wetness[i->index] < 700){
+ BV_SET(characteristic_map[i->index], CB_MEDIUM);
+ } else {
+ BV_SET(characteristic_map[i->index], CB_WET);
+ }
+ } whole_map_iterate_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-10-25 18:11:34.000000000
+0200
@@ -0,0 +1,63 @@
+/**********************************************************************
+ 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;
+/* operators, only pointer to these var are used */
+extern characteristic_type CM_OR, CM_AND, CM_NOT, CM_NOT_PLACED;
+/* 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;
+
+typedef struct {
+ /*
+ the **null_ended_array point to a bolean expresion in RPN
+ sample: CM_FROZEN && !CM_OCEANIC is writed has
+ data.null_ended_array = &{&CM_FROZEN, &CM_OCEANIC, &CM_NOT, &CM_AND, NULL};
+ */
+ characteristic_type **null_ended_array;
+} data_filter_chracteristic_type;
+bool filter_characteristic(const struct tile *ptile, const void *data);
+bool characteristic_condition(const struct tile *ptile,
+ characteristic_type **null_ended_array);
+
+bool characteristics_are_initialized(void);
+void create_characteristics(bool has_height_map);
+void destroy_characteristics(void);
+
+bool is_characteristic(const struct tile *ptile, characteristic_type mask );
+int count_characteristic_near(const struct tile *ptile, bool cardinal_only,
+ bool percentage, characteristic_type mask);
+
+#endif /* FC__CHARACTERISTICS_H */
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/height_map.c
freeciv_/server/generator/height_map.c
--- freeciv/server/generator/height_map.c 2004-10-17 10:03:53.000000000
+0200
+++ freeciv_/server/generator/height_map.c 2004-10-25 18:11:34.000000000
+0200
@@ -191,20 +191,20 @@
/* set initial points */
for (xn = 0; xn < xdiv2; xn++) {
for (yn = 0; yn < ydiv2; yn++) {
- do_in_map_pos(ptile, (xn * xmax / xdiv), (yn * ymax / ydiv)) {
- /* set initial points */
- hmap(ptile) = myrand(2 * step) - (2 * step) / 2;
+ struct tile *ptile = native_pos_to_tile(xn * xmax / xdiv,
+ yn * ymax / ydiv);
+ /* set initial points */
+ hmap(ptile) = myrand(2 * step) - (2 * step) / 2;
+
+ if (near_singularity(ptile)) {
+ /* avoid edges (topological singularities) */
+ hmap(ptile) -= avoidedge;
+ }
- if (near_singularity(ptile)) {
- /* avoid edges (topological singularities) */
- hmap(ptile) -= avoidedge;
- }
-
- if (map_colatitude(ptile) <= ICE_BASE_LEVEL / 2 ) {
- /* separate poles and avoid too much land at poles */
- hmap(ptile) -= myrand(avoidedge);
- }
- } do_in_map_pos_end;
+ if (map_colatitude(ptile) <= ICE_BASE_LEVEL / 2 ) {
+ /* separate poles and avoid too much land at poles */
+ hmap(ptile) -= myrand(avoidedge);
+ }
}
}
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-10-25 18:11:34.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-10-15 19:16:54.000000000 +0200
+++ freeciv_/server/generator/mapgen.c 2004-10-25 18:20:20.000000000 +0200
@@ -35,9 +35,8 @@
#include "mapgen.h"
#include "mapgen_topology.h"
#include "startpos.h"
-#include "temperature_map.h"
#include "utilities.h"
-
+#include "characteristics.h"
/* Old-style terrain enumeration: deprecated. */
enum {
@@ -55,17 +54,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;
@@ -75,272 +63,36 @@
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(ptile) \
- (map_colatitude((ptile)) <= DRY_MAX_LEVEL \
- && map_colatitude((ptile)) > DRY_MIN_LEVEL \
- && count_ocean_near_tile((ptile), 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(ptile) ((hmap((ptile)) < 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(const struct tile *ptile, wetness_c c)
-{
- switch(c) {
- case WC_ALL:
- return TRUE;
- case WC_DRY:
- return map_pos_is_dry(ptile);
- case WC_NDRY:
- return !map_pos_is_dry(ptile);
- }
- assert(0);
- return FALSE;
-}
-
-/***************************************************************************
- Checks if the given location satisfy some miscellaneous condition
-***************************************************************************/
-static bool test_miscellaneous(const struct tile *ptile, miscellaneous_c c)
-{
- switch(c) {
- case MC_NONE:
- return TRUE;
- case MC_LOW:
- return map_pos_is_low(ptile);
- case MC_NLOW:
- return !map_pos_is_low(ptile);
- }
- 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(const struct tile *ptile, const void *data)
-{
- const struct DataFilter *filter = data;
-
- return not_placed(ptile)
- && tmap_is(ptile, filter->tc)
- && test_wetness(ptile, filter->wc)
- && test_miscellaneous(ptile, 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 struct tile *rand_map_pos_characteristic(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(&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(struct tile *ptile,
- int thill, int my_height)
-{
- int higher_than_me = 0;
- square_iterate(ptile, 2, tile1) {
- if (hmap(tile1) > thill) {
- return FALSE;
- }
- if (hmap(tile1) > my_height) {
- if (map_distance(ptile, tile1) == 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(struct tile *ptile,
- int thill, int my_height)
-{
- square_iterate(ptile, 1, tile1) {
- if (hmap(tile1) + (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.
-**************************************************************************/
-static void make_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(ptile) {
- if (not_placed(ptile) &&
- ((hmap_mountain_level < hmap(ptile) &&
- (myrand(10) > 5
- || !terrain_is_too_high(ptile, hmap_mountain_level, hmap(ptile))))
- || terrain_is_too_flat(ptile, hmap_mountain_level, hmap(ptile)))) {
- /* 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(ptile, TT_NHOT)) {
- map_set_terrain(ptile, T_MOUNTAINS);
- map_set_placed(ptile);
- } else {
- map_set_terrain(ptile, T_HILLS);
- map_set_placed(ptile);
- }
- }
- } whole_map_iterate_end;
-}
-
-/****************************************************************************
- 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(ptile) {
- if (tmap_is(ptile, TT_FROZEN)
- || (tmap_is(ptile, TT_COLD)
- && (myrand(10) > 7)
- && is_temperature_type_near(ptile, TT_FROZEN))) {
- map_set_terrain(ptile, 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(struct tile *ptile)
-{
- if (!map.separatepoles) {
- return TRUE;
- }
- adjc_iterate(ptile, tile1) {
- if (!is_ocean(map_get_terrain(tile1)) &&
- map_get_continent(tile1) != 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(FALSE);
- whole_map_iterate(ptile) {
- if ((tmap_is(ptile, TT_FROZEN ) &&
- ok_for_separate_poles(ptile))
- ||
- (tmap_is(ptile, TT_COLD ) &&
- (myrand(10) > 7) &&
- is_temperature_type_near(ptile, TT_FROZEN) &&
- ok_for_separate_poles(ptile))) {
- map_set_terrain(ptile, T_UNKNOWN);
- map_set_continent(ptile, 0);
- }
- } whole_map_iterate_end;
-}
/**************************************************************************
Recursively generate terrains.
**************************************************************************/
static void place_terrain(struct tile *ptile, int diff,
- Terrain_type_id ter, int *to_be_placed,
- wetness_c wc,
- temperature_type tc,
- miscellaneous_c mc)
+ Terrain_type_id ter, int *to_be_placed,
+ characteristic_type **null_ended_array)
{
if (*to_be_placed <= 0) {
return;
}
assert(not_placed(ptile));
map_set_terrain(ptile, ter);
+ if (is_characteristic(ptile, CM_RIVER)) {
+ map_set_special(ptile, S_RIVER);
+ }
map_set_placed(ptile);
(*to_be_placed)--;
- cardinal_adjc_iterate(ptile, tile1) {
- int Delta = abs(map_colatitude(tile1) - map_colatitude(ptile)) / L_UNIT
- + abs(hmap(tile1) - (hmap(ptile))) / H_UNIT;
- if (not_placed(tile1)
- && tmap_is(tile1, tc)
- && test_wetness(tile1, wc)
- && test_miscellaneous(tile1, mc)
+ cardinal_adjc_iterate(ptile, ptile1) {
+ int Delta = abs(map_colatitude(ptile1) - map_colatitude(ptile)) / L_UNIT
+ + abs(hmap(ptile1) - (hmap(ptile))) / H_UNIT;
+ if (not_placed(ptile1)
+ && characteristic_condition(ptile1, null_ended_array)
+ && (is_characteristic(ptile1, CM_RIVER)
+ ? terrain_has_flag(ter, TER_CAN_HAVE_RIVER) : TRUE)
&& Delta < diff
&& myrand(10) > 4) {
- place_terrain(tile1, diff - 1 - Delta, ter, to_be_placed, wc, tc, mc);
+ place_terrain(ptile1, diff - 1 - Delta, ter,
+ to_be_placed, null_ended_array);
}
} cardinal_adjc_iterate_end;
}
@@ -351,10 +103,13 @@
**************************************************************************/
static void make_plain(struct tile *ptile, int *to_be_placed )
{
+ if (!not_placed(ptile)) {
+ return;
+ }
/* in cold place we get tundra instead */
- if (tmap_is(ptile, TT_FROZEN)) {
+ if (is_characteristic(ptile, CM_FROZEN)) {
map_set_terrain(ptile, T_ARCTIC);
- } else if (tmap_is(ptile, TT_COLD)) {
+ } else if (is_characteristic(ptile, CM_COLD)) {
map_set_terrain(ptile, T_TUNDRA);
} else {
if (myrand(100) > 50) {
@@ -363,6 +118,9 @@
map_set_terrain(ptile, T_PLAINS);
}
}
+ if (is_characteristic(ptile, CM_RIVER)) {
+ map_set_special(ptile, S_RIVER);
+ }
map_set_placed(ptile);
(*to_be_placed)--;
}
@@ -384,12 +142,15 @@
/**************************************************************************
This place randomly a cluster of terrains with some characteristics
**************************************************************************/
-#define PLACE_ONE_TYPE(count, alternate, ter, wc, tc, mc, weight) \
+#define PLACE_ONE_TYPE(count, alternate, ter, null_ended_array, weight) \
if((count) > 0) { \
struct tile *ptile; \
+ data.null_ended_array = null_ended_array; \
/* Place some terrains */ \
- if ((ptile = rand_map_pos_characteristic((wc), (tc), (mc)))) { \
- place_terrain(ptile, (weight), (ter), &(count), (wc),(tc), (mc)); \
+ if (NULL != \
+ (ptile = rand_map_pos_filtered(&data, filter_characteristic))) {\
+ place_terrain(ptile, (weight), (ter), &(count), \
+ (data).null_ended_array); \
} else { \
/* If rand_map_pos_temperature returns FALSE we may as well stop*/ \
/* looking for this time and go to alternate type. */ \
@@ -411,9 +172,30 @@
int forests_count = 0;
int jungles_count = 0;
int deserts_count = 0;
- int alt_deserts_count = 0;
int plains_count = 0;
int swamps_count = 0;
+ data_filter_chracteristic_type data;
+
+ create_placed_map();
+ whole_map_iterate(ptile) {
+ if (is_characteristic(ptile, CM_OCEANIC)) {
+ map_set_placed(ptile);
+ map_set_terrain(ptile, T_OCEAN);
+ } else {
+ if (is_characteristic(ptile, CM_HILLY)) {
+ map_set_placed(ptile);
+ map_set_terrain(ptile, T_HILLS);
+ /* hack for terrains-set, where hills are too green */
+ if (is_characteristic(ptile, CM_FROZEN)) {
+ map_set_placed(ptile);
+ map_set_terrain(ptile, T_MOUNTAINS);
+ }
+ } else if (is_characteristic(ptile, CM_ABRUPT)) {
+ map_set_placed(ptile);
+ map_set_terrain(ptile, T_MOUNTAINS);
+ }
+ }
+ } whole_map_iterate_end;
whole_map_iterate(ptile) {
if (not_placed(ptile)) {
@@ -433,24 +215,50 @@
/* the placement loop */
do {
-
- PLACE_ONE_TYPE(forests_count , plains_count, T_FOREST,
- WC_ALL, TT_NFROZEN, MC_NONE, 60);
- PLACE_ONE_TYPE(jungles_count, forests_count , T_JUNGLE,
- WC_ALL, TT_TROPICAL, MC_NONE, 50);
- PLACE_ONE_TYPE(swamps_count, forests_count , T_SWAMP,
- WC_NDRY, TT_HOT, MC_LOW, 50);
- PLACE_ONE_TYPE(deserts_count, alt_deserts_count , T_DESERT,
- WC_DRY, TT_NFROZEN, MC_NLOW, 80);
- PLACE_ONE_TYPE(alt_deserts_count, plains_count , T_DESERT,
- WC_ALL, TT_NFROZEN, MC_NLOW, 40);
-
+ {
+ characteristic_type *null_ended_array[] =
+ {&CM_NOT_PLACED, &CM_NDRY, &CM_AND,
+ &CM_NFROZEN, &CM_FLAT, &CM_AND,
+ &CM_AND, NULL};
+ PLACE_ONE_TYPE(forests_count , plains_count, T_FOREST,
+ null_ended_array, 60);
+ }
+ {
+ characteristic_type *null_ended_array[] =
+ {&CM_NOT_PLACED, &CM_NDRY, &CM_AND,
+ &CM_TROPICAL, &CM_FLAT, &CM_AND,
+ &CM_AND, NULL};
+ PLACE_ONE_TYPE(jungles_count, forests_count , T_JUNGLE,
+ null_ended_array, 50);
+
+ }
+ {
+ characteristic_type *null_ended_array[] =
+ {&CM_NOT_PLACED, &CM_WET, &CM_AND,
+ &CM_HOT, &CM_FLAT, &CM_AND,
+ &CM_AND, NULL};
+ PLACE_ONE_TYPE(swamps_count, jungles_count , T_SWAMP,
+ null_ended_array, 30);
+
+ }
+ {
+ characteristic_type *null_ended_array[] =
+ {&CM_NOT_PLACED, &CM_DRY, &CM_AND,
+ &CM_HOT, &CM_FLAT, &CM_AND,
+ &CM_AND, NULL};
+ PLACE_ONE_TYPE(deserts_count, plains_count , T_DESERT,
+ null_ended_array, 80);
+ }
/* make the plains and tundras */
if (plains_count > 0) {
struct tile *ptile;
-
- /* Don't use any restriction here ! */
- if ((ptile = rand_map_pos_characteristic(WC_ALL, TT_ALL, MC_NONE))) {
+ /* Don't use any restriction here! */
+ data_filter_chracteristic_type data;
+ characteristic_type *condition[] = {&CM_NOT_PLACED, NULL};
+
+ data.null_ended_array = condition;
+ if (NULL != (ptile = rand_map_pos_filtered((void *)&data,
+ filter_characteristic))) {
make_plain(ptile, &plains_count);
} else {
/* If rand_map_pos_temperature returns FALSE we may as well stop
@@ -459,491 +267,10 @@
}
}
} while (forests_count > 0 || jungles_count > 0
- || deserts_count > 0 || alt_deserts_count > 0
+ || deserts_count > 0
|| plains_count > 0 || swamps_count > 0 );
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_blocked(struct tile *ptile)
-{
- if (TEST_BIT(rmap(ptile), RS_BLOCKED))
- return 1;
-
- /* any un-blocked? */
- cardinal_adjc_iterate(ptile, tile1) {
- if (!TEST_BIT(rmap(tile1), 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(struct tile *ptile)
-{
- return (count_special_near_tile(ptile, TRUE, FALSE, S_RIVER) > 1) ? 1 : 0;
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_highlands(struct tile *ptile)
-{
- return (((map_get_terrain(ptile) == T_HILLS) ? 1 : 0) +
- ((map_get_terrain(ptile) == T_MOUNTAINS) ? 2 : 0));
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_ocean(struct tile *ptile)
-{
- return 100 - count_ocean_near_tile(ptile, TRUE, TRUE);
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_river(struct tile *ptile)
-{
- return 100 - count_special_near_tile(ptile, TRUE, TRUE, S_RIVER);
-}
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_highlands(struct tile *ptile)
-{
- return (count_terrain_near_tile(ptile, TRUE, TRUE, T_HILLS)
- + 2 * count_terrain_near_tile(ptile, TRUE, TRUE, T_MOUNTAINS));
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_swamp(struct tile *ptile)
-{
- return (map_get_terrain(ptile) != T_SWAMP) ? 1 : 0;
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_swamp(struct tile *ptile)
-{
- return 100 - count_terrain_near_tile(ptile, TRUE, TRUE, T_SWAMP);
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_height_map(struct tile *ptile)
-{
- return hmap(ptile);
-}
-
-/*********************************************************************
- Called from make_river. Marks all directions as blocked. -Erik Sigra
-*********************************************************************/
-static void river_blockmark(struct tile *ptile)
-{
- freelog(LOG_DEBUG, "Blockmarking (%d, %d) and adjacent tiles.",
- ptile->x, ptile->y);
-
- rmap(ptile) |= (1u << RS_BLOCKED);
-
- cardinal_adjc_iterate(ptile, tile1) {
- rmap(tile1) |= (1u << RS_BLOCKED);
- } cardinal_adjc_iterate_end;
-}
-
-struct test_func {
- int (*func)(struct tile *ptile);
- 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(struct tile *ptile)
-{
- /* 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(ptile) |= (1u << RS_RIVER);
- freelog(LOG_DEBUG,
- "The tile at (%d, %d) has been marked as river in river_map.\n",
- ptile->x, ptile->y);
-
- /* Test if the river is done. */
- /* We arbitrarily make rivers end at the poles. */
- if (count_special_near_tile(ptile, TRUE, TRUE, S_RIVER) > 0
- || count_ocean_near_tile(ptile, TRUE, TRUE) > 0
- || (map_get_terrain(ptile) == T_ARCTIC
- && map_colatitude(ptile) < 0.8 * COLD_LEVEL)) {
-
- freelog(LOG_DEBUG,
- "The river ended at (%d, %d).\n", ptile->x, ptile->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",
- ptile->x, ptile->y);
-
- /* Mark all available cardinal directions as available. */
- memset(rd_direction_is_valid, 0, sizeof(rd_direction_is_valid));
- cardinal_adjc_dir_iterate(ptile, tile1, 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(ptile, tile1, dir) {
- if (rd_direction_is_valid[dir]) {
- rd_comparison_val[dir] = (test_funcs[func_num].func) (tile1);
- 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(ptile, tile1, 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(ptile, tile1, 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(ptile, tile1, dir) {
- if (rd_direction_is_valid[dir]) {
- if (direction > 0) {
- direction--;
- } else {
- river_blockmark(ptile);
- ptile = tile1;
- 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)
-{
- struct tile *ptile;
-
- /* 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 (!(ptile = rand_map_pos_characteristic(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(ptile))
-
- /* Don't start a river on river. */
- && !map_has_special(ptile, S_RIVER)
-
- /* Don't start a river on a tile is surrounded by > 1 river +
- ocean tile. */
- && (count_special_near_tile(ptile, TRUE, FALSE, S_RIVER)
- + count_ocean_near_tile(ptile, 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(ptile, TRUE, TRUE, T_HILLS)
- + count_terrain_near_tile(ptile, 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(ptile) != 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(ptile) != 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(ptile) != 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(ptile) != 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.",
- ptile->x, ptile->y);
-
- /* Try to make a river. If it is OK, apply it to the map. */
- if (make_river(ptile)) {
- whole_map_iterate(tile1) {
- if (TEST_BIT(rmap(tile1), RS_RIVER)) {
- Terrain_type_id t = map_get_terrain(tile1);
-
- 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(tile1, t);
- }
- map_set_special(tile1, S_RIVER);
- current_riverlength++;
- map_set_placed(tile1);
- freelog(LOG_DEBUG, "Applied a river to (%d, %d).",
- tile1->x, tile1->y);
- }
- } 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(ptile) {
- map_set_terrain(ptile, T_UNKNOWN); /* set as oceans count is used */
- if (hmap(ptile) < hmap_shore_level) {
- map_set_terrain(ptile, 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 */
}
/**************************************************************************
@@ -983,6 +310,32 @@
}
/**************************************************************************
+ Convert parameters from the server into terrains percents parameters for
+ the generators, this is primary used has a hack for gen 2-4
+**************************************************************************/
+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
@@ -995,7 +348,7 @@
based on the map.size server parameter and the specified topology. If
not map.xsize and map.ysize will be used.
**************************************************************************/
-void map_fractal_generate(bool autosize)
+void map_generate(bool autosize)
{
/* save the current random state: */
RANDOM_STATE rstate = get_myrand_state();
@@ -1043,22 +396,38 @@
make_random_hmap(MAX(1, 1 + SQSIZE
- (map.startpos ? game.nplayers / 4 : 0)));
}
+ /*
+ * if height_map only generator make anything else
+ */
+ if ((map.generator == 1) || (map.generator == 2)) {
- /* if hmap only generator make anything else */
- if (map.generator == 1 || map.generator == 2) {
- make_land();
+ /************************************************************
+ * 2d step, Initialize generalized terrains characteristics *
+ ************************************************************/
+ create_characteristics(TRUE);
+
+ /****************************
+ * 3th step, place terrians *
+ ****************************/
+ make_terrains(); /* and rivers */
free(height_map);
height_map = NULL;
}
+ /* best detroy there, the old remove_tiny_islands can't update */
+ destroy_characteristics();
if (!map.tinyisles) {
remove_tiny_islands();
}
}
-
- 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(FALSE);
+ }
+
/* some scenarios already provide specials */
if (!map.have_specials) {
add_specials(map.riches);
@@ -1068,9 +437,9 @@
make_huts(map.huts);
}
+ destroy_characteristics();
/* restore previous random state: */
set_myrand_state(rstate);
- destroy_tmap();
/* We don't want random start positions in a scenario which already
* provides them. */
@@ -1100,32 +469,6 @@
assign_continent_numbers(FALSE);
}
-/**************************************************************************
- 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) ;
-}
-
/****************************************************************************
Return TRUE if a safe tile is in a radius of 1. This function is used to
test where to place specials on the sea.
@@ -1153,17 +496,21 @@
create_placed_map(); /* here it means placed huts */
while (number * map_num_tiles() >= 2000 && count++ < map_num_tiles() * 2) {
-
+ data_filter_chracteristic_type data;
+ characteristic_type *condition[] =
+ {&CM_NOT_PLACED, &CM_NFROZEN, &CM_AND,
+ &CM_OCEANIC, &CM_NOT, &CM_AND, NULL};
+
+ data.null_ended_array = condition;
/* Add a hut. But not on a polar area, on an ocean, or too close to
* another hut. */
- if ((ptile = rand_map_pos_characteristic(WC_ALL, TT_NFROZEN, MC_NONE))) {
- if (is_ocean(map_get_terrain(ptile))) {
- map_set_placed(ptile); /* not good for a hut */
- } else {
- number--;
- map_set_special(ptile, S_HUT);
- set_placed_near_pos(ptile, 3);
- }
+ if (NULL == (ptile = rand_map_pos_filtered((void *)&data,
+ filter_characteristic))) {
+ map_set_placed(ptile); /* not good for a hut */
+ } else {
+ number--;
+ map_set_special(ptile, S_HUT);
+ set_placed_near_pos(ptile, 3);
}
}
destroy_placed_map();
@@ -1219,6 +566,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(ptile) {
+ if (is_characteristic(ptile, CM_FROZEN )) {
+ map_set_terrain(ptile, T_ARCTIC);
+ }
+ } whole_map_iterate_end;
+}
+
/**************************************************************************
common variables for generator 2, 3 and 4
**************************************************************************/
@@ -1651,7 +1012,7 @@
{
height_map = fc_malloc(sizeof(int) * map.ysize * map.xsize);
create_placed_map(); /* land tiles which aren't placed yet */
- create_tmap(FALSE);
+ create_characteristics(FALSE);
whole_map_iterate(ptile) {
map_set_terrain(ptile, T_OCEAN);
@@ -1711,7 +1072,7 @@
if (placed_map_is_initialized()) {
destroy_placed_map();
- destroy_tmap();
+ destroy_characteristics();
}
initworld(pstate);
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/mapgen.h
freeciv_/server/generator/mapgen.h
--- freeciv/server/generator/mapgen.h 2004-09-16 11:53:11.000000000 +0200
+++ freeciv_/server/generator/mapgen.h 2004-10-25 18:11:34.000000000 +0200
@@ -13,6 +13,6 @@
#ifndef FC__MAPGEN_H
#define FC__MAPGEN_H
-void map_fractal_generate(bool autosize);
+void map_generate(bool autosize);
#endif /* FC__MAPGEN_H */
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/mapgen_topology.c
freeciv_/server/generator/mapgen_topology.c
--- freeciv/server/generator/mapgen_topology.c 2004-10-07 22:34:57.000000000
+0200
+++ freeciv_/server/generator/mapgen_topology.c 2004-10-25 18:11:34.000000000
+0200
@@ -277,15 +277,11 @@
ice_base_colatitude =
(MAX(0, 100 * COLD_LEVEL / 3 - 1 * MAX_COLATITUDE)
+ 1 * MAX_COLATITUDE * SQSIZE) / (100 * SQSIZE);
- /* correction for single pole
- * TODO uncomment it when generator 5 was well tuned
- * sometime it can put too many land near pole
-
+
if (topo_has_flag(TF_WRAPX) == topo_has_flag(TF_WRAPY)) {
ice_base_colatitude /= 2;
}
- */
} else {
/* any way strip poles are not so playable has isle poles */
ice_base_colatitude =
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-29 07:50:51.000000000
+0200
+++ freeciv_/server/generator/mapgen_topology.h 2004-10-25 18:11:34.000000000
+0200
@@ -45,6 +45,8 @@
extern int ice_base_colatitude;
#define ICE_BASE_LEVEL ice_base_colatitude
+#define HAS_POLES (map.temperature < 70 && !map.alltemperate)
+
int map_colatitude(const struct tile *ptile);
bool near_singularity(const struct tile *ptile);
void generator_init_topology(bool autosize);
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/temperature_map.c
freeciv_/server/generator/temperature_map.c
--- freeciv/server/generator/temperature_map.c 2004-10-16 00:56:47.000000000
+0200
+++ freeciv_/server/generator/temperature_map.c 1970-01-01 01:00:00.000000000
+0100
@@ -1,123 +0,0 @@
-/**********************************************************************
- Copyright (C) 2004 - Marcelo J. Burda
- 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.
-***********************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "map.h"
-
-#include "height_map.h"
-#include "temperature_map.h"
-#include "mapgen_topology.h"
-#include "utilities.h"
-
-static int *temperature_map;
-
-#define tmap(ptile) (temperature_map[(ptile)->index])
-
-/**************************************************************
- Return TRUE if temperateure_map is initialized
-**************************************************************/
-bool temperature_is_initialized(void)
-{
- return temperature_map != NULL;
-}
-/*********************************************************
- return true if the tile has tt temperature type
-**********************************************************/
-bool tmap_is(const struct tile *ptile, temperature_type tt)
-{
- return BOOL_VAL(tmap(ptile) & (tt));
-}
-
-/*****************************************************************
- return true if at last one tile has tt temperature type
-****************************************************************/
-bool is_temperature_type_near(const struct tile *ptile, temperature_type tt)
-{
- adjc_iterate(ptile, tile1) {
- if (BOOL_VAL(tmap(tile1) & (tt))) {
- return TRUE;
- };
- } adjc_iterate_end;
- return FALSE;
-}
-
-/****************************************************************************
- Free the tmap
- ****************************************************************************/
-void destroy_tmap(void)
-{
- assert(temperature_map != NULL);
- free(temperature_map);
- temperature_map = NULL;
-}
-
-/***************************************************************************
- * 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 create_tmap(bool real)
-{
- int i;
-
- /* if map is defined this is not changed */
- /* TO DO load if from scenario game with tmap */
- assert(temperature_map == NULL); /* to debug, never load a this time */
- if (temperature_map != NULL) {
- return;
- }
-
- temperature_map = fc_malloc(sizeof(int) * MAX_MAP_INDEX);
- whole_map_iterate(ptile) {
-
- /* the base temperature is equal to base map_colatitude */
- int t = map_colatitude(ptile);
- if (!real) {
- tmap(ptile) = t;
- } else {
- /* height land can be 30% collest */
- float height = - 0.3 * MAX(0, hmap(ptile) - 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_ocean_near_tile(ptile, FALSE, TRUE)) /
- 100;
-
- tmap(ptile) = t * (1.0 + temperate) * (1.0 + height);
- }
- } whole_map_iterate_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 */
- if (!map.alltemperate) {
- adjust_int_map(temperature_map, MAX_COLATITUDE);
- }
- /* now simplify to 4 base values */
- for (i = 0; i < MAX_MAP_INDEX; i++) {
- int t = temperature_map[i];
-
- if (t >= TROPICAL_LEVEL) {
- temperature_map[i] = TT_TROPICAL;
- } else if (t >= COLD_LEVEL) {
- temperature_map[i] = TT_TEMPERATE;
- } else if (t >= 2 * ICE_BASE_LEVEL) {
- temperature_map[i] = TT_COLD;
- } else {
- temperature_map[i] = TT_FROZEN;
- }
- }
-}
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/temperature_map.h
freeciv_/server/generator/temperature_map.h
--- freeciv/server/generator/temperature_map.h 2004-09-29 07:50:51.000000000
+0200
+++ freeciv_/server/generator/temperature_map.h 1970-01-01 01:00:00.000000000
+0100
@@ -1,40 +0,0 @@
-/**********************************************************************
- Copyright (C) 2004 - Marcelo J. Burda
- 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__TEMPERATURE_MAP_H
-#define FC__TEMPERATURE_MAP_H
-
-
-/*
- * temperature_map[] stores the temperature of each tile
- * values on tmap can get one of these 4 values
- * there is 4 extra values as macros combining the 4 basics ones
- */
-typedef int temperature_type;
-
-#define TT_FROZEN 1
-#define TT_COLD 2
-#define TT_TEMPERATE 4
-#define TT_TROPICAL 8
-
-#define TT_NFROZEN (TT_COLD | TT_TEMPERATE | TT_TROPICAL)
-#define TT_ALL (TT_FROZEN | TT_NFROZEN)
-#define TT_NHOT (TT_FROZEN | TT_COLD)
-#define TT_HOT (TT_TEMPERATE | TT_TROPICAL)
-
-bool temperature_is_initialized(void);
-bool tmap_is(const struct tile *ptile, temperature_type tt);
-bool is_temperature_type_near(const struct tile *ptile, temperature_type tt);
-void destroy_tmap(void);
-void create_tmap(bool real);
-
-#endif /* FC__TEMPERATURE_MAP_H */
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/utilities.h
freeciv_/server/generator/utilities.h
--- freeciv/server/generator/utilities.h 2004-10-15 19:16:54.000000000
+0200
+++ freeciv_/server/generator/utilities.h 2004-10-25 18:11:43.000000000
+0200
@@ -13,29 +13,13 @@
#ifndef FC__UTILITIES_H
#define FC__UTILITIES_H
-/* Provide a block to convert from native to map coordinates. For instance
- * do_in_map_pos(mx, my, xn, yn) {
- * map_set_terrain(mx, my, T_OCEAN);
- * } do_in_map_pos_end;
- * Note: that the map position is declared as const and can't be changed
- * inside the block.
- */
-#define do_in_map_pos(ptile, nat_x, nat_y) \
-{ \
- struct tile *ptile = native_pos_to_tile((nat_x), (nat_y)); \
- {
-
-#define do_in_map_pos_end \
- } \
-}
-
/***************************************************************************
iterate axe iterate on selected axe ( x if Xaxe is TRUE) over a intervale
- of -dist to dist arround the tile indexed by index0
+ of -dist to dist arround the tile pointed.
this iterator create 2 vars:
- index : the map index of the iterate pointed tile
+ iter_tile : the iterate pointed tile
i : the position in the intervale of iteration (from -dist to dist)
- index0, dist, Xaxe are side effect safe.
+ the center_tile, dist and Xaxe args are side effect safe.
***************************************************************************/
#define iterate_axe(iter_tile, i, center_tile, dist, Xaxe) \
{ \
diff -ruN -Xfreeciv/diff_ignore freeciv/server/srv_main.c
freeciv_/server/srv_main.c
--- freeciv/server/srv_main.c 2004-10-22 17:33:19.000000000 +0200
+++ freeciv_/server/srv_main.c 2004-10-25 18:11:51.000000000 +0200
@@ -1798,7 +1798,7 @@
/* If we have a tile map, and map.generator==0, call map_fractal_generate
* anyway to make the specials, huts and continent numbers. */
if (map_is_empty() || (map.generator == 0 && game.is_new_game)) {
- map_fractal_generate(TRUE);
+ map_generate(TRUE);
}
gamelog_map();
|
|