From affe682027989908d2fb37a4c0b22ebc5f4e5e07 Mon Sep 17 00:00:00 2001 From: Dino Date: Tue, 6 Oct 2026 16:23:55 -0400 Subject: [PATCH] load_ruleset_units(): allow spec_type to be NULL if no specialist entry RM #2187 --- client/cityrepdata.c | 2 ++ client/helpdata.c | 3 ++- common/actres.c | 4 ++-- common/networking/packets.def | 2 +- common/specialist.c | 10 ++++++++++ server/ruleset/ruleload.c | 8 ++------ server/unithand.c | 4 ++-- tools/ruleutil/rulesave.c | 2 +- 8 files changed, 22 insertions(+), 13 deletions(-) diff --git a/client/cityrepdata.c b/client/cityrepdata.c index 66cd31d456..a016002440 100644 --- a/client/cityrepdata.c +++ b/client/cityrepdata.c @@ -264,6 +264,8 @@ static const char *cr_entry_specialist(const struct city *pcity, static char buf[8]; const struct specialist *sp = data; + fc_assert_ret_val(sp != nullptr, nullptr); + fc_snprintf(buf, sizeof(buf), "%2d", pcity->specialists[specialist_index(sp)]); diff --git a/client/helpdata.c b/client/helpdata.c index 3698f6f7b1..1a73d45225 100644 --- a/client/helpdata.c +++ b/client/helpdata.c @@ -2933,7 +2933,7 @@ char *helptext_unit(char *buf, size_t bufsz, struct player *pplayer, /* TRANS: * ... Great Artist(s) ... */ _(" %s adds a %s superspecialist to the city.\n"), BULLET, specialist_plural_translation(utype->spec_type)); - } else if (DEFAULT_SPECIALIST != specialist_index(utype->spec_type)) { + } else if (utype->spec_type != nullptr) { cat_snprintf(buf, bufsz, /* TRANS: * ... Scientists */ _(" %s adds to cities as %s.\n"), @@ -4375,6 +4375,7 @@ void helptext_specialist(char *buf, size_t bufsz, struct player *pplayer, { bool reqs = FALSE; + fc_assert_ret(nullptr != pspec); fc_assert_ret(NULL != buf && 0 < bufsz); buf[0] = '\0'; diff --git a/common/actres.c b/common/actres.c index ff8b69f8b4..efcddf1c26 100644 --- a/common/actres.c +++ b/common/actres.c @@ -1046,8 +1046,8 @@ enum fc_tristate actres_possible(const struct civ_map *nmap, return TRI_NO; } - sid = specialist_index(unit_type_get(actor->unit)->spec_type); - if (DEFAULT_SPECIALIST != sid) { + if (unit_type_get(actor->unit)->spec_type != nullptr) { + sid = specialist_index(unit_type_get(actor->unit)->spec_type); if (!city_can_use_specialist(target->city, sid)) { /* Respect specialist reqs */ /* Potential info leak about if they are fulfilled */ diff --git a/common/networking/packets.def b/common/networking/packets.def index 9dbd9cb2cb..3c408e413f 100644 --- a/common/networking/packets.def +++ b/common/networking/packets.def @@ -1423,7 +1423,7 @@ PACKET_RULESET_UNIT = 140; sc, lsend UINT8 unit_class_id; UINT16 build_cost; UINT8 pop_cost; - UINT8 spectype_id; + SINT8 spectype_id; UINT8 attack_strength; UINT8 defense_strength; MOVEFRAGS move_rate; diff --git a/common/specialist.c b/common/specialist.c index 7260b6e3fd..5a3be1a9cd 100644 --- a/common/specialist.c +++ b/common/specialist.c @@ -156,6 +156,8 @@ struct specialist *specialist_by_translated_name(const char *name) **************************************************************************/ const char *specialist_rule_name(const struct specialist *sp) { + fc_assert_ret_val(sp != nullptr, nullptr); + return rule_name_get(&sp->name); } @@ -165,6 +167,8 @@ const char *specialist_rule_name(const struct specialist *sp) **************************************************************************/ const char *specialist_plural_translation(const struct specialist *sp) { + fc_assert_ret_val(sp != nullptr, nullptr); + return name_translation_get(&sp->name); } @@ -207,6 +211,9 @@ bool is_normal_specialist_id(Specialist_type_id sp) **************************************************************************/ bool is_super_specialist(const struct specialist *sp) { + if (sp == nullptr) { + return FALSE; + } return is_super_specialist_id(specialist_index(sp)); } @@ -216,6 +223,9 @@ bool is_super_specialist(const struct specialist *sp) **************************************************************************/ bool is_normal_specialist(const struct specialist *sp) { + if (sp == nullptr) { + return FALSE; + } return is_normal_specialist_id(specialist_index(sp)); } diff --git a/server/ruleset/ruleload.c b/server/ruleset/ruleload.c index fca376740f..eb062bd5d2 100644 --- a/server/ruleset/ruleload.c +++ b/server/ruleset/ruleload.c @@ -2440,11 +2440,7 @@ static bool load_ruleset_units(struct section_file *file, ok = FALSE; } } else { - /* Specialists must have been processed before */ - fc_assert_action(DEFAULT_SPECIALIST >= 0 - && specialist_by_number(DEFAULT_SPECIALIST), - ok = FALSE; break); - u->spec_type = specialist_by_number(DEFAULT_SPECIALIST); + u->spec_type = nullptr; } sval = secfile_lookup_str_default(file, transp_def_type_name(TDT_ALIGHT), @@ -8292,7 +8288,7 @@ static void send_ruleset_units(struct conn_list *dest) packet.unit_class_id = uclass_number(utype_class(u)); packet.build_cost = u->build_cost; packet.pop_cost = u->pop_cost; - packet.spectype_id = specialist_index(u->spec_type); + packet.spectype_id = u->spec_type ? specialist_index(u->spec_type) : -1; packet.attack_strength = u->attack_strength; packet.defense_strength = u->defense_strength; packet.move_rate = u->move_rate; diff --git a/server/unithand.c b/server/unithand.c index 07d0ccee34..1539bd5449 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -4346,13 +4346,13 @@ static bool city_build(struct player *pplayer, struct unit *punit, } act_utype = unit_type_get(punit); - sid = specialist_index(act_utype->spec_type); nationality = unit_nationality(punit); create_city(pplayer, ptile, name, nationality); size = act_utype->city_size; pcity = tile_city(ptile); /* A callback may destroy or replace it any time */ - if (nullptr != pcity) { + if (nullptr != pcity && nullptr != act_utype->spec_type) { + sid = specialist_index(act_utype->spec_type); if (is_super_specialist_id(sid) && pcity->specialists[sid] < MAX_CITY_SIZE) { pcity->specialists[sid]++; } diff --git a/tools/ruleutil/rulesave.c b/tools/ruleutil/rulesave.c index 0b95d8e4f0..1e9e840167 100644 --- a/tools/ruleutil/rulesave.c +++ b/tools/ruleutil/rulesave.c @@ -3397,7 +3397,7 @@ static bool save_units_ruleset(const char *filename, const char *name) secfile_insert_int(sfile, put->build_cost, "%s.build_cost", path); secfile_insert_int(sfile, put->pop_cost, "%s.pop_cost", path); - if (DEFAULT_SPECIALIST < 0 || DEFAULT_SPECIALIST != specialist_index(put->spec_type)) { + if (DEFAULT_SPECIALIST < 0 || (nullptr != put->spec_type)) { secfile_insert_str(sfile, specialist_rule_name(put->spec_type), "%s.specialist", path); } -- 2.31.0