--- /dev/null
+/* SCCS Id: @(#)makedefs.c 3.3 1999/08/16 */
+/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/* Copyright (c) M. Stephenson, 1990, 1991. */
+/* Copyright (c) Dean Luick, 1990. */
+/* NetHack may be freely redistributed. See license for details. */
+
+#define MAKEDEFS_C /* use to conditionally include file sections */
+/* #define DEBUG */ /* uncomment for debugging info */
+
+#include "config.h"
+#include "permonst.h"
+#include "objclass.h"
+#include "monsym.h"
+#include "artilist.h"
+#include "dungeon.h"
+#include "obj.h"
+#include "monst.h"
+#include "you.h"
+#include "flag.h"
+#include "dlb.h"
+
+/* version information */
+#ifdef SHORT_FILENAMES
+#include "patchlev.h"
+#else
+#include "patchlevel.h"
+#endif
+
+#ifdef MAC
+# ifdef applec /* Means the MPW compiler, I hope */
+# define MPWTOOL
+#include <CursorCtl.h>
+#include <string.h>
+#include <ctype.h>
+# else /* MAC without MPWTOOL */
+# define MACsansMPWTOOL
+# endif
+#endif /* MAC */
+
+#ifndef MPWTOOL
+# define SpinCursor(x)
+#endif
+
+#define Fprintf (void) fprintf
+#define Fclose (void) fclose
+#define Unlink (void) unlink
+#if !defined(AMIGA) || defined(AZTEC_C)
+#define rewind(fp) fseek((fp),0L,SEEK_SET) /* guarantee a return value */
+#endif
+
+#if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN)
+static const char SCCS_Id[] = "@(#)makedefs.c\t3.3\t1999/08/16";
+#endif
+
+ /* names of files to be generated */
+#define DATE_FILE "date.h"
+#define MONST_FILE "pm.h"
+#define ONAME_FILE "onames.h"
+#define OPTIONS_FILE "options"
+#define ORACLE_FILE "oracles"
+#define DATA_FILE "data"
+#define RUMOR_FILE "rumors"
+#define DGN_I_FILE "dungeon.def"
+#define DGN_O_FILE "dungeon.pdf"
+#define MON_STR_C "monstr.c"
+#define QTXT_I_FILE "quest.txt"
+#define QTXT_O_FILE "quest.dat"
+#define VIS_TAB_H "vis_tab.h"
+#define VIS_TAB_C "vis_tab.c"
+ /* locations for those files */
+#ifdef AMIGA
+# define FILE_PREFIX
+# define INCLUDE_TEMPLATE "NH:include/t.%s"
+# define SOURCE_TEMPLATE "NH:src/%s"
+# define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */
+# define DATA_TEMPLATE "NH:slib/%s"
+# define DATA_IN_TEMPLATE "NH:dat/%s"
+#else
+# ifdef MAC
+# define INCLUDE_TEMPLATE ":include:%s"
+# define SOURCE_TEMPLATE ":src:%s"
+# define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */
+# define DATA_TEMPLATE ":lib:%s"
+# define DATA_IN_TEMPLATE ":dat:%s"
+# else /* MAC */
+# ifdef OS2
+# define INCLUDE_TEMPLATE "..\\include\\%s"
+# define SOURCE_TEMPLATE "..\\src\\%s"
+# define DGN_TEMPLATE "..\\dat\\%s" /* where dungeon.pdf file goes */
+# define DATA_TEMPLATE "..\\dat\\%s"
+# define DATA_IN_TEMPLATE "..\\dat\\%s"
+# else /* OS2 */
+# define INCLUDE_TEMPLATE "../include/%s"
+# define SOURCE_TEMPLATE "../src/%s"
+# define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */
+# define DATA_TEMPLATE "../dat/%s"
+# define DATA_IN_TEMPLATE "../dat/%s"
+# endif /* OS2 */
+# endif /* MAC */
+#endif /* AMIGA */
+
+static const char
+ *Dont_Edit_Code =
+ "/* This source file is generated by 'makedefs'. Do not edit. */\n",
+ *Dont_Edit_Data =
+ "#\tThis data file is generated by 'makedefs'. Do not edit. \n";
+
+static struct version_info version;
+
+/* definitions used for vision tables */
+#define TEST_WIDTH COLNO
+#define TEST_HEIGHT ROWNO
+#define BLOCK_WIDTH (TEST_WIDTH + 10)
+#define BLOCK_HEIGHT TEST_HEIGHT /* don't need extra spaces */
+#define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT)
+#define MAX_COL (BLOCK_WIDTH + TEST_WIDTH)
+/* Use this as an out-of-bound value in the close table. */
+#define CLOSE_OFF_TABLE_STRING "99" /* for the close table */
+#define FAR_OFF_TABLE_STRING "0xff" /* for the far table */
+
+#define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0))
+#ifdef VISION_TABLES
+static char xclear[MAX_ROW][MAX_COL];
+#endif
+/*-end of vision defs-*/
+
+static char in_line[256], filename[60];
+
+#ifdef FILE_PREFIX
+ /* if defined, a first argument not starting with - is
+ * taken as a text string to be prepended to any
+ * output filename generated */
+char *file_prefix="";
+#endif
+
+#ifdef MACsansMPWTOOL
+int FDECL(main, (void));
+#else
+int FDECL(main, (int,char **));
+#endif
+void FDECL(do_makedefs, (char *));
+void NDECL(do_objs);
+void NDECL(do_data);
+void NDECL(do_dungeon);
+void NDECL(do_date);
+void NDECL(do_options);
+void NDECL(do_monstr);
+void NDECL(do_permonst);
+void NDECL(do_questtxt);
+void NDECL(do_rumors);
+void NDECL(do_oracles);
+void NDECL(do_vision);
+
+extern void NDECL(monst_init); /* monst.c */
+extern void NDECL(objects_init); /* objects.c */
+
+static void NDECL(make_version);
+static char *FDECL(version_string, (char *));
+static char *FDECL(version_id_string, (char *,const char *));
+static char *FDECL(xcrypt, (const char *));
+static int FDECL(check_control, (char *));
+static char *FDECL(without_control, (char *));
+static boolean FDECL(d_filter, (char *));
+static boolean FDECL(h_filter, (char *));
+static boolean FDECL(ranged_attk,(struct permonst*));
+static int FDECL(mstrength,(struct permonst *));
+
+static boolean FDECL(qt_comment, (char *));
+static boolean FDECL(qt_control, (char *));
+static int FDECL(get_hdr, (char *));
+static boolean FDECL(new_id, (char *));
+static boolean FDECL(known_msg, (int,int));
+static void FDECL(new_msg, (char *,int,int));
+static void FDECL(do_qt_control, (char *));
+static void FDECL(do_qt_text, (char *));
+static void NDECL(adjust_qt_hdrs);
+static void NDECL(put_qt_hdrs);
+
+#ifdef VISION_TABLES
+static void NDECL(H_close_gen);
+static void NDECL(H_far_gen);
+static void NDECL(C_close_gen);
+static void NDECL(C_far_gen);
+static int FDECL(clear_path, (int,int,int,int));
+#endif
+
+static char *FDECL(tmpdup, (const char *));
+static char *FDECL(limit, (char *,int));
+static char *FDECL(eos, (char *));
+
+/* input, output, tmp */
+static FILE *ifp, *ofp, *tfp;
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+extern unsigned _stklen = STKSIZ;
+#endif
+
+
+#ifdef MACsansMPWTOOL
+int
+main(void)
+{
+ const char *def_options = "odemvpqrhz";
+ char buf[100];
+ int len;
+
+ printf("Enter options to run: [%s] ", def_options);
+ fflush(stdout);
+ fgets(buf, 100, stdin);
+ len = strlen(buf);
+ if (len <= 1)
+ Strcpy(buf, def_options);
+ else
+ buf[len-1] = 0; /* remove return */
+
+ do_makedefs(buf);
+ exit(EXIT_SUCCESS);
+ return 0;
+}
+
+#else /* ! MAC */
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ if ( (argc != 2)
+#ifdef FILE_PREFIX
+ && (argc != 3)
+#endif
+ ) {
+ Fprintf(stderr, "Bad arg count (%d).\n", argc-1);
+ (void) fflush(stderr);
+ return 1;
+ }
+
+#ifdef FILE_PREFIX
+ if(argc >=2 && argv[1][0]!='-'){
+ file_prefix=argv[1];
+ argc--;argv++;
+ }
+#endif
+ do_makedefs(&argv[1][1]);
+ exit(EXIT_SUCCESS);
+ /*NOTREACHED*/
+ return 0;
+}
+
+#endif
+
+void
+do_makedefs(options)
+char *options;
+{
+ boolean more_than_one;
+
+ /* Note: these initializers don't do anything except guarantee that
+ we're linked properly.
+ */
+ monst_init();
+ objects_init();
+
+ /* construct the current version number */
+ make_version();
+
+
+ more_than_one = strlen(options) > 1;
+ while (*options) {
+ if (more_than_one)
+ Fprintf(stderr, "makedefs -%c\n", *options);
+
+ switch (*options) {
+ case 'o':
+ case 'O': do_objs();
+ break;
+ case 'd':
+ case 'D': do_data();
+ break;
+ case 'e':
+ case 'E': do_dungeon();
+ break;
+ case 'm':
+ case 'M': do_monstr();
+ break;
+ case 'v':
+ case 'V': do_date();
+ do_options();
+ break;
+ case 'p':
+ case 'P': do_permonst();
+ break;
+ case 'q':
+ case 'Q': do_questtxt();
+ break;
+ case 'r':
+ case 'R': do_rumors();
+ break;
+ case 'h':
+ case 'H': do_oracles();
+ break;
+ case 'z':
+ case 'Z': do_vision();
+ break;
+
+ default: Fprintf(stderr, "Unknown option '%c'.\n",
+ *options);
+ (void) fflush(stderr);
+ exit(EXIT_FAILURE);
+
+ }
+ options++;
+ }
+ if (more_than_one) Fprintf(stderr, "Completed.\n"); /* feedback */
+
+}
+
+
+/* trivial text encryption routine which can't be broken with `tr' */
+static
+char *xcrypt(str)
+const char *str;
+{ /* duplicated in src/hacklib.c */
+ static char buf[BUFSZ];
+ register const char *p;
+ register char *q;
+ register int bitmask;
+
+ for (bitmask = 1, p = str, q = buf; *p; q++) {
+ *q = *p++;
+ if (*q & (32|64)) *q ^= bitmask;
+ if ((bitmask <<= 1) >= 32) bitmask = 1;
+ }
+ *q = '\0';
+ return buf;
+}
+
+void
+do_rumors()
+{
+ char infile[60];
+ long true_rumor_size;
+
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename,file_prefix);
+#endif
+ Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE);
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+ Fprintf(ofp,Dont_Edit_Data);
+
+ Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
+ Strcat(infile, ".tru");
+ if (!(ifp = fopen(infile, RDTMODE))) {
+ perror(infile);
+ Fclose(ofp);
+ Unlink(filename); /* kill empty output file */
+ exit(EXIT_FAILURE);
+ }
+
+ /* get size of true rumors file */
+#ifndef VMS
+ (void) fseek(ifp, 0L, SEEK_END);
+ true_rumor_size = ftell(ifp);
+#else
+ /* seek+tell is only valid for stream format files; since rumors.%%%
+ might be in record format, count the actual data bytes instead.
+ */
+ true_rumor_size = 0;
+ while (fgets(in_line, sizeof in_line, ifp) != 0)
+ true_rumor_size += strlen(in_line); /* includes newline */
+#endif /* VMS */
+ Fprintf(ofp,"%06lx\n", true_rumor_size);
+ (void) fseek(ifp, 0L, SEEK_SET);
+
+ /* copy true rumors */
+ while (fgets(in_line, sizeof in_line, ifp) != 0)
+ (void) fputs(xcrypt(in_line), ofp);
+
+ Fclose(ifp);
+
+ Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
+ Strcat(infile, ".fal");
+ if (!(ifp = fopen(infile, RDTMODE))) {
+ perror(infile);
+ Fclose(ofp);
+ Unlink(filename); /* kill incomplete output file */
+ exit(EXIT_FAILURE);
+ }
+
+ /* copy false rumors */
+ while (fgets(in_line, sizeof in_line, ifp) != 0)
+ (void) fputs(xcrypt(in_line), ofp);
+
+ Fclose(ifp);
+ Fclose(ofp);
+ return;
+}
+
+static void
+make_version()
+{
+ register int i;
+
+ /*
+ * integer version number
+ */
+ version.incarnation = ((unsigned long)VERSION_MAJOR << 24) |
+ ((unsigned long)VERSION_MINOR << 16) |
+ ((unsigned long)PATCHLEVEL << 8) |
+ ((unsigned long)EDITLEVEL);
+ /*
+ * encoded feature list
+ * Note: if any of these magic numbers are changed or reassigned,
+ * EDITLEVEL in patchlevel.h should be incremented at the same time.
+ * The actual values have no special meaning, and the category
+ * groupings are just for convenience.
+ */
+ version.feature_set = (unsigned long)(0L
+ /* levels and/or topology (0..4) */
+#ifdef REINCARNATION
+ | (1L << 1)
+#endif
+#ifdef SINKS
+ | (1L << 2)
+#endif
+ /* monsters (5..9) */
+#ifdef KOPS
+ | (1L << 6)
+#endif
+#ifdef MAIL
+ | (1L << 7)
+#endif
+ /* objects (10..14) */
+#ifdef TOURIST
+ | (1L << 10)
+#endif
+#ifdef STEED
+ | (1L << 11)
+#endif
+#ifdef GOLDOBJ
+ | (1L << 12)
+#endif
+ /* flag bits and/or other global variables (15..26) */
+#ifdef TEXTCOLOR
+ | (1L << 17)
+#endif
+#ifdef INSURANCE
+ | (1L << 18)
+#endif
+#ifdef ELBERETH
+ | (1L << 19)
+#endif
+#ifdef EXP_ON_BOTL
+ | (1L << 20)
+#endif
+#ifdef SCORE_ON_BOTL
+ | (1L << 21)
+#endif
+#ifdef TIMED_DELAY
+ | (1L << 23)
+#endif
+ /* data format [COMPRESS excluded] (27..31) */
+#ifdef ZEROCOMP
+ | (1L << 27)
+#endif
+#ifdef RLECOMP
+ | (1L << 28)
+#endif
+ );
+ /*
+ * Value used for object & monster sanity check.
+ * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
+ */
+ for (i = 1; artifact_names[i]; i++) continue;
+ version.entity_count = (unsigned long)(i - 1);
+ for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++) continue;
+ version.entity_count = (version.entity_count << 12) | (unsigned long)i;
+ for (i = 0; mons[i].mlet; i++) continue;
+ version.entity_count = (version.entity_count << 12) | (unsigned long)i;
+ /*
+ * Value used for compiler (word size/field alignment/padding) check.
+ */
+ version.struct_sizes = (((unsigned long)sizeof (struct flag) << 24) |
+ ((unsigned long)sizeof (struct obj) << 17) |
+ ((unsigned long)sizeof (struct monst) << 10) |
+ ((unsigned long)sizeof (struct you)));
+ return;
+}
+
+static char *
+version_string(outbuf)
+char *outbuf;
+{
+ Sprintf(outbuf, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
+#ifdef BETA
+ Sprintf(eos(outbuf), "-%d", EDITLEVEL);
+#endif
+ return outbuf;
+}
+
+static char *
+version_id_string(outbuf, build_date)
+char *outbuf;
+const char *build_date;
+{
+ char subbuf[64], versbuf[64];
+
+ subbuf[0] = '\0';
+#ifdef PORT_SUB_ID
+ subbuf[0] = ' ';
+ Strcpy(&subbuf[1], PORT_SUB_ID);
+#endif
+#ifdef BETA
+ Strcat(subbuf, " Beta");
+#endif
+
+ Sprintf(outbuf, "%s NetHack%s Version %s - last build %s.",
+ PORT_ID, subbuf, version_string(versbuf), build_date);
+ return outbuf;
+}
+
+void
+do_date()
+{
+ long clocktim = 0;
+ char *c, cbuf[60], buf[BUFSZ];
+ const char *ul_sfx;
+
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename,file_prefix);
+#endif
+ Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE);
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+ Fprintf(ofp,"/*\tSCCS Id: @(#)date.h\t3.3\t1996/05/17 */\n\n");
+ Fprintf(ofp,Dont_Edit_Code);
+
+#ifdef KR1ED
+ (void) time(&clocktim);
+ Strcpy(cbuf, ctime(&clocktim));
+#else
+ (void) time((time_t *)&clocktim);
+ Strcpy(cbuf, ctime((time_t *)&clocktim));
+#endif
+ for (c = cbuf; *c; c++) if (*c == '\n') break;
+ *c = '\0'; /* strip off the '\n' */
+ Fprintf(ofp,"#define BUILD_DATE \"%s\"\n", cbuf);
+ Fprintf(ofp,"#define BUILD_TIME (%ldL)\n", clocktim);
+ Fprintf(ofp,"\n");
+#ifdef NHSTDC
+ ul_sfx = "UL";
+#else
+ ul_sfx = "L";
+#endif
+ Fprintf(ofp,"#define VERSION_NUMBER 0x%08lx%s\n",
+ version.incarnation, ul_sfx);
+ Fprintf(ofp,"#define VERSION_FEATURES 0x%08lx%s\n",
+ version.feature_set, ul_sfx);
+ Fprintf(ofp,"#define VERSION_SANITY1 0x%08lx%s\n",
+ version.entity_count, ul_sfx);
+ Fprintf(ofp,"#define VERSION_SANITY2 0x%08lx%s\n",
+ version.struct_sizes, ul_sfx);
+ Fprintf(ofp,"\n");
+ Fprintf(ofp,"#define VERSION_STRING \"%s\"\n", version_string(buf));
+ Fprintf(ofp,"#define VERSION_ID \\\n \"%s\"\n",
+ version_id_string(buf, cbuf));
+ Fprintf(ofp,"\n");
+#ifdef AMIGA
+ {
+ struct tm *tm = localtime((time_t *) &clocktim);
+ Fprintf(ofp,"#define AMIGA_VERSION_STRING ");
+ Fprintf(ofp,"\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
+ VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
+ tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900);
+ }
+#endif
+ Fclose(ofp);
+ return;
+}
+
+static const char *build_opts[] = {
+#ifdef AMIGA_WBENCH
+ "Amiga WorkBench support",
+#endif
+#ifdef ANSI_DEFAULT
+ "ANSI default terminal",
+#endif
+#ifdef TEXTCOLOR
+ "color",
+#endif
+#ifdef COM_COMPL
+ "command line completion",
+#endif
+#ifdef COMPRESS
+ "data file compression",
+#endif
+#ifdef DLB
+ "data librarian",
+#endif
+#ifdef WIZARD
+ "debug mode",
+#endif
+#ifdef ELBERETH
+ "Elbereth",
+#endif
+#ifdef EXP_ON_BOTL
+ "experience points on status line",
+#endif
+#ifdef MFLOPPY
+ "floppy drive support",
+#endif
+#ifdef GOLDOBJ
+ "gold object in inventories",
+#endif
+#ifdef INSURANCE
+ "insurance files for recovering from crashes",
+#endif
+#ifdef KOPS
+ "Keystone Kops",
+#endif
+#ifdef LOGFILE
+ "log file",
+#endif
+#ifdef MAIL
+ "mail daemon",
+#endif
+#ifdef GNUDOS
+ "MSDOS protected mode",
+#endif
+#ifdef NEWS
+ "news file",
+#endif
+#ifdef OVERLAY
+# ifdef MOVERLAY
+ "MOVE overlays",
+# else
+# ifdef VROOMM
+ "VROOMM overlays",
+# else
+ "overlays",
+# endif
+# endif
+#endif
+#ifdef REDO
+ "redo command",
+#endif
+#ifdef REINCARNATION
+ "rogue level",
+#endif
+#ifdef STEED
+ "saddles and riding",
+#endif
+#ifdef SCORE_ON_BOTL
+ "score on status line",
+#endif
+#ifdef CLIPPING
+ "screen clipping",
+#endif
+#ifdef NO_TERMS
+# ifdef MAC
+ "screen control via mactty",
+# endif
+# ifdef SCREEN_8514
+ "screen control via 8514/A graphics",
+# endif
+# ifdef SCREEN_BIOS
+ "screen control via BIOS",
+# endif
+# ifdef SCREEN_DJGPPFAST
+ "screen control via DJGPP fast",
+# endif
+# ifdef SCREEN_VESA
+ "screen control via VESA graphics",
+# endif
+# ifdef SCREEN_VGA
+ "screen control via VGA graphics",
+# endif
+# ifdef WIN32CON
+ "screen control via WIN32 console I/O",
+# endif
+#endif
+#ifdef SEDUCE
+ "seduction",
+#endif
+#ifdef SHELL
+ "shell command",
+#endif
+#ifdef SINKS
+ "sinks",
+#endif
+#ifdef SUSPEND
+ "suspend command",
+#endif
+#ifdef TERMINFO
+ "terminal info library",
+#else
+# if defined(TERMLIB) || (!defined(MICRO) && defined(TTY_GRAPHICS))
+ "terminal capability library",
+# endif
+#endif
+#ifdef TIMED_DELAY
+ "timed wait for display effects",
+#endif
+#ifdef TOURIST
+ "tourists",
+#endif
+#ifdef PREFIXES_IN_USE
+ "variable playground",
+#endif
+#ifdef VISION_TABLES
+ "vision tables",
+#endif
+#ifdef WALLIFIED_MAZE
+ "walled mazes",
+#endif
+#ifdef ZEROCOMP
+ "zero-compressed save files",
+#endif
+ "basic NetHack features"
+ };
+
+static const char *window_opts[] = {
+#ifdef TTY_GRAPHICS
+ "traditional tty-based graphics",
+#endif
+#ifdef X11_GRAPHICS
+ "X11",
+#endif
+#ifdef QT_GRAPHICS
+ "Qt",
+#endif
+#ifdef GNOME_GRAPHICS
+ "Gnome",
+#endif
+#ifdef MAC
+ "Mac",
+#endif
+#ifdef AMIGA_INTUITION
+ "Amiga Intuition",
+#endif
+#ifdef GEM_GRAPHICS
+ "Gem",
+#endif
+#ifdef WIN32_GRAPHICS
+ "Win32",
+#endif
+#ifdef BEOS_GRAPHICS
+ "BeOS InterfaceKit",
+#endif
+ 0
+ };
+
+void
+do_options()
+{
+ register int i, length;
+ register const char *str, *indent = " ";
+
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename,file_prefix);
+#endif
+ Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE);
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+
+ Fprintf(ofp,
+#ifdef BETA
+ "\n NetHack version %d.%d.%d [beta]\n",
+#else
+ "\n NetHack version %d.%d.%d\n",
+#endif
+ VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
+
+ Fprintf(ofp,"\nOptions compiled into this edition:\n");
+
+ length = COLNO + 1; /* force 1st item onto new line */
+ for (i = 0; i < SIZE(build_opts); i++) {
+ str = build_opts[i];
+ if (length + strlen(str) > COLNO - 5)
+ Fprintf(ofp,"\n%s", indent), length = strlen(indent);
+ else
+ Fprintf(ofp," "), length++;
+ Fprintf(ofp,"%s", str), length += strlen(str);
+ Fprintf(ofp,(i < SIZE(build_opts) - 1) ? "," : "."), length++;
+ }
+
+ Fprintf(ofp,"\n\nSupported windowing systems:\n");
+
+ length = COLNO + 1; /* force 1st item onto new line */
+ for (i = 0; i < SIZE(window_opts) - 1; i++) {
+ str = window_opts[i];
+ if (length + strlen(str) > COLNO - 5)
+ Fprintf(ofp,"\n%s", indent), length = strlen(indent);
+ else
+ Fprintf(ofp," "), length++;
+ Fprintf(ofp,"%s", str), length += strlen(str);
+ Fprintf(ofp, ","), length++;
+ }
+ Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS);
+ Fprintf(ofp,"\n\n");
+
+ Fclose(ofp);
+ return;
+}
+
+/* routine to decide whether to discard something from data.base */
+static boolean
+d_filter(line)
+ char *line;
+{
+ if (*line == '#') return TRUE; /* ignore comment lines */
+ return FALSE;
+}
+
+ /*
+ *
+ New format (v3.1) of 'data' file which allows much faster lookups [pr]
+"do not edit" first record is a comment line
+01234567 hexadecimal formatted offset to text area
+name-a first name of interest
+123,4 offset to name's text, and number of lines for it
+name-b next name of interest
+name-c multiple names which share same description also
+456,7 share a single offset,count line
+. sentinel to mark end of names
+789,0 dummy record containing offset, count of EOF
+text-a 4 lines of descriptive text for name-a
+text-a at file position 0x01234567L + 123L
+text-a
+text-a
+text-b/text-c 7 lines of text for names-b and -c
+text-b/text-c at fseek(0x01234567L + 456L)
+...
+ *
+ */
+
+void
+do_data()
+{
+ char infile[60], tempfile[60];
+ boolean ok;
+ long txt_offset;
+ int entry_cnt, line_cnt;
+
+ Sprintf(tempfile, DATA_TEMPLATE, "database.tmp");
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename,file_prefix);
+#endif
+ Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE);
+ Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE);
+ Strcat(infile,
+#ifdef SHORT_FILENAMES
+ ".bas"
+#else
+ ".base"
+#endif
+ );
+ if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */
+ perror(infile);
+ exit(EXIT_FAILURE);
+ }
+ if (!(ofp = fopen(filename, WRTMODE))) { /* data */
+ perror(filename);
+ Fclose(ifp);
+ exit(EXIT_FAILURE);
+ }
+ if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */
+ perror(tempfile);
+ Fclose(ifp);
+ Fclose(ofp);
+ Unlink(filename);
+ exit(EXIT_FAILURE);
+ }
+
+ /* output a dummy header record; we'll rewind and overwrite it later */
+ Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L);
+
+ entry_cnt = line_cnt = 0;
+ /* read through the input file and split it into two sections */
+ while (fgets(in_line, sizeof in_line, ifp)) {
+ if (d_filter(in_line)) continue;
+ if (*in_line > ' ') { /* got an entry name */
+ /* first finish previous entry */
+ if (line_cnt) Fprintf(ofp, "%d\n", line_cnt), line_cnt = 0;
+ /* output the entry name */
+ (void) fputs(in_line, ofp);
+ entry_cnt++; /* update number of entries */
+ } else if (entry_cnt) { /* got some descriptive text */
+ /* update previous entry with current text offset */
+ if (!line_cnt) Fprintf(ofp, "%ld,", ftell(tfp));
+ /* save the text line in the scratch file */
+ (void) fputs(in_line, tfp);
+ line_cnt++; /* update line counter */
+ }
+ }
+ /* output an end marker and then record the current position */
+ if (line_cnt) Fprintf(ofp, "%d\n", line_cnt);
+ Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0);
+ txt_offset = ftell(ofp);
+ Fclose(ifp); /* all done with original input file */
+
+ /* reprocess the scratch file; 1st format an error msg, just in case */
+ Sprintf(in_line, "rewind of \"%s\"", tempfile);
+ if (rewind(tfp) != 0) goto dead_data;
+ /* copy all lines of text from the scratch file into the output file */
+ while (fgets(in_line, sizeof in_line, tfp))
+ (void) fputs(in_line, ofp);
+
+ /* finished with scratch file */
+ Fclose(tfp);
+ Unlink(tempfile); /* remove it */
+
+ /* update the first record of the output file; prepare error msg 1st */
+ Sprintf(in_line, "rewind of \"%s\"", filename);
+ ok = (rewind(ofp) == 0);
+ if (ok) {
+ Sprintf(in_line, "header rewrite of \"%s\"", filename);
+ ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, txt_offset) >= 0);
+ }
+ if (!ok) {
+dead_data: perror(in_line); /* report the problem */
+ /* close and kill the aborted output file, then give up */
+ Fclose(ofp);
+ Unlink(filename);
+ exit(EXIT_FAILURE);
+ }
+
+ /* all done */
+ Fclose(ofp);
+
+ return;
+}
+
+/* routine to decide whether to discard something from oracles.txt */
+static boolean
+h_filter(line)
+ char *line;
+{
+ static boolean skip = FALSE;
+ char tag[sizeof in_line];
+
+ SpinCursor(3);
+
+ if (*line == '#') return TRUE; /* ignore comment lines */
+ if (sscanf(line, "----- %s", tag) == 1) {
+ skip = FALSE;
+#ifndef SINKS
+ if (!strcmp(tag, "SINKS")) skip = TRUE;
+#endif
+#ifndef ELBERETH
+ if (!strcmp(tag, "ELBERETH")) skip = TRUE;
+#endif
+ } else if (skip && !strncmp(line, "-----", 5))
+ skip = FALSE;
+ return skip;
+}
+
+static const char *special_oracle[] = {
+ "\"...it is rather disconcerting to be confronted with the",
+ "following theorem from [Baker, Gill, and Solovay, 1975].",
+ "",
+ "Theorem 7.18 There exist recursive languages A and B such that",
+ " (1) P(A) == NP(A), and",
+ " (2) P(B) != NP(B)",
+ "",
+ "This provides impressive evidence that the techniques that are",
+ "currently available will not suffice for proving that P != NP or ",
+ "that P == NP.\" [Garey and Johnson, p. 185.]"
+};
+
+/*
+ The oracle file consists of a "do not edit" comment, a decimal count N
+ and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
+ records, separated by "---" lines. The first oracle is a special case.
+ The input data contains just those multi-line records, separated by
+ "-----" lines.
+ */
+
+void
+do_oracles()
+{
+ char infile[60], tempfile[60];
+ boolean in_oracle, ok;
+ long txt_offset, offset, fpos;
+ int oracle_cnt;
+ register int i;
+
+ Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp");
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename, file_prefix);
+#endif
+ Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE);
+ Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE);
+ Strcat(infile, ".txt");
+ if (!(ifp = fopen(infile, RDTMODE))) {
+ perror(infile);
+ exit(EXIT_FAILURE);
+ }
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ Fclose(ifp);
+ exit(EXIT_FAILURE);
+ }
+ if (!(tfp = fopen(tempfile, WRTMODE))) { /* oracles.tmp */
+ perror(tempfile);
+ Fclose(ifp);
+ Fclose(ofp);
+ Unlink(filename);
+ exit(EXIT_FAILURE);
+ }
+
+ /* output a dummy header record; we'll rewind and overwrite it later */
+ Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0);
+
+ /* handle special oracle; it must come first */
+ (void) fputs("---\n", tfp);
+ Fprintf(ofp, "%05lx\n", ftell(tfp)); /* start pos of special oracle */
+ for (i = 0; i < SIZE(special_oracle); i++) {
+ (void) fputs(xcrypt(special_oracle[i]), tfp);
+ (void) fputc('\n', tfp);
+ }
+ SpinCursor(3);
+
+ oracle_cnt = 1;
+ (void) fputs("---\n", tfp);
+ Fprintf(ofp, "%05lx\n", ftell(tfp)); /* start pos of first oracle */
+ in_oracle = FALSE;
+
+ while (fgets(in_line, sizeof in_line, ifp)) {
+ SpinCursor(3);
+
+ if (h_filter(in_line)) continue;
+ if (!strncmp(in_line, "-----", 5)) {
+ if (!in_oracle) continue;
+ in_oracle = FALSE;
+ oracle_cnt++;
+ (void) fputs("---\n", tfp);
+ Fprintf(ofp, "%05lx\n", ftell(tfp));
+ /* start pos of this oracle */
+ } else {
+ in_oracle = TRUE;
+ (void) fputs(xcrypt(in_line), tfp);
+ }
+ }
+
+ if (in_oracle) { /* need to terminate last oracle */
+ oracle_cnt++;
+ (void) fputs("---\n", tfp);
+ Fprintf(ofp, "%05lx\n", ftell(tfp)); /* eof position */
+ }
+
+ /* record the current position */
+ txt_offset = ftell(ofp);
+ Fclose(ifp); /* all done with original input file */
+
+ /* reprocess the scratch file; 1st format an error msg, just in case */
+ Sprintf(in_line, "rewind of \"%s\"", tempfile);
+ if (rewind(tfp) != 0) goto dead_data;
+ /* copy all lines of text from the scratch file into the output file */
+ while (fgets(in_line, sizeof in_line, tfp))
+ (void) fputs(in_line, ofp);
+
+ /* finished with scratch file */
+ Fclose(tfp);
+ Unlink(tempfile); /* remove it */
+
+ /* update the first record of the output file; prepare error msg 1st */
+ Sprintf(in_line, "rewind of \"%s\"", filename);
+ ok = (rewind(ofp) == 0);
+ if (ok) {
+ Sprintf(in_line, "header rewrite of \"%s\"", filename);
+ ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >=0);
+ }
+ if (ok) {
+ Sprintf(in_line, "data rewrite of \"%s\"", filename);
+ for (i = 0; i <= oracle_cnt; i++) {
+#ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */
+ if (!(ok = (fflush(ofp) == 0))) break;
+#endif
+ if (!(ok = (fpos = ftell(ofp)) >= 0)) break;
+ if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
+ if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1))) break;
+#ifdef MAC
+# ifdef __MWERKS__
+ /*
+ MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
+ (ANSI C Libraries) needs this rewind or else the fprintf
+ stops working. This may also be true for CW11, but has
+ never been checked.
+ */
+ rewind(ofp);
+# endif
+#endif
+ if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
+ if (!(ok = (fprintf(ofp, "%05lx\n", offset + txt_offset) >= 0)))
+ break;
+ }
+ }
+ if (!ok) {
+dead_data: perror(in_line); /* report the problem */
+ /* close and kill the aborted output file, then give up */
+ Fclose(ofp);
+ Unlink(filename);
+ exit(EXIT_FAILURE);
+ }
+
+ /* all done */
+ Fclose(ofp);
+
+ return;
+}
+
+
+static struct deflist {
+
+ const char *defname;
+ boolean true_or_false;
+} deflist[] = {
+#ifdef REINCARNATION
+ { "REINCARNATION", TRUE },
+#else
+ { "REINCARNATION", FALSE },
+#endif
+ { 0, 0 } };
+
+static int
+check_control(s)
+ char *s;
+{
+ int i;
+
+ if(s[0] != '%') return(-1);
+
+ for(i = 0; deflist[i].defname; i++)
+ if(!strncmp(deflist[i].defname, s+1, strlen(deflist[i].defname)))
+ return(i);
+
+ return(-1);
+}
+
+static char *
+without_control(s)
+ char *s;
+{
+ return(s + 1 + strlen(deflist[check_control(in_line)].defname));
+}
+
+void
+do_dungeon()
+{
+ int rcnt = 0;
+
+ Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE);
+ if (!(ifp = fopen(filename, RDTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename, file_prefix);
+#endif
+ Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE);
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+ Fprintf(ofp,Dont_Edit_Data);
+
+ while (fgets(in_line, sizeof in_line, ifp) != 0) {
+ SpinCursor(3);
+
+ rcnt++;
+ if(in_line[0] == '#') continue; /* discard comments */
+recheck:
+ if(in_line[0] == '%') {
+ int i = check_control(in_line);
+ if(i >= 0) {
+ if(!deflist[i].true_or_false) {
+ while (fgets(in_line, sizeof in_line, ifp) != 0)
+ if(check_control(in_line) != i) goto recheck;
+ } else
+ (void) fputs(without_control(in_line),ofp);
+ } else {
+ Fprintf(stderr, "Unknown control option '%s' in file %s at line %d.\n",
+ in_line, DGN_I_FILE, rcnt);
+ exit(EXIT_FAILURE);
+ }
+ } else
+ (void) fputs(in_line,ofp);
+ }
+ Fclose(ifp);
+ Fclose(ofp);
+
+ return;
+}
+
+static boolean
+ranged_attk(ptr) /* returns TRUE if monster can attack at range */
+ register struct permonst *ptr;
+{
+ register int i, j;
+ register int atk_mask = (1<<AT_BREA) | (1<<AT_SPIT) | (1<<AT_GAZE);
+
+ for(i = 0; i < NATTK; i++) {
+ if((j=ptr->mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1<<j)))
+ return TRUE;
+ }
+
+ return(FALSE);
+}
+
+/* This routine is designed to return an integer value which represents
+ * an approximation of monster strength. It uses a similar method of
+ * determination as "experience()" to arrive at the strength.
+ */
+static int
+mstrength(ptr)
+struct permonst *ptr;
+{
+ int i, tmp2, n, tmp = ptr->mlevel;
+
+ if(tmp > 49) /* special fixed hp monster */
+ tmp = 2*(tmp - 6) / 4;
+
+/* For creation in groups */
+ n = (!!(ptr->geno & G_SGROUP));
+ n += (!!(ptr->geno & G_LGROUP)) << 1;
+
+/* For ranged attacks */
+ if (ranged_attk(ptr)) n++;
+
+/* For higher ac values */
+ n += (ptr->ac < 4);
+ n += (ptr->ac < 0);
+
+/* For very fast monsters */
+ n += (ptr->mmove >= 18);
+
+/* For each attack and "special" attack */
+ for(i = 0; i < NATTK; i++) {
+
+ tmp2 = ptr->mattk[i].aatyp;
+ n += (tmp2 > 0);
+ n += (tmp2 == AT_MAGC);
+ n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG));
+ }
+
+/* For each "special" damage type */
+ for(i = 0; i < NATTK; i++) {
+
+ tmp2 = ptr->mattk[i].adtyp;
+ if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST)
+ || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE))
+ n += 2;
+ else if (strcmp(ptr->mname, "grid bug")) n += (tmp2 != AD_PHYS);
+ n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23);
+ }
+
+/* Leprechauns are special cases. They have many hit dice so they
+ can hit and are hard to kill, but they don't really do much damage. */
+ if (!strcmp(ptr->mname, "leprechaun")) n -= 2;
+
+/* Finally, adjust the monster level 0 <= n <= 24 (approx.) */
+ if(n == 0) tmp--;
+ else if(n >= 6) tmp += ( n / 2 );
+ else tmp += ( n / 3 + 1);
+
+ return((tmp >= 0) ? tmp : 0);
+}
+
+void
+do_monstr()
+{
+ register struct permonst *ptr;
+ register int i, j;
+
+ /*
+ * create the source file, "monstr.c"
+ */
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename, file_prefix);
+#endif
+ Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C);
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+ Fprintf(ofp,Dont_Edit_Code);
+ Fprintf(ofp,"#include \"config.h\"\n");
+ Fprintf(ofp,"\nconst int monstr[] = {\n");
+ for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) {
+
+ SpinCursor(3);
+
+ i = mstrength(ptr);
+ Fprintf(ofp,"%2d,%c", i, (++j & 15) ? ' ' : '\n');
+ }
+ /* might want to insert a final 0 entry here instead of just newline */
+ Fprintf(ofp,"%s};\n", (j & 15) ? "\n" : "");
+
+ Fprintf(ofp,"\nvoid NDECL(monstr_init);\n");
+ Fprintf(ofp,"\nvoid\n");
+ Fprintf(ofp,"monstr_init()\n");
+ Fprintf(ofp,"{\n");
+ Fprintf(ofp," return;\n");
+ Fprintf(ofp,"}\n");
+ Fprintf(ofp,"\n/*monstr.c*/\n");
+
+ Fclose(ofp);
+ return;
+}
+
+void
+do_permonst()
+{
+ int i;
+ char *c, *nam;
+
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename, file_prefix);
+#endif
+ Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE);
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+ Fprintf(ofp,"/*\tSCCS Id: @(#)pm.h\t3.3\t1994/09/10 */\n\n");
+ Fprintf(ofp,Dont_Edit_Code);
+ Fprintf(ofp,"#ifndef PM_H\n#define PM_H\n");
+
+ if (strcmp(mons[0].mname, "playermon") != 0)
+ Fprintf(ofp,"\n#define\tPM_PLAYERMON\t(-1)");
+
+ for (i = 0; mons[i].mlet; i++) {
+ SpinCursor(3);
+
+ Fprintf(ofp,"\n#define\tPM_");
+ if (mons[i].mlet == S_HUMAN &&
+ !strncmp(mons[i].mname, "were", 4))
+ Fprintf(ofp, "HUMAN_");
+ for (nam = c = tmpdup(mons[i].mname); *c; c++)
+ if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
+ else if (*c < 'A' || *c > 'Z') *c = '_';
+ Fprintf(ofp,"%s\t%d", nam, i);
+ }
+ Fprintf(ofp,"\n\n#define\tNUMMONS\t%d\n", i);
+ Fprintf(ofp,"\n#endif /* PM_H */\n");
+ Fclose(ofp);
+ return;
+}
+
+
+/* Start of Quest text file processing. */
+#include "qtext.h"
+
+static struct qthdr qt_hdr;
+static struct msghdr msg_hdr[N_HDR];
+static struct qtmsg *curr_msg;
+
+static int qt_line;
+
+static boolean in_msg;
+#define NO_MSG 1 /* strlen of a null line returned by fgets() */
+
+static boolean
+qt_comment(s)
+ char *s;
+{
+ if(s[0] == '#') return(TRUE);
+ return((boolean)(!in_msg && strlen(s) == NO_MSG));
+}
+
+static boolean
+qt_control(s)
+ char *s;
+{
+ return((boolean)(s[0] == '%' && (s[1] == 'C' || s[1] == 'E')));
+}
+
+static int
+get_hdr (code)
+ char *code;
+{
+ int i;
+
+ for(i = 0; i < qt_hdr.n_hdr; i++)
+ if(!strncmp(code, qt_hdr.id[i], LEN_HDR)) return (++i);
+
+ return(0);
+}
+
+static boolean
+new_id (code)
+ char *code;
+{
+ if(qt_hdr.n_hdr >= N_HDR) {
+ Fprintf(stderr, OUT_OF_HEADERS, qt_line);
+ return(FALSE);
+ }
+
+ strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR);
+ msg_hdr[qt_hdr.n_hdr].n_msg = 0;
+ qt_hdr.offset[qt_hdr.n_hdr++] = 0L;
+ return(TRUE);
+}
+
+static boolean
+known_msg(num, id)
+ int num, id;
+{
+ int i;
+
+ for(i = 0; i < msg_hdr[num].n_msg; i++)
+ if(msg_hdr[num].qt_msg[i].msgnum == id) return(TRUE);
+
+ return(FALSE);
+}
+
+
+static void
+new_msg(s, num, id)
+ char *s;
+ int num, id;
+{
+ struct qtmsg *qt_msg;
+
+ if(msg_hdr[num].n_msg >= N_MSG) {
+ Fprintf(stderr, OUT_OF_MESSAGES, qt_line);
+ } else {
+ qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]);
+ qt_msg->msgnum = id;
+ qt_msg->delivery = s[2];
+ qt_msg->offset = qt_msg->size = 0L;
+
+ curr_msg = qt_msg;
+ }
+}
+
+static void
+do_qt_control(s)
+ char *s;
+{
+ char code[BUFSZ];
+ int num, id = 0;
+
+ switch(s[1]) {
+
+ case 'C': if(in_msg) {
+ Fprintf(stderr, CREC_IN_MSG, qt_line);
+ break;
+ } else {
+ in_msg = TRUE;
+ if (sscanf(&s[4], "%s %5d", code, &id) != 2) {
+ Fprintf(stderr, UNREC_CREC, qt_line);
+ break;
+ }
+ num = get_hdr(code);
+ if (!num && !new_id(code))
+ break;
+ num = get_hdr(code)-1;
+ if(known_msg(num, id))
+ Fprintf(stderr, DUP_MSG, qt_line);
+ else new_msg(s, num, id);
+ }
+ break;
+
+ case 'E': if(!in_msg) {
+ Fprintf(stderr, END_NOT_IN_MSG, qt_line);
+ break;
+ } else in_msg = FALSE;
+ break;
+
+ default: Fprintf(stderr, UNREC_CREC, qt_line);
+ break;
+ }
+}
+
+static void
+do_qt_text(s)
+ char *s;
+{
+ curr_msg->size += strlen(s);
+ return;
+}
+
+static void
+adjust_qt_hdrs()
+{
+ int i, j;
+ long count = 0L, hdr_offset = sizeof(int) +
+ (sizeof(char)*LEN_HDR + sizeof(long)) * qt_hdr.n_hdr;
+
+ for(i = 0; i < qt_hdr.n_hdr; i++) {
+ qt_hdr.offset[i] = hdr_offset;
+ hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg;
+ }
+
+ for(i = 0; i < qt_hdr.n_hdr; i++)
+ for(j = 0; j < msg_hdr[i].n_msg; j++) {
+
+ msg_hdr[i].qt_msg[j].offset = hdr_offset + count;
+ count += msg_hdr[i].qt_msg[j].size;
+ }
+ return;
+}
+
+static void
+put_qt_hdrs()
+{
+ int i;
+
+ /*
+ * The main header record.
+ */
+#ifdef DEBUG
+ Fprintf(stderr, "%ld: header info.\n", ftell(ofp));
+#endif
+ (void) fwrite((genericptr_t)&(qt_hdr.n_hdr), sizeof(int), 1, ofp);
+ (void) fwrite((genericptr_t)&(qt_hdr.id[0][0]), sizeof(char)*LEN_HDR,
+ qt_hdr.n_hdr, ofp);
+ (void) fwrite((genericptr_t)&(qt_hdr.offset[0]), sizeof(long),
+ qt_hdr.n_hdr, ofp);
+#ifdef DEBUG
+ for(i = 0; i < qt_hdr.n_hdr; i++)
+ Fprintf(stderr, "%c @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]);
+
+ Fprintf(stderr, "\n");
+#endif
+
+ /*
+ * The individual class headers.
+ */
+ for(i = 0; i < qt_hdr.n_hdr; i++) {
+
+#ifdef DEBUG
+ Fprintf(stderr, "%ld: %c header info.\n", ftell(ofp),
+ qt_hdr.id[i]);
+#endif
+ (void) fwrite((genericptr_t)&(msg_hdr[i].n_msg), sizeof(int),
+ 1, ofp);
+ (void) fwrite((genericptr_t)&(msg_hdr[i].qt_msg[0]),
+ sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp);
+#ifdef DEBUG
+ { int j;
+ for(j = 0; j < msg_hdr[i].n_msg; j++)
+ Fprintf(stderr, "msg %d @ %ld (%ld)\n",
+ msg_hdr[i].qt_msg[j].msgnum,
+ msg_hdr[i].qt_msg[j].offset,
+ msg_hdr[i].qt_msg[j].size);
+ }
+#endif
+ }
+}
+
+void
+do_questtxt()
+{
+ Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE);
+ if(!(ifp = fopen(filename, RDTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename, file_prefix);
+#endif
+ Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE);
+ if(!(ofp = fopen(filename, WRBMODE))) {
+ perror(filename);
+ Fclose(ifp);
+ exit(EXIT_FAILURE);
+ }
+
+ qt_hdr.n_hdr = 0;
+ qt_line = 0;
+ in_msg = FALSE;
+
+ while (fgets(in_line, 80, ifp) != 0) {
+ SpinCursor (3);
+
+ qt_line++;
+ if(qt_control(in_line)) do_qt_control(in_line);
+ else if(qt_comment(in_line)) continue;
+ else do_qt_text(in_line);
+ }
+
+ (void) rewind(ifp);
+ in_msg = FALSE;
+ adjust_qt_hdrs();
+ put_qt_hdrs();
+ while (fgets(in_line, 80, ifp) != 0) {
+
+ if(qt_control(in_line)) {
+ in_msg = (in_line[1] == 'C');
+ continue;
+ } else if(qt_comment(in_line)) continue;
+#ifdef DEBUG
+ Fprintf(stderr, "%ld: %s", ftell(stdout), in_line);
+#endif
+ (void) fputs(xcrypt(in_line), ofp);
+ }
+ Fclose(ifp);
+ Fclose(ofp);
+ return;
+}
+
+
+static char temp[32];
+
+static char *
+limit(name,pref) /* limit a name to 30 characters length */
+char *name;
+int pref;
+{
+ (void) strncpy(temp, name, pref ? 26 : 30);
+ temp[pref ? 26 : 30] = 0;
+ return temp;
+}
+
+void
+do_objs()
+{
+ int i, sum = 0;
+ char *c, *objnam;
+ int nspell = 0;
+ int prefix = 0;
+ char class = '\0';
+ boolean sumerr = FALSE;
+
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename, file_prefix);
+#endif
+ Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE);
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+ Fprintf(ofp,"/*\tSCCS Id: @(#)onames.h\t3.3\t1994/09/10 */\n\n");
+ Fprintf(ofp,Dont_Edit_Code);
+ Fprintf(ofp,"#ifndef ONAMES_H\n#define ONAMES_H\n\n");
+
+ for(i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) {
+ SpinCursor(3);
+
+ objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init */
+ if (!(objnam = tmpdup(OBJ_NAME(objects[i])))) continue;
+
+ /* make sure probabilities add up to 1000 */
+ if(objects[i].oc_class != class) {
+ if (sum && sum != 1000) {
+ Fprintf(stderr, "prob error for class %d (%d%%)",
+ class, sum);
+ (void) fflush(stderr);
+ sumerr = TRUE;
+ }
+ class = objects[i].oc_class;
+ sum = 0;
+ }
+
+ for (c = objnam; *c; c++)
+ if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
+ else if (*c < 'A' || *c > 'Z') *c = '_';
+
+ switch (class) {
+ case WAND_CLASS:
+ Fprintf(ofp,"#define\tWAN_"); prefix = 1; break;
+ case RING_CLASS:
+ Fprintf(ofp,"#define\tRIN_"); prefix = 1; break;
+ case POTION_CLASS:
+ Fprintf(ofp,"#define\tPOT_"); prefix = 1; break;
+ case SPBOOK_CLASS:
+ Fprintf(ofp,"#define\tSPE_"); prefix = 1; nspell++; break;
+ case SCROLL_CLASS:
+ Fprintf(ofp,"#define\tSCR_"); prefix = 1; break;
+ case AMULET_CLASS:
+ /* avoid trouble with stupid C preprocessors */
+ Fprintf(ofp,"#define\t");
+ if(objects[i].oc_material == PLASTIC) {
+ Fprintf(ofp,"FAKE_AMULET_OF_YENDOR\t%d\n", i);
+ prefix = -1;
+ break;
+ }
+ break;
+ case GEM_CLASS:
+ /* avoid trouble with stupid C preprocessors */
+ if(objects[i].oc_material == GLASS) {
+ Fprintf(ofp,"/* #define\t%s\t%d */\n",
+ objnam, i);
+ prefix = -1;
+ break;
+ }
+ default:
+ Fprintf(ofp,"#define\t");
+ }
+ if (prefix >= 0)
+ Fprintf(ofp,"%s\t%d\n", limit(objnam, prefix), i);
+ prefix = 0;
+
+ sum += objects[i].oc_prob;
+ }
+
+ /* check last set of probabilities */
+ if (sum && sum != 1000) {
+ Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
+ (void) fflush(stderr);
+ sumerr = TRUE;
+ }
+
+ Fprintf(ofp,"#define\tLAST_GEM\t(JADE)\n");
+ Fprintf(ofp,"#define\tMAXSPELL\t%d\n", nspell+1);
+ Fprintf(ofp,"#define\tNUM_OBJECTS\t%d\n", i);
+
+ Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n");
+
+ for (i = 1; artifact_names[i]; i++) {
+ SpinCursor(3);
+
+ for (c = objnam = tmpdup(artifact_names[i]); *c; c++)
+ if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
+ else if (*c < 'A' || *c > 'Z') *c = '_';
+
+ if (!strncmp(objnam, "THE_", 4))
+ objnam += 4;
+#ifdef TOURIST
+ /* fudge _platinum_ YENDORIAN EXPRESS CARD */
+ if (!strncmp(objnam, "PLATINUM_", 9))
+ objnam += 9;
+#endif
+ Fprintf(ofp,"#define\tART_%s\t%d\n", limit(objnam, 1), i);
+ }
+
+ Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i-1);
+ Fprintf(ofp,"\n#endif /* ONAMES_H */\n");
+ Fclose(ofp);
+ if (sumerr) exit(EXIT_FAILURE);
+ return;
+}
+
+static char *
+tmpdup(str)
+const char *str;
+{
+ static char buf[128];
+
+ if (!str) return (char *)0;
+ (void)strncpy(buf, str, 127);
+ return buf;
+}
+
+static char *
+eos(str)
+char *str;
+{
+ while (*str) str++;
+ return str;
+}
+
+/*
+ * macro used to control vision algorithms:
+ * VISION_TABLES => generate tables
+ */
+
+void
+do_vision()
+{
+#ifdef VISION_TABLES
+ int i, j;
+
+ /* Everything is clear. xclear may be malloc'ed.
+ * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
+ */
+ for (i = 0; i < MAX_ROW; i++)
+ for (j = 0; j < MAX_COL; j++)
+ if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH)
+ xclear[i][j] = '\000';
+ else
+ xclear[i][j] = '\001';
+#endif /* VISION_TABLES */
+
+ SpinCursor(3);
+
+ /*
+ * create the include file, "vis_tab.h"
+ */
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename, file_prefix);
+#endif
+ Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+ Fprintf(ofp,Dont_Edit_Code);
+ Fprintf(ofp,"#ifdef VISION_TABLES\n");
+#ifdef VISION_TABLES
+ H_close_gen();
+ H_far_gen();
+#endif /* VISION_TABLES */
+ Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
+ Fclose(ofp);
+
+ SpinCursor(3);
+
+ /*
+ * create the source file, "vis_tab.c"
+ */
+ filename[0]='\0';
+#ifdef FILE_PREFIX
+ Strcat(filename, file_prefix);
+#endif
+ Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C);
+ if (!(ofp = fopen(filename, WRTMODE))) {
+ perror(filename);
+ Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
+ Unlink(filename);
+ exit(EXIT_FAILURE);
+ }
+ Fprintf(ofp,Dont_Edit_Code);
+ Fprintf(ofp,"#include \"config.h\"\n");
+ Fprintf(ofp,"#ifdef VISION_TABLES\n");
+ Fprintf(ofp,"#include \"vis_tab.h\"\n");
+
+ SpinCursor(3);
+
+#ifdef VISION_TABLES
+ C_close_gen();
+ C_far_gen();
+ Fprintf(ofp,"\nvoid vis_tab_init() { return; }\n");
+#endif /* VISION_TABLES */
+
+ SpinCursor(3);
+
+ Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
+ Fprintf(ofp,"\n/*vis_tab.c*/\n");
+
+ Fclose(ofp);
+ return;
+}
+
+#ifdef VISION_TABLES
+
+/*-------------- vision tables --------------*\
+ *
+ * Generate the close and far tables. This is done by setting up a
+ * fake dungeon and moving our source to different positions relative
+ * to a block and finding the first/last visible position. The fake
+ * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
+ * by BLOCK_WIDTH) is blocked. Then we move the source around relative
+ * to the corner of the block. For each new position of the source
+ * we check positions on rows "kittycorner" from the source. We check
+ * positions until they are either in sight or out of sight (depends on
+ * which table we are generating). The picture below shows the setup
+ * for the generation of the close table. The generation of the far
+ * table would switch the quadrants of the '@' and the "Check rows
+ * here".
+ *
+ *
+ * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
+ * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ * ...............................
+ * ...............................
+ * .........@.....................
+ * ...............................
+ *
+ * Table generation figure (close_table). The 'X's are blocked points.
+ * The 'B' is a special blocked point. The '@' is the source. The ','s
+ * are the target area. The '.' are just open areas.
+ *
+ *
+ * Example usage of close_table[][][].
+ *
+ * The table is as follows:
+ *
+ * dy = |row of '@' - row of 'B'| - 1
+ * dx = |col of '@' - col of 'B'|
+ *
+ * The first indices are the deltas from the source '@' and the block 'B'.
+ * You must check for the value inside the abs value bars being zero. If
+ * so then the block is on the same row and you don't need to do a table
+ * lookup. The last value:
+ *
+ * dcy = |row of block - row to be checked|
+ *
+ * Is the value of the first visible spot on the check row from the
+ * block column. So
+ *
+ * first visible col = close_table[dy][dx][dcy] + col of 'B'
+ *
+\*-------------- vision tables --------------*/
+
+static void
+H_close_gen()
+{
+ Fprintf(ofp,"\n/* Close */\n");
+ Fprintf(ofp,"#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
+ TEST_HEIGHT-1);
+ Fprintf(ofp,"#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
+ TEST_WIDTH);
+ Fprintf(ofp,"#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
+ TEST_HEIGHT);
+ Fprintf(ofp,"typedef struct {\n");
+ Fprintf(ofp," unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
+ Fprintf(ofp,"} close2d;\n");
+ Fprintf(ofp,"extern close2d close_table[CLOSE_MAX_SB_DY];\n");
+ return;
+}
+
+static void
+H_far_gen()
+{
+ Fprintf(ofp,"\n/* Far */\n");
+ Fprintf(ofp,"#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
+ TEST_HEIGHT);
+ Fprintf(ofp,"#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
+ TEST_WIDTH-1);
+ Fprintf(ofp,"#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
+ TEST_HEIGHT-1);
+ Fprintf(ofp,"typedef struct {\n");
+ Fprintf(ofp," unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
+ Fprintf(ofp,"} far2d;\n");
+ Fprintf(ofp,"extern far2d far_table[FAR_MAX_SB_DY];\n");
+ return;
+}
+
+static void
+C_close_gen()
+{
+ int i,dx,dy;
+ int src_row, src_col; /* source */
+ int block_row, block_col; /* block */
+ int this_row;
+ int no_more;
+ const char *delim;
+
+ block_row = BLOCK_HEIGHT-1;
+ block_col = BLOCK_WIDTH-1;
+
+ Fprintf(ofp,"\n#ifndef FAR_TABLE_ONLY\n");
+ Fprintf(ofp,"\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
+#ifndef no_vision_progress
+ Fprintf(stderr,"\nclose:");
+#endif
+
+ for (dy = 1; dy < TEST_HEIGHT; dy++) {
+ src_row = block_row + dy;
+ Fprintf(ofp, "/* DY = %2d (- 1)*/\n {{\n", dy);
+#ifndef no_vision_progress
+ Fprintf(stderr," %2d",dy), (void)fflush(stderr);
+#endif
+ for (dx = 0; dx < TEST_WIDTH; dx++) {
+ src_col = block_col - dx;
+ Fprintf(ofp, " /*%2d*/ {", dx);
+
+ no_more = 0;
+ for (this_row = 0; this_row < TEST_HEIGHT; this_row++) {
+ delim = (this_row < TEST_HEIGHT - 1) ? "," : "";
+ if (no_more) {
+ Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim);
+ continue;
+ }
+ SpinCursor(3);
+
+ /* Find the first column that we can see. */
+ for (i = block_col+1; i < MAX_COL; i++) {
+ if (clear_path(src_row,src_col,block_row-this_row,i))
+ break;
+ }
+
+ if (i == MAX_COL) no_more = 1;
+ Fprintf(ofp, "%2d%s", i - block_col, delim);
+ }
+ Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
+ }
+ Fprintf(ofp," }},\n");
+ }
+
+ Fprintf(ofp,"}; /* close_table[] */\n"); /* closing brace for table */
+ Fprintf(ofp,"#endif /* !FAR_TABLE_ONLY */\n");
+#ifndef no_vision_progress
+ Fprintf(stderr,"\n");
+#endif
+ return;
+}
+
+static void
+C_far_gen()
+{
+ int i,dx,dy;
+ int src_row, src_col; /* source */
+ int block_row, block_col; /* block */
+ int this_row;
+ const char *delim;
+
+ block_row = BLOCK_HEIGHT-1;
+ block_col = BLOCK_WIDTH-1;
+
+ Fprintf(ofp,"\n#ifndef CLOSE_TABLE_ONLY\n");
+ Fprintf(ofp,"\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
+#ifndef no_vision_progress
+ Fprintf(stderr,"\n_far_:");
+#endif
+
+ for (dy = 0; dy < TEST_HEIGHT; dy++) {
+ src_row = block_row - dy;
+ Fprintf(ofp, "/* DY = %2d */\n {{\n", dy);
+#ifndef no_vision_progress
+ Fprintf(stderr," %2d",dy), (void)fflush(stderr);
+#endif
+ for (dx = 1; dx < TEST_WIDTH; dx++) {
+ src_col = block_col + dx;
+ Fprintf(ofp, " /*%2d(-1)*/ {", dx);
+
+ for (this_row = block_row+1; this_row < block_row+TEST_HEIGHT;
+ this_row++) {
+ delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : "";
+
+ SpinCursor(3);
+ /* Find first col that we can see. */
+ for (i = 0; i <= block_col; i++) {
+ if (clear_path(src_row,src_col,this_row,i)) break;
+ }
+
+ if (block_col-i < 0)
+ Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim);
+ else
+ Fprintf(ofp, "%2d%s", block_col - i, delim);
+ }
+ Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
+ }
+ Fprintf(ofp," }},\n");
+ }
+
+ Fprintf(ofp,"}; /* far_table[] */\n"); /* closing brace for table */
+ Fprintf(ofp,"#endif /* !CLOSE_TABLE_ONLY */\n");
+#ifndef no_vision_progress
+ Fprintf(stderr,"\n");
+#endif
+ return;
+}
+
+/*
+ * "Draw" a line from the hero to the given location. Stop if we hit a
+ * wall.
+ *
+ * Generalized integer Bresenham's algorithm (fast line drawing) for
+ * all quadrants. From _Procedural Elements for Computer Graphics_, by
+ * David F. Rogers. McGraw-Hill, 1985.
+ *
+ * I have tried a little bit of optimization by pulling compares out of
+ * the inner loops.
+ *
+ * NOTE: This had better *not* be called from a position on the
+ * same row as the hero.
+ */
+static int
+clear_path(you_row,you_col,y2,x2)
+ int you_row, you_col, y2, x2;
+{
+ int dx, dy, s1, s2;
+ register int i, error, x, y, dxs, dys;
+
+ x = you_col; y = you_row;
+ dx = abs(x2-you_col); dy = abs(y2-you_row);
+ s1 = sign(x2-you_col); s2 = sign(y2-you_row);
+
+ if (s1 == 0) { /* same column */
+ if (s2 == 1) { /* below (larger y2 value) */
+ for (i = you_row+1; i < y2; i++)
+ if (!xclear[i][you_col]) return 0;
+ } else { /* above (smaller y2 value) */
+ for (i = y2+1; i < you_row; i++)
+ if (!xclear[i][you_col]) return 0;
+ }
+ return 1;
+ }
+
+ /*
+ * Lines at 0 and 90 degrees have been weeded out.
+ */
+ if (dy > dx) {
+ error = dx; dx = dy; dy = error; /* swap the values */
+ dxs = dx << 1; /* save the shifted values */
+ dys = dy << 1;
+ error = dys - dx; /* NOTE: error is used as a temporary above */
+
+ for (i = 0; i < dx; i++) {
+ if (!xclear[y][x]) return 0; /* plot point */
+
+ while (error >= 0) {
+ x += s1;
+ error -= dxs;
+ }
+ y += s2;
+ error += dys;
+ }
+ } else {
+ dxs = dx << 1; /* save the shifted values */
+ dys = dy << 1;
+ error = dys - dx;
+
+ for (i = 0; i < dx; i++) {
+ if (!xclear[y][x]) return 0; /* plot point */
+
+ while (error >= 0) {
+ y += s2;
+ error -= dxs;
+ }
+ x += s1;
+ error += dys;
+ }
+ }
+ return 1;
+}
+#endif /* VISION_TABLES */
+
+#ifdef STRICT_REF_DEF
+NEARDATA struct flag flags;
+# ifdef ATTRIB_H
+struct attribs attrmax, attrmin;
+# endif
+#endif /* STRICT_REF_DEF */
+
+/*makedefs.c*/