Initial revision
authorEric S. Raymond <esr@thyrsus.com>
Mon, 27 Sep 2004 15:12:54 +0000 (15:12 +0000)
committerEric S. Raymond <esr@thyrsus.com>
Mon, 27 Sep 2004 15:12:54 +0000 (15:12 +0000)
data.c [new file with mode: 0644]
term.c [new file with mode: 0644]

diff --git a/data.c b/data.c
new file mode 100644 (file)
index 0000000..a20de1f
--- /dev/null
+++ b/data.c
@@ -0,0 +1,264 @@
+/* %W% %G% %U% - (c) Copyright 1987, 1988 Chuck Simmons */
+
+/*
+ *    Copyright (C) 1987, 1988 Chuck Simmons
+ * 
+ * See the file COPYING, distributed with empire, for restriction
+ * and warranty information.
+ */
+
+/*
+Static data.
+
+One of our hopes is that changing the types of pieces that
+exist in the game is mostly a matter of modifying this file.
+However, see also the help routine, empire.h, and empire.doc.
+*/
+
+#include "empire.h"
+
+/*
+Piece attributes.  Notice that the Transport is allowed only one hit.
+In the previous version of this game, the user could easily win simply
+by building armies and troop transports.  We attempt to alleviate this
+problem by making transports far more fragile.  We have also increased
+the range of a fighter from 20 to 30 so that fighters will be somewhat
+more useful.
+*/
+
+piece_attr_t piece_attr[] = {
+       {'A', /* character for printing piece */
+        "army", /* name of piece */ 
+        "army", /* nickname */
+        "an army", /* name with preceding article */
+        "armies", /* plural */
+        "+", /* terrain */
+        5, /* units to build */
+        1, /* strength */
+        1, /* max hits */
+        1, /* movement */
+        0, /* capacity */
+        INFINITY}, /* range */
+
+       /*
+        For fighters, the range is set to an even multiple of the speed.
+        This allows user to move fighter, say, two turns out and two
+        turns back.
+       */
+        
+       {'F', "fighter", "fighter", "a fighter", "fighters",
+               ".+", 10, 1,  1, 8, 0, 32},
+
+       {'P', "patrol boat", "patrol", "a patrol boat", "patrol boats",
+               ".",  15, 1,  1, 4, 0, INFINITY},
+               
+       {'D', "destroyer", "destroyer", "a destroyer", "destroyers",
+               ".",  20, 1,  3, 2, 0, INFINITY},
+
+       {'S', "submarine", "submarine", "a submarine", "submarines",
+               ".",  20, 3,  2, 2, 0, INFINITY},
+
+       {'T', "troop transport", "transport", "a troop transport", "troop transports",
+               ".",  30, 1,  1, 2, 6, INFINITY},
+
+       {'C', "aircraft carrier", "carrier", "an aircraft carrier", "aircraft carriers",
+               ".",  30, 1,  8, 2, 8, INFINITY},
+
+       {'B', "battleship", "battleship", "a battleship", "battleships",
+               ".",  40, 2, 10, 2, 0, INFINITY},
+               
+       {'Z', "satellite", "satellite", "a satellite", "satellites",
+               ".+", 50, 0, 1, 10, 0, 500}
+};
+
+/* Direction offsets. */
+
+int dir_offset [] = {-MAP_WIDTH, /* north */
+                    -MAP_WIDTH+1, /* northeast */
+                    1, /* east */
+                    MAP_WIDTH+1, /* southeast */
+                    MAP_WIDTH, /* south */
+                    MAP_WIDTH-1, /* southwest */
+                    -1, /* west */
+                    -MAP_WIDTH-1}; /* northwest */
+
+/* Names of movement functions. */
+
+char *func_name[] = {"none", "random", "sentry", "fill", "land",
+                       "explore", "load", "attack", "load", "repair",
+                       "transport",
+                       "W", "E", "D", "C", "X", "Z", "A", "Q"};
+
+/* The order in which pieces should be moved. */
+int move_order[] = {SATELLITE, TRANSPORT, CARRIER, BATTLESHIP, 
+                   PATROL, SUBMARINE, DESTROYER, ARMY, FIGHTER};
+
+/* types of pieces, in declared order */
+char type_chars[] = "AFPDSTCBZ";
+
+/* Lists of attackable objects if object is adjacent to moving piece. */
+
+char tt_attack[] = "T";
+char army_attack[] = "O*TACFBSDP";
+char fighter_attack[] = "TCFBSDPA";
+char ship_attack[] = "TCBSDP";
+
+/* Define various types of objectives */
+
+move_info_t tt_explore = { /* water objectives */
+       COMP, /* home city */
+       " ", /* objectives */
+       {1} /* weights */
+};
+move_info_t tt_load = { /* land objectives */
+       COMP, "$",           {1}
+};
+
+/*
+Rationale for 'tt_unload':
+
+     Any continent with four or more cities is extremely attractive,
+and we should grab it quickly.  A continent with three cities is
+fairly attractive, but we are willing to go slightly out of our
+way to find a better continent.  Similarily for two cities on a
+continent.  At one city on a continent, things are looking fairly
+unattractive, and we are willing to go quite a bit out of our way
+to find a better continent.
+
+     Cities marked with a '0' are on continents where we already
+have cities, and these cities will likely fall to our armies anyway,
+so we don't need to dump armies on them unless everything else is
+real far away.  We would prefer to use unloading transports for
+taking cities instead of exploring, but we are willing to explore
+if interesting cities are too far away.
+
+     It has been suggested that continents containing one city
+are not interesting.  Unfortunately, most of the time what the
+computer sees is a single city on a continent next to lots of
+unexplored territory.  So it dumps an army on the continent to
+explore the continent and the army ends up attacking the city
+anyway.  So, we have decided we might as well send the tt to
+the city in the first place and increase the speed with which
+the computer unloads its tts.
+*/
+
+move_info_t tt_unload     = {
+       COMP, "9876543210 ", {1, 1, 1, 1, 1, 1, 11, 21, 41, 101, 61}
+};
+
+/*
+ '$' represents loading tt must be first
+ 'x' represents tt producing city
+ '0' represnets explorable territory
+*/
+move_info_t army_fight    = { /* land objectives */
+       COMP, "O*TA ",       {1, 1, 1, 1, 11}
+};
+move_info_t army_load     = { /* water objectives */
+       COMP, "$x",          {1, W_TT_BUILD}
+};
+
+move_info_t fighter_fight = {
+       COMP, "TCFBSDPA ",   {1, 1, 5, 5, 5, 5, 5, 5, 9}
+};
+move_info_t ship_fight    = {
+       COMP, "TCBSDP ",     {1, 1, 3, 3, 3, 3, 21}
+};
+move_info_t ship_repair   = {
+       COMP, "X",           {1}
+};
+
+move_info_t user_army        = {
+       USER, " ",   {1}
+};
+move_info_t user_army_attack = {
+       USER, "*Xa ", {1, 1, 1, 12}
+};
+move_info_t user_fighter     = {
+       USER, " ",   {1}
+};
+move_info_t user_ship        = {
+       USER, " ",   {1}
+};
+move_info_t user_ship_repair = {
+       USER, "O",   {1}
+};
+
+/*
+Various help texts.
+*/
+
+char *help_cmd[] = {
+       "COMMAND MODE",
+       "Auto:     enter automove mode",
+       "City:     give city to computer",
+       "Date:     print round",
+       "Examine:  examine enemy map",
+       "File:     print map to file",
+       "Give:     give move to computer",
+       "Help:     display this text",
+       "J:        enter edit mode",
+       "Move:     make a move",
+       "N:        give N moves to computer",
+       "Print:    print a sector",
+       "Quit:     quit game",
+       "Restore:  restore game",
+       "Save:     save game",
+       "Trace:    save movie in empmovie.dat",
+       "Watch:    watch movie",
+       "Zoom:     display compressed map",
+       "<ctrl-L>: redraw screen"
+};
+int cmd_lines = 19;
+
+char *help_user[] = {
+       "USER MODE",
+       "QWE",
+       "A D       movement directions",
+       "ZXC",
+       "<space>:  sit",
+       "Build:    change city production",
+       "Fill:     set func to fill",
+       "Grope:    set func to explore",
+       "Help:     display this text",
+       "I <dir>:  set func to dir",
+       "J:        enter edit mode",
+       "Kill:     set func to awake",
+       "Land:     set func to land",
+       "Out:      leave automove mode",
+       "Print:    redraw screen",
+       "Random:   set func to random",
+       "Sentry:   set func to sentry",
+       "Upgrade:  set func to repair",
+       "V <piece> <func>:  set city func",
+       "Y:        set func to attack",
+       "<ctrl-L>: redraw screen",
+       "?:        describe piece"
+};
+int user_lines = 22;
+       
+char *help_edit[] = {
+       "EDIT MODE",
+       "QWE",
+       "A D       movement directions",
+       "ZXC",
+       "Build:    change city production",
+       "Fill:     set func to fill",
+       "Grope:    set func to explore",
+       "Help:     display this text",
+       "I <dir>:  set func to dir",
+       "Kill:     set func to awake",
+       "Land:     set func to land",
+       "Mark:     mark piece",
+       "N:        set dest for marked piece",
+       "Out:      exit edit mode",
+       "Print:    print sector",
+       "Random:   set func to random",
+       "Sentry:   set func to sentry",
+       "Upgrade:  set func to repair",
+       "V <piece> <func>:  set city func",
+       "Y:        set func to attack",
+       "<ctrl-L>: redraw screen",
+       "?:        describe piece"
+};
+int edit_lines = 22;
diff --git a/term.c b/term.c
new file mode 100644 (file)
index 0000000..e1d09d9
--- /dev/null
+++ b/term.c
@@ -0,0 +1,458 @@
+/* %W% %G% %U% - (c) Copyright 1987, 1988 Chuck Simmons */
+
+/*
+ *    Copyright (C) 1987, 1988 Chuck Simmons
+ * 
+ * See the file COPYING, distributed with empire, for restriction
+ * and warranty information.
+ */
+
+/*
+term.c -- this file contains various routines used to control the
+user communications area of the terminal.  This area consists of
+the top 3 lines of the terminal where messages are displayed to the
+user and input is acquired from the user.
+
+There are two types of output in this area.  One type is interactive
+output.  This consists of a prompt line and an error message line.
+The other type of output is informational output.  The user must
+be given time to read informational output.
+
+Whenever input is received, the top three lines are cleared and the
+screen refreshed as the user has had time to read these lines.  We
+also clear the 'need_delay' flag, saying that the user has read the
+information on the screen.
+
+When information is to be displayed, if the 'need_delay' flag is set,
+we refresh the screen and pause momentarily to give the user a chance
+to read the lines.  The new information is then displayed, and the
+'need_delay' flag is set.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <curses.h>
+#include <ctype.h>
+
+#include "empire.h"
+#include "extern.h"
+
+static int need_delay;
+static FILE *my_stream;
+void
+/* VARARGS1 */
+pdebug (s, a, b, c, d, e, f, g, h)
+char *s;
+int a, b, c, d, e, f, g, h;
+{
+       if (!print_debug) return;
+       comment (s, a, b, c, d, e, f, g, h);
+}
+
+/*
+Here are routines that handle printing to the top few lines of the
+screen.  'topini' should be called at initialization, and whenever
+we finish printing information to the screen.
+*/
+
+void
+topini()
+{
+       info (0, 0, 0);
+}
+/*
+Write a message to one of the top lines.
+*/
+
+void
+/* VARARGS2 */
+topmsg(linep, buf, a, b, c, d, e, f, g, h)
+int linep;
+char *buf;
+int a, b, c, d, e, f, g, h;
+{
+       if (linep < 1 || linep > NUMTOPS)
+               linep = 1;
+       (void) move (linep - 1, 0);
+       
+       if (buf != NULL && strlen (buf) > 0)
+               addprintf (buf, a, b, c, d, e, f, g, h);
+       
+       (void) clrtoeol ();
+}
+
+void
+topmsg1 (linep, buf, a, b, c, d, e, f, g, h)
+int linep;
+char *buf;
+char *a;
+int b, c, d, e, f, g, h;
+{
+       if (linep < 1 || linep > NUMTOPS)
+               linep = 1;
+       (void) move (linep - 1, 0);
+       
+       if (buf != NULL && strlen (buf) > 0)
+               addprintf1 (buf, a, b, c, d, e, f, g, h);
+       
+       (void) clrtoeol ();
+}
+void
+topmsg2 (linep, buf, a, b, c, d, e, f, g, h)
+int linep;
+char *buf;
+char *a, *e, *f;
+int b, c, d, g, h;
+{
+       if (linep < 1 || linep > NUMTOPS)
+               linep = 1;
+       (void) move (linep - 1, 0);
+       
+       if (buf != NULL && strlen (buf) > 0)
+               addprintf2 (buf, a, b, c, d, e, f, g, h);
+       
+       (void) clrtoeol ();
+}
+/*
+Print a prompt on the first message line.
+*/
+
+void
+/* VARARGS1 */
+prompt (buf, a, b, c, d, e, f, g, h)
+char *buf;
+int a,b,c,d,e,f,g,h;
+{
+       topmsg (1, buf, a, b, c, d, e, f, g, h);
+}
+void
+prompt1 (buf, a, b, c, d, e, f, g, h)
+char *buf, *a;
+int b,c,d,e,f,g,h;
+{
+       topmsg1 (1, buf, a, b, c, d, e, f, g, h);
+}
+void
+prompt2 (buf, a, b, c, d, e, f, g, h)
+char *buf, *a, *e, *f;
+int b,c,d,g,h;
+{
+       topmsg2 (1, buf, a, b, c, d, e, f, g, h);
+}
+
+/*
+Print an error message on the second message line.
+*/
+
+void
+/* VARARGS1 */
+error (buf, a, b, c, d, e, f, g, h)
+char *buf;
+int a, b, c, d, e, f, g, h;
+{
+       topmsg (2, buf, a, b, c, d, e, f, g, h);
+}
+
+/*
+Print out extra information.
+*/
+
+void
+/* VARARGS1 */
+extra (buf, a, b, c, d, e, f, g, h)
+char *buf;
+int a, b, c, d, e, f, g, h;
+{
+       topmsg (3, buf, a, b, c, d, e, f, g, h);
+}
+
+/*
+Print out a generic error message.
+*/
+
+void
+huh ()
+{
+       error ("Type H for Help.",0,0,0,0,0,0,0,0);
+}
+
+/*
+Display information on the screen.  If the 'need_delay' flag is set,
+we force a delay, then print the information.  After we print the
+information, we set the need_delay flag.
+*/
+
+void
+info (a, b, c)
+char *a, *b, *c;
+{
+       if (need_delay) delay ();
+       topmsg (1, a,0,0,0,0,0,0,0,0);
+       topmsg (2, b,0,0,0,0,0,0,0,0);
+       topmsg (3, c,0,0,0,0,0,0,0,0);
+       need_delay = (a || b || c);
+}
+
+void
+set_need_delay () {
+       need_delay = 1;
+}
+
+void
+comment (buf, a, b, c, d, e, f, g, h)
+char *buf;
+int a, b, c, d, e, f, g, h;
+{
+       if (need_delay) delay ();
+       topmsg (1, 0,0,0,0,0,0,0,0,0);
+       topmsg (2, 0,0,0,0,0,0,0,0,0);
+       topmsg (3, buf, a, b, c, d, e, f, g, h);
+       need_delay = (buf != 0);
+}
+       
+void
+comment1 (buf, a, b, c, d, e, f, g, h)
+char *buf, *a;
+int b, c, d, e, f, g, h;
+{
+       if (need_delay) delay ();
+       topmsg1 (1, 0,0,0,0,0,0,0,0,0);
+       topmsg1 (2, 0,0,0,0,0,0,0,0,0);
+       topmsg1 (3, buf, a, b, c, d, e, f, g, h);
+       need_delay = (buf != 0);
+}
+       
+/* kermyt begin */
+void
+ksend (buf, a, b, c, d, e, f, g, h)
+char *buf;
+int a,b,c,d,e,f,g,h;
+{
+       if(!(my_stream=fopen("info_list.txt","a")))
+       {
+               error("Cannot open info_list.txt",0,0,0,0,0,0,0,0);
+               return;
+       }
+       fprintf(my_stream, buf, a, b, c, d, e, f, g, h);
+       fclose(my_stream);
+       return;
+}
+void
+ksend1 (buf, a, b, c, d, e, f, g, h)
+char *buf, *a;
+int b,c,d,e,f,g,h;
+{
+       if(!(my_stream=fopen("info_list.txt","a")))
+       {
+               error("Cannot open info_list.txt",0,0,0,0,0,0,0,0);
+               return;
+       }
+       fprintf(my_stream, buf, a, b, c, d, e, f, g, h);
+       fclose(my_stream);
+       return;
+}
+/* kermyt end */
+/*
+Get a string from the user, echoing characters all the while.
+*/
+
+void
+get_str (buf, sizep)
+char *buf;
+int sizep;
+{
+       (void) echo();
+       get_strq(buf, sizep);
+       (void) noecho();
+}
+
+/*
+Get a string from the user, ignoring the current echo mode.
+*/
+
+void
+get_strq (buf, sizep)
+char *buf;
+int sizep;
+{
+       sizep = sizep; /* size of buf, currently unused */
+
+       (void) nocrmode ();
+       (void) refresh ();
+       (void) getstr (buf);
+       need_delay = FALSE;
+       info (0, 0, 0);
+       (void) crmode ();
+}
+
+/*
+Get a character from the user and convert it to uppercase.
+*/
+
+char
+get_chx()
+{
+       char c;
+
+       c = get_cq ();
+
+       if (islower(c))
+               return (upper(c));
+       else
+               return (c);
+}
+
+/*
+Input an integer from the user.
+*/
+
+int
+getint (message)
+char *message;
+{
+       char buf[STRSIZE];
+       char *p;
+
+       for (;;) { /* until we get a legal number */
+               prompt (message,0,0,0,0,0,0,0,0);
+               get_str (buf, sizeof (buf));
+               
+               for (p = buf; *p; p++) {
+                       if (*p < '0' || *p > '9') {
+                               error ("Please enter an integer.",0,0,0,0,0,0,0,0);
+                               break;
+                       }
+               }
+               if (*p == 0) { /* no error yet? */
+                       if (p - buf > 7) /* too many digits? */
+                               error ("Please enter a small integer.",0,0,0,0,0,0,0,0);
+                       else return (atoi (buf));
+               }
+       }
+}
+
+/*
+Input a character from the user with echoing.
+*/
+
+char
+get_c ()
+{
+       char c; /* one char and a null */
+
+       (void) echo ();
+       c = get_cq ();
+       (void) noecho ();
+       return (c);
+}
+
+/*
+Input a character quietly.
+*/
+
+char
+get_cq ()
+{
+       char c;
+
+       (void) crmode ();
+       (void) refresh ();
+       c = getch ();
+       topini (); /* clear information lines */
+       (void) nocrmode ();
+       return (c);
+}
+
+/*
+Input a yes or no response from the user.  We loop until we get
+a valid response.  We return TRUE iff the user replies 'y'.
+*/
+
+int
+getyn (message)
+char *message;
+{
+       char c;
+
+       for (;;) {
+               prompt (message,0,0,0,0,0,0,0,0);
+               c = get_chx ();
+
+               if (c == 'Y') return (TRUE);
+               if (c == 'N') return (FALSE);
+
+               error ("Please answer Y or N.",0,0,0,0,0,0,0,0);
+       }
+}
+
+/*
+Input an integer in a range.
+*/
+
+int
+get_range (message, low, high)
+char *message;
+int low, high;
+{
+       int result;
+
+       for (;;) {
+               result = getint (message);
+
+               if (result >= low && result <= high) return (result);
+
+               error ("Please enter an integer in the range %d..%d.",low, high,0,0,0,0,0,0);
+       }
+}
+
+/*
+Print a screen of help information.
+*/
+
+void
+help (text, nlines)
+char **text;
+int nlines;
+{
+       int i, r, c;
+       int text_lines;
+
+       text_lines = (nlines + 1) / 2; /* lines of text */
+
+       clear_screen ();
+
+       pos_str (NUMTOPS, 1, text[0],0,0,0,0,0,0,0,0); /* mode */
+       pos_str (NUMTOPS, 41, "See empire.doc for more information.",0,0,0,0,0,0,0,0);
+
+       for (i = 1; i < nlines; i++) {
+               if (i > text_lines)
+                       pos_str (i - text_lines + NUMTOPS + 1, 41, text[i],0,0,0,0,0,0,0,0);
+               else pos_str (i + NUMTOPS + 1, 1, text[i],0,0,0,0,0,0,0,0);
+       }
+
+       pos_str (text_lines + NUMTOPS + 2,  1, "--Piece---Yours-Enemy-Moves-Hits-Cost",0,0,0,0,0,0,0,0);
+       pos_str (text_lines + NUMTOPS + 2, 41, "--Piece---Yours-Enemy-Moves-Hits-Cost",0,0,0,0,0,0,0,0);
+
+       for (i = 0; i < NUM_OBJECTS; i++) {
+               if (i >= (NUM_OBJECTS+1)/2) {
+                       r = i - (NUM_OBJECTS+1)/2;
+                       c = 41;
+               }
+               else {
+                       r = i;
+                       c = 1;
+               }
+               pos_str1 (r + text_lines + NUMTOPS + 3, c,"%-12s%c     %c%6d%5d%6d",
+                       piece_attr[i].nickname,
+                       piece_attr[i].sname,
+                       tolower (piece_attr[i].sname),
+                       piece_attr[i].speed,
+                       piece_attr[i].max_hits,
+                       piece_attr[i].build_time,0,0);          //FLAG
+
+       }
+       (void) refresh ();
+}
+
+
+