From 88c8c067d65b062226bd14a812281445cbc8e7bb Mon Sep 17 00:00:00 2001 From: Ihnatus Date: Sun, 29 May 2022 02:05:03 +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 14f4347a3c..4582d47f71 100644 --- a/server/citytools.c +++ b/server/citytools.c @@ -1472,7 +1472,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); @@ -1483,7 +1484,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. */ @@ -1557,6 +1564,7 @@ void create_city(struct player *pplayer, struct tile *ptile, /* Before arranging workers to show unknown land */ pcity->server.vision = vision_new(pplayer, ptile); + conn_list_do_buffer(pplayer->connections); vision_reveal_tiles(pcity->server.vision, game.server.vision_reveal_tiles); city_refresh_vision(pcity); city_list_prepend(pplayer->cities, pcity); @@ -1591,6 +1599,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, @@ -1632,10 +1641,11 @@ void create_city(struct player *pplayer, struct tile *ptile, 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; } @@ -1649,7 +1659,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; } diff --git a/server/citytools.h b/server/citytools.h index 339af2dea7..8e91f579ab 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 eed7016502..5d680d60a4 100644 --- a/server/edithand.c +++ b/server/edithand.c @@ -663,6 +663,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(&(wld.map), tile); if (!ptile) { @@ -680,12 +681,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, 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)); @@ -695,11 +698,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 a 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 1337bac909..50c2983f3a 100644 --- a/server/gamehand.c +++ b/server/gamehand.c @@ -795,7 +795,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 5b7b1d0bde..292d28a945 100644 --- a/server/rssanity.c +++ b/server/rssanity.c @@ -1000,6 +1000,15 @@ bool sanity_check_ruleset_data(struct rscompat_info *compat) utype_rule_name(putype)); 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 that unit type fields are in range. */ diff --git a/server/scripting/api_server_edit.c b/server/scripting/api_server_edit.c index 609aa9a0e7..d8ce730a41 100644 --- a/server/scripting/api_server_edit.c +++ b/server/scripting/api_server_edit.c @@ -660,7 +660,7 @@ bool api_edit_create_city(lua_State *L, Player *pplayer, Tile *ptile, LUASCRIPT_CHECK_ARG_NIL(L, ptile, 3, Tile, FALSE); /* TODO: Allow initial citizen to be of nationality other than owner */ - return create_city_for_player(pplayer, ptile, name); + return create_city_for_player(pplayer, ptile, name, 1); } /**********************************************************************//** diff --git a/server/unithand.c b/server/unithand.c index 8ba3330634..d1d98e9f24 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -3914,7 +3914,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; const struct unit_type *act_utype; @@ -3934,15 +3933,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