diff -Nur -Xfreecivdiff.ignore freeciv-cvs/doc/README.borders-semifog freeciv-patched/doc/README.borders-semifog --- freeciv-cvs/doc/README.borders-semifog 1970-01-01 01:00:00.000000000 +0100 +++ freeciv-patched/doc/README.borders-semifog 2003-07-24 12:39:30.000000000 +0100 @@ -0,0 +1,24 @@ +Borders Semi-Fog Patch +---------------------- +Author: Ben Webb + +When borders are combined with fog of war, complications arise. The current +borders implementation is "omniscient" in that clients are told the ownership +of every known tile, whether or not it is fogged. This ensures that the +locations of borders are always consistent; however, it gives the client +more information about fogged areas than it should know (for example, it is +very easy to guess the position of enemy cities). One simple solution to +this problem is only to send ownership information for known tiles, and +not for fogged ones. This, however, is very confusing in practice, as your +own borders shift in weird ways as the fog of war is uncovered. + +An alternative solution is used in this "semi-fog" patch. Each player is sent +ownership information for tiles that can be directly seen, and for fogged +tiles only if the player owns the tile, has just lost ownership of the tile, +or the tile is directly adjacent to one that the player owns. This means +that you always know your own borders exactly, but have limited knowledge +of other players' borders. + +Note that savegames produced with this patch are not compatible with the +standard borders code, and vice versa - this patch should be used for +testing only! diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/maphand.c freeciv-patched/server/maphand.c --- freeciv-cvs/server/maphand.c 2003-07-23 16:36:57.000000000 +0100 +++ freeciv-patched/server/maphand.c 2003-07-24 12:30:58.000000000 +0100 @@ -321,6 +321,19 @@ } /************************************************************************** + Returns TRUE if the given player owns a tile adjacent to that passed. +**************************************************************************/ +static bool player_owns_adjc_tile(struct player *pplayer, int x, int y) +{ + adjc_iterate(x, y, x1, y1) { + if (map_get_owner(x1, y1) == pplayer) { + return TRUE; + } + } adjc_iterate_end; + return FALSE; +} + +/************************************************************************** Send tile information to all the clients in dest which know and see the tile. Also updates player knowledge. If dest is NULL, sends to all clients (game.game_connections) which know and see tile. @@ -354,13 +367,18 @@ send_packet_tile_info(pconn, &info); } else if (pplayer && map_get_known(x, y, pplayer) && !map_get_seen(x, y, pplayer)) { - /* Just update the owner */ struct player_tile *plrtile = map_get_player_tile(x, y, pplayer); + /* Update the owner of a fogged tile ONLY if we are gaining or losing + * ownership, OR if the tile is adjacent to one we do own */ info.known = TILE_KNOWN_FOGGED; info.type = plrtile->terrain; info.special = plrtile->special; info.continent = ptile->continent; - send_packet_tile_info(pconn, &info); + if (ptile->owner == pplayer || plrtile->owner == pplayer + || player_owns_adjc_tile(pplayer, x, y)) { + plrtile->owner = ptile->owner; + send_packet_tile_info(pconn, &info); + } } } conn_list_iterate_end; @@ -394,16 +412,21 @@ info.continent = ptile->continent; } else if (map_get_known(x, y, pplayer)) { + plrtile = map_get_player_tile(x, y, pplayer); if (map_get_seen(x, y, pplayer) != 0) { /* known and seen */ update_tile_knowledge(pplayer,x,y); /* visible; update info */ info.known = TILE_KNOWN; } else { /* known but not seen */ info.known = TILE_KNOWN_FOGGED; + if (ptile->owner == pplayer || plrtile->owner == pplayer + || player_owns_adjc_tile(pplayer, x, y)) { + plrtile->owner = ptile->owner; + } } - plrtile = map_get_player_tile(x, y, pplayer); info.type = plrtile->terrain; info.special = plrtile->special; info.continent = ptile->continent; + info.owner = plrtile->owner ? plrtile->owner->player_no : MAP_TILE_OWNER_NULL; } else { /* unknown (the client needs these sometimes to draw correctly) */ info.known = TILE_UNKNOWN; info.type = ptile->terrain; @@ -920,6 +943,7 @@ plrtile->terrain = T_UNKNOWN; plrtile->special = S_NO_SPECIAL; plrtile->city = NULL; + plrtile->owner = NULL; plrtile->seen = 0; plrtile->pending_seen = 0; @@ -953,6 +977,7 @@ plrtile->terrain = ptile->terrain; plrtile->special = ptile->special; + plrtile->owner = ptile->owner; } /*************************************************************** diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/maphand.h freeciv-patched/server/maphand.h --- freeciv-cvs/server/maphand.h 2003-07-23 16:36:57.000000000 +0100 +++ freeciv-patched/server/maphand.h 2003-07-24 12:30:58.000000000 +0100 @@ -35,6 +35,7 @@ struct player_tile { enum tile_terrain_type terrain; enum tile_special_type special; + struct player *owner; /* Player owning this tile, or NULL. */ unsigned short seen; unsigned short own_seen; /* If you build a city with an unknown square within city radius diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/savegame.c freeciv-patched/server/savegame.c --- freeciv-cvs/server/savegame.c 2003-07-23 16:36:57.000000000 +0100 +++ freeciv-patched/server/savegame.c 2003-07-24 12:30:58.000000000 +0100 @@ -213,6 +213,32 @@ } /*************************************************************** + Converts a tile owner pointer into a char suitable for + writing to the savefile. +***************************************************************/ +static char owner2char(struct player *owner) +{ + if (!owner) { + return '+'; + } else { + int plrno = owner->player_no; + return (plrno < 10 ? '0' + plrno : + plrno < 36 ? 'a' + plrno - 10 : 'A' + plrno - 36); + } +} + +/*************************************************************** + Obtains a tile owner pointer from the savefile information. +***************************************************************/ +static struct player *char2owner(char ch) +{ + return (ch == '+' ? NULL : + ch >= '0' && ch <= '9' ? get_player(ch - '0') : + ch >= 'a' && ch <= 'z' ? get_player(ch - 'a' + 10) : + get_player(ch - 'A' + 36)); +} + +/*************************************************************** Quote the memory block denoted by data and length so it consists only of " a-f0-9:". The returned string has to be freed by the caller using free(). @@ -1209,6 +1235,13 @@ map_get_player_tile(x, y, plr)->terrain = char2terrain(ch)); + /* Load tile ownership information if we're using borders */ + if (game.borders > 0) { + LOAD_MAP_DATA(secfile_lookup_str(file, "player%d.map_o%03d", plrno, y), + map_get_player_tile(x, y, plr)->owner = + char2owner(ch)); + } + /* get 4-bit segments of 12-bit "special" field. */ LOAD_MAP_DATA(secfile_lookup_str(file, "player%d.map_l%03d", plrno, y), map_get_player_tile(x, y, plr)->special = @@ -1617,6 +1650,13 @@ (x, y, plr)->terrain], "player%d.map_t%03d", plrno); + /* put tile ownership information if we're using borders */ + if (game.borders > 0) { + SAVE_PLAYER_MAP_DATA(file, + owner2char(map_get_player_tile(x, y, plr)->owner), + "player%d.map_o%03d", plrno); + } + /* put 4-bit segments of 12-bit "special flags" field */ SAVE_PLAYER_MAP_DATA(file, bin2ascii_hex(map_get_player_tile(x, y, plr)->