From 73e9c2f91ef03252b324ed1f7f28557cb0d82921 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C5=82awomir=20Lach?= <slawek@lach.art.pl>
Date: Wed, 5 Apr 2023 18:28:27 +0200
Subject: [PATCH] =?UTF-8?q?!OSDN=2047292:=20S=C5=82awomir=20Lach=20<slawek?=
 =?UTF-8?q?@lach.art.pl>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Unit counters should be handled properly.
No counters made yet.
It requires f5f35baa735c37dc328b8aace204c7f35735b995.

diff --git a/common/counters.c b/common/counters.c
index 341e6f519c..24db70ac55 100644
--- a/common/counters.c
+++ b/common/counters.c
@@ -32,6 +32,7 @@ static struct counter counters[MAX_COUNTERS];
 
 /* City counters array + related data */
 static struct counter *counters_city[MAX_COUNTERS];
+static struct counter *counters_unit[MAX_COUNTERS];
 static int number_city_counters;
 static int number_unit_counters;
 
@@ -68,6 +69,14 @@ int counters_get_city_counters_count(void)
   return number_city_counters;
 }
 
+/************************************************************************//**
+  Return number of unit counters.
+****************************************************************************/
+int counters_get_unit_counters_count(void)
+{
+  return number_unit_counters;
+}
+
 /************************************************************************//**
   Return number of counters.
 ****************************************************************************/
@@ -106,8 +115,9 @@ void attach_city_counter(struct counter *counter)
 ****************************************************************************/
 void attach_unit_counter(struct counter *counter)
 {
-  counter->index = number_unit_counters;
-  counter->ruledit_disabled = FALSE;
+  counters_unit[number_unit_counters] = counter;
+  counters_unit[number_unit_counters]->index = number_unit_counters;
+  counters_unit[number_unit_counters]->ruledit_disabled = FALSE;
   number_unit_counters++;
 }
 
@@ -199,7 +209,7 @@ struct counter *counter_by_index(int index, enum counter_target target)
     case CTGT_CITY:
       return counters_city[index];
     case CTGT_UNIT:
-      return NULL;
+      return counters_unit[index];
     case COUNTER_TARGET_LAST:
       return NULL;
   }
diff --git a/common/counters.h b/common/counters.h
index bef0115b9b..453922f171 100644
--- a/common/counters.h
+++ b/common/counters.h
@@ -51,6 +51,7 @@ struct counter *counter_by_translated_name(const char *name);
 int counter_index(const struct counter *pcount);
 struct counter *counter_by_index(int index, enum counter_target target);
 int counters_get_city_counters_count(void);
+int counters_get_unit_counters_count(void);
 int counters_get_count(void);
 void attach_city_counter(struct counter *counter);
 void attach_unit_counter(struct counter *counter);
@@ -65,6 +66,16 @@ void attach_unit_counter(struct counter *counter);
 #define city_counters_iterate_end } \
    }
 
+#define unit_counters_iterate(pcount) { \
+   int _i_##pcount; \
+   struct counter *pcount; \
+   int _ccounter_count_##pcount = counters_get_unit_counters_count(); \
+   for (_i_##pcount = 0; _i_##pcount < _ccounter_count_##pcount; _i_##pcount++) { \
+      pcount = counter_by_index(_i_##pcount, CTGT_UNIT);
+
+#define unit_counters_iterate_end } \
+   }
+
 #define counters_re_iterate(pcount) { \
    int _i_##pcount; \
    struct counter *pcount; \
diff --git a/common/unit.c b/common/unit.c
index 64585cb216..e2a04d626a 100644
--- a/common/unit.c
+++ b/common/unit.c
@@ -28,6 +28,7 @@
 #include "actions.h"
 #include "base.h"
 #include "city.h"
+#include "counters.h"
 #include "game.h"
 #include "log.h"
 #include "map.h"
@@ -1562,6 +1563,7 @@ struct unit *unit_virtual_create(struct player *pplayer, struct city *pcity,
 {
   /* Make sure that contents of unit structure are correctly initialized,
    * if you ever allocate it by some other mean than fc_calloc() */
+  int counter_count;
   struct unit *punit = fc_calloc(1, sizeof(*punit));
   int max_vet_lvl;
 
@@ -1652,6 +1654,18 @@ struct unit *unit_virtual_create(struct player *pplayer, struct city *pcity,
     punit->client.act_prob_cache = NULL;
   }
 
+  counter_count = counters_get_unit_counters_count();
+
+  punit->counter_values = NULL;
+  if (0 < counter_count) {
+
+    punit->counter_values = malloc(sizeof(*punit->counter_values) * counter_count);
+    while (counter_count--) {
+
+      punit->counter_values[counter_count] = counter_by_index(counter_count, CTGT_UNIT)->def;
+    }
+  }
+
   return punit;
 }
 
@@ -1690,6 +1704,11 @@ void unit_virtual_destroy(struct unit *punit)
     }
   }
 
+  if (NULL != punit->counter_values) {
+    FC_FREE(punit->counter_values);
+    punit->counter_values = NULL;
+  }
+
   if (--punit->refcount <= 0) {
     FC_FREE(punit);
   }
diff --git a/common/unit.h b/common/unit.h
index 87362abb74..8a9aab18e8 100644
--- a/common/unit.h
+++ b/common/unit.h
@@ -151,6 +151,8 @@ struct unit {
   int veteran;
   int fuel;
 
+  int *counter_values;
+
   struct tile *goto_tile; /* May be NULL. */
 
   enum unit_activity activity;
diff --git a/server/rscompat.c b/server/rscompat.c
index 15b1b7f439..6d815cd29b 100644
--- a/server/rscompat.c
+++ b/server/rscompat.c
@@ -27,6 +27,7 @@
 
 /* common */
 #include "actions.h"
+#include "counters.h"
 #include "effects.h"
 #include "fc_types.h"
 #include "game.h"
@@ -317,6 +318,22 @@ void rscompat_enablers_add_obligatory_hard_reqs(void)
   } action_iterate_end;
 }
 
+/**********************************************************************//**
+  Set some not-defined by ruleset authors counter fields.
+**************************************************************************/
+static void rscompat_set_counters_autorules(struct rscompat_info *info)
+{
+  int i;
+
+  if (info->version >= RSFORMAT_3_3) {
+    return;
+  }
+
+  for (i = 0; i < counters_get_count(); i++) {
+    counter_by_id(i)->target = CTGT_CITY;
+  }
+}
+
 /**********************************************************************//**
   Do compatibility things with names before they are referred to. Runs
   after names are loaded from the ruleset but before the ruleset objects
@@ -361,6 +378,8 @@ void rscompat_postprocess(struct rscompat_info *info)
    * compatibility post processing fulfills all hard action requirements. */
   rscompat_enablers_add_obligatory_hard_reqs();
 
+  rscompat_set_counters_autorules(info);
+
   /* The ruleset may need adjustments it didn't need before compatibility
    * post processing.
    *
diff --git a/server/ruleset.c b/server/ruleset.c
index 7a5741c592..6ff1a7db00 100644
--- a/server/ruleset.c
+++ b/server/ruleset.c
@@ -7479,21 +7479,53 @@ static bool load_ruleset_game(struct section_file *file, bool act,
 
         enum counter_target ct;
         enum counter_behaviour cb;
+        const char *counter_type;
         struct counter *pcount = counter_by_id(curr);
         const char *sec_name = section_name(section_list_get(sec, curr));
-        const char *counter_type = secfile_lookup_str_default(file, NULL,
-                                                              "%s.target",
-                                                              sec_name);;
+        struct entry *counter_type_entry = secfile_entry_lookup(file,
+                                                                "%s.target",
+                                                                sec_name);
 
-        ct = counter_target_by_name(counter_type,
-                                    fc_strcasecmp);
+        if (NULL != counter_type_entry) {
+          if (!entry_str_get(counter_type_entry,&counter_type)) {
+            ruleset_error(NULL, LOG_ERROR,
+                          "\"%s\" Unable to obtain one counter target."
+                          "Not string?",
+                          filename);
+            ok = FALSE;
+            break;
+          }
 
-        if (!counter_target_is_valid(ct)) {
-          ruleset_error(NULL, LOG_ERROR,
-                        "\"%s\" unknown counter target \"%s\".",
-                        filename, counter_type);
-          ok = FALSE;
-          break;
+          ct = counter_target_by_name(counter_type,
+                                      fc_strcasecmp);
+          if ((compat->version > RSFORMAT_3_2)) {
+            if (!counter_target_is_valid(ct)) {
+              ruleset_error(NULL, LOG_ERROR,
+                            "\"%s\" unknown counter target \"%s\".",
+                            filename, counter_type);
+              ok = FALSE;
+              break;
+            }
+          }
+          else if (CTGT_CITY != ct) {
+            ruleset_error(NULL, LOG_ERROR,
+                          "\"%s\" for ruleset in format 30, counter type"
+                          " must be set to city or should not been set."
+                          "Current value:  \"%s\".",
+                          filename, counter_type);
+            ok = FALSE;
+            break;
+          }
+        }
+        else {
+          if (compat->version > RSFORMAT_3_2) {
+            ruleset_error(NULL, LOG_ERROR,
+                          "\"%s\" Counter target not given.",
+                          filename);
+            ok = FALSE;
+            break;
+          }
+          ct = CTGT_CITY;
         }
 
         counter_type = secfile_lookup_str_default(file, NULL,
diff --git a/tools/ruleutil/rulesave.c b/tools/ruleutil/rulesave.c
index fc954c3d7a..3f79e622db 100644
--- a/tools/ruleutil/rulesave.c
+++ b/tools/ruleutil/rulesave.c
@@ -1805,6 +1805,7 @@ static bool save_game_ruleset(const char *filename, const char *name)
     save_default_int(sfile, pcounter->checkpoint, 0, path, "checkpoint");
 
     secfile_insert_str(sfile, counter_behaviour_name(pcounter->type), "%s.type", path);
+    secfile_insert_str(sfile, counter_target_name(pcounter->target), "%s.target", path);
 
   } counters_re_iterate_end;
 
-- 
2.40.1

