diff -Nur -X freeciv-cvs/diff_ignore freeciv-cvs/common/game.c freeciv/common/game.c --- freeciv-cvs/common/game.c Wed Jan 2 14:23:21 2002 +++ freeciv/common/game.c Thu Jan 3 08:40:46 2002 @@ -716,7 +716,8 @@ game.randseed=GAME_DEFAULT_RANDSEED; game.watchtower_vision=GAME_DEFAULT_WATCHTOWER_VISION; game.watchtower_extra_vision=GAME_DEFAULT_WATCHTOWER_EXTRA_VISION, - + game.allowed_city_names=GAME_DEFAULT_ALLOWED_CITY_NAMES; + sz_strlcpy(game.ruleset.techs, GAME_DEFAULT_RULESET); sz_strlcpy(game.ruleset.units, GAME_DEFAULT_RULESET); sz_strlcpy(game.ruleset.buildings, GAME_DEFAULT_RULESET); diff -Nur -X freeciv-cvs/diff_ignore freeciv-cvs/common/game.h freeciv/common/game.h --- freeciv-cvs/common/game.h Wed Jan 2 14:23:21 2002 +++ freeciv/common/game.h Thu Jan 3 10:14:08 2002 @@ -145,6 +145,8 @@ int watchtower_extra_vision; int watchtower_vision; + int allowed_city_names; + struct { char techs[MAX_LEN_NAME]; char units[MAX_LEN_NAME]; @@ -440,6 +442,10 @@ #define GAME_DEFAULT_WATCHTOWER_EXTRA_VISION 0 #define GAME_MIN_WATCHTOWER_EXTRA_VISION 0 #define GAME_MAX_WATCHTOWER_EXTRA_VISION 2 + +#define GAME_DEFAULT_ALLOWED_CITY_NAMES 1 +#define GAME_MIN_ALLOWED_CITY_NAMES 0 +#define GAME_MAX_ALLOWED_CITY_NAMES 3 #define GAME_START_YEAR -4000 diff -Nur -X freeciv-cvs/diff_ignore freeciv-cvs/server/cityhand.c freeciv/server/cityhand.c --- freeciv-cvs/server/cityhand.c Fri Dec 7 18:30:12 2001 +++ freeciv/server/cityhand.c Thu Jan 3 12:53:07 2002 @@ -395,10 +395,11 @@ return; if((cp=get_sane_name(preq->name))) { - /* more sanity tests! any existing city with that name? */ - sz_strlcpy(pcity->name, cp); - city_refresh(pcity); - send_city_info(0, pcity); + if(is_allowed_city_name(cp, pcity->x, pcity->y, pplayer)) { + sz_strlcpy(pcity->name, cp); + city_refresh(pcity); + send_city_info(0, pcity); + } } else { notify_player(pplayer, _("Game: %s is not a valid name."), preq->name); } diff -Nur -X freeciv-cvs/diff_ignore freeciv-cvs/server/citytools.c freeciv/server/citytools.c --- freeciv-cvs/server/citytools.c Thu Dec 13 22:05:48 2001 +++ freeciv/server/citytools.c Thu Jan 3 13:09:22 2002 @@ -58,8 +58,130 @@ char **misc_city_names; int num_misc_city_names; +/************************************************************************** +... +**************************************************************************/ +int is_in_city_name_list(char* name, char** list) +{ + char** pname; + for(pname = list; *pname; pname++) { + if( mystrcasecmp(name, *pname) == 0 ) { + return TRUE; + } + } + return FALSE; +} + + +/************************************************************************** +Checks if a city name belongs to default city names of a particular player. +**************************************************************************/ +int is_default_city_name(char* name, struct player* pplayer) +{ + struct nation_type *pnation = get_nation_by_plr(pplayer); + int i; + + if( is_in_city_name_list(name, pnation->default_city_names) || + is_in_city_name_list(name, pnation->default_rcity_names) || + is_in_city_name_list(name, pnation->default_crcity_names) || + is_in_city_name_list(name, pnation->default_ccity_names) ) + return TRUE; + + for(i=0; idefault_tcity_names[i])) + return TRUE; + } + + return FALSE; +} + + +/************************************************************************** +Search default city names of other players for a given name. +Returns NULL, if the name isn't among default city names of other players. +Otherwise, returns a pointer to one such player. +**************************************************************************/ +struct player* search_city_names_of_others(char* name, + struct player* pplayer) +{ + struct player* pother; + int i; + + assert(pplayer != NULL); + + for(i=0; i < game.nplayers; i++) { + pother = &game.players[i]; + if( pother != pplayer && + is_default_city_name(name, pother) ) { + return pother; + } + } + return NULL; +} + + +/************************************************************************** +Checks, if a city name is allowed for a player. If not, reports a reason for +rejection. There's 4 different modes: +0: no restrictions, +1: a city name has to be unique to player +2: a city name has to be globally unique +3: a city name has to be globally unique, and players can't use names that + are in another player's default city names. (E.g. Swedish may not + call new cities or rename old cities as Helsinki, because it's in + Finns' default city names) +**************************************************************************/ +int is_allowed_city_name(char* city_name, int x, int y, + struct player* pplayer) +{ + struct player* pother; + + freelog(LOG_DEBUG, "Checking, if %s is a proper city name\n", city_name); + + /* Mode 0: No restrictions to city names */ + if( game.allowed_city_names == 0) + return TRUE; + + /* Mode 1: A city name has to be unique to player */ + if( game.allowed_city_names == 1 && + city_list_find_name(&pplayer->cities,city_name) ) { + notify_player_ex(pplayer, x, y, E_NOEVENT, + _("Game: You already have a city called %s"), + city_name); + return FALSE; + } + + /* Modes 2,3: A city name has to be globally unique */ + + /* Mode 3: Check first that the proposed city name is not in another + player's default city names. Otherwise (in mode 2) one could try + default names to get information about another player's city count */ + if( game.allowed_city_names == 3 ) { + pother = search_city_names_of_others(city_name, pplayer); + if(pother != NULL) { + notify_player_ex(pplayer, x, y, E_NOEVENT, + _("Game: Can't use a city name %s. " + "It is reserved for %s."), + city_name, get_nation_name_plural(pother->nation)); + return FALSE; + } + } + + if( (game.allowed_city_names == 2 || + game.allowed_city_names == 3) && + game_find_city_by_name(city_name) ) { + notify_player_ex(pplayer, x, y, E_NOEVENT, + _("Game: A city called %s already exists."), + city_name); + return FALSE; + } + + return TRUE; +} + /**************************************************************** Come up with a default name when a new city is about to be built. +It is expected that returned name is globally unique. Handle running out of names etc. gracefully. Maybe we should keep track of which names have been rejected by the player, so that we do not suggest them again? @@ -81,11 +203,18 @@ CHECK_MAP_POS(x,y); -#define SEARCH_AND_RETURN_CITY_NAME(list) \ - for(nptr=list; *nptr; nptr++) { \ - if(!game_find_city_by_name(*nptr)) { \ - return *nptr; \ - } \ + /* Search for a first city name that's not used (globally). + * In case that allowed_city_names mode is 3, don't propose + * name that belongs to other player's default city names. + */ +#define SEARCH_AND_RETURN_CITY_NAME(list) \ + for(nptr=list; *nptr; nptr++) { \ + if(!game_find_city_by_name(*nptr)) { \ + if(!(game.allowed_city_names == 3 && \ + search_city_names_of_others(*nptr, pplayer))) { \ + return *nptr; \ + } \ + } \ } /* @@ -746,6 +875,7 @@ struct unit_list old_city_units; struct player *pgiver = city_owner(pcity); int old_trade_routes[4]; + char old_city_name[MAX_LEN_NAME]; int had_palace = pcity->improvements[B_PALACE] != I_NONE; assert(pgiver != ptaker); @@ -771,6 +901,16 @@ } } + sz_strlcpy(old_city_name,pcity->name); + if(game.allowed_city_names == 1 && + city_list_find_name(&ptaker->cities, pcity->name)) { + sz_strlcpy(pcity->name,city_name_suggestion(ptaker,pcity->x, pcity->y)); + notify_player_ex(ptaker, pcity->x, pcity->y, E_NOEVENT, + _("You already had a city called %s." + " A city renamed to %s."), + old_city_name, pcity->name); + } + city_list_unlink(&pgiver->cities, pcity); pcity->owner = ptaker->player_no; city_list_insert(&ptaker->cities, pcity); @@ -870,7 +1010,7 @@ gamelog(GAMELOG_LOSEC,"%s lose %s (%i,%i)", get_nation_name_plural(pgiver->nation), - pcity->name, pcity->x, pcity->y); + old_city_name, pcity->x, pcity->y); /* Build a new palace for free if the player lost her capital and savepalace is on. */ diff -Nur -X freeciv-cvs/diff_ignore freeciv-cvs/server/citytools.h freeciv/server/citytools.h --- freeciv-cvs/server/citytools.h Fri Dec 7 18:30:12 2001 +++ freeciv/server/citytools.h Thu Jan 3 12:53:56 2002 @@ -80,6 +80,8 @@ void change_build_target(struct player *pplayer, struct city *pcity, int target, int is_unit, int event); +int is_allowed_city_name(char* city_name, int x, int y, + struct player *pplayer); char *city_name_suggestion(struct player *pplayer, int x, int y); extern char **misc_city_names; extern int num_misc_city_names; diff -Nur -X freeciv-cvs/diff_ignore freeciv-cvs/server/savegame.c freeciv/server/savegame.c --- freeciv-cvs/server/savegame.c Wed Jan 2 14:23:25 2002 +++ freeciv/server/savegame.c Thu Jan 3 08:40:46 2002 @@ -1825,6 +1825,9 @@ game.randseed = secfile_lookup_int_default(file, game.randseed, "game.randseed"); + game.allowed_city_names = secfile_lookup_int_default(file, game.allowed_city_names, + "game.allowed_city_names"); + sz_strlcpy(game.ruleset.techs, secfile_lookup_str_default(file, "default", "game.ruleset.techs")); sz_strlcpy(game.ruleset.units, @@ -2147,6 +2150,7 @@ secfile_insert_str(file, game.demography, "game.demography"); secfile_insert_int(file, game.watchtower_vision, "game.watchtower_vision"); secfile_insert_int(file, game.watchtower_extra_vision, "game.watchtower_extra_vision"); + secfile_insert_int(file, game.allowed_city_names, "game.allowed_city_names"); if (1) { /* Now always save these, so the server options reflect the diff -Nur -X freeciv-cvs/diff_ignore freeciv-cvs/server/stdinhand.c freeciv/server/stdinhand.c --- freeciv-cvs/server/stdinhand.c Thu Dec 13 22:05:48 2001 +++ freeciv/server/stdinhand.c Thu Jan 3 10:32:22 2002 @@ -618,6 +618,19 @@ "Always the larger value of wtowervision and wtowerevision will \n" "be used. Also see wtowervision.") }, + { "citynames", &game.allowed_city_names, NULL, NULL, + SSET_RULES, SSET_TO_CLIENT, + GAME_MIN_ALLOWED_CITY_NAMES, GAME_MAX_ALLOWED_CITY_NAMES, GAME_DEFAULT_ALLOWED_CITY_NAMES, + N_("Allowed city names"), + N_("If set to 0, there's no restrictions, players can have\n" + "multiple cities with same names.\n" + "If set to 1, city names have to be unique to player, \n" + "one player can't have multiple cities with a same name.\n" + "If set to 2 or 3, city names have to be globally unique, \n" + "all cities in a game have to have different names.\n" + "If set to 3, a player isn't allowed to use a default city name \n" + "of another nations.\n") }, + /* Flexible rules: these can be changed after the game has started. * * The distinction between "rules" and "flexible rules" is not always diff -Nur -X freeciv-cvs/diff_ignore freeciv-cvs/server/unithand.c freeciv/server/unithand.c --- freeciv-cvs/server/unithand.c Thu Nov 22 13:00:07 2001 +++ freeciv/server/unithand.c Thu Jan 3 12:54:18 2002 @@ -546,13 +546,17 @@ char *name) { char *city_name = get_sane_name(name); - + if (!city_name) { notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, _("Game: Let's not build a city with " "such a stupid name.")); return; } + + if (!is_allowed_city_name(city_name, punit->x, punit->y, pplayer)) + return; + create_city(pplayer, punit->x, punit->y, city_name); wipe_unit(punit); }