From 3c90cc5605e109cb0b2bd6fe0f3779807df8d436 Mon Sep 17 00:00:00 2001 From: Ihnatus Date: Sun, 29 May 2022 00:25:22 +0300 Subject: [PATCH] Optimize create_city() function, allowing to create a city of arbitrary size at once. That also optimizes city creation in edit mode, losening size restriction. Illegal city_size values in units.ruleset won't be accepted any more. See OSDN#44703. Signed-off-by: Ihnatus --- server/citytools.c | 18 ++++++++++++++---- server/citytools.h | 5 +++-- server/edithand.c | 19 ++++++++++++------- server/gamehand.c | 2 +- server/rssanity.c | 9 +++++++++ server/scripting/api_server_edit.c | 2 +- server/unithand.c | 12 ++---------- 7 files changed, 42 insertions(+), 25 deletions(-) diff --git a/server/citytools.c b/server/citytools.c index 465053f5f5..d62899119d 100644 --- a/server/citytools.c +++ b/server/citytools.c @@ -173,10 +173,11 @@ void city_freeze_workers_queue(struct city *pcity) created. ****************************************************************************/ bool create_city_for_player(struct player *pplayer, struct tile *ptile, - const char *name) + const char *name, citizens size) { if (is_enemy_unit_tile(ptile, pplayer) != NULL - || !city_can_be_built_here(ptile, NULL)) { + || !city_can_be_built_here(ptile, NULL) + || size < 1) { return FALSE; } @@ -190,7 +191,7 @@ bool create_city_for_player(struct player *pplayer, struct tile *ptile, } map_show_tile(pplayer, ptile); - create_city(pplayer, ptile, name, pplayer); + create_city(pplayer, ptile, name, pplayer, size); return TRUE; } @@ -1481,7 +1482,8 @@ void city_build_free_buildings(struct city *pcity) Creates real city. **************************************************************************/ void create_city(struct player *pplayer, struct tile *ptile, - const char *name, struct player *nationality) + const char *name, struct player *nationality, + citizens size) { struct player *saved_owner = tile_owner(ptile); struct tile *saved_claimer = tile_claimer(ptile); @@ -1492,7 +1494,13 @@ void create_city(struct player *pplayer, struct tile *ptile, log_debug("create_city() %s", name); + fc_assert_ret(size); pcity = create_city_virtual(pplayer, ptile, name); + /* Created a city with 1 DEFAULT_SPECIALIST */ + if (size - 1) { + city_size_set(pcity, size); + city_repair_size(pcity, size - 1); + } /* Remove units no more seen. Do it before city is really put into the * game. */ @@ -1567,6 +1575,7 @@ void create_city(struct player *pplayer, struct tile *ptile, /* Before arranging workers to show unknown land */ pcity->server.vision = vision_new(pplayer, ptile); vision_reveal_tiles(pcity->server.vision, game.server.vision_reveal_tiles); + conn_list_do_buffer(pplayer->connections); city_refresh_vision(pcity); city_list_prepend(pplayer->cities, pcity); @@ -1600,6 +1609,7 @@ void create_city(struct player *pplayer, struct tile *ptile, pcity->server.synced = FALSE; send_city_info(NULL, pcity); + conn_list_do_unbuffer(pplayer->connections); sync_cities(); /* Will also send pwork. */ notify_player(pplayer, ptile, E_CITY_BUILD, ftc_server, diff --git a/server/citytools.h b/server/citytools.h index a11ca689d2..77fa495218 100644 --- a/server/citytools.h +++ b/server/citytools.h @@ -64,9 +64,10 @@ void remove_dumb_city(struct player *pplayer, struct tile *ptile); void city_build_free_buildings(struct city *pcity); void create_city(struct player *pplayer, struct tile *ptile, - const char *name, struct player *nationality); + const char *name, struct player *nationality, + citizens size); bool create_city_for_player(struct player *pplayer, struct tile *ptile, - const char *name); + const char *name, citizens size); void remove_city(struct city *pcity); struct trade_route *remove_trade_route(struct city *pc1, diff --git a/server/edithand.c b/server/edithand.c index 795e77a65f..2cb7e5966d 100644 --- a/server/edithand.c +++ b/server/edithand.c @@ -661,6 +661,7 @@ void handle_edit_city_create(struct connection *pc, int owner, int tile, struct tile *ptile; struct city *pcity; struct player *pplayer; + int maxsize; ptile = index_to_tile(tile); if (!ptile) { @@ -678,12 +679,14 @@ void handle_edit_city_create(struct connection *pc, int owner, int tile, "given owner's player id %d is invalid"), tile_link(ptile), owner); return; - } + fc_assert_action(size > 0, size = 1); + /* Set from UINT8 packet field, no need to check the top */ + /* fc_assert_action(size < MAX_CITY_SIZE, size = MAX_CITY_SIZE); */ conn_list_do_buffer(game.est_connections); - if (!create_city_for_player(pplayer, ptile, NULL)) { + if (!create_city_for_player(pplayer, ptile, NULL, size)) { notify_conn(pc->self, ptile, E_BAD_COMMAND, ftc_editor, /* TRANS: ..." at ." */ _("A city may not be built at %s."), tile_link(ptile)); @@ -693,11 +696,13 @@ void handle_edit_city_create(struct connection *pc, int owner, int tile, } pcity = tile_city(ptile); - - if (size > 1) { - /* FIXME: Slow and inefficient for large size changes. */ - city_change_size(pcity, CLIP(1, size, MAX_CITY_SIZE), pplayer, NULL); - send_city_info(NULL, pcity); + /* Gently note if city of such a size looks a bit unnatural now */ + maxsize = get_city_bonus(pcity, EFT_SIZE_ADJ); + if (city_size_get(pcity) > maxsize + && get_city_bonus(pcity, EFT_SIZE_UNLIMIT) <= 0) { + notify_conn(pc->self, ptile, E_CITY_AQUEDUCT, ftc_editor, + _("%s needs an improvement to grow beyond size %d."), + city_link(pcity), maxsize); } if (tag > 0) { diff --git a/server/gamehand.c b/server/gamehand.c index 08a63e0118..f961feeab3 100644 --- a/server/gamehand.c +++ b/server/gamehand.c @@ -793,7 +793,7 @@ void init_new_game(void) /* Place first city */ if (game.server.start_city) { create_city(pplayer, ptile, city_name_suggestion(pplayer, ptile), - NULL); + NULL, 1); /* Expose visible area. */ map_show_circle(pplayer, ptile, game.server.init_vis_radius_sq); diff --git a/server/rssanity.c b/server/rssanity.c index 71006b41d4..f51affc1d0 100644 --- a/server/rssanity.c +++ b/server/rssanity.c @@ -942,6 +942,15 @@ bool sanity_check_ruleset_data(bool ignore_retired) putype->paratroopers_range, UNIT_MAX_PARADROP_RANGE); ok = FALSE; } + if (putype->city_size < 1 + || putype->city_size > MAX_CITY_SIZE) { + ruleset_error(LOG_ERROR, + "The city_size of the unit type '%s' is %d. " + "That is out of range. Max range is %d.", + utype_rule_name(putype), + putype->city_size, MAX_CITY_SIZE); + ok = FALSE; + } } unit_type_iterate_end; /* Check requirement sets against conflicting requirements. diff --git a/server/scripting/api_server_edit.c b/server/scripting/api_server_edit.c index 56396c04b4..328f86e570 100644 --- a/server/scripting/api_server_edit.c +++ b/server/scripting/api_server_edit.c @@ -274,7 +274,7 @@ void api_edit_create_city(lua_State *L, Player *pplayer, Tile *ptile, } /* TODO: Allow initial citizen to be of nationality other than owner */ - create_city_for_player(pplayer, ptile, name); + create_city_for_player(pplayer, ptile, name, 1); } /***************************************************************************** diff --git a/server/unithand.c b/server/unithand.c index 34ae97e10a..2ed996f4cb 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -3304,7 +3304,6 @@ static bool city_build(struct player *pplayer, struct unit *punit, const struct action *paction) { char message[1024]; - int size; struct player *nationality; struct player *towner; @@ -3322,15 +3321,8 @@ static bool city_build(struct player *pplayer, struct unit *punit, nationality = unit_nationality(punit); - create_city(pplayer, ptile, name, nationality); - size = unit_type_get(punit)->city_size; - if (size > 1) { - struct city *pcity = tile_city(ptile); - - fc_assert_ret_val(pcity != NULL, FALSE); - - city_change_size(pcity, size, nationality, NULL); - } + create_city(pplayer, ptile, name, nationality, + unit_type_get(punit)->city_size); /* May cause an incident even if the target tile is unclaimed. A ruleset * could give everyone a casus belli against the city founder. A rule -- 2.34.1