1 /* NetHack 3.6 makedefs.c $NHDT-Date: 1520022901 2018/03/02 20:35:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.121 $ */
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[] = "@(#)makedefs.c\t3.6\t2018/03/02";
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 static char filename[600];
148 /* if defined, a first argument not starting with - is
149 * taken as a text string to be prepended to any
150 * output filename generated */
151 char *file_prefix = "";
154 #ifdef MACsansMPWTOOL
155 int FDECL(main, (void));
157 int FDECL(main, (int, char **));
159 void FDECL(do_makedefs, (char *));
162 void NDECL(do_dungeon);
164 void NDECL(do_options);
165 void NDECL(do_monstr);
166 void NDECL(do_permonst);
167 void NDECL(do_questtxt);
168 void NDECL(do_rumors);
169 void NDECL(do_oracles);
170 void NDECL(do_vision);
172 extern void NDECL(monst_init); /* monst.c */
173 extern void NDECL(objects_init); /* objects.c */
175 static void NDECL(link_sanity_check);
176 static char *FDECL(name_file, (const char *, const char *));
177 static void FDECL(delete_file, (const char *template, const char *));
178 static FILE *FDECL(getfp, (const char *, const char *, const char *));
179 static void FDECL(do_ext_makedefs, (int, char **));
181 static void NDECL(make_version);
182 static char *FDECL(version_string, (char *, const char *));
183 static char *FDECL(version_id_string, (char *, const char *));
184 static char *FDECL(bannerc_string, (char *, const char *));
185 static char *FDECL(xcrypt, (const char *));
186 static unsigned long FDECL(read_rumors_file,
187 (const char *, int *, long *, unsigned long));
188 static boolean FDECL(get_gitinfo, (char *, char *));
189 static void FDECL(do_rnd_access_file, (const char *));
190 static boolean FDECL(d_filter, (char *));
191 static boolean FDECL(h_filter, (char *));
192 static boolean FDECL(ranged_attk, (struct permonst *));
193 static int FDECL(mstrength, (struct permonst *));
194 static void NDECL(build_savebones_compat_string);
195 static void NDECL(windowing_sanity);
197 static boolean FDECL(qt_comment, (char *));
198 static boolean FDECL(qt_control, (char *));
199 static int FDECL(get_hdr, (char *));
200 static boolean FDECL(new_id, (char *));
201 static boolean FDECL(known_msg, (int, int));
202 static void FDECL(new_msg, (char *, int, int));
203 static char *FDECL(valid_qt_summary, (char *, BOOLEAN_P));
204 static void FDECL(do_qt_control, (char *));
205 static void FDECL(do_qt_text, (char *));
206 static void NDECL(adjust_qt_hdrs);
207 static void NDECL(put_qt_hdrs);
210 static void NDECL(H_close_gen);
211 static void NDECL(H_far_gen);
212 static void NDECL(C_close_gen);
213 static void NDECL(C_far_gen);
214 static int FDECL(clear_path, (int, int, int, int));
217 static char *FDECL(fgetline, (FILE*));
218 static char *FDECL(tmpdup, (const char *));
219 static char *FDECL(limit, (char *, int));
220 static char *FDECL(eos, (char *));
221 static int FDECL(case_insensitive_comp, (const char *, const char *));
223 /* input, output, tmp */
224 static FILE *ifp, *ofp, *tfp;
226 #if defined(__BORLANDC__) && !defined(_WIN32)
227 extern unsigned _stklen = STKSIZ;
230 #ifdef MACsansMPWTOOL
234 const char *def_options = "odemvpqrshz";
238 printf("Enter options to run: [%s] ", def_options);
240 fgets(buf, 100, stdin);
243 Strcpy(buf, def_options);
245 buf[len - 1] = 0; /* remove return */
247 if (buf[0] == '-' && buf[1] == '-') {
249 split up buf into words
250 do_ext_makedefs(fakeargc, fakeargv);
252 printf("extended makedefs not implemented for Mac OS9\n");
274 && !(argv[1][0] == '-' && argv[1][1] == '-'))) {
275 Fprintf(stderr, "Bad arg count (%d).\n", argc - 1);
276 (void) fflush(stderr);
281 if (argc >= 2 && argv[1][0] != '-') {
282 file_prefix = argv[1];
288 if (argv[1][0] == '-' && argv[1][1] == '-') {
289 do_ext_makedefs(argc, argv);
291 do_makedefs(&argv[1][1]);
303 /* Note: these initializers don't do anything except guarantee that
304 we're linked properly.
314 boolean more_than_one;
318 /* construct the current version number */
321 more_than_one = strlen(options) > 1;
324 Fprintf(stderr, "makedefs -%c\n", *options);
362 do_rnd_access_file(EPITAPHFILE);
363 do_rnd_access_file(ENGRAVEFILE);
364 do_rnd_access_file(BOGUSMONFILE);
376 Fprintf(stderr, "Unknown option '%c'.\n", *options);
377 (void) fflush(stderr);
383 Fprintf(stderr, "Completed.\n"); /* feedback */
386 static char namebuf[1000];
389 name_file(template, tag)
390 const char *template;
393 Sprintf(namebuf, template, tag);
398 delete_file(template, tag)
399 const char *template;
402 char *name = name_file(template, tag);
408 getfp(template, tag, mode)
409 const char *template;
413 char *name = name_file(template, tag);
414 FILE *rv = fopen(name, mode);
417 Fprintf(stderr, "Can't open '%s'.\n", name);
423 static boolean debug = FALSE;
425 static FILE *inputfp;
426 static FILE *outputfp;
430 int is_defined; /* 0 undef; 1 defined */
432 /* struct grep_var grep_vars[] and TODO_* constants in include file: */
435 static void NDECL(do_grep_showvars);
436 static struct grep_var *FDECL(grepsearch, (const char *));
437 static int FDECL(grep_check_id, (const char *));
438 static void FDECL(grep_show_wstack, (const char *));
439 static char *FDECL(do_grep_control, (char *));
440 static void NDECL(do_grep);
441 static void FDECL(grep0, (FILE *, FILE *));
443 static int grep_trace = 0;
445 #define IS_OPTION(str) if (!strcmp(&argv[0][2], str))
452 Fprintf(stderr, "missing option\n"); \
453 exit(EXIT_FAILURE); \
457 do_ext_makedefs(int argc, char **argv)
464 argv++; /* skip program name */
467 if (argv[0][0] != '-')
469 if (argv[0][1] != '-') {
470 Fprintf(stderr, "Can't mix - and -- options.\n");
474 /* short version string for packaging - note no \n */
478 argv++; /* not CONSUME */
481 strcpy(delim, argv[0]);
482 Fprintf(stdout, "%s", version_string(buf, delim));
491 do_makedefs(argv[0]);
496 if (!strcmp(argv[0], "-")) {
499 inputfp = fopen(argv[0], RDTMODE);
501 Fprintf(stderr, "Can't open '%s'.\n", argv[0]);
507 IS_OPTION("output") {
509 if (!strcmp(argv[0], "-")) {
512 outputfp = fopen(argv[0], WRTMODE);
514 Fprintf(stderr, "Can't open '%s'.\n", argv[0]);
522 Fprintf(stderr, "Can't do grep and something else.\n");
528 IS_OPTION("grep-showvars") {
532 IS_OPTION("grep-trace") {
536 IS_OPTION("grep-define") {
540 p = grepsearch(argv[0]);
544 Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]);
549 IS_OPTION("grep-undef") {
553 p = grepsearch(argv[0]);
557 Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]);
566 Fprintf(stderr, "Unknown option '%s'.\n", argv[0]);
570 Fprintf(stderr, "unexpected argument '%s'.\n", argv[0]);
576 Fprintf(stderr, "Confused about what to do?\n");
579 Fprintf(stderr, "Nothing to do?\n");
593 * Any line NOT starting with a caret is either suppressed or passed
594 * through unchanged depending on the current conditional state.
596 * The default conditional state is printing on.
598 * Conditionals may be nested.
600 * makedefs will exit with a EXIT_FAILURE if any errors are detected;
601 * as many errors as possible are detected before giving up.
603 * Unknown identifiers are treated as TRUE and also as an error to
604 * allow processing to continue past the unknown identifier (note
605 * that "#undef" is different than unknown).
607 * Any line starting with a caret is a control line; as in C, zero or
608 * more spaces may be embedded in the line almost anywhere; the caret
609 * MUST be in column 1.
610 * (XXX for the moment, no white space is allowed after the caret because
611 * existing lines in the docs look like that.)
614 * ^^ a line starting with a (single) literal caret
615 * ^# a comment - the line is ignored
616 * ^?ID if defined(ID)
617 * ^!ID if !defined(ID)
621 #define GREP_MAGIC '^'
622 #define GREP_STACK_SIZE 100
624 static int grep_rewrite = 0; /* need to (possibly) rewrite lines */
626 static int grep_writing = 1; /* need to copy lines to output */
627 static int grep_errors = 0;
628 static int grep_sp = 0;
629 #define ST_LD(old, opp) (((old) ? 1 : 0) | ((opp) ? 2 : 0))
630 #define ST_OLD(v) (((v) & 1) != 0)
631 #define ST_OPP(v) (((v) & 2) != 0)
633 static int grep_stack[GREP_STACK_SIZE] = { ST_LD(1, 0) };
634 static int grep_lineno = 0;
641 for (x = 0; x < SIZE(grep_vars) - 1; x++) {
642 printf("%d\t%s\n", grep_vars[x].is_defined, grep_vars[x].name);
646 static struct grep_var *
650 /* XXX make into binary search */
653 while (x < SIZE(grep_vars) - 1) {
654 if (!strcmp(grep_vars[x].name, name))
655 return &grep_vars[x];
667 while (*id && isspace((uchar) *id))
670 Fprintf(stderr, "missing identifier in line %d", grep_lineno);
677 Fprintf(outputfp, "ID %d %s\n", rv->is_defined, id);
679 return rv->is_defined;
683 Fprintf(outputfp, "ID U %s\n", id);
685 Fprintf(stderr, "unknown identifier '%s' in line %d.\n", id, grep_lineno);
687 return 2; /* So new features can be checked before makedefs
692 grep_show_wstack(tag)
700 Fprintf(outputfp, "%s w=%d sp=%d\t", tag, grep_writing, grep_sp);
701 for (x = grep_sp; x >= 0 && x > grep_sp - 6; x--) {
702 Fprintf(outputfp, "[%d]=%d ", x, grep_stack[x]);
704 Fprintf(outputfp, "\n");
714 if (isspace((uchar) buf[0]))
715 return &buf[-1]; /* XXX see docs above */
717 while (buf[0] && isspace((uchar) buf[0]))
721 case '#': /* comment */
723 case '.': /* end of if level */
725 Fprintf(stderr, "unmatched ^. (endif) at line %d.\n",
729 grep_writing = ST_OLD(grep_stack[grep_sp--]);
730 grep_show_wstack("pop");
733 case '!': /* if not ID */
736 case '?': /* if ID */
737 if (grep_sp == GREP_STACK_SIZE - 2) {
738 Fprintf(stderr, "stack overflow at line %d.", grep_lineno);
742 isif = grep_check_id(&buf[1]) ? isif : !isif;
743 grep_stack[++grep_sp] = ST_LD(grep_writing, !isif);
746 grep_stack[++grep_sp] = ST_LD(0, 0);
747 /* grep_writing = 0; */
749 grep_show_wstack("push");
752 if (ST_ELSE & grep_stack[grep_sp]) {
753 Fprintf(stderr, "multiple : for same conditional at line %d.\n",
757 grep_writing = ST_OPP(grep_stack[grep_sp]);
758 grep_stack[grep_sp] |= ST_ELSE;
761 case '(': /* start of expression */
763 case GREP_MAGIC: /* ^^ -> ^ */
768 if (isprint((uchar) buf[0])) {
772 sprintf(str, "0x%02x", buf[0]);
774 Fprintf(stderr, "unknown control ^%s at line %d.\n", str,
787 /* no language features use this yet */
792 static void grep0(FILE *, FILE *);
798 Fprintf(stderr, "--grep requires --input\n");
801 Fprintf(stderr, "--grep requires --output\n");
803 if (!inputfp || !outputfp) {
807 grep0(inputfp, outputfp);
811 grep0(inputfp0, outputfp0)
815 char buf[16384]; /* looong, just in case */
817 while (!feof(inputfp0) && !ferror(inputfp0)) {
821 if (fgets(buf, sizeof(buf), inputfp0) == 0)
823 if ((tmp = strchr(buf, '\n')))
827 Fprintf(outputfp0, "%04d %c >%s\n", grep_lineno,
828 grep_writing ? ' ' : '#', buf);
831 if (buf[0] == GREP_MAGIC) {
832 buf1 = do_grep_control(&buf[1]);
840 do_grep_rewrite(buf1);
843 Fprintf(outputfp0, "%s\n", buf1);
845 if (ferror(inputfp0)) {
846 Fprintf(stderr, "read error!\n");
849 if (ferror(outputfp0)) {
850 Fprintf(stderr, "write error!\n");
856 Fprintf(stderr, "%d unterminated conditional level%s\n", grep_sp,
857 grep_sp == 1 ? "" : "s");
861 Fprintf(stderr, "%d error%s detected.\n", grep_errors,
862 grep_errors == 1 ? "" : "s");
867 /* trivial text encryption routine which can't be broken with `tr' */
871 { /* duplicated in src/hacklib.c */
872 static char buf[BUFSZ];
873 register const char *p;
875 register int bitmask;
877 for (bitmask = 1, p = str, q = buf; *p; q++) {
881 if ((bitmask <<= 1) >= 32)
888 #define PAD_RUMORS_TO 60
889 /* common code for do_rumors(). Return 0 on error. */
891 read_rumors_file(file_ext, rumor_count, rumor_size, old_rumor_offset)
892 const char *file_ext;
895 unsigned long old_rumor_offset;
899 unsigned long rumor_offset;
901 Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
902 Strcat(infile, file_ext);
903 if (!(ifp = fopen(infile, RDTMODE))) {
908 /* copy the rumors */
909 while ((line = fgetline(ifp)) != 0) {
911 /* rumor selection is accomplished by seeking to a random
912 position in the file, advancing to newline, and taking
913 the next line; therefore, rumors which follow long-line
914 rumors are most likely to be chosen and rumors which
915 follow short-line rumors are least likely to be chosen;
916 we ameliorate the latter by padding the shortest lines,
917 increasing the chance of the random seek landing in them */
918 int len = (int) strlen(line);
920 if (len <= PAD_RUMORS_TO) {
921 char *base = index(line, '\n');
922 /* this is only safe because fgetline() overallocates */
923 while (len++ < PAD_RUMORS_TO) {
932 /*[if we forced binary output, this would be sufficient]*/
933 *rumor_size += strlen(line); /* includes newline */
935 (void) fputs(xcrypt(line), tfp);
938 /* record the current position; next rumors section will start here */
939 rumor_offset = (unsigned long) ftell(tfp);
940 Fclose(ifp); /* all done with rumors.file_ext */
942 /* the calculated value for *_rumor_count assumes that
943 a single-byte line terminator is in use; for platforms
944 which use two byte CR+LF, we need to override that value
945 [it's much simpler to do so unconditionally, rendering
946 the loop's accumulation above obsolete] */
947 *rumor_size = (long) (rumor_offset - old_rumor_offset);
952 do_rnd_access_file(fname)
957 Sprintf(filename, DATA_IN_TEMPLATE, fname);
958 Strcat(filename, ".txt");
959 if (!(ifp = fopen(filename, RDTMODE))) {
965 Strcat(filename, file_prefix);
967 Sprintf(eos(filename), DATA_TEMPLATE, fname);
968 if (!(ofp = fopen(filename, WRTMODE))) {
972 Fprintf(ofp, "%s", Dont_Edit_Data);
974 tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE);
976 ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE);
978 while ((line = fgetline(ifp)) != 0) {
979 if (line[0] != '#' && line[0] != '\n')
980 (void) fputs(xcrypt(line), ofp);
986 delete_file(DATA_TEMPLATE, "grep.tmp");
994 static const char rumors_header[] =
995 "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n";
997 int true_rumor_count, false_rumor_count;
998 long true_rumor_size, false_rumor_size;
999 unsigned long true_rumor_offset, false_rumor_offset, eof_offset;
1001 Sprintf(tempfile, DATA_TEMPLATE, "rumors.tmp");
1004 Strcat(filename, file_prefix);
1006 Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE);
1007 if (!(ofp = fopen(filename, WRTMODE))) {
1011 if (!(tfp = fopen(tempfile, WRTMODE))) {
1017 true_rumor_count = false_rumor_count = 0;
1018 true_rumor_size = false_rumor_size = 0L;
1019 true_rumor_offset = false_rumor_offset = eof_offset = 0L;
1021 /* output a dummy header record; we'll replace it in final output */
1022 Fprintf(tfp, rumors_header, Dont_Edit_Data, true_rumor_count,
1023 true_rumor_size, true_rumor_offset, false_rumor_count,
1024 false_rumor_size, false_rumor_offset, eof_offset);
1025 /* record the current position; true rumors will start here */
1026 true_rumor_offset = ftell(tfp);
1028 false_rumor_offset = read_rumors_file(
1029 ".tru", &true_rumor_count, &true_rumor_size, true_rumor_offset);
1030 if (!false_rumor_offset)
1031 goto rumors_failure;
1033 eof_offset = read_rumors_file(".fal", &false_rumor_count,
1034 &false_rumor_size, false_rumor_offset);
1036 goto rumors_failure;
1038 /* get ready to transfer the contents of temp file to output file */
1040 Sprintf(line, "rewind of \"%s\"", tempfile);
1041 if (rewind(tfp) != 0) {
1044 goto rumors_failure;
1048 /* output the header record */
1049 Fprintf(ofp, rumors_header, Dont_Edit_Data, true_rumor_count,
1050 true_rumor_size, true_rumor_offset, false_rumor_count,
1051 false_rumor_size, false_rumor_offset, eof_offset);
1052 /* skip the temp file's dummy header */
1053 if (!(line = fgetline(tfp))) { /* "Don't Edit" */
1055 goto rumors_failure;
1058 if (!(line = fgetline(tfp))) { /* count,size,offset */
1060 goto rumors_failure;
1063 /* copy the rest of the temp file into the final output file */
1064 while ((line = fgetline(tfp)) != 0) {
1065 (void) fputs(line, ofp);
1068 /* all done; delete temp file */
1076 Unlink(filename); /* kill empty or incomplete output file */
1078 Unlink(tempfile); /* and temporary file */
1083 * Use this to explicitly mask out features during version checks.
1085 * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features
1086 * that the port/plaform which wrote the savefile was capable of
1087 * dealing with. Don't reject a savefile just because the port
1088 * reading the savefile doesn't match on all/some of them.
1089 * The actual compression features used to produce the savefile are
1090 * recorded in the savefile_info structure immediately following the
1091 * version_info, and that is what needs to be checked against the
1092 * feature set of the port that is reading the savefile back in.
1093 * That check is done in src/restore.c now.
1096 #define IGNORED_FEATURES \
1097 (0L | (1L << 19) /* SCORE_ON_BOTL */ \
1098 | (1L << 27) /* ZEROCOMP */ \
1099 | (1L << 28) /* RLECOMP */ \
1108 * integer version number
1110 version.incarnation = ((unsigned long) VERSION_MAJOR << 24)
1111 | ((unsigned long) VERSION_MINOR << 16)
1112 | ((unsigned long) PATCHLEVEL << 8)
1113 | ((unsigned long) EDITLEVEL);
1115 * encoded feature list
1116 * Note: if any of these magic numbers are changed or reassigned,
1117 * EDITLEVEL in patchlevel.h should be incremented at the same time.
1118 * The actual values have no special meaning, and the category
1119 * groupings are just for convenience.
1121 version.feature_set = (unsigned long) (0L
1122 /* levels and/or topology (0..4) */
1123 /* monsters (5..9) */
1127 /* objects (10..14) */
1128 /* flag bits and/or other global variables (15..26) */
1135 #ifdef SCORE_ON_BOTL
1138 /* data format (27..31)
1139 * External compression methods such as COMPRESS and ZLIB_COMP
1140 * do not affect the contents and are thus excluded from here */
1149 * Value used for object & monster sanity check.
1150 * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
1152 for (i = 1; artifact_names[i]; i++)
1154 version.entity_count = (unsigned long) (i - 1);
1155 for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++)
1157 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
1158 for (i = 0; mons[i].mlet; i++)
1160 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
1162 * Value used for compiler (word size/field alignment/padding) check.
1164 version.struct_sizes1 =
1165 (((unsigned long) sizeof(struct context_info) << 24)
1166 | ((unsigned long) sizeof(struct obj) << 17)
1167 | ((unsigned long) sizeof(struct monst) << 10)
1168 | ((unsigned long) sizeof(struct you)));
1169 version.struct_sizes2 = (((unsigned long) sizeof(struct flag) << 10) |
1170 /* free bits in here */
1172 ((unsigned long) sizeof(struct sysflag)));
1174 ((unsigned long) 0L));
1179 /* REPRODUCIBLE_BUILD will change this to TRUE */
1180 static boolean date_via_env = FALSE;
1183 version_string(outbuf, delim)
1187 Sprintf(outbuf, "%d%s%d%s%d", VERSION_MAJOR, delim, VERSION_MINOR, delim,
1190 Sprintf(eos(outbuf), "-%d", EDITLEVEL);
1196 version_id_string(outbuf, build_date)
1198 const char *build_date;
1200 char subbuf[64], versbuf[64];
1205 Strcpy(&subbuf[1], PORT_SUB_ID);
1208 Strcat(subbuf, " Beta");
1211 Sprintf(outbuf, "%s NetHack%s Version %s - last %s %s.", PORT_ID,
1212 subbuf, version_string(versbuf, "."),
1213 date_via_env ? "revision" : "build", build_date);
1219 jversion_id_string(outbuf, build_date)
1221 const char *build_date;
1223 char subbuf[64], versbuf[64];
1227 Strcat(subbuf, " Beta");
1230 Sprintf(outbuf, "%s JNetHack%s Version %s-%d.%d.", PORT_ID,
1231 subbuf, version_string(versbuf, "."), JVERSION_MAJOR, JVERSION_MINOR);
1237 bannerc_string(outbuf, build_date)
1239 const char *build_date;
1241 char subbuf[64], versbuf[64];
1246 Strcpy(&subbuf[1], PORT_SUB_ID);
1249 Strcat(subbuf, " Beta");
1252 Sprintf(outbuf, " Version %s %s%s, %s %s.",
1253 version_string(versbuf, "."), PORT_ID, subbuf,
1254 date_via_env ? "revised" : "built", &build_date[4]);
1256 Sprintf(outbuf, "%s NetHack%s %s Copyright 1985-%s (built %s)",
1257 PORT_ID, subbuf, version_string(versbuf,"."), RELEASE_YEAR,
1269 time_t clocktim = 0;
1271 char githash[BUFSZ], gitbranch[BUFSZ];
1272 char *c, cbuf[60], buf[BUFSZ];
1275 /* before creating date.h, make sure that xxx_GRAPHICS and
1276 DEFAULT_WINDOW_SYS have been set up in a viable fashion */
1281 Strcat(filename, file_prefix);
1283 Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE);
1284 if (!(ofp = fopen(filename, WRTMODE))) {
1288 /* NB: We've moved on from SCCS, but this way this line
1289 * won't get clobbered when downstream projects import
1290 * this file into something more modern. */
1291 Fprintf(ofp, "%s", Dont_Edit_Code);
1293 (void) time(&clocktim);
1294 #ifdef REPRODUCIBLE_BUILD
1297 * Use date+time of latest source file revision (set up in
1298 * our environment rather than derived by scanning sources)
1299 * instead of current date+time, so that later rebuilds of
1300 * the same sources specifying the same configuration will
1301 * produce the same result.
1303 * Changing the configuration should be done by modifying
1304 * config.h or <port>conf.h and setting SOURCE_DATE_EPOCH
1305 * based on whichever changed most recently, not by using
1306 * make CFLAGS='-Dthis -Dthat'
1307 * to make alterations on the fly.
1309 * Limited validation is performed to prevent dates in the
1310 * future (beyond a leeway of 24 hours) or distant past.
1312 * Assumes the value of time_t is in seconds, which is
1313 * fundamental for Unix and mandated by POSIX. For any ports
1314 * where that isn't true, leaving REPRODUCIBLE_BUILD disabled
1315 * is probably preferrable to hacking this code....
1317 static struct tm nh360; /* static init should yield UTC timezone */
1318 unsigned long sd_num, sd_earliest, sd_latest;
1319 const char *sd_str = getenv("SOURCE_DATE_EPOCH");
1322 sd_num = strtoul(sd_str, (char **) 0, 10);
1324 * Note: this does not need to be updated for future
1325 * releases. It serves as a sanity check for potentially
1326 * mis-set environment, not a hard baseline for when the
1327 * current version could have first been built.
1329 /* oldest date we'll accept: 7-Dec-2015 (release of 3.6.0) */
1331 nh360.tm_mon = 12 - 1;
1332 nh360.tm_year = 2015 - 1900;
1333 sd_earliest = (unsigned long) mktime(&nh360);
1334 /* 'youngest' date we'll accept: 24 hours in the future */
1335 sd_latest = (unsigned long) clocktim + 24L * 60L * 60L;
1337 if (sd_num >= sd_earliest && sd_num <= sd_latest) {
1338 /* use SOURCE_DATE_EPOCH value */
1339 clocktim = (time_t) sd_num;
1340 date_via_env = TRUE;
1342 Fprintf(stderr, "? Invalid value for SOURCE_DATE_EPOCH (%lu)",
1344 if (sd_num > 0L && sd_num < sd_earliest)
1345 Fprintf(stderr, ", older than %lu", sd_earliest);
1346 else if (sd_num > sd_latest)
1347 Fprintf(stderr, ", newer than %lu", sd_latest);
1348 Fprintf(stderr, ".\n");
1349 Fprintf(stderr, ": Reverting to current date+time (%lu).\n",
1350 (unsigned long) clocktim);
1351 (void) fflush(stderr);
1354 /* REPRODUCIBLE_BUILD enabled but SOURCE_DATE_EPOCH is missing */
1355 Fprintf(stderr, "? No value for SOURCE_DATE_EPOCH.\n");
1356 Fprintf(stderr, ": Using current date+time (%lu).\n",
1357 (unsigned long) clocktim);
1358 (void) fflush(stderr);
1360 Strcpy(cbuf, asctime(gmtime(&clocktim)));
1363 /* ordinary build: use current date+time */
1364 Strcpy(cbuf, ctime(&clocktim));
1367 if ((c = index(cbuf, '\n')) != 0)
1368 *c = '\0'; /* strip off the '\n' */
1375 Fprintf(ofp, "#define SOURCE_DATE_EPOCH (%lu%s) /* via getenv() */\n",
1376 (unsigned long) clocktim, ul_sfx);
1377 Fprintf(ofp, "#define BUILD_DATE \"%s\"\n", cbuf);
1379 Fprintf(ofp, "#define BUILD_TIME SOURCE_DATE_EPOCH\n");
1381 Fprintf(ofp, "#define BUILD_TIME (%lu%s)\n",
1382 (unsigned long) clocktim, ul_sfx);
1384 Fprintf(ofp, "#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation,
1386 Fprintf(ofp, "#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set,
1388 #ifdef IGNORED_FEATURES
1389 Fprintf(ofp, "#define IGNORED_FEATURES 0x%08lx%s\n",
1390 (unsigned long) IGNORED_FEATURES, ul_sfx);
1392 Fprintf(ofp, "#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count,
1394 Fprintf(ofp, "#define VERSION_SANITY2 0x%08lx%s\n", version.struct_sizes1,
1396 Fprintf(ofp, "#define VERSION_SANITY3 0x%08lx%s\n", version.struct_sizes2,
1399 Fprintf(ofp, "#define VERSION_STRING \"%s\"\n", version_string(buf, "."));
1400 Fprintf(ofp, "#define VERSION_ID \\\n \"%s\"\n",
1401 version_id_string(buf, cbuf));
1403 Fprintf(ofp,"#define JVERSION_ID \\\n \"%s\"\n",
1404 jversion_id_string(buf, cbuf));
1406 Fprintf(ofp, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n",
1407 bannerc_string(buf, cbuf));
1409 if (get_gitinfo(githash, gitbranch)) {
1410 Fprintf(ofp, "#define NETHACK_GIT_SHA \"%s\"\n", githash);
1411 Fprintf(ofp, "#define NETHACK_GIT_BRANCH \"%s\"\n", gitbranch);
1415 struct tm *tm = localtime((time_t *) &clocktim);
1417 Fprintf(ofp, "#define AMIGA_VERSION_STRING ");
1418 Fprintf(ofp, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
1419 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
1420 tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900);
1428 get_gitinfo(githash, gitbranch)
1429 char *githash, *gitbranch;
1434 char *line, *strval, *opt, *c, *end;
1435 boolean havebranch = FALSE, havehash = FALSE;
1437 if (!githash || !gitbranch) return FALSE;
1439 Sprintf(infile, DATA_IN_TEMPLATE, GITINFO_FILE);
1440 if (!(gifp = fopen(infile, RDTMODE))) {
1441 /* perror(infile); */
1445 /* read the gitinfo file */
1446 while ((line = fgetline(gifp)) != 0) {
1447 strval = index(line, '=');
1448 if (strval && strlen(strval) < (BUFSZ-1)) {
1451 /* strip off the '\n' */
1452 if ((c = index(strval, '\n')) != 0)
1454 if ((c = index(opt, '\n')) != 0)
1456 /* strip leading and trailing white space */
1457 while (*strval == ' ' || *strval == '\t')
1460 while (--end >= strval && (*end == ' ' || *end == '\t'))
1462 while (*opt == ' ' || *opt == '\t')
1465 while (--end >= opt && (*end == ' ' || *end == '\t'))
1469 if ((len >= strlen("gitbranch")) && !case_insensitive_comp(opt, "gitbranch")) {
1470 Strcpy(gitbranch, strval);
1473 if ((len >= strlen("githash")) && !case_insensitive_comp(opt, "githash")) {
1474 Strcpy(githash, strval);
1480 if (havebranch && havehash)
1486 case_insensitive_comp(s1, s2)
1492 for (;; s1++, s2++) {
1499 if (u1 == '\0' || u1 != u2)
1505 static char save_bones_compat_buf[BUFSZ];
1508 build_savebones_compat_string()
1510 #ifdef VERSION_COMPATIBILITY
1511 unsigned long uver = VERSION_COMPATIBILITY;
1513 Strcpy(save_bones_compat_buf,
1514 "save and bones files accepted from version");
1515 #ifdef VERSION_COMPATIBILITY
1516 Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d",
1517 ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16),
1518 ((uver & 0x0000FF00L) >> 8), VERSION_MAJOR, VERSION_MINOR,
1521 Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only", VERSION_MAJOR,
1522 VERSION_MINOR, PATCHLEVEL);
1526 static const char *build_opts[] = {
1528 "Amiga WorkBench support",
1531 "ANSI default terminal",
1536 #ifdef TTY_TILES_ESCCODES
1537 "console escape codes for tile hinting",
1540 "command line completion",
1543 "Conway's Game of Life",
1546 "data file compression",
1549 "ZLIB data file compression",
1555 "end-of-game dumplogs",
1557 #ifdef HOLD_LOCKFILE_OPEN
1558 "exclusive lock on level 0 file",
1560 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
1561 "external program as a message handler",
1564 "floppy drive support",
1567 "insurance files for recovering from crashes",
1573 "extended log file",
1576 "errors and warnings log file",
1582 "MSDOS protected mode",
1598 /* pattern matching method will be substituted by nethack at run time */
1599 "pattern matching via :PATMATCH:",
1601 "restore saved games via menu",
1603 #ifdef SCORE_ON_BOTL
1604 "score on status line",
1611 "screen control via mactty",
1614 "screen control via BIOS",
1616 #ifdef SCREEN_DJGPPFAST
1617 "screen control via DJGPP fast",
1620 "screen control via VGA graphics",
1623 "screen control via WIN32 console I/O",
1629 "traditional status display",
1630 #ifdef STATUS_HILITES
1631 "status via windowport with highlighting",
1633 "status via windowport without highlighting",
1639 "terminal info library",
1641 #if defined(TERMLIB) \
1642 || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
1643 "terminal capability library",
1647 "timed wait for display effects",
1652 #ifdef PREFIXES_IN_USE
1653 "variable playground",
1655 #ifdef VISION_TABLES
1659 "zero-compressed save files",
1662 "run-length compression of map in save files",
1665 "system configuration at run-time",
1667 save_bones_compat_buf,
1668 "and basic NetHack features"
1672 const char *id, /* DEFAULT_WINDOW_SYS string */
1673 *name; /* description, often same as id */
1675 static struct win_info window_opts[] = {
1677 { "tty", "traditional tty-based graphics" },
1685 #ifdef GNOME_GRAPHICS
1686 { "Gnome", "Gnome" },
1691 #ifdef AMIGA_INTUITION
1692 { "amii", "Amiga Intuition" },
1697 #ifdef MSWIN_GRAPHICS
1698 { "mswin", "mswin" },
1700 #ifdef BEOS_GRAPHICS
1701 { "BeOS", "BeOS InterfaceKit" },
1709 #ifndef DEFAULT_WINDOW_SYS
1710 /* pre-standard compilers didn't support #error; wait til run-time */
1712 "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n");
1716 /* put in a dummy value so that do_options() will compile and makedefs
1717 will build, otherwise the message above won't ever get delivered */
1718 #define DEFAULT_WINDOW_SYS "<undefined>"
1719 #else /*DEFAULT_WINDOW_SYS*/
1721 if (!window_opts[0].id) {
1722 Fprintf(stderr, "Configuration error: no windowing systems "
1723 "(TTY_GRAPHICS, &c) enabled.\n");
1730 for (i = 0; window_opts[i].id; ++i)
1731 if (!strcmp(window_opts[i].id, DEFAULT_WINDOW_SYS))
1733 if (!window_opts[i].id) { /* went through whole list without a match */
1734 Fprintf(stderr, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n",
1735 DEFAULT_WINDOW_SYS);
1737 " does not match any enabled windowing system (%s%s).\n",
1738 window_opts[0].id, window_opts[1].id ? ", &c" : "");
1742 #endif /*DEFAULT_WINDOW_SYS*/
1748 static const char indent[] = " ";
1749 const char *str, *sep;
1750 char *word, buf[BUFSZ];
1751 int i, length, winsyscnt;
1757 Strcat(filename, file_prefix);
1759 Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE);
1760 if (!(ofp = fopen(filename, WRTMODE))) {
1765 build_savebones_compat_string();
1768 "\n NetHack version %d.%d.%d [beta]\n",
1770 "\n NetHack version %d.%d.%d\n",
1772 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
1774 Fprintf(ofp, "\nOptions compiled into this edition:\n");
1775 length = COLNO + 1; /* force 1st item onto new line */
1776 for (i = 0; i < SIZE(build_opts); i++) {
1777 str = strcat(strcpy(buf, build_opts[i]),
1778 (i < SIZE(build_opts) - 1) ? "," : ".");
1780 word = index(str, ' ');
1783 if (length + strlen(str) > COLNO - 5)
1784 Fprintf(ofp, "\n%s", indent), length = strlen(indent);
1786 Fprintf(ofp, " "), length++;
1787 Fprintf(ofp, "%s", str), length += strlen(str);
1788 str += strlen(str) + (word ? 1 : 0);
1792 winsyscnt = SIZE(window_opts) - 1;
1793 Fprintf(ofp, "\n\nSupported windowing system%s:\n",
1794 (winsyscnt > 1) ? "s" : "");
1795 length = COLNO + 1; /* force 1st item onto new line */
1796 for (i = 0; i < winsyscnt; i++) {
1797 str = window_opts[i].name;
1798 if (length + strlen(str) > COLNO - 5)
1799 Fprintf(ofp, "\n%s", indent), length = strlen(indent);
1801 Fprintf(ofp, " "), length++;
1802 Fprintf(ofp, "%s", str), length += strlen(str);
1803 sep = (winsyscnt == 1)
1806 ? ((i == 0) ? " and" : "")
1807 : (i < winsyscnt - 2)
1809 : ((i == winsyscnt - 2) ? ", and" : "");
1810 Fprintf(ofp, "%s", sep), length += strlen(sep);
1813 Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS);
1814 Fprintf(ofp, "\n\n");
1820 /* routine to decide whether to discard something from data.base */
1826 return TRUE; /* ignore comment lines */
1832 New format (v3.1) of 'data' file which allows much faster lookups [pr]
1833 "do not edit" first record is a comment line
1834 01234567 hexadecimal formatted offset to text area
1835 name-a first name of interest
1836 123,4 offset to name's text, and number of lines for it
1837 name-b next name of interest
1838 name-c multiple names which share same description also
1839 456,7 share a single offset,count line
1840 . sentinel to mark end of names
1841 789,0 dummy record containing offset, count of EOF
1842 text-a 4 lines of descriptive text for name-a
1843 text-a at file position 0x01234567L + 123L
1846 text-b/text-c 7 lines of text for names-b and -c
1847 text-b/text-c at fseek(0x01234567L + 456L)
1855 char infile[60], tempfile[60];
1858 int entry_cnt, line_cnt;
1861 Sprintf(tempfile, DATA_TEMPLATE, "database.tmp");
1864 Strcat(filename, file_prefix);
1866 Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE);
1867 Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE);
1868 #ifdef SHORT_FILENAMES
1869 Strcat(infile, ".bas");
1871 Strcat(infile, ".base");
1873 if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */
1877 if (!(ofp = fopen(filename, WRTMODE))) { /* data */
1882 if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */
1890 /* output a dummy header record; we'll rewind and overwrite it later */
1891 Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L);
1893 entry_cnt = line_cnt = 0;
1894 /* read through the input file and split it into two sections */
1895 while ((line = fgetline(ifp)) != 0) {
1897 if (d_filter(line)) {
1901 if (*line > ' ') { /* got an entry name */
1904 uc = *((unsigned char *)line);
1905 if (d_filter(line)) continue;
1906 if (uc > ' ') { /* got an entry name */
1908 /* first finish previous entry */
1910 Fprintf(ofp, "%d\n", line_cnt), line_cnt = 0;
1911 /* output the entry name */
1912 (void) fputs(line, ofp);
1913 entry_cnt++; /* update number of entries */
1914 } else if (entry_cnt) { /* got some descriptive text */
1915 /* update previous entry with current text offset */
1917 Fprintf(ofp, "%ld,", ftell(tfp));
1918 /* save the text line in the scratch file */
1919 (void) fputs(line, tfp);
1920 line_cnt++; /* update line counter */
1924 /* output an end marker and then record the current position */
1926 Fprintf(ofp, "%d\n", line_cnt);
1927 Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0);
1928 txt_offset = ftell(ofp);
1929 Fclose(ifp); /* all done with original input file */
1931 /* reprocess the scratch file; 1st format an error msg, just in case */
1933 Sprintf(line, "rewind of \"%s\"", tempfile);
1934 if (rewind(tfp) != 0)
1937 /* copy all lines of text from the scratch file into the output file */
1938 while ((line = fgetline(tfp)) != 0) {
1939 (void) fputs(line, ofp);
1943 /* finished with scratch file */
1945 Unlink(tempfile); /* remove it */
1947 /* update the first record of the output file; prepare error msg 1st */
1949 Sprintf(line, "rewind of \"%s\"", filename);
1950 ok = (rewind(ofp) == 0);
1952 Sprintf(line, "header rewrite of \"%s\"", filename);
1953 ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data,
1954 (unsigned long) txt_offset) >= 0);
1958 perror(line); /* report the problem */
1960 /* close and kill the aborted output file, then give up */
1973 /* routine to decide whether to discard something from oracles.txt */
1978 static boolean skip = FALSE;
1984 return TRUE; /* ignore comment lines */
1986 tag = malloc(strlen(line));
1987 if (sscanf(line, "----- %s", tag) == 1) {
1989 } else if (skip && !strncmp(line, "-----", 5))
1995 static const char *special_oracle[] = {
1997 "\"...it is rather disconcerting to be confronted with the",
1998 "following theorem from [Baker, Gill, and Solovay, 1975].", "",
1999 "Theorem 7.18 There exist recursive languages A and B such that",
2000 " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "",
2001 "This provides impressive evidence that the techniques that are",
2002 "currently available will not suffice for proving that P != NP or "
2004 "that P == NP.\" [Garey and Johnson, p. 185.]"
2006 "
\81u
\8e\9f\82Ì
\92è
\97\9d[Baker, Gill, and Solovay, 1975]
\82É
\92¼
\96Ê
\82·
\82é
\82±
\82Æ
\82Í",
2007 "
\82Þ
\82µ
\82ë
\8d¢
\98f
\82·
\82é
\82±
\82Æ
\82Å
\82 \82é
\81D",
2009 "
\92è
\97\9d 7.18
\8e\9f\82Ì
\82æ
\82¤
\82È
\8dÄ
\8bA
\93I
\8c¾
\8cê A
\81CB
\82ª
\91¶
\8dÝ
\82·
\82é",
2010 " (1) P(A) == NP(A)
\81C
\82©
\82Â",
2011 " (2) P(B) != NP(B)",
2013 "
\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é",
2014 "
\97L
\8cø
\82È
\8eè
\96@
\82ª
\82È
\82¢
\82±
\82Æ
\82ð
\8b
\82
\8e¦
\82µ
\82Ä
\82¢
\82é
\81D
\81v",
2015 "[Garey and Johnson, p. 185.]"
2020 The oracle file consists of a "do not edit" comment, a decimal count N
2021 and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
2022 records, separated by "---" lines. The first oracle is a special case.
2023 The input data contains just those multi-line records, separated by
2030 char infile[60], tempfile[60];
2031 boolean in_oracle, ok;
2033 unsigned long txt_offset, offset;
2038 Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp");
2041 Strcat(filename, file_prefix);
2043 Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE);
2044 Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE);
2045 Strcat(infile, ".txt");
2046 if (!(ifp = fopen(infile, RDTMODE))) {
2050 if (!(ofp = fopen(filename, WRTMODE))) {
2055 if (!(tfp = fopen(tempfile, WRTMODE))) { /* oracles.tmp */
2063 /* output a dummy header record; we'll rewind and overwrite it later */
2064 Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0);
2066 /* handle special oracle; it must come first */
2067 (void) fputs("---\n", tfp);
2068 offset = (unsigned long) ftell(tfp);
2069 Fprintf(ofp, "%05lx\n", offset); /* start pos of special oracle */
2070 for (i = 0; i < SIZE(special_oracle); i++) {
2071 (void) fputs(xcrypt(special_oracle[i]), tfp);
2072 (void) fputc('\n', tfp);
2077 (void) fputs("---\n", tfp);
2078 offset = (unsigned long) ftell(tfp);
2079 Fprintf(ofp, "%05lx\n", offset); /* start pos of first oracle */
2082 while ((line = fgetline(ifp)) != 0) {
2085 if (h_filter(line)) {
2089 if (!strncmp(line, "-----", 5)) {
2096 (void) fputs("---\n", tfp);
2097 offset = (unsigned long) ftell(tfp);
2098 Fprintf(ofp, "%05lx\n", offset); /* start pos of this oracle */
2101 (void) fputs(xcrypt(line), tfp);
2106 if (in_oracle) { /* need to terminate last oracle */
2108 (void) fputs("---\n", tfp);
2109 offset = (unsigned long) ftell(tfp);
2110 Fprintf(ofp, "%05lx\n", offset); /* eof position */
2113 /* record the current position */
2114 txt_offset = (unsigned long) ftell(ofp);
2115 Fclose(ifp); /* all done with original input file */
2117 /* reprocess the scratch file; 1st format an error msg, just in case */
2119 Sprintf(line, "rewind of \"%s\"", tempfile);
2120 if (rewind(tfp) != 0)
2123 /* copy all lines of text from the scratch file into the output file */
2124 while ((line = fgetline(tfp)) != 0) {
2125 (void) fputs(line, ofp);
2129 /* finished with scratch file */
2131 Unlink(tempfile); /* remove it */
2133 /* update the first record of the output file; prepare error msg 1st */
2135 Sprintf(line, "rewind of \"%s\"", filename);
2136 ok = (rewind(ofp) == 0);
2138 Sprintf(line, "header rewrite of \"%s\"", filename);
2139 ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >= 0);
2142 Sprintf(line, "data rewrite of \"%s\"", filename);
2143 for (i = 0; i <= oracle_cnt; i++) {
2144 #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */
2145 if (!(ok = (fflush(ofp) == 0)))
2148 if (!(ok = (fpos = ftell(ofp)) >= 0))
2150 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0)))
2152 if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1)))
2157 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
2158 (ANSI C Libraries) needs this rewind or else the fprintf
2159 stops working. This may also be true for CW11, but has
2165 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0)))
2167 offset += txt_offset;
2168 if (!(ok = (fprintf(ofp, "%05lx\n", offset) >= 0)))
2174 perror(line); /* report the problem */
2176 /* close and kill the aborted output file, then give up */
2194 Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE);
2195 if (!(ifp = fopen(filename, RDTMODE))) {
2201 Strcat(filename, file_prefix);
2203 Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE);
2204 if (!(ofp = fopen(filename, WRTMODE))) {
2208 Fprintf(ofp, "%s", Dont_Edit_Data);
2210 tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE);
2212 ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE);
2214 while ((line = fgetline(ifp)) != 0) {
2217 if (line[0] == '#') {
2219 continue; /* discard comments */
2221 (void) fputs(line, ofp);
2227 delete_file(DATA_TEMPLATE, "grep.tmp");
2232 ranged_attk(ptr) /* returns TRUE if monster can attack at range */
2233 register struct permonst *ptr;
2236 register int atk_mask = (1 << AT_BREA) | (1 << AT_SPIT) | (1 << AT_GAZE);
2238 for (i = 0; i < NATTK; i++) {
2239 if ((j = ptr->mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1 << j)))
2246 /* This routine is designed to return an integer value which represents
2247 * an approximation of monster strength. It uses a similar method of
2248 * determination as "experience()" to arrive at the strength.
2252 struct permonst *ptr;
2254 int i, tmp2, n, tmp = ptr->mlevel;
2256 if (tmp > 49) /* special fixed hp monster */
2257 tmp = 2 * (tmp - 6) / 4;
2259 /* For creation in groups */
2260 n = (!!(ptr->geno & G_SGROUP));
2261 n += (!!(ptr->geno & G_LGROUP)) << 1;
2263 /* For ranged attacks */
2264 if (ranged_attk(ptr))
2267 /* For higher ac values */
2271 /* For very fast monsters */
2272 n += (ptr->mmove >= 18);
2274 /* For each attack and "special" attack */
2275 for (i = 0; i < NATTK; i++) {
2276 tmp2 = ptr->mattk[i].aatyp;
2278 n += (tmp2 == AT_MAGC);
2279 n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG));
2282 /* For each "special" damage type */
2283 for (i = 0; i < NATTK; i++) {
2284 tmp2 = ptr->mattk[i].adtyp;
2285 if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST)
2286 || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE))
2288 else if (strcmp(ptr->mname, "grid bug"))
2289 n += (tmp2 != AD_PHYS);
2290 n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23);
2293 /* Leprechauns are special cases. They have many hit dice so they can
2294 hit and are hard to kill, but they don't really do much damage. */
2295 if (!strcmp(ptr->mname, "leprechaun"))
2298 /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */
2306 return (tmp >= 0) ? tmp : 0;
2312 register struct permonst *ptr;
2316 * create the source file, "monstr.c"
2320 Strcat(filename, file_prefix);
2322 Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C);
2323 if (!(ofp = fopen(filename, WRTMODE))) {
2327 Fprintf(ofp, "%s", Dont_Edit_Code);
2328 Fprintf(ofp, "#include \"config.h\"\n");
2329 Fprintf(ofp, "\nconst int monstr[] = {\n");
2330 for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) {
2334 Fprintf(ofp, "%2d,%c", i, (++j & 15) ? ' ' : '\n');
2336 /* might want to insert a final 0 entry here instead of just newline */
2337 Fprintf(ofp, "%s};\n", (j & 15) ? "\n" : "");
2339 Fprintf(ofp, "\nvoid NDECL(monstr_init);\n");
2340 Fprintf(ofp, "\nvoid\n");
2341 Fprintf(ofp, "monstr_init()\n");
2342 Fprintf(ofp, "{\n");
2343 Fprintf(ofp, " return;\n");
2344 Fprintf(ofp, "}\n");
2345 Fprintf(ofp, "\n/*monstr.c*/\n");
2359 Strcat(filename, file_prefix);
2361 Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE);
2362 if (!(ofp = fopen(filename, WRTMODE))) {
2366 Fprintf(ofp, "%s", Dont_Edit_Code);
2367 Fprintf(ofp, "#ifndef PM_H\n#define PM_H\n");
2369 for (i = 0; mons[i].mlet; i++) {
2372 Fprintf(ofp, "\n#define\tPM_");
2373 if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].mname, "were", 4))
2374 Fprintf(ofp, "HUMAN_");
2375 for (nam = c = tmpdup(mons[i].mname); *c; c++)
2376 if (*c >= 'a' && *c <= 'z')
2377 *c -= (char) ('a' - 'A');
2378 else if (*c < 'A' || *c > 'Z')
2380 Fprintf(ofp, "%s\t%d", nam, i);
2382 Fprintf(ofp, "\n\n#define\tNUMMONS\t%d\n", i);
2383 Fprintf(ofp, "\n#endif /* PM_H */\n");
2388 /* Start of Quest text file processing. */
2391 static struct qthdr qt_hdr;
2392 static struct msghdr msg_hdr[N_HDR];
2393 static struct qtmsg *curr_msg;
2397 static boolean in_msg;
2398 #define NO_MSG 1 /* strlen of a null line returned by fgets() */
2406 return (boolean) (!in_msg && strlen(s) == NO_MSG);
2413 return (boolean) (s[0] == '%' && (s[1] == 'C' || s[1] == 'E'));
2422 for (i = 0; i < qt_hdr.n_hdr; i++)
2423 if (!strncmp(code, qt_hdr.id[i], LEN_HDR))
2433 if (qt_hdr.n_hdr >= N_HDR) {
2434 Fprintf(stderr, OUT_OF_HEADERS, qt_line);
2438 strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR);
2439 msg_hdr[qt_hdr.n_hdr].n_msg = 0;
2440 qt_hdr.offset[qt_hdr.n_hdr++] = 0L;
2450 for (i = 0; i < msg_hdr[num].n_msg; i++)
2451 if (msg_hdr[num].qt_msg[i].msgnum == id)
2462 struct qtmsg *qt_msg;
2464 if (msg_hdr[num].n_msg >= N_MSG) {
2465 Fprintf(stderr, OUT_OF_MESSAGES, qt_line);
2467 qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]);
2468 qt_msg->msgnum = id;
2469 qt_msg->delivery = s[2];
2470 qt_msg->offset = qt_msg->size = qt_msg->summary_size = 0L;
2476 /* check %E record for "[summary text]" that nethack can stuff into the
2477 message history buffer when delivering text via window instead of pline */
2479 valid_qt_summary(s, parsing)
2480 char *s; /* end record: "%E" optionally followed by " [summary]" */
2481 boolean parsing; /* curr_msg is valid iff this is True */
2483 static char summary[BUFSZ];
2486 if (*s != '%' || *(s + 1) != 'E')
2488 if ((p = index(s, '[')) == 0)
2490 /* note: opening '[' and closing ']' will be retained in the output;
2491 anything after ']' will be discarded by putting a newline there */
2494 /* have an opening bracket; summary[] holds it and all text that follows
2497 /* find closing bracket */
2498 while (p > summary && *(p - 1) != ']')
2502 /* we backed up all the way to the start without finding a bracket */
2503 if (parsing) /* malformed summary */
2504 Fprintf(stderr, MAL_SUM, qt_line);
2505 } else if (p == summary + 1) {
2506 ; /* ignore empty [] */
2507 } else { /* got something */
2508 /* p points one spot past ']', usually to '\n';
2509 we need to include the \n as part of the size */
2511 /* during the writing pass we won't be able to recheck
2512 delivery, so any useless summary for a pline mode
2513 message has to be carried along to the output file */
2514 if (curr_msg->delivery == 'p')
2515 Fprintf(stderr, DUMB_SUM, qt_line);
2516 /* +1 is for terminating newline */
2517 curr_msg->summary_size = (long) (p - summary) + 1L;
2519 /* caller is writing rather than just parsing;
2520 force newline after the closing bracket */
2535 if (!index(s, '\n'))
2536 Fprintf(stderr, CTRL_TRUNC, qt_line);
2541 Fprintf(stderr, CREC_IN_MSG, qt_line);
2545 if (sscanf(&s[4], "%s %5d", code, &id) != 2) {
2546 Fprintf(stderr, UNREC_CREC, qt_line);
2549 num = get_hdr(code);
2550 if (!num && !new_id(code))
2552 num = get_hdr(code) - 1;
2553 if (known_msg(num, id))
2554 Fprintf(stderr, DUP_MSG, qt_line);
2556 new_msg(s, num, id);
2562 Fprintf(stderr, END_NOT_IN_MSG, qt_line);
2564 /* sets curr_msg->summary_size if applicable */
2565 (void) valid_qt_summary(s, TRUE);
2571 Fprintf(stderr, UNREC_CREC, qt_line);
2581 Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line);
2582 } else if (!index(s, '\n')) {
2583 Fprintf(stderr, TEXT_TRUNC, qt_line);
2586 curr_msg->size += strlen(s);
2594 long count = 0L, hdr_offset = sizeof(int)
2595 + (sizeof(char) * LEN_HDR + sizeof(long))
2598 for (i = 0; i < qt_hdr.n_hdr; i++) {
2599 qt_hdr.offset[i] = hdr_offset;
2600 hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg;
2603 for (i = 0; i < qt_hdr.n_hdr; i++)
2604 for (j = 0; j < msg_hdr[i].n_msg; j++) {
2605 msg_hdr[i].qt_msg[j].offset = hdr_offset + count;
2607 msg_hdr[i].qt_msg[j].size + msg_hdr[i].qt_msg[j].summary_size;
2618 * The main header record.
2621 Fprintf(stderr, "%ld: header info.\n", ftell(ofp));
2622 (void) fwrite((genericptr_t) & (qt_hdr.n_hdr), sizeof(int), 1, ofp);
2623 (void) fwrite((genericptr_t) & (qt_hdr.id[0][0]), sizeof(char) * LEN_HDR,
2625 (void) fwrite((genericptr_t) & (qt_hdr.offset[0]), sizeof(long),
2628 for (i = 0; i < qt_hdr.n_hdr; i++)
2629 Fprintf(stderr, "%s @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]);
2630 Fprintf(stderr, "\n");
2634 * The individual class headers.
2636 for (i = 0; i < qt_hdr.n_hdr; i++) {
2638 Fprintf(stderr, "%ld: %s header info.\n", ftell(ofp),
2640 (void) fwrite((genericptr_t) & (msg_hdr[i].n_msg), sizeof(int), 1,
2642 (void) fwrite((genericptr_t) & (msg_hdr[i].qt_msg[0]),
2643 sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp);
2647 for (j = 0; j < msg_hdr[i].n_msg; j++) {
2648 Fprintf(stderr, "msg %d @ %ld (%ld)",
2649 msg_hdr[i].qt_msg[j].msgnum,
2650 msg_hdr[i].qt_msg[j].offset,
2651 msg_hdr[i].qt_msg[j].size);
2652 if (msg_hdr[i].qt_msg[j].summary_size)
2653 Fprintf(stderr, " [%ld]",
2654 msg_hdr[i].qt_msg[j].summary_size);
2655 Fprintf(stderr, "\n");
2666 Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE);
2667 if (!(ifp = fopen(filename, RDTMODE))) {
2674 Strcat(filename, file_prefix);
2676 Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE);
2677 if (!(ofp = fopen(filename, WRBMODE))) {
2687 while ((line = fgetline(ifp)) != 0) {
2691 if (qt_control(line))
2692 do_qt_control(line);
2693 else if (qt_comment(line)) {
2705 while ((line = fgetline(ifp)) != 0) {
2706 if (qt_control(line)) {
2707 char *summary_p = 0;
2709 in_msg = (line[1] == 'C');
2711 summary_p = valid_qt_summary(line, FALSE);
2712 /* don't write anything unless we've got a summary */
2717 /* we have summary text; replace raw %E record with it */
2718 Strcpy(line, summary_p); /* (guaranteed to fit) */
2719 } else if (qt_comment(line)) {
2724 Fprintf(stderr, "%ld: %s", ftell(stdout), line);
2725 (void) fputs(xcrypt(line), ofp);
2733 static char temp[32];
2735 static char *limit(name, pref) /* limit a name to 30 characters length */
2739 (void) strncpy(temp, name, pref ? 26 : 30);
2740 temp[pref ? 26 : 30] = 0;
2752 boolean sumerr = FALSE;
2756 Strcat(filename, file_prefix);
2758 Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE);
2759 if (!(ofp = fopen(filename, WRTMODE))) {
2763 Fprintf(ofp, "%s", Dont_Edit_Code);
2764 Fprintf(ofp, "#ifndef ONAMES_H\n#define ONAMES_H\n\n");
2766 for (i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) {
2769 objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init */
2770 if (!(objnam = tmpdup(OBJ_NAME(objects[i]))))
2773 /* make sure probabilities add up to 1000 */
2774 if (objects[i].oc_class != class) {
2775 if (sum && sum != 1000) {
2776 Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
2777 (void) fflush(stderr);
2780 class = objects[i].oc_class;
2784 for (c = objnam; *c; c++)
2785 if (*c >= 'a' && *c <= 'z')
2786 *c -= (char) ('a' - 'A');
2787 else if (*c < 'A' || *c > 'Z')
2792 Fprintf(ofp, "#define\tWAN_");
2796 Fprintf(ofp, "#define\tRIN_");
2800 Fprintf(ofp, "#define\tPOT_");
2804 Fprintf(ofp, "#define\tSPE_");
2809 Fprintf(ofp, "#define\tSCR_");
2813 /* avoid trouble with stupid C preprocessors */
2814 Fprintf(ofp, "#define\t");
2815 if (objects[i].oc_material == PLASTIC) {
2816 Fprintf(ofp, "FAKE_AMULET_OF_YENDOR\t%d\n", i);
2822 /* avoid trouble with stupid C preprocessors */
2823 if (objects[i].oc_material == GLASS) {
2824 Fprintf(ofp, "/* #define\t%s\t%d */\n", objnam, i);
2830 Fprintf(ofp, "#define\t");
2833 Fprintf(ofp, "%s\t%d\n", limit(objnam, prefix), i);
2836 sum += objects[i].oc_prob;
2839 /* check last set of probabilities */
2840 if (sum && sum != 1000) {
2841 Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
2842 (void) fflush(stderr);
2846 Fprintf(ofp, "#define\tLAST_GEM\t(JADE)\n");
2847 Fprintf(ofp, "#define\tMAXSPELL\t%d\n", nspell + 1);
2848 Fprintf(ofp, "#define\tNUM_OBJECTS\t%d\n", i);
2850 Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n");
2852 for (i = 1; artifact_names[i]; i++) {
2855 for (c = objnam = tmpdup(artifact_names[i]); *c; c++)
2856 if (*c >= 'a' && *c <= 'z')
2857 *c -= (char) ('a' - 'A');
2858 else if (*c < 'A' || *c > 'Z')
2861 if (!strncmp(objnam, "THE_", 4))
2863 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
2864 if (!strncmp(objnam, "PLATINUM_", 9))
2866 Fprintf(ofp, "#define\tART_%s\t%d\n", limit(objnam, 1), i);
2869 Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i - 1);
2870 Fprintf(ofp, "\n#endif /* ONAMES_H */\n");
2877 /* Read one line from input, up to and including the next newline
2878 * character. Returns a pointer to the heap-allocated string, or a
2879 * null pointer if no characters were read.
2885 static const int inc = 256;
2887 char *c = malloc(len), *ret;
2890 ret = fgets(c + len - inc, inc, fd);
2895 } else if (index(c, '\n')) {
2896 /* normal case: we have a full line */
2900 c = realloc(c, len);
2909 static char buf[128];
2913 (void) strncpy(buf, str, 127);
2927 * macro used to control vision algorithms:
2928 * VISION_TABLES => generate tables
2934 #ifdef VISION_TABLES
2937 /* Everything is clear. xclear may be malloc'ed.
2938 * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
2940 for (i = 0; i < MAX_ROW; i++)
2941 for (j = 0; j < MAX_COL; j++)
2942 if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH)
2943 xclear[i][j] = '\000';
2945 xclear[i][j] = '\001';
2946 #endif /* VISION_TABLES */
2951 * create the include file, "vis_tab.h"
2955 Strcat(filename, file_prefix);
2957 Sprintf(eos(filename), INCLUDE_TEMPLATE, VIS_TAB_H);
2958 if (!(ofp = fopen(filename, WRTMODE))) {
2962 Fprintf(ofp, "%s", Dont_Edit_Code);
2963 Fprintf(ofp, "#ifdef VISION_TABLES\n");
2964 #ifdef VISION_TABLES
2967 #endif /* VISION_TABLES */
2968 Fprintf(ofp, "\n#endif /* VISION_TABLES */\n");
2974 * create the source file, "vis_tab.c"
2978 Strcat(filename, file_prefix);
2980 Sprintf(eos(filename), SOURCE_TEMPLATE, VIS_TAB_C);
2981 if (!(ofp = fopen(filename, WRTMODE))) {
2983 /* creating vis_tab.c failed; remove the vis_tab.h we just made */
2986 Strcat(filename, file_prefix);
2988 Sprintf(eos(filename), INCLUDE_TEMPLATE, VIS_TAB_H);
2992 Fprintf(ofp, "%s", Dont_Edit_Code);
2993 Fprintf(ofp, "#include \"config.h\"\n");
2994 Fprintf(ofp, "#ifdef VISION_TABLES\n");
2995 Fprintf(ofp, "#include \"vis_tab.h\"\n");
2999 #ifdef VISION_TABLES
3002 Fprintf(ofp, "\nvoid vis_tab_init() { return; }\n");
3003 #endif /* VISION_TABLES */
3007 Fprintf(ofp, "\n#endif /* VISION_TABLES */\n");
3008 Fprintf(ofp, "\n/*vis_tab.c*/\n");
3014 #ifdef VISION_TABLES
3016 /*-------------- vision tables --------------*\
3018 * Generate the close and far tables. This is done by setting up a
3019 * fake dungeon and moving our source to different positions relative
3020 * to a block and finding the first/last visible position. The fake
3021 * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
3022 * by BLOCK_WIDTH) is blocked. Then we move the source around relative
3023 * to the corner of the block. For each new position of the source
3024 * we check positions on rows "kittycorner" from the source. We check
3025 * positions until they are either in sight or out of sight (depends on
3026 * which table we are generating). The picture below shows the setup
3027 * for the generation of the close table. The generation of the far
3028 * table would switch the quadrants of the '@' and the "Check rows
3032 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
3033 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
3034 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
3035 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
3036 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
3037 * ...............................
3038 * ...............................
3039 * .........@.....................
3040 * ...............................
3042 * Table generation figure (close_table). The 'X's are blocked points.
3043 * The 'B' is a special blocked point. The '@' is the source. The ','s
3044 * are the target area. The '.' are just open areas.
3047 * Example usage of close_table[][][].
3049 * The table is as follows:
3051 * dy = |row of '@' - row of 'B'| - 1
3052 * dx = |col of '@' - col of 'B'|
3054 * The first indices are the deltas from the source '@' and the block 'B'.
3055 * You must check for the value inside the abs value bars being zero. If
3056 * so then the block is on the same row and you don't need to do a table
3057 * lookup. The last value:
3059 * dcy = |row of block - row to be checked|
3061 * Is the value of the first visible spot on the check row from the
3064 * first visible col = close_table[dy][dx][dcy] + col of 'B'
3066 \*-------------- vision tables --------------*/
3071 Fprintf(ofp, "\n/* Close */\n");
3073 "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
3076 "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
3079 "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
3081 Fprintf(ofp, "typedef struct {\n");
3083 " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
3084 Fprintf(ofp, "} close2d;\n");
3085 Fprintf(ofp, "extern close2d close_table[CLOSE_MAX_SB_DY];\n");
3092 Fprintf(ofp, "\n/* Far */\n");
3093 Fprintf(ofp, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
3096 "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
3099 "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
3101 Fprintf(ofp, "typedef struct {\n");
3102 Fprintf(ofp, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
3103 Fprintf(ofp, "} far2d;\n");
3104 Fprintf(ofp, "extern far2d far_table[FAR_MAX_SB_DY];\n");
3112 int src_row, src_col; /* source */
3113 int block_row, block_col; /* block */
3118 block_row = BLOCK_HEIGHT - 1;
3119 block_col = BLOCK_WIDTH - 1;
3121 Fprintf(ofp, "\n#ifndef FAR_TABLE_ONLY\n");
3122 Fprintf(ofp, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
3123 #ifndef no_vision_progress
3124 Fprintf(stderr, "\nclose:");
3127 for (dy = 1; dy < TEST_HEIGHT; dy++) {
3128 src_row = block_row + dy;
3129 Fprintf(ofp, "/* DY = %2d (- 1)*/\n {{\n", dy);
3130 #ifndef no_vision_progress
3131 Fprintf(stderr, " %2d", dy), (void) fflush(stderr);
3133 for (dx = 0; dx < TEST_WIDTH; dx++) {
3134 src_col = block_col - dx;
3135 Fprintf(ofp, " /*%2d*/ {", dx);
3138 for (this_row = 0; this_row < TEST_HEIGHT; this_row++) {
3139 delim = (this_row < TEST_HEIGHT - 1) ? "," : "";
3141 Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim);
3146 /* Find the first column that we can see. */
3147 for (i = block_col + 1; i < MAX_COL; i++) {
3148 if (clear_path(src_row, src_col, block_row - this_row, i))
3154 Fprintf(ofp, "%2d%s", i - block_col, delim);
3156 Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
3158 Fprintf(ofp, " }},\n");
3161 Fprintf(ofp, "}; /* close_table[] */\n"); /* closing brace for table */
3162 Fprintf(ofp, "#endif /* !FAR_TABLE_ONLY */\n");
3163 #ifndef no_vision_progress
3164 Fprintf(stderr, "\n");
3173 int src_row, src_col; /* source */
3174 int block_row, block_col; /* block */
3178 block_row = BLOCK_HEIGHT - 1;
3179 block_col = BLOCK_WIDTH - 1;
3181 Fprintf(ofp, "\n#ifndef CLOSE_TABLE_ONLY\n");
3182 Fprintf(ofp, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
3183 #ifndef no_vision_progress
3184 Fprintf(stderr, "\n_far_:");
3187 for (dy = 0; dy < TEST_HEIGHT; dy++) {
3188 src_row = block_row - dy;
3189 Fprintf(ofp, "/* DY = %2d */\n {{\n", dy);
3190 #ifndef no_vision_progress
3191 Fprintf(stderr, " %2d", dy), (void) fflush(stderr);
3193 for (dx = 1; dx < TEST_WIDTH; dx++) {
3194 src_col = block_col + dx;
3195 Fprintf(ofp, " /*%2d(-1)*/ {", dx);
3197 for (this_row = block_row + 1; this_row < block_row + TEST_HEIGHT;
3199 delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : "";
3202 /* Find first col that we can see. */
3203 for (i = 0; i <= block_col; i++) {
3204 if (clear_path(src_row, src_col, this_row, i))
3208 if (block_col - i < 0)
3209 Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim);
3211 Fprintf(ofp, "%2d%s", block_col - i, delim);
3213 Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
3215 Fprintf(ofp, " }},\n");
3218 Fprintf(ofp, "}; /* far_table[] */\n"); /* closing brace for table */
3219 Fprintf(ofp, "#endif /* !CLOSE_TABLE_ONLY */\n");
3220 #ifndef no_vision_progress
3221 Fprintf(stderr, "\n");
3227 * "Draw" a line from the hero to the given location. Stop if we hit a
3230 * Generalized integer Bresenham's algorithm (fast line drawing) for
3231 * all quadrants. From _Procedural Elements for Computer Graphics_, by
3232 * David F. Rogers. McGraw-Hill, 1985.
3234 * I have tried a little bit of optimization by pulling compares out of
3237 * NOTE: This had better *not* be called from a position on the
3238 * same row as the hero.
3241 clear_path(you_row, you_col, y2, x2)
3242 int you_row, you_col, y2, x2;
3245 register int i, error, x, y, dxs, dys;
3249 dx = abs(x2 - you_col);
3250 dy = abs(y2 - you_row);
3251 s1 = sign(x2 - you_col);
3252 s2 = sign(y2 - you_row);
3254 if (s1 == 0) { /* same column */
3255 if (s2 == 1) { /* below (larger y2 value) */
3256 for (i = you_row + 1; i < y2; i++)
3257 if (!xclear[i][you_col])
3259 } else { /* above (smaller y2 value) */
3260 for (i = y2 + 1; i < you_row; i++)
3261 if (!xclear[i][you_col])
3268 * Lines at 0 and 90 degrees have been weeded out.
3273 dy = error; /* swap the values */
3274 dxs = dx << 1; /* save the shifted values */
3276 error = dys - dx; /* NOTE: error is used as a temporary above */
3278 for (i = 0; i < dx; i++) {
3280 return 0; /* plot point */
3282 while (error >= 0) {
3290 dxs = dx << 1; /* save the shifted values */
3294 for (i = 0; i < dx; i++) {
3296 return 0; /* plot point */
3298 while (error >= 0) {
3308 #endif /* VISION_TABLES */
3310 #ifdef STRICT_REF_DEF
3311 NEARDATA struct flag flags;
3313 struct attribs attrmax, attrmin;
3315 #endif /* STRICT_REF_DEF */