Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2002:
[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]
To: undisclosed-recipients:;
Subject: [Freeciv-Dev] (PR#2464) patch: restrict techs by nation
From: "Per I. Mathisen via RT" <rt@xxxxxxxxxxxxxx>
Date: Sun, 1 Dec 2002 06:42:50 -0800
Reply-to: rt@xxxxxxxxxxxxxx

This patch adds the ability to restrict the availability of certain techs
to certain nations. Just add a new field "nations" to the [tech_name] box
of tech.ruleset which, if it has any entries, is a list of nations that
have this tech exclusively. Other nations cannot research it, steal it,
conquer it, find it or otherwise obtain it.

Testers and reviewers wanted. Comments on design desired.

  - Per

Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.263
diff -u -r1.263 packhand.c
--- client/packhand.c   23 Nov 2002 02:55:42 -0000      1.263
+++ client/packhand.c   30 Nov 2002 21:24:13 -0000
@@ -1788,7 +1788,7 @@
   a->flags = p->flags;
   a->preset_cost = p->preset_cost;
   a->num_reqs = p->num_reqs;
-  
+  a->nation_req = p->nation_req; /* pointer assignment */
   a->helptext = p->helptext;   /* pointer assignment */
 }
 
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   15 Nov 2002 21:24:28 -0000      1.38
+++ client/gui-gtk/diplodlg.c   30 Nov 2002 21:24:13 -0000
@@ -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-2.0/diplodlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/diplodlg.c,v
retrieving revision 1.7
diff -u -r1.7 diplodlg.c
--- client/gui-gtk-2.0/diplodlg.c       15 Nov 2002 23:40:05 -0000      1.7
+++ client/gui-gtk-2.0/diplodlg.c       30 Nov 2002 21:24:13 -0000
@@ -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-mui/diplodlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/diplodlg.c,v
retrieving revision 1.14
diff -u -r1.14 diplodlg.c
--- client/gui-mui/diplodlg.c   15 Nov 2002 21:24:29 -0000      1.14
+++ client/gui-mui/diplodlg.c   30 Nov 2002 21:24:13 -0000
@@ -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-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 17 Nov 2002 19:22:24 -0000      1.12
+++ client/gui-win32/diplodlg.c 30 Nov 2002 21:24:13 -0000
@@ -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-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   15 Nov 2002 21:24:29 -0000      1.34
+++ client/gui-xaw/diplodlg.c   30 Nov 2002 21:24:13 -0000
@@ -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: common/capstr.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/capstr.c,v
retrieving revision 1.115
diff -u -r1.115 capstr.c
--- common/capstr.c     14 Nov 2002 09:15:01 -0000      1.115
+++ common/capstr.c     30 Nov 2002 21:24:13 -0000
@@ -74,7 +74,7 @@
  * are not directly related to the capability strings discussed here.)
  */
 
-#define CAPABILITY "+1.14.0 conn_info +occupied team"
+#define CAPABILITY "+1.14.0 conn_info +occupied team nation_req"
   
 /* "+1.14.0" is protocol for 1.14.0 release.
   
Index: common/packets.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.c,v
retrieving revision 1.226
diff -u -r1.226 packets.c
--- common/packets.c    14 Nov 2002 09:15:02 -0000      1.226
+++ common/packets.c    30 Nov 2002 21:24:13 -0000
@@ -2029,6 +2029,8 @@
 int send_packet_ruleset_tech(struct connection *pc,
                             const struct packet_ruleset_tech *packet)
 {
+  int count, i;
+
   SEND_PACKET_START(PACKET_RULESET_TECH);
 
   dio_put_uint8(&dout, packet->id);
@@ -2037,8 +2039,21 @@
   dio_put_uint32(&dout, packet->flags);
   dio_put_uint32(&dout, packet->preset_cost);
   dio_put_uint32(&dout, packet->num_reqs);
-  dio_put_string(&dout, packet->name);
   
+  if (has_capability("nation_req", pc->capability)) {
+    /* Send nation requirements */
+    for (count = 0; packet->nation_req[count] != -1; count++) {
+      /* nothing */
+    }
+    dio_put_uint16(&dout, count);
+    for (i = 0; i < count; i++) {
+      assert(packet->nation_req[i] >= -1
+             && packet->nation_req[i] <= MAX_NUM_NATIONS);
+      dio_put_uint16(&dout, packet->nation_req[i]);
+    }
+  }
+
+  dio_put_string(&dout, packet->name);
   /* This must be last, so client can determine length: */
   if(packet->helptext) {
     dio_put_string(&dout, packet->helptext);
@@ -2053,7 +2068,7 @@
 struct packet_ruleset_tech *
 receive_packet_ruleset_tech(struct connection *pc)
 {
-  int len;
+  int len, count, i;
   RECEIVE_PACKET_START(packet_ruleset_tech, packet);
 
   dio_get_uint8(&din, &packet->id);
@@ -2062,8 +2077,20 @@
   dio_get_uint32(&din, &packet->flags);
   dio_get_uint32(&din, &packet->preset_cost);
   dio_get_uint32(&din, &packet->num_reqs);
-  dio_get_string(&din, packet->name, sizeof(packet->name));
 
+  if (has_capability("nation_req", pc->capability)) {
+    /* Get nation requirements */
+    dio_get_uint16(&din, &count);
+    packet->nation_req = fc_malloc((count + 1) * 
sizeof(packet->nation_req[0]));
+    for (i = 0; i < count; i++) {
+      dio_get_uint16(&din, &packet->nation_req[i]);
+      assert(packet->nation_req[i] >= -1
+             && packet->nation_req[i] <= MAX_NUM_NATIONS);
+    }
+    packet->nation_req[count] = -1;
+  }
+
+  dio_get_string(&din, packet->name, sizeof(packet->name));
   len = dio_input_remaining(&din);
   if (len > 0) {
     packet->helptext = fc_malloc(len);
Index: common/packets.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.h,v
retrieving revision 1.129
diff -u -r1.129 packets.h
--- common/packets.h    11 Nov 2002 10:00:47 -0000      1.129
+++ common/packets.h    30 Nov 2002 21:24:13 -0000
@@ -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"
@@ -641,6 +642,7 @@
   char *helptext;              /* same as for packet_ruleset_unit, above */
   int preset_cost;
   int num_reqs;
+  Nation_Type_id *nation_req;
 };
 
 struct packet_ruleset_building {
Index: common/tech.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/tech.c,v
retrieving revision 1.51
diff -u -r1.51 tech.c
--- common/tech.c       14 Nov 2002 09:15:03 -0000      1.51
+++ common/tech.c       30 Nov 2002 21:24:13 -0000
@@ -95,7 +95,7 @@
 {
   /* The is_tech_a_req_for_goal condition is true if the tech is
    * already marked */
-  if (tech == A_NONE || !tech_exists(tech)
+  if (tech == A_NONE || !tech_is_available(pplayer, tech)
       || get_invention(pplayer, tech) == TECH_KNOWN
       || is_tech_a_req_for_goal(pplayer, tech, goal)) {
     return;
@@ -157,6 +157,30 @@
 }
 
 /**************************************************************************
+  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)
+{
+  int j = 0;
+
+  if (!tech_exists(id)) {
+    return FALSE;
+  }
+
+  if (advances[id].nation_req[0] != -1) {
+    while (advances[id].nation_req[j] != -1) {
+      if (advances[id].nation_req[j] == pplayer->nation) {
+        return TRUE;
+      }
+      j++;
+    }
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**************************************************************************
   Marks reachable techs. Calls build_required_techs to update the
   cache of requirements.
 **************************************************************************/
@@ -166,7 +190,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) {
@@ -201,7 +225,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_NONE;
   }
   if (get_invention(pplayer, goal) == TECH_REACHABLE) {
@@ -223,8 +248,8 @@
 **************************************************************************/
 Tech_Type_id get_next_tech(struct player *pplayer, Tech_Type_id goal)
 {
-  if (goal == A_NONE || !tech_exists(goal) ||
-      get_invention(pplayer, goal) == TECH_KNOWN) {
+  if (goal == A_NONE || !tech_is_available(pplayer, goal)
+      || get_invention(pplayer, goal) == TECH_KNOWN) {
     return A_NONE;
   }
   return (get_next_tech_rec(pplayer, goal));
Index: common/tech.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/tech.h,v
retrieving revision 1.35
diff -u -r1.35 tech.h
--- common/tech.h       1 Nov 2002 17:40:46 -0000       1.35
+++ common/tech.h       30 Nov 2002 21:24:14 -0000
@@ -15,6 +15,8 @@
 
 #include "shared.h"
 
+#include "nation.h" /* Nation_Type_id */
+
 struct player;
 
 typedef int Tech_Type_id;
@@ -86,6 +88,12 @@
    * itself. Precalculated at server then send to client.
    */
   int num_reqs;
+
+  /* 
+   * Unless the FIRST int is -1, this is a list of nations that 
+   * can have this tech and no others can. The list is -1 terminated.
+   */
+  Nation_Type_id *nation_req;
 };
 
 enum tech_state get_invention(struct player *pplayer, Tech_Type_id tech);
@@ -94,6 +102,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: 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   15 Nov 2002 21:24:30 -0000      1.65
+++ server/diplhand.c   30 Nov 2002 21:24:14 -0000
@@ -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.32
diff -u -r1.32 diplomats.c
--- server/diplomats.c  14 Nov 2002 09:15:04 -0000      1.32
+++ server/diplomats.c  30 Nov 2002 21:24:14 -0000
@@ -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.250
diff -u -r1.250 plrhand.c
--- server/plrhand.c    14 Nov 2002 09:15:04 -0000      1.250
+++ server/plrhand.c    30 Nov 2002 21:24:14 -0000
@@ -123,7 +123,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!"),
@@ -207,6 +208,8 @@
   bool macro_polo_was_obsolete = wonder_obsolete(B_MARCO);
   struct city *pcity;
 
+  assert(tech_is_available(plr, tech_found));
+
   plr->got_tech = TRUE;
   plr->research.techs_researched++;
   was_first = (game.global_advances[tech_found] == 0);
@@ -570,8 +573,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++;
     }
   }
@@ -588,8 +592,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.126
diff -u -r1.126 ruleset.c
--- server/ruleset.c    26 Nov 2002 12:24:56 -0000      1.126
+++ server/ruleset.c    30 Nov 2002 21:24:14 -0000
@@ -495,6 +495,9 @@
   advances[A_NONE].req[0] = A_NONE;
   advances[A_NONE].req[1] = A_NONE;
   advances[A_NONE].flags = 0;
+  advances[A_NONE].nation_req =
+                 fc_malloc(sizeof(advances[A_NONE].nation_req[0]));
+  advances[A_NONE].nation_req[0] = -1;
 
   a = &advances[A_FIRST];
   
@@ -535,6 +538,14 @@
     }
     free(slist);
 
+    slist = secfile_lookup_str_vec(file, &nval, "%s.nations", sec[i]);
+    a->nation_req = fc_malloc((nval + 1) * sizeof(a->nation_req[0]));
+    for (j = 0; j < nval; j++) {
+      a->nation_req[j] = find_nation_by_name(slist[j]);
+    }
+    a->nation_req[j] = -1; /* terminate last */
+    free(slist);
+
     a->helptext = lookup_helptext(file, sec[i]);    
     a->bonus_message = lookup_string(file, sec[i], "bonus_message");
     a->preset_cost =
@@ -2431,6 +2442,7 @@
     packet.flags = a->flags;
     packet.preset_cost = a->preset_cost;
     packet.num_reqs = a->num_reqs;
+    packet.nation_req = a->nation_req; /* pointer assignment */
     packet.helptext = a->helptext;   /* pointer assignment */
 
     lsend_packet_ruleset_tech(dest, &packet);
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.197
diff -u -r1.197 unittools.c
--- server/unittools.c  22 Nov 2002 17:44:45 -0000      1.197
+++ server/unittools.c  30 Nov 2002 21:24:15 -0000
@@ -1335,7 +1335,7 @@
   if requirements to make partisans when a city is conquered is fullfilled
   this routine makes a lot of partisans based on the city's size.
   To be candidate for partisans the following things must be satisfied:
-  1) Guerilla warfare must be known by atleast 1 player
+  1) The tech requirement for guerilla warfare must exist in the ruleset.
   2) The owner of the city is the original player.
   3) The player must know about communism and gunpowder
   4) the player must run either a democracy or a communist society.

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