From 88fc6c85da0c45405e61d9a726f9326ee084779b Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Mon, 4 Jul 2022 01:09:44 +0300 Subject: [PATCH 64/64] Split wrap to a separate server setting from topology Requested by pjlsergeant See osdn #42289 Signed-off-by: Marko Lindqvist --- client/mapview_common.c | 26 ++-- client/overview_common.c | 27 ++-- client/packhand.c | 23 ++-- common/fc_types.h | 22 +++- common/map.c | 37 +++--- common/map.h | 10 +- common/map_types.h | 1 + common/mapimg.c | 18 ++- common/networking/packets.def | 2 + data/alien/game.ruleset | 3 +- data/civ1/game.ruleset | 3 +- data/civ2/game.ruleset | 3 +- data/civ2civ3/game.ruleset | 3 +- data/multiplayer/game.ruleset | 3 +- data/sandbox/game.ruleset | 3 +- data/webperimental/game.ruleset | 2 +- fc_version | 2 +- server/generator/height_map.c | 14 +- server/generator/mapgen.c | 16 +-- server/generator/mapgen_topology.c | 6 +- server/maphand.c | 1 + server/savegame/savecompat.c | 204 +++++++++++++++++++++++++++++ server/settings.c | 171 ++++++++++++++++++------ tools/ruleutil/rulesave.c | 14 +- 24 files changed, 469 insertions(+), 145 deletions(-) diff --git a/client/mapview_common.c b/client/mapview_common.c index 22596ae473..d349a4c987 100644 --- a/client/mapview_common.c +++ b/client/mapview_common.c @@ -774,10 +774,10 @@ static void normalize_gui_pos(const struct tileset *t, * we wrap even if the map position is unreal, which normalize_map_pos * doesn't necessarily do. */ MAP_TO_NATIVE_POS(&nat_x, &nat_y, map_x, map_y); - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { nat_x = FC_WRAP(nat_x, wld.map.xsize); } - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { nat_y = FC_WRAP(nat_y, wld.map.ysize); } NATIVE_TO_MAP_POS(&map_x, &map_y, nat_x, nat_y); @@ -949,11 +949,11 @@ static bool calc_mapview_origin(float *gui_x0, float *gui_y0) * while clipping is done in scroll (native) positions. */ get_mapview_scroll_window(&xmin, &ymin, &xmax, &ymax, &xsize, &ysize); - if (!current_topo_has_flag(TF_WRAPX)) { + if (!current_wrap_has_flag(WRAP_X)) { *gui_x0 = CLIP(xmin, *gui_x0, xmax - xsize); } - if (!current_topo_has_flag(TF_WRAPY)) { + if (!current_wrap_has_flag(WRAP_Y)) { *gui_y0 = CLIP(ymin, *gui_y0, ymax - ysize); } @@ -1091,13 +1091,13 @@ void get_mapview_scroll_window(float *xmin, float *ymin, * iso-view or a full tile in non-iso view. The above math already has * taken care of some of this so all that's left is to fix the corner * cases. */ - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { *xmax += *xsize; /* We need to be able to scroll a little further to the left. */ *xmin -= tileset_tile_width(tileset) * map_zoom; } - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { *ymax += *ysize; /* We need to be able to scroll a little further up. */ @@ -1263,19 +1263,19 @@ bool tile_visible_and_not_on_border_mapcanvas(struct tile *ptile) * border, then it's a border tile. We can only really check the * scrolling when the mapview window lines up with the map. */ if (canvas_x < border_x - && (!same || scroll_x > xmin || current_topo_has_flag(TF_WRAPX))) { + && (!same || scroll_x > xmin || current_wrap_has_flag(WRAP_X))) { return FALSE; } if (canvas_y < border_y - && (!same || scroll_y > ymin || current_topo_has_flag(TF_WRAPY))) { + && (!same || scroll_y > ymin || current_wrap_has_flag(WRAP_Y))) { return FALSE; } if (canvas_x + tileset_tile_width(tileset) * map_zoom > mapview.width - border_x - && (!same || scroll_x + xsize < xmax || current_topo_has_flag(TF_WRAPX))) { + && (!same || scroll_x + xsize < xmax || current_wrap_has_flag(WRAP_X))) { return FALSE; } if (canvas_y + tileset_tile_height(tileset) * map_zoom > mapview.height - border_y - && (!same || scroll_y + ysize < ymax || current_topo_has_flag(TF_WRAPY))) { + && (!same || scroll_y + ysize < ymax || current_wrap_has_flag(WRAP_Y))) { return FALSE; } @@ -3215,7 +3215,7 @@ static bool can_do_cached_drawing(void) * * The logic below is complicated and determined in part by * trial-and-error. */ - if (!current_topo_has_flag(TF_WRAPX) && !current_topo_has_flag(TF_WRAPY)) { + if (!current_wrap_has_flag(WRAP_X) && !current_wrap_has_flag(WRAP_Y)) { /* An unwrapping map: no limitation. On an unwrapping map no tile can * be visible twice so there's no problem. */ return TRUE; @@ -3241,11 +3241,11 @@ static bool can_do_cached_drawing(void) /* Now we can use the full width and height, with the exception of a small * area on each side. */ - if (current_topo_has_flag(TF_WRAPX) + if (current_wrap_has_flag(WRAP_X) && w > (NATURAL_WIDTH - isodiff) * W / isofactor) { return FALSE; } - if (current_topo_has_flag(TF_WRAPY) + if (current_wrap_has_flag(WRAP_Y) && h > (NATURAL_HEIGHT - isodiff) * H / isofactor) { return FALSE; } diff --git a/client/overview_common.c b/client/overview_common.c index f3f78143f6..f872a6d3e0 100644 --- a/client/overview_common.c +++ b/client/overview_common.c @@ -83,8 +83,8 @@ static void gui_to_natural_pos(const struct tileset *t, Translate from gui to overview coordinate systems. ****************************************************************************/ static void gui_to_overview_pos(const struct tileset *t, - int *ovr_x, int *ovr_y, - int gui_x, int gui_y) + int *ovr_x, int *ovr_y, + int gui_x, int gui_y) { double ntl_x, ntl_y; @@ -95,7 +95,7 @@ static void gui_to_overview_pos(const struct tileset *t, *ovr_y = floor((ntl_y - (double)gui_options.overview.map_y0) * OVERVIEW_TILE_SIZE); /* Now do additional adjustments. See map_to_overview_pos(). */ - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { *ovr_x = FC_WRAP(*ovr_x, NATURAL_WIDTH * OVERVIEW_TILE_SIZE); } else { if (MAP_IS_ISOMETRIC) { @@ -107,7 +107,8 @@ static void gui_to_overview_pos(const struct tileset *t, *ovr_x -= OVERVIEW_TILE_SIZE; } } - if (current_topo_has_flag(TF_WRAPY)) { + + if (current_wrap_has_flag(WRAP_Y)) { *ovr_y = FC_WRAP(*ovr_y, NATURAL_HEIGHT * OVERVIEW_TILE_SIZE); } } @@ -290,19 +291,19 @@ void center_tile_overviewcanvas(void) int ox, oy; gui_to_natural_pos(tileset, &ntl_x, &ntl_y, - mapview.gui_x0 + mapview.width / 2, - mapview.gui_y0 + mapview.height / 2); + mapview.gui_x0 + mapview.width / 2, + mapview.gui_y0 + mapview.height / 2); /* NOTE: this embeds the map wrapping in the overview code. This is * basically necessary for the overview to be efficiently * updated. */ - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { gui_options.overview.map_x0 = wrap_double(ntl_x - (double)NATURAL_WIDTH / 2.0, NATURAL_WIDTH); } else { gui_options.overview.map_x0 = 0; } - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { gui_options.overview.map_y0 = wrap_double(ntl_y - (double)NATURAL_HEIGHT / 2.0, NATURAL_HEIGHT); } else { @@ -330,7 +331,7 @@ void map_to_overview_pos(int *overview_x, int *overview_y, int ovr_x = ntl_x - gui_options.overview.map_x0; int ovr_y = ntl_y - gui_options.overview.map_y0; - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { ovr_x = FC_WRAP(ovr_x, NATURAL_WIDTH); } else { if (MAP_IS_ISOMETRIC) { @@ -342,7 +343,7 @@ void map_to_overview_pos(int *overview_x, int *overview_y, ovr_x--; } } - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { ovr_y = FC_WRAP(ovr_y, NATURAL_HEIGHT); } *overview_x = OVERVIEW_TILE_SIZE * ovr_x; @@ -359,7 +360,7 @@ void overview_to_map_pos(int *map_x, int *map_y, int ntl_x = overview_x / OVERVIEW_TILE_SIZE + gui_options.overview.map_x0; int ntl_y = overview_y / OVERVIEW_TILE_SIZE + gui_options.overview.map_y0; - if (MAP_IS_ISOMETRIC && !current_topo_has_flag(TF_WRAPX)) { + if (MAP_IS_ISOMETRIC && !current_wrap_has_flag(WRAP_X)) { /* Clip half tile left and right. See comment in map_to_overview_pos. */ ntl_x++; } @@ -418,7 +419,7 @@ void overview_update_tile(struct tile *ptile) int overview_x = ntl_x * OVERVIEW_TILE_SIZE; if (MAP_IS_ISOMETRIC) { - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { if (overview_x > gui_options.overview.width - OVERVIEW_TILE_WIDTH) { /* This tile is shown half on the left and half on the right * side of the overview. So we have to draw it in two parts. */ @@ -453,7 +454,7 @@ void calculate_overview_dimensions(void) static int recursion = 0; /* Just to be safe. */ /* Clip half tile left and right. See comment in map_to_overview_pos. */ - int shift = (MAP_IS_ISOMETRIC && !current_topo_has_flag(TF_WRAPX)) ? -1 : 0; + int shift = (MAP_IS_ISOMETRIC && !current_wrap_has_flag(WRAP_X)) ? -1 : 0; if (recursion > 0 || wld.map.xsize <= 0 || wld.map.ysize <= 0) { return; diff --git a/client/packhand.c b/client/packhand.c index 4b62b95d3f..a3f2b64c1f 100644 --- a/client/packhand.c +++ b/client/packhand.c @@ -2153,9 +2153,10 @@ void handle_unit_short_info(const struct packet_unit_short_info *packet) /************************************************************************//** Server requested topology change. ****************************************************************************/ -void handle_set_topology(int topology_id) +void handle_set_topology(int topology_id, int wrap_id) { wld.map.topology_id = topology_id; + wld.map.wrap_id = wrap_id; if (forced_tileset_name[0] == '\0' && (tileset_map_topo_compatible(topology_id, tileset, NULL) @@ -2172,11 +2173,10 @@ void handle_set_topology(int topology_id) } /************************************************************************//** - Receive information about the map size and topology from the server. We + Receive information about the map size and topology from the server. We initialize some global variables at the same time. ****************************************************************************/ -void handle_map_info(int xsize, int ysize, int topology_id, - bool alltemperate, bool single_pole) +void handle_map_info(const struct packet_map_info *packet) { int ts_topo; @@ -2185,18 +2185,19 @@ void handle_map_info(int xsize, int ysize, int topology_id, free_city_map_index(); } - wld.map.xsize = xsize; - wld.map.ysize = ysize; + wld.map.xsize = packet->xsize; + wld.map.ysize = packet->ysize; - wld.map.alltemperate = alltemperate; - wld.map.single_pole = single_pole; + wld.map.alltemperate = packet->alltemperate; + wld.map.single_pole = packet->single_pole; - if (tileset_map_topo_compatible(topology_id, tileset, &ts_topo) == TOPO_INCOMP_HARD) { + if (tileset_map_topo_compatible(packet->topology_id, tileset, &ts_topo) == TOPO_INCOMP_HARD) { tileset_error(LOG_NORMAL, _("Map topology (%s) and tileset (%s) incompatible."), - describe_topology(topology_id), describe_topology(ts_topo)); + describe_topology(packet->topology_id), describe_topology(ts_topo)); } - wld.map.topology_id = topology_id; + wld.map.topology_id = packet->topology_id; + wld.map.wrap_id = packet->wrap_id; map_init_topology(); main_map_allocate(); diff --git a/common/fc_types.h b/common/fc_types.h index 643db5af0a..d7052e0f54 100644 --- a/common/fc_types.h +++ b/common/fc_types.h @@ -571,15 +571,23 @@ const char *ai_level_name_update_cb(const char *old); * Changing the names will break file format compatibility. */ #define SPECENUM_NAME topo_flag #define SPECENUM_BITWISE -#define SPECENUM_VALUE0 TF_WRAPX +#define SPECENUM_VALUE0 TF_ISO +#define SPECENUM_VALUE0NAME N_("ISO") +#define SPECENUM_VALUE1 TF_HEX +#define SPECENUM_VALUE1NAME N_("Hex") +#define SPECENUM_VALUE2 TF_OLD_WRAPX +#define SPECENUM_VALUE2NAME N_("WrapX") +#define SPECENUM_VALUE3 TF_OLD_WRAPY +#define SPECENUM_VALUE3NAME N_("WrapY") +#define TOPO_FLAG_BITS 4 +#include "specenum_gen.h" + +#define SPECENUM_NAME wrap_flag +#define SPECENUM_BITWISE +#define SPECENUM_VALUE0 WRAP_X #define SPECENUM_VALUE0NAME N_("WrapX") -#define SPECENUM_VALUE1 TF_WRAPY +#define SPECENUM_VALUE1 WRAP_Y #define SPECENUM_VALUE1NAME N_("WrapY") -#define SPECENUM_VALUE2 TF_ISO -#define SPECENUM_VALUE2NAME N_("ISO") -#define SPECENUM_VALUE3 TF_HEX -#define SPECENUM_VALUE3NAME N_("Hex") -#define TOPO_FLAG_BITS 4 #include "specenum_gen.h" /* Used in the network protocol. */ diff --git a/common/map.c b/common/map.c index df13c40e3a..f49c024eef 100644 --- a/common/map.c +++ b/common/map.c @@ -157,6 +157,7 @@ bool map_is_empty(void) void map_init(struct civ_map *imap, bool server_side) { imap->topology_id = MAP_DEFAULT_TOPO; + imap->wrap_id = MAP_DEFAULT_WRAP; imap->num_continents = 0; imap->num_oceans = 0; imap->tiles = NULL; @@ -240,13 +241,13 @@ static void generate_map_indices(void) * case we're not concerned with going too far and wrapping around, so we * just have to make sure we go far enough if we're at one edge of the * map. */ - nat_min_x = (current_topo_has_flag(TF_WRAPX) ? 0 : (nat_center_x - wld.map.xsize + 1)); - nat_min_y = (current_topo_has_flag(TF_WRAPY) ? 0 : (nat_center_y - wld.map.ysize + 1)); + nat_min_x = (current_wrap_has_flag(WRAP_X) ? 0 : (nat_center_x - wld.map.xsize + 1)); + nat_min_y = (current_wrap_has_flag(WRAP_Y) ? 0 : (nat_center_y - wld.map.ysize + 1)); - nat_max_x = (current_topo_has_flag(TF_WRAPX) + nat_max_x = (current_wrap_has_flag(WRAP_X) ? (wld.map.xsize - 1) : (nat_center_x + wld.map.xsize - 1)); - nat_max_y = (current_topo_has_flag(TF_WRAPY) + nat_max_y = (current_wrap_has_flag(WRAP_Y) ? (wld.map.ysize - 1) : (nat_center_y + wld.map.ysize - 1)); tiles = (nat_max_x - nat_min_x + 1) * (nat_max_y - nat_min_y + 1); @@ -397,12 +398,12 @@ static inline struct tile *base_native_pos_to_tile(const struct civ_map *nmap, /* Wrap in X and Y directions, as needed. */ /* If the position is out of range in a non-wrapping direction, it is * unreal. */ - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { nat_x = FC_WRAP(nat_x, wld.map.xsize); } else if (nat_x < 0 || nat_x >= wld.map.xsize) { return NULL; } - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { nat_y = FC_WRAP(nat_y, wld.map.ysize); } else if (nat_y < 0 || nat_y >= wld.map.ysize) { return NULL; @@ -989,10 +990,10 @@ struct tile *nearest_real_tile(const struct civ_map *nmap, int x, int y) int nat_x, nat_y; MAP_TO_NATIVE_POS(&nat_x, &nat_y, x, y); - if (!current_topo_has_flag(TF_WRAPX)) { + if (!current_wrap_has_flag(WRAP_X)) { nat_x = CLIP(0, nat_x, wld.map.xsize - 1); } - if (!current_topo_has_flag(TF_WRAPY)) { + if (!current_wrap_has_flag(WRAP_Y)) { nat_y = CLIP(0, nat_y, wld.map.ysize - 1); } NATIVE_TO_MAP_POS(&x, &y, nat_x, nat_y); @@ -1014,9 +1015,9 @@ int map_num_tiles(void) instead. ***********************************************************************/ void base_map_distance_vector(int *dx, int *dy, - int x0dv, int y0dv, int x1dv, int y1dv) + int x0dv, int y0dv, int x1dv, int y1dv) { - if (current_topo_has_flag(TF_WRAPX) || current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_X) || current_wrap_has_flag(WRAP_Y)) { /* Wrapping is done in native coordinates. */ MAP_TO_NATIVE_POS(&x0dv, &y0dv, x0dv, y0dv); MAP_TO_NATIVE_POS(&x1dv, &y1dv, x1dv, y1dv); @@ -1025,11 +1026,11 @@ void base_map_distance_vector(int *dx, int *dy, * map distance vector but is easier to wrap. */ *dx = x1dv - x0dv; *dy = y1dv - y0dv; - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { /* Wrap dx to be in [-map.xsize/2, map.xsize/2). */ *dx = FC_WRAP(*dx + wld.map.xsize / 2, wld.map.xsize) - wld.map.xsize / 2; } - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { /* Wrap dy to be in [-map.ysize/2, map.ysize/2). */ *dy = FC_WRAP(*dy + wld.map.ysize / 2, wld.map.ysize) - wld.map.ysize / 2; } @@ -1440,14 +1441,14 @@ static double map_relative_southness(const struct tile *ptile) y = (double)ntl_y / (NATURAL_HEIGHT - 1); } do_in_natural_pos_end; - if (!current_topo_has_flag(TF_WRAPY)) { + if (!current_wrap_has_flag(WRAP_Y)) { /* In an Earth-like topology, north and south are at the top and * bottom of the map. * This is equivalent to a Mercator projection. */ return y; } - if (!current_topo_has_flag(TF_WRAPX) && current_topo_has_flag(TF_WRAPY)) { + if (!current_wrap_has_flag(WRAP_X) && current_wrap_has_flag(WRAP_Y)) { /* In a Uranus-like topology, north and south are at the left and * right side of the map. * This isn't really the way Uranus is; it's the way Earth would look @@ -1616,10 +1617,10 @@ bool is_singular_tile(const struct tile *ptile, int dist) /* Iso-natural coordinates are doubled in scale. */ dist *= MAP_IS_ISOMETRIC ? 2 : 1; - return ((!current_topo_has_flag(TF_WRAPX) - && (ntl_x < dist || ntl_x >= NATURAL_WIDTH - dist)) - || (!current_topo_has_flag(TF_WRAPY) - && (ntl_y < dist || ntl_y >= NATURAL_HEIGHT - dist))); + return ((!current_wrap_has_flag(WRAP_X) + && (ntl_x < dist || ntl_x >= NATURAL_WIDTH - dist)) + || (!current_wrap_has_flag(WRAP_Y) + && (ntl_y < dist || ntl_y >= NATURAL_HEIGHT - dist))); } do_in_natural_pos_end; } diff --git a/common/map.h b/common/map.h index 68c6977f3c..9f0af0b5e1 100644 --- a/common/map.h +++ b/common/map.h @@ -40,10 +40,14 @@ static const bool C_PERCENT = TRUE; #define MAP_IS_ISOMETRIC (CURRENT_TOPOLOGY & (TF_ISO + TF_HEX)) #define CURRENT_TOPOLOGY (wld.map.topology_id) +#define CURRENT_WRAP (wld.map.wrap_id) #define topo_has_flag(topo, flag) (((topo) & (flag)) != 0) #define current_topo_has_flag(flag) topo_has_flag((CURRENT_TOPOLOGY), (flag)) +#define wrap_has_flag(wrap, flag) (((wrap) & (flag)) != 0) +#define current_wrap_has_flag(flag) wrap_has_flag((CURRENT_WRAP), (flag)) + #define ALL_DIRECTIONS_CARDINAL() topo_has_flag((CURRENT_TOPOLOGY), TF_HEX) bool map_is_empty(void); @@ -639,9 +643,11 @@ moves. Includes MAP_MAX_LINEAR_SIZE because a map can be non wrapping. */ #define MAP_ORIGINAL_TOPO TF_WRAPX #ifdef FREECIV_WEB /* Freeciv-web doesn't support isometric maps yet. */ -#define MAP_DEFAULT_TOPO TF_WRAPX +#define MAP_DEFAULT_TOPO 0 +#define MAP_DEFAULT_WRAP WRAP_X #else /* FREECIV_WEB */ -#define MAP_DEFAULT_TOPO (TF_WRAPX|TF_ISO|TF_HEX) +#define MAP_DEFAULT_TOPO (TF_ISO|TF_HEX) +#define MAP_DEFAULT_WRAP (WRAP_X) #endif /* FREECIV_WEB */ #define MAP_DEFAULT_SEED 0 diff --git a/common/map_types.h b/common/map_types.h index 824ee0f157..4bdd742e94 100644 --- a/common/map_types.h +++ b/common/map_types.h @@ -70,6 +70,7 @@ enum map_startpos { struct civ_map { int topology_id; + int wrap_id; enum direction8 valid_dirs[8], cardinal_dirs[8]; int num_valid_dirs, num_cardinal_dirs; struct iter_index *iterate_outwards_indices; diff --git a/common/mapimg.c b/common/mapimg.c index 6c615638e3..9303a32b1e 100644 --- a/common/mapimg.c +++ b/common/mapimg.c @@ -389,7 +389,8 @@ struct img { const struct rgbcolor **map; }; -static struct img *img_new(struct mapdef *mapdef, int topo, int xsize, int ysize); +static struct img *img_new(struct mapdef *mapdef, int topo, int wrap, + int xsize, int ysize); static void img_destroy(struct img *pimg); static inline void img_set_pixel(struct img *pimg, const int mindex, const struct rgbcolor *pcolor); @@ -1374,7 +1375,8 @@ bool mapimg_create(struct mapdef *pmapdef, bool force, const char *savename, generate_save_name(savename, mapimgfile, sizeof(mapimgfile), mapimg_generate_name(pmapdef)); - pimg = img_new(pmapdef, CURRENT_TOPOLOGY, wld.map.xsize, wld.map.ysize); + pimg = img_new(pmapdef, CURRENT_TOPOLOGY, CURRENT_WRAP, + wld.map.xsize, wld.map.ysize); img_createmap(pimg); if (!img_save(pimg, mapimgfile, path)) { ret = FALSE; @@ -1397,7 +1399,8 @@ bool mapimg_create(struct mapdef *pmapdef, bool force, const char *savename, generate_save_name(savename, mapimgfile, sizeof(mapimgfile), mapimg_generate_name(pmapdef)); - pimg = img_new(pmapdef, CURRENT_TOPOLOGY, wld.map.xsize, wld.map.ysize); + pimg = img_new(pmapdef, CURRENT_TOPOLOGY, CURRENT_WRAP, + wld.map.xsize, wld.map.ysize); img_createmap(pimg); if (!img_save(pimg, mapimgfile, path)) { ret = FALSE; @@ -1444,7 +1447,7 @@ bool mapimg_colortest(const char *savename, const char *path) #define SIZE_X 16 #define SIZE_Y 5 - pimg = img_new(pmapdef, 0, SIZE_X + 2, + pimg = img_new(pmapdef, 0, 0, SIZE_X + 2, SIZE_Y * (max_playercolor / SIZE_X) + 2); pixel = pimg->pixel_tile(NULL, NULL, FALSE); @@ -1863,7 +1866,8 @@ static const struct toolkit *img_toolkit_get(enum imagetool tool) /************************************************************************//** Create a new image. ****************************************************************************/ -static struct img *img_new(struct mapdef *mapdef, int topo, int xsize, int ysize) +static struct img *img_new(struct mapdef *mapdef, int topo, int wrap, + int xsize, int ysize) { struct img *pimg; @@ -1894,8 +1898,8 @@ static struct img *img_new(struct mapdef *mapdef, int topo, int xsize, int ysize * TILE_SIZE; /* magic for isohexa: change size if wrapping in only one direction */ - if ((topo_has_flag(topo, TF_WRAPX) && !topo_has_flag(topo, TF_WRAPY)) - || (!topo_has_flag(topo, TF_WRAPX) && topo_has_flag(topo, TF_WRAPY))) { + if ((wrap_has_flag(wrap, WRAP_X) && !wrap_has_flag(wrap, WRAP_Y)) + || (!wrap_has_flag(wrap, WRAP_X) && wrap_has_flag(wrap, WRAP_Y))) { pimg->imgsize.y += (pimg->mapsize.x - pimg->mapsize.y / 2) / 2 * TILE_SIZE; } diff --git a/common/networking/packets.def b/common/networking/packets.def index f49800ffd8..8d4b7d4203 100644 --- a/common/networking/packets.def +++ b/common/networking/packets.def @@ -630,6 +630,7 @@ PACKET_MAP_INFO = 17; sc, lsend XYSIZE xsize; XYSIZE ysize; UINT8 topology_id; + UINT8 wrap_id; BOOL alltemperate; BOOL single_pole; end @@ -2052,6 +2053,7 @@ end PACKET_SET_TOPOLOGY = 253; sc UINT8 topology_id; + UINT8 wrap_id; end /************** Effects hash packets **********************/ diff --git a/data/alien/game.ruleset b/data/alien/game.ruleset index e47452ef29..9ce17497dd 100644 --- a/data/alien/game.ruleset +++ b/data/alien/game.ruleset @@ -1665,7 +1665,8 @@ colorlist = ; freeciv game settings for the alien ruleset set = { "name", "value", "lock" - "topology", "WRAPX|WRAPY|ISO|HEX", FALSE + "topology", "ISO|HEX", FALSE + "wrap", "WRAPX|WRAPY", FALSE "mapsize", "PLAYER", FALSE "tilesperplayer", 300, FALSE "aifill", 7, FALSE diff --git a/data/civ1/game.ruleset b/data/civ1/game.ruleset index c181a933a2..1446099567 100644 --- a/data/civ1/game.ruleset +++ b/data/civ1/game.ruleset @@ -1496,5 +1496,6 @@ set = ; no effect anyway "traitdistribution", "FIXED", TRUE "plrcolormode", "NATION_ORDER", FALSE - "topology", "WRAPX|ISO", FALSE + "topology", "ISO", FALSE + "wrap", "WRAPX", FALSE } diff --git a/data/civ2/game.ruleset b/data/civ2/game.ruleset index ed41d827ce..a84cb4f7ba 100644 --- a/data/civ2/game.ruleset +++ b/data/civ2/game.ruleset @@ -1740,5 +1740,6 @@ set = ; no effect anyway "traitdistribution", "FIXED", TRUE "plrcolormode", "NATION_ORDER", FALSE - "topology", "WRAPX|ISO", FALSE + "topology", "ISO", FALSE + "wrap", "WRAPX", FALSE } diff --git a/data/civ2civ3/game.ruleset b/data/civ2civ3/game.ruleset index 17ec264399..e4b41e4641 100644 --- a/data/civ2civ3/game.ruleset +++ b/data/civ2civ3/game.ruleset @@ -2174,7 +2174,8 @@ set = { "name", "value" "aifill", 6 "generator", "FRACTAL" - "topology", "WRAPX|WRAPY|ISO|HEX" + "topology", "ISO|HEX" + "wrap", "WRAPX|WRAPY" "mapsize", "PLAYER" "tilesperplayer", 100 "tinyisles", "ENABLED" diff --git a/data/multiplayer/game.ruleset b/data/multiplayer/game.ruleset index c3356438c7..0e1e56844a 100644 --- a/data/multiplayer/game.ruleset +++ b/data/multiplayer/game.ruleset @@ -1995,7 +1995,8 @@ set = { "name", "value", "lock" "minplayers", 2, FALSE "generator", "ISLAND", FALSE - "topology", "HEX|WRAPX|WRAPY|ISO", FALSE + "topology", "HEX|ISO", FALSE + "wrap", "WRAPX|WRAPY", FALSE "startpos", "SINGLE", FALSE "tinyisles", FALSE, FALSE "alltemperate", TRUE, FALSE diff --git a/data/sandbox/game.ruleset b/data/sandbox/game.ruleset index 52a12a99bd..aa2b291307 100644 --- a/data/sandbox/game.ruleset +++ b/data/sandbox/game.ruleset @@ -3595,7 +3595,8 @@ set = { "name", "value" "aifill", 12 "generator", "FRACTAL" - "topology", "WRAPX|WRAPY|ISO" + "topology", "ISO" + "wrap", "WRAPX|WRAPY" "mapsize", "PLAYER" "tilesperplayer", 100 "tinyisles", "ENABLED" diff --git a/data/webperimental/game.ruleset b/data/webperimental/game.ruleset index 8d61b8ef0e..8364836b34 100644 --- a/data/webperimental/game.ruleset +++ b/data/webperimental/game.ruleset @@ -2225,7 +2225,7 @@ colorlist = ; freeciv game settings for the experimental freeciv-web ruleset set = { "name", "value", "lock" - "topology", "WRAPX", FALSE + "wrap", "WRAPX", FALSE "nationset", "all", FALSE "traitdistribution", "EVEN", FALSE "maxplayers", 32, TRUE diff --git a/fc_version b/fc_version index 06c8e9610c..755aa28975 100755 --- a/fc_version +++ b/fc_version @@ -56,7 +56,7 @@ DEFAULT_FOLLOW_TAG=S3_2 # - No new mandatory capabilities can be added to the release branch; doing # so would break network capability of supposedly "compatible" releases. # -NETWORK_CAPSTRING="+Freeciv.Devel-3.2-2022.Jul.02" +NETWORK_CAPSTRING="+Freeciv.Devel-3.2-2022.Jul.03" FREECIV_DISTRIBUTOR="" diff --git a/server/generator/height_map.c b/server/generator/height_map.c index 274be276ca..51e4fc3ac5 100644 --- a/server/generator/height_map.c +++ b/server/generator/height_map.c @@ -196,14 +196,14 @@ static void gen5rec(int step, int xl, int yt, int xr, int yb) **************************************************************************/ void make_pseudofractal1_hmap(int extra_div) { - const bool xnowrap = !current_topo_has_flag(TF_WRAPX); - const bool ynowrap = !current_topo_has_flag(TF_WRAPY); + const bool xnowrap = !current_wrap_has_flag(WRAP_X); + const bool ynowrap = !current_wrap_has_flag(WRAP_Y); - /* + /* * How many blocks should the x and y directions be divided into - * initially. + * initially. */ - const int xdiv = 5 + extra_div; + const int xdiv = 5 + extra_div; const int ydiv = 5 + extra_div; int xdiv2 = xdiv + (xnowrap ? 1 : 0); @@ -213,9 +213,9 @@ void make_pseudofractal1_hmap(int extra_div) int ymax = wld.map.ysize - (ynowrap ? 1 : 0); int x_current, y_current; /* just need something > log(max(xsize, ysize)) for the recursion */ - int step = wld.map.xsize + wld.map.ysize; + int step = wld.map.xsize + wld.map.ysize; /* edges are avoided more strongly as this increases */ - int avoidedge = (100 - wld.map.server.landpercent) * step / 100 + step / 3; + int avoidedge = (100 - wld.map.server.landpercent) * step / 100 + step / 3; height_map = fc_malloc(sizeof(*height_map) * MAP_INDEX_SIZE); diff --git a/server/generator/mapgen.c b/server/generator/mapgen.c index da1ded9ade..545653f099 100644 --- a/server/generator/mapgen.c +++ b/server/generator/mapgen.c @@ -2551,14 +2551,14 @@ fair_map_pos_tile(struct fair_tile *pmap, int x, int y) /* Wrap in X and Y directions, as needed. */ if (nat_x < 0 || nat_x >= wld.map.xsize) { - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { nat_x = FC_WRAP(nat_x, wld.map.xsize); } else { return NULL; } } if (nat_y < 0 || nat_y >= wld.map.ysize) { - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { nat_y = FC_WRAP(nat_y, wld.map.ysize); } else { return NULL; @@ -2594,7 +2594,7 @@ fair_map_tile_border(struct fair_tile *pmap, struct fair_tile *ptile, index_to_native_pos(&nat_x, &nat_y, ptile - pmap); - if (!current_topo_has_flag(TF_WRAPX) + if (!current_wrap_has_flag(WRAP_X) && (nat_x < dist || nat_x >= wld.map.xsize - dist)) { return TRUE; } @@ -2603,7 +2603,7 @@ fair_map_tile_border(struct fair_tile *pmap, struct fair_tile *ptile, dist *= 2; } - if (!current_topo_has_flag(TF_WRAPY) + if (!current_wrap_has_flag(WRAP_Y) && (nat_y < dist || nat_y >= wld.map.ysize - dist)) { return TRUE; } @@ -3548,19 +3548,19 @@ static bool map_generate_fair_islands(void) } /* Make start point for teams. */ - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { dx = fc_rand(wld.map.xsize); } - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { dy = fc_rand(wld.map.ysize); } for (j = 0; j < teams_num; j++) { start_x[j] = (wld.map.xsize * (2 * j + 1)) / (2 * teams_num) + dx; start_y[j] = (wld.map.ysize * (2 * j + 1)) / (2 * teams_num) + dy; - if (current_topo_has_flag(TF_WRAPX)) { + if (current_wrap_has_flag(WRAP_X)) { start_x[j] = FC_WRAP(start_x[j], wld.map.xsize); } - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { start_y[j] = FC_WRAP(start_y[j], wld.map.ysize); } } diff --git a/server/generator/mapgen_topology.c b/server/generator/mapgen_topology.c index 0e2009b654..7a47ca5904 100644 --- a/server/generator/mapgen_topology.c +++ b/server/generator/mapgen_topology.c @@ -134,8 +134,8 @@ static void set_sizes(double size, int Xratio, int Yratio) ****************************************************************************/ static void get_ratios(int *x_ratio, int *y_ratio) { - if (current_topo_has_flag(TF_WRAPX)) { - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_X)) { + if (current_wrap_has_flag(WRAP_Y)) { /* Ratios for torus map. */ *x_ratio = 1; *y_ratio = 1; @@ -145,7 +145,7 @@ static void get_ratios(int *x_ratio, int *y_ratio) *y_ratio = 2; } } else { - if (current_topo_has_flag(TF_WRAPY)) { + if (current_wrap_has_flag(WRAP_Y)) { /* Ratios for uranus map. */ *x_ratio = 2; *y_ratio = 3; diff --git a/server/maphand.c b/server/maphand.c index d32231a553..636c847f82 100644 --- a/server/maphand.c +++ b/server/maphand.c @@ -631,6 +631,7 @@ void send_map_info(struct conn_list *dest) minfo.xsize = wld.map.xsize; minfo.ysize = wld.map.ysize; minfo.topology_id = wld.map.topology_id; + minfo.wrap_id = wld.map.wrap_id; minfo.alltemperate = wld.map.alltemperate; minfo.single_pole = wld.map.single_pole; diff --git a/server/savegame/savecompat.c b/server/savegame/savecompat.c index b3e7f7122e..6cd1e1af23 100644 --- a/server/savegame/savecompat.c +++ b/server/savegame/savecompat.c @@ -26,6 +26,7 @@ /* server */ #include "aiiface.h" #include "setcompat.h" +#include "settings.h" #include "unittools.h" #include "savecompat.h" @@ -1901,6 +1902,8 @@ static void compat_load_030200(struct loaddata *loading, /* Server setting migration. */ { if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) { + bool count_changed = FALSE; + gamestart_valid = secfile_lookup_bool_default(loading->file, FALSE, "settings.gamestart_valid"); @@ -1959,8 +1962,98 @@ static void compat_load_030200(struct loaddata *loading, #endif } } + } else if (!fc_strcasecmp("topology", name)) { + struct setting *pset = setting_by_name(name); + const char *val = secfile_lookup_str(loading->file, + "settings.set%d.value", i); + + if (setting_bitwise_set(pset, val, NULL, NULL, 0)) { + enum topo_flag otopo = setting_bitwise_get(pset); + char wrap[100]; + char buf[100]; + + if (topo_has_flag(otopo, TF_OLD_WRAPX)) { + if (topo_has_flag(otopo, TF_OLD_WRAPY)) { + fc_strlcpy(wrap, "WrapX|WrapY", sizeof(wrap)); + } else { + fc_strlcpy(wrap, "WrapX", sizeof(wrap)); + } + } else if (topo_has_flag(otopo, TF_OLD_WRAPY)) { + fc_strlcpy(wrap, "WrapY", sizeof(wrap)); + } else { + fc_strlcpy(wrap, "", sizeof(wrap)); + } + + if (topo_has_flag(otopo, TF_ISO)) { + if (topo_has_flag(otopo, TF_HEX)) { + setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0); + } else { + setting_bitwise_set(pset, "ISO", NULL, NULL, 0); + } + } else if (topo_has_flag(otopo, TF_HEX)) { + setting_bitwise_set(pset, "HEX", NULL, NULL, 0); + } else { + setting_bitwise_set(pset, "", NULL, NULL, 0); + } + + setting_value_name(pset, FALSE, buf, sizeof(buf)); + secfile_replace_str(loading->file, buf, + "settings.set%d.value", i); + + secfile_insert_str(loading->file, + "wrap", "settings.set%d.name", set_count); + secfile_insert_str(loading->file, + wrap, "settings.set%d.value", set_count); + + if (gamestart_valid) { + val = secfile_lookup_str(loading->file, + "settings.set%d.gamestart", i); + if (setting_bitwise_set(pset, val, NULL, NULL, 0)) { + otopo = setting_bitwise_get(pset); + + if (topo_has_flag(otopo, TF_OLD_WRAPX)) { + if (topo_has_flag(otopo, TF_OLD_WRAPY)) { + fc_strlcpy(wrap, "WrapX|WrapY", sizeof(wrap)); + } else { + fc_strlcpy(wrap, "WrapX", sizeof(wrap)); + } + } else if (topo_has_flag(otopo, TF_OLD_WRAPY)) { + fc_strlcpy(wrap, "WrapY", sizeof(wrap)); + } else { + fc_strlcpy(wrap, "", sizeof(wrap)); + } + + if (topo_has_flag(otopo, TF_ISO)) { + if (topo_has_flag(otopo, TF_HEX)) { + setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0); + } else { + setting_bitwise_set(pset, "ISO", NULL, NULL, 0); + } + } else if (topo_has_flag(otopo, TF_HEX)) { + setting_bitwise_set(pset, "HEX", NULL, NULL, 0); + } else { + setting_bitwise_set(pset, "", NULL, NULL, 0); + } + + setting_value_name(pset, FALSE, buf, sizeof(buf)); + secfile_replace_str(loading->file, buf, + "settings.set%d.gamestart", i); + + secfile_insert_str(loading->file, + wrap, "settings.set%d.gamestart", set_count); + } + } + + set_count++; + count_changed = TRUE; + } } } + + if (count_changed) { + secfile_replace_int(loading->file, set_count, + "settings.set_count"); + } } } @@ -2340,7 +2433,12 @@ static void compat_load_dev(struct loaddata *loading) int set_count; bool gamestart_valid = FALSE; bool al_set_already = FALSE; + bool wrap_set_already = FALSE; const char *level; + bool count_changed = FALSE; + bool topo_defined = FALSE; + char wrap[100]; + char wrap_gs[100]; if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) { int i; @@ -2405,6 +2503,96 @@ static void compat_load_dev(struct loaddata *loading) } } else if (!fc_strcasecmp("ailevel", name)) { al_set_already = TRUE; + } else if (!fc_strcasecmp("topology", name)) { + struct setting *pset = setting_by_name(name); + const char *val = secfile_lookup_str(loading->file, + "settings.set%d.value", i); + + if (setting_bitwise_set(pset, val, NULL, NULL, 0)) { + enum topo_flag otopo = setting_bitwise_get(pset); + bool topo_changed = TRUE; + + if (topo_has_flag(otopo, TF_OLD_WRAPX)) { + if (topo_has_flag(otopo, TF_OLD_WRAPY)) { + fc_strlcpy(wrap, "WrapX|WrapY", sizeof(wrap)); + } else { + fc_strlcpy(wrap, "WrapX", sizeof(wrap)); + } + } else if (topo_has_flag(otopo, TF_OLD_WRAPY)) { + fc_strlcpy(wrap, "WrapY", sizeof(wrap)); + } else { + fc_strlcpy(wrap, "", sizeof(wrap)); + topo_changed = FALSE; + } + + if (topo_changed) { + char buf[100]; + + if (topo_has_flag(otopo, TF_ISO)) { + if (topo_has_flag(otopo, TF_HEX)) { + setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0); + } else { + setting_bitwise_set(pset, "ISO", NULL, NULL, 0); + } + } else if (topo_has_flag(otopo, TF_HEX)) { + setting_bitwise_set(pset, "HEX", NULL, NULL, 0); + } else { + setting_bitwise_set(pset, "", NULL, NULL, 0); + } + + setting_value_name(pset, FALSE, buf, sizeof(buf)); + secfile_replace_str(loading->file, buf, + "settings.set%d.value", i); + } + + if (gamestart_valid) { + val = secfile_lookup_str(loading->file, + "settings.set%d.gamestart", i); + + if (setting_bitwise_set(pset, val, NULL, NULL, 0)) { + otopo = setting_bitwise_get(pset); + + topo_changed = TRUE; + + if (topo_has_flag(otopo, TF_OLD_WRAPX)) { + if (topo_has_flag(otopo, TF_OLD_WRAPY)) { + fc_strlcpy(wrap_gs, "WrapX|WrapY", sizeof(wrap)); + } else { + fc_strlcpy(wrap_gs, "WrapX", sizeof(wrap)); + } + } else if (topo_has_flag(otopo, TF_OLD_WRAPY)) { + fc_strlcpy(wrap_gs, "WrapY", sizeof(wrap)); + } else { + fc_strlcpy(wrap_gs, "", sizeof(wrap)); + topo_changed = FALSE; + } + + if (topo_changed) { + char buf[100]; + + if (topo_has_flag(otopo, TF_ISO)) { + if (topo_has_flag(otopo, TF_HEX)) { + setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0); + } else { + setting_bitwise_set(pset, "ISO", NULL, NULL, 0); + } + } else if (topo_has_flag(otopo, TF_HEX)) { + setting_bitwise_set(pset, "HEX", NULL, NULL, 0); + } else { + setting_bitwise_set(pset, "", NULL, NULL, 0); + } + + setting_value_name(pset, FALSE, buf, sizeof(buf)); + secfile_replace_str(loading->file, buf, + "settings.set%d.gamestart", i); + } + } + } + + topo_defined = TRUE; + } + } else if (!fc_strcasecmp("wrap", name)) { + wrap_set_already = TRUE; } } } @@ -2445,6 +2633,22 @@ static void compat_load_dev(struct loaddata *loading) } set_count++; + count_changed = TRUE; + } + + if (!wrap_set_already && topo_defined) { + secfile_insert_str(loading->file, "wrap", "settings.set%d.name", set_count); + secfile_insert_str(loading->file, wrap, "settings.set%d.value", set_count); + + if (gamestart_valid) { + secfile_insert_str(loading->file, wrap_gs, "settings.set%d.value", set_count); + } + + set_count++; + count_changed = TRUE; + } + + if (count_changed) { secfile_replace_int(loading->file, set_count, "settings.set_count"); } diff --git a/server/settings.c b/server/settings.c index 3607b43d72..7dbd3435c0 100644 --- a/server/settings.c +++ b/server/settings.c @@ -256,11 +256,23 @@ static const struct sset_val_name *mapsize_name(int mapsize) static const struct sset_val_name *topology_name(int topology_bit) { switch (1 << topology_bit) { - NAME_CASE(TF_WRAPX, "WRAPX", N_("Wrap East-West")); - NAME_CASE(TF_WRAPY, "WRAPY", N_("Wrap North-South")); NAME_CASE(TF_ISO, "ISO", N_("Isometric")); NAME_CASE(TF_HEX, "HEX", N_("Hexagonal")); } + + return NULL; +} + +/************************************************************************//** + Map wrap setting names accessor. +****************************************************************************/ +static const struct sset_val_name *wrap_name(int wrap_bit) +{ + switch (1 << wrap_bit) { + NAME_CASE(WRAP_X, "WRAPX", N_("Wrap East-West")); + NAME_CASE(WRAP_Y, "WRAPY", N_("Wrap North-South")); + } + return NULL; } @@ -811,6 +823,22 @@ static void topology_action(const struct setting *pset) struct packet_set_topology packet; packet.topology_id = *pset->integer.pvalue; + packet.wrap_id = wld.map.wrap_id; + + conn_list_iterate(game.est_connections, pconn) { + send_packet_set_topology(pconn, &packet); + } conn_list_iterate_end; +} + +/************************************************************************//** + Map wrap setting changed. +****************************************************************************/ +static void wrap_action(const struct setting *pset) +{ + struct packet_set_topology packet; + + packet.topology_id = wld.map.topology_id; + packet.wrap_id = *pset->integer.pvalue; conn_list_iterate(game.est_connections, pconn) { send_packet_set_topology(pconn, &packet); @@ -1300,11 +1328,11 @@ static bool topology_callback(unsigned value, struct connection *caller, #ifdef FREECIV_WEB /* Remember to update the help text too if Freeciv-web gets the ability * to display other map topologies. */ - if ((value & (TF_WRAPY)) != 0 - /* Are you removing this because Freeciv-web gained the ability to - * display isometric maps? Why don't you remove the Freeciv-web - * specific MAP_DEFAULT_TOPO too? */ - || (value & (TF_ISO)) != 0 + + /* Are you removing this because Freeciv-web gained the ability to + * display isometric maps? Why don't you remove the Freeciv-web + * specific MAP_DEFAULT_TOPO too? */ + if ((value & (TF_ISO)) != 0 || (value & (TF_HEX)) != 0) { /* The Freeciv-web client can't display these topologies yet. */ settings_snprintf(reject_msg, reject_msg_len, @@ -1332,6 +1360,26 @@ static bool aitype_callback(const char *value, struct connection *caller, return TRUE; } +/************************************************************************//** + Map wrap setting validation callback. +****************************************************************************/ +static bool wrap_callback(unsigned value, struct connection *caller, + char *reject_msg, size_t reject_msg_len) +{ +#ifdef FREECIV_WEB + /* Remember to update the help text too if Freeciv-web gets the ability + * to display other map wraps. */ + if ((value & (WRAP_Y)) != 0) { + /* The Freeciv-web client can't display wraps mapped this way. */ + settings_snprintf(reject_msg, reject_msg_len, + _("Freeciv-web doesn't support this map wrap.")); + return FALSE; + } +#endif /* FREECIV_WEB */ + + return TRUE; +} + /************************************************************************//** Validate that the player color mode can be used. ****************************************************************************/ @@ -1505,14 +1553,11 @@ static struct setting settings[] = { N_("Map topology"), #ifdef FREECIV_WEB /* TRANS: Freeciv-web version of the help text. */ - N_("Freeciv-web maps are always two-dimensional. They may wrap " - "at the east-west directions to form a flat map or a " - "cylinder.\n"), + N_("Freeciv-web maps are always two-dimensional.\n"), #else /* FREECIV_WEB */ /* TRANS: do not edit the ugly ASCII art */ - N_("Freeciv maps are always two-dimensional. They may wrap at " - "the north-south and east-west directions to form a flat " - "map, a cylinder, or a torus (donut). Individual tiles may " + N_("Freeciv maps are always two-dimensional. " + "Individual tiles may " "be rectangular or hexagonal, with either an overhead " "(\"classic\") or isometric alignment.\n" "To play with a particular topology, clients will need a " @@ -1534,6 +1579,22 @@ static struct setting settings[] = { #endif /* FREECIV_WEB */ topology_callback, topology_action, topology_name, MAP_DEFAULT_TOPO) + GEN_BITWISE("wrap", wld.map.wrap_id, SSET_MAP_SIZE, + SSET_GEOLOGY, SSET_VITAL, ALLOW_NONE, ALLOW_BASIC, + N_("Map wrap"), +#ifdef FREECIV_WEB + /* TRANS: Freeciv-web version of the help text. */ + N_("Freeciv-web maps may wrap " + "at the east-west directions to form a flat map or a " + "cylinder.\n"), +#else /* FREECIV_WEB */ + /* TRANS: do not edit the ugly ASCII art */ + N_("Freeciv maps may wrap at " + "the north-south and east-west directions to form a flat " + "map, a cylinder, or a torus (donut)."), +#endif /* FREECIV_WEB */ + wrap_callback, wrap_action, wrap_name, MAP_DEFAULT_WRAP) + GEN_ENUM("generator", wld.map.server.generator, SSET_MAP_GEN, SSET_GEOLOGY, SSET_VITAL, ALLOW_NONE, ALLOW_BASIC, N_("Method used to generate map"), @@ -3766,8 +3827,7 @@ const char *setting_enum_secfile_str(secfile_data_t data, int val) Convert the integer to the string representation of an enumerator. Return NULL if 'val' is not a valid enumerator. ****************************************************************************/ -const char *setting_enum_val(const struct setting *pset, int val, - bool pretty) +const char *setting_enum_val(const struct setting *pset, int val, bool pretty) { const struct sset_val_name *name; @@ -3941,8 +4001,19 @@ bool setting_enum_validate(const struct setting *pset, const char *val, ****************************************************************************/ const char *setting_bitwise_secfile_str(secfile_data_t data, int bit) { - const struct sset_val_name *name = - ((const struct setting *) data)->bitwise.name(bit); + struct sf_cb_data *info = (struct sf_cb_data *)data; + const struct sset_val_name *name = info->set->bitwise.name(bit); + + if (info->compat && name == NULL) { + if (!fc_strcasecmp("topology", setting_name(info->set))) { + if ((1 << bit) == TF_OLD_WRAPX) { + return "WrapX"; + } + if ((1 << bit) == TF_OLD_WRAPY) { + return "WrapY"; + } + } + } return (NULL != name ? name->support : NULL); } @@ -4307,6 +4378,7 @@ static bool setting_ruleset_one(struct section_file *file, struct setting *pset = NULL; char reject_msg[256], buf[256]; bool lock; + struct sf_cb_data info = { pset, compat }; settings_iterate(SSET_ALL, pset_check) { if (0 == fc_strcasecmp(setting_name(pset_check), name)) { @@ -4320,6 +4392,9 @@ static bool setting_ruleset_one(struct section_file *file, return FALSE; } + info.set = pset; + info.compat = compat; + switch (pset->stype) { case SST_BOOL: { @@ -4395,7 +4470,6 @@ static bool setting_ruleset_one(struct section_file *file, case SST_ENUM: { int val; - struct sf_cb_data info = { pset, compat }; if (!secfile_lookup_enum_data(file, &val, FALSE, setting_enum_secfile_str, &info, @@ -4422,11 +4496,34 @@ static bool setting_ruleset_one(struct section_file *file, int val; if (!secfile_lookup_enum_data(file, &val, TRUE, - setting_bitwise_secfile_str, pset, + setting_bitwise_secfile_str, &info, "%s.value", path)) { log_error("Can't read value for setting '%s': %s", name, secfile_error()); } else if (val != *pset->bitwise.pvalue) { + /* RSFORMAT_3_1 */ + if (compat && !fc_strcasecmp("topology", name)) { + struct setting *wrap = setting_by_name("wrap"); + + if (val & TF_OLD_WRAPX) { + if (val & TF_OLD_WRAPY) { + setting_bitwise_set(wrap, "WrapX|WrapY", NULL, NULL, 0); + } else { + setting_bitwise_set(wrap, "WrapX", NULL, NULL, 0); + } + } else if (val & TF_OLD_WRAPY) { + setting_bitwise_set(wrap, "WrapY", NULL, NULL, 0); + } else { + setting_bitwise_set(wrap, "", NULL, NULL, 0); + } + + val &= ~(TF_OLD_WRAPX | TF_OLD_WRAPY); + + log_normal(_("Ruleset: '%s' has been set to %s."), + setting_name(wrap), + setting_value_name(wrap, TRUE, buf, sizeof(buf))); + } + if (NULL == pset->bitwise.validate || pset->bitwise.validate((unsigned) val, NULL, reject_msg, sizeof(reject_msg))) { @@ -4637,6 +4734,7 @@ void settings_game_save(struct section_file *file, const char *section) settings_iterate(SSET_ALL, pset) { char errbuf[200]; + struct sf_cb_data info = { pset, FALSE }; if (/* It's explicitly set to some value to save */ setting_get_setdef(pset) == SETDEF_CHANGED @@ -4665,23 +4763,19 @@ void settings_game_save(struct section_file *file, const char *section) "%s.set%d.gamestart", section, set_count); break; case SST_ENUM: - { - struct sf_cb_data info = { pset, FALSE }; - - secfile_insert_enum_data(file, read_enum_value(pset), FALSE, - setting_enum_secfile_str, &info, - "%s.set%d.value", section, set_count); - secfile_insert_enum_data(file, pset->enumerator.game_value, FALSE, - setting_enum_secfile_str, &info, - "%s.set%d.gamestart", section, set_count); - } + secfile_insert_enum_data(file, read_enum_value(pset), FALSE, + setting_enum_secfile_str, &info, + "%s.set%d.value", section, set_count); + secfile_insert_enum_data(file, pset->enumerator.game_value, FALSE, + setting_enum_secfile_str, &info, + "%s.set%d.gamestart", section, set_count); break; case SST_BITWISE: secfile_insert_enum_data(file, *pset->bitwise.pvalue, TRUE, - setting_bitwise_secfile_str, pset, + setting_bitwise_secfile_str, &info, "%s.set%d.value", section, set_count); secfile_insert_enum_data(file, pset->bitwise.game_value, TRUE, - setting_bitwise_secfile_str, pset, + setting_bitwise_secfile_str, &info, "%s.set%d.gamestart", section, set_count); break; case SST_COUNT: @@ -4731,6 +4825,8 @@ void settings_game_load(struct section_file *file, const char *section) name = secfile_lookup_str(file, "%s.set%d.name", section, i); settings_iterate(SSET_ALL, pset) { + struct sf_cb_data info = { pset, FALSE }; + if (fc_strcasecmp(setting_name(pset), name) != 0) { continue; } @@ -4834,7 +4930,6 @@ void settings_game_load(struct section_file *file, const char *section) case SST_ENUM: { int val; - struct sf_cb_data info = { pset, FALSE }; if (!secfile_lookup_enum_data(file, &val, FALSE, setting_enum_secfile_str, &info, @@ -4871,7 +4966,7 @@ void settings_game_load(struct section_file *file, const char *section) int val; if (!secfile_lookup_enum_data(file, &val, TRUE, - setting_bitwise_secfile_str, pset, + setting_bitwise_secfile_str, &info, "%s.set%d.value", section, i)) { log_verbose("Option '%s' not defined in the savegame: %s", name, secfile_error()); @@ -4931,21 +5026,17 @@ void settings_game_load(struct section_file *file, const char *section) break; case SST_ENUM: - { - struct sf_cb_data info = { pset, FALSE }; - - pset->enumerator.game_value = - secfile_lookup_enum_default_data(file, + pset->enumerator.game_value = + secfile_lookup_enum_default_data(file, read_enum_value(pset), FALSE, setting_enum_secfile_str, &info, "%s.set%d.gamestart", section, i); - } break; case SST_BITWISE: pset->bitwise.game_value = secfile_lookup_enum_default_data(file, *pset->bitwise.pvalue, TRUE, setting_bitwise_secfile_str, - pset, "%s.set%d.gamestart", section, i); + &info, "%s.set%d.gamestart", section, i); break; case SST_COUNT: diff --git a/tools/ruleutil/rulesave.c b/tools/ruleutil/rulesave.c index 713ba41059..060fc4aaf7 100644 --- a/tools/ruleutil/rulesave.c +++ b/tools/ruleutil/rulesave.c @@ -1734,6 +1734,8 @@ static bool save_game_ruleset(const char *filename, const char *name) set_count = 0; settings_iterate(SSET_ALL, pset) { + struct sf_cb_data info = { pset, FALSE }; + if (setting_get_setdef(pset) == SETDEF_RULESET || setting_locked(pset)) { secfile_insert_str(sfile, setting_name(pset), "settings.set%d.name", set_count); @@ -1751,17 +1753,13 @@ static bool save_game_ruleset(const char *filename, const char *name) "settings.set%d.value", set_count); break; case SST_ENUM: - { - struct sf_cb_data info = { pset, FALSE }; - - secfile_insert_enum_data(sfile, read_enum_value(pset), FALSE, - setting_enum_secfile_str, &info, - "settings.set%d.value", set_count); - } + secfile_insert_enum_data(sfile, read_enum_value(pset), FALSE, + setting_enum_secfile_str, &info, + "settings.set%d.value", set_count); break; case SST_BITWISE: secfile_insert_enum_data(sfile, setting_bitwise_get(pset), TRUE, - setting_bitwise_secfile_str, pset, + setting_bitwise_secfile_str, &info, "settings.set%d.value", set_count); break; case SST_COUNT: -- 2.35.1