From 25f3d4f9759b25fd93287c20ddb546bef6a287ae Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Mon, 25 Dec 2023 13:08:54 +0200
Subject: [PATCH 11/11] Store activity triggering actions to savegame

See RM #77

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 server/savegame/savecompat.c | 164 +++++++++++++++++++++++++++++++++++
 server/savegame/savegame3.c  |  34 +++-----
 2 files changed, 177 insertions(+), 21 deletions(-)

diff --git a/server/savegame/savecompat.c b/server/savegame/savecompat.c
index fa7e3af70d..77e18ca7ba 100644
--- a/server/savegame/savecompat.c
+++ b/server/savegame/savecompat.c
@@ -2466,6 +2466,89 @@ static void compat_load_030300(struct loaddata *loading,
       free(savemod);
     }
   }
+
+  /* Add actions for unit activities */
+  if (format_class == SAVEGAME_3) {
+    loading->activities.size
+      = secfile_lookup_int_default(loading->file, 0,
+                                   "savefile.activities_size");
+    if (loading->activities.size) {
+      loading->activities.order
+        = secfile_lookup_str_vec(loading->file, &loading->activities.size,
+                                 "savefile.activities_vector");
+      sg_failure_ret(loading->activities.size != 0,
+                     "Failed to load activity order: %s",
+                     secfile_error());
+    }
+
+    loading->action.size = secfile_lookup_int_default(loading->file, 0,
+                                                      "savefile.action_size");
+
+    sg_failure_ret(loading->action.size > 0,
+                   "Failed to load action order: %s",
+                   secfile_error());
+
+    if (loading->action.size) {
+      const char **modname;
+      int j;
+
+      modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
+                                       "savefile.action_vector");
+
+      loading->action.order = fc_calloc(loading->action.size,
+                                        sizeof(*loading->action.order));
+
+      for (j = 0; j < loading->action.size; j++) {
+        struct action *real_action = action_by_rule_name(modname[j]);
+
+        if (real_action) {
+          loading->action.order[j] = real_action->id;
+        } else {
+          log_sg("Unknown action \'%s\'", modname[j]);
+          loading->action.order[j] = ACTION_NONE;
+        }
+      }
+
+      free(modname);
+    }
+
+    player_slots_iterate(pslot) {
+      int plrno = player_slot_index(pslot);
+      int nunits;
+      int unro;
+
+      if (secfile_section_lookup(loading->file, "player%d", plrno) == nullptr) {
+        continue;
+      }
+
+      nunits = secfile_lookup_int_default(loading->file, 0,
+                                          "player%d.nunits", plrno);
+
+      for (unro = 0; unro < nunits; unro++) {
+        int ei;
+        int i;
+        enum unit_activity activity;
+        enum gen_action act;
+
+        ei = secfile_lookup_int_default(loading->file, -1,
+                                        "player%d.u%d.activity", plrno, unro);
+
+        if (ei >= 0 && ei < loading->activities.size) {
+          activity = unit_activity_by_name(loading->activities.order[ei],
+                                           fc_strcasecmp);
+          act = activity_default_action(activity);
+
+          for (i = 0; i < loading->action.size; i++) {
+            if (act == loading->action.order[i]) {
+              secfile_insert_int(loading->file, i, "player%d.u%d.action",
+                                 plrno, unro);
+              break;
+            }
+          }
+        }
+      }
+    } player_slots_iterate_end;
+  }
 }
 
 /************************************************************************//**
@@ -3240,6 +3323,87 @@ static void compat_load_dev(struct loaddata *loading)
 
     secfile_insert_bool(loading->file, FALSE, "map.altitude");
 
+    /* Add actions for unit activities */
+    loading->activities.size
+      = secfile_lookup_int_default(loading->file, 0,
+                                   "savefile.activities_size");
+    if (loading->activities.size) {
+      loading->activities.order
+        = secfile_lookup_str_vec(loading->file, &loading->activities.size,
+                                 "savefile.activities_vector");
+      sg_failure_ret(loading->activities.size != 0,
+                     "Failed to load activity order: %s",
+                     secfile_error());
+    }
+
+    loading->action.size = secfile_lookup_int_default(loading->file, 0,
+                                                      "savefile.action_size");
+
+    sg_failure_ret(loading->action.size > 0,
+                   "Failed to load action order: %s",
+                   secfile_error());
+
+    if (loading->action.size) {
+      const char **modname;
+      int j;
+
+      modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
+                                       "savefile.action_vector");
+
+      loading->action.order = fc_calloc(loading->action.size,
+                                        sizeof(*loading->action.order));
+
+      for (j = 0; j < loading->action.size; j++) {
+        struct action *real_action = action_by_rule_name(modname[j]);
+
+        if (real_action) {
+          loading->action.order[j] = real_action->id;
+        } else {
+          log_sg("Unknown action \'%s\'", modname[j]);
+          loading->action.order[j] = ACTION_NONE;
+        }
+      }
+
+      free(modname);
+    }
+
+    player_slots_iterate(pslot) {
+      int plrno = player_slot_index(pslot);
+      int nunits;
+      int unro;
+
+      if (secfile_section_lookup(loading->file, "player%d", plrno) == nullptr) {
+        continue;
+      }
+
+      nunits = secfile_lookup_int_default(loading->file, 0,
+                                          "player%d.nunits", plrno);
+
+      for (unro = 0; unro < nunits; unro++) {
+        int ei;
+        int i;
+        enum unit_activity activity;
+        enum gen_action act;
+
+        ei = secfile_lookup_int_default(loading->file, -1,
+                                        "player%d.u%d.activity", plrno, unro);
+
+        if (ei >= 0 && ei < loading->activities.size) {
+          activity = unit_activity_by_name(loading->activities.order[ei],
+                                           fc_strcasecmp);
+          act = activity_default_action(activity);
+
+          for (i = 0; i < loading->action.size; i++) {
+            if (act == loading->action.order[i]) {
+              secfile_insert_int(loading->file, i, "player%d.u%d.action",
+                                 plrno, unro);
+              break;
+            }
+          }
+        }
+      }
+    } player_slots_iterate_end;
+
   } /* Version < 3.2.92 */
 
 #endif /* FREECIV_DEV_SAVE_COMPAT_3_3 */
diff --git a/server/savegame/savegame3.c b/server/savegame/savegame3.c
index 532cfcc1fe..a7f5f6f336 100644
--- a/server/savegame/savegame3.c
+++ b/server/savegame/savegame3.c
@@ -6131,6 +6131,7 @@ static bool sg_load_player_unit(struct loaddata *loading,
   int natnbr;
   int unconverted;
   const char *str;
+  enum gen_action action;
 
   sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->id, "%s.id",
                                      unitstr), FALSE, "%s", secfile_error());
@@ -6185,6 +6186,10 @@ static bool sg_load_player_unit(struct loaddata *loading,
                   "%s", secfile_error());
   activity = unit_activity_by_name(loading->activities.order[ei],
                                    fc_strcasecmp);
+  sg_warn_ret_val(secfile_lookup_int(loading->file, &ei,
+                                     "%s.action", unitstr), FALSE,
+                  "%s", secfile_error());
+  action = loading->action.order[ei];
 
   punit->server.birth_turn
     = secfile_lookup_int_default(loading->file, game.info.turn,
@@ -6199,22 +6204,16 @@ static bool sg_load_player_unit(struct loaddata *loading,
   if (extra_id != -2) {
     if (extra_id >= 0 && extra_id < loading->extra.size) {
       pextra = loading->extra.order[extra_id];
-      /* FIXME: Correct action from the savegame */
-      set_unit_activity_targeted(punit, activity, pextra,
-                                 activity_default_action(activity));
+      set_unit_activity_targeted(punit, activity, pextra, action);
     } else if (activity == ACTIVITY_IRRIGATE) {
       struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
                                                    EC_IRRIGATION,
                                                    unit_owner(punit),
                                                    punit);
       if (tgt != NULL) {
-        /* FIXME: Correct action from the savegame */
-        set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, tgt,
-                                   activity_default_action(ACTIVITY_IRRIGATE));
+        set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, tgt, action);
       } else {
-        /* FIXME: Correct action from the savegame */
-        set_unit_activity(punit, ACTIVITY_CULTIVATE,
-                          activity_default_action(ACTIVITY_CULTIVATE));
+        set_unit_activity(punit, ACTIVITY_CULTIVATE, action);
       }
     } else if (activity == ACTIVITY_MINE) {
       struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
@@ -6222,23 +6221,15 @@ static bool sg_load_player_unit(struct loaddata *loading,
                                                    unit_owner(punit),
                                                    punit);
       if (tgt != NULL) {
-        /* FIXME: Correct action from the savegame */
-        set_unit_activity_targeted(punit, ACTIVITY_MINE, tgt,
-                                   activity_default_action(ACTIVITY_MINE));
+        set_unit_activity_targeted(punit, ACTIVITY_MINE, tgt, action);
       } else {
-        /* FIXME: Correct action from the savegame */
-        set_unit_activity(punit, ACTIVITY_PLANT,
-                          activity_default_action(ACTIVITY_PLANT));
+        set_unit_activity(punit, ACTIVITY_PLANT, action);
       }
     } else {
-      /* FIXME: Correct action from the savegame */
-      set_unit_activity(punit, activity,
-                        activity_default_action(activity));
+      set_unit_activity(punit, activity, action);
     }
   } else {
-    /* FIXME: Correct action from the savegame */
-    set_unit_activity_targeted(punit, activity, NULL,
-                               activity_default_action(activity));
+    set_unit_activity_targeted(punit, activity, NULL, action);
   } /* activity_tgt == NULL */
 
   sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->activity_count,
@@ -6722,6 +6713,7 @@ static void sg_save_player_units(struct savedata *saving,
     secfile_insert_int(saving->file, punit->activity, "%s.activity", buf);
     secfile_insert_int(saving->file, punit->activity_count,
                        "%s.activity_count", buf);
+    secfile_insert_int(saving->file, punit->action, "%s.action", buf);
     if (punit->activity_target == NULL) {
       secfile_insert_int(saving->file, -1, "%s.activity_tgt", buf);
     } else {
-- 
2.43.0

