From 2a2f09b578a46b04cba425d5d283a57d45e552fb Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Sat, 24 May 2025 14:23:32 +0300
Subject: [PATCH 75/75] Turn Upkeep_Factor to Upkeep_Pct

Make the effect a percentage one, and rename accordingly.

See RM #1351

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 ai/default/daieffects.c             |  2 +-
 client/helpdata.c                   |  6 ++++--
 common/unittype.c                   |  2 +-
 doc/README.effects                  |  4 ++--
 gen_headers/enums/effects_enums.def |  2 +-
 server/ruleset/rscompat.c           | 22 +++++++++++++++++++---
 server/ruleset/rscompat.h           |  1 +
 server/ruleset/ruleload.c           |  4 ++++
 8 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/ai/default/daieffects.c b/ai/default/daieffects.c
index ab16eef1ba..aa3a5e8dca 100644
--- a/ai/default/daieffects.c
+++ b/ai/default/daieffects.c
@@ -587,7 +587,7 @@ adv_want dai_effect_value(struct player *pplayer,
   /* Currently not supported for building AI - wait for modpack users */
   case EFT_CITY_UNHAPPY_SIZE:
   case EFT_UNHAPPY_FACTOR:
-  case EFT_UPKEEP_FACTOR:
+  case EFT_UPKEEP_PCT:
   case EFT_UNIT_UPKEEP_FREE_PER_CITY:
   case EFT_CIVIL_WAR_CHANCE:
   case EFT_EMPIRE_SIZE_BASE:
diff --git a/client/helpdata.c b/client/helpdata.c
index 3ef7179c88..3651454a3d 100644
--- a/client/helpdata.c
+++ b/client/helpdata.c
@@ -4491,6 +4491,7 @@ void helptext_government(char *buf, size_t bufsz, struct player *pplayer,
        * is sufficient reason to list it in that gov's help.
        * Guard accesses to these with 'playerwide' or 'world_value_valid'. */
       int world_value = -999, net_value = -999;
+
       if (world_value_valid) {
         /* Get government-independent world value of effect if the extra
          * requirements were simple enough. */
@@ -4513,7 +4514,7 @@ void helptext_government(char *buf, size_t bufsz, struct player *pplayer,
          * output types. Generate lists for that. */
         bool harvested_only = TRUE; /* Consider only output types from fields */
 
-        if (peffect->type == EFT_UPKEEP_FACTOR
+        if (peffect->type == EFT_UPKEEP_PCT
             || peffect->type == EFT_UNIT_UPKEEP_FREE_PER_CITY
             || peffect->type == EFT_OUTPUT_BONUS
             || peffect->type == EFT_OUTPUT_BONUS_2) {
@@ -4611,7 +4612,7 @@ void helptext_government(char *buf, size_t bufsz, struct player *pplayer,
                        BULLET, peffect->value);
         }
         break;
-      case EFT_UPKEEP_FACTOR:
+      case EFT_UPKEEP_PCT:
         if (world_value_valid && !unittype) {
           if (net_value == 0) {
             if (output_type != O_LAST) {
@@ -4627,6 +4628,7 @@ void helptext_government(char *buf, size_t bufsz, struct player *pplayer,
             }
           } else if (net_value != world_value) {
             double ratio = (double)net_value / world_value;
+
             if (output_type != O_LAST) {
               cat_snprintf(buf, bufsz,
                            /* TRANS: %s is the output type, like 'shield'
diff --git a/common/unittype.c b/common/unittype.c
index 8df69de464..9c399ee442 100644
--- a/common/unittype.c
+++ b/common/unittype.c
@@ -190,7 +190,7 @@ int utype_upkeep_cost(const struct unit_type *ut, const struct unit *punit,
                                     .tile     = ptile,
                                     .city     = pcity
                                   },
-                                  NULL, EFT_UPKEEP_FACTOR);
+                                  NULL, EFT_UPKEEP_PCT) / 100;
 
   return val;
 }
diff --git a/doc/README.effects b/doc/README.effects
index 243a6ed468..920c01e8e4 100644
--- a/doc/README.effects
+++ b/doc/README.effects
@@ -814,8 +814,8 @@ Upgrade_Price_Pct
 Upgrade_Unit
     Upgrade amount obsolete units per turn.
 
-Upkeep_Factor
-    Multiply unit upkeep by amount.
+Upkeep_Pct
+    Unit upkeep is amount percents.
 
 Upkeep_Free
     Improvements with amount or less upkeep cost become free to upkeep (others
diff --git a/gen_headers/enums/effects_enums.def b/gen_headers/enums/effects_enums.def
index ae0ef63b82..24792824c0 100644
--- a/gen_headers/enums/effects_enums.def
+++ b/gen_headers/enums/effects_enums.def
@@ -83,7 +83,7 @@ values
   /* Multiply unhappy upkeep by this effect */
   UNHAPPY_FACTOR                    "Unhappy_Factor"
   /* Multiply upkeep by this effect */
-  UPKEEP_FACTOR                     "Upkeep_Factor"
+  UPKEEP_PCT                        "Upkeep_Pct"
   /* This many units are free from upkeep */
   UNIT_UPKEEP_FREE_PER_CITY         "Unit_Upkeep_Free_Per_City"
   OUTPUT_WASTE                      "Output_Waste"
diff --git a/server/ruleset/rscompat.c b/server/ruleset/rscompat.c
index 3217aa4ae0..f4fc528453 100644
--- a/server/ruleset/rscompat.c
+++ b/server/ruleset/rscompat.c
@@ -434,8 +434,12 @@ static bool effect_list_compat_cb(struct effect *peffect, void *data)
   struct rscompat_info *info = (struct rscompat_info *)data;
 
   if (info->version < RSFORMAT_3_4) {
-    if (!game.server.deprecated.homeless_gold_upkeep) {
-      if (peffect->type == EFT_UPKEEP_FACTOR) {
+    if (peffect->type == EFT_UPKEEP_PCT) {
+
+      /* From old Upkeep_Factor to new Upkeep_Pct */
+      peffect->value *= 100;
+
+      if (!game.server.deprecated.homeless_gold_upkeep) {
         bool gold_included = TRUE;
         bool only_gold = FALSE;
 
@@ -454,7 +458,7 @@ static bool effect_list_compat_cb(struct effect *peffect, void *data)
 
         if (gold_included) {
           if (!only_gold) {
-            struct effect *copy = effect_copy(peffect, EFT_UPKEEP_FACTOR);
+            struct effect *copy = effect_copy(peffect, EFT_UPKEEP_PCT);
 
             /* Split to gold-only and not-gold effects.
              * Make sure the gold-only is the one we currently handle
@@ -548,3 +552,15 @@ static int first_free_tech_user_flag(void)
   /* All tech user flags are taken. */
   return MAX_NUM_USER_TECH_FLAGS;
 }
+
+/**********************************************************************//**
+  Convert 3.3 effect name to a 3.4 one.
+**************************************************************************/
+const char *rscompat_effect_name_3_4(const char *old_name)
+{
+  if (!fc_strcasecmp("Upkeep_Factor", old_name)) {
+    return "Upkeep_Pct";
+  }
+
+  return old_name;
+}
diff --git a/server/ruleset/rscompat.h b/server/ruleset/rscompat.h
index 1e5862951b..e5b87e3491 100644
--- a/server/ruleset/rscompat.h
+++ b/server/ruleset/rscompat.h
@@ -56,6 +56,7 @@ struct requirement_vector *lookup_req_list(struct section_file *file,
                                            const char *rfor);
 
 /* Functions specific to 3.3 -> 3.4 transition */
+const char *rscompat_effect_name_3_4(const char *old_name);
 
 #ifdef __cplusplus
 }
diff --git a/server/ruleset/ruleload.c b/server/ruleset/ruleload.c
index 9eb85d9778..dfd2560da4 100644
--- a/server/ruleset/ruleload.c
+++ b/server/ruleset/ruleload.c
@@ -6146,6 +6146,10 @@ static bool load_ruleset_effects(struct section_file *file,
       break;
     }
 
+    if (compat->compat_mode && compat->version < RSFORMAT_3_4) {
+      type = rscompat_effect_name_3_4(type);
+    }
+
     eff = effect_type_by_name(type, fc_strcasecmp);
     if (!effect_type_is_valid(eff)) {
       ruleset_error(NULL, LOG_ERROR,
-- 
2.47.2

