From e62b53e2756e7e884cb00ab4718c0ad420c7202b Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Wed, 10 Jan 2024 22:10:11 +0200
Subject: [PATCH 50/50] Add building flag "Indestructible"

See RM #168

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 common/fc_types.h                    | 19 +++++++++++--------
 data/alien/buildings.ruleset         |  1 +
 data/civ1/buildings.ruleset          |  1 +
 data/civ2/buildings.ruleset          |  1 +
 data/civ2civ3/buildings.ruleset      |  1 +
 data/classic/buildings.ruleset       |  1 +
 data/goldkeep/buildings.ruleset      |  1 +
 data/granularity/buildings.ruleset   |  1 +
 data/multiplayer/buildings.ruleset   |  1 +
 data/ruledit/comments-3.3.txt        |  1 +
 data/sandbox/buildings.ruleset       |  1 +
 data/stub/buildings.ruleset          |  1 +
 data/webperimental/buildings.ruleset |  1 +
 server/actiontools.c                 |  2 +-
 server/diplomats.c                   |  5 +++--
 server/unithand.c                    | 16 ++++++++++++++++
 16 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/common/fc_types.h b/common/fc_types.h
index cdae58dce1..0bf4df584d 100644
--- a/common/fc_types.h
+++ b/common/fc_types.h
@@ -663,14 +663,17 @@ const char *ai_level_name_update_cb(const char *old);
 /* Never destroyed by disasters */
 #define SPECENUM_VALUE3 IF_DISASTER_PROOF
 #define SPECENUM_VALUE3NAME "DisasterProof"
-#define SPECENUM_VALUE4 IF_USER_FLAG_1
-#define SPECENUM_VALUE5 IF_USER_FLAG_2
-#define SPECENUM_VALUE6 IF_USER_FLAG_3
-#define SPECENUM_VALUE7 IF_USER_FLAG_4
-#define SPECENUM_VALUE8 IF_USER_FLAG_5
-#define SPECENUM_VALUE9 IF_USER_FLAG_6
-#define SPECENUM_VALUE10 IF_USER_FLAG_7
-#define SPECENUM_VALUE11 IF_USER_FLAG_8
+/* Never destroyed by a surgical strike */
+#define SPECENUM_VALUE4 IF_INDESTRUCTIBLE
+#define SPECENUM_VALUE4NAME "Indestructible"
+#define SPECENUM_VALUE5 IF_USER_FLAG_1
+#define SPECENUM_VALUE6 IF_USER_FLAG_2
+#define SPECENUM_VALUE7 IF_USER_FLAG_3
+#define SPECENUM_VALUE8 IF_USER_FLAG_4
+#define SPECENUM_VALUE9 IF_USER_FLAG_5
+#define SPECENUM_VALUE10 IF_USER_FLAG_6
+#define SPECENUM_VALUE11 IF_USER_FLAG_7
+#define SPECENUM_VALUE12 IF_USER_FLAG_8
 #define SPECENUM_COUNT IF_COUNT
 #define SPECENUM_NAMEOVERRIDE
 #define SPECENUM_BITVECTOR bv_impr_flags
diff --git a/data/alien/buildings.ruleset b/data/alien/buildings.ruleset
index 52e678ee0c..398cd22e24 100644
--- a/data/alien/buildings.ruleset
+++ b/data/alien/buildings.ruleset
@@ -76,6 +76,7 @@ format_version = 40
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/civ1/buildings.ruleset b/data/civ1/buildings.ruleset
index a5e662523d..9c70e6487b 100644
--- a/data/civ1/buildings.ruleset
+++ b/data/civ1/buildings.ruleset
@@ -74,6 +74,7 @@ building_flags =
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/civ2/buildings.ruleset b/data/civ2/buildings.ruleset
index f93b4aa260..a1652ad632 100644
--- a/data/civ2/buildings.ruleset
+++ b/data/civ2/buildings.ruleset
@@ -76,6 +76,7 @@ building_flags =
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/civ2civ3/buildings.ruleset b/data/civ2civ3/buildings.ruleset
index 73a80d72a8..b99497980d 100644
--- a/data/civ2civ3/buildings.ruleset
+++ b/data/civ2civ3/buildings.ruleset
@@ -76,6 +76,7 @@ building_flags =
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/classic/buildings.ruleset b/data/classic/buildings.ruleset
index 266bd1440e..cd73ae2d2c 100644
--- a/data/classic/buildings.ruleset
+++ b/data/classic/buildings.ruleset
@@ -76,6 +76,7 @@ building_flags =
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/goldkeep/buildings.ruleset b/data/goldkeep/buildings.ruleset
index be4874881c..ff77aa6136 100644
--- a/data/goldkeep/buildings.ruleset
+++ b/data/goldkeep/buildings.ruleset
@@ -78,6 +78,7 @@ building_flags =
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/granularity/buildings.ruleset b/data/granularity/buildings.ruleset
index 4b6adb3755..e791972c6a 100644
--- a/data/granularity/buildings.ruleset
+++ b/data/granularity/buildings.ruleset
@@ -75,6 +75,7 @@ format_version = 40
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/multiplayer/buildings.ruleset b/data/multiplayer/buildings.ruleset
index fbfcb190d5..b534508edf 100644
--- a/data/multiplayer/buildings.ruleset
+++ b/data/multiplayer/buildings.ruleset
@@ -75,6 +75,7 @@ building_flags =
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/ruledit/comments-3.3.txt b/data/ruledit/comments-3.3.txt
index 4d16968e15..4066c19a3c 100644
--- a/data/ruledit/comments-3.3.txt
+++ b/data/ruledit/comments-3.3.txt
@@ -68,6 +68,7 @@ buildings = "\
 ; \"DisasterProof\"    = Disasters never destroy this building. Is meaningful\n\
 ;                      only for genus \"Improvement\" buildings as others are\n\
 ;                      automatically disaster proof.\n\
+; \"Indestructible\"   = Surgical strike can never destroy this building.\n\
 ;\n\
 ; */ <-- avoid gettext warnings\n\
 "
diff --git a/data/sandbox/buildings.ruleset b/data/sandbox/buildings.ruleset
index a6ebfedc49..3417b1e4f3 100644
--- a/data/sandbox/buildings.ruleset
+++ b/data/sandbox/buildings.ruleset
@@ -76,6 +76,7 @@ building_flags =
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/stub/buildings.ruleset b/data/stub/buildings.ruleset
index acf63c0a83..9c8446017c 100644
--- a/data/stub/buildings.ruleset
+++ b/data/stub/buildings.ruleset
@@ -66,6 +66,7 @@ format_version = 40
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/data/webperimental/buildings.ruleset b/data/webperimental/buildings.ruleset
index ce1cb17451..1597358f50 100644
--- a/data/webperimental/buildings.ruleset
+++ b/data/webperimental/buildings.ruleset
@@ -76,6 +76,7 @@ building_flags =
 ; "DisasterProof"    = Disasters never destroy this building. Is meaningful
 ;                      only for genus "Improvement" buildings as others are
 ;                      automatically disaster proof.
+; "Indestructible"   = Surgical strike can never destroy this building.
 ;
 ; */ <-- avoid gettext warnings
 
diff --git a/server/actiontools.c b/server/actiontools.c
index 4d3e68bfd4..66599b4fec 100644
--- a/server/actiontools.c
+++ b/server/actiontools.c
@@ -1190,5 +1190,5 @@ bool action_failed_dice_roll(const struct player *act_player,
                                    paction);
 
   /* Roll the dice. */
-  return fc_rand (100) >= odds;
+  return fc_rand(100) >= odds;
 }
diff --git a/server/diplomats.c b/server/diplomats.c
index 49c7d3793d..9dbcc9153a 100644
--- a/server/diplomats.c
+++ b/server/diplomats.c
@@ -449,13 +449,14 @@ void spy_send_sabotage_list(struct connection *pc, struct unit *pdiplomat,
 
     plrcity = map_get_player_city(city_tile(pcity), unit_owner(pdiplomat));
 
-    if (!plrcity) {
+    if (plrcity == nullptr) {
       /* Must know city to remember visible buildings. */
       return;
     }
 
     improvement_iterate(ptarget) {
-      if (BV_ISSET(plrcity->improvements, improvement_index(ptarget))) {
+      if (BV_ISSET(plrcity->improvements, improvement_index(ptarget))
+          && !improvement_has_flag(ptarget, IF_INDESTRUCTIBLE)) {
         BV_SET(packet.improvements, improvement_index(ptarget));
       }
     } improvement_iterate_end;
diff --git a/server/unithand.c b/server/unithand.c
index 579588796a..959f99804f 100644
--- a/server/unithand.c
+++ b/server/unithand.c
@@ -5455,6 +5455,22 @@ static bool do_unit_strike_city_building(struct player *act_player,
     return FALSE;
   }
 
+  if (improvement_has_flag(tgt_bld, IF_INDESTRUCTIBLE)) {
+    /* Notify the player. */
+    notify_player(act_player, tgt_tile,
+                  E_UNIT_ACTION_ACTOR_FAILURE, ftc_server,
+                  _("Your %s cannot do %s to %s in %s."),
+                  unit_link(act_unit),
+                  action_name_translation(paction),
+                  improvement_name_translation(tgt_bld),
+                  city_link(tgt_city));
+
+    /* Punish the player for blindly attacking a building. */
+    act_unit->moves_left = MAX(0, act_unit->moves_left - SINGLE_MOVE);
+
+    return FALSE;
+  }
+
   act_utype = unit_type_get(act_unit);
 
   /* Destroy the building. */
-- 
2.43.0

