Author: cazfi Date: Sat Jun 25 09:36:10 2016 New Revision: 33020 URL: http://svn.gna.org/viewcvs/freeciv?rev=33020&view=rev Log: Added fracture map genarator
Patch by Robert Finch <robfinch> and myself See patch #6882 Added: trunk/server/generator/fracture_map.c trunk/server/generator/fracture_map.h Modified: trunk/common/map_types.h trunk/server/generator/Makefile.am trunk/server/generator/mapgen.c trunk/server/settings.c Modified: trunk/common/map_types.h URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/map_types.h?rev=33020&r1=33019&r2=33020&view=diff ============================================================================== --- trunk/common/map_types.h (original) +++ trunk/common/map_types.h Sat Jun 25 09:36:10 2016 @@ -42,7 +42,8 @@ MAPGEN_RANDOM, MAPGEN_FRACTAL, MAPGEN_ISLAND, - MAPGEN_FAIR + MAPGEN_FAIR, + MAPGEN_FRACTURE }; enum map_startpos { Modified: trunk/server/generator/Makefile.am URL: http://svn.gna.org/viewcvs/freeciv/trunk/server/generator/Makefile.am?rev=33020&r1=33019&r2=33020&view=diff ============================================================================== --- trunk/server/generator/Makefile.am (original) +++ trunk/server/generator/Makefile.am Sat Jun 25 09:36:10 2016 @@ -16,6 +16,8 @@ mapgen_topology.h \ utilities.c \ utilities.h \ + fracture_map.c \ + fracture_map.h \ height_map.c \ height_map.h \ startpos.c \ Added: trunk/server/generator/fracture_map.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/server/generator/fracture_map.c?rev=33020&view=auto ============================================================================== --- trunk/server/generator/fracture_map.c (added) +++ trunk/server/generator/fracture_map.c Sat Jun 25 09:36:10 2016 @@ -0,0 +1,362 @@ +/*********************************************************************** + Freeciv - Copyright (C) 1996-2016 - The Freeciv Project + 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 <fc_config.h> +#endif + +/* utility */ +#include "rand.h" + +/* common */ +#include "map.h" + +/* server/generator */ +#include "height_map.h" +#include "mapgen_topology.h" +#include "utilities.h" + +#include "fracture_map.h" + +static void circle_bresenham(int xc, int yc, int r, int nn); +static void fmfill(int x, int y, int c, int r); +static int local_ave_elevation(struct tile *ptile); + +extern int *height_map; +int num_landmass = 50; + +typedef struct { + int x; + int y; +} map_point; + +typedef struct { + int minX, minY; + int maxX, maxY; + int elevation; +} map_landmass; + +/* Landmass: a chunk of rock with common properties */ +static map_landmass *landmass; +static map_point *fracture_points; + +/************************************************************************** + Fracture map generator +**************************************************************************/ +void make_fracture_map(void) +{ + int nn, mm; + int rad; + int x,y; + struct tile *ptile1; + + /* Calculate the mountain level. map.server.mountains specifies the + * percentage of land that is turned into hills and mountains. */ + hmap_mountain_level = (((hmap_max_level - hmap_shore_level) + * (100 - game.map.server.steepness)) + / 100 + hmap_shore_level); + + /* For larger maps, increase the number of landmasses - makes the map more interesting */ + num_landmass = 20 + 15 * get_sqsize(); + landmass = (map_landmass *)fc_malloc((game.map.xsize / 2 + game.map.ysize / 2 + num_landmass) * sizeof(map_landmass)); + fracture_points = (map_point *)fc_malloc((game.map.xsize / 2 + game.map.ysize / 2 + num_landmass) * sizeof(map_point)); + height_map = fc_malloc(sizeof(*height_map) * MAP_INDEX_SIZE); + + /* Setup a whole bunch of landmasses along the view bordere. These will be sunken + to create ocean terrain.*/ + nn = 0; + for (x = 3; x < game.map.xsize; x += 5, nn++) { + fracture_points[nn].x = x; + fracture_points[nn].y = 3; + } + for (x = 3; x < game.map.xsize; x += 5, nn++) { + fracture_points[nn].x = x; + fracture_points[nn].y = game.map.ysize - 3; + } + for (y = 3; y < game.map.ysize; y += 5, nn++) { + fracture_points[nn].x = 3; + fracture_points[nn].y = y; + } + for (y = 3; y < game.map.ysize; y += 5, nn++) { + fracture_points[nn].x = game.map.xsize - 3; + fracture_points[nn].y = y; + } + + /* pick remaining points randomly */ + mm = nn; + for (; nn < mm + num_landmass; nn++) { + fracture_points[nn].x = fc_rand(game.map.xsize - 6) + 3; + fracture_points[nn].y = fc_rand(game.map.ysize - 6) + 3; + } + for (nn = 0; nn < mm + num_landmass; nn++) { + landmass[nn].minX = game.map.xsize-1; + landmass[nn].minY = game.map.ysize-1; + landmass[nn].maxX = 0; + landmass[nn].maxY = 0; + x = fracture_points[nn].x; + y = fracture_points[nn].y; + ptile1 = native_pos_to_tile(x,y); + ptile1->continent = nn+1; + } + + /* Assign a base elevation to the landmass */ + for (nn = 0; nn < mm + num_landmass; nn++) { + if (nn < mm) { /* sink the border masses */ + landmass[nn].elevation = 0; + } else { + landmass[nn].elevation = fc_rand(1000); + } + } + + /* Assign cells to landmass. Gradually expand the radius of the + fracture point. */ + for (rad = 1; rad < (game.map.xsize >> 1); rad++) { + for (nn = 0; nn < mm + num_landmass; nn++) { + circle_bresenham(fracture_points[nn].x, fracture_points[nn].y, rad, nn+1); + } + } + + /* put in some random fuzz */ + whole_map_iterate(ptile) { + if (hmap(ptile) > hmap_shore_level) { + hmap(ptile) = hmap(ptile) + fc_rand(4) - 2; + } + if (hmap(ptile) <= hmap_shore_level) { + hmap(ptile) = hmap_shore_level + 1; + } + } whole_map_iterate_end; + + adjust_int_map(height_map, hmap_max_level); + free(landmass); + free(fracture_points); +} + +/************************************************************************** + An expanding circle from the fracture point is used to determine the + midpoint between fractures. The cells must be assigned to landmasses + anyway. +**************************************************************************/ +static void circle_bresenham(int xc, int yc, int r, int nn) +{ + int x = 0; + int y = r; + int p = 3 - 2 * r; + + if (!r) { + return; + } + + while (y >= x) { /* only formulate 1/8 of circle */ + fmfill(xc-x, yc-y, nn, r); /* upper left left */ + fmfill(xc-y, yc-x, nn, r); /* upper upper left */ + fmfill(xc+y, yc-x, nn, r); /* upper upper right */ + fmfill(xc+x, yc-y, nn, r); /* upper right right */ + fmfill(xc-x, yc+y, nn, r); /* lower left left */ + fmfill(xc-y, yc+x, nn, r); /* lower lower left */ + fmfill(xc+y, yc+x, nn, r); /* lower lower right */ + fmfill(xc+x, yc+y, nn, r); /* lower right right */ + if (p < 0) { + p += 4 * x++ + 6; + } else { + p += 4 * (x++ - y--) + 10; + } + } +} + +/************************************************************************** + Assign landmass in 3x3 area increments to avoid "holes" created by the + circle algorithm. +**************************************************************************/ +static void fmfill(int x, int y, int c, int r) +{ + int x1,x2,y1,y2; + struct tile *ptileXY; + struct tile *ptileX2Y; + struct tile *ptileX1Y; + struct tile *ptileXY2; + struct tile *ptileXY1; + struct tile *ptileX2Y1; + struct tile *ptileX2Y2; + struct tile *ptileX1Y2; + struct tile *ptileX1Y1; + + if (x < 0) { + x = game.map.xsize+x; + } else if (x > game.map.xsize) { + x = x-game.map.xsize; + } + x1 = x - 1; + if (x1 < 0) { + x1 = game.map.xsize - 1; + } + x2 = x + 1; + if (x2 >= game.map.xsize) { + x2 = 0; + } + y1 = y - 1; + if (y1 < 0) { + y1 = game.map.ysize - 1; + } + y2 = y + 1; + if (y2 >= game.map.ysize) { + y2 = 0; + } + + if (y >= 0 && y < game.map.ysize) { + ptileXY = native_pos_to_tile(x,y); + ptileX2Y = native_pos_to_tile(x2,y); + ptileX1Y = native_pos_to_tile(x1,y); + ptileXY2 = native_pos_to_tile(x,y2); + ptileXY1 = native_pos_to_tile(x,y1); + ptileX2Y1 = native_pos_to_tile(x2,y1); + ptileX2Y2 = native_pos_to_tile(x2,y2); + ptileX1Y2 = native_pos_to_tile(x1,y2); + ptileX1Y1 = native_pos_to_tile(x1,y1); + + if (ptileXY->continent == 0 ) { + ptileXY->continent = c; + ptileX2Y->continent = c; + ptileX1Y->continent = c; + ptileXY2->continent = c; + ptileXY1->continent = c; + ptileX2Y2->continent = c; + ptileX2Y1->continent = c; + ptileX1Y2->continent = c; + ptileX1Y1->continent = c; + hmap(ptileXY) = landmass[c-1].elevation; + hmap(ptileX2Y) = landmass[c-1].elevation; + hmap(ptileX1Y) = landmass[c-1].elevation; + hmap(ptileXY2) = landmass[c-1].elevation; + hmap(ptileXY1) = landmass[c-1].elevation; + hmap(ptileX2Y1) = landmass[c-1].elevation; + hmap(ptileX2Y2) = landmass[c-1].elevation; + hmap(ptileX1Y2) = landmass[c-1].elevation; + hmap(ptileX1Y1) = landmass[c-1].elevation; + /* This bit of code could track the maximum and minimum extent + of the landmass. */ + if (x < landmass[c-1].minX) { + landmass[c-1].minX = x; + } + if (x > landmass[c-1].maxX) { + landmass[c-1].maxX = x; + } + if (y < landmass[c-1].minY) { + landmass[c-1].minY = y; + } + if (y > landmass[c-1].maxY) { + landmass[c-1].maxY = y; + } + } + } +} + +/************************************************************************** + Determine the local average elevation. Used to determine where hills + and mountains are. +**************************************************************************/ +static int local_ave_elevation(struct tile *ptile) +{ + int ele; + int n; + + n = ele = 0; + square_iterate(ptile, 3, tile2) { + ele = ele + hmap(tile2); + n++; + } square_iterate_end; + ele /= n; + + return ele; +} + +/************************************************************************** + make_fracture_relief() Goes through a couple of iterations. + The first iteration chooses mountains and hills based on how much the + tile exceeds the elevation of the surrounding tiles. This will typically + causes hills and mountains to be placed along the edges of landmasses. + It can generate mountain ranges where there a differences in elevation + between landmasses. +**************************************************************************/ +void make_fracture_relief(void) +{ + int choose_mountain; + int choose_hill; + int landarea; + int total_mtns; + int iter; + + /* compute the land area */ + landarea = 0; + whole_map_iterate(ptile) { + if (hmap(ptile) > hmap_shore_level) { + landarea++; + } + } whole_map_iterate_end; + + /* Iteration 1 + Choose hills and mountains based on local elevation. + */ + total_mtns = 0; + whole_map_iterate(ptile) { + if (not_placed(ptile) && hmap(ptile) > hmap_shore_level) { /* place on land only */ + /* mountains */ + choose_mountain = (hmap(ptile) > local_ave_elevation(ptile) * 1.20) + || (area_is_too_flat(ptile, hmap_mountain_level, hmap(ptile)) * (fc_rand(10) < 4)); + + choose_hill = (hmap(ptile) > local_ave_elevation(ptile) * 1.10) + || (area_is_too_flat(ptile, hmap_mountain_level, hmap(ptile)) * (fc_rand(10) < 4)); + /* The following avoids hills and mountains directly along the coast. */ + if (count_terrain_class_near_tile(ptile, TRUE, TRUE, TC_OCEAN) > 0) { + choose_mountain = 0; + choose_hill = 0; + } + if (choose_mountain) { + total_mtns++; + tile_set_terrain(ptile,pick_terrain(MG_MOUNTAINOUS, MG_UNUSED, MG_GREEN)); + map_set_placed(ptile); + } else if (choose_hill) { + /* hills */ + total_mtns++; + tile_set_terrain(ptile,pick_terrain(MG_MOUNTAINOUS, MG_GREEN, MG_UNUSED)); + map_set_placed(ptile); + } + } + } whole_map_iterate_end; + + /* Iteration 2 + Make sure the map has at least the minimum number of mountains according to the + map steepness setting. + The iteration limit is a failsafe to prevent the iteration from taking forever. + */ + for (iter = 0; total_mtns < (landarea * game.map.server.steepness) / 100 && iter < 50; + iter++) { + whole_map_iterate(ptile) { + if (not_placed(ptile) && hmap(ptile) > hmap_shore_level) { /* place on land only */ + choose_mountain = fc_rand(10000) < 10; + choose_hill = fc_rand(10000) < 10; + if (choose_mountain) { + total_mtns++; + tile_set_terrain(ptile,pick_terrain(MG_MOUNTAINOUS, MG_UNUSED, MG_GREEN)); + map_set_placed(ptile); + } else if (choose_hill) { + /* hills */ + total_mtns++; + tile_set_terrain(ptile,pick_terrain(MG_MOUNTAINOUS, MG_GREEN, MG_UNUSED)); + map_set_placed(ptile); + } + } + if (total_mtns >= landarea * game.map.server.steepness / 100) { + break; + } + } whole_map_iterate_end; + } +} Added: trunk/server/generator/fracture_map.h URL: http://svn.gna.org/viewcvs/freeciv/trunk/server/generator/fracture_map.h?rev=33020&view=auto ============================================================================== --- trunk/server/generator/fracture_map.h (added) +++ trunk/server/generator/fracture_map.h Sat Jun 25 09:36:10 2016 @@ -0,0 +1,34 @@ +/*********************************************************************** + Freeciv - Copyright (C) 1996-2007 - The Freeciv Project + 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__FRACTURE_MAP_H +#define FC__FRACTURE_MAP_H + +/* + * Height map information + * + * height_map[] stores the height of each tile + * hmap_max_level is the maximum height (heights will range from + * [0,hmap_max_level). + * hmap_shore_level is the level of ocean. Any tile at this height or + * above is land; anything below is ocean. + * hmap_mount_level is the level of mountains and hills. Any tile above + * this height will usually be a mountain or hill. + */ +extern int *height_map; +extern int hmap_shore_level, hmap_mountain_level; + +void make_fracture_map(void); +void make_fracture_relief(void); +#define MG_UNUSED mapgen_terrain_property_invalid() + +#endif /* FC__FRACTURE__MAP_H */ Modified: trunk/server/generator/mapgen.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/server/generator/mapgen.c?rev=33020&r1=33019&r2=33020&view=diff ============================================================================== --- trunk/server/generator/mapgen.c (original) +++ trunk/server/generator/mapgen.c Sat Jun 25 09:36:10 2016 @@ -35,6 +35,7 @@ #include "road.h" /* server/generator */ +#include "fracture_map.h" #include "height_map.h" #include "mapgen_topology.h" #include "startpos.h" @@ -1126,7 +1127,11 @@ create_placed_map(); /* here it means land terrains to be placed */ set_all_ocean_tiles_placed(); - make_relief(); /* base relief on map */ + if (MAPGEN_FRACTURE == game.map.server.generator) { + make_fracture_relief(); + } else { + make_relief(); /* base relief on map */ + } make_terrains(); /* place all exept mountains and hill */ destroy_placed_map(); @@ -1334,9 +1339,15 @@ ? player_count() / 4 : 0))); } + if (MAPGEN_FRACTURE == game.map.server.generator) { + make_fracture_map(); + } + /* if hmap only generator make anything else */ if (MAPGEN_RANDOM == game.map.server.generator - || MAPGEN_FRACTAL == game.map.server.generator) { + || MAPGEN_FRACTAL == game.map.server.generator + || MAPGEN_FRACTURE == game.map.server.generator) { + make_land(); free(height_map); height_map = NULL; @@ -1385,6 +1396,7 @@ "start positions!"); case MAPGEN_SCENARIO: case MAPGEN_RANDOM: + case MAPGEN_FRACTURE: mode = game.map.server.startpos; break; case MAPGEN_FRACTAL: Modified: trunk/server/settings.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/server/settings.c?rev=33020&r1=33019&r2=33020&view=diff ============================================================================== --- trunk/server/settings.c (original) +++ trunk/server/settings.c Sat Jun 25 09:36:10 2016 @@ -253,6 +253,7 @@ NAME_CASE(MAPGEN_FRACTAL, "FRACTAL", N_("Pseudo-fractal height")); NAME_CASE(MAPGEN_ISLAND, "ISLAND", N_("Island-based")); NAME_CASE(MAPGEN_FAIR, "FAIR", N_("Fair islands")); + NAME_CASE(MAPGEN_FRACTURE, "FRACTURE", N_("Fracture map")); } return NULL; } @@ -1417,6 +1418,9 @@ "each player gets their own island.\n" "- \"Fair islands\" (FAIR): generates the exact copy of the " "same island for every player or every team.\n" + "- \"Fracture map\" (FRACTURE): generates maps from a fracture " + "patttern. Tends to place hills and mountains along the edges " + "of the continents.\n" "If the requested generator is incompatible with other server " "settings, the server may fall back to another generator."), NULL, generator_validate, NULL, generator_name, MAP_DEFAULT_GENERATOR) _______________________________________________ Freeciv-commits mailing list Freeciv-commits@gna.org https://mail.gna.org/listinfo/freeciv-commits