Complete.Org: Mailing Lists: Archives: freeciv-dev: February 2003:
[Freeciv-Dev] (PR#2464) patch: restrict techs by nation
Home

[Freeciv-Dev] (PR#2464) patch: restrict techs by nation

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Cc: freeciv-dev@xxxxxxxxxxx
Subject: [Freeciv-Dev] (PR#2464) patch: restrict techs by nation
From: "Per I. Mathisen via RT" <rt@xxxxxxxxxxxxxx>
Date: Sun, 2 Feb 2003 04:32:36 -0800
Reply-to: rt@xxxxxxxxxxxxxx

CHANGES
  - A active govchange wonder cannot change into a government requiring an
unavailable technology for that player.
  - Change helptext for such techs.
  - Some AI changes to cope with unavailable techs.
  - Ensure that we don't show goal techs that don't exist for this player.

PS In the clients, there is a spy restriction that you cannot select an
unreachable tech for stealing, but there is no such restriction in the
server. Which is correct? Davide says in civ2 you could steal any tech,
but we agreed this isn't a good idea. So the server should be fixed. Note
that you can steal random, unreachable techs by not selecting one.

PPS Why isn't there a tech iterator? IMHO there should be two, one for
all techs, and one for available and reachable techs in X steps.

That way we avoid having code like this in each client:

 for(i=A_FIRST, flag=0; i<game.num_tech_types; i++)
    if (tech_is_available(game.player_ptr, i)
        && get_invention(game.player_ptr, i) != TECH_KNOWN
        && advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST
        && num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
      ...
    }

Instead we could have

  available_tech_iterate(game.player_ptr, 11, tech) {
    ...
  } available_tech_iterate_end;

I think the path is ready to go in.

  - Per

Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.100
diff -u -r1.100 advdomestic.c
--- ai/advdomestic.c    2003/01/30 19:31:27     1.100
+++ ai/advdomestic.c    2003/02/02 12:29:32
@@ -547,8 +547,10 @@
         values[id]= impr_happy_val(pcity, get_cathedral_power(pcity), val);
       else
       if (tech_exists(game.rtech.cathedral_plus)
-        && get_invention(pplayer, game.rtech.cathedral_plus) != TECH_KNOWN)
-        values[id]= impr_happy_val(pcity, 4, val) - impr_happy_val(pcity, 3, 
val);
+        && get_invention(pplayer, game.rtech.cathedral_plus) != TECH_KNOWN) {
+        values[id]= impr_happy_val(pcity, 4, val) 
+                    - impr_happy_val(pcity, 3, val);
+      }
       break;
     case B_COLOSSEUM:
       values[id] = impr_happy_val(pcity, get_colosseum_power(pcity), val);
@@ -642,11 +644,12 @@
   } impr_type_iterate_end;
 
   /* Miscellaneous building values */
-  if ( values[B_COLOSSEUM] == 0
-    && tech_exists(game.rtech.colosseum_plus)
-    && get_invention(pplayer, game.rtech.colosseum_plus) != TECH_KNOWN)
+  if (values[B_COLOSSEUM] == 0
+      && tech_exists(game.rtech.colosseum_plus)
+      && get_invention(pplayer, game.rtech.colosseum_plus) != TECH_KNOWN) {
     values[B_COLOSSEUM] = 
       impr_happy_val(pcity, 4, val) - impr_happy_val(pcity, 3, val);
+  }
     
   /* Wonders */
   impr_type_iterate(id) {
Index: ai/aitech.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitech.c,v
retrieving revision 1.38
diff -u -r1.38 aitech.c
--- ai/aitech.c 2003/01/13 23:27:03     1.38
+++ ai/aitech.c 2003/02/02 12:29:32
@@ -50,8 +50,10 @@
       && !wonder_obsolete(building)) {
     Tech_Type_id tech = improvement_types[building].tech_req;
 
-    if (tech_exists(tech) && get_invention(plr, tech) != TECH_KNOWN)
+    if (tech_is_available(plr, tech) 
+        && get_invention(plr, tech) != TECH_KNOWN) {
       return tech;
+    }
   }
   return A_UNSET;
 }
@@ -70,20 +72,21 @@
 
   for (i = 0 ; i < MAX_NUM_TECH_GOALS; i++) {
     Tech_Type_id j = prace->goals.tech[i];
-    if (!tech_exists(j) || get_invention(pplayer, j) == TECH_KNOWN) 
+    if (!tech_is_available(pplayer, j) 
+        || get_invention(pplayer, j) == TECH_KNOWN) {
       continue;
+    }
     dist = num_unknown_techs_for_goal(pplayer, j);
     if (dist < bestdist) { 
       bestdist = dist;
       goal = j;
       break; /* remove this to restore old functionality -- Syela */
     }
-  } 
+  }
   tech = get_wonder_tech(pplayer);
   if (tech != A_UNSET) {
     dist = num_unknown_techs_for_goal(pplayer, tech);
     if (dist < bestdist) { 
-/*    bestdist = dist; */ /* useless, reinclude when adding a new if statement 
*/
       goal = tech;
     }
   }
@@ -154,11 +157,18 @@
     } else goal_values[i] = 0;
   }
 
-  l = A_UNSET;
-  k = A_UNSET;
+  l = A_UNSET; /* currently researched tech */
+  k = A_UNSET; /* current tech goal */
   for (i = A_FIRST; i < game.num_tech_types; i++) {
-    if (values[i] > values[l] && get_invention(pplayer, i) == TECH_REACHABLE) 
l = i;
-    if (goal_values[i] > goal_values[k]) k = i;
+    if (values[i] > values[l]
+        && tech_is_available(pplayer, i)
+        && get_invention(pplayer, i) == TECH_REACHABLE) {
+      l = i;
+    }
+    if (goal_values[i] > goal_values[k]
+        && tech_is_available(pplayer, i)) {
+      k = i;
+    }
   }
   freelog(LOG_DEBUG, "%s wants %s with desire %d (%d).", pplayer->name,
                advances[l].name, values[l], pplayer->ai.tech_want[l]);
Index: client/helpdata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/helpdata.c,v
retrieving revision 1.59
diff -u -r1.59 helpdata.c
--- client/helpdata.c   2003/01/29 05:10:49     1.59
+++ client/helpdata.c   2003/02/02 12:29:32
@@ -785,7 +785,7 @@
              _("If we would now start with %s we would need %d bulbs."),
              advances[i].name,
              base_total_bulbs_required(game.player_ptr, i));
-    } else {
+    } else if (tech_is_available(game.player_ptr, i)) {
       sprintf(buf + strlen(buf),
              _("To reach %s we need to obtain %d other "
                "technologies first. The whole project "
@@ -793,8 +793,11 @@
              advances[i].name,
              num_unknown_techs_for_goal(game.player_ptr, i) - 1,
              total_bulbs_required_for_goal(game.player_ptr, i));
+    } else {
+      sprintf(buf + strlen(buf),
+             _("You cannot research this technology."));
     }
-    if (!techs_have_fixed_costs()) {
+    if (!techs_have_fixed_costs() && tech_is_available(game.player_ptr, i)) {
       sprintf(buf + strlen(buf),
              _(" This number may vary depending on what "
                "other players will research.\n"));
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.281
diff -u -r1.281 packhand.c
--- client/packhand.c   2003/02/01 07:41:10     1.281
+++ client/packhand.c   2003/02/02 12:29:33
@@ -1802,10 +1802,10 @@
   sz_strlcpy(a->graphic_alt, p->graphic_alt);
   a->req[0] = p->req[0];
   a->req[1] = p->req[1];
+  a->root_req = p->root_req;
   a->flags = p->flags;
   a->preset_cost = p->preset_cost;
   a->num_reqs = p->num_reqs;
-  
   a->helptext = p->helptext;   /* pointer assignment */
   
   tilespec_setup_tech_type(p->id);
Index: client/gui-gtk/diplodlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/diplodlg.c,v
retrieving revision 1.38
diff -u -r1.38 diplodlg.c
--- client/gui-gtk/diplodlg.c   2002/11/15 21:24:28     1.38
+++ client/gui-gtk/diplodlg.c   2003/02/02 12:29:33
@@ -218,10 +218,10 @@
   int i, flag;
 
   for(i=1, flag=0; i<game.num_tech_types; i++) {
-    if(get_invention(plr0, i)==TECH_KNOWN && 
-       (get_invention(plr1, i)==TECH_UNKNOWN || 
-       get_invention(plr1, i)==TECH_REACHABLE))
-       {
+    if (get_invention(plr0, i) == TECH_KNOWN
+        && (get_invention(plr1, i) == TECH_UNKNOWN
+           || get_invention(plr1, i) == TECH_REACHABLE)
+        && tech_is_available(plr1, i)) {
          GtkWidget *item=gtk_menu_item_new_with_label(advances[i].name);
 
          gtk_menu_append(GTK_MENU(popupmenu),item);
Index: client/gui-gtk/repodlgs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/repodlgs.c,v
retrieving revision 1.69
diff -u -r1.69 repodlgs.c
--- client/gui-gtk/repodlgs.c   2003/01/13 23:27:03     1.69
+++ client/gui-gtk/repodlgs.c   2003/02/02 12:29:33
@@ -491,9 +491,10 @@
    */
   hist=0;
   for(i=A_FIRST; i<game.num_tech_types; i++) {
-    if(get_invention(game.player_ptr, i) != TECH_KNOWN &&
-       advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST &&
-       num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
+    if (tech_is_available(game.player_ptr, i)
+        && get_invention(game.player_ptr, i) != TECH_KNOWN
+        && advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST
+        && num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
       if (i==game.player_ptr->ai.tech_goal)
        hist=i;
       sorting_list = g_list_append(sorting_list, GINT_TO_POINTER(i));
Index: client/gui-gtk-2.0/diplodlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/diplodlg.c,v
retrieving revision 1.8
diff -u -r1.8 diplodlg.c
--- client/gui-gtk-2.0/diplodlg.c       2002/12/30 02:32:02     1.8
+++ client/gui-gtk-2.0/diplodlg.c       2003/02/02 12:29:33
@@ -216,10 +216,10 @@
   int i, flag;
 
   for(i=1, flag=0; i<game.num_tech_types; i++) {
-    if(get_invention(plr0, i)==TECH_KNOWN && 
-       (get_invention(plr1, i)==TECH_UNKNOWN || 
-       get_invention(plr1, i)==TECH_REACHABLE))
-       {
+    if (get_invention(plr0, i) == TECH_KNOWN
+        && (get_invention(plr1, i) == TECH_UNKNOWN
+           || get_invention(plr1, i) == TECH_REACHABLE)
+        && tech_is_available(plr1, i)) {
          GtkWidget *item=gtk_menu_item_new_with_label(advances[i].name);
 
          gtk_menu_append(GTK_MENU(popupmenu),item);
Index: client/gui-gtk-2.0/repodlgs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/repodlgs.c,v
retrieving revision 1.24
diff -u -r1.24 repodlgs.c
--- client/gui-gtk-2.0/repodlgs.c       2003/01/13 23:27:03     1.24
+++ client/gui-gtk-2.0/repodlgs.c       2003/02/02 12:29:33
@@ -491,9 +491,10 @@
    */
   hist=0;
   for(i=A_FIRST; i<game.num_tech_types; i++) {
-    if(get_invention(game.player_ptr, i) != TECH_KNOWN &&
-       advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST &&
-       num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
+    if (tech_is_available(game.player_ptr, i)
+        && get_invention(game.player_ptr, i) != TECH_KNOWN
+        && advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST
+        && num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
       if (i==game.player_ptr->ai.tech_goal)
        hist=i;
       sorting_list = g_list_append(sorting_list, GINT_TO_POINTER(i));
Index: client/gui-mui/diplodlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/diplodlg.c,v
retrieving revision 1.15
diff -u -r1.15 diplodlg.c
--- client/gui-mui/diplodlg.c   2003/01/11 16:24:42     1.15
+++ client/gui-mui/diplodlg.c   2003/02/02 12:29:33
@@ -262,7 +262,10 @@
 
   for(i=1, flag=0; i<game.num_tech_types; i++)
   {
-    if(get_invention(plr0, i)==TECH_KNOWN && (get_invention(plr1, 
i)==TECH_UNKNOWN || get_invention(plr1, i)==TECH_REACHABLE))
+    if (get_invention(plr0, i) == TECH_KNOWN 
+        && (get_invention(plr1, i) == TECH_UNKNOWN
+            || get_invention(plr1, i) == TECH_REACHABLE)
+        && tech_is_available(plr1, i))
     {
       entry = MUI_MakeObject(MUIO_Menuitem,advances[i].name,NULL,0,0);
       set(entry,MUIA_UserData,i);
Index: client/gui-mui/repodlgs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/repodlgs.c,v
retrieving revision 1.28
diff -u -r1.28 repodlgs.c
--- client/gui-mui/repodlgs.c   2003/01/13 23:27:03     1.28
+++ client/gui-mui/repodlgs.c   2003/02/02 12:29:33
@@ -240,9 +240,10 @@
 
   for (i = A_FIRST, j = 0; i < game.num_tech_types; i++)
   {
-    if (get_invention(game.player_ptr, i) != TECH_KNOWN &&
-       advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST &&
-       num_unknown_techs_for_goal(game.player_ptr, i) < 11)
+    if (tech_is_available(game.player_ptr, i)
+       && get_invention(game.player_ptr, i) != TECH_KNOWN &&
+       && advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST
+       && num_unknown_techs_for_goal(game.player_ptr, i) < 11)
       j++;
   }
   if (game.player_ptr->ai.tech_goal == A_UNSET) {
Index: client/gui-sdl/repodlgs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/repodlgs.c,v
retrieving revision 1.8
diff -u -r1.8 repodlgs.c
--- client/gui-sdl/repodlgs.c   2003/02/01 12:10:33     1.8
+++ client/gui-sdl/repodlgs.c   2003/02/02 12:29:33
@@ -846,9 +846,10 @@
    */
   count = 0;
   for (i = A_FIRST; i < game.num_tech_types; i++) {
-    if (get_invention(game.player_ptr, i) != TECH_KNOWN &&
-       advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST &&
-       num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
+    if (tech_is_available(game.player_ptr, i)
+        && get_invention(game.player_ptr, i) != TECH_KNOWN
+        && advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST
+       && num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
 
       pStr = create_str16_from_char(advances[i].name, 10);
       pStr->style |= TTF_STYLE_BOLD;
Index: client/gui-win32/diplodlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/diplodlg.c,v
retrieving revision 1.12
diff -u -r1.12 diplodlg.c
--- client/gui-win32/diplodlg.c 2002/11/17 19:22:24     1.12
+++ client/gui-win32/diplodlg.c 2003/02/02 12:29:33
@@ -184,9 +184,10 @@
   plr1=plr?pdialog->treaty.plr0:pdialog->treaty.plr1;
   menu=CreatePopupMenu();
   for(i=1, flag=0; i<game.num_tech_types; i++) {
-    if(get_invention(plr0, i)==TECH_KNOWN && 
-       (get_invention(plr1, i)==TECH_UNKNOWN || 
-        get_invention(plr1, i)==TECH_REACHABLE)) {
+    if (get_invention(plr0, i) == TECH_KNOWN
+        && (get_invention(plr1, i) == TECH_UNKNOWN || 
+            || get_invention(plr1, i) == TECH_REACHABLE)
+        && tech_is_available(plr1, i)) {
       AppendMenu(menu,MF_STRING,ID_ADVANCES_BASE+i,advances[i].name);
       iteminfo.dwItemData=plr0->player_no*10000+plr1->player_no*100+i;
       iteminfo.fMask = MIIM_DATA;
Index: client/gui-win32/repodlgs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/repodlgs.c,v
retrieving revision 1.26
diff -u -r1.26 repodlgs.c
--- client/gui-win32/repodlgs.c 2003/01/13 23:27:04     1.26
+++ client/gui-win32/repodlgs.c 2003/02/02 12:29:33
@@ -144,9 +144,10 @@
   ComboBox_ResetContent(GetDlgItem(science_dlg,ID_SCIENCE_GOAL));
     hist=0;
   for(i=A_FIRST; i<game.num_tech_types; i++) {
-    if(get_invention(game.player_ptr, i) != TECH_KNOWN &&
-       advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST &&
-       num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
+    if (tech_is_available(game.player_ptr, i)
+        && get_invention(game.player_ptr, i) != TECH_KNOWN
+        && advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST
+        && num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
       id=ComboBox_AddString(GetDlgItem(science_dlg,ID_SCIENCE_GOAL),
                            advances[i].name);
       ComboBox_SetItemData(GetDlgItem(science_dlg,ID_SCIENCE_GOAL),
Index: client/gui-xaw/diplodlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/diplodlg.c,v
retrieving revision 1.34
diff -u -r1.34 diplodlg.c
--- client/gui-xaw/diplodlg.c   2002/11/15 21:24:29     1.34
+++ client/gui-xaw/diplodlg.c   2003/02/02 12:29:33
@@ -252,9 +252,10 @@
   int i, flag;
   
   for(i=A_FIRST, flag=0; i<game.num_tech_types; i++) {
-    if(get_invention(plr0, i)==TECH_KNOWN && 
-       (get_invention(plr1, i)==TECH_UNKNOWN || 
-       get_invention(plr1, i)==TECH_REACHABLE)) {
+    if (get_invention(plr0, i) == TECH_KNOWN
+        && (get_invention(plr1, i) == TECH_UNKNOWN
+           || get_invention(plr1, i) == TECH_REACHABLE)
+        && tech_is_available(plr1, i)) {
       Widget entry=
        XtVaCreateManagedWidget(advances[i].name, smeBSBObjectClass, 
                                popupmenu, NULL);
Index: client/gui-xaw/repodlgs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/repodlgs.c,v
retrieving revision 1.47
diff -u -r1.47 repodlgs.c
--- client/gui-xaw/repodlgs.c   2002/11/29 20:11:59     1.47
+++ client/gui-xaw/repodlgs.c   2003/02/02 12:29:33
@@ -333,9 +333,10 @@
     XtSetSensitive(science_change_menu_button, FALSE);
   
  for(i=A_FIRST, flag=0; i<game.num_tech_types; i++)
-    if(get_invention(game.player_ptr, i) != TECH_KNOWN &&
-       advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST &&
-       num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
+    if (tech_is_available(game.player_ptr, i)
+        && get_invention(game.player_ptr, i) != TECH_KNOWN
+        && advances[i].req[0] != A_LAST && advances[i].req[1] != A_LAST
+        && num_unknown_techs_for_goal(game.player_ptr, i) < 11) {
       Widget entry=
       XtVaCreateManagedWidget(advances[i].name, smeBSBObjectClass, 
                              goalmenu, NULL);
Index: common/capstr.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/capstr.c,v
retrieving revision 1.120
diff -u -r1.120 capstr.c
--- common/capstr.c     2003/02/01 02:10:45     1.120
+++ common/capstr.c     2003/02/02 12:29:34
@@ -76,7 +76,7 @@
 
 #define CAPABILITY "+1.14.0 conn_info +occupied team tech_impr_gfx " \
                    "city_struct_minor_cleanup obsolete_last class_legend" \
-                   "+impr_req"
+                   "+impr_req root_tech"
   
 /* "+1.14.0" is protocol for 1.14.0 release.
  *
@@ -102,6 +102,8 @@
  *
  * "impr_req" is the ability to have city improvements as a prerequisite for
  * building specific types of units
+ *
+ * "root_tech" restricts technology transfers between players.
  */
 
 void init_our_capability(void)
Index: common/government.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/government.c,v
retrieving revision 1.38
diff -u -r1.38 government.c
--- common/government.c 2003/01/29 05:10:50     1.38
+++ common/government.c 2003/02/02 12:29:34
@@ -246,7 +246,7 @@
         government >= 0 && government < game.government_count);
 
   req = governments[government].required_tech;
-  if (!tech_exists(req)) {
+  if (!tech_is_available(pplayer, req)) {
     return FALSE;
   } else {
     return (get_invention(pplayer, req) == TECH_KNOWN
Index: common/packets.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.c,v
retrieving revision 1.232
diff -u -r1.232 packets.c
--- common/packets.c    2003/02/01 02:10:45     1.232
+++ common/packets.c    2003/02/02 12:29:34
@@ -2048,6 +2048,9 @@
   dio_put_uint8(&dout, packet->id);
   dio_put_uint8(&dout, packet->req[0]);
   dio_put_uint8(&dout, packet->req[1]);
+  if (has_capability("root_tech", pc->capability)) {
+    dio_put_uint8(&dout, packet->root_req);
+  }
   dio_put_uint32(&dout, packet->flags);
   dio_put_uint32(&dout, packet->preset_cost);
   dio_put_uint32(&dout, packet->num_reqs);
@@ -2078,6 +2081,9 @@
   dio_get_uint8(&din, &packet->id);
   dio_get_uint8(&din, &packet->req[0]);
   dio_get_uint8(&din, &packet->req[1]);
+  if (has_capability("root_tech", pc->capability)) {
+    dio_get_uint8(&din, &packet->root_req);
+  }
   dio_get_uint32(&din, &packet->flags);
   dio_get_uint32(&din, &packet->preset_cost);
   dio_get_uint32(&din, &packet->num_reqs);
Index: common/packets.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.h,v
retrieving revision 1.133
diff -u -r1.133 packets.h
--- common/packets.h    2003/02/01 02:10:45     1.133
+++ common/packets.h    2003/02/02 12:29:34
@@ -15,6 +15,7 @@
 
 #include "connection.h"                /* struct connection, MAX_LEN_* */
 #include "map.h"
+#include "nation.h"
 #include "player.h"
 #include "shared.h"            /* MAX_LEN_NAME, MAX_LEN_ADDR */
 #include "spaceship.h"
@@ -635,7 +636,7 @@
 };
 
 struct packet_ruleset_tech {
-  int id, req[2];              /* indices for advances[] */
+  int id, req[2], root_req;    /* indices for advances[] */
   int flags;
   char name[MAX_LEN_NAME];
   char graphic_str[MAX_LEN_NAME];
Index: common/tech.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/tech.c,v
retrieving revision 1.56
diff -u -r1.56 tech.c
--- common/tech.c       2003/01/22 19:55:08     1.56
+++ common/tech.c       2003/02/02 12:29:34
@@ -94,7 +94,8 @@
 {
   /* The is_tech_a_req_for_goal condition is true if the tech is
    * already marked */
-  if (!tech_exists(tech) || get_invention(pplayer, tech) == TECH_KNOWN
+  if (!tech_is_available(pplayer, tech)
+      || get_invention(pplayer, tech) == TECH_KNOWN
       || is_tech_a_req_for_goal(pplayer, tech, goal)) {
     return;
   }
@@ -155,6 +156,25 @@
 }
 
 /**************************************************************************
+  Returns TRUE iff the given tech is ever reachable by the given player
+  by checking tech tree limitations.
+**************************************************************************/
+bool tech_is_available(struct player *pplayer, Tech_Type_id id)
+{
+  if (!tech_exists(id)) {
+    return FALSE;
+  }
+
+  if (advances[id].root_req != A_NONE && advances[id].root_req != A_LAST
+      && get_invention(pplayer, advances[id].root_req) != TECH_KNOWN) {
+    /* This tech requires knowledge of another tech before being 
+     * available. Prevents sharing of untransferable techs. */
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**************************************************************************
   Marks reachable techs. Calls build_required_techs to update the
   cache of requirements.
 **************************************************************************/
@@ -164,7 +184,7 @@
   enum tech_flag_id flag;
 
   for (i = 0; i < game.num_tech_types; i++) {
-    if (!tech_exists(i)) {
+    if (!tech_is_available(pplayer, i)) {
       set_invention(pplayer, i, TECH_UNKNOWN);
     } else {
       if (get_invention(pplayer, i) == TECH_REACHABLE) {
@@ -199,7 +219,8 @@
 {
   Tech_Type_id sub_goal;
 
-  if (!tech_exists(goal) || get_invention(pplayer, goal) == TECH_KNOWN) {
+  if (!tech_is_available(pplayer, goal)
+      || get_invention(pplayer, goal) == TECH_KNOWN) {
     return A_UNSET;
   }
   if (get_invention(pplayer, goal) == TECH_REACHABLE) {
@@ -221,7 +242,8 @@
 **************************************************************************/
 Tech_Type_id get_next_tech(struct player *pplayer, Tech_Type_id goal)
 {
-  if (!tech_exists(goal) || get_invention(pplayer, goal) == TECH_KNOWN) {
+  if (!tech_is_available(pplayer, goal)
+      || get_invention(pplayer, goal) == TECH_KNOWN) {
     return A_UNSET;
   }
   return (get_next_tech_rec(pplayer, goal));
Index: common/tech.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/tech.h,v
retrieving revision 1.38
diff -u -r1.38 tech.h
--- common/tech.h       2003/01/13 23:27:12     1.38
+++ common/tech.h       2003/02/02 12:29:34
@@ -15,6 +15,8 @@
 
 #include "shared.h"
 
+#include "nation.h" /* Nation_Type_id */
+
 struct player;
 
 typedef int Tech_Type_id;
@@ -75,9 +77,10 @@
 struct advance {
   char name[MAX_LEN_NAME];
   char name_orig[MAX_LEN_NAME];              /* untranslated */
-  char graphic_str[MAX_LEN_NAME];      /* which named sprite to use */
-  char graphic_alt[MAX_LEN_NAME];      /* alternate icon name */
-  int req[2];
+  char graphic_str[MAX_LEN_NAME];     /* which named sprite to use */
+  char graphic_alt[MAX_LEN_NAME];     /* alternate icon name */
+  Tech_Type_id req[2];
+  Tech_Type_id root_req;              /* A_NONE or A_LAST means unrestricted */
   unsigned int flags;
   char *helptext;
 
@@ -107,6 +110,7 @@
 void update_research(struct player *pplayer);
 Tech_Type_id get_next_tech(struct player *pplayer, Tech_Type_id goal);
 
+bool tech_is_available(struct player *pplayer, Tech_Type_id id);
 bool tech_exists(Tech_Type_id id);
 Tech_Type_id find_tech_by_name(const char *s);
 
Index: data/default/techs.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/default/techs.ruleset,v
retrieving revision 1.21
diff -u -r1.21 techs.ruleset
--- data/default/techs.ruleset  2003/01/03 08:58:48     1.21
+++ data/default/techs.ruleset  2003/02/02 12:29:34
@@ -22,6 +22,9 @@
 ;
 ; name          = name as seen by user 
 ; req1, req2   = advances required before researching this one
+; root_req      = advance required before acquiring this one, inherited
+;                 by all techs that require this tech in turn unless
+;                 "None" is given explicitly
 ; flags         = special flag strings
 ; graphic       = icon for technology
 ; graphic_alt   = alternate icon
Index: server/diplhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/diplhand.c,v
retrieving revision 1.65
diff -u -r1.65 diplhand.c
--- server/diplhand.c   2002/11/15 21:24:30     1.65
+++ server/diplhand.c   2003/02/02 12:29:34
@@ -147,6 +147,16 @@
       if (pclause->from == pplayer) {
        switch(pclause->type) {
        case CLAUSE_ADVANCE:
+          if (!tech_is_available(other, pclause->value)) {
+           freelog(LOG_ERROR, "Treaty: The %s can't have tech %s",
+                    get_nation_name_plural(other->nation),
+                    advances[pclause->value].name);
+           notify_player(pplayer,
+                          _("Game: The %s can't accept %s."),
+                          get_nation_name_plural(other->nation),
+                          advances[pclause->value].name);
+           return;
+          }
          if (get_invention(pplayer, pclause->value) != TECH_KNOWN) {
            freelog(LOG_ERROR,
                     "The %s don't know tech %s, but try to give it to the %s.",
Index: server/diplomats.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/diplomats.c,v
retrieving revision 1.33
diff -u -r1.33 diplomats.c
--- server/diplomats.c  2002/12/11 10:39:42     1.33
+++ server/diplomats.c  2003/02/02 12:29:34
@@ -559,8 +559,9 @@
   /* Examine the civilization for technologies to steal. */
   count = 0;
   for (index = A_FIRST; index < game.num_tech_types; index++) {
-    if ((get_invention (pplayer, index) != TECH_KNOWN) &&
-       (get_invention (cplayer, index) == TECH_KNOWN)) {
+    if (get_invention(pplayer, index) != TECH_KNOWN
+       && get_invention(cplayer, index) == TECH_KNOWN
+        && tech_is_available(pplayer, index)) {
       count++;
     }
   }
@@ -590,8 +591,9 @@
     target = -1;
     which = myrand (count);
     for (index = A_FIRST; index < game.num_tech_types; index++) {
-      if ((get_invention (pplayer, index) != TECH_KNOWN) &&
-         (get_invention (cplayer, index) == TECH_KNOWN)) {
+      if (get_invention(pplayer, index) != TECH_KNOWN
+         && get_invention(cplayer, index) == TECH_KNOWN
+          && tech_is_available(pplayer, index)) {
        if (which > 0) {
          which--;
        } else {
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.258
diff -u -r1.258 plrhand.c
--- server/plrhand.c    2003/01/29 09:39:38     1.258
+++ server/plrhand.c    2003/02/02 12:29:34
@@ -127,7 +127,8 @@
   if (find_city_wonder(B_GREAT)) {
     if (pplayer->player_no==find_city_wonder(B_GREAT)->owner) {
       for (i=0;i<game.num_tech_types;i++) {
-       if (get_invention(pplayer, i)!=TECH_KNOWN 
+       if (get_invention(pplayer, i) != TECH_KNOWN
+            && tech_is_available(pplayer, i)
            && game.global_advances[i]>=2) {
          notify_player_ex(pplayer, -1, -1, E_TECH_GAIN,
                           _("Game: %s acquired from The Great Library!"),
@@ -215,6 +216,8 @@
          && get_invention(plr, tech_found) != TECH_KNOWN)
         || tech_found == A_FUTURE);
 
+  assert(tech_is_available(plr, tech_found));
+
   plr->got_tech = TRUE;
   plr->research.techs_researched++;
   was_first = (game.global_advances[tech_found] == 0);
@@ -580,8 +583,9 @@
   int i;
   int j=0;
   for (i=0;i<game.num_tech_types;i++) {
-    if (get_invention(pplayer, i)!=TECH_KNOWN && 
-       get_invention(target, i)== TECH_KNOWN) {
+    if (get_invention(pplayer, i) != TECH_KNOWN
+       && get_invention(target, i) == TECH_KNOWN
+        && tech_is_available(pplayer, i)) {
       j++;
     }
   }
@@ -598,8 +602,9 @@
     /* pick random tech */
     j = myrand(j) + 1;
     for (i = 0; i < game.num_tech_types; i++) {
-      if (get_invention(pplayer, i) != TECH_KNOWN &&
-         get_invention(target, i) == TECH_KNOWN) {
+      if (get_invention(pplayer, i) != TECH_KNOWN
+         && get_invention(target, i) == TECH_KNOWN
+          && tech_is_available(pplayer, i)) {
        j--;
       }
       if (j == 0) {
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.134
diff -u -r1.134 ruleset.c
--- server/ruleset.c    2003/02/01 02:10:46     1.134
+++ server/ruleset.c    2003/02/02 12:29:34
@@ -204,8 +204,8 @@
   char *sval;
   int i;
   
-  sval = secfile_lookup_str(file, "%s.%s", prefix, entry);
-  if (!required && strcmp(sval, "Never")==0) {
+  sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
+  if (!sval || (!required && strcmp(sval, "Never") == 0)) {
     i = A_LAST;
   } else {
     i = find_tech_by_name(sval);
@@ -495,6 +495,7 @@
   advances[A_NONE].req[0] = A_NONE;
   advances[A_NONE].req[1] = A_NONE;
   advances[A_NONE].flags = 0;
+  advances[A_NONE].root_req = A_LAST;
 
   a = &advances[A_FIRST];
   
@@ -504,7 +505,8 @@
 
     a->req[0] = lookup_tech(file, sec[i], "req1", FALSE, filename, a->name);
     a->req[1] = lookup_tech(file, sec[i], "req2", FALSE, filename, a->name);
-    
+    a->root_req = lookup_tech(file, sec[i], "root_req", FALSE, filename, 
a->name);
+
     if ((a->req[0]==A_LAST && a->req[1]!=A_LAST) ||
        (a->req[0]!=A_LAST && a->req[1]==A_LAST)) {
       freelog(LOG_ERROR, "for tech %s: \"Never\" with non-\"Never\" (%s)",
@@ -550,6 +552,26 @@
     a++;
   }
 
+  /* Propagate a root tech up into the tech tree */
+  for(i = A_FIRST; i < num_techs; i++) {
+    a = &advances[i];
+    if (a->root_req != A_LAST && tech_exists(i)) {
+      int j;
+
+      for(j = 0; j < num_techs; j++) {
+        a = &advances[j];
+        if (a->req[0] == i || a->req[1] == i) {
+          if (a->root_req == A_LAST) {
+            a->root_req = i;
+          } else if (a->root_req != i) {
+            die("Tech %s has two root technologies - this is illegal.",
+                a->name);
+          }
+        }
+      }
+    }
+  }
+
   /* Some more consistency checking: 
      Non-removed techs depending on removed techs is too
      broken to fix by default, so die.
@@ -2472,6 +2494,7 @@
     sz_strlcpy(packet.graphic_alt, a->graphic_alt);      
     packet.req[0] = a->req[0];
     packet.req[1] = a->req[1];
+    packet.root_req = a->root_req;
     packet.flags = a->flags;
     packet.preset_cost = a->preset_cost;
     packet.num_reqs = a->num_reqs;

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