From ced05585797d45074cd5e32d6ff82493775b5d37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C5=82awomir=20Lach?= <slawek@lach.art.pl>
Date: Sun, 17 Apr 2022 10:34:26 +0200
Subject: [PATCH] =?UTF-8?q?OSDN!44345=20S=C5=82awomir=20Lach=20<slawek@lac?=
 =?UTF-8?q?h.art.pl>=20Add=20ruleset=20(save/load)=20counters-related=20co?=
 =?UTF-8?q?de?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit


diff --git a/common/counters.c b/common/counters.c
index aa3f647c15..3ad331e482 100644
--- a/common/counters.c
+++ b/common/counters.c
@@ -25,7 +25,7 @@
 
 static struct counter counters[MAX_COUNTERS] =
 {
-  { (struct name_translation) NAME_INIT, CB_CITY_OWNED_TURNS, CTGT_CITY, 5, 0 }
+
 };
 
 static struct counter *counters_city[MAX_COUNTERS];
@@ -36,22 +36,7 @@ static int number_city_counters;
 ****************************************************************************/
 void counters_init(void)
 {
-  int i;
-
   number_city_counters = 0;
-
-  name_set(&counters[0].name, NULL, N_("?counter:Owned"));
-
-  for (i = 0; i < MAX_COUNTERS; i++) {
-
-    if (counters[i].type == CB_CITY_OWNED_TURNS) {
-      /* City counter type */
-      counters_city[number_city_counters] = &counters[i];
-      counters[i].index = number_city_counters;
-      counters[i].target = CTGT_CITY;
-      number_city_counters++;
-    }
-  }
 }
 
 
@@ -81,6 +66,17 @@ struct counter *counter_by_id(int id)
   return &counters[id];
 }
 
+/************************************************************************//**
+  Attaching given counter type to array containing counter type
+  related to cities. Counter must be present in array for
+  each counter in game, but we do not check this.
+****************************************************************************/
+void attach_city_counter(struct counter *counter)
+{
+  counters_city[number_city_counters] = counter;
+  number_city_counters++;
+}
+
 /************************************************************************//**
     Return id of a given counter
 ****************************************************************************/
diff --git a/common/counters.h b/common/counters.h
index 1848e9e9d2..394c1e1e83 100644
--- a/common/counters.h
+++ b/common/counters.h
@@ -58,6 +58,7 @@ struct counter *counter_by_translated_name(const char *name);
 int counter_index(struct counter *pcount);
 struct counter *counter_by_index(int index, enum counter_target target);
 int counters_get_city_counters_count(void);
+void attach_city_counter(struct counter *counter);
 
 #define city_counters_iterate(pcount) { \
    int _i_##pcount; \
diff --git a/server/ruleset.c b/server/ruleset.c
index e805d89321..fd03fd2e62 100644
--- a/server/ruleset.c
+++ b/server/ruleset.c
@@ -38,6 +38,7 @@
 #include "base.h"
 #include "capability.h"
 #include "city.h"
+#include "counters.h"
 #include "effects.h"
 #include "extras.h"
 #include "fc_types.h"
@@ -108,6 +109,7 @@
 #define ACHIEVEMENT_SECTION_PREFIX "achievement_"
 #define ACTION_ENABLER_SECTION_PREFIX "actionenabler_"
 #define MULTIPLIER_SECTION_PREFIX "multiplier_"
+#define COUNTER_SECTION_PREFIX "counter_"
 
 #define check_name(name) (check_strlen(name, MAX_LEN_NAME, NULL))
 #define check_cityname(name) (check_strlen(name, MAX_LEN_CITYNAME, NULL))
@@ -1410,6 +1412,39 @@ static bool load_game_names(struct section_file *file,
     section_list_destroy(sec);
   }
 
+  if (ok) {
+
+    sec = secfile_sections_by_name_prefix(file, COUNTER_SECTION_PREFIX);
+
+    nval = (NULL != sec ? section_list_size(sec) : 0);
+    if (nval > MAX_COUNTERS) {
+      size_t num = nval;
+
+      ruleset_error(LOG_ERROR,
+                    "\"%s\": Too many counters (" SIZE_T_PRINTF ", max  %d)",
+                    filename, num, MAX_COUNTERS);
+      ok = FALSE;
+    }
+
+    if (ok) {
+      int count_idx;
+
+      for (count_idx = 0; count_idx < nval; ++count_idx) {
+        struct counter *pcount = counter_by_id(count_idx);
+        const char *sec_name
+        = section_name(section_list_get(sec, counter_index(pcount)));
+
+        if (!ruleset_load_names(&pcount->name, NULL, file, sec_name)) {
+          ruleset_error(LOG_ERROR, "\"%s\": Cannot load counters names",
+                        filename);
+          ok = FALSE;
+          break;
+        }
+      }
+    }
+    section_list_destroy(sec);
+  }
+
   return ok;
 }
 
@@ -7560,6 +7595,57 @@ static bool load_ruleset_game(struct section_file *file, bool act,
     section_list_destroy(sec);
   }
 
+  if (ok) {
+    sec = secfile_sections_by_name_prefix(file, COUNTER_SECTION_PREFIX);
+
+    if (sec != NULL) {
+      int num = section_list_size(sec);
+      int curr;
+
+      for (curr = 0; curr < num; ++curr) {
+
+        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);
+
+        enum counter_behaviour cb = counter_behaviour_by_name(counter_type,
+                                        fc_strcasecmp);
+        if (!counter_behaviour_is_valid(cb)) {
+          ruleset_error(LOG_ERROR, "\"%s\" unknown counter type \"%s\".",
+                        filename, counter_type);
+          ok = FALSE;
+          break;
+        }
+
+        if (!ruleset_load_names(&pcount->name, NULL, file, sec_name)) {
+          ruleset_error(LOG_ERROR, "\"%s\": Cannot load counter names",
+                        filename);
+          ok = FALSE;
+          break;
+        }
+
+        pcount->type = cb;
+        if (!secfile_lookup_int(file, &pcount->checkpoint,
+                                "%s.checkpoint",sec_name)) {
+
+          ruleset_error(LOG_ERROR, "\"%s\": No checkpoint value",
+                        filename);
+          ok = FALSE;
+          break;
+        }
+
+        pcount->target = CTGT_CITY;
+        pcount->index = curr;
+        pcount->def = secfile_lookup_int_default(file, 0,
+                                                 "%s.def",
+                                                 sec_name);
+        attach_city_counter(pcount);
+      }
+    }
+  }
+
   /* secfile_check_unused() is not here, but only after also settings section
    * has been loaded. */
 
diff --git a/tools/ruleutil/rulesave.c b/tools/ruleutil/rulesave.c
index cd8b515173..16ed8214c6 100644
--- a/tools/ruleutil/rulesave.c
+++ b/tools/ruleutil/rulesave.c
@@ -21,6 +21,7 @@
 
 /* common */
 #include "achievements.h"
+#include "counters.h"
 #include "game.h"
 #include "government.h"
 #include "map.h"
@@ -1647,6 +1648,21 @@ static bool save_game_ruleset(const char *filename, const char *name)
                        "trade.goods_selection");
   }
 
+  sect_idx = 0;
+  city_counters_iterate(pcounter) {
+    char path[512];
+
+    fc_snprintf(path, sizeof(path), "counter_%d", sect_idx++);
+
+    save_name_translation(sfile, &(pcounter->name), path);
+
+    save_default_int(sfile, pcounter->def, 0, path,"default");
+    save_default_int(sfile, pcounter->checkpoint, 0, path,"checkpoint");
+
+    secfile_insert_str(sfile, counter_behaviour_name(pcounter->type), "%s.type", path);
+
+  } city_counters_iterate_end;
+
   /* Goods */
   comment_goods(sfile);
 
-- 
2.36.1

