Complete.Org: Mailing Lists: Archives: freeciv-dev: August 2004:
[Freeciv-Dev] Re: (PR#9685) Make server create a wiki server manual
Home

[Freeciv-Dev] Re: (PR#9685) Make server create a wiki server manual

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] Re: (PR#9685) Make server create a wiki server manual
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Thu, 19 Aug 2004 15:13:25 -0700
Reply-to: rt@xxxxxxxxxxx

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

New version. Can now create server commands, server options, wonders,
buildings and terrain manual pages. It is a bit kludgy.

Input on how this beast can be done in a more clean and nice way would be
appreciated. It is rather ugly.

  - Per

Index: common/improvement.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/improvement.c,v
retrieving revision 1.43
diff -u -r1.43 improvement.c
--- common/improvement.c        13 Aug 2004 15:59:12 -0000      1.43
+++ common/improvement.c        19 Aug 2004 22:07:59 -0000
@@ -17,6 +17,8 @@
 
 #include <assert.h>
 
+#include "astring.h"
+#include "fcintl.h"
 #include "game.h"
 #include "log.h"
 #include "map.h"
@@ -617,3 +618,59 @@
 
 #undef CHECK_CITY_IMPR 
 }
+
+/****************************************************************
+  Write misc dynamic text for improvements (not wonders).  buf
+  must be an initialized astring.
+*****************************************************************/
+void improvement_helptext(struct astring *buf, int which)
+{
+  struct impr_type *imp = &improvement_types[which];
+
+  if (which == B_AQUEDUCT) {
+    astr_add(buf, _("Allows a city to grow larger than size %d.  "),
+            game.aqueduct_size);
+    if (improvement_exists(B_SEWER)) {
+      astr_add(buf, _("(The %s improvement is also required for a city to grow"
+                      " larger than size %d.)  "), 
+               improvement_types[B_SEWER].name, game.sewer_size);
+    }
+    astr_add(buf, "\n");
+  }
+  if (which == B_SEWER) {
+    astr_add(buf, _("Allows a city to grow larger than size %d.  "),
+             game.sewer_size);
+  }
+  if (imp->helptext != NULL && imp->helptext[0] != '\0') {
+    astr_add(buf, "%s  ", _(imp->helptext));
+  }
+  if (which == B_BARRACKS
+      && tech_exists(improvement_types[B_BARRACKS].obsolete_by)
+      && tech_exists(improvement_types[B_BARRACKS2].obsolete_by)) {
+    astr_add(buf, _("\n\nNote that discovering %s or %s will obsolete"
+                    " any existing %s.  "),
+            advances[improvement_types[B_BARRACKS].obsolete_by].name,
+            advances[improvement_types[B_BARRACKS2].obsolete_by].name,
+            improvement_types[B_BARRACKS].name);
+  }
+  if (which == B_BARRACKS2
+      && tech_exists(improvement_types[B_BARRACKS2].obsolete_by)) {
+    astr_add(buf, _("\n\nThe discovery of %s will make %s obsolete.  "),
+            advances[improvement_types[B_BARRACKS2].obsolete_by].name,
+            improvement_types[B_BARRACKS2].name);
+  }
+  if (which == B_MANHATTEN && num_role_units(F_NUCLEAR) > 0) {
+    int u, t;
+
+    u = get_role_unit(F_NUCLEAR, 0);
+    assert(u<game.num_unit_types);
+    t = get_unit_type(u)->tech_requirement;
+    assert(t<game.num_tech_types);
+    astr_add(buf,
+           _("Allows all players with knowledge of %s to build %s units.  "),
+           advances[t].name, get_unit_type(u)->name);
+  }
+  if (buf->str != NULL) {
+    wordwrap_string(buf->str, 68);
+  }
+}
Index: common/improvement.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/improvement.h,v
retrieving revision 1.28
diff -u -r1.28 improvement.h
--- common/improvement.h        13 Aug 2004 15:59:12 -0000      1.28
+++ common/improvement.h        19 Aug 2004 22:08:00 -0000
@@ -24,6 +24,7 @@
 #include "effects.h"
 
 struct player;
+struct astring;
 
 /* Improvement status (for cities' lists of improvements)
  * An enum or bitfield would be neater here, but we use a typedef for
@@ -167,6 +168,8 @@
 void improvements_update_redundant(struct player *pplayer, struct city *pcity,
                                    Continent_id cont, enum impr_range range);
 
+void improvement_helptext(struct astring *buf, int which);
+
 /* Iterates over all improvements. Creates a new variable names m_i
  * with type Impr_Type_id which holds the id of the current improvement. */
 #define impr_type_iterate(m_i)                                                \
Index: server/stdinhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v
retrieving revision 1.335
diff -u -r1.335 stdinhand.c
--- server/stdinhand.c  9 Aug 2004 15:45:49 -0000       1.335
+++ server/stdinhand.c  19 Aug 2004 22:08:00 -0000
@@ -1163,6 +1163,7 @@
   CMD_LOAD,
   CMD_READ_SCRIPT,
   CMD_WRITE_SCRIPT,
+  CMD_WRITE_MANUAL,
 
   /* undocumented */
   CMD_RFCSTYLE,
@@ -1292,9 +1293,10 @@
   },
   {"rulesetdir", ALLOW_CTRL,
    N_("rulesetdir <directory>"),
+   N_("Choose new ruleset directory or modpack."),
    N_("Choose new ruleset directory or modpack. Calling this\n "
       "without any arguments will show you the currently selected "
-      "ruleset."), NULL
+      "ruleset.")
   },
   {"metainfo", ALLOW_CTRL,
    /* TRANS: translate text between <> only */
@@ -1490,6 +1492,11 @@
    N_("write <file-name>"),
    N_("Write current settings as server commands to file."), NULL
   },
+  {"manual",   ALLOW_HACK,
+   /* TRANS: translate text between <> only */
+   N_("manual"),
+   N_("Write the server manual."), NULL
+  },
   {"rfcstyle", ALLOW_HACK,
    "rfcstyle",
    N_("Switch server output between 'RFC-style' and normal style."), NULL
@@ -2264,6 +2271,292 @@
 }
 
 /**************************************************************************
+  Write a server manual in html format, then quit.
+**************************************************************************/
+static bool manual_command(struct connection *caller, bool check)
+{
+#define NUM_MANUALS 5
+#define HTML_HEADER "<html><head><link rel=\"stylesheet\" type=\"text/css\" "\
+                    "href=\"manual.css\" /></head><body>\n\n"
+#ifdef USE_HTML
+#define SECTION_BEGIN "<h3>"
+#define SECTION_END "</h3>"
+#define IMAGE_BEGIN "<img src="
+#define IMAGE_END ".png\">"
+#else
+#define SECTION_BEGIN "==="
+#define SECTION_END "==="
+#define IMAGE_BEGIN "[[Image:"
+#define IMAGE_END ".png]]"
+#endif
+
+  FILE *doc;
+  char filename[40];
+  int manuals;
+
+  if (check) {
+    return TRUE; /* Always */
+  }
+  load_rulesets();
+  for (manuals = 1; manuals < NUM_MANUALS + 1; manuals++) {
+    int i;
+
+    snprintf(filename, sizeof(filename), "manual%d.html", manuals);
+
+    if (!is_reg_file_for_access(filename, TRUE)
+        || !(doc = fopen(filename, "w"))) {
+      die(_("Could not write manual file %s."), filename);
+      return FALSE;
+    }
+
+#ifdef USE_HTML
+      fprintf(doc, HTML_HEADER);
+#endif
+
+    switch (manuals) {
+    case 1:
+    fprintf(doc, "<h1>Freeciv %s server options</h1>\n\n", VERSION_STRING);
+    for (i = 0; settings[i].name; i++) {
+      struct settings_s *op = &settings[i];
+      static struct astring abuf = ASTRING_INIT;
+      const char *help = _(op->extra_help);
+
+      astr_minsize(&abuf, strlen(help) + 10);
+      strcpy(abuf.str, help);
+      wordwrap_string(abuf.str, 76);
+
+#ifndef USE_HTML
+      fprintf(doc, "----\n\n");
+#endif
+      fprintf(doc, "%s%s - %s%s\n\n", SECTION_BEGIN, op->name,
+              _(op->short_help), SECTION_END);
+      if (strlen(op->extra_help) > 0) {
+        fprintf(doc, "<pre>%s</pre>\n\n", abuf.str);
+      }
+      fprintf(doc, "<p class=\"misc\">");
+      fprintf(doc, _("Level: %s.<br>"), sset_level_names[op->level]);
+      fprintf(doc, _("Category: %s.<br>"), sset_category_names[op->category]);
+      if (op->to_client == SSET_SERVER_ONLY) {
+        fprintf(doc, _("Can only be used in server console. "));
+      }
+      if (sset_is_changeable(i)) {
+        fprintf(doc, _("Can be changed during a game. "));
+      } else {
+        fprintf(doc, _("Can <b>not</b> be changed during a game. "));
+      }
+      fprintf(doc, "</p>\n\n");
+      switch (op->type) {
+      case SSET_BOOL:
+        fprintf(doc, _("<p class=\"bounds\">Minimum: 0, Default: %d, "
+                  "Maximum: 1</p>\n\n"), op->bool_default_value ? 1 : 0);
+       if (*(op->bool_value) != op->bool_default_value) {
+          fprintf(doc, _("<p class=\"changed\">Value set to %d</p>\n\n"),
+                  *(op->bool_value));
+        }
+        break;
+      case SSET_INT:
+        fprintf(doc, _("<p class=\"bounds\">Minimum: %d, Default: %d, "
+                "Maximum: %d</p>\n\n"),
+               op->int_min_value, op->int_default_value, op->int_max_value);
+       if (*(op->int_value) != op->int_default_value) {
+          fprintf(doc, _("<p class=\"changed\">Value set to %d</p>\n\n"),
+                  *(op->int_value));
+        }
+        break;
+      case SSET_STRING:
+        fprintf(doc, _("<p class=\"bounds\">Default: \"%s\"</p>\n\n"), 
+                op->string_default_value);
+       if (strcmp(op->string_value, op->string_default_value) != 0) {
+          fprintf(doc, _("<p class=\"changed\">Value set to %s</p>\n\n"),
+                  op->string_value);
+        }
+        break;
+      }
+    }
+    break;
+
+    case 2:
+    fprintf(doc, "<h1>Freeciv %s server commands</h1>\n\n", VERSION_STRING);
+    for (i = 0; i < CMD_NUM; i++) {
+      const struct command *cmd = &commands[i];
+
+#ifndef USE_HTML
+      fprintf(doc, "----\n\n");
+#endif
+      fprintf(doc, _("%s%s  -  %s%s\n\n"), SECTION_BEGIN, cmd->name,
+              _(cmd->short_help), SECTION_END);
+      if (cmd->synopsis) {
+        fprintf(doc, _("<table>\n<tr>\n<td valign=\"top\"><pre>Synopsis:</pre>"
+                        "</td>\n<td>"));
+        fprintf(doc, "<pre>%s</pre></td></tr></table>", _(cmd->synopsis));
+      }
+      fprintf(doc, _("<p class=\"level\">Level: %s</p>\n\n"), 
+              cmdlevel_name(cmd->level));
+      if (cmd->extra_help) {
+        static struct astring abuf = ASTRING_INIT;
+        const char *help = _(cmd->extra_help);
+      
+        astr_minsize(&abuf, strlen(help)+1);
+        strcpy(abuf.str, help);
+        wordwrap_string(abuf.str, 76);
+        fprintf(doc, _("<p>Description:</p>\n\n"));
+        fprintf(doc, "<pre>%s</pre>\n\n", abuf.str);
+      }
+    }
+    break;
+
+    case 3:
+    fprintf(doc, _("<h1>Freeciv %s terrain help</h1>\n\n"), VERSION_STRING);
+    fprintf(doc, _("<table border=1><tr><th>Terrain</th>"));
+    fprintf(doc, _("<th>Food/ Shield/ Trade</th>"));
+    fprintf(doc, _("<th>Special 1</th><th>Food/ Shield/ Trade</th>"));
+    fprintf(doc, _("<th>Special 2</th><th>Food/ Shield/ Trade</th>"));
+    fprintf(doc, _("<th>Move cost</th><th>Defense</th><th>Road 
+trade</th>\n"));
+    fprintf(doc, _("<th>Irrigation +food</th><th>Mining +shields</th>\n"));
+    fprintf(doc, _("<th>Transform to</th>"));
+    fprintf(doc, "</tr>\n");
+    terrain_type_iterate(id) {
+      struct tile_type *ptype = get_tile_type(id);
+
+      if (ptype->defense_bonus == 0) {
+        /* Must be a disabled piece of terrain */
+        continue;
+      }
+
+      fprintf(doc, "<tr><td>%s%s%s %s</td>", IMAGE_BEGIN, ptype->graphic_str,
+              IMAGE_END, get_terrain_name(id));
+      fprintf(doc, "<td>%d / %d / %d</td>",
+              ptype->food, ptype->shield, ptype->trade);
+
+      fprintf(doc, "<td>%s%s%s %s</td>", IMAGE_BEGIN, 
+              ptype->special[0].graphic_str, IMAGE_END, 
+              ptype->special_1_name);
+      fprintf(doc, "<td>%d / %d / %d</td>",
+              ptype->food_special_1, ptype->shield_special_1, 
+              ptype->trade_special_1);
+
+      fprintf(doc, "<td>%s%s%s", IMAGE_BEGIN,
+              ptype->special[1].graphic_str, IMAGE_END);
+      fprintf(doc, " %s</td>", ptype->special_2_name);
+      fprintf(doc, "<td>%d / %d / %d</td>",
+              ptype->food_special_2, ptype->shield_special_2, 
+              ptype->trade_special_2);
+
+      fprintf(doc, "<td>%d</td>\n", ptype->movement_cost);
+      fprintf(doc, "<td>%d0%%</td><td>%d</td><td>%d</td><td>%d</td>\n",
+              ptype->defense_bonus, ptype->road_trade_incr,
+              ptype->irrigation_food_incr, ptype->mining_shield_incr);
+      fprintf(doc, "<td>%s</td></tr>\n\n", 
+              get_terrain_name(ptype->transform_result));
+    } terrain_type_iterate_end;
+    fprintf(doc, "</table><br><br><br><table border=1>");
+    fprintf(doc, "<caption>Time to perform action</caption>");
+    fprintf(doc, "<tr><th>Terrain</th>\n");
+    fprintf(doc, "<th>Road</th><th>Irrigation</th>\n");
+    fprintf(doc, "<th>Mining</th><th>Rail</th>\n");
+    fprintf(doc, "<th>Airbase</th><th>Fortress</th>\n");
+    fprintf(doc, "<th>Clean pollution</th><th>Clean fallout</th>\n");
+    fprintf(doc, "<th>Transform</th></tr>\n");
+    terrain_type_iterate(id) {
+      const char *name = get_terrain_name(id);
+      struct tile_type *ptype = get_tile_type(id);
+
+      if (ptype->defense_bonus == 0) {
+        /* Must be a disabled piece of terrain */
+        continue;
+      }
+
+      fprintf(doc, "<tr><td>%s%s%s %s</td><td>%d</td>\n",
+              IMAGE_BEGIN, ptype->graphic_str, IMAGE_END, name,
+              ptype->road_time);
+      fprintf(doc, "<td>%d</td><td>%d</td><td>%d</td><td>%d</td>\n",
+              ptype->irrigation_time, ptype->mining_time,
+              ptype->rail_time, ptype->airbase_time);
+      fprintf(doc, "<td>%d</td><td>%d</td><td>%d</td><td>%d</td>\n",
+              ptype->fortress_time, ptype->clean_pollution_time,
+              ptype->clean_fallout_time, ptype->transform_time);
+      fprintf(doc, "</tr>\n\n");
+    } terrain_type_iterate_end;
+    
+    fprintf(doc, "</table>\n");
+    break;
+
+    case 4:
+    fprintf(doc, _("<h1>Buildings help for %s</h1>\n\n"), VERSION_STRING);
+    impr_type_iterate(id) {
+      struct astring astr = ASTRING_INIT;
+      struct impr_type *pimpr = get_improvement_type(id);
+
+      if (pimpr->is_wonder) {
+        continue;
+      }
+
+      astr_init(&astr);
+      improvement_helptext(&astr, id);
+      fprintf(doc, "%s%s%s\n\n", SECTION_BEGIN, get_improvement_name(id), 
+              SECTION_END);
+      fprintf(doc, "<table>\n");
+      fprintf(doc, _("<tr><td>Cost: <td>%d</tr>\n"), pimpr->build_cost);
+      fprintf(doc, _("<tr><td>Upkeep: <td>%d</tr>\n"), pimpr->upkeep);
+      if (tech_exists(pimpr->tech_req)) {
+        fprintf(doc, _("<tr><td>Tech required: <td>%s</tr>\n"), 
+                advances[pimpr->tech_req].name);
+      }
+      if (tech_exists(pimpr->obsolete_by)) {
+        fprintf(doc, _("<tr><td>Obsoleted by: <td>%s</tr>\n"), 
+                advances[pimpr->obsolete_by].name);
+      }
+      fprintf(doc, "</table>\n\n");
+      fprintf(doc, "<pre>%s</pre>\n\n", astr.str);
+      astr_free(&astr);
+    } impr_type_iterate_end;
+    break;
+
+    case 5:
+    fprintf(doc, _("<h1>Wonder help for %s</h1>\n\n"), VERSION_STRING);
+    impr_type_iterate(id) {
+      struct astring astr = ASTRING_INIT;
+      struct impr_type *pimpr = get_improvement_type(id);
+
+      if (!pimpr->is_wonder) {
+        continue;
+      }
+
+      astr_init(&astr);
+      improvement_helptext(&astr, id);
+      fprintf(doc, "%s%s%s\n\n", SECTION_BEGIN, get_improvement_name(id), 
+              SECTION_END);
+      fprintf(doc, "<table>\n");
+      fprintf(doc, _("<tr><td>Cost: <td>%d</tr>\n"), pimpr->build_cost);
+      fprintf(doc, _("<tr><td>Upkeep: <td>%d</tr>\n"), pimpr->upkeep);
+      if (tech_exists(pimpr->tech_req)) {
+        fprintf(doc, _("<tr><td>Tech required: <td>%s</tr>\n"), 
+                advances[pimpr->tech_req].name);
+      }
+      if (tech_exists(pimpr->obsolete_by)) {
+        fprintf(doc, _("<tr><td>Obsoleted by: <td>%s</tr>\n"), 
+                advances[pimpr->obsolete_by].name);
+      }
+      fprintf(doc, "</table>\n\n");
+      if (astr.str != NULL) {
+        fprintf(doc, "<pre>%s</pre>\n\n", astr.str);
+      }
+      astr_free(&astr);
+    } impr_type_iterate_end;
+    break;
+
+    } /* switch */
+
+#ifdef USE_HTML
+    fprintf(doc, "</body></html>");
+#endif
+    fclose(doc);
+  } /* manuals */
+  exit(EXIT_SUCCESS);
+  return TRUE;
+}
+
+/**************************************************************************
 ...
 (Should this take a 'caller' argument for output? --dwp)
 **************************************************************************/
@@ -4479,6 +4772,8 @@
     return save_command(caller,arg, check);
   case CMD_LOAD:
     return load_command(caller, arg, check);
+  case CMD_WRITE_MANUAL:
+    return manual_command(caller, check);
   case CMD_METAINFO:
     return metainfo_command(caller, arg, check);
   case CMD_METACONN:
Index: client/helpdata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/helpdata.c,v
retrieving revision 1.71
diff -u -r1.71 helpdata.c
--- client/helpdata.c   18 Aug 2004 04:23:20 -0000      1.71
+++ client/helpdata.c   19 Aug 2004 22:09:05 -0000
@@ -495,52 +495,19 @@
 /****************************************************************
   Write misc dynamic text for improvements (not wonders).
   user_text is written after some extra, and before others.
+
+  Strictly backwards-compatible function.
 *****************************************************************/
 void helptext_improvement(char *buf, int which, const char *user_text)
 {
-  struct impr_type *imp = &improvement_types[which];
+  struct astring astr = ASTRING_INIT;
   
-  assert(buf&&user_text);
-  buf[0] = '\0';
-  if(which==B_AQUEDUCT) {
-    sprintf(buf+strlen(buf), _("Allows a city to grow larger than size %d.  "),
-           game.aqueduct_size);
-    if(improvement_exists(B_SEWER)) {
-      char *s = improvement_types[B_SEWER].name;
-      sprintf(buf+strlen(buf),
-             _("(The %s improvement is also required for a city to grow"
-               " larger than size %d.)  "), s, game.sewer_size);
-    }
-    strcat(buf,"\n");
-  }
-  if(which==B_SEWER) {
-    sprintf(buf+strlen(buf), _("Allows a city to grow larger than size %d.  "),
-          game.sewer_size);
-  }
-  if (imp->helptext[0] != '\0') {
-    sprintf(buf + strlen(buf), "%s  ", _(imp->helptext));
-  }
-  if(which==B_BARRACKS
-     && tech_exists(improvement_types[B_BARRACKS].obsolete_by)
-     && tech_exists(improvement_types[B_BARRACKS2].obsolete_by)) {
-    sprintf(buf+strlen(buf),
-          _("\n\nNote that discovering %s or %s will obsolete"
-          " any existing %s.  "),
-          advances[improvement_types[B_BARRACKS].obsolete_by].name,
-          advances[improvement_types[B_BARRACKS2].obsolete_by].name,
-          improvement_types[B_BARRACKS].name);
-  }
-  if(which==B_BARRACKS2
-     && tech_exists(improvement_types[B_BARRACKS2].obsolete_by)) {
-    sprintf(buf+strlen(buf),
-          _("\n\nThe discovery of %s will make %s obsolete.  "),
-          advances[improvement_types[B_BARRACKS2].obsolete_by].name,
-          improvement_types[B_BARRACKS2].name);
-  }
-  if (strcmp(user_text, "")!=0) {
-    sprintf(buf+strlen(buf), "\n\n%s", user_text);
-  }
+  astr_init(&astr);
+
+  improvement_helptext(&astr, which);
+  sprintf(buf, "%s\n\n%s", astr.str, user_text);
   wordwrap_string(buf, 68);
+  astr_free(&astr);
 }
 
 /****************************************************************

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