[Freeciv-Dev] Re: (PR#3489) Patch to add new generator
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
On Thu, Jul 24, 2003 at 06:15:34PM -0700, Guest wrote:
>
> Hello,
>
> I've tested gen 6 on 5560 and 5561 and localhost servers and mostly
> obtained crashes at start (segfault on create_peninsula). The way
> not to have a crash is starting a "fake-game" which won't make the
> server to restart.
>
> It seems that remaining_count doesn't take a good value if the server
> hasn't yet been started with another gen than 6.
>
> G. Gracian
Okay, the problem is that in 1.14 map.start_positions is initialized before
the generators are called. In the current cvs it is not initialized.
This caused gen 6 to segfault.
This is fixed with the line:
map.start_positions = fc_realloc(map.start_positions,
game.nplayers
* sizeof(*map.start_positions));
Attached is a new patch that will work with the current cvs.
--
Josh Cogliati
jjc@xxxxxxxxxxxxxxxxxx
This message created in Linux, the choice of a GNU generation.
Index: common/map.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/map.h,v
retrieving revision 1.151
diff -U9 -r1.151 map.h
--- common/map.h 2003/07/23 20:24:36 1.151
+++ common/map.h 2003/08/08 13:16:42
@@ -660,19 +660,19 @@
#define MAP_MIN_RIVERS 0
#define MAP_MAX_RIVERS 100
#define MAP_DEFAULT_FORESTS 20
#define MAP_MIN_FORESTS 0
#define MAP_MAX_FORESTS 100
#define MAP_DEFAULT_GENERATOR 1
#define MAP_MIN_GENERATOR 1
-#define MAP_MAX_GENERATOR 5
+#define MAP_MAX_GENERATOR 6
#define MAP_DEFAULT_TINYISLES FALSE
#define MAP_MIN_TINYISLES FALSE
#define MAP_MAX_TINYISLES TRUE
#define MAP_DEFAULT_SEPARATE_POLES TRUE
#define MAP_MIN_SEPARATE_POLES FALSE
#define MAP_MAX_SEPARATE_POLES TRUE
Index: server/mapgen.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/mapgen.c,v
retrieving revision 1.112
diff -U9 -r1.112 mapgen.c
--- server/mapgen.c 2003/07/23 13:46:04 1.112
+++ server/mapgen.c 2003/08/08 13:17:07
@@ -36,18 +36,19 @@
#define rmap(x, y) (river_map[map_pos_to_index(x, y)])
static void make_huts(int number);
static void add_specials(int prob);
static void mapgenerator1(void);
static void mapgenerator2(void);
static void mapgenerator3(void);
static void mapgenerator4(void);
static void mapgenerator5(void);
+static void mapgenerator6(void);
static void smooth_map(void);
static void adjust_map(int minval);
#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.
@@ -1154,18 +1155,20 @@
mysrand(map.seed);
/* don't generate tiles with mapgen==0 as we've loaded them from file */
/* also, don't delete (the handcrafted!) tiny islands in a scenario */
if (map.generator != 0) {
map_allocate();
/* if one mapgenerator fails, it will choose another mapgenerator */
/* with a lower number to try again */
+ if (map.generator == 6 )
+ mapgenerator6();
if (map.generator == 5 )
mapgenerator5();
if (map.generator == 4 )
mapgenerator4();
if (map.generator == 3 )
mapgenerator3();
if( map.generator == 2 )
mapgenerator2();
if( map.generator == 1 )
@@ -2137,10 +2140,472 @@
if (hmap(x, y) < minval)
minval = hmap(x, y);
} whole_map_iterate_end;
maxval -= minval;
adjust_map(minval);
make_land();
free(height_map);
height_map = NULL;
+}
+
+enum gen6_terrain { T6_PERM_LAND = T_GRASSLAND, T6_TEMP_LAND = T_SWAMP,
+ T6_PERM_OCEAN = T_OCEAN, T6_TEMP_OCEAN = T_ARCTIC,
+ T6_ERODE_LAND = T_DESERT, T6_DILATE_LAND = T_JUNGLE};
+
+/****************************************************************************
+ returns true if the terrain is generator 6 ocean.
+****************************************************************************/
+static int g6_ocean(int terrain)
+{
+ return terrain == T6_PERM_OCEAN || terrain == T6_TEMP_OCEAN;
+}
+
+/****************************************************************************
+ returns true if the terrain at point x,y is land.
+****************************************************************************/
+static int land_terrain(int x, int y)
+{
+ int terrain = map_get_terrain(x, y);
+ return !g6_ocean(terrain);
+}
+
+/****************************************************************************
+ returns true if a neighboring point should be eroded.
+****************************************************************************/
+static int erode_terrain(int x, int y)
+{
+ int terrain = map_get_terrain(x, y);
+ return g6_ocean(terrain);
+}
+
+/****************************************************************************
+ returns true if the terrain at point x,y should be eroded.
+****************************************************************************/
+static int should_erode(int x, int y)
+{
+ int terrain = map_get_terrain(x, y);
+ if(g6_ocean(terrain) || terrain == T6_PERM_LAND) {
+ return FALSE;
+ }
+ if (erode_terrain(x - 1, y)
+ || erode_terrain(x + 1, y)
+ || erode_terrain(x, y - 1)
+ || erode_terrain(x, y + 1)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/****************************************************************************
+ removes all temporary shores. (I.e. shrink the land by one tile.)
+****************************************************************************/
+static void erode_map(int polar_height)
+{
+ int x, y;
+ for (x = 0; x < map.xsize; x++) {
+ for (y = polar_height; y < map.ysize - polar_height; y++) {
+ if (should_erode(x, y)) {
+ map_set_terrain(x, y, T6_ERODE_LAND);
+ }
+ }
+ }
+
+ for (x = 0; x < map.xsize; x++) {
+ for (y = polar_height; y < map.ysize - polar_height; y++) {
+ if (map_get_terrain(x, y) == T6_ERODE_LAND) {
+ map_set_terrain(x, y, T6_TEMP_OCEAN);
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ returns true if a neighboring point should be dilated.
+****************************************************************************/
+static int dilate_terrain(int x, int y)
+{
+ int terrain = map_get_terrain(x, y);
+ return !g6_ocean(terrain) && terrain != T6_DILATE_LAND;
+}
+
+/****************************************************************************
+ returns true if the terrain at point x,y should be dilated.
+****************************************************************************/
+static int should_dilate(int x, int y)
+{
+ int terrain = map_get_terrain(x, y);
+ if(!g6_ocean(terrain) || terrain == T6_PERM_OCEAN) {
+ return FALSE;
+ }
+ if (dilate_terrain(x - 1, y)
+ || dilate_terrain(x + 1, y)
+ || dilate_terrain(x, y - 1)
+ || dilate_terrain(x, y + 1)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/****************************************************************************
+ removes all temporary beaches. (I.e. shrink the ocean by one tile.)
+****************************************************************************/
+static void dilate_map(int polar_height)
+{
+ int x, y;
+ for (x = 0; x < map.xsize; x++) {
+ for (y = polar_height; y < map.ysize - polar_height; y++) {
+ if (should_dilate(x, y)) {
+ map_set_terrain(x, y, T6_DILATE_LAND);
+ }
+ }
+ }
+
+ for (x = 0; x < map.xsize; x++) {
+ for (y = polar_height; y < map.ysize - polar_height; y++) {
+ if (map_get_terrain(x, y) == T6_DILATE_LAND) {
+ map_set_terrain(x, y, T6_TEMP_LAND);
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ returns a score based on the amount of land surrounding the point x,y.
+ No land is 0. All eight neighbors is 12
+ ***************************************************************************/
+static int border_score(int x, int y)
+{
+ int adj_score = 2;
+ int diag_score = 1;
+ int score = 0;
+ score += land_terrain(x - 1, y) ? adj_score : 0;
+ score += land_terrain(x + 1, y) ? adj_score : 0;
+ score += land_terrain(x, y - 1) ? adj_score : 0;
+ score += land_terrain(x, y + 1) ? adj_score : 0;
+ score += land_terrain(x - 1, y - 1) ? diag_score : 0;
+ score += land_terrain(x + 1, y - 1) ? diag_score : 0;
+ score += land_terrain(x - 1, y + 1) ? diag_score : 0;
+ score += land_terrain(x + 1, y + 1) ? diag_score : 0;
+ return score;
+}
+
+enum terrain_status { TS_OCEAN, TS_LAND, TS_NEW_LAND};
+
+/*************************************************************************
+ Returns TS_NEW_LAND if the point is not already land and
+ the random number is less than the border score.
+ More likely to return TS_NEW_LAND on a location that has
+ more land around it. Will never return TS_NEW_LAND on a
+ location that has no land in any of the eight neighbors.
+ *************************************************************************/
+static int random_new_land(int x, int y)
+{
+ int score;
+ int random;
+ if (land_terrain(x, y)) {
+ return TS_LAND;
+ }
+ if (map_get_terrain(x, y) == T6_PERM_OCEAN) {
+ return TS_OCEAN;
+ }
+ score = border_score(x, y);
+ random = myrand(4 * 2 + 4 * 1);
+ return random + 1 > score ? TS_OCEAN : TS_NEW_LAND;
+
+}
+
+/*************************************************************************
+ Creates a peninsula and put the player's starting position
+ on it. The direction is either +1 or -1 depending on which
+ direction the peninsula should go from the y position.
+ The remaining_count is the number of tiles to fill with
+ land.
+ *************************************************************************/
+static void create_peninsula(int x, int y, int player_number,
+ int width, int height, int direction,
+ int neck_height,int neck_width,
+ int neck_displacement)
+{
+ int cx, cy;
+ int head_height = height-neck_height;
+ int neck_start = x + neck_displacement;
+ int ocean_distance = neck_height / 2;
+
+ /* make perm ocean */
+ {
+ int top_location = y - (ocean_distance + 1) * direction;
+ int bottom_location = y + (height - ocean_distance) * direction;
+ int left_location = x - ocean_distance - 1;
+ int right_location = x + width + ocean_distance;
+
+ /* top and bottom */
+ for (cx = left_location; cx < right_location + 1; cx++) {
+ map_set_terrain(cx, top_location, T6_PERM_OCEAN);
+ map_set_terrain(cx, bottom_location, T6_PERM_OCEAN);
+ }
+
+ /* left and right */
+ for (cy = top_location; cy != bottom_location + direction;
+ cy += direction) {
+ map_set_terrain(left_location, cy, T6_PERM_OCEAN);
+ map_set_terrain(right_location, cy, T6_PERM_OCEAN);
+ }
+
+ /* connect to central ocean */
+ for (cy = map.ysize / 2; cy != top_location; cy += direction) {
+ map_set_terrain(x + width / 2, cy, T6_PERM_OCEAN);
+ }
+ }
+
+ /* make head */
+ for (cx = x; cx < x + width; cx++) {
+ for (cy = y; cy != y + (head_height + 1) * direction; cy += direction) {
+ map_set_terrain(cx, cy, T6_PERM_LAND);
+ hmap(cx, cy) = myrand(7000) - 2000;
+ }
+ }
+
+ /* make neck */
+ for (cx = neck_start; cx < neck_start + neck_width; cx++) {
+ for (cy = y + (head_height + 1) * direction;
+ cy != y + (height + 1) * direction; cy += direction ) {
+ map_set_terrain(cx, cy, T6_PERM_LAND);
+ hmap(cx, cy) = myrand(7000) - 2000;
+ }
+ }
+
+ map.start_positions[player_number].x = x + width / 2;
+ map.start_positions[player_number].y = y;
+}
+
+/*************************************************************************
+ This generator creates a map with one penisula for each
+ player and an isthmus between. It creates a central
+ ocean and puts the peninsulas around the edges. It is
+ intented for quicker games. Should look something like this:
+ *****************************
+ **** ***** ***** *****
+ ** *** *** ***
+ **
+ **
+ ** *** ***
+ **** ***** *****
+ *****************************
+
+ *************************************************************************/
+static void mapgenerator6(void)
+{
+ int peninsulas = game.nplayers;
+ int peninsulas_on_one_side = (peninsulas + 1) / 2;
+ int isthmus_width = 10;
+ int neck_height = (map.ysize / 8) | 1;
+ int polar_height = 3;
+ int peninsula_separation = neck_height;
+ int max_peninsula_width = (map.xsize - isthmus_width - peninsula_separation)
+ / (peninsulas_on_one_side) - peninsula_separation;
+ int max_peninsula_height = map.ysize / 2 - polar_height - neck_height;
+ int neck_width = MIN(6,max_peninsula_width - 1);
+ int min_peninsula_width = neck_width;
+ int min_peninsula_height = neck_height;
+ int peninsula_area = MAX((max_peninsula_width * max_peninsula_height *
+ map.landpercent) / 100,
+ min_peninsula_width * min_peninsula_height);
+ int i, x, y;
+ int isle = 1;
+
+ if(min_peninsula_width > max_peninsula_width
+ || min_peninsula_height > max_peninsula_height
+ || min_peninsula_width < 2 || min_peninsula_height < 2)
+ {
+ freelog(LOG_NORMAL,
+ "mapgen.c: unable to use generator 6. "\
+ "mw %d Mw %d mh %d Mh %d area %d",
+ min_peninsula_width,max_peninsula_width,
+ min_peninsula_height,max_peninsula_height,peninsula_area);
+ map.generator = 5;
+ return;
+ }
+
+ height_map = fc_malloc(sizeof(int) * map.xsize * map.ysize);
+
+ map.start_positions = fc_realloc(map.start_positions,
+ game.nplayers
+ * sizeof(*map.start_positions));
+
+ /* initialize everything to temp ocean */
+ for (y = 0; y < map.ysize; y++)
+ for (x = 0; x < map.xsize; x++) {
+ map_set_terrain(x, y, T6_TEMP_OCEAN);
+ hmap(x, y) = 0;
+ }
+
+ /* create central perm ocean */
+ y = map.ysize / 2;
+ for (x = isthmus_width; x < map.xsize; x++) {
+ map_set_terrain(x, y, T6_PERM_OCEAN);
+ hmap(x, y) = 0;
+ }
+
+ /* create polar regions */
+ for (x = 0; x < map.xsize; x++) {
+ for (y = 0; y < polar_height; y++) {
+ int rand_num = myrand(9);
+ map_set_terrain(x, y, rand_num > 7 ? T_ARCTIC :
+ (rand_num < 2 ? T_MOUNTAINS : T_TUNDRA));
+ rand_num = myrand(9);
+ map_set_terrain(x, map.ysize - 1 - y, rand_num > 7 ? T_ARCTIC :
+ (rand_num < 2 ? T_MOUNTAINS : T_TUNDRA));
+ }
+ }
+
+ /* build polar regions road */
+ for (x = 0; x < map.xsize; x++) {
+ y = polar_height - 1;
+ if (map_build_road_time(x, y - 1) < map_build_road_time(x, y)) {
+ map_set_special(x, y - 1, S_ROAD);
+ } else {
+ map_set_special(x, y, S_ROAD);
+ }
+ y = map.ysize - polar_height;
+ if (map_build_road_time(x, y + 1) < map_build_road_time(x, y)) {
+ map_set_special(x, y + 1, S_ROAD);
+ } else {
+ map_set_special(x, y, S_ROAD);
+ }
+ }
+
+ map.num_continents = 1;
+
+ /* create isthmus centeral strip */
+ x = isthmus_width / 2;
+ for (y = polar_height; y < map.ysize - polar_height; y++) {
+ map_set_terrain(x, y, T6_PERM_LAND);
+ hmap(x, y) = 100 * x * (isthmus_width - x) + (myrand(400) - 200);
+ }
+
+ /* setup peninsulas */
+ for (i = 0; i < game.nplayers; i++) {
+ /* direction is the direction to increment from the x and y location */
+ int direction = (i < peninsulas_on_one_side) ? -1 : 1;
+ int index = (direction == -1) ? i : i - peninsulas_on_one_side;
+ int width = min_peninsula_width +
+ myrand(max_peninsula_width - min_peninsula_width);
+ int height = CLIP(min_peninsula_height,
+ peninsula_area / width + neck_height,
+ max_peninsula_height);
+ int neck_displacement = myrand(width - neck_width);
+ int x_displacement = myrand(max_peninsula_width - width);
+ if(index == 0) {
+ x = peninsula_separation + isthmus_width;
+ if(direction == 1 && game.nplayers & 1) {
+ /* center the thing */
+ x = x + max_peninsula_width / 2;
+ }
+ }
+ y = (direction == -1)
+ ? height + polar_height : map.ysize - 1 - height - polar_height;
+ create_peninsula(x + x_displacement, y, i, width, height, direction,
+ neck_height,neck_width,neck_displacement);
+ x = x + peninsula_separation + max_peninsula_width;
+ }
+
+ map.num_start_positions = game.nplayers;
+
+ {
+ int consider_height = map.ysize - 2 * polar_height;
+ int desired_squares =
+ (consider_height * map.xsize * map.landpercent) / 200;
+ int bailout_number = desired_squares * 30;
+ int seed = MIN(20, desired_squares / 20); /* seed islands */
+ desired_squares = MAX(0, desired_squares - seed);
+ while (bailout_number > 0 && seed > 0) {
+ x = myrand(map.xsize);
+ y = myrand(consider_height) + polar_height;
+ if (map_get_terrain(x, y) == T6_TEMP_OCEAN) {
+ map_set_terrain(x, y, T6_TEMP_LAND);
+ hmap(x, y) = myrand(7000) - 2000;
+ seed--;
+ }
+ bailout_number--;
+ }
+ while (bailout_number > 0 && desired_squares > 0) {
+ x = myrand(map.xsize);
+ y = myrand(consider_height) + polar_height;
+ if (random_new_land(x, y) == TS_NEW_LAND) {
+ map_set_terrain(x, y, T6_TEMP_LAND);
+ hmap(x, y) = myrand(7000) - 2000;
+ desired_squares--;
+ }
+ bailout_number--;
+ }
+ }
+
+ /* remove small oceans */
+ dilate_map(polar_height);
+ erode_map(polar_height);
+ /* remove small islands */
+ erode_map(polar_height);
+ dilate_map(polar_height);
+
+ /* translate to real terrain */
+ for (x = 0; x < map.xsize; x++) {
+ for (y = polar_height; y < map.ysize - polar_height; y++) {
+ int terrain = map_get_terrain(x, y);
+ if (terrain == T6_TEMP_LAND) {
+ map_set_terrain(x, y, T_GRASSLAND);
+ } else if(terrain == T6_TEMP_OCEAN) {
+ map_set_terrain(x, y, T_OCEAN);
+ }
+ }
+ }
+
+ whole_map_iterate(x, y) {
+ map_set_continent(x, y, 0);
+ } whole_map_iterate_end;
+
+ assign_continent_flood(0, 0, isle++);
+
+ whole_map_iterate(x, y) {
+ if (map_get_continent(x, y) == 0
+ && !is_ocean(map_get_terrain(x, y))) {
+ assign_continent_flood(x, y, isle++);
+ }
+ } whole_map_iterate_end;
+
+ map.num_continents = isle-1;
+
+ /* setup terrain */
+ smooth_map();
+ make_mountains(1600);
+ make_swamps();
+ make_forests();
+ make_deserts();
+ make_plains();
+ make_fair();
+ make_rivers();
+
+ /* create isthmus road */
+ {
+ int last_x, middle_x = isthmus_width / 2;
+ last_x = middle_x;
+ for (y = polar_height - 1; y < map.ysize - polar_height + 1; y++) {
+ int best_x = middle_x;
+ int min_build = map_build_road_time(middle_x, y);
+ for (x = MAX(last_x - 1, middle_x - 1);
+ x != MIN(last_x + 1, middle_x + 1) + 1; x++) {
+ if (land_terrain(x, y) && map_build_road_time(x, y) < min_build) {
+ best_x = x;
+ min_build = map_build_road_time(x, y);
+ }
+ }
+ map_set_special(best_x, y, S_ROAD);
+ last_x = best_x;
+ }
+ }
+
+ free(height_map);
+
}
Index: server/stdinhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v
retrieving revision 1.287
diff -U9 -r1.287 stdinhand.c
--- server/stdinhand.c 2003/08/04 14:57:42 1.287
+++ server/stdinhand.c 2003/08/08 13:17:32
@@ -240,19 +240,21 @@
"3 = equally sized large islands with one player each, and "
"a number of other\n"
" islands of similar size;\n"
"4 = equally sized large islands with two players on every "
"island (or one\n"
" with three players for an odd number of players), and "
"additional\n"
" smaller islands;\n"
"5 = one or more large earthlike continents with some scatter.\n"
- "Note: values 2,3 and 4 generate \"fairer\" (but more boring) "
+ "6 = equally sized peninsulas with one player each surrounding \n"
+ " an inland sea.\n"
+ "Note: values 2,3,4 and 6 generate \"fairer\" (but more boring) "
"maps.\n"
"(Zero indicates a scenario map.)"), NULL,
MAP_MIN_GENERATOR, MAP_MAX_GENERATOR, MAP_DEFAULT_GENERATOR)
GEN_BOOL("tinyisles", map.tinyisles, SSET_MAP_GEN, SSET_TO_CLIENT,
N_("Presence or absence of 1x1 islands"),
N_("0 = no 1x1 islands; 1 = some 1x1 islands"), NULL,
MAP_DEFAULT_TINYISLES)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Freeciv-Dev] Re: (PR#3489) Patch to add new generator,
jjc@xxxxxxxxxxxxxxxxxx <=
|
|