Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2003:
[Freeciv-Dev] rewrite of upgrade wrapper code (PR#6735)
Home

[Freeciv-Dev] rewrite of upgrade wrapper code (PR#6735)

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: brett.albertson@xxxxxxxxxxxx, rt-guest@xxxxxxxxxxx
Subject: [Freeciv-Dev] rewrite of upgrade wrapper code (PR#6735)
From: "Jason Short" <jdorje@xxxxxxxxxxxxxx>
Date: Sun, 21 Dec 2003 18:03:07 -0800
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=6735 >

Here is the actual patch.  See the previous RT discussion for explanation.

Raimar: I disagree about the split of need_city/need_gold.  If this is 
ever generalized in future it will be no problem to change this code. 
However I am dubious that this will happen, and in the meantime the 
extra parameter gives the function unneeded complexity IMO.

Untested.

jason

Index: client/gui-gtk/citydlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/citydlg.c,v
retrieving revision 1.174
diff -u -r1.174 citydlg.c
--- client/gui-gtk/citydlg.c    2003/11/28 17:37:19     1.174
+++ client/gui-gtk/citydlg.c    2003/12/22 02:02:07
@@ -2688,48 +2688,25 @@
 *****************************************************************/
 static void unit_upgrade_callback(gpointer data)
 {
-  struct unit *punit;
+  struct unit *punit = player_find_unit_by_id(game.player_ptr, (size_t) data);
   char buf[512];
-  int ut1, ut2;
-  int value;
 
-  if ((punit = player_find_unit_by_id(game.player_ptr, (size_t) data))) {
-    ut1 = punit->type;
-    ut2 = can_upgrade_unittype(game.player_ptr, ut1);
+  if (!punit) {
+    return;
+  }
 
-    if (ut2 == -1) {
-      /* this shouldn't generally happen, but it is conceivable */
-      my_snprintf(buf, sizeof(buf),
-                 _("Sorry: cannot upgrade %s."), unit_types[ut1].name);
-      popup_message_dialog(top_vbox,
-                          _("Upgrade Unit!"), buf,
-                          dummy_close_callback, NULL, 
-                          _("Darn"), NULL, 0, NULL);
-    } else {
-      value = unit_upgrade_price(game.player_ptr, ut1, ut2);
-
-      if (game.player_ptr->economic.gold >= value) {
-       my_snprintf(buf, sizeof(buf), _("Upgrade %s to %s for %d gold?\n"
-                                       "Treasury contains %d gold."),
-                   unit_types[ut1].name, unit_types[ut2].name,
-                   value, game.player_ptr->economic.gold);
-       popup_message_dialog(top_vbox,
-                            _("Upgrade Obsolete Units"), buf,
-                            dummy_close_callback, NULL,
-                            _("_Yes"), unit_upgrade_callback_yes,
-                            GINT_TO_POINTER(punit->id), _("_No"),
-                            NULL, 0, NULL);
-      } else {
-       my_snprintf(buf, sizeof(buf),
-                   _("Upgrading %s to %s costs %d gold.\n"
-                     "Treasury contains %d gold."), unit_types[ut1].name,
-                   unit_types[ut2].name, value,
-                   game.player_ptr->economic.gold);
-       popup_message_dialog(top_vbox,_("Upgrade Unit!"),buf,
-                            dummy_close_callback, NULL, 
-                            _("Darn"), NULL, 0, NULL);
-      }
-    }
+  if (get_unit_upgrade_info(buf, sizeof(buf), punit) == UR_OK) {
+    popup_message_dialog(top_vbox,
+                        _("Upgrade Obsolete Units"), buf,
+                        dummy_close_callback, NULL,
+                        _("_Yes"), unit_upgrade_callback_yes,
+                        GINT_TO_POINTER(punit->id), _("_No"),
+                        NULL, 0, NULL);
+  } else {
+    popup_message_dialog(top_vbox,
+                        _("Upgrade Unit!"), buf,
+                        dummy_close_callback, NULL,
+                        _("Darn"), NULL, 0, NULL);
   }
 }
 
Index: client/gui-gtk-2.0/citydlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/citydlg.c,v
retrieving revision 1.67
diff -u -r1.67 citydlg.c
--- client/gui-gtk-2.0/citydlg.c        2003/11/28 17:37:20     1.67
+++ client/gui-gtk-2.0/citydlg.c        2003/12/22 02:02:07
@@ -2206,71 +2206,41 @@
 *****************************************************************/
 static void unit_upgrade_callback(GtkWidget *w, gpointer data)
 {
-  struct unit *punit;
-  int ut1, ut2;
-  int value;
+  struct unit *punit = player_find_unit_by_id(game.player_ptr,
+                                             (size_t) data);
   GtkWidget *shell;
+  char buf[512];
 
-  if ((punit = player_find_unit_by_id(game.player_ptr, (size_t) data))) {
-    ut1 = punit->type;
-    ut2 = can_upgrade_unittype(game.player_ptr, ut1);
-
-    if (ut2 == -1) {
-      /* this shouldn't generally happen, but it is conceivable */
-      shell = gtk_message_dialog_new(NULL,
-        0,
-        GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
-        _("Sorry: cannot upgrade %s."), unit_types[ut1].name);
-
-      gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Unit!"));
-      if (dialogs_on_top) {
-       gtk_window_set_transient_for(GTK_WINDOW(shell),
-                                    GTK_WINDOW(toplevel));
-      }
-      g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy),
-        NULL);
-      gtk_window_present(GTK_WINDOW(shell));
-    } else {
-      value = unit_upgrade_price(game.player_ptr, ut1, ut2);
-
-      if (game.player_ptr->economic.gold >= value) {
-        shell = gtk_message_dialog_new(NULL,
-              GTK_DIALOG_MODAL,
-              GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
-              _("Upgrade %s to %s for %d gold?\n"
-                "Treasury contains %d gold."),
-              unit_types[ut1].name, unit_types[ut2].name,
-              value, game.player_ptr->economic.gold);
-        gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Obsolete Units"));
-       if (dialogs_on_top) {
-         gtk_window_set_transient_for(GTK_WINDOW(shell),
-                                      GTK_WINDOW(toplevel));
-       }
-        gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_YES);
-
-        if (gtk_dialog_run(GTK_DIALOG(shell)) == GTK_RESPONSE_YES) {
-          request_unit_upgrade(punit);
-        }
-        gtk_widget_destroy(shell);
-      } else {
-        shell = gtk_message_dialog_new(NULL,
-          0,
-          GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
-          _("Upgrading %s to %s costs %d gold.\n"
-            "Treasury contains %d gold."),
-          unit_types[ut1].name, unit_types[ut2].name,
-          value, game.player_ptr->economic.gold);
+  if (!punit) {
+    return;
+  }
+
+  if (get_unit_upgrade_info(buf, sizeof(buf), punit) == UR_OK) {
+    shell = gtk_message_dialog_new(NULL, 0,
+                                  GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, buf);
+    gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Unit!"));
+    if (dialogs_on_top) {
+      gtk_window_set_transient_for(GTK_WINDOW(shell),
+                                  GTK_WINDOW(toplevel));
+    }
+    g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy),
+                    NULL);
+    gtk_window_present(GTK_WINDOW(shell));
+  } else {
+    shell = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
+                                  GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+                                  buf);
+    gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Obsolete Units"));
+    if (dialogs_on_top) {
+      gtk_window_set_transient_for(GTK_WINDOW(shell),
+                                  GTK_WINDOW(toplevel));
+    }
+    gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_YES);
 
-        gtk_window_set_title(GTK_WINDOW(shell), _("Upgrade Unit!"));
-       if (dialogs_on_top) {
-         gtk_window_set_transient_for(GTK_WINDOW(shell),
-                                      GTK_WINDOW(toplevel));
-       }
-        g_signal_connect(shell, "response", G_CALLBACK(gtk_widget_destroy),
-          NULL);
-        gtk_window_present(GTK_WINDOW(shell));
-      }
+    if (gtk_dialog_run(GTK_DIALOG(shell)) == GTK_RESPONSE_YES) {
+      request_unit_upgrade(punit);
     }
+    gtk_widget_destroy(shell);
   }
 }
 
Index: client/gui-win32/citydlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/citydlg.c,v
retrieving revision 1.66
diff -u -r1.66 citydlg.c
--- client/gui-win32/citydlg.c  2003/12/08 06:34:37     1.66
+++ client/gui-win32/citydlg.c  2003/12/22 02:02:08
@@ -1523,52 +1523,29 @@
 *****************************************************************/       
 static void upgrade_callback(HWND w, void * data)
 {
-  struct unit *punit;
+  struct unit *punit = player_find_unit_by_id(game.player_ptr,
+                                             (size_t) data);
   char buf[512];
-  int ut1,ut2;
-  int value;
- 
-  if((punit=player_find_unit_by_id(game.player_ptr, (size_t)data))) {
-    ut1=punit->type;
-    /* printf("upgrade_callback for %s\n", unit_types[ut1].name); */
- 
-    ut2=can_upgrade_unittype(game.player_ptr,ut1);
- 
-    if (ut2==-1) {
-      /* this shouldn't generally happen, but it is conceivable */
-      my_snprintf(buf, sizeof(buf),
-                  _("Sorry: cannot upgrade %s."), unit_types[ut1].name);
-      popup_message_dialog(NULL, /*"upgradenodialog"*/_("Upgrade Unit!"), buf,
-                           _("Darn"), unitupgrade_callback_no, 0,
-                           NULL);
-    } else {
-      value=unit_upgrade_price(game.player_ptr, ut1, ut2);
- 
-      if(game.player_ptr->economic.gold>=value) {
-        my_snprintf(buf, sizeof(buf), _("Upgrade %s to %s for %d gold?\n"
-               "Treasury contains %d gold."),
-               unit_types[ut1].name, unit_types[ut2].name,
-               value, game.player_ptr->economic.gold);
-        popup_message_dialog(NULL,
-                             /*"upgradedialog"*/_("Upgrade Obsolete Units"), 
buf,
-                             _("_Yes"),
-                               unitupgrade_callback_yes, (void *)(punit->id),
-                             _("_No"),
-                               unitupgrade_callback_no, 0,
-                             NULL);
-      } else {
-        my_snprintf(buf, sizeof(buf), _("Upgrading %s to %s costs %d gold.\n"
-               "Treasury contains %d gold."),
-               unit_types[ut1].name, unit_types[ut2].name,
-               value, game.player_ptr->economic.gold);
-        popup_message_dialog(NULL,
-                             /*"upgradenodialog"*/_("Upgrade Unit!"), buf,
-                             _("Darn"), unitupgrade_callback_no, 0,
-                             NULL);
-      }
-    }
-    destroy_message_dialog(w);
+
+  if (!punit) {
+    return;
   }
+
+  if (get_unit_upgrade_info(buf, sizeof(buf), punit) == UR_OK) {
+    popup_message_dialog(NULL,
+                        _("Upgrade Obsolete Units"), buf,
+                        _("_Yes"),
+                        unitupgrade_callback_yes, (void *)(punit->id),
+                        _("_No"),
+                        unitupgrade_callback_no, 0,
+                        NULL);
+  } else {
+    popup_message_dialog(NULL, _("Upgrade Unit!"), buf,
+                        _("Darn"), unitupgrade_callback_no, 0,
+                        NULL);
+  }
+
+  destroy_message_dialog(w);
 }
 
 /**************************************************************************
Index: client/gui-xaw/citydlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/citydlg.c,v
retrieving revision 1.107
diff -u -r1.107 citydlg.c
--- client/gui-xaw/citydlg.c    2003/11/28 17:37:20     1.107
+++ client/gui-xaw/citydlg.c    2003/12/22 02:02:08
@@ -2020,50 +2020,26 @@
 *****************************************************************/
 void upgrade_callback(Widget w, XtPointer client_data, XtPointer call_data)
 {
-  struct unit *punit;
+  struct unit *punit = player_find_unit_by_id(game.player_ptr,
+                                             (size_t)client_data);
   char buf[512];
-  int ut1,ut2;
-  int value;
 
-  if((punit=player_find_unit_by_id(game.player_ptr, (size_t)client_data))) {
-    ut1 = punit->type;
-    /* printf("upgrade_callback for %s\n", unit_types[ut1].name); */
-
-    ut2 = can_upgrade_unittype(game.player_ptr,ut1);
-
-    if ( ut2 == -1 ) {
-      /* this shouldn't generally happen, but it is conceivable */
-      my_snprintf(buf, sizeof(buf),
-                 _("Sorry: cannot upgrade %s."), unit_types[ut1].name);
-      popup_message_dialog(toplevel, "upgradenodialog", buf,
-                           unitupgrade_callback_no, 0, 0,
-                           NULL);
-    } else {
-      value=unit_upgrade_price(game.player_ptr, ut1, ut2);
+  if (!punit) {
+    return;
+  }
 
-      if(game.player_ptr->economic.gold>=value) {
-        my_snprintf(buf, sizeof(buf),
-                   _("Upgrade %s to %s for %d gold?\n"
-                     "Treasury contains %d gold."),
-                   unit_types[ut1].name, unit_types[ut2].name,
-                   value, game.player_ptr->economic.gold);
-       popup_message_dialog(toplevel, "upgradedialog", buf,
-                            unitupgrade_callback_yes,
-                            INT_TO_XTPOINTER(punit->id), 0,
-                            unitupgrade_callback_no, 0, 0, NULL);
-      } else {
-        my_snprintf(buf, sizeof(buf),
-                   _("Upgrading %s to %s costs %d gold.\n"
-                     "Treasury contains %d gold."),
-                   unit_types[ut1].name, unit_types[ut2].name,
-                   value, game.player_ptr->economic.gold);
-        popup_message_dialog(toplevel, "upgradenodialog", buf,
-                             unitupgrade_callback_no, 0, 0,
-                             NULL);
-      }
-    }
-    destroy_message_dialog(w);
+  if (get_unit_upgrade_info(buf, sizeof(buf), punit) == UR_OK) {
+    popup_message_dialog(toplevel, "upgradedialog", buf,
+                        unitupgrade_callback_yes,
+                        INT_TO_XTPOINTER(punit->id), 0,
+                        unitupgrade_callback_no, 0, 0, NULL);
+  } else {
+    popup_message_dialog(toplevel, "upgradenodialog", buf,
+                        unitupgrade_callback_no, 0, 0,
+                        NULL);
   }
+
+  destroy_message_dialog(w);
 }
 
 
Index: common/unit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v
retrieving revision 1.190
diff -u -r1.190 unit.c
--- common/unit.c       2003/11/28 17:37:21     1.190
+++ common/unit.c       2003/12/22 02:02:09
@@ -1513,3 +1513,118 @@
     punit->pgr = NULL;
   }
 }
+
+/****************************************************************************
+  Expensive function to check how many units are in the transport.
+****************************************************************************/
+int get_transporter_occupancy(struct unit *ptrans)
+{
+  int occupied = 0;
+
+  unit_list_iterate(map_get_tile(ptrans->x, ptrans->y)->units, pcargo) {
+    if (pcargo->transported_by == ptrans->id) {
+      occupied++;
+    }
+  } unit_list_iterate_end;
+
+  return occupied;
+}
+
+/***************************************************************************
+  Tests if the unit could be updated. Returns UR_OK if is this is
+  possible.
+
+  need_money: Leonardo upgrade for free, in all other cases the unit
+  owner has to pay
+  need_city: Leonardo upgrade everywhere, all other cases the unit has
+  to be inside an owned city
+
+  Note that this function is strongly tied to unittools.c:upgrade_unit().
+***************************************************************************/
+enum unit_upgrade_result test_unit_upgrade(struct unit *punit, bool is_free)
+{
+  struct player *pplayer = unit_owner(punit);
+  Unit_Type_id to_unittype = can_upgrade_unittype(pplayer, punit->type);
+  struct city *pcity;
+  int cost;
+
+  if (to_unittype == -1) {
+    return UR_NO_UNITTYPE;
+  }
+
+  cost = unit_upgrade_price(pplayer, punit->type, to_unittype);
+  if (!is_free && pplayer->economic.gold < cost) {
+    return UR_NO_MONEY;
+  }
+
+  pcity = map_get_city(punit->x, punit->y);
+  if (!is_free && !pcity) {
+    return UR_NOT_IN_CITY;
+  }
+  if (!is_free && city_owner(pcity) != pplayer) {
+    /* TODO: should upgrades in allied cities be possible? */
+    return UR_NOT_CITY_OWNER;
+  }
+
+  if (get_transporter_occupancy(punit) >
+      unit_types[to_unittype].transport_capacity) {
+    /* TODO: allow transported units to be reassigned.  Check for
+     * ground_unit_transporter_capacity here and make changes to
+     * upgrade_unit. */
+    return UR_NOT_ENOUGH_ROOM;
+  }
+
+  return UR_OK;
+}
+
+/**************************************************************************
+  Find the result of trying to upgrade the unit, and a message that
+  most callers can use directly.
+**************************************************************************/
+enum unit_upgrade_result get_unit_upgrade_info(char *buf, size_t bufsz,
+                                              struct unit *punit)
+{
+  enum unit_upgrade_result result = test_unit_upgrade(punit, FALSE);
+  int upgrade_cost;
+  Unit_Type_id from_unittype = punit->type;
+  Unit_Type_id to_unittype = can_upgrade_unittype(punit->type,
+                                                 game.player_ptr);
+
+  switch (result) {
+  case UR_OK:
+    upgrade_cost = unit_upgrade_price(game.player_ptr,
+                                     from_unittype, to_unittype);
+    /* This message is targeted toward the GUI callers. */
+    my_snprintf(buf, bufsz, _("Upgrade %s to %s for %d gold?\n"
+                             "Treasury contains %d gold."),
+               unit_types[from_unittype].name, unit_types[to_unittype].name,
+               upgrade_cost, game.player_ptr->economic.gold);
+    break;
+  case UR_NO_UNITTYPE:
+    my_snprintf(buf, bufsz,
+               _("Sorry, cannot upgrade %s (yet)."),
+               unit_types[from_unittype].name);
+    break;
+  case UR_NO_MONEY:
+    upgrade_cost = unit_upgrade_price(game.player_ptr,
+                                     from_unittype, to_unittype);
+    my_snprintf(buf, bufsz,
+               _("Upgrading %s to %s costs %d gold.\n"
+                 "Treasury contains %d gold."),
+               unit_types[from_unittype].name, unit_types[to_unittype].name,
+               upgrade_cost, game.player_ptr->economic.gold);
+    break;
+  case UR_NOT_IN_CITY:
+  case UR_NOT_CITY_OWNER:
+    my_snprintf(buf, bufsz,
+               _("You can only upgrade units in your cities."));
+    break;
+  case UR_NOT_ENOUGH_ROOM:
+    my_snprintf(buf, bufsz,
+               _("Upgrading this %s would strand units it transports."),
+               unit_types[from_unittype].name);
+    break;
+  }
+
+  return result;
+}
Index: common/unit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v
retrieving revision 1.105
diff -u -r1.105 unit.h
--- common/unit.h       2003/12/01 18:14:22     1.105
+++ common/unit.h       2003/12/22 02:02:09
@@ -92,6 +92,15 @@
                                   sewer but city has no sewer */
 };
 
+enum unit_upgrade_result {
+  UR_OK,
+  UR_NO_UNITTYPE,
+  UR_NO_MONEY,
+  UR_NOT_IN_CITY,
+  UR_NOT_CITY_OWNER,
+  UR_NOT_ENOUGH_ROOM
+};
+    
 struct unit_ai {
   bool control; /* 0: not automated    1: automated */
   enum ai_unit_task ai_role;
@@ -293,5 +302,11 @@
                                  Unit_Type_id type, bool make_veteran);
 void destroy_unit_virtual(struct unit *punit);
 void free_unit_goto_route(struct unit *punit);
+
+int get_transporter_occupancy(struct unit *ptrans);
+
+enum unit_upgrade_result test_unit_upgrade(struct unit *punit, bool is_free);
+enum unit_upgrade_result get_unit_upgrade_info(char *buf, size_t bufsz,
+                                              struct unit *punit);
 
 #endif  /* FC__UNIT_H */
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.280
diff -u -r1.280 unithand.c
--- server/unithand.c   2003/12/15 19:14:50     1.280
+++ server/unithand.c   2003/12/22 02:02:10
@@ -153,83 +153,71 @@
   const Unit_Type_id from_unittype = type;
   const Unit_Type_id to_unittype = can_upgrade_unittype(pplayer,
                                                        from_unittype);
+  int number_of_upgraded_units = 0;
 
   if (to_unittype == -1) {
     notify_player(pplayer,
                  _("Game: Illegal packet, can't upgrade %s (yet)."),
-                  unit_types[from_unittype].name);
-  } else {
-    const int cost = unit_upgrade_price(pplayer, from_unittype, to_unittype);
-    int number_of_upgraded_units = 0;
-
-    if (pplayer->economic.gold >= cost) {
-      const int player_no = pplayer->player_no;
+                 unit_types[from_unittype].name);
+    return;
+  }
 
-      /* Try to upgrade units. The order we upgrade in is arbitrary (if
-       * the player really cared they should have done it manually). */
-      conn_list_do_buffer(&pplayer->connections);
-      unit_list_iterate(pplayer->units, punit) {
-        if (punit->type == from_unittype) {
-          const struct city * const pcity = map_get_city(punit->x, punit->y);
-
-         /* Only units in cities can be upgraded. */
-          if (pcity && pcity->owner == player_no) {
-            upgrade_unit(punit, to_unittype);
-           number_of_upgraded_units++;
-            if ((pplayer->economic.gold -= cost) < cost) {
-             /* We can't upgrade any more units. */
-              break;
-            }
-          }
-        }
-      } unit_list_iterate_end;
-      conn_list_do_unbuffer(&pplayer->connections);
+  /* 
+   * Try to upgrade units. The order we upgrade in is arbitrary (if
+   * the player really cared they should have done it manually). 
+   */
+  conn_list_do_buffer(&pplayer->connections);
+  unit_list_iterate(pplayer->units, punit) {
+    if (punit->type == from_unittype) {
+      enum unit_upgrade_result result = test_unit_upgrade(punit, FALSE);
+
+      if (result == UR_OK) {
+       number_of_upgraded_units++;
+       upgrade_unit(punit, to_unittype, FALSE);
+      } else if (result == UR_NO_MONEY) {
+       break;
+      }
     }
+  } unit_list_iterate_end;
+  conn_list_do_unbuffer(&pplayer->connections);
 
-    /* Alert the player about what happened. */
-    if (number_of_upgraded_units > 0) {
-      notify_player(pplayer, _("Game: %d %s upgraded to %s for %d gold."),
-                    number_of_upgraded_units, unit_types[from_unittype].name,
-                    unit_types[to_unittype].name,
-                    cost * number_of_upgraded_units);
-      send_player_info(pplayer, pplayer);
-    } else {
-      notify_player(pplayer, _("Game: No units could be upgraded."));
-    }
+  /* Alert the player about what happened. */
+  if (number_of_upgraded_units > 0) {
+    const int cost = unit_upgrade_price(pplayer, from_unittype, to_unittype);
+    notify_player(pplayer, _("Game: %d %s upgraded to %s for %d gold."),
+                 number_of_upgraded_units, unit_types[from_unittype].name,
+                 unit_types[to_unittype].name,
+                 cost * number_of_upgraded_units);
+    send_player_info(pplayer, pplayer);
+  } else {
+    notify_player(pplayer, _("Game: No units could be upgraded."));
   }
 }
 
 /**************************************************************************
  Upgrade a single unit.
- TODO: should upgrades in allied cities be possible?
 **************************************************************************/
 void handle_unit_upgrade(struct player *pplayer, int unit_id)
 {
-  int cost;
-  int from_unit, to_unit;
   struct unit *punit = player_find_unit_by_id(pplayer, unit_id);
+  char buf[512];
   
-  if (!punit || !map_get_city(punit->x, punit->y)) {
+  if (!punit) {
     return;
   }
 
-  from_unit = punit->type;
-  if((to_unit=can_upgrade_unittype(pplayer, punit->type)) == -1) {
-    notify_player(pplayer, _("Game: Illegal package, can't upgrade %s 
(yet)."), 
-                 unit_type(punit)->name);
-    return;
-  }
-  cost = unit_upgrade_price(pplayer, punit->type, to_unit);
-  if(cost > pplayer->economic.gold) {
-    notify_player(pplayer, _("Game: Insufficient funds, upgrade costs %d."),
-                 cost);
-    return;
+  if (get_unit_upgrade_info(buf, sizeof(buf), punit) == UR_OK) {
+    Unit_Type_id from_unit = punit->type;
+    Unit_Type_id to_unit = can_upgrade_unittype(pplayer, punit->type);
+    int cost = unit_upgrade_price(pplayer, punit->type, to_unit);
+
+    upgrade_unit(punit, to_unit, FALSE);
+    send_player_info(pplayer, pplayer);
+    notify_player(pplayer, _("Game: %s upgraded to %s for %d gold."), 
+                 unit_name(from_unit), unit_name(to_unit), cost);
+  } else {
+    notify_player(pplayer, _("Game: %s"), buf);
   }
-  pplayer->economic.gold -= cost;
-  upgrade_unit(punit, to_unit);
-  send_player_info(pplayer, pplayer);
-  notify_player(pplayer, _("Game: %s upgraded to %s for %d gold."), 
-               unit_name(from_unit), unit_name(to_unit), cost);
 }
 
 /***************************************************************
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.267
diff -u -r1.267 unittools.c
--- server/unittools.c  2003/12/04 18:32:45     1.267
+++ server/unittools.c  2003/12/22 02:02:11
@@ -59,7 +59,6 @@
 static void unit_restore_movepoints(struct player *pplayer, struct unit 
*punit);
 static void update_unit_activity(struct unit *punit);
 static void wakeup_neighbor_sentries(struct unit *punit);
-static bool upgrade_would_strand(struct unit *punit, int upgrade_type);
 static void handle_leonardo(struct player *pplayer);
 
 static void sentry_transported_idle_units(struct unit *ptrans);
@@ -158,63 +157,11 @@
 }
 
 /***************************************************************************
- Return 1 if upgrading this unit could cause passengers to
- get stranded at sea, due to transport capacity changes
- caused by the upgrade.
- Return 0 if ok to upgrade (as far as stranding goes).
-***************************************************************************/
-static bool upgrade_would_strand(struct unit *punit, int upgrade_type)
-{
-  int old_cap, new_cap, tile_cap, tile_ncargo;
-  
-  if (!is_sailing_unit(punit))
-    return FALSE;
-  if (!is_ocean(map_get_terrain(punit->x, punit->y))) {
-    return FALSE;
-  }
-
-  /* With weird non-standard unit types, upgrading these could
-     cause air units to run out of fuel; too bad. */
-  if (unit_flag(punit, F_CARRIER)
-      || unit_flag(punit, F_MISSILE_CARRIER))
-    return FALSE;
-
-  old_cap = get_transporter_capacity(punit);
-  new_cap = unit_types[upgrade_type].transport_capacity;
-
-  if (new_cap >= old_cap)
-    return FALSE;
-
-  tile_cap = 0;
-  tile_ncargo = 0;
-  unit_list_iterate(map_get_tile(punit->x, punit->y)->units, punit2) {
-    if (punit2->owner == punit->owner
-        || pplayers_allied(unit_owner(punit2), unit_owner(punit))) {
-      if (is_sailing_unit(punit2) && is_ground_units_transport(punit2)) { 
-       tile_cap += get_transporter_capacity(punit2);
-      } else if (is_ground_unit(punit2)) {
-       tile_ncargo++;
-      }
-    }
-  }
-  unit_list_iterate_end;
-
-  if (tile_ncargo <= tile_cap - old_cap + new_cap)
-    return FALSE;
-
-  freelog(LOG_VERBOSE, "Can't upgrade %s at (%d,%d)"
-         " because would strand passenger(s)",
-         unit_type(punit)->name, punit->x, punit->y);
-  return TRUE;
-}
-
-/***************************************************************************
 Do Leonardo's Workshop upgrade(s). Select unit to upgrade by random. --Zamar
 Now be careful not to strand units at sea with the Workshop. --dwp
 ****************************************************************************/
 static void handle_leonardo(struct player *pplayer)
 {
-  int upgrade_type; 
   int leonardo_variant;
        
   struct unit_list candidates;
@@ -227,9 +174,9 @@
   unit_list_init(&candidates);
        
   unit_list_iterate(pplayer->units, punit) {
-    if ((upgrade_type=can_upgrade_unittype(pplayer, punit->type))!=-1 &&
-       !upgrade_would_strand(punit, upgrade_type))
-      unit_list_insert(&candidates, punit); /* Potential candidate :) */
+    if (test_unit_upgrade(punit, TRUE) == UR_OK) {
+      unit_list_insert(&candidates, punit);    /* Potential candidate :) */
+    }
   } unit_list_iterate_end;
        
   if (unit_list_size(&candidates) == 0)
@@ -241,7 +188,8 @@
   i=0; 
   unit_list_iterate(candidates, punit) {
     if (leonardo_variant != 0 || i == candidate_to_upgrade) {
-      upgrade_type=can_upgrade_unittype(pplayer, punit->type);
+      Unit_Type_id upgrade_type = can_upgrade_unittype(pplayer, punit->type);
+
       notify_player(pplayer,
             _("Game: %s has upgraded %s to %s%s."),
             improvement_types[B_LEONARDO].name,
@@ -249,7 +197,8 @@
             get_unit_type(upgrade_type)->name,
             get_location_str_in(pplayer, punit->x, punit->y));
       punit->veteran = FALSE;
-      upgrade_unit(punit, upgrade_type);
+      assert(test_unit_upgrade(punit, TRUE) == UR_OK);
+      upgrade_unit(punit, upgrade_type, FALSE);
     }
     i++;
   } unit_list_iterate_end;
@@ -1418,30 +1367,29 @@
   }
 }
 
-/****************************************************************************
-  Expensive function to check how many units are in the transport.
-****************************************************************************/
-int get_transporter_occupancy(struct unit *ptrans)
-{
-  int occupied = 0;
+/**************************************************************************
+  Really upgrades a single unit.
 
-  unit_list_iterate(map_get_tile(ptrans->x, ptrans->y)->units, pcargo) {
-    if (pcargo->transported_by == ptrans->id) {
-      occupied++;
-    }
-  } unit_list_iterate_end;
+  Before calling this function you should use unit_upgrade to test if
+  this is possible.
 
-  return occupied;
-}
+  has_to_pay: Leonardo upgrade for free, in all other cases the unit
+  owner has to pay
 
-/**************************************************************************
-...
+  Note that this function is strongly tied to unit.c:test_unit_upgrade().
 **************************************************************************/
-void upgrade_unit(struct unit *punit, Unit_Type_id to_unit)
+void upgrade_unit(struct unit *punit, Unit_Type_id to_unit, bool is_free)
 {
   struct player *pplayer = unit_owner(punit);
   int range;
   int old_mr = unit_move_rate(punit), old_hp = unit_type(punit)->hp;
+
+  assert(test_unit_upgrade(punit, is_free) == UR_OK);
+
+  if (!is_free) {
+    pplayer->economic.gold -=
+       unit_upgrade_price(pplayer, punit->type, to_unit);
+  }
 
   /* save old vision range */
   if (map_has_special(punit->x, punit->y, S_FORTRESS)
Index: server/unittools.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.h,v
retrieving revision 1.58
diff -u -r1.58 unittools.h
--- server/unittools.h  2003/11/28 17:37:22     1.58
+++ server/unittools.h  2003/12/22 02:02:11
@@ -29,7 +29,6 @@
 /* move check related */
 bool is_airunit_refuel_point(int x, int y, struct player *pplayer,
                             Unit_Type_id type, bool unit_is_on_tile);
-int get_transporter_occupancy(struct unit *ptrans);
 
 /* turn update related */
 void player_restore_units(struct player *pplayer);
@@ -51,7 +50,7 @@
 void bounce_unit(struct unit *punit, bool verbose);
 
 /* creation/deletion/upgrading */
-void upgrade_unit(struct unit *punit, Unit_Type_id to_unit);
+void upgrade_unit(struct unit *punit, Unit_Type_id to_unit, bool has_to_pay);
 struct unit *create_unit(struct player *pplayer, int x, int y, Unit_Type_id 
type,
                         bool make_veteran, int homecity_id, int moves_left);
 struct unit *create_unit_full(struct player *pplayer, int x, int y,

[Prev in Thread] Current Thread [Next in Thread]