From fa5cdde61f926dcb0d8b7c5dce0e6930519f2fcc Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 22 Oct 2022 06:19:46 +0300 Subject: [PATCH 44/44] Make number of cities in Top Cities report configurable See osdn #45826 Signed-off-by: Marko Lindqvist --- client/gui-gtk-3.22/menu.c | 20 ++++- client/gui-gtk-4.0/menu.c | 6 +- client/gui-qt/menu.cpp | 21 ++++-- client/gui-qt/menu.h | 7 +- client/gui-sdl2/gui_main.c | 2 +- common/game.c | 1 + common/game.h | 4 + common/networking/packets.def | 1 + common/networking/packets.h | 2 +- fc_version | 2 +- server/report.c | 136 ++++++++++++++++++---------------- server/report.h | 10 +-- server/settings.c | 10 +++ server/srv_main.c | 4 +- 14 files changed, 141 insertions(+), 85 deletions(-) diff --git a/client/gui-gtk-3.22/menu.c b/client/gui-gtk-3.22/menu.c index e4c24bc225..e569098b8b 100644 --- a/client/gui-gtk-3.22/menu.c +++ b/client/gui-gtk-3.22/menu.c @@ -305,7 +305,7 @@ static struct menu_entry_info menu_entries[] = G_CALLBACK(report_cities_callback), MGROUP_SAFE }, { "REPORT_WOW", N_("_Wonders of the World"), GDK_KEY_F7, 0, G_CALLBACK(report_wow_callback), MGROUP_SAFE }, - { "REPORT_TOP_CITIES", N_("Top _Five Cities"), GDK_KEY_F8, 0, + { "REPORT_TOP_CITIES", N_("Top Cities"), GDK_KEY_F8, 0, G_CALLBACK(report_top_cities_callback), MGROUP_SAFE }, { "REPORT_MESSAGES", N_("_Messages"), GDK_KEY_F9, 0, G_CALLBACK(report_messages_callback), MGROUP_SAFE }, @@ -727,7 +727,7 @@ static void report_wow_callback(GtkMenuItem *item, gpointer data) ****************************************************************************/ static void report_top_cities_callback(GtkMenuItem *item, gpointer data) { - send_report_request(REPORT_TOP_5_CITIES); + send_report_request(REPORT_TOP_CITIES); } /************************************************************************//** @@ -2218,6 +2218,22 @@ void real_menus_update(void) } } + { + char top_cities_buf[128]; + + if (game.info.top_cities_count > 0) { + fc_snprintf(top_cities_buf, sizeof(top_cities_buf), + PL_("Top %d City", "Top %d Cities", + game.info.top_cities_count), + game.info.top_cities_count); + menus_rename("REPORT_TOP_CITIES", top_cities_buf); + } else { + menus_rename("REPORT_TOP_CITIES", _("Top Cities")); + } + + menu_entry_set_sensitive("REPORT_TOP_CITIES", game.info.top_cities_count > 0); + } + if (!can_client_issue_orders()) { return; } diff --git a/client/gui-gtk-4.0/menu.c b/client/gui-gtk-4.0/menu.c index 845d830ad5..a1dd229615 100644 --- a/client/gui-gtk-4.0/menu.c +++ b/client/gui-gtk-4.0/menu.c @@ -450,7 +450,7 @@ static struct menu_entry_info menu_entries[] = { "REPORT_WOW", N_("_Wonders of the World"), "report_wow", "F7", MGROUP_SAFE }, - { "REPORT_TOP_CITIES", N_("Top _Five Cities"), + { "REPORT_TOP_CITIES", N_("Top Cities"), "report_top_cities", "F8", MGROUP_SAFE }, { "REPORT_MESSAGES", N_("_Messages"), "report_messages", "F9", MGROUP_SAFE }, @@ -975,7 +975,7 @@ static void report_top_cities_callback(GSimpleAction *action, GVariant *parameter, gpointer data) { - send_report_request(REPORT_TOP_5_CITIES); + send_report_request(REPORT_TOP_CITIES); } /************************************************************************//** @@ -2954,6 +2954,8 @@ void real_menus_update(void) menu_entry_set_sensitive(map, "INFRA_DLG", terrain_control.infrapoints); + menu_entry_set_sensitive(map, "REPORT_TOP_CITIES", game.info.top_cities_count > 0); + #ifdef MENUS_GTK3 menu_entry_set_active("EDIT_MODE", game.info.is_edit_mode); diff --git a/client/gui-qt/menu.cpp b/client/gui-qt/menu.cpp index 5e3485e150..68262745dd 100644 --- a/client/gui-qt/menu.cpp +++ b/client/gui-qt/menu.cpp @@ -1555,9 +1555,10 @@ void mr_menu::setup_menus() act->setShortcut(QKeySequence(tr("F7"))); connect(act, &QAction::triggered, this, &mr_menu::slot_traveler); - act = main_menu->addAction(_("Top Five Cities")); + act = main_menu->addAction(_("Top Cities")); act->setShortcut(QKeySequence(tr("F8"))); - connect(act, &QAction::triggered, this, &mr_menu::slot_top_five); + menu_list.insert(TOP_CITIES, act); + connect(act, &QAction::triggered, this, &mr_menu::slot_top_cities); act = main_menu->addAction(_("Demographics")); act->setShortcut(QKeySequence(tr("F11"))); @@ -2052,6 +2053,16 @@ void mr_menu::menus_sensitive() i.value()->setVisible(false); } break; + case TOP_CITIES: + i.value()->setEnabled(game.info.top_cities_count > 0); + if (game.info.top_cities_count > 0) { + i.value()->setText(QString(PL_("Top %1 City", "Top %1 Cities", + game.info.top_cities_count)) + .arg(game.info.top_cities_count)); + } else { + i.value()->setText(QString(_("Top Cities"))); + } + break; default: break; } @@ -3405,11 +3416,11 @@ void mr_menu::slot_endgame() } /**********************************************************************//** - Action "SHOW TOP FIVE CITIES" + Action "SHOW TOP CITIES" **************************************************************************/ -void mr_menu::slot_top_five() +void mr_menu::slot_top_cities() { - send_report_request(REPORT_TOP_5_CITIES); + send_report_request(REPORT_TOP_CITIES); } /**********************************************************************//** diff --git a/client/gui-qt/menu.h b/client/gui-qt/menu.h index db9309464a..ed427a585e 100644 --- a/client/gui-qt/menu.h +++ b/client/gui-qt/menu.h @@ -34,7 +34,7 @@ class QPushButton; class QScrollArea; struct fc_shortcut; -/** used for indicating menu about current option - for renaming +/** Used for indicating menu about current option - for renaming * and enabling, disabling */ enum munit { STANDARD, @@ -74,7 +74,8 @@ enum munit { NOT_4_OBS, MULTIPLIERS, ENDGAME, - SAVE + SAVE, + TOP_CITIES }; enum delay_order{ @@ -411,7 +412,7 @@ private slots: void slot_demographics(); void slot_achievements(); void slot_endgame(); - void slot_top_five(); + void slot_top_cities(); void slot_traveler(); private: diff --git a/client/gui-sdl2/gui_main.c b/client/gui-sdl2/gui_main.c index fa6eb88cfd..3ab584e7b3 100644 --- a/client/gui-sdl2/gui_main.c +++ b/client/gui-sdl2/gui_main.c @@ -246,7 +246,7 @@ static Uint16 main_key_down_handler(SDL_Keysym key, void *data) return ID_ERROR; case SDLK_F8: - send_report_request(REPORT_TOP_5_CITIES); + send_report_request(REPORT_TOP_CITIES); return ID_ERROR; case SDLK_F9: diff --git a/common/game.c b/common/game.c index 0cccfdca03..75a339f4d6 100644 --- a/common/game.c +++ b/common/game.c @@ -316,6 +316,7 @@ static void game_defaults(bool keep_ruleset_value) game.info.warminglevel = 0; /* set later */ game.info.year_0_hack = FALSE; game.info.year = GAME_DEFAULT_START_YEAR; + game.info.top_cities_count = GAME_DEFAULT_TOP_CITIES_COUNT; BV_CLR_ALL(game.info.diplchance_initial_odds); /* The scenario packets. */ diff --git a/common/game.h b/common/game.h index 56b193de4d..0e4b15e543 100644 --- a/common/game.h +++ b/common/game.h @@ -713,6 +713,10 @@ static inline bool is_ruleset_compat_mode(void) #define GAME_HARDCODED_DEFAULT_SKILL_LEVEL 3 /* that was 'easy' in old saves */ #define GAME_OLD_DEFAULT_SKILL_LEVEL 5 /* normal; for oldest save games */ +#define GAME_DEFAULT_TOP_CITIES_COUNT 5 +#define GAME_MIN_TOP_CITIES_COUNT 0 +#define GAME_MAX_TOP_CITIES_COUNT 40 + #define GAME_DEFAULT_DEMOGRAPHY "NASRLPEMOCqrb" #define GAME_DEFAULT_ALLOW_TAKE "HAhadOo" diff --git a/common/networking/packets.def b/common/networking/packets.def index d378d1d79c..2161375b63 100644 --- a/common/networking/packets.def +++ b/common/networking/packets.def @@ -606,6 +606,7 @@ PACKET_GAME_INFO = 16; sc, is-info UINT32 warminglevel; YEAR year; BOOL year_0_hack; + UINT8 top_cities_count; UINT16 fragment_count; BOOL civil_war_enabled; SINT16 civil_war_bonus_celebrating; diff --git a/common/networking/packets.h b/common/networking/packets.h index e11a2e1310..35b869f12c 100644 --- a/common/networking/packets.h +++ b/common/networking/packets.h @@ -81,7 +81,7 @@ do { \ /* Used in network protocol. */ enum report_type { REPORT_WONDERS_OF_THE_WORLD, - REPORT_TOP_5_CITIES, + REPORT_TOP_CITIES, REPORT_DEMOGRAPHIC, REPORT_ACHIEVEMENTS }; diff --git a/fc_version b/fc_version index 2fc445ab43..2243975cf9 100755 --- a/fc_version +++ b/fc_version @@ -61,7 +61,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-${MAIN_VERSION}-2022.Oct.22b" +NETWORK_CAPSTRING="+Freeciv.Devel-${MAIN_VERSION}-2022.Oct.22c" FREECIV_DISTRIBUTOR="" diff --git a/server/report.c b/server/report.c index 0da5d4b2a1..a7bf833333 100644 --- a/server/report.c +++ b/server/report.c @@ -77,6 +77,9 @@ static void plrdata_slot_free(struct plrdata_slot *plrdata); static void page_conn_etype(struct conn_list *dest, const char *caption, const char *headline, const char *lines, enum event_type event); +static void page_conn(struct conn_list *dest, const char *caption, + const char *headline, const char *lines); + enum historian_type { HISTORIAN_RICHEST = 0, HISTORIAN_ADVANCED = 1, @@ -323,76 +326,85 @@ static int nr_wonders(struct city *pcity) } /**********************************************************************//** - Send report listing the "best" 5 cities in the world. + Send report listing the "best" cities in the world. **************************************************************************/ -void report_top_five_cities(struct conn_list *dest) +void report_top_cities(struct conn_list *dest) { - const int NUM_BEST_CITIES = 5; - /* a wonder equals WONDER_FACTOR citizen */ - const int WONDER_FACTOR = 5; - struct city_score_entry size[NUM_BEST_CITIES]; - int i; - char buffer[4096]; + if (game.info.top_cities_count > 0) { + /* A wonder equals WONDER_FACTOR citizen */ + const int WONDER_FACTOR = 5; + struct city_score_entry size[game.info.top_cities_count]; + int i; + char header[256]; + char buffer[4096]; - for (i = 0; i < NUM_BEST_CITIES; i++) { - size[i].value = 0; - size[i].city = NULL; - } + for (i = 0; i < game.info.top_cities_count; i++) { + size[i].value = 0; + size[i].city = NULL; + } - shuffled_players_iterate(pplayer) { - city_list_iterate(pplayer->cities, pcity) { - int value_of_pcity = city_size_get(pcity) - + nr_wonders(pcity) * WONDER_FACTOR; + shuffled_players_iterate(pplayer) { + city_list_iterate(pplayer->cities, pcity) { + int value_of_pcity = city_size_get(pcity) + + nr_wonders(pcity) * WONDER_FACTOR; - if (value_of_pcity > size[NUM_BEST_CITIES - 1].value) { - size[NUM_BEST_CITIES - 1].value = value_of_pcity; - size[NUM_BEST_CITIES - 1].city = pcity; - qsort(size, NUM_BEST_CITIES, sizeof(size[0]), secompare); + if (value_of_pcity > size[game.info.top_cities_count - 1].value) { + size[game.info.top_cities_count - 1].value = value_of_pcity; + size[game.info.top_cities_count - 1].city = pcity; + qsort(size, game.info.top_cities_count, sizeof(size[0]), secompare); + } + } city_list_iterate_end; + } shuffled_players_iterate_end; + + buffer[0] = '\0'; + for (i = 0; i < game.info.top_cities_count; i++) { + int wonders; + + if (size[i].city == NULL) { + /* + * There are less than game.info.top_cities_count cities in + * the whole game. + */ + break; } - } city_list_iterate_end; - } shuffled_players_iterate_end; - buffer[0] = '\0'; - for (i = 0; i < NUM_BEST_CITIES; i++) { - int wonders; - - if (!size[i].city) { - /* - * pcity may be NULL if there are less than NUM_BEST_CITIES in - * the whole game. - */ - break; - } + if (player_count() > team_count()) { + /* There exists a team with more than one member. */ + char team_name[2 * MAX_LEN_NAME]; + + team_pretty_name(city_owner(size[i].city)->team, team_name, + sizeof(team_name)); + cat_snprintf(buffer, sizeof(buffer), + /* TRANS:"The French City of Lyon (team 3) of size 18". */ + _("%2d: The %s City of %s (%s) of size %d, "), i + 1, + nation_adjective_for_player(city_owner(size[i].city)), + city_name_get(size[i].city), team_name, + city_size_get(size[i].city)); + } else { + cat_snprintf(buffer, sizeof(buffer), + _("%2d: The %s City of %s of size %d, "), i + 1, + nation_adjective_for_player(city_owner(size[i].city)), + city_name_get(size[i].city), city_size_get(size[i].city)); + } - if (player_count() > team_count()) { - /* There exists a team with more than one member. */ - char team_name[2 * MAX_LEN_NAME]; - - team_pretty_name(city_owner(size[i].city)->team, team_name, - sizeof(team_name)); - cat_snprintf(buffer, sizeof(buffer), - /* TRANS:"The French City of Lyon (team 3) of size 18". */ - _("%2d: The %s City of %s (%s) of size %d, "), i + 1, - nation_adjective_for_player(city_owner(size[i].city)), - city_name_get(size[i].city), team_name, - city_size_get(size[i].city)); - } else { - cat_snprintf(buffer, sizeof(buffer), - _("%2d: The %s City of %s of size %d, "), i + 1, - nation_adjective_for_player(city_owner(size[i].city)), - city_name_get(size[i].city), city_size_get(size[i].city)); + wonders = nr_wonders(size[i].city); + if (wonders == 0) { + cat_snprintf(buffer, sizeof(buffer), _("with no Great Wonders\n")); + } else { + cat_snprintf(buffer, sizeof(buffer), + PL_("with %d Great Wonder\n", "with %d Great Wonders\n", + wonders), + wonders); + } } - wonders = nr_wonders(size[i].city); - if (wonders == 0) { - cat_snprintf(buffer, sizeof(buffer), _("with no Great Wonders\n")); - } else { - cat_snprintf(buffer, sizeof(buffer), - PL_("with %d Great Wonder\n", "with %d Great Wonders\n", wonders), - wonders);} + fc_snprintf(header, sizeof(header), + PL_("The %d Greatest City in the World!", + "The %d Greatest Cities in the World!", + game.info.top_cities_count), + game.info.top_cities_count); + page_conn(dest, _("Traveler's Report:"), header, buffer); } - page_conn(dest, _("Traveler's Report:"), - _("The Five Greatest Cities in the World!"), buffer); } /**********************************************************************//** @@ -1632,12 +1644,12 @@ void report_final_scores(struct conn_list *dest) /**********************************************************************//** This function pops up a non-modal message dialog on the player's desktop **************************************************************************/ -void page_conn(struct conn_list *dest, const char *caption, - const char *headline, const char *lines) { +static void page_conn(struct conn_list *dest, const char *caption, + const char *headline, const char *lines) +{ page_conn_etype(dest, caption, headline, lines, E_REPORT); } - /**********************************************************************//** This function pops up a non-modal message dialog on the player's desktop diff --git a/server/report.h b/server/report.h index 3837c7a8b7..173a86c830 100644 --- a/server/report.h +++ b/server/report.h @@ -1,4 +1,4 @@ -/********************************************************************** +/*********************************************************************** Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,6 +13,7 @@ #ifndef FC__REPORT_H #define FC__REPORT_H +/* uility */ #include "support.h" /* bool type */ struct connection; @@ -28,9 +29,6 @@ struct history_report char body[REPORT_BODYSIZE]; }; -void page_conn(struct conn_list *dest, const char *caption, - const char *headline, const char *lines); - void log_civ_score_init(void); void log_civ_score_free(void); void log_civ_score_now(void); @@ -38,7 +36,7 @@ void log_civ_score_now(void); void make_history_report(void); void send_current_history_report(struct conn_list *dest); void report_wonders_of_the_world(struct conn_list *dest); -void report_top_five_cities(struct conn_list *dest); +void report_top_cities(struct conn_list *dest); bool is_valid_demography(const char *demography, int *error); void report_demographics(struct connection *pconn); void report_achievements(struct connection *pconn); @@ -46,4 +44,4 @@ void report_final_scores(struct conn_list *dest); struct history_report *history_report_get(void); -#endif /* FC__REPORT_H */ +#endif /* FC__REPORT_H */ diff --git a/server/settings.c b/server/settings.c index 7bec8b3c30..74fe6f81bc 100644 --- a/server/settings.c +++ b/server/settings.c @@ -3030,6 +3030,16 @@ static struct setting settings[] = { "have clicked on \"Turn Done\"."), NULL, NULL, FALSE) + GEN_INT("top_cities", game.info.top_cities_count, + SSET_META, SSET_INTERNAL, SSET_SITUATIONAL, + ALLOW_NONE, ALLOW_BASIC, + N_("Number of cities in Top Cities report"), + N_("How many cities should the Top Cities report contain? " + "If this is zero, Top Cities report is not available " + "at all."), NULL, NULL, NULL, + GAME_MIN_TOP_CITIES_COUNT, GAME_MAX_TOP_CITIES_COUNT, + GAME_DEFAULT_TOP_CITIES_COUNT) + GEN_STRING("demography", game.server.demography, SSET_META, SSET_INTERNAL, SSET_SITUATIONAL, ALLOW_NONE, ALLOW_BASIC, diff --git a/server/srv_main.c b/server/srv_main.c index afafc65ae5..dc0e0781ed 100644 --- a/server/srv_main.c +++ b/server/srv_main.c @@ -1917,8 +1917,8 @@ void handle_report_req(struct connection *pconn, enum report_type type) case REPORT_WONDERS_OF_THE_WORLD: report_wonders_of_the_world(dest); return; - case REPORT_TOP_5_CITIES: - report_top_five_cities(dest); + case REPORT_TOP_CITIES: + report_top_cities(dest); return; case REPORT_DEMOGRAPHIC: report_demographics(pconn); -- 2.35.1