Complete.Org: Mailing Lists: Archives: freeciv-dev: August 2003:
[Freeciv-Dev] Re: New unit flags patch v17 (PR#1324)
Home

[Freeciv-Dev] Re: New unit flags patch v17 (PR#1324)

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: Per.Inge.Mathisen@xxxxxxxxxxx
Subject: [Freeciv-Dev] Re: New unit flags patch v17 (PR#1324)
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Fri, 1 Aug 2003 06:09:29 -0700
Reply-to: rt@xxxxxxxxxxxxxx

On Fri, 1 Aug 2003, Per I. Mathisen wrote:
> This patch adds the flags "GameLoss", "Unique", "Unbribable",
> "Undisbandable", "SuperSpy" and "NoHome" to units.
>
> I intend to commit this one unless there are protests.

Oh, and the patch.

  - Per

"This is the future for the world we're in at the moment,"
promised Lawrence Di Rita, special assistant to Rumsfeld.
"We'll get better as we do it more often."

Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.147
diff -u -r1.147 advmilitary.c
--- ai/advmilitary.c    2003/06/19 17:44:21     1.147
+++ ai/advmilitary.c    2003/08/01 12:51:47
@@ -572,6 +572,9 @@
   if (unit_type_flag(i, F_PIKEMEN)) {
     desire += desire / 2;
   }
+  if (unit_type_flag(i, F_GAMELOSS)) {
+    desire /= 10; /* but might actually be worth it */
+  }
   return desire;
 }
 
@@ -590,6 +593,9 @@
   desire += defense;
   if (unit_type_flag(i, F_IGTER)) {
     desire += desire / 2;
+  }
+  if (unit_type_flag(i, F_GAMELOSS)) {
+    desire /= 10; /* but might actually be worth it */
   }
   if (unit_type_flag(i, F_IGTIRED)) {
     desire += desire / 4;
Index: client/gui-gtk/citydlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/citydlg.c,v
retrieving revision 1.167
diff -u -r1.167 citydlg.c
--- client/gui-gtk/citydlg.c    2003/07/31 21:05:37     1.167
+++ client/gui-gtk/citydlg.c    2003/08/01 12:51:47
@@ -2456,6 +2456,7 @@
   struct unit *punit;
   struct city *pcity;
   struct city_dialog *pdialog;
+  GtkWidget *wd;
 
   if ((punit = player_find_unit_by_id(game.player_ptr, (size_t) data)) &&
       (pcity = find_city_by_id(punit->homecity)) &&
@@ -2465,7 +2466,7 @@
       return FALSE;
     }
 
-    popup_message_dialog(pdialog->shell,       /* "supported unit popup" */
+    wd = popup_message_dialog(pdialog->shell,  /* "supported unit popup" */
                         _("Unit Commands"), unit_description(punit),
                         dummy_close_callback, NULL, 
                         _("Cen_ter"), unit_center_callback, punit->id,
@@ -2475,6 +2476,9 @@
                         _("_Disband unit"), unit_disband_callback,
                         punit->id, _("_Cancel"), NULL, 0,
                         0);
+    if (unit_flag(punit, F_UNDISBANDABLE)) {
+      message_dialog_button_set_sensitive(wd, "button3", FALSE);
+    }
   }
   return TRUE;
 }
@@ -2521,6 +2525,9 @@
     if (punit->activity == ACTIVITY_FORTIFYING
        || !can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) {
       message_dialog_button_set_sensitive(wd, "button3", FALSE);
+    }
+    if (unit_flag(punit, F_UNDISBANDABLE)) {
+      message_dialog_button_set_sensitive(wd, "button4", FALSE);
     }
     if (punit->homecity == pcity->id) {
       message_dialog_button_set_sensitive(wd, "button5", FALSE);
Index: client/gui-gtk/dialogs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/dialogs.c,v
retrieving revision 1.129
diff -u -r1.129 dialogs.c
--- client/gui-gtk/dialogs.c    2003/07/20 20:41:37     1.129
+++ client/gui-gtk/dialogs.c    2003/08/01 12:51:47
@@ -438,7 +438,11 @@
 {
   char buf[128];
   
-  if(game.player_ptr->economic.gold>=punit->bribe_cost) {
+  if (unit_flag(punit, F_UNBRIBABLE)) {
+    popup_message_dialog(top_vbox, _("Ooops..."),
+                        _("This unit cannot be bribed!"),
+                        dummy_close_callback, NULL, _("Darn"), NULL, 0, 0);
+  } else if(game.player_ptr->economic.gold>=punit->bribe_cost) {
     my_snprintf(buf, sizeof(buf),
                _("Bribe unit for %d gold?\nTreasury contains %d gold."), 
                punit->bribe_cost, game.player_ptr->economic.gold);
Index: client/gui-gtk/menu.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/menu.c,v
retrieving revision 1.77
diff -u -r1.77 menu.c
--- client/gui-gtk/menu.c       2003/07/23 13:46:02     1.77
+++ client/gui-gtk/menu.c       2003/08/01 12:51:47
@@ -1148,6 +1148,8 @@
                           can_unit_do_connect(punit, ACTIVITY_IDLE));
       menus_set_sensitive("<main>/_Orders/Patrol (_Q)",
                           can_unit_do_activity(punit, ACTIVITY_PATROL));
+      menus_set_sensitive("<main>/_Orders/_Disband Unit",
+                          !unit_flag(punit, F_UNDISBANDABLE));
       menus_set_sensitive("<main>/_Orders/Diplomat|Spy Actions",
                           (is_diplomat_unit(punit)
                            && diplomat_can_do_action(punit, 
DIPLOMAT_ANY_ACTION,
Index: client/gui-gtk-2.0/dialogs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/dialogs.c,v
retrieving revision 1.52
diff -u -r1.52 dialogs.c
--- client/gui-gtk-2.0/dialogs.c        2003/07/20 20:41:37     1.52
+++ client/gui-gtk-2.0/dialogs.c        2003/08/01 12:51:47
@@ -304,10 +304,15 @@
 void popup_bribe_dialog(struct unit *punit)
 {
   GtkWidget *shell;
-  
-  if(game.player_ptr->economic.gold>=punit->bribe_cost) {
-    shell = gtk_message_dialog_new(NULL,
-      0,
+
+  if (unit_flag(punit, F_UNBRIBABLE)) {
+    shell = popup_message_dialog(GTK_WINDOW(toplevel), _("Ooops..."),
+                                 _("This unit cannot be bribed!"),
+                                 GTK_STOCK_OK, NULL, NULL, NULL);
+    gtk_window_present(GTK_WINDOW(shell));
+    return;
+  } else if (game.player_ptr->economic.gold >= punit->bribe_cost) {
+    shell = gtk_message_dialog_new(NULL, 0,
       GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
       _("Bribe unit for %d gold?\nTreasury contains %d gold."),
       punit->bribe_cost, game.player_ptr->economic.gold);
Index: client/gui-gtk-2.0/menu.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/menu.c,v
retrieving revision 1.20
diff -u -r1.20 menu.c
--- client/gui-gtk-2.0/menu.c   2003/07/23 13:46:02     1.20
+++ client/gui-gtk-2.0/menu.c   2003/08/01 12:51:47
@@ -1152,6 +1152,8 @@
                          can_unit_do_activity(punit, ACTIVITY_SENTRY));
       menus_set_sensitive("<main>/_Orders/Pillage",
                          can_unit_do_activity(punit, ACTIVITY_PILLAGE));
+      menus_set_sensitive("<main>/_Orders/_Disband Unit",
+                         !unit_flag(punit, F_UNDISBANDABLE));
       menus_set_sensitive("<main>/_Orders/Make _Homecity",
                          can_unit_change_homecity(punit));
       menus_set_sensitive("<main>/_Orders/_Unload",
Index: client/gui-win32/citydlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/citydlg.c,v
retrieving revision 1.56
diff -u -r1.56 citydlg.c
--- client/gui-win32/citydlg.c  2003/07/31 21:05:37     1.56
+++ client/gui-win32/citydlg.c  2003/08/01 12:51:47
@@ -1592,10 +1592,12 @@
 {
   struct unit *punit;
   struct city *pcity;  
+  HWND wd;
+
   if((punit=player_find_unit_by_id(game.player_ptr, 
                                   pdialog->support_unit_ids[n])) &&
      (pcity = find_city_by_id(punit->homecity))) {   
-      popup_message_dialog(NULL,
+    wd = popup_message_dialog(NULL,
            /*"supportunitsdialog"*/ _("Unit Commands"),
            unit_description(punit),
            _("_Activate unit"),
@@ -1605,7 +1607,10 @@
            _("_Disband unit"),
              present_units_disband_callback, punit->id,
            _("_Cancel"),
-            present_units_cancel_callback, 0, 0,NULL);
+             present_units_cancel_callback, 0, 0, NULL);
+    if (unit_flag(punit, F_UNDISBANDABLE)) {
+      message_dialog_button_set_sensitive(wd, 3, FALSE);
+    }
   }
 }
 
@@ -1650,6 +1655,9 @@
      if (punit->activity == ACTIVITY_FORTIFYING
         || !can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) {
        message_dialog_button_set_sensitive(wd,3, FALSE);
+     }
+     if (unit_flag(punit, F_UNDISBANDABLE)) {
+       message_dialog_button_set_sensitive(wd,4, FALSE);
      }
      if (punit->homecity == pcity->id) {
        message_dialog_button_set_sensitive(wd,5, FALSE);
Index: client/gui-win32/dialogs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/dialogs.c,v
retrieving revision 1.35
diff -u -r1.35 dialogs.c
--- client/gui-win32/dialogs.c  2003/07/20 20:41:38     1.35
+++ client/gui-win32/dialogs.c  2003/08/01 12:51:47
@@ -1356,8 +1356,11 @@
 void popup_bribe_dialog(struct unit *punit)
 {
   char buf[128];
-  
-  if(game.player_ptr->economic.gold>=punit->bribe_cost) {
+  if (unit_flag(punit, F_UNBRIBABLE)) {
+    popup_message_dialog(root_window, _("Ooops..."),
+                         _("This unit cannot be bribed!"),
+                         diplomat_bribe_no_callback, 0, 0);
+  } else if(game.player_ptr->economic.gold>=punit->bribe_cost) {
     my_snprintf(buf, sizeof(buf),
                 _("Bribe unit for %d gold?\nTreasury contains %d gold."), 
                 punit->bribe_cost, game.player_ptr->economic.gold);
Index: client/gui-xaw/citydlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/citydlg.c,v
retrieving revision 1.99
diff -u -r1.99 citydlg.c
--- client/gui-xaw/citydlg.c    2003/07/31 21:05:37     1.99
+++ client/gui-xaw/citydlg.c    2003/08/01 12:51:47
@@ -1350,6 +1350,9 @@
        || !can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) {
       XtSetSensitive(XtNameToWidget(wd, "*button3"), FALSE);
     }
+    if (unit_flag(punit, F_UNDISBANDABLE)) {
+      XtSetSensitive(XtNameToWidget(wd, "*button4"), FALSE);
+    }
     if (punit->homecity == pcity->id) {
       XtSetSensitive(XtNameToWidget(wd, "*button5"), FALSE);
     }
@@ -1627,7 +1630,8 @@
   struct city *pcity;
   struct city_dialog *pdialog;
   XEvent *e = (XEvent*)call_data;
-  
+  Widget wd;
+
   if((punit=player_find_unit_by_id(game.player_ptr, (size_t)client_data)))
     if((pcity=find_city_by_id(punit->homecity)))
       if((pdialog=get_city_dialog(pcity)))  {
@@ -1640,7 +1644,7 @@
          set_unit_focus(punit);
          return;
        }
-       popup_message_dialog(pdialog->shell,
+       wd = popup_message_dialog(pdialog->shell,
                             "supportunitsdialog", 
                             unit_description(punit),
                             supported_units_activate_callback, punit->id, 1,
@@ -1649,6 +1653,9 @@
                             present_units_disband_callback, punit->id, 1,
                             present_units_cancel_callback, 0, 0,
                             NULL);
+        if (unit_flag(punit, F_UNDISBANDABLE)) {
+          XtSetSensitive(XtNameToWidget(wd, "*button3"), FALSE);
+        }
       }
 }
 
Index: client/gui-xaw/dialogs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/dialogs.c,v
retrieving revision 1.87
diff -u -r1.87 dialogs.c
--- client/gui-xaw/dialogs.c    2003/07/20 20:41:38     1.87
+++ client/gui-xaw/dialogs.c    2003/08/01 12:51:47
@@ -443,8 +443,12 @@
 void popup_bribe_dialog(struct unit *punit)
 {
   char buf[128];
-  
-  if(game.player_ptr->economic.gold>=punit->bribe_cost) {
+
+  if (unit_flag(punit, F_UNBRIBABLE)) {
+    popup_message_dialog(toplevel, "diplomatbribedialog",
+                         _("This unit cannot be bribed!"),
+                         diplomat_bribe_no_callback, 0, 0, NULL);
+  } else if(game.player_ptr->economic.gold>=punit->bribe_cost) {
     my_snprintf(buf, sizeof(buf),
                _("Bribe unit for %d gold?\n"
                  "Treasury contains %d gold."), 
Index: client/gui-xaw/menu.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/menu.c,v
retrieving revision 1.55
diff -u -r1.55 menu.c
--- client/gui-xaw/menu.c       2003/07/23 13:46:03     1.55
+++ client/gui-xaw/menu.c       2003/08/01 12:51:48
@@ -362,6 +362,8 @@
       menu_entry_sensitive(MENU_ORDER, MENU_ORDER_AUTO_ATTACK, 
                           (can_unit_do_auto(punit)
                            && !unit_flag(punit, F_SETTLERS)));
+      menu_entry_sensitive(MENU_ORDER, MENU_ORDER_DISBAND,
+                          !unit_flag(punit, F_UNDISBANDABLE));
       menu_entry_sensitive(MENU_ORDER, MENU_ORDER_AUTO_EXPLORE, 
                           can_unit_do_activity(punit, ACTIVITY_EXPLORE));
       menu_entry_sensitive(MENU_ORDER, MENU_ORDER_CONNECT, 
Index: common/player.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.c,v
retrieving revision 1.120
diff -u -r1.120 player.c
--- common/player.c     2003/07/03 18:18:51     1.120
+++ common/player.c     2003/08/01 12:51:48
@@ -102,6 +102,7 @@
   plr->current_conn = NULL;
   plr->is_connected = FALSE;
   plr->is_alive=TRUE;
+  plr->is_dying = FALSE;
   plr->embassy=0;
   plr->reputation=GAME_DEFAULT_REPUTATION;
   for(i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
Index: common/player.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.h,v
retrieving revision 1.100
diff -u -r1.100 player.h
--- common/player.h     2003/05/31 16:22:15     1.100
+++ common/player.h     2003/08/01 12:51:48
@@ -180,6 +180,7 @@
   bool turn_done;
   int nturns_idle;
   bool is_alive;
+  bool is_dying;
   bool got_tech;
   int revolution;
   bool capital; /* used to give player capital in first city. */
Index: common/unittype.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unittype.c,v
retrieving revision 1.27
diff -u -r1.27 unittype.c
--- common/unittype.c   2003/04/04 15:47:49     1.27
+++ common/unittype.c   2003/08/01 12:51:48
@@ -45,7 +45,8 @@
   "AEGIS", "Fighter", "Marines", "Partial_Invis", "Settlers", "Diplomat",
   "Trireme", "Nuclear", "Spy", "Transform", "Paratroopers",
   "Airbase", "Cities", "IgTired", "Missile_Carrier", "No_Land_Attack",
-  "AddToCity", "Fanatic"
+  "AddToCity", "Fanatic", "GameLoss", "Unique", "Unbribable", 
+  "Undisbandable", "SuperSpy", "NoHome"
 };
 static const char *role_names[] = {
   "FirstBuild", "Explorer", "Hut", "HutTech", "Partisan",
@@ -431,6 +432,16 @@
     return FALSE;
   if (get_invention(p,unit_types[id].tech_requirement)!=TECH_KNOWN)
     return FALSE;
+  if (unit_type_flag(id, F_UNIQUE)) {
+    /* FIXME: This could be slow if we have lots of units. We could
+     * consider keeping an array of unittypes updated with this info 
+     * instead. */
+    unit_list_iterate(p->units, punit) {
+      if (punit->type == id) { 
+        return FALSE;
+      }
+    } unit_list_iterate_end;
+  }
 
   /* If the unit has a building requirement, we check to see if the player
    * can build that building.  Note that individual cities may not have
Index: common/unittype.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unittype.h,v
retrieving revision 1.20
diff -u -r1.20 unittype.h
--- common/unittype.h   2003/07/02 19:32:47     1.20
+++ common/unittype.h   2003/08/01 12:51:48
@@ -109,6 +109,12 @@
   F_ADD_TO_CITY,      /* unit can add to city population */
   F_FANATIC,          /* Only Fundamentalist government can build
                         these units */
+  F_GAMELOSS,         /* Losing this unit means losing the game */
+  F_UNIQUE,           /* A player can only have one unit of this type */
+  F_UNBRIBABLE,       /* Cannot be bribed */
+  F_UNDISBANDABLE,    /* Cannot be disbanded, won't easily go away */
+  F_SUPERSPY,         /* Always wins diplomatic contests */
+  F_NOHOME,           /* Has no homecity */
   F_LAST
 };
 #define F_MAX 64
Index: data/default/units.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/default/units.ruleset,v
retrieving revision 1.47
diff -u -r1.47 units.ruleset
--- data/default/units.ruleset  2003/06/14 13:20:51     1.47
+++ data/default/units.ruleset  2003/08/01 12:51:48
@@ -10,7 +10,10 @@
 ; The AI does not know the value of Partial_Invis, nor does this
 ; work against the AI, since it knows all. It does not know anything 
 ; about air units at all. It does not build No_Land_Attack, Missile 
-; or Nuclear units.
+; or Nuclear units. It values GameLoss units at 1/10th its usual value
+; and therefore would not easily build it, but if it does, it does not 
+; protect it from harm. NoHome units are likely to be given a homecity
+; by the AI, because it is rather stupid in this regard.
 ;
 ; You should sort role units from worst to better, as often the best
 ; available role unit of a given sort will be picked by choosing
@@ -100,6 +103,22 @@
 ;                (see cities.ruleset for limitation of this ability)
 ; "Fanatic"    = can only be built by governments that allow them
 ;                (see data/civ2/governments.ruleset, Fanaticism government)
+; "Unique"     = a player can only have one of these units in the game at
+;                the same time; barbarians cannot use this at present
+; "GameLoss"   = losing one of these units means you lose the game, but it
+;                is produced without homecity and upkeep
+; "Unbribable" = this unit cannot be bribed
+; "Undisbandable" = this unit cannot be disbanded, won't drown, and will not
+;                disband due to lack of shields to upkeep it in homecity;
+;                if not given enough food to upkeep it, homecity will shrink 
+;                every turn it cannot do so, however
+; "SuperSpy"   = this unit always wins diplomatic contests, that is, unless
+;                it encounters another SuperSpy, in which case defender wins;
+;                can also be used on non-diplomat units, in which case it can
+;                protect cities from diplomats; also 100% spy survival chance
+; "NoHome"     = this unit has no homecity and will be free of all upkeep, and
+;                therefore will not revolt along with its city of origin should
+;                it be incited
 ;
 ; Following flag strings require extra fields:
 ;  "Paratroopers"
@@ -1744,7 +1763,8 @@
 uk_shield     = 0
 uk_food       = 0
 uk_gold       = 0
-flags         = "IgZOC", "NonMil"
+flags         = "IgZOC", "NonMil", "GameLoss", "Unique", "Unbribable",
+                "Undisbandable", "SuperSpy", "NoHome"
 roles         = "BarbarianLeader"
 helptext      = _("\
 When barbarian leader is killed on a tile without any defending units, \
Index: server/barbarian.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/barbarian.c,v
retrieving revision 1.65
diff -u -r1.65 barbarian.c
--- server/barbarian.c  2003/07/13 01:51:11     1.65
+++ server/barbarian.c  2003/08/01 12:51:48
@@ -91,6 +91,7 @@
       if (!barbarians->is_alive) {
         barbarians->economic.gold = 0;
         barbarians->is_alive = TRUE;
+        barbarians->is_dying = FALSE;
         pick_ai_player_name(game.nation_count - 1, barbarians->name);
        sz_strlcpy(barbarians->username, ANON_USER_NAME);
         /* I need to make them to forget the map, I think */
Index: server/cityturn.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/cityturn.c,v
retrieving revision 1.217
diff -u -r1.217 cityturn.c
--- server/cityturn.c   2003/07/18 15:51:01     1.217
+++ server/cityturn.c   2003/08/01 12:51:48
@@ -583,7 +583,8 @@
      * reserves.  Hence, I'll assume food upkeep > 0 units. -- jjm
      */
     unit_list_iterate(pcity->units_supported, punit) {
-      if (unit_type(punit)->food_cost > 0) {
+      if (unit_type(punit)->food_cost > 0 
+          && !unit_flag(punit, F_UNDISBANDABLE)) {
        char *utname = unit_type(punit)->name;
        wipe_unit_safe(punit, &myiter);
        notify_player_ex(city_owner(pcity), pcity->x, pcity->y, E_UNIT_LOST,
@@ -889,7 +890,7 @@
 }
 
 /**************************************************************************
-...
+  Disband units if we don't have enough shields to support them.
 **************************************************************************/
 static void city_distribute_surplus_shields(struct player *pplayer,
                                            struct city *pcity)
@@ -898,7 +899,8 @@
 
   while (pcity->shield_surplus < 0) {
     unit_list_iterate(pcity->units_supported, punit) {
-      if (utype_shield_cost(unit_type(punit), g) > 0) {
+      if (utype_shield_cost(unit_type(punit), g) > 0
+          && !unit_flag(punit, F_UNDISBANDABLE)) {
        struct packet_unit_request packet;
 
        notify_player_ex(pplayer, pcity->x, pcity->y, E_UNIT_LOST,
@@ -908,6 +910,17 @@
         handle_unit_disband(pplayer, &packet);
        break;
       }
+    } unit_list_iterate_end;
+    /* Special case: F_UNDISBANDABLE. This nasty unit won't go so easily. It'd
+       rather make the citizens pay in blood for their failure to upkeep it! */
+    unit_list_iterate(pcity->units_supported, punit) {
+      if (utype_shield_cost(unit_type(punit), g) > 0) {
+       notify_player_ex(pplayer, pcity->x, pcity->y, E_UNIT_LOST,
+                        _("Game: Citizens in %s perish for their failure to "
+                        "upkeep %s!"), pcity->name, unit_type(punit)->name);
+        city_reduce_size(pcity, 1);
+       break;
+      }
     }
     unit_list_iterate_end;
   }
@@ -1050,6 +1063,18 @@
 {
   upgrade_unit_prod(pcity);
 
+  /* We must make a special case for barbarians here, because they are
+     so dumb. Really. They don't know the prerequisite techs for units
+     they build!! - Per */
+  if (!can_build_unit_direct(pcity, pcity->currently_building)
+      && !is_barbarian(pplayer)) {
+    notify_player_ex(pplayer, pcity->x, pcity->y, E_CITY_CANTBUILD,
+        _("Game: %s is building %s, which is no longer available."),
+        pcity->name, unit_name(pcity->currently_building));
+    freelog(LOG_VERBOSE, _("%s's %s tried build %s, which is not available"),
+            pplayer->name, pcity->name, unit_name(pcity->currently_building)); 
           
+    return TRUE;
+  }
   if (pcity->shield_stock >= unit_value(pcity->currently_building)) {
     int pop_cost = unit_pop_value(pcity->currently_building);
 
@@ -1098,8 +1123,11 @@
 
     /* If there's something in the worklist, change the build
        target. If there's nothing there, worklist_change_build_target
-       won't do anything. */
-    (void) worklist_change_build_target(pplayer, pcity);
+       won't do anything, unless the unit built is unique. */
+    if (!worklist_change_build_target(pplayer, pcity) 
+        && unit_type_flag(pcity->currently_building, F_UNIQUE)) {
+      advisor_choose_build(pplayer, pcity);
+    }
   }
   return TRUE;
 }
Index: server/diplomats.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/diplomats.c,v
retrieving revision 1.39
diff -u -r1.39 diplomats.c
--- server/diplomats.c  2003/07/21 01:43:52     1.39
+++ server/diplomats.c  2003/08/01 12:51:48
@@ -430,6 +430,12 @@
     return;
   }
 
+  if (unit_flag(pvictim, F_UNBRIBABLE)) {
+    notify_player_ex(pplayer, pdiplomat->x, pdiplomat->y, E_MY_DIPLOMAT_FAILED,
+                    _("Game: You cannot bribe %s!"), unit_name(pvictim->type));
+    return;
+  }
+
   freelog (LOG_DEBUG, "bribe-unit: succeeded");
 
   /* Convert the unit to your cause. Fog is lifted in the create algorithm. */
@@ -1068,6 +1074,10 @@
 {
   int success = game.diplchance;
 
+  if (unit_flag(pdefender, F_SUPERSPY)) {
+    return TRUE;
+  }
+
   if (unit_flag (pdefender, F_SPY)) {
     if (success > 66) {
       success -= (100 - success);
@@ -1099,8 +1109,13 @@
                              struct unit *pdiplomat, struct city *pcity)
 {
   unit_list_iterate ((map_get_tile (pcity->x, pcity->y))->units, punit)
-    if (unit_flag (punit, F_DIPLOMAT)) {
-      if (diplomat_success_vs_defender (punit)) {
+    if (unit_flag(punit, F_DIPLOMAT) || unit_flag(punit, F_SUPERSPY)) {
+      /* A F_SUPERSPY unit may not acutally be a spy, but a superboss which 
+         we cannot allow puny diplomats from getting the better of. Note that 
+         diplomat_success_vs_defender(punit) is always TRUE if the attacker
+         is F_SUPERSPY. Hence F_SUPERSPY vs F_SUPERSPY in a diplomatic contest
+         always kills the attacker. */
+      if (diplomat_success_vs_defender(punit) && !unit_flag(punit, 
F_SUPERSPY)) {
        /* Defending Spy/Diplomat dies. */
 
        notify_player_ex(cplayer, pcity->x, pcity->y, E_MY_DIPLOMAT_FAILED,
@@ -1158,10 +1173,16 @@
       y = pdiplomat->y;
     }
 
-    if (myrand (100) < game.diplchance) {
+    if (myrand (100) < game.diplchance || unit_flag(pdiplomat, F_SUPERSPY)) {
       /* Attacking Spy/Diplomat survives. */
 
       struct city *spyhome = find_city_by_id (pdiplomat->homecity);
+
+      /* It may never have had a homecity */
+      if (!spyhome) {
+       spyhome = find_closest_owned_city(pplayer, pdiplomat->x, pdiplomat->y,
+                                         FALSE, NULL);
+      }
 
       if (!spyhome) {
        send_unit_info (pplayer, pdiplomat);
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.281
diff -u -r1.281 plrhand.c
--- server/plrhand.c    2003/07/21 01:43:52     1.281
+++ server/plrhand.c    2003/08/01 12:51:48
@@ -43,6 +43,9 @@
 #include "srv_main.h"
 #include "stdinhand.h"
 #include "unittools.h"
+#include "spaceship.h"
+#include "spacerace.h"
+#include "unittools.h"
 
 #include "advmilitary.h"
 #include "aidata.h"
@@ -176,28 +179,74 @@
 void update_player_aliveness(struct player *pplayer)
 {
   assert(pplayer != NULL);
-  if(pplayer->is_alive) {
-    if(unit_list_size(&pplayer->units)==0 && 
-       city_list_size(&pplayer->cities)==0) {
-      notify_player_ex(pplayer, -1, -1, E_GAME_END,
-                      _("Game: You are dead!"));
-      pplayer->is_alive = FALSE;
-      if( !is_barbarian(pplayer) ) {
-       notify_player_ex(NULL, -1, -1, E_DESTROYED,
-                        _("Game: The %s are no more!"),
-                        get_nation_name_plural(pplayer->nation));
-       gamelog(GAMELOG_GENO, _("%s civilization destroyed"),
-               get_nation_name(pplayer->nation));
-      }
-      players_iterate(pplayer2) {
-       if (gives_shared_vision(pplayer, pplayer2))
-         remove_shared_vision(pplayer, pplayer2);
-      } players_iterate_end;
+  if (pplayer->is_alive) {
+     if (unit_list_size(&pplayer->units) == 0
+         && city_list_size(&pplayer->cities) == 0) {
+       kill_player(pplayer);
+     }
+  }
+}
 
-      cancel_all_meetings(pplayer);
-      map_know_and_see_all(pplayer);
-    }
+/**************************************************************************
+  Murder a player in cold blood.
+**************************************************************************/
+void kill_player(struct player *pplayer) {
+  bool palace;
+
+  pplayer->is_alive = FALSE;
+
+  cancel_all_meetings(pplayer);
+  map_know_and_see_all(pplayer);
+
+  if (is_barbarian(pplayer)) {
+    gamelog(GAMELOG_GENO, _("The feared barbarian leader %s is no more"),
+        pplayer->name);
+    return;
+  } else {
+    notify_player_ex(NULL, -1, -1, E_DESTROYED, _("Game: The %s are no more!"),
+                     get_nation_name_plural(pplayer->nation));
+    gamelog(GAMELOG_GENO, _("%s civilization destroyed"),
+            get_nation_name(pplayer->nation));
   }
+
+  /* Transfer back all cities not originally owned by player to their
+     rightful owners, if they are still around */
+  palace = game.savepalace;
+  game.savepalace = FALSE; /* moving it around is dumb */
+  city_list_iterate(pplayer->cities, pcity) {
+    if ((pcity->original != pplayer->player_no)
+        && (get_player(pcity->original)->is_alive)) {
+      /* Transfer city to original owner, kill all its units outside of
+         a radius of 3, give verbose messages of every unit transferred,
+         and raze buildings according to raze chance (also removes palace) */
+      transfer_city(get_player(pcity->original), pcity, 3, TRUE, TRUE, TRUE);
+    }
+  } city_list_iterate_end;
+
+  /* Remove all units that are still ours */
+  unit_list_iterate_safe(pplayer->units, punit) {
+    wipe_unit(punit);
+  } unit_list_iterate_safe_end;
+
+  /* Destroy any remaining cities */
+  city_list_iterate(pplayer->cities, pcity) {
+    remove_city(pcity);
+  } city_list_iterate_end;
+  game.savepalace = palace;
+
+  players_iterate(aplayer) {
+    /* Remove shared vision */  
+    if (gives_shared_vision(pplayer, aplayer)) {
+      remove_shared_vision(pplayer, aplayer);
+    }
+  } players_iterate_end;
+    
+  /* Ensure this dead player doesn't win with a spaceship.
+   * Now that would be truly unbelievably dumb - Per */
+  spaceship_init(&pplayer->spaceship);
+  send_spaceship_info(pplayer, NULL);
+
+  send_player_info_c(pplayer, &game.est_connections);
 }
 
 /**************************************************************************
Index: server/plrhand.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.h,v
retrieving revision 1.54
diff -u -r1.54 plrhand.h
--- server/plrhand.h    2003/04/30 21:14:35     1.54
+++ server/plrhand.h    2003/08/01 12:51:48
@@ -26,6 +26,7 @@
 
 void server_player_init(struct player *pplayer, bool initmap);
 void server_remove_player(struct player *pplayer);
+void kill_player(struct player *pplayer);
 void begin_player_turn(struct player *pplayer);
 void update_player_aliveness(struct player *pplayer);
 void update_revolution(struct player *pplayer);
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.132
diff -u -r1.132 srv_main.c
--- server/srv_main.c   2003/07/21 01:23:27     1.132
+++ server/srv_main.c   2003/08/01 12:51:48
@@ -964,6 +964,9 @@
            type, conn_description(pconn));
   }
 
+  if (pplayer->is_alive && pplayer->is_dying) {
+    kill_player(pplayer);
+  }
   free(packet);
   pplayer->current_conn = NULL;
   return TRUE;
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.265
diff -u -r1.265 unithand.c
--- server/unithand.c   2003/07/20 20:41:39     1.265
+++ server/unithand.c   2003/08/01 12:51:48
@@ -400,17 +400,23 @@
 static void do_unit_disband_safe(struct city *pcity, struct unit *punit,
                                 struct genlist_iterator *iter)
 {
-  if (pcity) {
-    pcity->shield_stock += (unit_type(punit)->build_cost/2);
-    /* If we change production later at this turn. No penalty is added. */
-    pcity->disbanded_shields += (unit_type(punit)->build_cost/2);
+  if (!unit_flag(punit, F_UNDISBANDABLE)) { /* refuse to kill ourselves */
+    if (pcity) {
+      pcity->shield_stock += (unit_type(punit)->build_cost/2);
+      /* If we change production later at this turn. No penalty is added. */
+      pcity->disbanded_shields += (unit_type(punit)->build_cost/2);
 
-    /* Note: Nowadays it's possible to disband unit in allied city and
-     * your ally receives those shields. Should it be like this? Why not?
-     * That's why we must use city_owner instead of pplayer -- Zamar */
-    send_city_info(city_owner(pcity), pcity);
+      /* Note: Nowadays it's possible to disband unit in allied city and
+       * your ally receives those shields. Should it be like this? Why not?
+       * That's why we must use city_owner instead of pplayer -- Zamar */
+      send_city_info(city_owner(pcity), pcity);
+    }
+    wipe_unit_safe(punit, iter);
+  } else {
+    notify_player_ex(unit_owner(punit), punit->x, punit->y, E_NOEVENT,
+              _("Game: %s refuses to disband!"), unit_name(punit->type));
+    return;
   }
-  wipe_unit_safe(punit, iter);
 }
 
 /**************************************************************************
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.236
diff -u -r1.236 unittools.c
--- server/unittools.c  2003/07/24 16:52:28     1.236
+++ server/unittools.c  2003/08/01 12:51:48
@@ -1282,6 +1282,19 @@
   freelog(LOG_VERBOSE, "Disbanded %s's %s at (%d, %d)",
          unit_owner(punit)->name, unit_name(punit->type),
          punit->x, punit->y);
+  /* Too cheesy way to kill an enemy player */
+  if (unit_flag(punit, F_GAMELOSS)) {
+    struct city *toc =
+          find_closest_owned_city(unit_owner(punit),
+              punit->x, punit->y, FALSE, NULL);
+    assert(toc != NULL);
+    notify_player_ex(unit_owner(punit), punit->x, punit->y, E_UNIT_WIN,
+        _("%s narrowly escaped death and fled to %s"), 
+        unit_name(punit->type), toc->name);
+    teleport_unit_to_city(punit, toc, -1, TRUE);
+    return;
+  }
+  /* remove it */
   if (verbose) {
     notify_player(unit_owner(punit),
                  _("Game: Disbanded your %s at (%d, %d)."),
@@ -1484,7 +1497,11 @@
   punit->y = y;
 
   pcity = find_city_by_id(homecity_id);
-  punit->homecity = homecity_id;
+  if (unit_type_flag(type, F_NOHOME)) {
+    punit->homecity = 0; /* none */
+  } else {
+    punit->homecity = homecity_id;
+  }
 
   if (hp_left >= 0) {
     /* Override default full HP */
@@ -1508,10 +1525,9 @@
 
   unit_list_insert(&pplayer->units, punit);
   unit_list_insert(&map_get_tile(x, y)->units, punit);
-  if (pcity) {
+  if (pcity && !unit_type_flag(type, F_NOHOME)) {
     assert(city_owner(pcity) == pplayer);
     unit_list_insert(&pcity->units_supported, punit);
-    assert(city_owner(pcity) == pplayer);
     /* Refresh the unit's homecity. */
     city_refresh(pcity);
     send_city_info(pplayer, pcity);
@@ -1543,7 +1559,7 @@
 }
 
 /**************************************************************************
-We remove the unit and see if it's disapperance have affected the homecity
+We remove the unit and see if it's disappearance has affected the homecity
 and the city it was in.
 **************************************************************************/
 static void server_remove_unit(struct unit *punit)
@@ -1571,6 +1587,19 @@
     }
   } players_iterate_end;
 
+  /* check if this unit had F_GAMELOSS flag */
+  if (unit_flag(punit, F_GAMELOSS) && unit_owner(punit)->is_alive) {
+    notify_conn_ex(&game.est_connections, punit->x, punit->y, E_UNIT_LOST,
+                   _("Unable to defend %s, %s has lost the game."),
+                   unit_name(punit->type), unit_owner(punit)->name);
+    notify_player(unit_owner(punit), _("Losing %s meant losing the game! "
+                  "Be more careful next time!"), unit_name(punit->type));
+    gamelog(GAMELOG_NORMAL, _("Player %s lost a game loss unit and died"),
+            unit_owner(punit)->name);
+    unit_owner(punit)->is_dying = TRUE;
+    unit_owner(punit)->is_alive = FALSE;
+  }
+
   game_remove_unit(punit);
   punit = NULL;
 
@@ -1616,6 +1645,7 @@
       && wipe_cargo) {
     int x = punit->x;
     int y = punit->y;
+    struct city *pcity = NULL;
 
     int capacity =
        ground_unit_transporter_capacity(x, y, unit_owner(punit));
@@ -1629,15 +1659,30 @@
          freelog(LOG_DEBUG, "iterating over %s in wipe_unit_safe",
                  unit_name(pcargo->type));
          ITERATOR_NEXT((*iter));
+       }
+       /* Undisbandable units should be hard to get rid of. Drowning
+          them in a trireme is too simple. Or too easy a way to lose an
+          all-important unit, depending on the scenario. */
+       if (unit_flag(pcargo, F_UNDISBANDABLE)) {
+         pcity = find_closest_owned_city(unit_owner(pcargo),
+                       pcargo->x, pcargo->y, TRUE, NULL);
+         if (pcity && teleport_unit_to_city(pcargo, pcity, 0, FALSE)) {
+           notify_player_ex(unit_owner(punit), x, y, E_NOEVENT,
+                        _("Game: %s escaped the destruction of %s, and "
+                        "fled to %s"), unit_type(pcargo)->name,
+                        unit_type(punit)->name, pcity->name);
+         }
        }
-       notify_player_ex(unit_owner(punit), x, y, E_UNIT_LOST,
+       if (!unit_flag(pcargo, F_UNDISBANDABLE) || !pcity) {
+         notify_player_ex(unit_owner(punit), x, y, E_UNIT_LOST,
                         _("Game: %s lost when %s was lost."),
                         unit_type(pcargo)->name,
                         unit_type(punit)->name);
-       gamelog(GAMELOG_UNITL, _("%s lose %s when %s lost"),
+         gamelog(GAMELOG_UNITL, _("%s lose %s when %s lost"),
                get_nation_name_plural(unit_owner(punit)->nation),
                unit_type(pcargo)->name, unit_type(punit)->name);
-       server_remove_unit(pcargo);
+         server_remove_unit(pcargo);
+       }
        capacity++;
       }
     } unit_list_iterate_end;
@@ -2114,6 +2159,7 @@
   if (is_ocean(map_get_terrain(dest_x, dest_y))
       && is_ground_unit(punit)) {
     int srange = unit_type(punit)->vision_range;
+
     show_area(pplayer, dest_x, dest_y, srange);
 
     notify_player_ex(pplayer, dest_x, dest_y, E_UNIT_LOST,

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] Re: New unit flags patch v17 (PR#1324), Per I. Mathisen <=