1 /* NetHack 3.6 makedefs.c $NHDT-Date: 1557254354 2019/05/07 18:39:14 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.145 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */
4 /* Copyright (c) M. Stephenson, 1990, 1991. */
5 /* Copyright (c) Dean Luick, 1990. */
6 /* NetHack may be freely redistributed. See license for details. */
8 #define MAKEDEFS_C /* use to conditionally include file sections */
12 #undef free /* makedefs doesn't use the alloc and free in src/alloc.c */
26 /* version information */
27 #ifdef SHORT_FILENAMES
30 #include "../japanese/jpatchle.h"
33 #include "patchlevel.h"
35 #include "../japanese/jpatchlevel.h"
41 #if defined(__SC__) || defined(__MRC__) /* MPW compilers */
43 #include <CursorCtl.h>
45 #else /* MAC without MPWTOOL */
46 #define MACsansMPWTOOL
54 #define Fprintf (void) fprintf
55 #define Fclose (void) fclose
56 #define Unlink (void) unlink
57 #if !defined(AMIGA) || defined(AZTEC_C)
58 #define rewind(fp) fseek((fp), 0L, SEEK_SET) /* guarantee a return value */
61 #if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN)
62 static const char SCCS_Id[] UNUSED = "@(#)makedefs.c\t3.6\t2019/05/07";
65 /* names of files to be generated */
66 #define DATE_FILE "date.h"
67 #define MONST_FILE "pm.h"
68 #define ONAME_FILE "onames.h"
70 #define OPTIONS_FILE "options"
72 #define ORACLE_FILE "oracles"
73 #define DATA_FILE "data"
74 #define RUMOR_FILE "rumors"
75 #define DGN_I_FILE "dungeon.def"
76 #define DGN_O_FILE "dungeon.pdf"
77 #define MON_STR_C "monstr.c"
78 #define QTXT_I_FILE "quest.txt"
79 #define QTXT_O_FILE "quest.dat"
80 #define VIS_TAB_H "vis_tab.h"
81 #define VIS_TAB_C "vis_tab.c"
82 #define GITINFO_FILE "gitinfo.txt"
83 /* locations for those files */
86 #define INCLUDE_TEMPLATE "NH:include/t.%s"
87 #define SOURCE_TEMPLATE "NH:src/%s"
88 #define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */
89 #define DATA_TEMPLATE "NH:slib/%s"
90 #define DATA_IN_TEMPLATE "NH:dat/%s"
92 #if defined(MAC) && !defined(__MACH__)
93 /* MacOS 9 or earlier */
94 #define INCLUDE_TEMPLATE ":include:%s"
95 #define SOURCE_TEMPLATE ":src:%s"
96 #define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */
98 #define DATA_TEMPLATE ":Dungeon:%s"
100 #define DATA_TEMPLATE ":lib:%s"
101 #endif /* __SC__ || __MRC__ */
102 #define DATA_IN_TEMPLATE ":dat:%s"
103 #else /* neither AMIGA nor MAC */
105 #define INCLUDE_TEMPLATE "..\\include\\%s"
106 #define SOURCE_TEMPLATE "..\\src\\%s"
107 #define DGN_TEMPLATE "..\\dat\\%s" /* where dungeon.pdf file goes */
108 #define DATA_TEMPLATE "..\\dat\\%s"
109 #define DATA_IN_TEMPLATE "..\\dat\\%s"
110 #else /* not AMIGA, MAC, or OS2 */
111 #define INCLUDE_TEMPLATE "../include/%s"
112 #define SOURCE_TEMPLATE "../src/%s"
113 #define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */
114 #define DATA_TEMPLATE "../dat/%s"
115 #define DATA_IN_TEMPLATE "../dat/%s"
116 #endif /* else !OS2 */
117 #endif /* else !MAC */
118 #endif /* else !AMIGA */
122 "/* This source file is generated by 'makedefs'. Do not edit. */\n",
124 "#\tThis data file is generated by 'makedefs'. Do not edit. \n";
126 static struct version_info version;
128 /* definitions used for vision tables */
129 #define TEST_WIDTH COLNO
130 #define TEST_HEIGHT ROWNO
131 #define BLOCK_WIDTH (TEST_WIDTH + 10)
132 #define BLOCK_HEIGHT TEST_HEIGHT /* don't need extra spaces */
133 #define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT)
134 #define MAX_COL (BLOCK_WIDTH + TEST_WIDTH)
135 /* Use this as an out-of-bound value in the close table. */
136 #define CLOSE_OFF_TABLE_STRING "99" /* for the close table */
137 #define FAR_OFF_TABLE_STRING "0xff" /* for the far table */
139 #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0))
141 static char xclear[MAX_ROW][MAX_COL];
143 /*-end of vision defs-*/
145 #define MAXFNAMELEN 600
147 static char filename[MAXFNAMELEN];
150 /* if defined, a first argument not starting with - is
151 * taken as a text string to be prepended to any
152 * output filename generated */
153 char *file_prefix = "";
156 #ifdef MACsansMPWTOOL
157 int FDECL(main, (void));
159 int FDECL(main, (int, char **));
161 void FDECL(do_makedefs, (char *));
164 void NDECL(do_dungeon);
166 void NDECL(do_options);
167 void NDECL(do_monstr);
168 void NDECL(do_permonst);
169 void NDECL(do_questtxt);
170 void NDECL(do_rumors);
171 void NDECL(do_oracles);
172 void NDECL(do_vision);
174 extern void NDECL(monst_init); /* monst.c */
175 extern void NDECL(objects_init); /* objects.c */
177 static void NDECL(link_sanity_check);
178 static char *FDECL(name_file, (const char *, const char *));
179 static void FDECL(delete_file, (const char *template, const char *));
180 static FILE *FDECL(getfp, (const char *, const char *, const char *));
181 static void FDECL(do_ext_makedefs, (int, char **));
183 static void NDECL(make_version);
184 static char *FDECL(version_string, (char *, const char *));
185 static char *FDECL(version_id_string, (char *, const char *));
186 static char *FDECL(bannerc_string, (char *, const char *));
187 static char *FDECL(xcrypt, (const char *));
188 static unsigned long FDECL(read_rumors_file,
189 (const char *, int *, long *, unsigned long));
190 static boolean FDECL(get_gitinfo, (char *, char *));
191 static void FDECL(do_rnd_access_file, (const char *));
192 static boolean FDECL(d_filter, (char *));
193 static boolean FDECL(h_filter, (char *));
194 static void NDECL(build_savebones_compat_string);
195 static void NDECL(windowing_sanity);
196 static void FDECL(opt_out_words, (char *, int *));
198 static boolean FDECL(qt_comment, (char *));
199 static boolean FDECL(qt_control, (char *));
200 static int FDECL(get_hdr, (char *));
201 static boolean FDECL(new_id, (char *));
202 static boolean FDECL(known_msg, (int, int));
203 static void FDECL(new_msg, (char *, int, int));
204 static char *FDECL(valid_qt_summary, (char *, BOOLEAN_P));
205 static void FDECL(do_qt_control, (char *));
206 static void FDECL(do_qt_text, (char *));
207 static void NDECL(adjust_qt_hdrs);
208 static void NDECL(put_qt_hdrs);
211 static void NDECL(H_close_gen);
212 static void NDECL(H_far_gen);
213 static void NDECL(C_close_gen);
214 static void NDECL(C_far_gen);
215 static int FDECL(clear_path, (int, int, int, int));
218 static char *FDECL(fgetline, (FILE*));
219 static char *FDECL(tmpdup, (const char *));
220 static char *FDECL(limit, (char *, int));
221 static char *FDECL(eos, (char *));
222 static int FDECL(case_insensitive_comp, (const char *, const char *));
224 /* input, output, tmp */
225 static FILE *ifp, *ofp, *tfp;
227 #if defined(__BORLANDC__) && !defined(_WIN32)
228 extern unsigned _stklen = STKSIZ;
231 #ifdef MACsansMPWTOOL
235 const char *def_options = "odemvpqrshz";
239 printf("Enter options to run: [%s] ", def_options);
241 fgets(buf, 100, stdin);
244 Strcpy(buf, def_options);
246 buf[len - 1] = 0; /* remove return */
248 if (buf[0] == '-' && buf[1] == '-') {
250 split up buf into words
251 do_ext_makedefs(fakeargc, fakeargv);
253 printf("extended makedefs not implemented for Mac OS9\n");
275 && !(argv[1][0] == '-' && argv[1][1] == '-'))) {
276 Fprintf(stderr, "Bad arg count (%d).\n", argc - 1);
277 (void) fflush(stderr);
282 if (argc >= 2 && argv[1][0] != '-') {
283 file_prefix = argv[1];
289 if (argv[1][0] == '-' && argv[1][1] == '-') {
290 do_ext_makedefs(argc, argv);
292 do_makedefs(&argv[1][1]);
304 /* Note: these initializers don't do anything except guarantee that
305 we're linked properly.
316 boolean more_than_one;
320 /* construct the current version number */
323 more_than_one = strlen(options) > 1;
326 Fprintf(stderr, "makedefs -%c\n", *options);
364 do_rnd_access_file(EPITAPHFILE);
365 do_rnd_access_file(ENGRAVEFILE);
366 do_rnd_access_file(BOGUSMONFILE);
378 Fprintf(stderr, "Unknown option '%c'.\n", *options);
379 (void) fflush(stderr);
385 Fprintf(stderr, "Completed.\n"); /* feedback */
388 static char namebuf[1000];
391 name_file(template, tag)
392 const char *template;
395 Sprintf(namebuf, template, tag);
400 delete_file(template, tag)
401 const char *template;
404 char *name = name_file(template, tag);
410 getfp(template, tag, mode)
411 const char *template;
415 char *name = name_file(template, tag);
416 FILE *rv = fopen(name, mode);
419 Fprintf(stderr, "Can't open '%s'.\n", name);
425 static boolean debug = FALSE;
427 static FILE *inputfp;
428 static FILE *outputfp;
432 int is_defined; /* 0 undef; 1 defined */
434 /* struct grep_var grep_vars[] and TODO_* constants in include file: */
437 static void NDECL(do_grep_showvars);
438 static struct grep_var *FDECL(grepsearch, (const char *));
439 static int FDECL(grep_check_id, (const char *));
440 static void FDECL(grep_show_wstack, (const char *));
441 static char *FDECL(do_grep_control, (char *));
442 static void NDECL(do_grep);
443 static void FDECL(grep0, (FILE *, FILE *));
445 static int grep_trace = 0;
447 #define IS_OPTION(str) if (!strcmp(&argv[0][2], str))
454 Fprintf(stderr, "missing option\n"); \
455 exit(EXIT_FAILURE); \
459 do_ext_makedefs(int argc, char **argv)
466 argv++; /* skip program name */
469 if (argv[0][0] != '-')
471 if (argv[0][1] != '-') {
472 Fprintf(stderr, "Can't mix - and -- options.\n");
476 /* short version string for packaging - note no \n */
480 argv++; /* not CONSUME */
483 strcpy(delim, argv[0]);
484 Fprintf(stdout, "%s", version_string(buf, delim));
493 do_makedefs(argv[0]);
498 if (!strcmp(argv[0], "-")) {
501 inputfp = fopen(argv[0], RDTMODE);
503 Fprintf(stderr, "Can't open '%s'.\n", argv[0]);
509 IS_OPTION("output") {
511 if (!strcmp(argv[0], "-")) {
514 outputfp = fopen(argv[0], WRTMODE);
516 Fprintf(stderr, "Can't open '%s'.\n", argv[0]);
524 Fprintf(stderr, "Can't do grep and something else.\n");
530 IS_OPTION("grep-showvars") {
534 IS_OPTION("grep-trace") {
538 IS_OPTION("grep-define") {
542 p = grepsearch(argv[0]);
546 Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]);
551 IS_OPTION("grep-undef") {
555 p = grepsearch(argv[0]);
559 Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]);
568 Fprintf(stderr, "Unknown option '%s'.\n", argv[0]);
572 Fprintf(stderr, "unexpected argument '%s'.\n", argv[0]);
578 Fprintf(stderr, "Confused about what to do?\n");
581 Fprintf(stderr, "Nothing to do?\n");
595 * Any line NOT starting with a caret is either suppressed or passed
596 * through unchanged depending on the current conditional state.
598 * The default conditional state is printing on.
600 * Conditionals may be nested.
602 * makedefs will exit with a EXIT_FAILURE if any errors are detected;
603 * as many errors as possible are detected before giving up.
605 * Unknown identifiers are treated as TRUE and also as an error to
606 * allow processing to continue past the unknown identifier (note
607 * that "#undef" is different than unknown).
609 * Any line starting with a caret is a control line; as in C, zero or
610 * more spaces may be embedded in the line almost anywhere; the caret
611 * MUST be in column 1.
612 * (XXX for the moment, no white space is allowed after the caret because
613 * existing lines in the docs look like that.)
616 * ^^ a line starting with a (single) literal caret
617 * ^# a comment - the line is ignored
618 * ^?ID if defined(ID)
619 * ^!ID if !defined(ID)
623 #define GREP_MAGIC '^'
624 #define GREP_STACK_SIZE 100
626 static int grep_rewrite = 0; /* need to (possibly) rewrite lines */
628 static int grep_writing = 1; /* need to copy lines to output */
629 static int grep_errors = 0;
630 static int grep_sp = 0;
631 #define ST_LD(old, opp) (((old) ? 1 : 0) | ((opp) ? 2 : 0))
632 #define ST_OLD(v) (((v) & 1) != 0)
633 #define ST_OPP(v) (((v) & 2) != 0)
635 static int grep_stack[GREP_STACK_SIZE] = { ST_LD(1, 0) };
636 static int grep_lineno = 0;
643 for (x = 0; x < SIZE(grep_vars) - 1; x++) {
644 printf("%d\t%s\n", grep_vars[x].is_defined, grep_vars[x].name);
648 static struct grep_var *
652 /* XXX make into binary search */
655 while (x < SIZE(grep_vars) - 1) {
656 if (!strcmp(grep_vars[x].name, name))
657 return &grep_vars[x];
669 while (*id && isspace((uchar) *id))
672 Fprintf(stderr, "missing identifier in line %d", grep_lineno);
679 Fprintf(outputfp, "ID %d %s\n", rv->is_defined, id);
681 return rv->is_defined;
685 Fprintf(outputfp, "ID U %s\n", id);
687 Fprintf(stderr, "unknown identifier '%s' in line %d.\n", id, grep_lineno);
689 return 2; /* So new features can be checked before makedefs
694 grep_show_wstack(tag)
702 Fprintf(outputfp, "%s w=%d sp=%d\t", tag, grep_writing, grep_sp);
703 for (x = grep_sp; x >= 0 && x > grep_sp - 6; x--) {
704 Fprintf(outputfp, "[%d]=%d ", x, grep_stack[x]);
706 Fprintf(outputfp, "\n");
716 if (isspace((uchar) buf[0]))
717 return &buf[-1]; /* XXX see docs above */
719 while (buf[0] && isspace((uchar) buf[0]))
723 case '#': /* comment */
725 case '.': /* end of if level */
727 Fprintf(stderr, "unmatched ^. (endif) at line %d.\n",
731 grep_writing = ST_OLD(grep_stack[grep_sp--]);
732 grep_show_wstack("pop");
735 case '!': /* if not ID */
738 case '?': /* if ID */
739 if (grep_sp == GREP_STACK_SIZE - 2) {
740 Fprintf(stderr, "stack overflow at line %d.", grep_lineno);
744 isif = grep_check_id(&buf[1]) ? isif : !isif;
745 grep_stack[++grep_sp] = ST_LD(grep_writing, !isif);
748 grep_stack[++grep_sp] = ST_LD(0, 0);
749 /* grep_writing = 0; */
751 grep_show_wstack("push");
754 if (ST_ELSE & grep_stack[grep_sp]) {
755 Fprintf(stderr, "multiple : for same conditional at line %d.\n",
759 grep_writing = ST_OPP(grep_stack[grep_sp]);
760 grep_stack[grep_sp] |= ST_ELSE;
763 case '(': /* start of expression */
765 case GREP_MAGIC: /* ^^ -> ^ */
770 if (isprint((uchar) buf[0])) {
774 sprintf(str, "0x%02x", buf[0]);
776 Fprintf(stderr, "unknown control ^%s at line %d.\n", str,
789 /* no language features use this yet */
794 static void grep0(FILE *, FILE *);
800 Fprintf(stderr, "--grep requires --input\n");
803 Fprintf(stderr, "--grep requires --output\n");
805 if (!inputfp || !outputfp) {
809 grep0(inputfp, outputfp);
813 grep0(inputfp0, outputfp0)
817 char buf[16384]; /* looong, just in case */
819 while (!feof(inputfp0) && !ferror(inputfp0)) {
823 if (fgets(buf, sizeof(buf), inputfp0) == 0)
825 if ((tmp = strchr(buf, '\n')))
829 Fprintf(outputfp0, "%04d %c >%s\n", grep_lineno,
830 grep_writing ? ' ' : '#', buf);
833 if (buf[0] == GREP_MAGIC) {
834 buf1 = do_grep_control(&buf[1]);
842 do_grep_rewrite(buf1);
845 Fprintf(outputfp0, "%s\n", buf1);
847 if (ferror(inputfp0)) {
848 Fprintf(stderr, "read error!\n");
851 if (ferror(outputfp0)) {
852 Fprintf(stderr, "write error!\n");
858 Fprintf(stderr, "%d unterminated conditional level%s\n", grep_sp,
859 grep_sp == 1 ? "" : "s");
863 Fprintf(stderr, "%d error%s detected.\n", grep_errors,
864 grep_errors == 1 ? "" : "s");
869 /* trivial text encryption routine which can't be broken with `tr' */
873 { /* duplicated in src/hacklib.c */
874 static char buf[BUFSZ];
875 register const char *p;
877 register int bitmask;
879 for (bitmask = 1, p = str, q = buf; *p; q++) {
883 if ((bitmask <<= 1) >= 32)
890 #define PAD_RUMORS_TO 60
891 /* common code for do_rumors(). Return 0 on error. */
893 read_rumors_file(file_ext, rumor_count, rumor_size, old_rumor_offset)
894 const char *file_ext;
897 unsigned long old_rumor_offset;
899 char infile[MAXFNAMELEN];
901 unsigned long rumor_offset;
903 Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
904 Strcat(infile, file_ext);
905 if (!(ifp = fopen(infile, RDTMODE))) {
910 /* copy the rumors */
911 while ((line = fgetline(ifp)) != 0) {
913 /* rumor selection is accomplished by seeking to a random
914 position in the file, advancing to newline, and taking
915 the next line; therefore, rumors which follow long-line
916 rumors are most likely to be chosen and rumors which
917 follow short-line rumors are least likely to be chosen;
918 we ameliorate the latter by padding the shortest lines,
919 increasing the chance of the random seek landing in them */
920 int len = (int) strlen(line);
922 if (len <= PAD_RUMORS_TO) {
923 char *base = index(line, '\n');
924 /* this is only safe because fgetline() overallocates */
925 while (len++ < PAD_RUMORS_TO) {
934 /*[if we forced binary output, this would be sufficient]*/
935 *rumor_size += strlen(line); /* includes newline */
937 (void) fputs(xcrypt(line), tfp);
940 /* record the current position; next rumors section will start here */
941 rumor_offset = (unsigned long) ftell(tfp);
942 Fclose(ifp); /* all done with rumors.file_ext */
944 /* the calculated value for *_rumor_count assumes that
945 a single-byte line terminator is in use; for platforms
946 which use two byte CR+LF, we need to override that value
947 [it's much simpler to do so unconditionally, rendering
948 the loop's accumulation above obsolete] */
949 *rumor_size = (long) (rumor_offset - old_rumor_offset);
954 do_rnd_access_file(fname)
959 Sprintf(filename, DATA_IN_TEMPLATE, fname);
960 Strcat(filename, ".txt");
961 if (!(ifp = fopen(filename, RDTMODE))) {
967 Strcat(filename, file_prefix);
969 Sprintf(eos(filename), DATA_TEMPLATE, fname);
970 if (!(ofp = fopen(filename, WRTMODE))) {
974 Fprintf(ofp, "%s", Dont_Edit_Data);
976 tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE);
978 ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE);
980 while ((line = fgetline(ifp)) != 0) {
981 if (line[0] != '#' && line[0] != '\n')
982 (void) fputs(xcrypt(line), ofp);
988 delete_file(DATA_TEMPLATE, "grep.tmp");
996 static const char rumors_header[] =
997 "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n";
998 char tempfile[MAXFNAMELEN];
999 int true_rumor_count, false_rumor_count;
1000 long true_rumor_size, false_rumor_size;
1001 unsigned long true_rumor_offset, false_rumor_offset, eof_offset;
1003 Sprintf(tempfile, DATA_TEMPLATE, "rumors.tmp");
1006 Strcat(filename, file_prefix);
1008 Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE);
1009 if (!(ofp = fopen(filename, WRTMODE))) {
1013 if (!(tfp = fopen(tempfile, WRTMODE))) {
1019 true_rumor_count = false_rumor_count = 0;
1020 true_rumor_size = false_rumor_size = 0L;
1021 true_rumor_offset = false_rumor_offset = eof_offset = 0L;
1023 /* output a dummy header record; we'll replace it in final output */
1024 Fprintf(tfp, rumors_header, Dont_Edit_Data, true_rumor_count,
1025 true_rumor_size, true_rumor_offset, false_rumor_count,
1026 false_rumor_size, false_rumor_offset, eof_offset);
1027 /* record the current position; true rumors will start here */
1028 true_rumor_offset = ftell(tfp);
1030 false_rumor_offset = read_rumors_file(
1031 ".tru", &true_rumor_count, &true_rumor_size, true_rumor_offset);
1032 if (!false_rumor_offset)
1033 goto rumors_failure;
1035 eof_offset = read_rumors_file(".fal", &false_rumor_count,
1036 &false_rumor_size, false_rumor_offset);
1038 goto rumors_failure;
1040 /* get ready to transfer the contents of temp file to output file */
1041 line = malloc(BUFSZ + MAXFNAMELEN);
1042 Sprintf(line, "rewind of \"%s\"", tempfile);
1043 if (rewind(tfp) != 0) {
1046 goto rumors_failure;
1050 /* output the header record */
1051 Fprintf(ofp, rumors_header, Dont_Edit_Data, true_rumor_count,
1052 true_rumor_size, true_rumor_offset, false_rumor_count,
1053 false_rumor_size, false_rumor_offset, eof_offset);
1054 /* skip the temp file's dummy header */
1055 if (!(line = fgetline(tfp))) { /* "Don't Edit" */
1057 goto rumors_failure;
1060 if (!(line = fgetline(tfp))) { /* count,size,offset */
1062 goto rumors_failure;
1065 /* copy the rest of the temp file into the final output file */
1066 while ((line = fgetline(tfp)) != 0) {
1067 (void) fputs(line, ofp);
1070 /* all done; delete temp file */
1078 Unlink(filename); /* kill empty or incomplete output file */
1080 Unlink(tempfile); /* and temporary file */
1085 * Use this to explicitly mask out features during version checks.
1087 * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features
1088 * that the port/plaform which wrote the savefile was capable of
1089 * dealing with. Don't reject a savefile just because the port
1090 * reading the savefile doesn't match on all/some of them.
1091 * The actual compression features used to produce the savefile are
1092 * recorded in the savefile_info structure immediately following the
1093 * version_info, and that is what needs to be checked against the
1094 * feature set of the port that is reading the savefile back in.
1095 * That check is done in src/restore.c now.
1098 #define IGNORED_FEATURES \
1099 (0L | (1L << 19) /* SCORE_ON_BOTL */ \
1100 | (1L << 27) /* ZEROCOMP */ \
1101 | (1L << 28) /* RLECOMP */ \
1110 * integer version number
1112 version.incarnation = ((unsigned long) VERSION_MAJOR << 24)
1113 | ((unsigned long) VERSION_MINOR << 16)
1114 | ((unsigned long) PATCHLEVEL << 8)
1115 | ((unsigned long) EDITLEVEL);
1117 * encoded feature list
1118 * Note: if any of these magic numbers are changed or reassigned,
1119 * EDITLEVEL in patchlevel.h should be incremented at the same time.
1120 * The actual values have no special meaning, and the category
1121 * groupings are just for convenience.
1123 version.feature_set = (unsigned long) (0L
1124 /* levels and/or topology (0..4) */
1125 /* monsters (5..9) */
1129 /* objects (10..14) */
1130 /* flag bits and/or other global variables (15..26) */
1137 #ifdef SCORE_ON_BOTL
1140 /* data format (27..31)
1141 * External compression methods such as COMPRESS and ZLIB_COMP
1142 * do not affect the contents and are thus excluded from here */
1151 * Value used for object & monster sanity check.
1152 * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
1154 for (i = 1; artifact_names[i]; i++)
1156 version.entity_count = (unsigned long) (i - 1);
1157 for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++)
1159 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
1160 for (i = 0; mons[i].mlet; i++)
1162 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
1164 * Value used for compiler (word size/field alignment/padding) check.
1166 version.struct_sizes1 =
1167 (((unsigned long) sizeof(struct context_info) << 24)
1168 | ((unsigned long) sizeof(struct obj) << 17)
1169 | ((unsigned long) sizeof(struct monst) << 10)
1170 | ((unsigned long) sizeof(struct you)));
1171 version.struct_sizes2 = (((unsigned long) sizeof(struct flag) << 10) |
1172 /* free bits in here */
1174 ((unsigned long) sizeof(struct sysflag)));
1176 ((unsigned long) 0L));
1181 /* REPRODUCIBLE_BUILD will change this to TRUE */
1182 static boolean date_via_env = FALSE;
1185 version_string(outbuf, delim)
1189 Sprintf(outbuf, "%d%s%d%s%d", VERSION_MAJOR, delim, VERSION_MINOR, delim,
1192 Sprintf(eos(outbuf), "-%d", EDITLEVEL);
1198 version_id_string(outbuf, build_date)
1200 const char *build_date;
1202 char subbuf[64], versbuf[64];
1206 Strcpy(betabuf, " Beta");
1214 Strcpy(&subbuf[1], PORT_SUB_ID);
1217 Sprintf(outbuf, "%s NetHack%s Version %s%s - last %s %s.", PORT_ID,
1218 subbuf, version_string(versbuf, "."), betabuf,
1219 date_via_env ? "revision" : "build", build_date);
1225 jversion_id_string(outbuf, build_date)
1227 const char *build_date;
1229 char subbuf[64], versbuf[64];
1233 Strcat(subbuf, " Beta");
1236 Sprintf(outbuf, "%s JNetHack%s Version %s-%d.%d.", PORT_ID,
1237 subbuf, version_string(versbuf, "."), JVERSION_MAJOR, JVERSION_MINOR);
1243 bannerc_string(outbuf, build_date)
1245 const char *build_date;
1247 char subbuf[64], versbuf[64];
1252 Strcpy(&subbuf[1], PORT_SUB_ID);
1255 Strcat(subbuf, " Beta");
1258 Sprintf(outbuf, " Version %s %s%s, %s %s.",
1259 version_string(versbuf, "."), PORT_ID, subbuf,
1260 date_via_env ? "revised" : "built", &build_date[4]);
1262 Sprintf(outbuf, "%s NetHack%s %s Copyright 1985-%s (built %s)",
1263 PORT_ID, subbuf, version_string(versbuf,"."), RELEASE_YEAR,
1275 time_t clocktim = 0;
1277 char githash[BUFSZ], gitbranch[BUFSZ];
1278 char *c, cbuf[60], buf[BUFSZ];
1281 /* before creating date.h, make sure that xxx_GRAPHICS and
1282 DEFAULT_WINDOW_SYS have been set up in a viable fashion */
1287 Strcat(filename, file_prefix);
1289 Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE);
1290 if (!(ofp = fopen(filename, WRTMODE))) {
1294 /* NB: We've moved on from SCCS, but this way this line
1295 * won't get clobbered when downstream projects import
1296 * this file into something more modern. */
1297 Fprintf(ofp, "%s", Dont_Edit_Code);
1299 (void) time(&clocktim);
1300 #ifdef REPRODUCIBLE_BUILD
1303 * Use date+time of latest source file revision (set up in
1304 * our environment rather than derived by scanning sources)
1305 * instead of current date+time, so that later rebuilds of
1306 * the same sources specifying the same configuration will
1307 * produce the same result.
1309 * Changing the configuration should be done by modifying
1310 * config.h or <port>conf.h and setting SOURCE_DATE_EPOCH
1311 * based on whichever changed most recently, not by using
1312 * make CFLAGS='-Dthis -Dthat'
1313 * to make alterations on the fly.
1315 * Limited validation is performed to prevent dates in the
1316 * future (beyond a leeway of 24 hours) or distant past.
1318 * Assumes the value of time_t is in seconds, which is
1319 * fundamental for Unix and mandated by POSIX. For any ports
1320 * where that isn't true, leaving REPRODUCIBLE_BUILD disabled
1321 * is probably preferrable to hacking this code....
1323 static struct tm nh360; /* static init should yield UTC timezone */
1324 unsigned long sd_num, sd_earliest, sd_latest;
1325 const char *sd_str = getenv("SOURCE_DATE_EPOCH");
1328 sd_num = strtoul(sd_str, (char **) 0, 10);
1330 * Note: this does not need to be updated for future
1331 * releases. It serves as a sanity check for potentially
1332 * mis-set environment, not a hard baseline for when the
1333 * current version could have first been built.
1335 /* oldest date we'll accept: 7-Dec-2015 (release of 3.6.0) */
1337 nh360.tm_mon = 12 - 1;
1338 nh360.tm_year = 2015 - 1900;
1339 sd_earliest = (unsigned long) mktime(&nh360);
1340 /* 'youngest' date we'll accept: 24 hours in the future */
1341 sd_latest = (unsigned long) clocktim + 24L * 60L * 60L;
1343 if (sd_num >= sd_earliest && sd_num <= sd_latest) {
1344 /* use SOURCE_DATE_EPOCH value */
1345 clocktim = (time_t) sd_num;
1346 date_via_env = TRUE;
1348 Fprintf(stderr, "? Invalid value for SOURCE_DATE_EPOCH (%lu)",
1350 if (sd_num > 0L && sd_num < sd_earliest)
1351 Fprintf(stderr, ", older than %lu", sd_earliest);
1352 else if (sd_num > sd_latest)
1353 Fprintf(stderr, ", newer than %lu", sd_latest);
1354 Fprintf(stderr, ".\n");
1355 Fprintf(stderr, ": Reverting to current date+time (%lu).\n",
1356 (unsigned long) clocktim);
1357 (void) fflush(stderr);
1360 /* REPRODUCIBLE_BUILD enabled but SOURCE_DATE_EPOCH is missing */
1361 Fprintf(stderr, "? No value for SOURCE_DATE_EPOCH.\n");
1362 Fprintf(stderr, ": Using current date+time (%lu).\n",
1363 (unsigned long) clocktim);
1364 (void) fflush(stderr);
1366 Strcpy(cbuf, asctime(gmtime(&clocktim)));
1369 /* ordinary build: use current date+time */
1370 Strcpy(cbuf, ctime(&clocktim));
1373 if ((c = index(cbuf, '\n')) != 0)
1374 *c = '\0'; /* strip off the '\n' */
1381 Fprintf(ofp, "#define SOURCE_DATE_EPOCH (%lu%s) /* via getenv() */\n",
1382 (unsigned long) clocktim, ul_sfx);
1383 Fprintf(ofp, "#define BUILD_DATE \"%s\"\n", cbuf);
1385 Fprintf(ofp, "#define BUILD_TIME SOURCE_DATE_EPOCH\n");
1387 Fprintf(ofp, "#define BUILD_TIME (%lu%s)\n",
1388 (unsigned long) clocktim, ul_sfx);
1390 Fprintf(ofp, "#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation,
1392 Fprintf(ofp, "#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set,
1394 #ifdef IGNORED_FEATURES
1395 Fprintf(ofp, "#define IGNORED_FEATURES 0x%08lx%s\n",
1396 (unsigned long) IGNORED_FEATURES, ul_sfx);
1398 Fprintf(ofp, "#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count,
1400 Fprintf(ofp, "#define VERSION_SANITY2 0x%08lx%s\n", version.struct_sizes1,
1402 Fprintf(ofp, "#define VERSION_SANITY3 0x%08lx%s\n", version.struct_sizes2,
1405 Fprintf(ofp, "#define VERSION_STRING \"%s\"\n", version_string(buf, "."));
1406 Fprintf(ofp, "#define VERSION_ID \\\n \"%s\"\n",
1407 version_id_string(buf, cbuf));
1409 Fprintf(ofp,"#define JVERSION_ID \\\n \"%s\"\n",
1410 jversion_id_string(buf, cbuf));
1412 Fprintf(ofp, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n",
1413 bannerc_string(buf, cbuf));
1415 if (get_gitinfo(githash, gitbranch)) {
1416 Fprintf(ofp, "#define NETHACK_GIT_SHA \"%s\"\n", githash);
1417 Fprintf(ofp, "#define NETHACK_GIT_BRANCH \"%s\"\n", gitbranch);
1421 struct tm *tm = localtime((time_t *) &clocktim);
1423 Fprintf(ofp, "#define AMIGA_VERSION_STRING ");
1424 Fprintf(ofp, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
1425 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
1426 tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900);
1434 get_gitinfo(githash, gitbranch)
1435 char *githash, *gitbranch;
1439 char infile[MAXFNAMELEN];
1440 char *line, *strval, *opt, *c, *end;
1441 boolean havebranch = FALSE, havehash = FALSE;
1443 if (!githash || !gitbranch) return FALSE;
1445 Sprintf(infile, DATA_IN_TEMPLATE, GITINFO_FILE);
1446 if (!(gifp = fopen(infile, RDTMODE))) {
1447 /* perror(infile); */
1451 /* read the gitinfo file */
1452 while ((line = fgetline(gifp)) != 0) {
1453 strval = index(line, '=');
1454 if (strval && strlen(strval) < (BUFSZ-1)) {
1457 /* strip off the '\n' */
1458 if ((c = index(strval, '\n')) != 0)
1460 if ((c = index(opt, '\n')) != 0)
1462 /* strip leading and trailing white space */
1463 while (*strval == ' ' || *strval == '\t')
1466 while (--end >= strval && (*end == ' ' || *end == '\t'))
1468 while (*opt == ' ' || *opt == '\t')
1471 while (--end >= opt && (*end == ' ' || *end == '\t'))
1475 if ((len >= strlen("gitbranch")) && !case_insensitive_comp(opt, "gitbranch")) {
1476 Strcpy(gitbranch, strval);
1479 if ((len >= strlen("githash")) && !case_insensitive_comp(opt, "githash")) {
1480 Strcpy(githash, strval);
1487 if (havebranch && havehash)
1493 case_insensitive_comp(s1, s2)
1499 for (;; s1++, s2++) {
1506 if (u1 == '\0' || u1 != u2)
1512 static char save_bones_compat_buf[BUFSZ];
1515 build_savebones_compat_string()
1517 #ifdef VERSION_COMPATIBILITY
1518 unsigned long uver = VERSION_COMPATIBILITY;
1520 Strcpy(save_bones_compat_buf,
1521 "save and bones files accepted from version");
1522 #ifdef VERSION_COMPATIBILITY
1523 Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d",
1524 ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16),
1525 ((uver & 0x0000FF00L) >> 8), VERSION_MAJOR, VERSION_MINOR,
1528 Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only", VERSION_MAJOR,
1529 VERSION_MINOR, PATCHLEVEL);
1533 static const char *build_opts[] = {
1535 "Amiga WorkBench support",
1538 "ANSI default terminal",
1543 #ifdef TTY_TILES_ESCCODES
1544 "console escape codes for tile hinting",
1547 "command line completion",
1550 "Conway's Game of Life",
1553 "data file compression",
1556 "ZLIB data file compression",
1562 "end-of-game dumplogs",
1564 #ifdef HOLD_LOCKFILE_OPEN
1565 "exclusive lock on level 0 file",
1567 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
1568 "external program as a message handler",
1571 "floppy drive support",
1574 "insurance files for recovering from crashes",
1580 "extended log file",
1583 "errors and warnings log file",
1589 "MSDOS protected mode",
1605 /* pattern matching method will be substituted by nethack at run time */
1606 "pattern matching via :PATMATCH:",
1608 "pseudo random numbers generated by ISAAC64",
1611 /* include which specific one */
1612 "strong PRNG seed available from " DEV_RANDOM,
1614 "strong PRNG seed available from DEV_RANDOM",
1618 "strong PRNG seed available from CNG BCryptGenRandom()",
1620 #endif /* DEV_RANDOM */
1623 "pseudo random numbers generated by random()",
1625 "pseudo random numbers generated by C rand()",
1629 "restore saved games via menu",
1631 #ifdef SCORE_ON_BOTL
1632 "score on status line",
1639 "screen control via mactty",
1642 "screen control via BIOS",
1644 #ifdef SCREEN_DJGPPFAST
1645 "screen control via DJGPP fast",
1648 "screen control via VGA graphics",
1651 "screen control via WIN32 console I/O",
1657 "traditional status display",
1658 #ifdef STATUS_HILITES
1659 "status via windowport with highlighting",
1661 "status via windowport without highlighting",
1667 "terminal info library",
1669 #if defined(TERMLIB) \
1670 || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
1671 "terminal capability library",
1675 "tile_file in XPM format",
1677 #ifdef GRAPHIC_TOMBSTONE
1678 "graphical RIP screen",
1681 "timed wait for display effects",
1686 #ifdef PREFIXES_IN_USE
1687 "variable playground",
1689 #ifdef VISION_TABLES
1693 "zero-compressed save files",
1696 "run-length compression of map in save files",
1699 "system configuration at run-time",
1701 save_bones_compat_buf,
1702 "and basic NetHack features"
1706 const char *id, /* DEFAULT_WINDOW_SYS string */
1707 *name; /* description, often same as id */
1709 static struct win_info window_opts[] = {
1712 /* testing 'USE_TILES' here would bring confusion because it could
1713 apply to another interface such as X11, so check MSDOS explicitly
1714 instead; even checking TTY_TILES_ESCCODES would probably be
1715 confusing to most users (and it will already be listed separately
1716 in the compiled options section so users aware of it can find it) */
1718 "traditional text with optional 'tiles' graphics"
1720 /* assume that one or more of IBMgraphics, DECgraphics, or MACgraphics
1721 can be enabled; we can't tell from here whether that is accurate */
1722 "traditional text with optional line-drawing"
1726 #ifdef CURSES_GRAPHICS
1727 { "curses", "terminal-based graphics" },
1735 #ifdef GNOME_GRAPHICS
1736 { "Gnome", "Gnome" },
1741 #ifdef AMIGA_INTUITION
1742 { "amii", "Amiga Intuition" },
1747 #ifdef MSWIN_GRAPHICS
1748 { "mswin", "mswin" },
1750 #ifdef BEOS_GRAPHICS
1751 { "BeOS", "BeOS InterfaceKit" },
1759 #ifndef DEFAULT_WINDOW_SYS
1760 /* pre-standard compilers didn't support #error; wait til run-time */
1762 "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n");
1766 /* put in a dummy value so that do_options() will compile and makedefs
1767 will build, otherwise the message above won't ever get delivered */
1768 #define DEFAULT_WINDOW_SYS "<undefined>"
1769 #else /*DEFAULT_WINDOW_SYS*/
1771 if (!window_opts[0].id) {
1772 Fprintf(stderr, "Configuration error: no windowing systems "
1773 "(TTY_GRAPHICS, &c) enabled.\n");
1780 for (i = 0; window_opts[i].id; ++i)
1781 if (!strcmp(window_opts[i].id, DEFAULT_WINDOW_SYS))
1783 if (!window_opts[i].id) { /* went through whole list without a match */
1784 Fprintf(stderr, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n",
1785 DEFAULT_WINDOW_SYS);
1787 " does not match any enabled windowing system (%s%s).\n",
1788 window_opts[0].id, window_opts[1].id ? ", &c" : "");
1792 #endif /*DEFAULT_WINDOW_SYS*/
1795 static const char opt_indent[] = " ";
1798 opt_out_words(str, length_p)
1799 char *str; /* input, but modified during processing */
1800 int *length_p; /* in/out */
1805 word = index(str, ' ');
1807 /* treat " (" as unbreakable space */
1808 if (word && *(word + 1) == '(')
1809 word = index(word + 1, ' ');
1813 if (*length_p + (int) strlen(str) > COLNO - 5)
1814 Fprintf(ofp, "\n%s", opt_indent),
1815 *length_p = (int) strlen(opt_indent);
1817 Fprintf(ofp, " "), (*length_p)++;
1818 Fprintf(ofp, "%s", str), *length_p += (int) strlen(str);
1819 str += strlen(str) + (word ? 1 : 0);
1827 int i, length, winsyscnt;
1833 Strcat(filename, file_prefix);
1835 Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE);
1836 if (!(ofp = fopen(filename, WRTMODE))) {
1841 build_savebones_compat_string();
1842 Fprintf(ofp, "\n%sNetHack version %d.%d.%d%s\n",
1844 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
1852 Fprintf(ofp, "\nOptions compiled into this edition:\n");
1853 length = COLNO + 1; /* force 1st item onto new line */
1854 for (i = 0; i < SIZE(build_opts); i++) {
1855 opt_out_words(strcat(strcpy(buf, build_opts[i]),
1856 (i < SIZE(build_opts) - 1) ? "," : "."),
1859 Fprintf(ofp, "\n"); /* terminate last line of words */
1861 winsyscnt = SIZE(window_opts) - 1;
1862 Fprintf(ofp, "\nSupported windowing system%s:\n",
1863 (winsyscnt > 1) ? "s" : "");
1864 length = COLNO + 1; /* force 1st item onto new line */
1865 for (i = 0; i < winsyscnt; i++) {
1866 Sprintf(buf, "\"%s\"", window_opts[i].id);
1867 if (strcmp(window_opts[i].name, window_opts[i].id))
1868 Sprintf(eos(buf), " (%s)", window_opts[i].name);
1871 * 2 : foo and bar (note no period; comes from 'with default' below)
1872 * 3+: for, bar, and quux
1874 opt_out_words(strcat(buf, (winsyscnt == 1) ? "." /* no 'default' */
1875 : (winsyscnt == 2 && i == 0) ? " and"
1876 : (i == winsyscnt - 2) ? ", and"
1880 if (winsyscnt > 1) {
1881 Sprintf(buf, "with a default of \"%s\".", DEFAULT_WINDOW_SYS);
1882 opt_out_words(buf, &length);
1884 Fprintf(ofp, "\n"); /* terminate last line of words */
1886 /* end with a blank line */
1892 /* routine to decide whether to discard something from data.base */
1898 return TRUE; /* ignore comment lines */
1904 New format (v3.1) of 'data' file which allows much faster lookups [pr]
1905 "do not edit" first record is a comment line
1906 01234567 hexadecimal formatted offset to text area
1907 name-a first name of interest
1908 123,4 offset to name's text, and number of lines for it
1909 name-b next name of interest
1910 name-c multiple names which share same description also
1911 456,7 share a single offset,count line
1912 . sentinel to mark end of names
1913 789,0 dummy record containing offset, count of EOF
1914 text-a 4 lines of descriptive text for name-a
1915 text-a at file position 0x01234567L + 123L
1918 text-b/text-c 7 lines of text for names-b and -c
1919 text-b/text-c at fseek(0x01234567L + 456L)
1927 char infile[60], tempfile[60];
1930 int entry_cnt, line_cnt;
1933 Sprintf(tempfile, DATA_TEMPLATE, "database.tmp");
1936 Strcat(filename, file_prefix);
1938 Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE);
1939 Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE);
1940 #ifdef SHORT_FILENAMES
1941 Strcat(infile, ".bas");
1943 Strcat(infile, ".base");
1945 if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */
1949 if (!(ofp = fopen(filename, WRTMODE))) { /* data */
1954 if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */
1962 /* output a dummy header record; we'll rewind and overwrite it later */
1963 Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L);
1965 entry_cnt = line_cnt = 0;
1966 /* read through the input file and split it into two sections */
1967 while ((line = fgetline(ifp)) != 0) {
1969 if (d_filter(line)) {
1973 if (*line > ' ') { /* got an entry name */
1976 if (d_filter(line)) {
1980 uc = *((unsigned char *)line);
1981 if (uc > ' ') { /* got an entry name */
1983 /* first finish previous entry */
1985 Fprintf(ofp, "%d\n", line_cnt), line_cnt = 0;
1986 /* output the entry name */
1987 (void) fputs(line, ofp);
1988 entry_cnt++; /* update number of entries */
1989 } else if (entry_cnt) { /* got some descriptive text */
1990 /* update previous entry with current text offset */
1992 Fprintf(ofp, "%ld,", ftell(tfp));
1993 /* save the text line in the scratch file */
1994 (void) fputs(line, tfp);
1995 line_cnt++; /* update line counter */
1999 /* output an end marker and then record the current position */
2001 Fprintf(ofp, "%d\n", line_cnt);
2002 Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0);
2003 txt_offset = ftell(ofp);
2004 Fclose(ifp); /* all done with original input file */
2006 /* reprocess the scratch file; 1st format an error msg, just in case */
2007 line = malloc(BUFSZ + MAXFNAMELEN);
2008 Sprintf(line, "rewind of \"%s\"", tempfile);
2009 if (rewind(tfp) != 0)
2012 /* copy all lines of text from the scratch file into the output file */
2013 while ((line = fgetline(tfp)) != 0) {
2014 (void) fputs(line, ofp);
2018 /* finished with scratch file */
2020 Unlink(tempfile); /* remove it */
2022 /* update the first record of the output file; prepare error msg 1st */
2023 line = malloc(BUFSZ + MAXFNAMELEN);
2024 Sprintf(line, "rewind of \"%s\"", filename);
2025 ok = (rewind(ofp) == 0);
2027 Sprintf(line, "header rewrite of \"%s\"", filename);
2028 ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data,
2029 (unsigned long) txt_offset) >= 0);
2033 perror(line); /* report the problem */
2035 /* close and kill the aborted output file, then give up */
2048 /* routine to decide whether to discard something from oracles.txt */
2053 static boolean skip = FALSE;
2059 return TRUE; /* ignore comment lines */
2061 tag = malloc(strlen(line));
2062 if (sscanf(line, "----- %s", tag) == 1) {
2064 } else if (skip && !strncmp(line, "-----", 5))
2070 static const char *special_oracle[] = {
2072 "\"...it is rather disconcerting to be confronted with the",
2073 "following theorem from [Baker, Gill, and Solovay, 1975].", "",
2074 "Theorem 7.18 There exist recursive languages A and B such that",
2075 " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "",
2076 "This provides impressive evidence that the techniques that are",
2077 "currently available will not suffice for proving that P != NP or "
2079 "that P == NP.\" [Garey and Johnson, p. 185.]"
2081 "
\81u
\8e\9f\82Ì
\92è
\97\9d[Baker, Gill, and Solovay, 1975]
\82É
\92¼
\96Ê
\82·
\82é
\82±
\82Æ
\82Í",
2082 "
\82Þ
\82µ
\82ë
\8d¢
\98f
\82·
\82é
\82±
\82Æ
\82Å
\82 \82é
\81D",
2084 "
\92è
\97\9d 7.18
\8e\9f\82Ì
\82æ
\82¤
\82È
\8dÄ
\8bA
\93I
\8c¾
\8cê A
\81CB
\82ª
\91¶
\8dÝ
\82·
\82é",
2085 " (1) P(A) == NP(A)
\81C
\82©
\82Â",
2086 " (2) P(B) != NP(B)",
2088 "
\82±
\82ê
\82Í
\8c»
\8dÝ P != NP
\82Å
\82 \82é
\82©
\82Ü
\82½
\82Í P == NP
\82Å
\82 \82é
\82©
\82ð
\8fØ
\96¾
\82·
\82é",
2089 "
\97L
\8cø
\82È
\8eè
\96@
\82ª
\82È
\82¢
\82±
\82Æ
\82ð
\8b
\82
\8e¦
\82µ
\82Ä
\82¢
\82é
\81D
\81v",
2090 "[Garey and Johnson, p. 185.]"
2095 The oracle file consists of a "do not edit" comment, a decimal count N
2096 and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
2097 records, separated by "---" lines. The first oracle is a special case.
2098 The input data contains just those multi-line records, separated by
2105 char infile[60], tempfile[60];
2106 boolean in_oracle, ok;
2108 unsigned long txt_offset, offset;
2113 Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp");
2116 Strcat(filename, file_prefix);
2118 Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE);
2119 Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE);
2120 Strcat(infile, ".txt");
2121 if (!(ifp = fopen(infile, RDTMODE))) {
2125 if (!(ofp = fopen(filename, WRTMODE))) {
2130 if (!(tfp = fopen(tempfile, WRTMODE))) { /* oracles.tmp */
2138 /* output a dummy header record; we'll rewind and overwrite it later */
2139 Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0);
2141 /* handle special oracle; it must come first */
2142 (void) fputs("---\n", tfp);
2143 offset = (unsigned long) ftell(tfp);
2144 Fprintf(ofp, "%05lx\n", offset); /* start pos of special oracle */
2145 for (i = 0; i < SIZE(special_oracle); i++) {
2146 (void) fputs(xcrypt(special_oracle[i]), tfp);
2147 (void) fputc('\n', tfp);
2152 (void) fputs("---\n", tfp);
2153 offset = (unsigned long) ftell(tfp);
2154 Fprintf(ofp, "%05lx\n", offset); /* start pos of first oracle */
2157 while ((line = fgetline(ifp)) != 0) {
2160 if (h_filter(line)) {
2164 if (!strncmp(line, "-----", 5)) {
2171 (void) fputs("---\n", tfp);
2172 offset = (unsigned long) ftell(tfp);
2173 Fprintf(ofp, "%05lx\n", offset); /* start pos of this oracle */
2176 (void) fputs(xcrypt(line), tfp);
2181 if (in_oracle) { /* need to terminate last oracle */
2183 (void) fputs("---\n", tfp);
2184 offset = (unsigned long) ftell(tfp);
2185 Fprintf(ofp, "%05lx\n", offset); /* eof position */
2188 /* record the current position */
2189 txt_offset = (unsigned long) ftell(ofp);
2190 Fclose(ifp); /* all done with original input file */
2192 /* reprocess the scratch file; 1st format an error msg, just in case */
2193 line = malloc(BUFSZ + MAXFNAMELEN);
2194 Sprintf(line, "rewind of \"%s\"", tempfile);
2195 if (rewind(tfp) != 0)
2198 /* copy all lines of text from the scratch file into the output file */
2199 while ((line = fgetline(tfp)) != 0) {
2200 (void) fputs(line, ofp);
2204 /* finished with scratch file */
2206 Unlink(tempfile); /* remove it */
2208 /* update the first record of the output file; prepare error msg 1st */
2209 line = malloc(BUFSZ + MAXFNAMELEN);
2210 Sprintf(line, "rewind of \"%s\"", filename);
2211 ok = (rewind(ofp) == 0);
2213 Sprintf(line, "header rewrite of \"%s\"", filename);
2214 ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >= 0);
2217 Sprintf(line, "data rewrite of \"%s\"", filename);
2218 for (i = 0; i <= oracle_cnt; i++) {
2219 #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */
2220 if (!(ok = (fflush(ofp) == 0)))
2223 if (!(ok = (fpos = ftell(ofp)) >= 0))
2225 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0)))
2227 if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1)))
2232 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
2233 (ANSI C Libraries) needs this rewind or else the fprintf
2234 stops working. This may also be true for CW11, but has
2240 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0)))
2242 offset += txt_offset;
2243 if (!(ok = (fprintf(ofp, "%05lx\n", offset) >= 0)))
2249 perror(line); /* report the problem */
2251 /* close and kill the aborted output file, then give up */
2269 Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE);
2270 if (!(ifp = fopen(filename, RDTMODE))) {
2276 Strcat(filename, file_prefix);
2278 Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE);
2279 if (!(ofp = fopen(filename, WRTMODE))) {
2283 Fprintf(ofp, "%s", Dont_Edit_Data);
2285 tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE);
2287 ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE);
2289 while ((line = fgetline(ifp)) != 0) {
2292 if (line[0] == '#') {
2294 continue; /* discard comments */
2296 (void) fputs(line, ofp);
2302 delete_file(DATA_TEMPLATE, "grep.tmp");
2309 /* Don't break anything for ports that haven't been updated. */
2310 printf("DEPRECATION WARNINGS:\n");
2311 printf("'makedefs -m' is deprecated. Remove all references\n");
2312 printf(" to it from the build process.\n");
2313 printf("'monstr.c' is deprecated. Remove all references to\n");
2314 printf(" it from the build process.\n");
2315 printf("monstr[] is deprecated. Replace monstr[x] with\n");
2316 printf(" mons[x].difficulty\n");
2317 printf("monstr_init() is deprecated. Remove all references to it.\n");
2320 * create the source file, "monstr.c"
2324 Strcat(filename, file_prefix);
2326 Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C);
2327 if (!(ofp = fopen(filename, WRTMODE))) {
2331 Fprintf(ofp, "%s", Dont_Edit_Code);
2332 Fprintf(ofp, "#include \"config.h\"\n");
2333 Fprintf(ofp, "\nconst int monstrXXX[] = {\n");
2334 Fprintf(ofp, "0};\n");
2335 Fprintf(ofp, "/*\n");
2336 Fprintf(ofp, "DEPRECATION WARNINGS:\n");
2337 Fprintf(ofp, "'makedefs -m' is deprecated. Remove all references\n");
2338 Fprintf(ofp, " to it from the build process.\n");
2339 Fprintf(ofp, "'monstr.c' is deprecated. Remove all references to\n");
2340 Fprintf(ofp, " it from the build process.\n");
2341 Fprintf(ofp, "monstr[] is deprecated. Replace monstr[x] with\n");
2342 Fprintf(ofp, " mons[x].difficulty\n");
2343 Fprintf(ofp, "monstr_init() is deprecated. Remove all references to it.\n");
2344 Fprintf(ofp, "*/\n");
2346 Fprintf(ofp, "\nvoid NDECL(monstr_init);\n");
2347 Fprintf(ofp, "\nvoid\n");
2348 Fprintf(ofp, "monstr_init()\n");
2349 Fprintf(ofp, "{\n");
2350 Fprintf(ofp, " return;\n");
2351 Fprintf(ofp, "}\n");
2352 Fprintf(ofp, "\n/*monstr.c*/\n");
2366 Strcat(filename, file_prefix);
2368 Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE);
2369 if (!(ofp = fopen(filename, WRTMODE))) {
2373 Fprintf(ofp, "%s", Dont_Edit_Code);
2374 Fprintf(ofp, "#ifndef PM_H\n#define PM_H\n");
2376 for (i = 0; mons[i].mlet; i++) {
2379 Fprintf(ofp, "\n#define\tPM_");
2380 if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].mname, "were", 4))
2381 Fprintf(ofp, "HUMAN_");
2382 for (nam = c = tmpdup(mons[i].mname); *c; c++)
2383 if (*c >= 'a' && *c <= 'z')
2384 *c -= (char) ('a' - 'A');
2385 else if (*c < 'A' || *c > 'Z')
2387 Fprintf(ofp, "%s\t%d", nam, i);
2389 Fprintf(ofp, "\n\n#define\tNUMMONS\t%d\n", i);
2390 Fprintf(ofp, "\n#endif /* PM_H */\n");
2395 /* Start of Quest text file processing. */
2398 static struct qthdr qt_hdr;
2399 static struct msghdr msg_hdr[N_HDR];
2400 static struct qtmsg *curr_msg;
2404 static boolean in_msg;
2405 #define NO_MSG 1 /* strlen of a null line returned by fgets() */
2413 return (boolean) (!in_msg && strlen(s) == NO_MSG);
2420 return (boolean) (s[0] == '%' && (s[1] == 'C' || s[1] == 'E'));
2429 for (i = 0; i < qt_hdr.n_hdr; i++)
2430 if (!strncmp(code, qt_hdr.id[i], LEN_HDR))
2440 if (qt_hdr.n_hdr >= N_HDR) {
2441 Fprintf(stderr, OUT_OF_HEADERS, qt_line);
2445 strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR);
2446 msg_hdr[qt_hdr.n_hdr].n_msg = 0;
2447 qt_hdr.offset[qt_hdr.n_hdr++] = 0L;
2457 for (i = 0; i < msg_hdr[num].n_msg; i++)
2458 if (msg_hdr[num].qt_msg[i].msgnum == id)
2469 struct qtmsg *qt_msg;
2471 if (msg_hdr[num].n_msg >= N_MSG) {
2472 Fprintf(stderr, OUT_OF_MESSAGES, qt_line);
2474 qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]);
2475 qt_msg->msgnum = id;
2476 qt_msg->delivery = s[2];
2477 qt_msg->offset = qt_msg->size = qt_msg->summary_size = 0L;
2483 /* check %E record for "[summary text]" that nethack can stuff into the
2484 message history buffer when delivering text via window instead of pline */
2486 valid_qt_summary(s, parsing)
2487 char *s; /* end record: "%E" optionally followed by " [summary]" */
2488 boolean parsing; /* curr_msg is valid iff this is True */
2490 static char summary[BUFSZ];
2493 if (*s != '%' || *(s + 1) != 'E')
2495 if ((p = index(s, '[')) == 0)
2497 /* note: opening '[' and closing ']' will be retained in the output;
2498 anything after ']' will be discarded by putting a newline there */
2501 /* have an opening bracket; summary[] holds it and all text that follows
2504 /* find closing bracket */
2505 while (p > summary && *(p - 1) != ']')
2509 /* we backed up all the way to the start without finding a bracket */
2510 if (parsing) /* malformed summary */
2511 Fprintf(stderr, MAL_SUM, qt_line);
2512 } else if (p == summary + 1) {
2513 ; /* ignore empty [] */
2514 } else { /* got something */
2515 /* p points one spot past ']', usually to '\n';
2516 we need to include the \n as part of the size */
2518 /* during the writing pass we won't be able to recheck
2519 delivery, so any useless summary for a pline mode
2520 message has to be carried along to the output file */
2521 if (curr_msg->delivery == 'p')
2522 Fprintf(stderr, DUMB_SUM, qt_line);
2523 /* +1 is for terminating newline */
2524 curr_msg->summary_size = (long) (p - summary) + 1L;
2526 /* caller is writing rather than just parsing;
2527 force newline after the closing bracket */
2542 if (!index(s, '\n'))
2543 Fprintf(stderr, CTRL_TRUNC, qt_line);
2548 Fprintf(stderr, CREC_IN_MSG, qt_line);
2552 if (sscanf(&s[4], "%s %5d", code, &id) != 2) {
2553 Fprintf(stderr, UNREC_CREC, qt_line);
2556 num = get_hdr(code);
2557 if (!num && !new_id(code))
2559 num = get_hdr(code) - 1;
2560 if (known_msg(num, id))
2561 Fprintf(stderr, DUP_MSG, qt_line);
2563 new_msg(s, num, id);
2569 Fprintf(stderr, END_NOT_IN_MSG, qt_line);
2571 /* sets curr_msg->summary_size if applicable */
2572 (void) valid_qt_summary(s, TRUE);
2578 Fprintf(stderr, UNREC_CREC, qt_line);
2588 Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line);
2589 } else if (!index(s, '\n')) {
2590 Fprintf(stderr, TEXT_TRUNC, qt_line);
2593 curr_msg->size += strlen(s);
2601 long count = 0L, hdr_offset = sizeof(int)
2602 + (sizeof(char) * LEN_HDR + sizeof(long))
2605 for (i = 0; i < qt_hdr.n_hdr; i++) {
2606 qt_hdr.offset[i] = hdr_offset;
2607 hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg;
2610 for (i = 0; i < qt_hdr.n_hdr; i++)
2611 for (j = 0; j < msg_hdr[i].n_msg; j++) {
2612 msg_hdr[i].qt_msg[j].offset = hdr_offset + count;
2614 msg_hdr[i].qt_msg[j].size + msg_hdr[i].qt_msg[j].summary_size;
2625 * The main header record.
2628 Fprintf(stderr, "%ld: header info.\n", ftell(ofp));
2629 (void) fwrite((genericptr_t) & (qt_hdr.n_hdr), sizeof(int), 1, ofp);
2630 (void) fwrite((genericptr_t) & (qt_hdr.id[0][0]), sizeof(char) * LEN_HDR,
2632 (void) fwrite((genericptr_t) & (qt_hdr.offset[0]), sizeof(long),
2635 for (i = 0; i < qt_hdr.n_hdr; i++)
2636 Fprintf(stderr, "%s @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]);
2637 Fprintf(stderr, "\n");
2641 * The individual class headers.
2643 for (i = 0; i < qt_hdr.n_hdr; i++) {
2645 Fprintf(stderr, "%ld: %s header info.\n", ftell(ofp),
2647 (void) fwrite((genericptr_t) & (msg_hdr[i].n_msg), sizeof(int), 1,
2649 (void) fwrite((genericptr_t) & (msg_hdr[i].qt_msg[0]),
2650 sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp);
2654 for (j = 0; j < msg_hdr[i].n_msg; j++) {
2655 Fprintf(stderr, "msg %d @ %ld (%ld)",
2656 msg_hdr[i].qt_msg[j].msgnum,
2657 msg_hdr[i].qt_msg[j].offset,
2658 msg_hdr[i].qt_msg[j].size);
2659 if (msg_hdr[i].qt_msg[j].summary_size)
2660 Fprintf(stderr, " [%ld]",
2661 msg_hdr[i].qt_msg[j].summary_size);
2662 Fprintf(stderr, "\n");
2673 Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE);
2674 if (!(ifp = fopen(filename, RDTMODE))) {
2681 Strcat(filename, file_prefix);
2683 Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE);
2684 if (!(ofp = fopen(filename, WRBMODE))) {
2694 while ((line = fgetline(ifp)) != 0) {
2698 if (qt_control(line))
2699 do_qt_control(line);
2700 else if (qt_comment(line)) {
2712 while ((line = fgetline(ifp)) != 0) {
2713 if (qt_control(line)) {
2714 char *summary_p = 0;
2716 in_msg = (line[1] == 'C');
2718 summary_p = valid_qt_summary(line, FALSE);
2719 /* don't write anything unless we've got a summary */
2724 /* we have summary text; replace raw %E record with it */
2725 Strcpy(line, summary_p); /* (guaranteed to fit) */
2726 } else if (qt_comment(line)) {
2731 Fprintf(stderr, "%ld: %s", ftell(stdout), line);
2732 (void) fputs(xcrypt(line), ofp);
2740 static char temp[32];
2742 static char *limit(name, pref) /* limit a name to 30 characters length */
2746 (void) strncpy(temp, name, pref ? 26 : 30);
2747 temp[pref ? 26 : 30] = 0;
2759 boolean sumerr = FALSE;
2763 Strcat(filename, file_prefix);
2765 Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE);
2766 if (!(ofp = fopen(filename, WRTMODE))) {
2770 Fprintf(ofp, "%s", Dont_Edit_Code);
2771 Fprintf(ofp, "#ifndef ONAMES_H\n#define ONAMES_H\n\n");
2773 for (i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) {
2776 objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init */
2777 if (!(objnam = tmpdup(OBJ_NAME(objects[i]))))
2780 /* make sure probabilities add up to 1000 */
2781 if (objects[i].oc_class != class) {
2782 if (sum && sum != 1000) {
2783 Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
2784 (void) fflush(stderr);
2787 class = objects[i].oc_class;
2791 for (c = objnam; *c; c++)
2792 if (*c >= 'a' && *c <= 'z')
2793 *c -= (char) ('a' - 'A');
2794 else if (*c < 'A' || *c > 'Z')
2799 Fprintf(ofp, "#define\tWAN_");
2803 Fprintf(ofp, "#define\tRIN_");
2807 Fprintf(ofp, "#define\tPOT_");
2811 Fprintf(ofp, "#define\tSPE_");
2816 Fprintf(ofp, "#define\tSCR_");
2820 /* avoid trouble with stupid C preprocessors */
2821 Fprintf(ofp, "#define\t");
2822 if (objects[i].oc_material == PLASTIC) {
2823 Fprintf(ofp, "FAKE_AMULET_OF_YENDOR\t%d\n", i);
2829 /* avoid trouble with stupid C preprocessors */
2830 if (objects[i].oc_material == GLASS) {
2831 Fprintf(ofp, "/* #define\t%s\t%d */\n", objnam, i);
2837 Fprintf(ofp, "#define\t");
2840 Fprintf(ofp, "%s\t%d\n", limit(objnam, prefix), i);
2843 sum += objects[i].oc_prob;
2846 /* check last set of probabilities */
2847 if (sum && sum != 1000) {
2848 Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
2849 (void) fflush(stderr);
2853 Fprintf(ofp, "#define\tLAST_GEM\t(JADE)\n");
2854 Fprintf(ofp, "#define\tMAXSPELL\t%d\n", nspell + 1);
2855 Fprintf(ofp, "#define\tNUM_OBJECTS\t%d\n", i);
2857 Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n");
2859 for (i = 1; artifact_names[i]; i++) {
2862 for (c = objnam = tmpdup(artifact_names[i]); *c; c++)
2863 if (*c >= 'a' && *c <= 'z')
2864 *c -= (char) ('a' - 'A');
2865 else if (*c < 'A' || *c > 'Z')
2868 if (!strncmp(objnam, "THE_", 4))
2870 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
2871 if (!strncmp(objnam, "PLATINUM_", 9))
2873 Fprintf(ofp, "#define\tART_%s\t%d\n", limit(objnam, 1), i);
2876 Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i - 1);
2877 Fprintf(ofp, "\n#endif /* ONAMES_H */\n");
2884 /* Read one line from input, up to and including the next newline
2885 * character. Returns a pointer to the heap-allocated string, or a
2886 * null pointer if no characters were read.
2892 static const int inc = 256;
2894 char *c = malloc(len), *ret;
2897 ret = fgets(c + len - inc, inc, fd);
2902 } else if (index(c, '\n')) {
2903 /* normal case: we have a full line */
2907 c = realloc(c, len);
2916 static char buf[128];
2920 (void) strncpy(buf, str, 127);
2934 * macro used to control vision algorithms:
2935 * VISION_TABLES => generate tables
2941 #ifdef VISION_TABLES
2944 /* Everything is clear. xclear may be malloc'ed.
2945 * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
2947 for (i = 0; i < MAX_ROW; i++)
2948 for (j = 0; j < MAX_COL; j++)
2949 if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH)
2950 xclear[i][j] = '\000';
2952 xclear[i][j] = '\001';
2953 #endif /* VISION_TABLES */
2958 * create the include file, "vis_tab.h"
2962 Strcat(filename, file_prefix);
2964 Sprintf(eos(filename), INCLUDE_TEMPLATE, VIS_TAB_H);
2965 if (!(ofp = fopen(filename, WRTMODE))) {
2969 Fprintf(ofp, "%s", Dont_Edit_Code);
2970 Fprintf(ofp, "#ifdef VISION_TABLES\n");
2971 #ifdef VISION_TABLES
2974 #endif /* VISION_TABLES */
2975 Fprintf(ofp, "\n#endif /* VISION_TABLES */\n");
2981 * create the source file, "vis_tab.c"
2985 Strcat(filename, file_prefix);
2987 Sprintf(eos(filename), SOURCE_TEMPLATE, VIS_TAB_C);
2988 if (!(ofp = fopen(filename, WRTMODE))) {
2990 /* creating vis_tab.c failed; remove the vis_tab.h we just made */
2993 Strcat(filename, file_prefix);
2995 Sprintf(eos(filename), INCLUDE_TEMPLATE, VIS_TAB_H);
2999 Fprintf(ofp, "%s", Dont_Edit_Code);
3000 Fprintf(ofp, "#include \"config.h\"\n");
3001 Fprintf(ofp, "#ifdef VISION_TABLES\n");
3002 Fprintf(ofp, "#include \"vis_tab.h\"\n");
3006 #ifdef VISION_TABLES
3009 Fprintf(ofp, "\nvoid vis_tab_init() { return; }\n");
3010 #endif /* VISION_TABLES */
3014 Fprintf(ofp, "\n#endif /* VISION_TABLES */\n");
3015 Fprintf(ofp, "\n/*vis_tab.c*/\n");
3021 #ifdef VISION_TABLES
3023 /*-------------- vision tables --------------*\
3025 * Generate the close and far tables. This is done by setting up a
3026 * fake dungeon and moving our source to different positions relative
3027 * to a block and finding the first/last visible position. The fake
3028 * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
3029 * by BLOCK_WIDTH) is blocked. Then we move the source around relative
3030 * to the corner of the block. For each new position of the source
3031 * we check positions on rows "kittycorner" from the source. We check
3032 * positions until they are either in sight or out of sight (depends on
3033 * which table we are generating). The picture below shows the setup
3034 * for the generation of the close table. The generation of the far
3035 * table would switch the quadrants of the '@' and the "Check rows
3039 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
3040 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
3041 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
3042 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
3043 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
3044 * ...............................
3045 * ...............................
3046 * .........@.....................
3047 * ...............................
3049 * Table generation figure (close_table). The 'X's are blocked points.
3050 * The 'B' is a special blocked point. The '@' is the source. The ','s
3051 * are the target area. The '.' are just open areas.
3054 * Example usage of close_table[][][].
3056 * The table is as follows:
3058 * dy = |row of '@' - row of 'B'| - 1
3059 * dx = |col of '@' - col of 'B'|
3061 * The first indices are the deltas from the source '@' and the block 'B'.
3062 * You must check for the value inside the abs value bars being zero. If
3063 * so then the block is on the same row and you don't need to do a table
3064 * lookup. The last value:
3066 * dcy = |row of block - row to be checked|
3068 * Is the value of the first visible spot on the check row from the
3071 * first visible col = close_table[dy][dx][dcy] + col of 'B'
3073 \*-------------- vision tables --------------*/
3078 Fprintf(ofp, "\n/* Close */\n");
3080 "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
3083 "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
3086 "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
3088 Fprintf(ofp, "typedef struct {\n");
3090 " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
3091 Fprintf(ofp, "} close2d;\n");
3092 Fprintf(ofp, "extern close2d close_table[CLOSE_MAX_SB_DY];\n");
3099 Fprintf(ofp, "\n/* Far */\n");
3100 Fprintf(ofp, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
3103 "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
3106 "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
3108 Fprintf(ofp, "typedef struct {\n");
3109 Fprintf(ofp, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
3110 Fprintf(ofp, "} far2d;\n");
3111 Fprintf(ofp, "extern far2d far_table[FAR_MAX_SB_DY];\n");
3119 int src_row, src_col; /* source */
3120 int block_row, block_col; /* block */
3125 block_row = BLOCK_HEIGHT - 1;
3126 block_col = BLOCK_WIDTH - 1;
3128 Fprintf(ofp, "\n#ifndef FAR_TABLE_ONLY\n");
3129 Fprintf(ofp, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
3130 #ifndef no_vision_progress
3131 Fprintf(stderr, "\nclose:");
3134 for (dy = 1; dy < TEST_HEIGHT; dy++) {
3135 src_row = block_row + dy;
3136 Fprintf(ofp, "/* DY = %2d (- 1)*/\n {{\n", dy);
3137 #ifndef no_vision_progress
3138 Fprintf(stderr, " %2d", dy), (void) fflush(stderr);
3140 for (dx = 0; dx < TEST_WIDTH; dx++) {
3141 src_col = block_col - dx;
3142 Fprintf(ofp, " /*%2d*/ {", dx);
3145 for (this_row = 0; this_row < TEST_HEIGHT; this_row++) {
3146 delim = (this_row < TEST_HEIGHT - 1) ? "," : "";
3148 Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim);
3153 /* Find the first column that we can see. */
3154 for (i = block_col + 1; i < MAX_COL; i++) {
3155 if (clear_path(src_row, src_col, block_row - this_row, i))
3161 Fprintf(ofp, "%2d%s", i - block_col, delim);
3163 Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
3165 Fprintf(ofp, " }},\n");
3168 Fprintf(ofp, "}; /* close_table[] */\n"); /* closing brace for table */
3169 Fprintf(ofp, "#endif /* !FAR_TABLE_ONLY */\n");
3170 #ifndef no_vision_progress
3171 Fprintf(stderr, "\n");
3180 int src_row, src_col; /* source */
3181 int block_row, block_col; /* block */
3185 block_row = BLOCK_HEIGHT - 1;
3186 block_col = BLOCK_WIDTH - 1;
3188 Fprintf(ofp, "\n#ifndef CLOSE_TABLE_ONLY\n");
3189 Fprintf(ofp, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
3190 #ifndef no_vision_progress
3191 Fprintf(stderr, "\n_far_:");
3194 for (dy = 0; dy < TEST_HEIGHT; dy++) {
3195 src_row = block_row - dy;
3196 Fprintf(ofp, "/* DY = %2d */\n {{\n", dy);
3197 #ifndef no_vision_progress
3198 Fprintf(stderr, " %2d", dy), (void) fflush(stderr);
3200 for (dx = 1; dx < TEST_WIDTH; dx++) {
3201 src_col = block_col + dx;
3202 Fprintf(ofp, " /*%2d(-1)*/ {", dx);
3204 for (this_row = block_row + 1; this_row < block_row + TEST_HEIGHT;
3206 delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : "";
3209 /* Find first col that we can see. */
3210 for (i = 0; i <= block_col; i++) {
3211 if (clear_path(src_row, src_col, this_row, i))
3215 if (block_col - i < 0)
3216 Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim);
3218 Fprintf(ofp, "%2d%s", block_col - i, delim);
3220 Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
3222 Fprintf(ofp, " }},\n");
3225 Fprintf(ofp, "}; /* far_table[] */\n"); /* closing brace for table */
3226 Fprintf(ofp, "#endif /* !CLOSE_TABLE_ONLY */\n");
3227 #ifndef no_vision_progress
3228 Fprintf(stderr, "\n");
3234 * "Draw" a line from the hero to the given location. Stop if we hit a
3237 * Generalized integer Bresenham's algorithm (fast line drawing) for
3238 * all quadrants. From _Procedural Elements for Computer Graphics_, by
3239 * David F. Rogers. McGraw-Hill, 1985.
3241 * I have tried a little bit of optimization by pulling compares out of
3244 * NOTE: This had better *not* be called from a position on the
3245 * same row as the hero.
3248 clear_path(you_row, you_col, y2, x2)
3249 int you_row, you_col, y2, x2;
3252 register int i, error, x, y, dxs, dys;
3256 dx = abs(x2 - you_col);
3257 dy = abs(y2 - you_row);
3258 s1 = sign(x2 - you_col);
3259 s2 = sign(y2 - you_row);
3261 if (s1 == 0) { /* same column */
3262 if (s2 == 1) { /* below (larger y2 value) */
3263 for (i = you_row + 1; i < y2; i++)
3264 if (!xclear[i][you_col])
3266 } else { /* above (smaller y2 value) */
3267 for (i = y2 + 1; i < you_row; i++)
3268 if (!xclear[i][you_col])
3275 * Lines at 0 and 90 degrees have been weeded out.
3280 dy = error; /* swap the values */
3281 dxs = dx << 1; /* save the shifted values */
3283 error = dys - dx; /* NOTE: error is used as a temporary above */
3285 for (i = 0; i < dx; i++) {
3287 return 0; /* plot point */
3289 while (error >= 0) {
3297 dxs = dx << 1; /* save the shifted values */
3301 for (i = 0; i < dx; i++) {
3303 return 0; /* plot point */
3305 while (error >= 0) {
3315 #endif /* VISION_TABLES */
3317 #ifdef STRICT_REF_DEF
3318 NEARDATA struct flag flags;
3320 struct attribs attrmax, attrmin;
3322 #endif /* STRICT_REF_DEF */