From aa526b7be3ecdac11640884b12d5a53fddb67cda Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Mon, 8 Dec 2025 03:01:17 +0200
Subject: [PATCH 44/44] Rework extra (dis)appearance notifications

- Notify only if the tile is seen. This is a rule change.
  Previously player got "rumors" about all extra
  (dis)appearances in their empire.
- Handle also borders-disabled case by considering
  owner of the closest city, if within 7 tiles,
  owner of the tile.
- If the tile is not owned, but extras on it are owned,
  notify extra owner.

Reported by Dean Brown

See RM #1737

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 server/srv_main.c | 49 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 8 deletions(-)

diff --git a/server/srv_main.c b/server/srv_main.c
index 2daba2cf1b..9dac45af65 100644
--- a/server/srv_main.c
+++ b/server/srv_main.c
@@ -1751,14 +1751,31 @@ static void end_turn(void)
       if (tile_has_extra(ptile, pextra)
           && fc_rand(10000) < pextra->disappearance_chance
           && can_extra_disappear(pextra, ptile)) {
+        struct player *owner = tile_owner(ptile);
+
         tile_extra_rm_apply(ptile, pextra);
 
         update_tile_knowledge(ptile);
 
-        if (tile_owner(ptile) != nullptr) {
-          /* TODO: Should notify players nearby even when borders disabled,
-           *       like in case of barbarian uprising */
-          notify_player(tile_owner(ptile), ptile,
+        if (owner == nullptr) {
+          owner = extra_owner(ptile);
+
+          if (owner == nullptr && game.info.borders == BORDERS_DISABLED) {
+            /* In case of disabled borders, consider owner of the closest
+             * city, if within 7 tiles, owner of the ilte. */
+            iterate_outward(&(wld.map), ptile, 7, ctile) {
+              struct city *pcity = tile_city(ctile);
+
+              if (pcity != nullptr) {
+                owner = city_owner(pcity);
+                break;
+              }
+            } iterate_outward_end;
+          }
+        }
+
+        if (owner != nullptr && tile_is_seen(ptile, owner)) {
+          notify_player(owner, ptile,
                         E_SPONTANEOUS_EXTRA, ftc_server,
                         /* TRANS: Small Fish disappears from (32, 72). */
                         _("%s disappears from %s."),
@@ -1778,15 +1795,31 @@ static void end_turn(void)
       if (!tile_has_extra(ptile, pextra)
           && fc_rand(10000) < pextra->appearance_chance
           && can_extra_appear(pextra, ptile)) {
+        struct player *owner = tile_owner(ptile);
 
         tile_extra_apply(ptile, pextra);
 
         update_tile_knowledge(ptile);
 
-        if (tile_owner(ptile) != nullptr) {
-          /* TODO: Should notify players nearby even when borders disabled,
-           *       like in case of barbarian uprising */
-          notify_player(tile_owner(ptile), ptile,
+        if (owner == nullptr) {
+          owner = extra_owner(ptile);
+
+          if (owner == nullptr && game.info.borders == BORDERS_DISABLED) {
+            /* In case of disabled borders, consider owner of the closest
+             * city, if within 7 tiles, owner of the ilte. */
+            iterate_outward(&(wld.map), ptile, 7, ctile) {
+              struct city *pcity = tile_city(ctile);
+
+              if (pcity != nullptr) {
+                owner = city_owner(pcity);
+                break;
+              }
+            } iterate_outward_end;
+          }
+        }
+
+        if (owner != nullptr && tile_is_seen(ptile, owner)) {
+          notify_player(owner, ptile,
                         E_SPONTANEOUS_EXTRA, ftc_server,
                         /* TRANS: Small Fish appears to (32, 72). */
                         _("%s appears to %s."),
-- 
2.51.0

