From 684240020194b329645d960752cc3c78bc8a3505 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 7 Jan 2023 12:17:34 +0200 Subject: [PATCH 51/51] Add building user flags support See osdn #45832 Signed-off-by: Marko Lindqvist --- client/packhand.c | 26 ++++++++++ common/fc_types.h | 12 +++++ common/game.c | 2 + common/improvement.c | 77 ++++++++++++++++++++++++++++ common/improvement.h | 7 +++ common/networking/packets.def | 6 +++ data/alien/buildings.ruleset | 12 +++++ data/civ1/buildings.ruleset | 12 +++++ data/civ2/buildings.ruleset | 12 +++++ data/civ2civ3/buildings.ruleset | 12 +++++ data/classic/buildings.ruleset | 12 +++++ data/goldkeep/buildings.ruleset | 12 +++++ data/granularity/buildings.ruleset | 12 +++++ data/multiplayer/buildings.ruleset | 12 +++++ data/sandbox/buildings.ruleset | 12 +++++ data/stub/buildings.ruleset | 12 +++++ data/webperimental/buildings.ruleset | 12 +++++ server/ruleset.c | 59 ++++++++++++++++++++- tools/ruleutil/rulesave.c | 16 ++++++ 19 files changed, 335 insertions(+), 2 deletions(-) diff --git a/client/packhand.c b/client/packhand.c index 36c48a9a84..f10dd09ef5 100644 --- a/client/packhand.c +++ b/client/packhand.c @@ -3891,6 +3891,32 @@ void handle_ruleset_building(const struct packet_ruleset_building *p) tileset_setup_impr_type(tileset, b); } +/************************************************************************//** + Packet ruleset_impr_flag handler. +****************************************************************************/ +void handle_ruleset_impr_flag(const struct packet_ruleset_impr_flag *p) +{ + const char *flagname; + const char *helptxt; + + fc_assert_ret_msg(p->id >= IF_USER_FLAG_1 && p->id <= IF_LAST_USER_FLAG, + "Bad user flag %d.", p->id); + + if (p->name[0] == '\0') { + flagname = NULL; + } else { + flagname = p->name; + } + + if (p->helptxt[0] == '\0') { + helptxt = NULL; + } else { + helptxt = p->helptxt; + } + + set_user_impr_flag_name(p->id, flagname, helptxt); +} + /************************************************************************//** Packet ruleset_multiplier handler. ****************************************************************************/ diff --git a/common/fc_types.h b/common/fc_types.h index bf66ffabbd..f52a506ab9 100644 --- a/common/fc_types.h +++ b/common/fc_types.h @@ -636,10 +636,22 @@ const char *ai_level_name_update_cb(const char *old); /* Never destroyed by disasters */ #define SPECENUM_VALUE3 IF_DISASTER_PROOF #define SPECENUM_VALUE3NAME "DisasterProof" +#define SPECENUM_VALUE4 IF_USER_FLAG_1 +#define SPECENUM_VALUE5 IF_USER_FLAG_2 +#define SPECENUM_VALUE6 IF_USER_FLAG_3 +#define SPECENUM_VALUE7 IF_USER_FLAG_4 +#define SPECENUM_VALUE8 IF_USER_FLAG_5 +#define SPECENUM_VALUE9 IF_USER_FLAG_6 +#define SPECENUM_VALUE10 IF_USER_FLAG_7 +#define SPECENUM_VALUE11 IF_USER_FLAG_8 #define SPECENUM_COUNT IF_COUNT +#define SPECENUM_NAMEOVERRIDE #define SPECENUM_BITVECTOR bv_impr_flags #include "specenum_gen.h" +#define IF_LAST_USER_FLAG IF_USER_FLAG_8 +#define MAX_NUM_USER_BUILDING_FLAGS (IF_LAST_USER_FLAG - IF_USER_FLAG_1 + 1) + /* A server setting + its value. */ typedef int ssetv; diff --git a/common/game.c b/common/game.c index 233caf3956..e3d7ebe51f 100644 --- a/common/game.c +++ b/common/game.c @@ -542,6 +542,7 @@ void game_ruleset_init(void) user_unit_type_flags_init(); user_terrain_flags_init(); user_extra_flags_init(); + user_impr_flags_init(); tech_classes_init(); user_tech_flags_init(); multipliers_init(); @@ -602,6 +603,7 @@ void game_ruleset_free(void) terrains_free(); user_tech_flags_free(); extra_flags_free(); + impr_flags_free(); user_terrain_flags_free(); ruleset_cache_free(); nation_sets_groups_free(); diff --git a/common/improvement.c b/common/improvement.c index 78c1cfde98..1810d72c01 100644 --- a/common/improvement.c +++ b/common/improvement.c @@ -40,6 +40,8 @@ The improvement_types array is now setup in: **************************************************************************/ static struct impr_type improvement_types[B_LAST]; +static struct user_flag user_impr_flags[MAX_NUM_USER_BUILDING_FLAGS]; + /**********************************************************************//** Initialize building structures. **************************************************************************/ @@ -1140,3 +1142,78 @@ const struct impr_type *improvement_replacement(const struct impr_type *pimprove return NULL; } + +/************************************************************************//** + Initialize user building flags. +****************************************************************************/ +void user_impr_flags_init(void) +{ + int i; + + for (i = 0; i < MAX_NUM_USER_BUILDING_FLAGS; i++) { + user_flag_init(&user_impr_flags[i]); + } +} + +/************************************************************************//** + Frees the memory associated with all building flags +****************************************************************************/ +void impr_flags_free(void) +{ + int i; + + for (i = 0; i < MAX_NUM_USER_BUILDING_FLAGS; i++) { + user_flag_free(&user_impr_flags[i]); + } +} + +/************************************************************************//** + Sets user defined name for building flag. +****************************************************************************/ +void set_user_impr_flag_name(enum impr_flag_id id, const char *name, + const char *helptxt) +{ + int bfid = id - IF_USER_FLAG_1; + + fc_assert_ret(id >= IF_USER_FLAG_1 && id <= IF_LAST_USER_FLAG); + + if (user_impr_flags[bfid].name != NULL) { + FC_FREE(user_impr_flags[bfid].name); + user_impr_flags[bfid].name = NULL; + } + + if (name && name[0] != '\0') { + user_impr_flags[bfid].name = fc_strdup(name); + } + + if (user_impr_flags[bfid].helptxt != NULL) { + free(user_impr_flags[bfid].helptxt); + user_impr_flags[bfid].helptxt = NULL; + } + + if (helptxt && helptxt[0] != '\0') { + user_impr_flags[bfid].helptxt = fc_strdup(helptxt); + } +} + +/************************************************************************//** + Building flag name callback, called from specenum code. +****************************************************************************/ +const char *impr_flag_id_name_cb(enum impr_flag_id flag) +{ + if (flag < IF_USER_FLAG_1 || flag > IF_LAST_USER_FLAG) { + return NULL; + } + + return user_impr_flags[flag - IF_USER_FLAG_1].name; +} + +/************************************************************************//** + Return the (untranslated) help text of the user building flag. +****************************************************************************/ +const char *impr_flag_helptxt(enum impr_flag_id id) +{ + fc_assert(id >= IF_USER_FLAG_1 && id <= IF_LAST_USER_FLAG); + + return user_impr_flags[id - IF_USER_FLAG_1].helptxt; +} diff --git a/common/improvement.h b/common/improvement.h index 8c9f848982..e56194804e 100644 --- a/common/improvement.h +++ b/common/improvement.h @@ -94,6 +94,13 @@ const char *improvement_name_translation(const struct impr_type *pimprove); bool improvement_has_flag(const struct impr_type *pimprove, enum impr_flag_id flag); +void user_impr_flags_init(void); +void impr_flags_free(void); +void set_user_impr_flag_name(enum impr_flag_id id, + const char *name, + const char *helptxt); +const char *impr_flag_helptxt(enum impr_flag_id id); + /* Ancillary routines */ int impr_build_shield_cost(const struct city *pcity, const struct impr_type *pimprove); diff --git a/common/networking/packets.def b/common/networking/packets.def index a83baa12b7..6474dc1e76 100644 --- a/common/networking/packets.def +++ b/common/networking/packets.def @@ -1667,6 +1667,12 @@ PACKET_RULESET_BUILDING = 150; sc, lsend STRVEC helptext[MAX_LEN_PACKET]; end +PACKET_RULESET_IMPR_FLAG = 20; sc, lsend + UINT8 id; + STRING name[MAX_LEN_NAME]; + STRING helptxt[MAX_LEN_PACKET]; +end + PACKET_RULESET_TERRAIN = 151; sc, lsend TERRAIN id; diff --git a/data/alien/buildings.ruleset b/data/alien/buildings.ruleset index 598df105fb..9555e8b622 100644 --- a/data/alien/buildings.ruleset +++ b/data/alien/buildings.ruleset @@ -16,6 +16,18 @@ description = "Alien World buildings data for Freeciv" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/data/civ1/buildings.ruleset b/data/civ1/buildings.ruleset index 9c0223a227..52bea956d0 100644 --- a/data/civ1/buildings.ruleset +++ b/data/civ1/buildings.ruleset @@ -15,6 +15,18 @@ description = "Civ1 buildings data for Freeciv (approximate)" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; Below: The individual buildings, one per section. ; (Buildings = City Improvements and Wonders) ; diff --git a/data/civ2/buildings.ruleset b/data/civ2/buildings.ruleset index 4afc4ecb09..277188984a 100644 --- a/data/civ2/buildings.ruleset +++ b/data/civ2/buildings.ruleset @@ -15,6 +15,18 @@ description = "Civ2 buildings data for Freeciv (incomplete)" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/data/civ2civ3/buildings.ruleset b/data/civ2civ3/buildings.ruleset index 9a1874a220..761651bca8 100644 --- a/data/civ2civ3/buildings.ruleset +++ b/data/civ2civ3/buildings.ruleset @@ -15,6 +15,18 @@ description = "Civ2Civ3 buildings data for Freeciv" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02 web-compatible" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/data/classic/buildings.ruleset b/data/classic/buildings.ruleset index a82d1f61c2..b19ca9ab65 100644 --- a/data/classic/buildings.ruleset +++ b/data/classic/buildings.ruleset @@ -15,6 +15,18 @@ description = "Classic buildings data for Freeciv" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02 web-compatible" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/data/goldkeep/buildings.ruleset b/data/goldkeep/buildings.ruleset index 9312663084..6975885a30 100644 --- a/data/goldkeep/buildings.ruleset +++ b/data/goldkeep/buildings.ruleset @@ -17,6 +17,18 @@ description = "Goldkeep buildings data for Freeciv" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/data/granularity/buildings.ruleset b/data/granularity/buildings.ruleset index 4f04ed50a7..33d2e4d0af 100644 --- a/data/granularity/buildings.ruleset +++ b/data/granularity/buildings.ruleset @@ -15,6 +15,18 @@ description = "Granularity buildings data for Freeciv" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/data/multiplayer/buildings.ruleset b/data/multiplayer/buildings.ruleset index 580989c356..e9a8924f6e 100644 --- a/data/multiplayer/buildings.ruleset +++ b/data/multiplayer/buildings.ruleset @@ -14,6 +14,18 @@ description = "Multiplayer buildings data for Freeciv" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02 web-compatible" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/data/sandbox/buildings.ruleset b/data/sandbox/buildings.ruleset index ea7a541f5b..798a262875 100644 --- a/data/sandbox/buildings.ruleset +++ b/data/sandbox/buildings.ruleset @@ -15,6 +15,18 @@ description = "Sandbox buildings data for Freeciv" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/data/stub/buildings.ruleset b/data/stub/buildings.ruleset index 9c85e9b2b5..d0592f1bb1 100644 --- a/data/stub/buildings.ruleset +++ b/data/stub/buildings.ruleset @@ -6,6 +6,18 @@ description = " buildings data for Freeciv" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/data/webperimental/buildings.ruleset b/data/webperimental/buildings.ruleset index 16a8500678..e42e41c140 100644 --- a/data/webperimental/buildings.ruleset +++ b/data/webperimental/buildings.ruleset @@ -15,6 +15,18 @@ description = "Experimental web-client buildings data for Freeciv" options = "+Freeciv-ruleset-3.2-Devel-2022.Feb.02 web-compatible" format_version = 30 +[control] + +; Names for custom building flags. There can be up to 8 of these. +; name = rule name; In some circumstances user may see this +; as part of some sentences, so try to make it descriptive +; and sensible. +; helptxt = displayed in the help for building types with this flag +; (optional) +;building_flags = +; { "name", "helptxt" +; } + ; /* <-- avoid gettext warnings ; ; Below: The individual buildings, one per section. diff --git a/server/ruleset.c b/server/ruleset.c index ad2cc5f5fd..5ef778138c 100644 --- a/server/ruleset.c +++ b/server/ruleset.c @@ -2666,6 +2666,7 @@ static bool load_building_names(struct section_file *file, int i, nval = 0; const char *filename = secfile_name(file); bool ok = TRUE; + const char *flag; if (!rscompat_check_cap_and_version(file, filename, compat)) { return FALSE; @@ -2703,6 +2704,34 @@ static bool load_building_names(struct section_file *file, } } + /* User building flag names */ + for (i = 0; + (flag = secfile_lookup_str_default(file, NULL, + "control.building_flags%d.name", + i)); + i++) { + const char *helptxt = secfile_lookup_str_default(file, NULL, + "control.building_flags%d.helptxt", i); + + if (impr_flag_id_by_name(flag, fc_strcasecmp) + != impr_flag_id_invalid()) { + ruleset_error(NULL, LOG_ERROR, + "\"%s\": Duplicate building flag name '%s'", + filename, flag); + ok = FALSE; + break; + } + if (i > MAX_NUM_USER_BUILDING_FLAGS) { + ruleset_error(NULL, LOG_ERROR, + "\"%s\": Too many user building flags!", + filename); + ok = FALSE; + break; + } + + set_user_impr_flag_name(IF_USER_FLAG_1 + i, flag, helptxt); + } + section_list_destroy(sec); return ok; @@ -8289,6 +8318,32 @@ static void send_ruleset_counters(struct conn_list *dest) **************************************************************************/ static void send_ruleset_buildings(struct conn_list *dest) { + int i; + + for (i = 0; i < MAX_NUM_USER_BUILDING_FLAGS; i++) { + struct packet_ruleset_impr_flag fpacket; + const char *flagname; + const char *helptxt; + + fpacket.id = i + IF_USER_FLAG_1; + + flagname = impr_flag_id_name(i + IF_USER_FLAG_1); + if (flagname == NULL) { + fpacket.name[0] = '\0'; + } else { + sz_strlcpy(fpacket.name, flagname); + } + + helptxt = impr_flag_helptxt(i + IF_USER_FLAG_1); + if (helptxt == NULL) { + fpacket.helptxt[0] = '\0'; + } else { + sz_strlcpy(fpacket.helptxt, helptxt); + } + + lsend_packet_ruleset_impr_flag(dest, &fpacket); + } + improvement_iterate(b) { struct packet_ruleset_building packet; int j; @@ -8454,11 +8509,10 @@ static void send_ruleset_resources(struct conn_list *dest) **************************************************************************/ static void send_ruleset_extras(struct conn_list *dest) { - struct packet_ruleset_extra packet; - struct packet_ruleset_extra_flag fpacket; int i; for (i = 0; i < MAX_NUM_USER_EXTRA_FLAGS; i++) { + struct packet_ruleset_extra_flag fpacket; const char *flagname; const char *helptxt; @@ -8482,6 +8536,7 @@ static void send_ruleset_extras(struct conn_list *dest) } extra_type_iterate(e) { + struct packet_ruleset_extra packet; int j; packet.id = extra_number(e); diff --git a/tools/ruleutil/rulesave.c b/tools/ruleutil/rulesave.c index 09084293d0..836d41b462 100644 --- a/tools/ruleutil/rulesave.c +++ b/tools/ruleutil/rulesave.c @@ -387,11 +387,27 @@ static bool save_buildings_ruleset(const char *filename, const char *name) { struct section_file *sfile = create_ruleset_file(name, "building"); int sect_idx; + int i; if (sfile == NULL) { return FALSE; } + for (i = 0; i < MAX_NUM_USER_BUILDING_FLAGS; i++) { + const char *flagname = impr_flag_id_name_cb(i + IF_USER_FLAG_1); + const char *helptxt = impr_flag_helptxt(i + IF_USER_FLAG_1); + + if (flagname != NULL) { + secfile_insert_str(sfile, flagname, "control.building_flags%d.name", i); + + /* Save the user flag help text even when it is undefined. That makes + * the formatting code happy. The resulting "" is ignored when the + * ruleset is loaded. */ + secfile_insert_str(sfile, helptxt, + "control.building_flags%d.helptxt", i); + } + } + comment_buildings(sfile); sect_idx = 0; -- 2.39.0