From 25923762efff998d815f585b579d925095c43be6 Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Sat, 24 May 2025 14:23:32 +0300
Subject: [PATCH 67/73] 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 +-
 data/alien/effects.ruleset          |  8 ++++----
 data/civ1/effects.ruleset           | 16 ++++++++--------
 data/civ2/effects.ruleset           | 24 ++++++++++++------------
 data/civ2civ3/effects.ruleset       | 20 ++++++++++----------
 data/classic/effects.ruleset        | 16 ++++++++--------
 data/goldkeep/effects.ruleset       | 20 ++++++++++----------
 data/granularity/effects.ruleset    |  4 ++--
 data/multiplayer/effects.ruleset    | 20 ++++++++++----------
 data/sandbox/effects.ruleset        | 20 ++++++++++----------
 data/stub/effects.ruleset           |  4 ++--
 data/webperimental/effects.ruleset  | 20 ++++++++++----------
 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 ++++
 19 files changed, 119 insertions(+), 96 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 59a90dc666..333ef352c6 100644
--- a/client/helpdata.c
+++ b/client/helpdata.c
@@ -4441,6 +4441,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. */
@@ -4463,7 +4464,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) {
@@ -4561,7 +4562,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) {
@@ -4577,6 +4578,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/data/alien/effects.ruleset b/data/alien/effects.ruleset
index e56f602621..d9f02bad73 100644
--- a/data/alien/effects.ruleset
+++ b/data/alien/effects.ruleset
@@ -101,16 +101,16 @@ type    = "City_Vision_Radius_Sq"
 value   = 5
 
 [effect_base_unit_upkeep_not_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name", "range", "present"
       "OutputType", "Gold", "Local", FALSE
     }
 
 [effect_base_unit_upkeep_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",        "range"
       "OutputType", "Gold",        "Local"
diff --git a/data/civ1/effects.ruleset b/data/civ1/effects.ruleset
index df0a425c6b..575cc18808 100644
--- a/data/civ1/effects.ruleset
+++ b/data/civ1/effects.ruleset
@@ -269,16 +269,16 @@ type    = "Max_Rates"
 value   = 100
 
 [effect_base_unit_upkeep_not_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name", "range", "present"
       "OutputType", "Gold", "Local", FALSE
     }
 
 [effect_base_unit_upkeep_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",        "range"
       "OutputType", "Gold",        "Local"
@@ -286,8 +286,8 @@ reqs    =
     }
 
 [effect_republic_unit_upkeep]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range"
       "Gov", "Republic", "Player"
@@ -295,8 +295,8 @@ reqs    =
     }
 
 [effect_democracy_unit_upkeep]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range"
       "Gov", "Democracy", "Player"
diff --git a/data/civ2/effects.ruleset b/data/civ2/effects.ruleset
index ae555d7899..556268347a 100644
--- a/data/civ2/effects.ruleset
+++ b/data/civ2/effects.ruleset
@@ -419,16 +419,16 @@ reqs    =
     }
 
 [effect_base_unit_upkeep_not_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name", "range", "present"
       "OutputType", "Gold", "Local", FALSE
     }
 
 [effect_base_unit_upkeep_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",        "range"
       "OutputType", "Gold",        "Local"
@@ -436,8 +436,8 @@ reqs    =
     }
 
 [effect_communism_unit_upkeep]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range"
       "Gov", "Communism", "Player"
@@ -445,8 +445,8 @@ reqs    =
     }
 
 [effect_fundamentalism_unit_upkeep]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range"
       "Gov", "Fundamentalism", "Player"
@@ -462,8 +462,8 @@ reqs  =
     }
 
 [effect_republic_unit_upkeep]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range"
       "Gov", "Republic", "Player"
@@ -471,8 +471,8 @@ reqs    =
     }
 
 [effect_democracy_unit_upkeep]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range"
       "Gov", "Democracy", "Player"
diff --git a/data/civ2civ3/effects.ruleset b/data/civ2civ3/effects.ruleset
index e013c36b3b..c7488d03ea 100644
--- a/data/civ2civ3/effects.ruleset
+++ b/data/civ2civ3/effects.ruleset
@@ -46,8 +46,8 @@ format_version = 50
 
 ; "Away" "Novice" "Easy" "Normal" "Hard" "Cheating" "Experimental"
 [effect_ai_cheat_food]
-type    = "Upkeep_Factor"
-value   = -1
+type    = "Upkeep_Pct"
+value   = -100
 reqs    =
     { "type", "name", "range"
       "AI", "Cheating", "Player"
@@ -742,8 +742,8 @@ reqs    =
     }
 
 [effect_base_unit_upkeep_gold_1]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",           "range",  "present"
       "OutputType", "Gold",           "Local",  TRUE
@@ -761,8 +761,8 @@ reqs    =
 
 ; Additive with previous => x2 for Fundamentalism, Federation, Democracy
 [effect_base_unit_upkeep_gold_2]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",           "range",  "present"
       "OutputType", "Gold",           "Local",  TRUE
@@ -779,8 +779,8 @@ reqs    =
     }
 
 [effect_base_unit_upkeep_shield]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range", "present"
       "OutputType", "Shield", "Local", TRUE
@@ -796,8 +796,8 @@ reqs    =
     }
 
 [effect_base_unit_upkeep_food]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range"
       "OutputType", "Food", "Local"
diff --git a/data/classic/effects.ruleset b/data/classic/effects.ruleset
index 6c5699e6b5..1acc611b3e 100644
--- a/data/classic/effects.ruleset
+++ b/data/classic/effects.ruleset
@@ -341,16 +341,16 @@ reqs	=
     }
 
 [effect_base_unit_upkeep_not_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name", "range", "present"
       "OutputType", "Gold", "Local", FALSE
     }
 
 [effect_base_unit_upkeep_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",        "range"
       "OutputType", "Gold",        "Local"
@@ -358,8 +358,8 @@ reqs    =
     }
 
 [effect_republic_unit_upkeep]
-type    = "Upkeep_Factor"
-value	= 1
+type    = "Upkeep_Pct"
+value	= 100
 reqs   =
     { "type", "name", "range"
       "Gov", "Republic", "Player"
@@ -367,8 +367,8 @@ reqs   =
     }
 
 [effect_democracy_unit_upkeep]
-type    = "Upkeep_Factor"
-value	= 1
+type    = "Upkeep_Pct"
+value	= 100
 reqs   =
     { "type", "name", "range"
       "Gov", "Democracy", "Player"
diff --git a/data/goldkeep/effects.ruleset b/data/goldkeep/effects.ruleset
index b59b5cef16..d4d06677ea 100644
--- a/data/goldkeep/effects.ruleset
+++ b/data/goldkeep/effects.ruleset
@@ -401,16 +401,16 @@ reqs	=
     }
 
 [effect_base_unit_upkeep_not_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name", "range", "present"
       "OutputType", "Gold", "Local", FALSE
     }
 
 [effect_base_unit_upkeep_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",        "range"
       "OutputType", "Gold",        "Local"
@@ -418,18 +418,18 @@ reqs    =
     }
 
 [effect_republic_unit_upkeep]
-type    = "Upkeep_Factor"
-value	= 1
-reqs   =
+type    = "Upkeep_Pct"
+value   = 100
+reqs    =
     { "type", "name", "range"
       "Gov", "Republic", "Player"
       "OutputType", "Food", "Local"
     }
 
 [effect_democracy_unit_upkeep]
-type    = "Upkeep_Factor"
-value	= 1
-reqs   =
+type    = "Upkeep_Pct"
+value   = 100
+reqs    =
     { "type", "name", "range"
       "Gov", "Democracy", "Player"
       "OutputType", "Food", "Local"
diff --git a/data/granularity/effects.ruleset b/data/granularity/effects.ruleset
index f7c3550c8b..132869db2f 100644
--- a/data/granularity/effects.ruleset
+++ b/data/granularity/effects.ruleset
@@ -85,8 +85,8 @@ reqs    =
     }
 
 [effect_base_unit_upkeep]
-type	= "Upkeep_Factor"
-value	= 1
+type	= "Upkeep_Pct"
+value	= 100
 
 [effect_empire_size_base]
 type    = "Empire_Size_Base"
diff --git a/data/multiplayer/effects.ruleset b/data/multiplayer/effects.ruleset
index 3632ab2a41..0b082eeb3b 100644
--- a/data/multiplayer/effects.ruleset
+++ b/data/multiplayer/effects.ruleset
@@ -321,16 +321,16 @@ reqs	=
     }
 
 [effect_base_unit_upkeep_not_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name", "range", "present"
       "OutputType", "Gold", "Local", FALSE
     }
 
 [effect_base_unit_upkeep_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",        "range"
       "OutputType", "Gold",        "Local"
@@ -338,8 +338,8 @@ reqs    =
     }
 
 [effect_republic_unit_upkeep]
-type    = "Upkeep_Factor"
-value	= 1
+type    = "Upkeep_Pct"
+value	= 100
 reqs   =
     { "type", "name", "range"
       "Gov", "Republic", "Player"
@@ -347,8 +347,8 @@ reqs   =
     }
 
 [effect_democracy_unit_upkeep]
-type    = "Upkeep_Factor"
-value	= 1
+type    = "Upkeep_Pct"
+value	= 100
 reqs   =
     { "type", "name", "range"
       "Gov", "Democracy", "Player"
@@ -2225,8 +2225,8 @@ reqs    =
     }
 
 [effect_fundamentalism_unit_upkeep]
-type    = "Upkeep_Factor"
-value   = 2
+type    = "Upkeep_Pct"
+value   = 200
 reqs    =
     { "type", "name", "range"
       "Gov", "Fundamentalism", "Player"
diff --git a/data/sandbox/effects.ruleset b/data/sandbox/effects.ruleset
index af2b8b51aa..60ce793ce6 100644
--- a/data/sandbox/effects.ruleset
+++ b/data/sandbox/effects.ruleset
@@ -46,8 +46,8 @@ format_version = 50
 
 ; "Away" "Novice" "Easy" "Normal" "Hard" "Cheating" "Experimental"
 [effect_ai_cheat_food]
-type    = "Upkeep_Factor"
-value   = -1
+type    = "Upkeep_Pct"
+value   = -100
 reqs    =
     { "type", "name", "range"
       "AI", "Cheating", "Player"
@@ -833,8 +833,8 @@ reqs    =
     }
 
 [effect_base_unit_upkeep_gold_1]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",           "range",  "present"
       "OutputType", "Gold",           "Local",  TRUE
@@ -852,8 +852,8 @@ reqs    =
 
 ; Additive with previous => x2 for Fundamentalism, Federation, Democracy
 [effect_base_unit_upkeep_gold_2]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",           "range",  "present"
       "OutputType", "Gold",           "Local",  TRUE
@@ -870,8 +870,8 @@ reqs    =
     }
 
 [effect_base_unit_upkeep_shield]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range", "present"
       "OutputType", "Shield", "Local", TRUE
@@ -887,8 +887,8 @@ reqs    =
     }
 
 [effect_base_unit_upkeep_food]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type", "name", "range"
       "OutputType", "Food", "Local"
diff --git a/data/stub/effects.ruleset b/data/stub/effects.ruleset
index 3920f2d4d3..3797fed978 100644
--- a/data/stub/effects.ruleset
+++ b/data/stub/effects.ruleset
@@ -45,8 +45,8 @@ type    = "City_Vision_Radius_Sq"
 value   = 5
 
 [effect_base_unit_upkeep]
-type	= "Upkeep_Factor"
-value	= 1
+type	= "Upkeep_Pct"
+value	= 100
 
 [effect_empire_size_base]
 type    = "Empire_Size_Base"
diff --git a/data/webperimental/effects.ruleset b/data/webperimental/effects.ruleset
index f1fa951099..336b274586 100644
--- a/data/webperimental/effects.ruleset
+++ b/data/webperimental/effects.ruleset
@@ -341,16 +341,16 @@ reqs	=
     }
 
 [effect_base_unit_upkeep_not_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name", "range", "present"
       "OutputType", "Gold", "Local", FALSE
     }
 
 [effect_base_unit_upkeep_gold]
-type    = "Upkeep_Factor"
-value   = 1
+type    = "Upkeep_Pct"
+value   = 100
 reqs    =
     { "type",       "name",        "range"
       "OutputType", "Gold",        "Local"
@@ -358,18 +358,18 @@ reqs    =
     }
 
 [effect_republic_unit_upkeep]
-type    = "Upkeep_Factor"
-value	= 1
-reqs   =
+type    = "Upkeep_Pct"
+value   = 100
+reqs    =
     { "type", "name", "range"
       "Gov", "Republic", "Player"
       "OutputType", "Food", "Local"
     }
 
 [effect_democracy_unit_upkeep]
-type    = "Upkeep_Factor"
-value	= 1
-reqs   =
+type    = "Upkeep_Pct"
+value   = 100
+reqs    =
     { "type", "name", "range"
       "Gov", "Democracy", "Player"
       "OutputType", "Food", "Local"
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

