<URL: http://bugs.freeciv.org/Ticket/Display.html?id=34431 >

 This adds new requirement type: minimum AI level. This allows
creating cheating effects for hard level AI in effects.ruleset.
 This is just first version. More work is needed before this can go
in. There probably should be two requirement types instead of one:
'Minimum AI level' (as in this patch) for creating bonus effects for
hard level AI and 'Maximum AI level' for creating penalties for novice
level AI.

 Making this required more changes to ai level name handling than I
anticipated. I'll probably split those changes to separate patch to be
committed first.


 - ML

diff -Nurd -X.diff_ignore freeciv/client/gui-gtk-2.0/gui_main.c freeciv/client/gui-gtk-2.0/gui_main.c
--- freeciv/client/gui-gtk-2.0/gui_main.c	2007-01-10 18:13:57.000000000 +0200
+++ freeciv/client/gui-gtk-2.0/gui_main.c	2007-01-24 14:10:24.000000000 +0200
@@ -1522,21 +1522,8 @@
       } conn_list_iterate_end;
 
       if (pplayer->ai.control) {
-	sz_strlcpy(name, _("<AI>"));
-	switch (pplayer->ai.skill_level) {
-	case 2:
-	  sz_strlcpy(name, _("<Novice AI>"));
-	  break;
-	case 3:
-	  sz_strlcpy(name, _("<Easy AI>"));
-	  break;
-	case 5:
-	  sz_strlcpy(name, _("<Normal AI>"));
-	  break;
-	case 7:
-	  sz_strlcpy(name, _("<Hard AI>"));
-	  break;
-	}
+        my_snprintf(name, sizeof(name), _("<%s AI>"),
+                    name_of_ai_level(pplayer->ai.skill_level));
       } else if (access_level <= ALLOW_INFO) {
 	sz_strlcpy(name, pplayer->username);
       } else {
diff -Nurd -X.diff_ignore freeciv/client/helpdata.c freeciv/client/helpdata.c
--- freeciv/client/helpdata.c	2007-01-23 16:05:15.000000000 +0200
+++ freeciv/client/helpdata.c	2007-01-24 14:13:30.000000000 +0200
@@ -210,6 +210,10 @@
     cat_snprintf(buf, bufsz, _("Requires a minimum size of %d.\n\n"),
 		 req->source.value.minsize);
     return;
+  case REQ_AI:
+    cat_snprintf(buf, bufsz, _("Requires AI player of level %s or higher.\n\n"),
+                 name_of_ai_level(req->source.value.level));
+    return;
   }
   assert(0);
 }
diff -Nurd -X.diff_ignore freeciv/common/fc_types.h freeciv/common/fc_types.h
--- freeciv/common/fc_types.h	2006-07-17 23:56:46.000000000 +0300
+++ freeciv/common/fc_types.h	2007-01-24 13:19:21.000000000 +0200
@@ -162,4 +162,12 @@
 #define DIR8_LAST 8
 #define DIR8_COUNT DIR8_LAST
 
+/* AI levels. This must correspond to ai_level_names[] in player.c */
+enum ai_level { AI_LEVEL_NOVICE       = 2,
+                AI_LEVEL_EASY         = 3,
+                AI_LEVEL_NORMAL       = 5,
+                AI_LEVEL_HARD         = 7,
+                AI_LEVEL_EXPERIMENTAL = 10,
+                AI_LEVEL_LAST};
+
 #endif /* FC__FC_TYPES_H */
diff -Nurd -X.diff_ignore freeciv/common/player.c freeciv/common/player.c
--- freeciv/common/player.c	2006-07-17 23:56:46.000000000 +0300
+++ freeciv/common/player.c	2007-01-24 13:40:28.000000000 +0200
@@ -34,6 +34,14 @@
 
 #include "player.h"
 
+/* Names of AI levels. These must correspond to enum ai_level in
+ * player.h. Also set_ai_level() calls in handle_stdin_input()
+ * must use same level names as present here. */
+static const char *ai_level_names[] = {
+  NULL, NULL, "Novice", "Easy", NULL, "Normal",
+  NULL, "Hard", NULL, NULL, "Experimental"
+};
+
 /***************************************************************
   Returns true iff p1 can cancel treaty on p2.
 
@@ -834,3 +842,34 @@
   }
   return &(plr->team->research);
 }
+
+/****************************************************************************
+  Returns AI level associated with level name
+****************************************************************************/
+enum ai_level find_ai_level_by_name(const char *name)
+{
+  enum ai_level level;
+
+  for (level = 0; level < AI_LEVEL_LAST; level++) {
+    if (ai_level_names[level] != NULL) {
+      /* Only consider levels that really have names */
+      if (mystrcasecmp(ai_level_names[level], name) == 0) {
+        return level;
+      }
+    }
+  }
+
+  /* No level matches name */
+  return AI_LEVEL_LAST;
+}
+
+/***************************************************************
+  Return name of the AI level
+***************************************************************/
+const char *name_of_ai_level(enum ai_level level)
+{
+  assert(level >= 0 && level < AI_LEVEL_LAST
+         && ai_level_names[level] != NULL);
+
+  return ai_level_names[level];
+}
diff -Nurd -X.diff_ignore freeciv/common/player.h freeciv/common/player.h
--- freeciv/common/player.h	2007-01-24 12:25:59.000000000 +0200
+++ freeciv/common/player.h	2007-01-24 13:52:43.000000000 +0200
@@ -104,7 +104,7 @@
   /* The units of tech_want seem to be shields */
   int tech_want[A_LAST+1];
   int handicap;			/* sum of enum handicap_type */
-  int skill_level;		/* 0-10 value for save/load/display */
+  enum ai_level skill_level;   	/* 0-10 value for save/load/display */
   int fuzzy;			/* chance in 1000 to mis-decide */
   int expand;			/* percentage factor to value new cities */
   int science_cost;             /* Cost in bulbs to get new tech, relative
@@ -304,5 +304,7 @@
 /* User functions. */
 bool is_valid_username(const char *name);
 
+enum ai_level find_ai_level_by_name(const char *name);
+const char *name_of_ai_level(enum ai_level level);
 
 #endif  /* FC__PLAYER_H */
diff -Nurd -X.diff_ignore freeciv/common/requirements.c freeciv/common/requirements.c
--- freeciv/common/requirements.c	2006-07-17 23:56:46.000000000 +0300
+++ freeciv/common/requirements.c	2007-01-24 13:50:16.000000000 +0200
@@ -41,7 +41,8 @@
   "UnitClass",
   "OutputType",
   "Specialist",
-  "MinSize"
+  "MinSize",
+  "AI"
 };
 
 /* Names of requirement ranges. These must correspond to enum req_range in
@@ -174,6 +175,12 @@
       return source;
     }
     break;
+  case REQ_AI:
+    source.value.level = find_ai_level_by_name(value);
+    if (source.value.level != AI_LEVEL_LAST) {
+      return source;
+    }
+    break;
   case REQ_LAST:
     break;
   }
@@ -232,6 +239,9 @@
   case REQ_MINSIZE:
     source.value.minsize = value;
     return source;
+  case REQ_AI:
+    source.value.level = value;
+    return source;
   case REQ_LAST:
     return source;
   }
@@ -291,6 +301,9 @@
   case REQ_MINSIZE:
     *value = source->value.minsize;
     return;
+  case REQ_AI:
+    *value = source->value.level;
+    return;
   case REQ_LAST:
     break;
   }
@@ -339,6 +352,7 @@
     case REQ_GOV:
     case REQ_TECH:
     case REQ_NATION:
+    case REQ_AI:
       req.range = REQ_RANGE_PLAYER;
       break;
     }
@@ -359,6 +373,7 @@
     invalid = (req.range < REQ_RANGE_PLAYER);
     break;
   case REQ_GOV:
+  case REQ_AI:
     invalid = (req.range != REQ_RANGE_PLAYER);
     break;
   case REQ_BUILDING:
@@ -860,6 +875,11 @@
   case REQ_MINSIZE:
     eval = target_city && target_city->size >= req->source.value.minsize;
     break;
+  case REQ_AI:
+    eval = target_player
+      && target_player->ai.control
+      && target_player->ai.skill_level >= req->source.value.level;
+    break;
   case REQ_LAST:
     assert(0);
     return FALSE;
@@ -922,6 +942,7 @@
   case REQ_NONE:
   case REQ_OUTPUTTYPE:
   case REQ_SPECIALIST: /* Only so long as it's at local range only */
+  case REQ_AI:
     return TRUE;
   case REQ_TECH:
   case REQ_GOV:
@@ -982,6 +1003,8 @@
     return psource1->value.specialist == psource2->value.specialist;
   case REQ_MINSIZE:
     return psource1->value.minsize == psource2->value.minsize;
+  case REQ_AI:
+    return psource1->value.level == psource2->value.level;
   case REQ_LAST:
     break;
   }
@@ -1040,6 +1063,10 @@
     cat_snprintf(buf, bufsz, _("Size %d"),
 		 psource->value.minsize);
     break;
+  case REQ_AI:
+    cat_snprintf(buf, bufsz, _("AI minimum level: %s"),
+                 name_of_ai_level(psource->value.level));
+    break;
   case REQ_LAST:
     assert(0);
     break;
diff -Nurd -X.diff_ignore freeciv/common/requirements.h freeciv/common/requirements.h
--- freeciv/common/requirements.h	2006-07-17 23:56:46.000000000 +0300
+++ freeciv/common/requirements.h	2007-01-24 13:19:36.000000000 +0200
@@ -35,6 +35,7 @@
   REQ_OUTPUTTYPE,
   REQ_SPECIALIST,
   REQ_MINSIZE, /* Minimum size: at city range means city size */
+  REQ_AI,      /* AI level of the player */
   REQ_LAST
 };
 
@@ -67,6 +68,7 @@
     Output_type_id outputtype;          /* source output type */
     Specialist_type_id specialist;      /* specialist type */
     int minsize;                        /* source minsize type */
+    enum ai_level level;                /* source AI level */
   } value;                              /* source value */
 };
 
diff -Nurd -X.diff_ignore freeciv/server/cityturn.c freeciv/server/cityturn.c
--- freeciv/server/cityturn.c	2006-07-17 23:56:22.000000000 +0300
+++ freeciv/server/cityturn.c	2007-01-24 13:49:29.000000000 +0200
@@ -835,6 +835,21 @@
 				 API_TYPE_CITY, pcity,
 				 API_TYPE_STRING, "need_minsize");
 	      break;
+            case REQ_AI:
+	      /* FIXME: we should skip rather than postpone, since we'll
+	       * never be able to meet this req... */
+	      notify_player(pplayer, pcity->tile, E_CITY_CANTBUILD,
+			       _("%s can't build %s from the worklist; "
+				 "only AI of level %s or higher may build this.  "
+                                 "Postponing..."),
+			       pcity->name,
+			       get_impr_name_ex(pcity, building->index),
+			       name_of_ai_level(preq->source.value.level));
+	      script_signal_emit("building_cant_be_built", 3,
+				 API_TYPE_BUILDING_TYPE, building,
+				 API_TYPE_CITY, pcity,
+				 API_TYPE_STRING, "need_ai_level");
+	      break;
 	    case REQ_NONE:
 	    case REQ_LAST:
 	      assert(0);
diff -Nurd -X.diff_ignore freeciv/server/srv_main.c freeciv/server/srv_main.c
--- freeciv/server/srv_main.c	2007-01-20 01:44:41.000000000 +0200
+++ freeciv/server/srv_main.c	2007-01-24 13:43:13.000000000 +0200
@@ -1505,11 +1505,11 @@
     freelog(LOG_NORMAL,
 	    _("%s has been added as %s level AI-controlled player."),
             pplayer->name,
-	    name_of_skill_level(pplayer->ai.skill_level));
+	    name_of_ai_level(pplayer->ai.skill_level));
     notify_conn(NULL, NULL, E_SETTING,
 		_("%s has been added as %s level AI-controlled player."),
 		pplayer->name,
-		name_of_skill_level(pplayer->ai.skill_level));
+		name_of_ai_level(pplayer->ai.skill_level));
 
     game.info.nplayers++;
 
diff -Nurd -X.diff_ignore freeciv/server/stdinhand.c freeciv/server/stdinhand.c
--- freeciv/server/stdinhand.c	2007-01-24 12:25:59.000000000 +0200
+++ freeciv/server/stdinhand.c	2007-01-24 14:05:29.000000000 +0200
@@ -85,8 +85,10 @@
 static void show_teams(struct connection *caller);
 static void show_connections(struct connection *caller);
 static void show_scenarios(struct connection *caller);
-static bool set_ai_level(struct connection *caller, char *name, int level, 
-                         bool check);
+static bool set_ai_level_named(struct connection *caller, char *name,
+                               const char *level_name, bool check);
+static bool set_ai_level(struct connection *caller, char *name,
+                         enum ai_level level, bool check);
 static bool set_away(struct connection *caller, char *name, bool check);
 
 static bool observe_command(struct connection *caller, char *name, bool check);
@@ -659,20 +661,6 @@
 }
 
 /***************************************************************
- This could be in common/player if the client ever gets
- told the ai player skill levels.
-***************************************************************/
-const char *name_of_skill_level(int level)
-{
-  const char *nm[11] = { "UNUSED", "away", "novice", "easy",
-			 "UNKNOWN", "normal", "UNKNOWN", "hard",
-			 "UNKNOWN", "UNKNOWN", "experimental" };
-  
-  assert(level>0 && level<=10);
-  return nm[level];
-}
-
-/***************************************************************
 ...
 ***************************************************************/
 static int handicap_of_skill_level(int level)
@@ -1735,7 +1723,7 @@
 /******************************************************************
   Set an AI level and related quantities, with no feedback.
 ******************************************************************/
-void set_ai_level_directer(struct player *pplayer, int level)
+void set_ai_level_directer(struct player *pplayer, enum ai_level level)
 {
   pplayer->ai.handicap = handicap_of_skill_level(level);
   pplayer->ai.fuzzy = fuzzy_of_skill_level(level);
@@ -1765,21 +1753,31 @@
 /******************************************************************
   Set an AI level from the server prompt.
 ******************************************************************/
-void set_ai_level_direct(struct player *pplayer, int level)
+void set_ai_level_direct(struct player *pplayer, enum ai_level level)
 {
   set_ai_level_directer(pplayer,level);
   send_player_info(pplayer, NULL);
   cmd_reply(cmd_of_level(level), NULL, C_OK,
 	_("Player '%s' now has AI skill level '%s'."),
-	pplayer->name, name_of_skill_level(level));
+	pplayer->name, name_of_ai_level(level));
   
 }
 
 /******************************************************************
   Handle a user command to set an AI level.
 ******************************************************************/
+static bool set_ai_level_named(struct connection *caller, char *name,
+                               const char *level_name, bool check)
+{
+  enum ai_level level = find_ai_level_by_name(level_name);
+  return set_ai_level(caller, name, level, check);
+}
+
+/******************************************************************
+  Set AI level
+******************************************************************/
 static bool set_ai_level(struct connection *caller, char *name, 
-                         int level, bool check)
+                         enum ai_level level, bool check)
 {
   enum m_pre_result match_result;
   struct player *pplayer;
@@ -1797,7 +1795,7 @@
       send_player_info(pplayer, NULL);
       cmd_reply(cmd_of_level(level), caller, C_OK,
 		_("Player '%s' now has AI skill level '%s'."),
-		pplayer->name, name_of_skill_level(level));
+		pplayer->name, name_of_ai_level(level));
     } else {
       cmd_reply(cmd_of_level(level), caller, C_FAIL,
 		_("%s is not controlled by the AI."), pplayer->name);
@@ -1813,13 +1811,13 @@
 	send_player_info(pplayer, NULL);
         cmd_reply(cmd_of_level(level), caller, C_OK,
 		_("Player '%s' now has AI skill level '%s'."),
-		pplayer->name, name_of_skill_level(level));
+		pplayer->name, name_of_ai_level(level));
       }
     } players_iterate_end;
     game.info.skill_level = level;
     cmd_reply(cmd_of_level(level), caller, C_OK,
 		_("Default AI skill level set to '%s'."),
-		name_of_skill_level(level));
+		name_of_ai_level(level));
   } else {
     cmd_reply_no_such_player(cmd_of_level(level), caller, name, match_result);
     return FALSE;
@@ -3556,15 +3554,15 @@
   case CMD_AWAY:
     return set_away(caller, arg, check);
   case CMD_NOVICE:
-    return set_ai_level(caller, arg, 2, check);
+    return set_ai_level_named(caller, arg, "Novice", check);
   case CMD_EASY:
-    return set_ai_level(caller, arg, 3, check);
+    return set_ai_level_named(caller, arg, "Easy", check);
   case CMD_NORMAL:
-    return set_ai_level(caller, arg, 5, check);
+    return set_ai_level_named(caller, arg, "Normal", check);
   case CMD_HARD:
-    return set_ai_level(caller, arg, 7, check);
+    return set_ai_level_named(caller, arg, "Hard", check);
   case CMD_EXPERIMENTAL:
-    return set_ai_level(caller, arg, 10, check);
+    return set_ai_level_named(caller, arg, "Experimental", check);
   case CMD_QUIT:
     return quit_game(caller, check);
   case CMD_CUT:
@@ -4073,7 +4071,7 @@
       }
       if(pplayer->ai.control) {
 	cat_snprintf(buf2, sizeof(buf2), _(", difficulty level %s"),
-		     name_of_skill_level(pplayer->ai.skill_level));
+		     name_of_ai_level(pplayer->ai.skill_level));
       }
       if (!game.info.is_new_game) {
 	cat_snprintf(buf2, sizeof(buf2), _(", nation %s"),
diff -Nurd -X.diff_ignore freeciv/server/stdinhand.h freeciv/server/stdinhand.h
--- freeciv/server/stdinhand.h	2006-07-17 23:56:22.000000000 +0300
+++ freeciv/server/stdinhand.h	2007-01-24 13:55:49.000000000 +0200
@@ -26,8 +26,8 @@
 bool handle_stdin_input(struct connection *caller, char *str, bool check);
 void report_server_options(struct conn_list *dest, int which);
 void send_server_settings(struct conn_list *dest);
-void set_ai_level_direct(struct player *pplayer, int level);
-void set_ai_level_directer(struct player *pplayer, int level);
+void set_ai_level_direct(struct player *pplayer, enum ai_level level);
+void set_ai_level_directer(struct player *pplayer, enum ai_level level);
 bool read_init_script(struct connection *caller, char *script_filename,
                       bool from_cmdline);
 void show_players(struct connection *caller);
@@ -38,8 +38,6 @@
 void toggle_ai_player_direct(struct connection *caller,
 			     struct player *pplayer);
 
-const char *name_of_skill_level(int level);
-
 /* for sernet.c in initing a new connection */
 enum cmdlevel_id access_level_for_next_connection(void);
 
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to