From f5f35baa735c37dc328b8aace204c7f35735b995 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C5=82awomir=20Lach?= <slawek@lach.art.pl>
Date: Tue, 28 Mar 2023 16:51:17 +0200
Subject: [PATCH 2/2] =?UTF-8?q?!OSDN=2047292:=20S=C5=82awomir=20Lach=20<sl?=
 =?UTF-8?q?awek@lach.art.pl>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

From now ruleset will load counter of unit target
No way to use it - just ensure it does not mess
anything.
---
 client/packhand.c     | 19 ++++++++++-----
 common/counters.c     | 27 ++++++++++++++++++++++
 common/counters.h     |  2 ++
 common/fc_types.h     | 10 +++++++-
 common/requirements.c | 23 +++++++++++++-----
 server/ruleset.c      | 54 +++++++++++++++++++++++++++++++++----------
 6 files changed, 110 insertions(+), 25 deletions(-)

diff --git a/client/packhand.c b/client/packhand.c
index a4713baa6e..a390ffdb8c 100644
--- a/client/packhand.c
+++ b/client/packhand.c
@@ -5539,7 +5539,7 @@ client.
 **************************************************************************/
 void handle_ruleset_counter(const struct packet_ruleset_counter *packet)
 {
-  int counter_count = counters_get_city_counters_count();
+  int counter_count = counters_get_count();
   struct counter *curr = counter_by_id(counter_count);
 
   names_set(&curr->name, NULL, packet->name, packet->rule_name);
@@ -5548,13 +5548,20 @@ void handle_ruleset_counter(const struct packet_ruleset_counter *packet)
   curr->target = packet->type;
   curr->def = packet->def;
 
-  if (!counter_behaviour_is_valid(curr->type)
-    || curr->target != CTGT_CITY) {
+  switch (curr->target) {
+    case CTGT_CITY:
+      if (!counter_behaviour_is_valid(curr->type)) {
 
-    return;
+        return;
+      }
+      attach_city_counter(curr);
+    break;
+    case CTGT_UNIT:
+      attach_unit_counter(curr);
+    break;
+    case COUNTER_TARGET_LAST:
+    break;
   }
-
-  attach_city_counter(curr);
 }
 
 /**********************************************************************//**
diff --git a/common/counters.c b/common/counters.c
index b18334009f..341e6f519c 100644
--- a/common/counters.c
+++ b/common/counters.c
@@ -33,6 +33,7 @@ static struct counter counters[MAX_COUNTERS];
 /* City counters array + related data */
 static struct counter *counters_city[MAX_COUNTERS];
 static int number_city_counters;
+static int number_unit_counters;
 
 /************************************************************************//**
   Initialize counters system
@@ -41,6 +42,7 @@ void counters_init(void)
 {
   game.control.num_counters = 0;
   number_city_counters = 0;
+  number_unit_counters = 0;
 }
 
 
@@ -55,6 +57,7 @@ void counters_free(void)
 
   game.control.num_counters = 0;
   number_city_counters = 0;
+  number_unit_counters = 0;
 }
 
 /************************************************************************//**
@@ -65,6 +68,14 @@ int counters_get_city_counters_count(void)
   return number_city_counters;
 }
 
+/************************************************************************//**
+  Return number of counters.
+****************************************************************************/
+int counters_get_count(void)
+{
+  return number_city_counters + number_unit_counters;
+}
+
 /************************************************************************//**
   Return counter by given id
 ****************************************************************************/
@@ -88,6 +99,18 @@ void attach_city_counter(struct counter *counter)
   number_city_counters++;
 }
 
+/************************************************************************//**
+  Attaching given counter type to array containing counter type
+  related to units. Counter must be present in array for
+  each counter in game, but we do not check this.
+****************************************************************************/
+void attach_unit_counter(struct counter *counter)
+{
+  counter->index = number_unit_counters;
+  counter->ruledit_disabled = FALSE;
+  number_unit_counters++;
+}
+
 /************************************************************************//**
     Return id of a given counter
 ****************************************************************************/
@@ -175,6 +198,10 @@ struct counter *counter_by_index(int index, enum counter_target target)
   {
     case CTGT_CITY:
       return counters_city[index];
+    case CTGT_UNIT:
+      return NULL;
+    case COUNTER_TARGET_LAST:
+      return NULL;
   }
 
   return NULL;
diff --git a/common/counters.h b/common/counters.h
index bf43e32b84..bef0115b9b 100644
--- a/common/counters.h
+++ b/common/counters.h
@@ -51,7 +51,9 @@ 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_count(void);
 void attach_city_counter(struct counter *counter);
+void attach_unit_counter(struct counter *counter);
 
 #define city_counters_iterate(pcount) { \
    int _i_##pcount; \
diff --git a/common/fc_types.h b/common/fc_types.h
index 39c9c83ce0..909f31d344 100644
--- a/common/fc_types.h
+++ b/common/fc_types.h
@@ -112,6 +112,7 @@ enum output_type_id {
 /* Counters related types. See common/counters.h */
 /* Used in the network protocol. */
 #define SPECENUM_NAME counter_behaviour
+#define SPECENUM_VALUE0 CB_VALUE_NONE
 #define SPECENUM_VALUE1 CB_CITY_OWNED_TURNS
 #define SPECENUM_VALUE1NAME "Owned"
 #define SPECENUM_VALUE2 CB_CITY_CELEBRATION_TURNS
@@ -123,7 +124,14 @@ enum output_type_id {
 #include "specenum_gen.h"
 
 /* Used in the network protocol. */
-enum counter_target { CTGT_CITY };
+#define SPECENUM_NAME counter_target
+#define SPECENUM_VALUE0 CTGT_CITY
+#define SPECENUM_VALUE0NAME "City"
+#define SPECENUM_VALUE1 CTGT_UNIT
+#define SPECENUM_VALUE1NAME "Unit"
+
+#define SPECENUM_COUNT COUNTER_TARGET_LAST
+#include "specenum_gen.h"
 
 /* Changing this enum will break savegame and network compatibility. */
 /* When changing this, also update the list of valid requirement "Activity"
diff --git a/common/requirements.c b/common/requirements.c
index 364a603f74..d0bfb5be23 100644
--- a/common/requirements.c
+++ b/common/requirements.c
@@ -1052,7 +1052,6 @@ struct requirement req_from_str(const char *type, const char *range,
       case VUT_MAXLATITUDE:
         req.range = REQ_RANGE_TILE;
         break;
-      case VUT_COUNTER:
       case VUT_MINSIZE:
       case VUT_MINCULTURE:
       case VUT_MINFOREIGNPCT:
@@ -1081,6 +1080,7 @@ struct requirement req_from_str(const char *type, const char *range,
       case VUT_WRAP:
       case VUT_MINTECHS:
       case VUT_SERVERSETTING:
+      case VUT_COUNTER:
         req.range = REQ_RANGE_WORLD;
         break;
       }
@@ -1237,7 +1237,8 @@ struct requirement req_from_str(const char *type, const char *range,
                  && req.range != REQ_RANGE_CITY);
       break;
     case VUT_COUNTER:
-      invalid = req.range != REQ_RANGE_CITY;
+      invalid = req.range != REQ_RANGE_CITY
+                && req.range != REQ_RANGE_LOCAL;
       break;
     case VUT_IMPROVEMENT:
       /* Valid ranges depend on the building genus (wonder/improvement),
@@ -4745,12 +4746,22 @@ is_counter_req_active(const struct req_context *context,
 
   count = req->source.value.counter;
 
-  if (NULL == context->city) {
-    return TRI_MAYBE;
-  }
-  return BOOL_TO_TRISTATE(count->checkpoint <=
+  switch (count->target) {
+    case CTGT_CITY:
+      if (NULL == context->city) {
+        return TRI_MAYBE;
+      }
+      return BOOL_TO_TRISTATE(count->checkpoint <=
                           context->city->counter_values[
                               counter_index(count)]);
+    break;
+    case CTGT_UNIT:
+      return TRI_MAYBE;
+    break;
+    case COUNTER_TARGET_LAST:
+    break;
+  }
+  return TRI_MAYBE;
 }
 
 /**********************************************************************//**
diff --git a/server/ruleset.c b/server/ruleset.c
index 80df66b92e..7a5741c592 100644
--- a/server/ruleset.c
+++ b/server/ruleset.c
@@ -7477,22 +7477,29 @@ static bool load_ruleset_game(struct section_file *file, bool act,
 
       for (curr = 0; curr < num; curr++) {
 
+        enum counter_target ct;
+        enum counter_behaviour cb;
         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.type",
-                                                              sec_name);
+                                                              "%s.target",
+                                                              sec_name);;
 
-        enum counter_behaviour cb = counter_behaviour_by_name(counter_type,
-                                        fc_strcasecmp);
-        if (!counter_behaviour_is_valid(cb)) {
+        ct = counter_target_by_name(counter_type,
+                                    fc_strcasecmp);
+
+        if (!counter_target_is_valid(ct)) {
           ruleset_error(NULL, LOG_ERROR,
-                        "\"%s\" unknown counter type \"%s\".",
+                        "\"%s\" unknown counter target \"%s\".",
                         filename, counter_type);
           ok = FALSE;
           break;
         }
 
+        counter_type = secfile_lookup_str_default(file, NULL,
+                                                  "%s.type",
+                                                  sec_name);
+
         if (!ruleset_load_names(&pcount->name, NULL, file, sec_name)) {
           ruleset_error(NULL, LOG_ERROR,
                         "\"%s\": Cannot load counter names",
@@ -7501,7 +7508,6 @@ static bool load_ruleset_game(struct section_file *file, bool act,
           break;
         }
 
-        pcount->type = cb;
         if (!secfile_lookup_int(file, &pcount->checkpoint,
                                 "%s.checkpoint", sec_name)) {
 
@@ -7512,12 +7518,32 @@ static bool load_ruleset_game(struct section_file *file, bool act,
           break;
         }
 
-        pcount->target = CTGT_CITY;
-        pcount->index = curr;
         pcount->def = secfile_lookup_int_default(file, 0,
                                                  "%s.def",
                                                  sec_name);
-        attach_city_counter(pcount);
+        pcount->target = ct;
+        switch (pcount->target) {
+          case CTGT_CITY:
+            cb = counter_behaviour_by_name(counter_type,
+                                           fc_strcasecmp);
+
+            if (!counter_behaviour_is_valid(cb)) {
+              ruleset_error(NULL, LOG_ERROR,
+                            "\"%s\" unknown counter type \"%s\".",
+                            filename, counter_type);
+              ok = FALSE;
+              break;
+            }
+            pcount->type = cb;
+            attach_city_counter(pcount);
+            break;
+          case CTGT_UNIT:
+            pcount->type = CB_VALUE_NONE;
+            attach_unit_counter(pcount);
+            break;
+          case COUNTER_TARGET_LAST:
+            break;
+        }
       }
     }
   }
@@ -8157,9 +8183,13 @@ Send the counters ruleset information  to the specified connections.
 **************************************************************************/
 static void send_ruleset_counters(struct conn_list *dest)
 {
-  city_counters_iterate(pcount) {
+  struct counter *pcount;
+  int i;
+
+  for (i = 0; i < game.control.num_counters; i++) {
     struct packet_ruleset_counter packet;
 
+    pcount = counter_by_id(i);
     sz_strlcpy(packet.name, untranslated_name(&pcount->name));
     sz_strlcpy(packet.rule_name, rule_name_get(&pcount->name));
     packet.checkpoint = pcount->checkpoint;
@@ -8168,7 +8198,7 @@ static void send_ruleset_counters(struct conn_list *dest)
     packet.def = pcount->def;
 
     lsend_packet_ruleset_counter(dest, &packet);
-  } city_counters_iterate_end;
+  }
 }
 
 /**********************************************************************//**
-- 
2.40.0

