From 7e8032a02977b92d8fc5707992c91894869cda36 Mon Sep 17 00:00:00 2001
From: John Robertson <jro@advops.com>
Date: Thu, 11 Dec 2025 09:36:12 -0700
Subject: [PATCH] embellish city name for potential disband, and the existance
 of airports and recycle centers

 Case I: Identify cities being disbanded.
  After taking over the cities of another player, especially an AI player,
  there is a need to prune the cities that are too close together.

  During the game, dialog lists of city names allow the player to avoid
  sending/building resources in cities designated to be disbanded.

 Case II: GoTo city that has an airport.  This is assisted by attributing
 the city name with an 'airport' character.

 Case III: show pollution risk cities that already has a Recycle Center
 improvement built.

 For large cities, the pollution threat exists even when the city has a
  recycle center building improvement.  Save time from the city list page
  to address only those cities that need the recycle center improvement.

 Case IV: changing the city name (e.g. prefix 'x' for cities being disbanded)
  causes future cities to reuse previously used city names, causing confusion.

---
 client/cityrepdata.c          |  2 +-
 client/gui-gtk-3.22/citydlg.c | 13 +++++++------
 client/gui-gtk-4.0/citydlg.c  | 13 +++++++------
 client/gui-gtk-5.0/citydlg.c  | 12 ++++++------
 client/gui-qt/citydlg.cpp     | 10 +++++-----
 client/gui-sdl2/citydlg.c     |  2 +-
 client/gui-sdl2/cityrep.c     |  2 +-
 client/gui-sdl3/citydlg.c     |  2 +-
 client/mapview_common.c       |  2 +-
 common/city.c                 | 35 +++++++++++++++++++++++++++++++++++
 common/city.h                 |  1 +
 11 files changed, 66 insertions(+), 28 deletions(-)

diff --git a/client/cityrepdata.c b/client/cityrepdata.c
index 09d57cbe76..82b4fec841 100644
--- a/client/cityrepdata.c
+++ b/client/cityrepdata.c
@@ -56,7 +56,7 @@ static const char *cr_entry_cityname(const struct city *pcity,
   /* We used to truncate the name to 14 bytes.  This should not be needed
    * in any modern GUI library and may give an invalid string if a
    * multibyte character is clipped. */
-  return city_name_get(pcity);
+  return city_name_getx(pcity);
 }
 
 /********************************************************************//**
diff --git a/client/gui-gtk-3.22/citydlg.c b/client/gui-gtk-3.22/citydlg.c
index b113ac9449..729e0c9e87 100644
--- a/client/gui-gtk-3.22/citydlg.c
+++ b/client/gui-gtk-3.22/citydlg.c
@@ -1669,7 +1669,8 @@ static struct city_dialog *create_city_dialog(struct city *pcity)
                                  canvas_width, canvas_height);
 
   pdialog->shell = gtk_dialog_new();
-  gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pcity));
+  gtk_window_set_title(GTK_WINDOW(pdialog->shell),
+                      city_name_getx(pcity));
   setup_dialog(pdialog->shell, toplevel);
   gtk_window_set_role(GTK_WINDOW(pdialog->shell), "city");
 
@@ -1835,28 +1836,28 @@ static void city_dialog_update_title(struct city_dialog *pdialog)
   if (city_unhappy(pdialog->pcity)) {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - DISORDER"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   } else if (city_celebrating(pdialog->pcity)) {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - celebrating"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   } else if (city_happy(pdialog->pcity)) {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - happy"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   } else {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   }
 
   now = gtk_label_get_text(GTK_LABEL(pdialog->name_label));
   if (strcmp(now, buf) != 0) {
-    gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pdialog->pcity));
+    gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_getx(pdialog->pcity));
     gtk_label_set_markup(GTK_LABEL(pdialog->name_label), buf);
   }
 
diff --git a/client/gui-gtk-4.0/citydlg.c b/client/gui-gtk-4.0/citydlg.c
index b83adadf21..2905285389 100644
--- a/client/gui-gtk-4.0/citydlg.c
+++ b/client/gui-gtk-4.0/citydlg.c
@@ -1587,7 +1587,8 @@ static struct city_dialog *create_city_dialog(struct city *pcity)
                                  canvas_width, canvas_height);
 
   pdialog->shell = gtk_dialog_new();
-  gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pcity));
+  gtk_window_set_title(GTK_WINDOW(pdialog->shell),
+                      city_name_getx(pcity));
   setup_dialog(pdialog->shell, toplevel);
 
   g_signal_connect(pdialog->shell, "destroy",
@@ -1751,28 +1752,28 @@ static void city_dialog_update_title(struct city_dialog *pdialog)
   if (city_unhappy(pdialog->pcity)) {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - DISORDER"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   } else if (city_celebrating(pdialog->pcity)) {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - celebrating"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   } else if (city_happy(pdialog->pcity)) {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - happy"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   } else {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   }
 
   now = gtk_label_get_text(GTK_LABEL(pdialog->name_label));
   if (strcmp(now, buf) != 0) {
-    gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pdialog->pcity));
+    gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_getx(pdialog->pcity));
     gtk_label_set_markup(GTK_LABEL(pdialog->name_label), buf);
   }
 
diff --git a/client/gui-gtk-5.0/citydlg.c b/client/gui-gtk-5.0/citydlg.c
index 452bceaaeb..ca355f8845 100644
--- a/client/gui-gtk-5.0/citydlg.c
+++ b/client/gui-gtk-5.0/citydlg.c
@@ -1876,7 +1876,7 @@ static struct city_dialog *create_city_dialog(struct city *pcity)
                                  canvas_width, canvas_height);
 
   pdialog->shell = gtk_dialog_new();
-  gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pcity));
+  gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_getx(pcity));
   setup_dialog(pdialog->shell, toplevel);
 
   g_signal_connect(pdialog->shell, "destroy",
@@ -2040,28 +2040,28 @@ static void city_dialog_update_title(struct city_dialog *pdialog)
   if (city_unhappy(pdialog->pcity)) {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - DISORDER"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   } else if (city_celebrating(pdialog->pcity)) {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - celebrating"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   } else if (city_happy(pdialog->pcity)) {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens - happy"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   } else {
     /* TRANS: city dialog title */
     buf = g_strdup_printf(_("<b>%s</b> - %s citizens"),
-                          city_name_get(pdialog->pcity),
+                          city_name_getx(pdialog->pcity),
                           population_to_text(city_population(pdialog->pcity)));
   }
 
   now = gtk_label_get_text(GTK_LABEL(pdialog->name_label));
   if (strcmp(now, buf) != 0) {
-    gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_get(pdialog->pcity));
+    gtk_window_set_title(GTK_WINDOW(pdialog->shell), city_name_getx(pdialog->pcity));
     gtk_label_set_markup(GTK_LABEL(pdialog->name_label), buf);
   }
 
diff --git a/client/gui-qt/citydlg.cpp b/client/gui-qt/citydlg.cpp
index b2c6d5a6f7..9eb52d954a 100644
--- a/client/gui-qt/citydlg.cpp
+++ b/client/gui-qt/citydlg.cpp
@@ -3801,24 +3801,24 @@ void city_dialog::update_title()
   QString buf;
 
   // Defeat keyboard shortcut mnemonics
-  lcity_name->setText(QString(city_name_get(dlgcity))
+  lcity_name->setText(QString(city_name_getx(dlgcity))
                       .replace("&", "&&"));
 
   if (city_unhappy(dlgcity)) {
     // TRANS: city dialog title
-    buf = QString(_("%1 - %2 citizens - DISORDER")).arg(city_name_get(dlgcity),
+    buf = QString(_("%1 - %2 citizens - DISORDER")).arg(city_name_getx(dlgcity),
           population_to_text(city_population(dlgcity)));
   } else if (city_celebrating(dlgcity)) {
     // TRANS: city dialog title
-    buf = QString(_("%1 - %2 citizens - celebrating")).arg(city_name_get(dlgcity),
+    buf = QString(_("%1 - %2 citizens - celebrating")).arg(city_name_getx(dlgcity),
           population_to_text(city_population(dlgcity)));
   } else if (city_happy(dlgcity)) {
     // TRANS: city dialog title
-    buf = QString(_("%1 - %2 citizens - happy")).arg(city_name_get(dlgcity),
+    buf = QString(_("%1 - %2 citizens - happy")).arg(city_name_getx(dlgcity),
           population_to_text(city_population(dlgcity)));
   } else {
     // TRANS: city dialog title
-    buf = QString(_("%1 - %2 citizens")).arg(city_name_get(dlgcity),
+    buf = QString(_("%1 - %2 citizens")).arg(city_name_getx(dlgcity),
           population_to_text(city_population(dlgcity)));
   }
 
diff --git a/client/gui-sdl2/citydlg.c b/client/gui-sdl2/citydlg.c
index 85fbb9214b..4528a58e8b 100644
--- a/client/gui-sdl2/citydlg.c
+++ b/client/gui-sdl2/citydlg.c
@@ -3525,7 +3525,7 @@ static void rebuild_citydlg_title_str(struct widget *pwindow,
 
   fc_snprintf(cbuf, sizeof(cbuf),
               _("City of %s (Population %s citizens)"),
-              city_name_get(pcity),
+              city_name_getx(pcity),
               population_to_text(city_population(pcity)));
 
   if (city_unhappy(pcity)) {
diff --git a/client/gui-sdl2/cityrep.c b/client/gui-sdl2/cityrep.c
index ecc9db9b52..0459724b79 100644
--- a/client/gui-sdl2/cityrep.c
+++ b/client/gui-sdl2/cityrep.c
@@ -295,7 +295,7 @@ static void real_info_city_report_dialog_update(void)
   last = pbuf;
   count = 0;
   city_list_iterate(client.conn.playing->cities, pcity) {
-    pstr = create_utf8_from_char_fonto(city_name_get(pcity), FONTO_ATTENTION);
+    pstr = create_utf8_from_char_fonto(city_name_getx(pcity), FONTO_ATTENTION);
     pstr->style |= TTF_STYLE_BOLD;
     pbuf = create_iconlabel(NULL, pwindow->dst, pstr,
                             (WF_RESTORE_BACKGROUND | WF_SELECT_WITHOUT_BAR));
diff --git a/client/gui-sdl3/citydlg.c b/client/gui-sdl3/citydlg.c
index dc5f3cf957..b0d712fa58 100644
--- a/client/gui-sdl3/citydlg.c
+++ b/client/gui-sdl3/citydlg.c
@@ -3513,7 +3513,7 @@ static void rebuild_citydlg_title_str(struct widget *pwindow,
 
   fc_snprintf(cbuf, sizeof(cbuf),
               _("City of %s (Population %s citizens)"),
-              city_name_get(pcity),
+              city_name_getx(pcity),
               population_to_text(city_population(pcity)));
 
   if (city_unhappy(pcity)) {
diff --git a/client/mapview_common.c b/client/mapview_common.c
index c96dd70a77..30523ac447 100644
--- a/client/mapview_common.c
+++ b/client/mapview_common.c
@@ -3162,7 +3162,7 @@ void get_city_mapview_name_and_growth(struct city *pcity,
                                       enum color_std *growth_color,
                                       enum color_std *production_color)
 {
-  fc_strlcpy(name_buffer, city_name_get(pcity), name_buffer_len);
+  fc_strlcpy(name_buffer, city_name_getx(pcity), name_buffer_len);
 
   *production_color = COLOR_MAPVIEW_CITYTEXT;
   if (NULL == client.conn.playing
diff --git a/common/city.c b/common/city.c
index 4533336bfe..26a9d39027 100644
--- a/common/city.c
+++ b/common/city.c
@@ -1139,6 +1139,41 @@ const char *city_name_get(const struct city *pcity)
   return (pcity->name != NULL) ? pcity->name : "City missing a name";
 }
 
+/**********************************************************************//**
+  Return the name of the city, embellished for removeable, recyclable flags.
+**************************************************************************/
+const char *city_name_getx(const struct city *pcity)
+{
+  bool spacer = FALSE;
+  static char em_city_name[MAX_LEN_CITYNAME + 7];
+
+  em_city_name[0] = '\0';
+
+  if(is_city_option_set(pcity, CITYO_DISBAND)) {
+    sz_strlcat(em_city_name, "ₓ"); /* ₓ🞪⁻⁰… (alternatives)*/
+  }
+
+  sz_strlcat(em_city_name, city_name_get(pcity));
+
+  if (city_has_building(pcity, improvement_by_rule_name(_("Airport")))) {
+    if (!spacer) {
+      sz_strlcat(em_city_name, " ");
+      spacer = TRUE;
+    }
+    sz_strlcat(em_city_name, "🛧"); /* 🛧🛪 (alternatives)*/
+  }
+
+  if (city_has_building(pcity, improvement_by_rule_name(_("Recycling Center")))) {
+    if (!spacer) {
+      sz_strlcat(em_city_name, " ");
+      spacer = TRUE;
+    }
+    sz_strlcat(em_city_name, "♺"); /* ♺♻♳ (alternatives)*/
+  }
+
+  return em_city_name;
+}
+
 /**********************************************************************//**
   Set a new name for the city.
 **************************************************************************/
diff --git a/common/city.h b/common/city.h
index 04bcf5c7ae..283ffa412d 100644
--- a/common/city.h
+++ b/common/city.h
@@ -559,6 +559,7 @@ void set_city_production(struct city *pcity);
 /* Properties */
 
 const char *city_name_get(const struct city *pcity);
+const char *city_name_getx(const struct city *pcity);
 void city_name_set(struct city *pcity, const char *new_name);
 #define city_owner(_pcity_) (_pcity_)->owner
 #define city_tile(_pcity_) (_pcity_)->tile
-- 
2.43.0

