[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);
}
/****************************************************************
|
|