mplayer.c formatting
[aNetHack.git] / util / makedefs.c
blob2969b66456ff22b38cf11763eefcb0bccaa24cc4
1 /* NetHack 3.6 makedefs.c $NHDT-Date: 1455357861 2016/02/13 10:04:21 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.109 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* Copyright (c) M. Stephenson, 1990, 1991. */
4 /* Copyright (c) Dean Luick, 1990. */
5 /* NetHack may be freely redistributed. See license for details. */
7 #define MAKEDEFS_C /* use to conditionally include file sections */
9 #include "config.h"
10 #ifdef MONITOR_HEAP
11 #undef free /* makedefs doesn't use the alloc and free in src/alloc.c */
12 #endif
13 #include "permonst.h"
14 #include "objclass.h"
15 #include "monsym.h"
16 #include "artilist.h"
17 #include "dungeon.h"
18 #include "obj.h"
19 #include "monst.h"
20 #include "you.h"
21 #include "context.h"
22 #include "flag.h"
23 #include "dlb.h"
25 /* version information */
26 #ifdef SHORT_FILENAMES
27 #include "patchlev.h"
28 #else
29 #include "patchlevel.h"
30 #endif
32 #include <ctype.h>
33 #ifdef MAC
34 #if defined(__SC__) || defined(__MRC__) /* MPW compilers */
35 #define MPWTOOL
36 #include <CursorCtl.h>
37 #include <string.h>
38 #else /* MAC without MPWTOOL */
39 #define MACsansMPWTOOL
40 #endif
41 #endif /* MAC */
43 #ifndef MPWTOOL
44 #define SpinCursor(x)
45 #endif
47 #define Fprintf (void) fprintf
48 #define Fclose (void) fclose
49 #define Unlink (void) unlink
50 #if !defined(AMIGA) || defined(AZTEC_C)
51 #define rewind(fp) fseek((fp), 0L, SEEK_SET) /* guarantee a return value */
52 #endif
54 #if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN)
55 static const char SCCS_Id[] = "@(#)makedefs.c\t3.6\t2016/02/12";
56 #endif
58 /* names of files to be generated */
59 #define DATE_FILE "date.h"
60 #define MONST_FILE "pm.h"
61 #define ONAME_FILE "onames.h"
62 #ifndef OPTIONS_FILE
63 #define OPTIONS_FILE "options"
64 #endif
65 #define ORACLE_FILE "oracles"
66 #define DATA_FILE "data"
67 #define RUMOR_FILE "rumors"
68 #define DGN_I_FILE "dungeon.def"
69 #define DGN_O_FILE "dungeon.pdf"
70 #define MON_STR_C "monstr.c"
71 #define QTXT_I_FILE "quest.txt"
72 #define QTXT_O_FILE "quest.dat"
73 #define VIS_TAB_H "vis_tab.h"
74 #define VIS_TAB_C "vis_tab.c"
75 /* locations for those files */
76 #ifdef AMIGA
77 #define FILE_PREFIX
78 #define INCLUDE_TEMPLATE "NH:include/t.%s"
79 #define SOURCE_TEMPLATE "NH:src/%s"
80 #define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */
81 #define DATA_TEMPLATE "NH:slib/%s"
82 #define DATA_IN_TEMPLATE "NH:dat/%s"
83 #else /* not AMIGA */
84 #if defined(MAC) && !defined(__MACH__)
85 /* MacOS 9 or earlier */
86 #define INCLUDE_TEMPLATE ":include:%s"
87 #define SOURCE_TEMPLATE ":src:%s"
88 #define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */
89 #if __SC__ || __MRC__
90 #define DATA_TEMPLATE ":Dungeon:%s"
91 #else
92 #define DATA_TEMPLATE ":lib:%s"
93 #endif /* __SC__ || __MRC__ */
94 #define DATA_IN_TEMPLATE ":dat:%s"
95 #else /* neither AMIGA nor MAC */
96 #ifdef OS2
97 #define INCLUDE_TEMPLATE "..\\include\\%s"
98 #define SOURCE_TEMPLATE "..\\src\\%s"
99 #define DGN_TEMPLATE "..\\dat\\%s" /* where dungeon.pdf file goes */
100 #define DATA_TEMPLATE "..\\dat\\%s"
101 #define DATA_IN_TEMPLATE "..\\dat\\%s"
102 #else /* not AMIGA, MAC, or OS2 */
103 #define INCLUDE_TEMPLATE "../include/%s"
104 #define SOURCE_TEMPLATE "../src/%s"
105 #define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */
106 #define DATA_TEMPLATE "../dat/%s"
107 #define DATA_IN_TEMPLATE "../dat/%s"
108 #endif /* else !OS2 */
109 #endif /* else !MAC */
110 #endif /* else !AMIGA */
112 static const char
113 *Dont_Edit_Code =
114 "/* This source file is generated by 'makedefs'. Do not edit. */\n",
115 *Dont_Edit_Data =
116 "#\tThis data file is generated by 'makedefs'. Do not edit. \n";
118 static struct version_info version;
120 /* definitions used for vision tables */
121 #define TEST_WIDTH COLNO
122 #define TEST_HEIGHT ROWNO
123 #define BLOCK_WIDTH (TEST_WIDTH + 10)
124 #define BLOCK_HEIGHT TEST_HEIGHT /* don't need extra spaces */
125 #define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT)
126 #define MAX_COL (BLOCK_WIDTH + TEST_WIDTH)
127 /* Use this as an out-of-bound value in the close table. */
128 #define CLOSE_OFF_TABLE_STRING "99" /* for the close table */
129 #define FAR_OFF_TABLE_STRING "0xff" /* for the far table */
131 #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0))
132 #ifdef VISION_TABLES
133 static char xclear[MAX_ROW][MAX_COL];
134 #endif
135 /*-end of vision defs-*/
137 static char filename[600];
139 #ifdef FILE_PREFIX
140 /* if defined, a first argument not starting with - is
141 * taken as a text string to be prepended to any
142 * output filename generated */
143 char *file_prefix = "";
144 #endif
146 #ifdef MACsansMPWTOOL
147 int FDECL(main, (void));
148 #else
149 int FDECL(main, (int, char **));
150 #endif
151 void FDECL(do_makedefs, (char *));
152 void NDECL(do_objs);
153 void NDECL(do_data);
154 void NDECL(do_dungeon);
155 void NDECL(do_date);
156 void NDECL(do_options);
157 void NDECL(do_monstr);
158 void NDECL(do_permonst);
159 void NDECL(do_questtxt);
160 void NDECL(do_rumors);
161 void NDECL(do_oracles);
162 void NDECL(do_vision);
164 extern void NDECL(monst_init); /* monst.c */
165 extern void NDECL(objects_init); /* objects.c */
167 static void NDECL(link_sanity_check);
168 static char *FDECL(name_file, (const char *, const char *));
169 static void FDECL(delete_file, (const char *template, const char *));
170 static FILE *FDECL(getfp, (const char *, const char *, const char *));
171 static void FDECL(do_ext_makedefs, (int, char **));
173 static void NDECL(make_version);
174 static char *FDECL(version_string, (char *, const char *));
175 static char *FDECL(version_id_string, (char *, const char *));
176 static char *FDECL(bannerc_string, (char *, const char *));
177 static char *FDECL(xcrypt, (const char *));
178 static unsigned long FDECL(read_rumors_file,
179 (const char *, int *, long *, unsigned long));
180 static void FDECL(do_rnd_access_file, (const char *));
181 static boolean FDECL(d_filter, (char *));
182 static boolean FDECL(h_filter, (char *));
183 static boolean FDECL(ranged_attk, (struct permonst *));
184 static int FDECL(mstrength, (struct permonst *));
185 static void NDECL(build_savebones_compat_string);
186 static void NDECL(windowing_sanity);
188 static boolean FDECL(qt_comment, (char *));
189 static boolean FDECL(qt_control, (char *));
190 static int FDECL(get_hdr, (char *));
191 static boolean FDECL(new_id, (char *));
192 static boolean FDECL(known_msg, (int, int));
193 static void FDECL(new_msg, (char *, int, int));
194 static char *FDECL(valid_qt_summary, (char *, BOOLEAN_P));
195 static void FDECL(do_qt_control, (char *));
196 static void FDECL(do_qt_text, (char *));
197 static void NDECL(adjust_qt_hdrs);
198 static void NDECL(put_qt_hdrs);
200 #ifdef VISION_TABLES
201 static void NDECL(H_close_gen);
202 static void NDECL(H_far_gen);
203 static void NDECL(C_close_gen);
204 static void NDECL(C_far_gen);
205 static int FDECL(clear_path, (int, int, int, int));
206 #endif
208 static char *FDECL(fgetline, (FILE*));
209 static char *FDECL(tmpdup, (const char *));
210 static char *FDECL(limit, (char *, int));
211 static char *FDECL(eos, (char *));
213 /* input, output, tmp */
214 static FILE *ifp, *ofp, *tfp;
216 #if defined(__BORLANDC__) && !defined(_WIN32)
217 extern unsigned _stklen = STKSIZ;
218 #endif
220 #ifdef MACsansMPWTOOL
222 main(void)
224 const char *def_options = "odemvpqrshz";
225 char buf[100];
226 int len;
228 printf("Enter options to run: [%s] ", def_options);
229 fflush(stdout);
230 fgets(buf, 100, stdin);
231 len = strlen(buf);
232 if (len <= 1)
233 Strcpy(buf, def_options);
234 else
235 buf[len - 1] = 0; /* remove return */
237 if (buf[0] == '-' && buf[1] == '-') {
238 #if 0
239 split up buf into words
240 do_ext_makedefs(fakeargc, fakeargv);
241 #else
242 printf("extended makedefs not implemented for Mac OS9\n");
243 exit(EXIT_FAILURE);
244 #endif
247 do_makedefs(buf);
248 exit(EXIT_SUCCESS);
249 return 0;
252 #else /* ! MAC */
255 main(argc, argv)
256 int argc;
257 char *argv[];
259 if ((argc != 2)
260 #ifdef FILE_PREFIX
261 && (argc != 3)
262 #endif
263 && !(argv[1][0] == '-' && argv[1][1] == '-')) {
264 Fprintf(stderr, "Bad arg count (%d).\n", argc - 1);
265 (void) fflush(stderr);
266 return 1;
269 #ifdef FILE_PREFIX
270 if (argc >= 2 && argv[1][0] != '-') {
271 file_prefix = argv[1];
272 argc--;
273 argv++;
275 #endif
277 if (argv[1][0] == '-' && argv[1][1] == '-') {
278 do_ext_makedefs(argc, argv);
279 } else {
280 do_makedefs(&argv[1][1]);
282 exit(EXIT_SUCCESS);
283 /*NOTREACHED*/
284 return 0;
287 #endif
289 static void
290 link_sanity_check()
292 /* Note: these initializers don't do anything except guarantee that
293 we're linked properly.
295 monst_init();
296 objects_init();
299 void
300 do_makedefs(options)
301 char *options;
303 boolean more_than_one;
305 link_sanity_check();
307 /* construct the current version number */
308 make_version();
310 more_than_one = strlen(options) > 1;
311 while (*options) {
312 if (more_than_one)
313 Fprintf(stderr, "makedefs -%c\n", *options);
315 switch (*options) {
316 case 'o':
317 case 'O':
318 do_objs();
319 break;
320 case 'd':
321 case 'D':
322 do_data();
323 break;
324 case 'e':
325 case 'E':
326 do_dungeon();
327 break;
328 case 'm':
329 case 'M':
330 do_monstr();
331 break;
332 case 'v':
333 case 'V':
334 do_date();
335 do_options();
336 break;
337 case 'p':
338 case 'P':
339 do_permonst();
340 break;
341 case 'q':
342 case 'Q':
343 do_questtxt();
344 break;
345 case 'r':
346 case 'R':
347 do_rumors();
348 break;
349 case 's':
350 case 'S':
351 do_rnd_access_file(EPITAPHFILE);
352 do_rnd_access_file(ENGRAVEFILE);
353 do_rnd_access_file(BOGUSMONFILE);
354 break;
355 case 'h':
356 case 'H':
357 do_oracles();
358 break;
359 case 'z':
360 case 'Z':
361 do_vision();
362 break;
364 default:
365 Fprintf(stderr, "Unknown option '%c'.\n", *options);
366 (void) fflush(stderr);
367 exit(EXIT_FAILURE);
369 options++;
371 if (more_than_one)
372 Fprintf(stderr, "Completed.\n"); /* feedback */
375 static char namebuf[1000];
377 static char *
378 name_file(template, tag)
379 const char *template;
380 const char *tag;
382 Sprintf(namebuf, template, tag);
383 return namebuf;
386 static void
387 delete_file(template, tag)
388 const char *template;
389 const char *tag;
391 char *name = name_file(template, tag);
393 Unlink(name);
396 static FILE *
397 getfp(template, tag, mode)
398 const char *template;
399 const char *tag;
400 const char *mode;
402 char *name = name_file(template, tag);
403 FILE *rv = fopen(name, mode);
405 if (!rv) {
406 Fprintf(stderr, "Can't open '%s'.\n", name);
407 exit(EXIT_FAILURE);
409 return rv;
412 static boolean debug = FALSE;
414 static FILE *inputfp;
415 static FILE *outputfp;
417 struct grep_var {
418 const char *name;
419 int is_defined; /* 0 undef; 1 defined */
421 /* struct grep_var grep_vars[] and TODO_* constants in include file: */
422 #include "mdgrep.h"
424 static void NDECL(do_grep_showvars);
425 static struct grep_var *FDECL(grepsearch, (const char *));
426 static int FDECL(grep_check_id, (const char *));
427 static void FDECL(grep_show_wstack, (const char *));
428 static char *FDECL(do_grep_control, (char *));
429 static void NDECL(do_grep);
430 static void FDECL(grep0, (FILE *, FILE *));
432 static int grep_trace = 0;
434 #define IS_OPTION(str) if (!strcmp(&argv[0][2], str))
435 #define CONTINUE \
436 argv++, argc--; \
437 continue
438 #define CONSUME \
439 argv++, argc--; \
440 if (argc == 0) { \
441 Fprintf(stderr, "missing option\n"); \
442 exit(EXIT_FAILURE); \
445 static void
446 do_ext_makedefs(int argc, char **argv)
448 int todo = 0;
450 link_sanity_check();
452 argc--;
453 argv++; /* skip program name */
455 while (argc) {
456 if (argv[0][0] != '-')
457 break;
458 if (argv[0][1] != '-') {
459 Fprintf(stderr, "Can't mix - and -- options.\n");
460 exit(EXIT_FAILURE);
462 IS_OPTION("svs") {
463 /* short version string for packaging - note no \n */
464 char buf[100];
465 char delim[10];
467 argv++; /* not CONSUME */
468 delim[0] = '\0';
469 if (argv[0])
470 strcpy(delim, argv[0]);
471 Fprintf(stdout, "%s", version_string(buf, delim));
472 exit(EXIT_SUCCESS);
474 IS_OPTION("debug") {
475 debug = TRUE;
476 CONTINUE;
478 IS_OPTION("make") {
479 CONSUME;
480 do_makedefs(argv[0]);
481 exit(EXIT_SUCCESS);
483 IS_OPTION("input") {
484 CONSUME;
485 if (!strcmp(argv[0], "-")) {
486 inputfp = stdin;
487 } else {
488 inputfp = fopen(argv[0], RDTMODE);
489 if (!inputfp) {
490 Fprintf(stderr, "Can't open '%s'.\n", argv[0]);
491 exit(EXIT_FAILURE);
494 CONTINUE;
496 IS_OPTION("output") {
497 CONSUME;
498 if (!strcmp(argv[0], "-")) {
499 outputfp = stdout;
500 } else {
501 outputfp = fopen(argv[0], WRTMODE);
502 if (!outputfp) {
503 Fprintf(stderr, "Can't open '%s'.\n", argv[0]);
504 exit(EXIT_FAILURE);
507 CONTINUE;
509 IS_OPTION("grep") {
510 if (todo) {
511 Fprintf(stderr, "Can't do grep and something else.\n");
512 exit(EXIT_FAILURE);
514 todo = TODO_GREP;
515 CONTINUE;
517 IS_OPTION("grep-showvars") {
518 do_grep_showvars();
519 exit(EXIT_SUCCESS);
521 IS_OPTION("grep-trace") {
522 grep_trace = 1;
523 CONTINUE;
525 IS_OPTION("grep-define") {
526 struct grep_var *p;
528 CONSUME;
529 p = grepsearch(argv[0]);
530 if (p) {
531 p->is_defined = 1;
532 } else {
533 Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]);
534 exit(EXIT_FAILURE);
536 CONTINUE;
538 IS_OPTION("grep-undef") {
539 struct grep_var *p;
541 CONSUME;
542 p = grepsearch(argv[0]);
543 if (p) {
544 p->is_defined = 0;
545 } else {
546 Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]);
547 exit(EXIT_FAILURE);
549 CONTINUE;
551 #ifdef notyet
552 IS_OPTION("help") {
554 #endif
555 Fprintf(stderr, "Unknown option '%s'.\n", argv[0]);
556 exit(EXIT_FAILURE);
558 if (argc) {
559 Fprintf(stderr, "unexpected argument '%s'.\n", argv[0]);
560 exit(EXIT_FAILURE);
563 switch (todo) {
564 default:
565 Fprintf(stderr, "Confused about what to do?\n");
566 exit(EXIT_FAILURE);
567 case 0:
568 Fprintf(stderr, "Nothing to do?\n");
569 exit(EXIT_FAILURE);
570 case TODO_GREP:
571 do_grep();
572 break;
576 #undef IS_OPTION
577 #undef CONTINUE
578 #undef CONSUME
581 Filtering syntax:
582 Any line NOT starting with a caret is either suppressed or passed through
583 unchanged depending on the current conditional state.
585 The default conditional state is printing on.
587 Conditionals may be nested.
589 makedefs will exit with a EXIT_FAILURE if any errors are detected; as many
590 errors as possible are detected before giving up.
592 Unknown identifiers are treated as TRUE and also as an error to allow
593 processing to continue past the unknown identifier (note that "#undef" is
594 different than unknown).
596 Any line starting with a caret is a control line; as in C, zero or more
597 spaces
598 may be embedded in the line almost anywhere; the caret MUST be in column 1.
599 (XXX for the moment, no white space is allowed after the caret because
600 existing lines in the docs look like that)
602 Control lines:
603 ^^ a line starting with a (single) literal caret
604 ^# a comment - the line is ignored
605 ^?ID if defined(ID)
606 ^!ID if !defined(ID)
607 ^: else
608 ^. endif
611 #define GREP_MAGIC '^'
612 #define GREP_STACK_SIZE 100
613 #ifdef notyet
614 static int grep_rewrite = 0; /* need to (possibly) rewrite lines */
615 #endif
616 static int grep_writing = 1; /* need to copy lines to output */
617 static int grep_errors = 0;
618 static int grep_sp = 0;
619 #define ST_LD(old, opp) (!!(old) | (!!(opp) << 1))
620 #define ST_OLD(v) ((v) &1)
621 #define ST_OPP(v) !!((v) &2)
622 #define ST_ELSE 4
623 static int grep_stack[GREP_STACK_SIZE] = { ST_LD(1, 0) };
624 static int grep_lineno = 0;
626 static void
627 do_grep_showvars()
629 int x;
631 for (x = 0; x < SIZE(grep_vars) - 1; x++) {
632 printf("%d\t%s\n", grep_vars[x].is_defined, grep_vars[x].name);
636 static struct grep_var *
637 grepsearch(name)
638 const char *name;
640 /* XXX make into binary search */
641 int x = 0;
643 while (x < SIZE(grep_vars) - 1) {
644 if (!strcmp(grep_vars[x].name, name))
645 return &grep_vars[x];
646 x++;
648 return 0;
651 static int
652 grep_check_id(id)
653 const char *id;
655 struct grep_var *rv;
657 while (*id && isspace(*id))
658 id++;
659 if (!*id) {
660 Fprintf(stderr, "missing identifier in line %d", grep_lineno);
661 grep_errors++;
662 return 0;
664 rv = grepsearch(id);
665 if (rv) {
666 if (grep_trace) {
667 Fprintf(outputfp, "ID %d %s\n", rv->is_defined, id);
669 return rv->is_defined;
672 if (grep_trace) {
673 Fprintf(outputfp, "ID U %s\n", id);
675 Fprintf(stderr, "unknown identifier '%s' in line %d.\n", id, grep_lineno);
676 grep_errors++;
677 return 2; /* So new features can be checked before makedefs
678 * is rebuilt. */
681 static void
682 grep_show_wstack(tag)
683 const char *tag;
685 int x;
687 if (!grep_trace)
688 return;
690 Fprintf(outputfp, "%s w=%d sp=%d\t", tag, grep_writing, grep_sp);
691 for (x = grep_sp; x >= 0 && x > grep_sp - 6; x--) {
692 Fprintf(outputfp, "[%d]=%d ", x, grep_stack[x]);
694 Fprintf(outputfp, "\n");
697 static char *
698 do_grep_control(buf)
699 char *buf;
701 int isif = 1;
702 char *buf0 = buf;
703 #if 1
704 if (isspace(buf[0]))
705 return &buf[-1]; /* XXX see docs above */
706 #else
707 while (buf[0] && isspace(buf[0]))
708 buf++;
709 #endif
710 switch (buf[0]) {
711 case '#': /* comment */
712 break;
713 case '.': /* end of if level */
714 if (grep_sp == 0) {
715 Fprintf(stderr, "unmatched ^. (endif) at line %d.\n",
716 grep_lineno);
717 grep_errors++;
718 } else {
719 grep_writing = ST_OLD(grep_stack[grep_sp--]);
720 grep_show_wstack("pop");
722 break;
723 case '!': /* if not ID */
724 isif = 0;
725 /* FALLTHROUGH */
726 case '?': /* if ID */
727 if (grep_sp == GREP_STACK_SIZE - 2) {
728 Fprintf(stderr, "stack overflow at line %d.", grep_lineno);
729 exit(EXIT_FAILURE);
731 if (grep_writing) {
732 isif = grep_check_id(&buf[1]) ? isif : !isif;
733 grep_stack[++grep_sp] = ST_LD(grep_writing, !isif);
734 grep_writing = isif;
735 } else {
736 grep_stack[++grep_sp] = ST_LD(0, 0);
737 /* grep_writing = 0; */
739 grep_show_wstack("push");
740 break;
741 case ':': /* else */
742 if (ST_ELSE & grep_stack[grep_sp]) {
743 Fprintf(stderr, "multiple : for same conditional at line %d.\n",
744 grep_lineno);
745 grep_errors++;
747 grep_writing = ST_OPP(grep_stack[grep_sp]);
748 grep_stack[grep_sp] |= ST_ELSE;
749 break;
750 #if defined(notyet)
751 case '(': /* start of expression */
752 #endif
753 case GREP_MAGIC: /* ^^ -> ^ */
754 return buf0;
755 default: {
756 char str[10];
758 if (isprint(buf[0])) {
759 str[0] = buf[0];
760 str[1] = '\0';
761 } else {
762 sprintf(str, "0x%02x", buf[0]);
764 Fprintf(stderr, "unknown control ^%s at line %d.\n", str,
765 grep_lineno);
766 grep_errors++;
767 } break;
769 return NULL;
772 #ifdef notyet
773 static void
774 do_grep_rewrite(buf)
775 char *buf;
777 /* no language features use this yet */
778 return;
780 #endif
782 static void grep0(FILE *, FILE *);
784 static void
785 do_grep()
787 if (!inputfp) {
788 Fprintf(stderr, "--grep requires --input\n");
790 if (!outputfp) {
791 Fprintf(stderr, "--grep requires --output\n");
793 if (!inputfp || !outputfp) {
794 exit(EXIT_FAILURE);
797 grep0(inputfp, outputfp);
800 static void
801 grep0(inputfp0, outputfp0)
802 FILE *inputfp0;
803 FILE *outputfp0;
805 char buf[16384]; /* looong, just in case */
807 while (!feof(inputfp0) && !ferror(inputfp0)) {
808 char *tmp;
809 char *buf1;
811 if (fgets(buf, sizeof(buf), inputfp0) == 0)
812 break;
813 if ((tmp = strchr(buf, '\n')))
814 *tmp = '\0';
815 grep_lineno++;
816 if (grep_trace) {
817 Fprintf(outputfp0, "%04d %c >%s\n", grep_lineno,
818 grep_writing ? ' ' : '#', buf);
821 if (buf[0] == GREP_MAGIC) {
822 buf1 = do_grep_control(&buf[1]);
823 if (!buf1)
824 continue;
825 } else {
826 buf1 = buf;
828 #ifdef notyet
829 if (grep_rewrite)
830 do_grep_rewrite(buf1);
831 #endif
832 if (grep_writing)
833 Fprintf(outputfp0, "%s\n", buf1);
835 if (ferror(inputfp0)) {
836 Fprintf(stderr, "read error!\n");
837 exit(EXIT_FAILURE);
839 if (ferror(outputfp0)) {
840 Fprintf(stderr, "write error!\n");
841 exit(EXIT_FAILURE);
843 fclose(inputfp0);
844 fclose(outputfp0);
845 if (grep_sp) {
846 Fprintf(stderr, "%d unterminated conditional level%s\n", grep_sp,
847 grep_sp == 1 ? "" : "s");
848 grep_errors++;
850 if (grep_errors) {
851 Fprintf(stderr, "%d error%s detected.\n", grep_errors,
852 grep_errors == 1 ? "" : "s");
853 exit(EXIT_FAILURE);
857 /* trivial text encryption routine which can't be broken with `tr' */
858 static char *
859 xcrypt(str)
860 const char *str;
861 { /* duplicated in src/hacklib.c */
862 static char buf[BUFSZ];
863 register const char *p;
864 register char *q;
865 register int bitmask;
867 for (bitmask = 1, p = str, q = buf; *p; q++) {
868 *q = *p++;
869 if (*q & (32 | 64))
870 *q ^= bitmask;
871 if ((bitmask <<= 1) >= 32)
872 bitmask = 1;
874 *q = '\0';
875 return buf;
878 #define PAD_RUMORS_TO 60
879 /* common code for do_rumors(). Return 0 on error. */
880 static unsigned long
881 read_rumors_file(file_ext, rumor_count, rumor_size, old_rumor_offset)
882 const char *file_ext;
883 int *rumor_count;
884 long *rumor_size;
885 unsigned long old_rumor_offset;
887 char infile[600];
888 char *line;
889 unsigned long rumor_offset;
891 Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
892 Strcat(infile, file_ext);
893 if (!(ifp = fopen(infile, RDTMODE))) {
894 perror(infile);
895 return 0L;
898 /* copy the rumors */
899 while ((line = fgetline(ifp)) != 0) {
900 #ifdef PAD_RUMORS_TO
901 /* rumor selection is accomplished by seeking to a random
902 position in the file, advancing to newline, and taking
903 the next line; therefore, rumors which follow long-line
904 rumors are most likely to be chosen and rumors which
905 follow short-line rumors are least likely to be chosen;
906 we ameliorate the latter by padding the shortest lines,
907 increasing the chance of the random seek landing in them */
908 int len = (int) strlen(line);
910 if (len <= PAD_RUMORS_TO) {
911 char *base = index(line, '\n');
912 /* this is only safe because fgetline() overallocates */
913 while (len++ < PAD_RUMORS_TO) {
914 *base++ = '_';
916 *base++ = '\n';
917 *base = '\0';
919 #endif
920 (*rumor_count)++;
921 #if 0
922 /*[if we forced binary output, this would be sufficient]*/
923 *rumor_size += strlen(line); /* includes newline */
924 #endif
925 (void) fputs(xcrypt(line), tfp);
926 free(line);
928 /* record the current position; next rumors section will start here */
929 rumor_offset = (unsigned long) ftell(tfp);
930 Fclose(ifp); /* all done with rumors.file_ext */
932 /* the calculated value for *_rumor_count assumes that
933 a single-byte line terminator is in use; for platforms
934 which use two byte CR+LF, we need to override that value
935 [it's much simpler to do so unconditionally, rendering
936 the loop's accumulation above obsolete] */
937 *rumor_size = (long) (rumor_offset - old_rumor_offset);
938 return rumor_offset;
941 void
942 do_rnd_access_file(fname)
943 const char *fname;
945 char *line;
947 Sprintf(filename, DATA_IN_TEMPLATE, fname);
948 Strcat(filename, ".txt");
949 if (!(ifp = fopen(filename, RDTMODE))) {
950 perror(filename);
951 exit(EXIT_FAILURE);
953 filename[0] = '\0';
954 #ifdef FILE_PREFIX
955 Strcat(filename, file_prefix);
956 #endif
957 Sprintf(eos(filename), DATA_TEMPLATE, fname);
958 if (!(ofp = fopen(filename, WRTMODE))) {
959 perror(filename);
960 exit(EXIT_FAILURE);
962 Fprintf(ofp, "%s", Dont_Edit_Data);
964 tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE);
965 grep0(ifp, tfp);
966 ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE);
968 while ((line = fgetline(ifp)) != 0) {
969 if (line[0] != '#' && line[0] != '\n')
970 (void) fputs(xcrypt(line), ofp);
971 free(line);
973 Fclose(ifp);
974 Fclose(ofp);
976 delete_file(DATA_TEMPLATE, "grep.tmp");
977 return;
980 void
981 do_rumors()
983 char *line;
984 static const char rumors_header[] =
985 "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n";
986 char tempfile[600];
987 int true_rumor_count, false_rumor_count;
988 long true_rumor_size, false_rumor_size;
989 unsigned long true_rumor_offset, false_rumor_offset, eof_offset;
991 Sprintf(tempfile, DATA_TEMPLATE, "rumors.tmp");
992 filename[0] = '\0';
993 #ifdef FILE_PREFIX
994 Strcat(filename, file_prefix);
995 #endif
996 Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE);
997 if (!(ofp = fopen(filename, WRTMODE))) {
998 perror(filename);
999 exit(EXIT_FAILURE);
1001 if (!(tfp = fopen(tempfile, WRTMODE))) {
1002 perror(tempfile);
1003 Fclose(ofp);
1004 exit(EXIT_FAILURE);
1007 true_rumor_count = false_rumor_count = 0;
1008 true_rumor_size = false_rumor_size = 0L;
1009 true_rumor_offset = false_rumor_offset = eof_offset = 0L;
1011 /* output a dummy header record; we'll replace it in final output */
1012 Fprintf(tfp, rumors_header, Dont_Edit_Data, true_rumor_count,
1013 true_rumor_size, true_rumor_offset, false_rumor_count,
1014 false_rumor_size, false_rumor_offset, eof_offset);
1015 /* record the current position; true rumors will start here */
1016 true_rumor_offset = ftell(tfp);
1018 false_rumor_offset = read_rumors_file(
1019 ".tru", &true_rumor_count, &true_rumor_size, true_rumor_offset);
1020 if (!false_rumor_offset)
1021 goto rumors_failure;
1023 eof_offset = read_rumors_file(".fal", &false_rumor_count,
1024 &false_rumor_size, false_rumor_offset);
1025 if (!eof_offset)
1026 goto rumors_failure;
1028 /* get ready to transfer the contents of temp file to output file */
1029 line = malloc(256);
1030 Sprintf(line, "rewind of \"%s\"", tempfile);
1031 if (rewind(tfp) != 0) {
1032 perror(line);
1033 free(line);
1034 goto rumors_failure;
1036 free(line);
1038 /* output the header record */
1039 Fprintf(ofp, rumors_header, Dont_Edit_Data, true_rumor_count,
1040 true_rumor_size, true_rumor_offset, false_rumor_count,
1041 false_rumor_size, false_rumor_offset, eof_offset);
1042 /* skip the temp file's dummy header */
1043 if (!(line = fgetline(tfp))) { /* "Don't Edit" */
1044 perror(tempfile);
1045 goto rumors_failure;
1047 free(line);
1048 if (!(line = fgetline(tfp))) { /* count,size,offset */
1049 perror(tempfile);
1050 goto rumors_failure;
1052 free(line);
1053 /* copy the rest of the temp file into the final output file */
1054 while ((line = fgetline(tfp)) != 0) {
1055 (void) fputs(line, ofp);
1056 free(line);
1058 /* all done; delete temp file */
1059 Fclose(tfp);
1060 Unlink(tempfile);
1061 Fclose(ofp);
1062 return;
1064 rumors_failure:
1065 Fclose(ofp);
1066 Unlink(filename); /* kill empty or incomplete output file */
1067 Fclose(tfp);
1068 Unlink(tempfile); /* and temporary file */
1069 exit(EXIT_FAILURE);
1073 * Use this to explicitly mask out features during version checks.
1075 * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features
1076 * that the port/plaform which wrote the savefile was capable of
1077 * dealing with. Don't reject a savefile just because the port
1078 * reading the savefile doesn't match on all/some of them.
1079 * The actual compression features used to produce the savefile are
1080 * recorded in the savefile_info structure immediately following the
1081 * version_info, and that is what needs to be checked against the
1082 * feature set of the port that is reading the savefile back in.
1083 * That check is done in src/restore.c now.
1086 #define IGNORED_FEATURES \
1087 (0L | (1L << 19) /* SCORE_ON_BOTL */ \
1088 | (1L << 27) /* ZEROCOMP */ \
1089 | (1L << 28) /* RLECOMP */ \
1092 static void
1093 make_version()
1095 register int i;
1098 * integer version number
1100 version.incarnation = ((unsigned long) VERSION_MAJOR << 24)
1101 | ((unsigned long) VERSION_MINOR << 16)
1102 | ((unsigned long) PATCHLEVEL << 8)
1103 | ((unsigned long) EDITLEVEL);
1105 * encoded feature list
1106 * Note: if any of these magic numbers are changed or reassigned,
1107 * EDITLEVEL in patchlevel.h should be incremented at the same time.
1108 * The actual values have no special meaning, and the category
1109 * groupings are just for convenience.
1111 version.feature_set = (unsigned long) (0L
1112 /* levels and/or topology (0..4) */
1113 /* monsters (5..9) */
1114 #ifdef MAIL
1115 | (1L << 6)
1116 #endif
1117 /* objects (10..14) */
1118 /* flag bits and/or other global variables (15..26) */
1119 #ifdef TEXTCOLOR
1120 | (1L << 17)
1121 #endif
1122 #ifdef INSURANCE
1123 | (1L << 18)
1124 #endif
1125 #ifdef SCORE_ON_BOTL
1126 | (1L << 19)
1127 #endif
1128 /* data format (27..31)
1129 * External compression methods such as COMPRESS and ZLIB_COMP
1130 * do not affect the contents and are thus excluded from here */
1131 #ifdef ZEROCOMP
1132 | (1L << 27)
1133 #endif
1134 #ifdef RLECOMP
1135 | (1L << 28)
1136 #endif
1139 * Value used for object & monster sanity check.
1140 * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
1142 for (i = 1; artifact_names[i]; i++)
1143 continue;
1144 version.entity_count = (unsigned long) (i - 1);
1145 for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++)
1146 continue;
1147 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
1148 for (i = 0; mons[i].mlet; i++)
1149 continue;
1150 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
1152 * Value used for compiler (word size/field alignment/padding) check.
1154 version.struct_sizes1 =
1155 (((unsigned long) sizeof(struct context_info) << 24)
1156 | ((unsigned long) sizeof(struct obj) << 17)
1157 | ((unsigned long) sizeof(struct monst) << 10)
1158 | ((unsigned long) sizeof(struct you)));
1159 version.struct_sizes2 = (((unsigned long) sizeof(struct flag) << 10) |
1160 /* free bits in here */
1161 #ifdef SYSFLAGS
1162 ((unsigned long) sizeof(struct sysflag)));
1163 #else
1164 ((unsigned long) 0L));
1165 #endif
1166 return;
1169 static char *
1170 version_string(outbuf, delim)
1171 char *outbuf;
1172 const char *delim;
1174 Sprintf(outbuf, "%d%s%d%s%d", VERSION_MAJOR, delim, VERSION_MINOR, delim,
1175 PATCHLEVEL);
1176 #ifdef BETA
1177 Sprintf(eos(outbuf), "-%d", EDITLEVEL);
1178 #endif
1179 return outbuf;
1182 static char *
1183 version_id_string(outbuf, build_date)
1184 char *outbuf;
1185 const char *build_date;
1187 char subbuf[64], versbuf[64];
1189 subbuf[0] = '\0';
1190 #ifdef PORT_SUB_ID
1191 subbuf[0] = ' ';
1192 Strcpy(&subbuf[1], PORT_SUB_ID);
1193 #endif
1194 #ifdef BETA
1195 Strcat(subbuf, " Beta");
1196 #endif
1198 Sprintf(outbuf, "%s NetHack%s Version %s - last build %s.", PORT_ID,
1199 subbuf, version_string(versbuf, "."), build_date);
1200 return outbuf;
1203 static char *
1204 bannerc_string(outbuf, build_date)
1205 char *outbuf;
1206 const char *build_date;
1208 char subbuf[64], versbuf[64];
1210 subbuf[0] = '\0';
1211 #ifdef PORT_SUB_ID
1212 subbuf[0] = ' ';
1213 Strcpy(&subbuf[1], PORT_SUB_ID);
1214 #endif
1215 #ifdef BETA
1216 Strcat(subbuf, " Beta");
1217 #endif
1219 Sprintf(outbuf, " Version %s %s%s, built %s.",
1220 version_string(versbuf, "."), PORT_ID, subbuf, &build_date[4]);
1221 #if 0
1222 Sprintf(outbuf, "%s NetHack%s %s Copyright 1985-%s (built %s)",
1223 PORT_ID, subbuf, version_string(versbuf,"."), RELEASE_YEAR,
1224 &build_date[4]);
1225 #endif
1226 return outbuf;
1229 void
1230 do_date()
1232 #ifdef KR1ED
1233 long clocktim = 0;
1234 #else
1235 time_t clocktim = 0;
1236 #endif
1237 char *c, cbuf[60], buf[BUFSZ];
1238 const char *ul_sfx;
1240 /* before creating date.h, make sure that xxx_GRAPHICS and
1241 DEFAULT_WINDOW_SYS have been set up in a viable fashion */
1242 windowing_sanity();
1244 filename[0] = '\0';
1245 #ifdef FILE_PREFIX
1246 Strcat(filename, file_prefix);
1247 #endif
1248 Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE);
1249 if (!(ofp = fopen(filename, WRTMODE))) {
1250 perror(filename);
1251 exit(EXIT_FAILURE);
1253 /* NB: We've moved on from SCCS, but this way this line
1254 * won't get clobbered when downstream projects import
1255 * this file into something more modern. */
1256 Fprintf(ofp, "%s", Dont_Edit_Code);
1258 (void) time(&clocktim);
1259 Strcpy(cbuf, ctime(&clocktim));
1261 for (c = cbuf; *c; c++)
1262 if (*c == '\n')
1263 break;
1264 *c = '\0'; /* strip off the '\n' */
1265 Fprintf(ofp, "#define BUILD_DATE \"%s\"\n", cbuf);
1266 Fprintf(ofp, "#define BUILD_TIME (%ldL)\n", (long) clocktim);
1267 Fprintf(ofp, "\n");
1268 #ifdef NHSTDC
1269 ul_sfx = "UL";
1270 #else
1271 ul_sfx = "L";
1272 #endif
1273 Fprintf(ofp, "#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation,
1274 ul_sfx);
1275 Fprintf(ofp, "#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set,
1276 ul_sfx);
1277 #ifdef IGNORED_FEATURES
1278 Fprintf(ofp, "#define IGNORED_FEATURES 0x%08lx%s\n",
1279 (unsigned long) IGNORED_FEATURES, ul_sfx);
1280 #endif
1281 Fprintf(ofp, "#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count,
1282 ul_sfx);
1283 Fprintf(ofp, "#define VERSION_SANITY2 0x%08lx%s\n", version.struct_sizes1,
1284 ul_sfx);
1285 Fprintf(ofp, "#define VERSION_SANITY3 0x%08lx%s\n", version.struct_sizes2,
1286 ul_sfx);
1287 Fprintf(ofp, "\n");
1288 Fprintf(ofp, "#define VERSION_STRING \"%s\"\n", version_string(buf, "."));
1289 Fprintf(ofp, "#define VERSION_ID \\\n \"%s\"\n",
1290 version_id_string(buf, cbuf));
1291 Fprintf(ofp, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n",
1292 bannerc_string(buf, cbuf));
1293 Fprintf(ofp, "\n");
1294 #ifdef AMIGA
1296 struct tm *tm = localtime((time_t *) &clocktim);
1297 Fprintf(ofp, "#define AMIGA_VERSION_STRING ");
1298 Fprintf(ofp, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
1299 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, tm->tm_mday,
1300 tm->tm_mon + 1, tm->tm_year + 1900);
1302 #endif
1303 Fclose(ofp);
1304 return;
1307 static char save_bones_compat_buf[BUFSZ];
1309 static void
1310 build_savebones_compat_string()
1312 #ifdef VERSION_COMPATIBILITY
1313 unsigned long uver = VERSION_COMPATIBILITY;
1314 #endif
1315 Strcpy(save_bones_compat_buf,
1316 "save and bones files accepted from version");
1317 #ifdef VERSION_COMPATIBILITY
1318 Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d",
1319 ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16),
1320 ((uver & 0x0000FF00L) >> 8), VERSION_MAJOR, VERSION_MINOR,
1321 PATCHLEVEL);
1322 #else
1323 Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only", VERSION_MAJOR,
1324 VERSION_MINOR, PATCHLEVEL);
1325 #endif
1328 static const char *build_opts[] = {
1329 #ifdef AMIGA_WBENCH
1330 "Amiga WorkBench support",
1331 #endif
1332 #ifdef ANSI_DEFAULT
1333 "ANSI default terminal",
1334 #endif
1335 #ifdef TEXTCOLOR
1336 "color",
1337 #endif
1338 #ifdef TTY_TILES_ESCCODES
1339 "console escape codes for tile hinting",
1340 #endif
1341 #ifdef COM_COMPL
1342 "command line completion",
1343 #endif
1344 #ifdef LIFE
1345 "Conway's Game of Life",
1346 #endif
1347 #ifdef COMPRESS
1348 "data file compression",
1349 #endif
1350 #ifdef ZLIB_COMP
1351 "ZLIB data file compression",
1352 #endif
1353 #ifdef DLB
1354 "data librarian",
1355 #endif
1356 #ifdef MFLOPPY
1357 "floppy drive support",
1358 #endif
1359 #ifdef INSURANCE
1360 "insurance files for recovering from crashes",
1361 #endif
1362 #ifdef HOLD_LOCKFILE_OPEN
1363 "exclusive lock on level 0 file",
1364 #endif
1365 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
1366 "external program as a message handler",
1367 #endif
1368 #ifdef LOGFILE
1369 "log file",
1370 #endif
1371 #ifdef MAIL
1372 "mail daemon",
1373 #endif
1374 #ifdef GNUDOS
1375 "MSDOS protected mode",
1376 #endif
1377 #ifdef NEWS
1378 "news file",
1379 #endif
1380 #ifdef OVERLAY
1381 #ifdef MOVERLAY
1382 "MOVE overlays",
1383 #else
1384 #ifdef VROOMM
1385 "VROOMM overlays",
1386 #else
1387 "overlays",
1388 #endif
1389 #endif
1390 #endif
1391 #ifdef SELECTSAVED
1392 "restore saved games via menu",
1393 #endif
1394 #ifdef SCORE_ON_BOTL
1395 "score on status line",
1396 #endif
1397 #ifdef CLIPPING
1398 "screen clipping",
1399 #endif
1400 #ifdef NO_TERMS
1401 #ifdef MAC
1402 "screen control via mactty",
1403 #endif
1404 #ifdef SCREEN_BIOS
1405 "screen control via BIOS",
1406 #endif
1407 #ifdef SCREEN_DJGPPFAST
1408 "screen control via DJGPP fast",
1409 #endif
1410 #ifdef SCREEN_VGA
1411 "screen control via VGA graphics",
1412 #endif
1413 #ifdef WIN32CON
1414 "screen control via WIN32 console I/O",
1415 #endif
1416 #endif
1417 #ifdef SHELL
1418 "shell command",
1419 #endif
1420 #ifdef STATUS_VIA_WINDOWPORT
1421 # ifdef STATUS_HILITES
1422 "status via windowport with highlighting",
1423 # else
1424 "status via windowport without highlighting",
1425 # endif
1426 #else
1427 "traditional status display",
1428 #endif
1429 #ifdef SUSPEND
1430 "suspend command",
1431 #endif
1432 #ifdef TERMINFO
1433 "terminal info library",
1434 #else
1435 #if defined(TERMLIB) \
1436 || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
1437 "terminal capability library",
1438 #endif
1439 #endif
1440 #ifdef TIMED_DELAY
1441 "timed wait for display effects",
1442 #endif
1443 #ifdef USER_SOUNDS
1444 "user sounds",
1445 #endif
1446 #ifdef PREFIXES_IN_USE
1447 "variable playground",
1448 #endif
1449 #ifdef VISION_TABLES
1450 "vision tables",
1451 #endif
1452 #ifdef ZEROCOMP
1453 "zero-compressed save files",
1454 #endif
1455 #ifdef RLECOMP
1456 "run-length compression of map in save files",
1457 #endif
1458 #ifdef SYSCF
1459 "system configuration at run-time",
1460 #endif
1461 save_bones_compat_buf, "and basic NetHack features"
1464 struct win_info {
1465 const char *id, /* DEFAULT_WINDOW_SYS string */
1466 *name; /* description, often same as id */
1468 static struct win_info window_opts[] = {
1469 #ifdef TTY_GRAPHICS
1470 { "tty", "traditional tty-based graphics" },
1471 #endif
1472 #ifdef X11_GRAPHICS
1473 { "X11", "X11" },
1474 #endif
1475 #ifdef QT_GRAPHICS
1476 { "Qt", "Qt" },
1477 #endif
1478 #ifdef GNOME_GRAPHICS
1479 { "Gnome", "Gnome" },
1480 #endif
1481 #ifdef MAC
1482 { "mac", "Mac" },
1483 #endif
1484 #ifdef AMIGA_INTUITION
1485 { "amii", "Amiga Intuition" },
1486 #endif
1487 #ifdef GEM_GRAPHICS
1488 { "Gem", "Gem" },
1489 #endif
1490 #ifdef MSWIN_GRAPHICS
1491 { "mswin", "mswin" },
1492 #endif
1493 #ifdef BEOS_GRAPHICS
1494 { "BeOS", "BeOS InterfaceKit" },
1495 #endif
1496 { 0, 0 }
1499 static void
1500 windowing_sanity()
1502 #ifndef DEFAULT_WINDOW_SYS
1503 /* pre-standard compilers didn't support #error; wait til run-time */
1504 Fprintf(stderr,
1505 "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n");
1506 exit(EXIT_FAILURE);
1507 /*NOTREACHED*/
1509 /* put in a dummy value so that do_options() will compile and makedefs
1510 will build, otherwise the message above won't ever get delivered */
1511 #define DEFAULT_WINDOW_SYS "<undefined>"
1512 #else /*DEFAULT_WINDOW_SYS*/
1514 if (!window_opts[0].id) {
1515 Fprintf(stderr, "Configuration error: no windowing systems "
1516 "(TTY_GRAPHICS, &c) enabled.\n");
1517 exit(EXIT_FAILURE);
1521 int i;
1523 for (i = 0; window_opts[i].id; ++i)
1524 if (!strcmp(window_opts[i].id, DEFAULT_WINDOW_SYS))
1525 break;
1526 if (!window_opts[i]
1527 .id) { /* went through whole list without a match */
1528 Fprintf(stderr, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n",
1529 DEFAULT_WINDOW_SYS);
1530 Fprintf(stderr,
1531 " does not match any enabled windowing system (%s%s).\n",
1532 window_opts[0].id, window_opts[1].id ? ", &c" : "");
1533 exit(EXIT_FAILURE);
1536 #endif /*DEFAULT_WINDOW_SYS*/
1539 void
1540 do_options()
1542 static const char indent[] = " ";
1543 const char *str, *sep;
1544 char *word, buf[BUFSZ];
1545 int i, length, winsyscnt;
1547 windowing_sanity();
1549 filename[0] = '\0';
1550 #ifdef FILE_PREFIX
1551 Strcat(filename, file_prefix);
1552 #endif
1553 Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE);
1554 if (!(ofp = fopen(filename, WRTMODE))) {
1555 perror(filename);
1556 exit(EXIT_FAILURE);
1559 build_savebones_compat_string();
1560 Fprintf(ofp,
1561 #ifdef BETA
1562 "\n NetHack version %d.%d.%d [beta]\n",
1563 #else
1564 "\n NetHack version %d.%d.%d\n",
1565 #endif
1566 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
1568 Fprintf(ofp, "\nOptions compiled into this edition:\n");
1569 length = COLNO + 1; /* force 1st item onto new line */
1570 for (i = 0; i < SIZE(build_opts); i++) {
1571 str = strcpy(buf, build_opts[i]);
1572 while (*str) {
1573 word = index(str, ' ');
1574 if (word)
1575 *word = '\0';
1576 if (length + strlen(str) > COLNO - 5)
1577 Fprintf(ofp, "\n%s", indent), length = strlen(indent);
1578 else
1579 Fprintf(ofp, " "), length++;
1580 Fprintf(ofp, "%s", str), length += strlen(str);
1581 str += strlen(str) + (word ? 1 : 0);
1583 Fprintf(ofp, (i < SIZE(build_opts) - 1) ? "," : "."), length++;
1586 winsyscnt = SIZE(window_opts) - 1;
1587 Fprintf(ofp, "\n\nSupported windowing system%s:\n",
1588 (winsyscnt > 1) ? "s" : "");
1589 length = COLNO + 1; /* force 1st item onto new line */
1590 for (i = 0; i < winsyscnt; i++) {
1591 str = window_opts[i].name;
1592 if (length + strlen(str) > COLNO - 5)
1593 Fprintf(ofp, "\n%s", indent), length = strlen(indent);
1594 else
1595 Fprintf(ofp, " "), length++;
1596 Fprintf(ofp, "%s", str), length += strlen(str);
1597 sep = (winsyscnt == 1)
1598 ? "."
1599 : (winsyscnt == 2)
1600 ? ((i == 0) ? " and" : "")
1601 : (i < winsyscnt - 2)
1602 ? ","
1603 : ((i == winsyscnt - 2) ? ", and" : "");
1604 Fprintf(ofp, "%s", sep), length += strlen(sep);
1606 if (winsyscnt > 1)
1607 Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS);
1608 Fprintf(ofp, "\n\n");
1610 Fclose(ofp);
1611 return;
1614 /* routine to decide whether to discard something from data.base */
1615 static boolean
1616 d_filter(line)
1617 char *line;
1619 if (*line == '#')
1620 return TRUE; /* ignore comment lines */
1621 return FALSE;
1626 New format (v3.1) of 'data' file which allows much faster lookups [pr]
1627 "do not edit" first record is a comment line
1628 01234567 hexadecimal formatted offset to text area
1629 name-a first name of interest
1630 123,4 offset to name's text, and number of lines for it
1631 name-b next name of interest
1632 name-c multiple names which share same description also
1633 456,7 share a single offset,count line
1634 . sentinel to mark end of names
1635 789,0 dummy record containing offset, count of EOF
1636 text-a 4 lines of descriptive text for name-a
1637 text-a at file position 0x01234567L + 123L
1638 text-a
1639 text-a
1640 text-b/text-c 7 lines of text for names-b and -c
1641 text-b/text-c at fseek(0x01234567L + 456L)
1646 void
1647 do_data()
1649 char infile[60], tempfile[60];
1650 boolean ok;
1651 long txt_offset;
1652 int entry_cnt, line_cnt;
1653 char *line;
1655 Sprintf(tempfile, DATA_TEMPLATE, "database.tmp");
1656 filename[0] = '\0';
1657 #ifdef FILE_PREFIX
1658 Strcat(filename, file_prefix);
1659 #endif
1660 Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE);
1661 Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE);
1662 #ifdef SHORT_FILENAMES
1663 Strcat(infile, ".bas");
1664 #else
1665 Strcat(infile, ".base");
1666 #endif
1667 if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */
1668 perror(infile);
1669 exit(EXIT_FAILURE);
1671 if (!(ofp = fopen(filename, WRTMODE))) { /* data */
1672 perror(filename);
1673 Fclose(ifp);
1674 exit(EXIT_FAILURE);
1676 if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */
1677 perror(tempfile);
1678 Fclose(ifp);
1679 Fclose(ofp);
1680 Unlink(filename);
1681 exit(EXIT_FAILURE);
1684 /* output a dummy header record; we'll rewind and overwrite it later */
1685 Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L);
1687 entry_cnt = line_cnt = 0;
1688 /* read through the input file and split it into two sections */
1689 while ((line = fgetline(ifp)) != 0) {
1690 if (d_filter(line)) {
1691 free(line);
1692 continue;
1694 if (*line > ' ') { /* got an entry name */
1695 /* first finish previous entry */
1696 if (line_cnt)
1697 Fprintf(ofp, "%d\n", line_cnt), line_cnt = 0;
1698 /* output the entry name */
1699 (void) fputs(line, ofp);
1700 entry_cnt++; /* update number of entries */
1701 } else if (entry_cnt) { /* got some descriptive text */
1702 /* update previous entry with current text offset */
1703 if (!line_cnt)
1704 Fprintf(ofp, "%ld,", ftell(tfp));
1705 /* save the text line in the scratch file */
1706 (void) fputs(line, tfp);
1707 line_cnt++; /* update line counter */
1709 free(line);
1711 /* output an end marker and then record the current position */
1712 if (line_cnt)
1713 Fprintf(ofp, "%d\n", line_cnt);
1714 Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0);
1715 txt_offset = ftell(ofp);
1716 Fclose(ifp); /* all done with original input file */
1718 /* reprocess the scratch file; 1st format an error msg, just in case */
1719 line = malloc(256);
1720 Sprintf(line, "rewind of \"%s\"", tempfile);
1721 if (rewind(tfp) != 0)
1722 goto dead_data;
1723 free(line);
1724 /* copy all lines of text from the scratch file into the output file */
1725 while ((line = fgetline(tfp)) != 0) {
1726 (void) fputs(line, ofp);
1727 free(line);
1730 /* finished with scratch file */
1731 Fclose(tfp);
1732 Unlink(tempfile); /* remove it */
1734 /* update the first record of the output file; prepare error msg 1st */
1735 line = malloc(256);
1736 Sprintf(line, "rewind of \"%s\"", filename);
1737 ok = (rewind(ofp) == 0);
1738 if (ok) {
1739 Sprintf(line, "header rewrite of \"%s\"", filename);
1740 ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data,
1741 (unsigned long) txt_offset) >= 0);
1743 if (!ok) {
1744 dead_data:
1745 perror(line); /* report the problem */
1746 free(line);
1747 /* close and kill the aborted output file, then give up */
1748 Fclose(ofp);
1749 Unlink(filename);
1750 exit(EXIT_FAILURE);
1752 free(line);
1754 /* all done */
1755 Fclose(ofp);
1757 return;
1760 /* routine to decide whether to discard something from oracles.txt */
1761 static boolean
1762 h_filter(line)
1763 char *line;
1765 static boolean skip = FALSE;
1766 char *tag;
1768 SpinCursor(3);
1770 if (*line == '#')
1771 return TRUE; /* ignore comment lines */
1773 tag = malloc(strlen(line));
1774 if (sscanf(line, "----- %s", tag) == 1) {
1775 skip = FALSE;
1776 } else if (skip && !strncmp(line, "-----", 5))
1777 skip = FALSE;
1778 free(tag);
1779 return skip;
1782 static const char *special_oracle[] = {
1783 "\"...it is rather disconcerting to be confronted with the",
1784 "following theorem from [Baker, Gill, and Solovay, 1975].", "",
1785 "Theorem 7.18 There exist recursive languages A and B such that",
1786 " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "",
1787 "This provides impressive evidence that the techniques that are",
1788 "currently available will not suffice for proving that P != NP or "
1789 " ",
1790 "that P == NP.\" [Garey and Johnson, p. 185.]"
1794 The oracle file consists of a "do not edit" comment, a decimal count N
1795 and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
1796 records, separated by "---" lines. The first oracle is a special case.
1797 The input data contains just those multi-line records, separated by
1798 "-----" lines.
1801 void
1802 do_oracles()
1804 char infile[60], tempfile[60];
1805 boolean in_oracle, ok;
1806 long fpos;
1807 unsigned long txt_offset, offset;
1808 int oracle_cnt;
1809 register int i;
1810 char *line;
1812 Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp");
1813 filename[0] = '\0';
1814 #ifdef FILE_PREFIX
1815 Strcat(filename, file_prefix);
1816 #endif
1817 Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE);
1818 Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE);
1819 Strcat(infile, ".txt");
1820 if (!(ifp = fopen(infile, RDTMODE))) {
1821 perror(infile);
1822 exit(EXIT_FAILURE);
1824 if (!(ofp = fopen(filename, WRTMODE))) {
1825 perror(filename);
1826 Fclose(ifp);
1827 exit(EXIT_FAILURE);
1829 if (!(tfp = fopen(tempfile, WRTMODE))) { /* oracles.tmp */
1830 perror(tempfile);
1831 Fclose(ifp);
1832 Fclose(ofp);
1833 Unlink(filename);
1834 exit(EXIT_FAILURE);
1837 /* output a dummy header record; we'll rewind and overwrite it later */
1838 Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0);
1840 /* handle special oracle; it must come first */
1841 (void) fputs("---\n", tfp);
1842 offset = (unsigned long) ftell(tfp);
1843 Fprintf(ofp, "%05lx\n", offset); /* start pos of special oracle */
1844 for (i = 0; i < SIZE(special_oracle); i++) {
1845 (void) fputs(xcrypt(special_oracle[i]), tfp);
1846 (void) fputc('\n', tfp);
1848 SpinCursor(3);
1850 oracle_cnt = 1;
1851 (void) fputs("---\n", tfp);
1852 offset = (unsigned long) ftell(tfp);
1853 Fprintf(ofp, "%05lx\n", offset); /* start pos of first oracle */
1854 in_oracle = FALSE;
1856 while ((line = fgetline(ifp)) != 0) {
1857 SpinCursor(3);
1859 if (h_filter(line)) {
1860 free(line);
1861 continue;
1863 if (!strncmp(line, "-----", 5)) {
1864 if (!in_oracle) {
1865 free(line);
1866 continue;
1868 in_oracle = FALSE;
1869 oracle_cnt++;
1870 (void) fputs("---\n", tfp);
1871 offset = (unsigned long) ftell(tfp);
1872 Fprintf(ofp, "%05lx\n", offset); /* start pos of this oracle */
1873 } else {
1874 in_oracle = TRUE;
1875 (void) fputs(xcrypt(line), tfp);
1877 free(line);
1880 if (in_oracle) { /* need to terminate last oracle */
1881 oracle_cnt++;
1882 (void) fputs("---\n", tfp);
1883 offset = (unsigned long) ftell(tfp);
1884 Fprintf(ofp, "%05lx\n", offset); /* eof position */
1887 /* record the current position */
1888 txt_offset = (unsigned long) ftell(ofp);
1889 Fclose(ifp); /* all done with original input file */
1891 /* reprocess the scratch file; 1st format an error msg, just in case */
1892 line = malloc(256);
1893 Sprintf(line, "rewind of \"%s\"", tempfile);
1894 if (rewind(tfp) != 0)
1895 goto dead_data;
1896 free(line);
1897 /* copy all lines of text from the scratch file into the output file */
1898 while ((line = fgetline(tfp)) != 0) {
1899 (void) fputs(line, ofp);
1900 free(line);
1903 /* finished with scratch file */
1904 Fclose(tfp);
1905 Unlink(tempfile); /* remove it */
1907 /* update the first record of the output file; prepare error msg 1st */
1908 line = malloc(256);
1909 Sprintf(line, "rewind of \"%s\"", filename);
1910 ok = (rewind(ofp) == 0);
1911 if (ok) {
1912 Sprintf(line, "header rewrite of \"%s\"", filename);
1913 ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >= 0);
1915 if (ok) {
1916 Sprintf(line, "data rewrite of \"%s\"", filename);
1917 for (i = 0; i <= oracle_cnt; i++) {
1918 #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */
1919 if (!(ok = (fflush(ofp) == 0)))
1920 break;
1921 #endif
1922 if (!(ok = (fpos = ftell(ofp)) >= 0))
1923 break;
1924 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0)))
1925 break;
1926 if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1)))
1927 break;
1928 #ifdef MAC
1929 #ifdef __MWERKS__
1931 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
1932 (ANSI C Libraries) needs this rewind or else the fprintf
1933 stops working. This may also be true for CW11, but has
1934 never been checked.
1936 rewind(ofp);
1937 #endif
1938 #endif
1939 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0)))
1940 break;
1941 offset += txt_offset;
1942 if (!(ok = (fprintf(ofp, "%05lx\n", offset) >= 0)))
1943 break;
1946 if (!ok) {
1947 dead_data:
1948 perror(line); /* report the problem */
1949 free(line);
1950 /* close and kill the aborted output file, then give up */
1951 Fclose(ofp);
1952 Unlink(filename);
1953 exit(EXIT_FAILURE);
1955 free(line);
1957 /* all done */
1958 Fclose(ofp);
1960 return;
1963 void
1964 do_dungeon()
1966 int rcnt = 0;
1967 char *line;
1969 Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE);
1970 if (!(ifp = fopen(filename, RDTMODE))) {
1971 perror(filename);
1972 exit(EXIT_FAILURE);
1974 filename[0] = '\0';
1975 #ifdef FILE_PREFIX
1976 Strcat(filename, file_prefix);
1977 #endif
1978 Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE);
1979 if (!(ofp = fopen(filename, WRTMODE))) {
1980 perror(filename);
1981 exit(EXIT_FAILURE);
1983 Fprintf(ofp, "%s", Dont_Edit_Data);
1985 tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE);
1986 grep0(ifp, tfp);
1987 ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE);
1989 while ((line = fgetline(ifp)) != 0) {
1990 SpinCursor(3);
1992 rcnt++;
1993 if (line[0] == '#') {
1994 free(line);
1995 continue; /* discard comments */
1997 (void) fputs(line, ofp);
1998 free(line);
2000 Fclose(ifp);
2001 Fclose(ofp);
2003 delete_file(DATA_TEMPLATE, "grep.tmp");
2004 return;
2007 static boolean
2008 ranged_attk(ptr) /* returns TRUE if monster can attack at range */
2009 register struct permonst *ptr;
2011 register int i, j;
2012 register int atk_mask = (1 << AT_BREA) | (1 << AT_SPIT) | (1 << AT_GAZE);
2014 for (i = 0; i < NATTK; i++) {
2015 if ((j = ptr->mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1 << j)))
2016 return TRUE;
2019 return FALSE;
2022 /* This routine is designed to return an integer value which represents
2023 * an approximation of monster strength. It uses a similar method of
2024 * determination as "experience()" to arrive at the strength.
2026 static int
2027 mstrength(ptr)
2028 struct permonst *ptr;
2030 int i, tmp2, n, tmp = ptr->mlevel;
2032 if (tmp > 49) /* special fixed hp monster */
2033 tmp = 2 * (tmp - 6) / 4;
2035 /* For creation in groups */
2036 n = (!!(ptr->geno & G_SGROUP));
2037 n += (!!(ptr->geno & G_LGROUP)) << 1;
2039 /* For ranged attacks */
2040 if (ranged_attk(ptr))
2041 n++;
2043 /* For higher ac values */
2044 n += (ptr->ac < 4);
2045 n += (ptr->ac < 0);
2047 /* For very fast monsters */
2048 n += (ptr->mmove >= 18);
2050 /* For each attack and "special" attack */
2051 for (i = 0; i < NATTK; i++) {
2052 tmp2 = ptr->mattk[i].aatyp;
2053 n += (tmp2 > 0);
2054 n += (tmp2 == AT_MAGC);
2055 n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG));
2058 /* For each "special" damage type */
2059 for (i = 0; i < NATTK; i++) {
2060 tmp2 = ptr->mattk[i].adtyp;
2061 if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST)
2062 || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE))
2063 n += 2;
2064 else if (strcmp(ptr->mname, "grid bug"))
2065 n += (tmp2 != AD_PHYS);
2066 n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23);
2069 /* Leprechauns are special cases. They have many hit dice so they can
2070 hit and are hard to kill, but they don't really do much damage. */
2071 if (!strcmp(ptr->mname, "leprechaun"))
2072 n -= 2;
2074 /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */
2075 if (n == 0)
2076 tmp--;
2077 else if (n >= 6)
2078 tmp += (n / 2);
2079 else
2080 tmp += (n / 3 + 1);
2082 return (tmp >= 0) ? tmp : 0;
2085 void
2086 do_monstr()
2088 register struct permonst *ptr;
2089 register int i, j;
2092 * create the source file, "monstr.c"
2094 filename[0] = '\0';
2095 #ifdef FILE_PREFIX
2096 Strcat(filename, file_prefix);
2097 #endif
2098 Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C);
2099 if (!(ofp = fopen(filename, WRTMODE))) {
2100 perror(filename);
2101 exit(EXIT_FAILURE);
2103 Fprintf(ofp, "%s", Dont_Edit_Code);
2104 Fprintf(ofp, "#include \"config.h\"\n");
2105 Fprintf(ofp, "\nconst int monstr[] = {\n");
2106 for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) {
2107 SpinCursor(3);
2109 i = mstrength(ptr);
2110 Fprintf(ofp, "%2d,%c", i, (++j & 15) ? ' ' : '\n');
2112 /* might want to insert a final 0 entry here instead of just newline */
2113 Fprintf(ofp, "%s};\n", (j & 15) ? "\n" : "");
2115 Fprintf(ofp, "\nvoid NDECL(monstr_init);\n");
2116 Fprintf(ofp, "\nvoid\n");
2117 Fprintf(ofp, "monstr_init()\n");
2118 Fprintf(ofp, "{\n");
2119 Fprintf(ofp, " return;\n");
2120 Fprintf(ofp, "}\n");
2121 Fprintf(ofp, "\n/*monstr.c*/\n");
2123 Fclose(ofp);
2124 return;
2127 void
2128 do_permonst()
2130 int i;
2131 char *c, *nam;
2133 filename[0] = '\0';
2134 #ifdef FILE_PREFIX
2135 Strcat(filename, file_prefix);
2136 #endif
2137 Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE);
2138 if (!(ofp = fopen(filename, WRTMODE))) {
2139 perror(filename);
2140 exit(EXIT_FAILURE);
2142 Fprintf(ofp, "%s", Dont_Edit_Code);
2143 Fprintf(ofp, "#ifndef PM_H\n#define PM_H\n");
2145 if (strcmp(mons[0].mname, "playermon") != 0)
2146 Fprintf(ofp, "\n#define\tPM_PLAYERMON\t(-1)");
2148 for (i = 0; mons[i].mlet; i++) {
2149 SpinCursor(3);
2151 Fprintf(ofp, "\n#define\tPM_");
2152 if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].mname, "were", 4))
2153 Fprintf(ofp, "HUMAN_");
2154 for (nam = c = tmpdup(mons[i].mname); *c; c++)
2155 if (*c >= 'a' && *c <= 'z')
2156 *c -= (char) ('a' - 'A');
2157 else if (*c < 'A' || *c > 'Z')
2158 *c = '_';
2159 Fprintf(ofp, "%s\t%d", nam, i);
2161 Fprintf(ofp, "\n\n#define\tNUMMONS\t%d\n", i);
2162 Fprintf(ofp, "\n#endif /* PM_H */\n");
2163 Fclose(ofp);
2164 return;
2167 /* Start of Quest text file processing. */
2168 #include "qtext.h"
2170 static struct qthdr qt_hdr;
2171 static struct msghdr msg_hdr[N_HDR];
2172 static struct qtmsg *curr_msg;
2174 static int qt_line;
2176 static boolean in_msg;
2177 #define NO_MSG 1 /* strlen of a null line returned by fgets() */
2179 static boolean
2180 qt_comment(s)
2181 char *s;
2183 if (s[0] == '#')
2184 return TRUE;
2185 return (boolean) (!in_msg && strlen(s) == NO_MSG);
2188 static boolean
2189 qt_control(s)
2190 char *s;
2192 return (boolean) (s[0] == '%' && (s[1] == 'C' || s[1] == 'E'));
2195 static int
2196 get_hdr(code)
2197 char *code;
2199 int i;
2201 for (i = 0; i < qt_hdr.n_hdr; i++)
2202 if (!strncmp(code, qt_hdr.id[i], LEN_HDR))
2203 return ++i;
2205 return 0;
2208 static boolean
2209 new_id(code)
2210 char *code;
2212 if (qt_hdr.n_hdr >= N_HDR) {
2213 Fprintf(stderr, OUT_OF_HEADERS, qt_line);
2214 return FALSE;
2217 strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR);
2218 msg_hdr[qt_hdr.n_hdr].n_msg = 0;
2219 qt_hdr.offset[qt_hdr.n_hdr++] = 0L;
2220 return TRUE;
2223 static boolean
2224 known_msg(num, id)
2225 int num, id;
2227 int i;
2229 for (i = 0; i < msg_hdr[num].n_msg; i++)
2230 if (msg_hdr[num].qt_msg[i].msgnum == id)
2231 return TRUE;
2233 return FALSE;
2236 static void
2237 new_msg(s, num, id)
2238 char *s;
2239 int num, id;
2241 struct qtmsg *qt_msg;
2243 if (msg_hdr[num].n_msg >= N_MSG) {
2244 Fprintf(stderr, OUT_OF_MESSAGES, qt_line);
2245 } else {
2246 qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]);
2247 qt_msg->msgnum = id;
2248 qt_msg->delivery = s[2];
2249 qt_msg->offset = qt_msg->size = qt_msg->summary_size = 0L;
2251 curr_msg = qt_msg;
2255 /* check %E record for "[summary text]" that nethack can stuff into the
2256 message history buffer when delivering text via window instead of pline */
2257 static char *
2258 valid_qt_summary(s, parsing)
2259 char *s; /* end record: "%E" optionally followed by " [summary]" */
2260 boolean parsing; /* curr_msg is valid iff this is True */
2262 static char summary[BUFSZ];
2263 char *p;
2265 if (*s != '%' || *(s + 1) != 'E')
2266 return (char *) 0;
2267 if ((p = index(s, '[')) == 0)
2268 return (char *) 0;
2269 /* note: opening '[' and closing ']' will be retained in the output;
2270 anything after ']' will be discarded by putting a newline there */
2271 Strcpy(summary, p);
2273 /* have an opening bracket; summary[] holds it and all text that follows
2275 p = eos(summary);
2276 /* find closing bracket */
2277 while (p > summary && *(p - 1) != ']')
2278 --p;
2280 if (p == summary) {
2281 /* we backed up all the way to the start without finding a bracket */
2282 if (parsing) /* malformed summary */
2283 Fprintf(stderr, MAL_SUM, qt_line);
2284 } else if (p == summary + 1) {
2285 ; /* ignore empty [] */
2286 } else { /* got something */
2287 /* p points one spot past ']', usually to '\n';
2288 we need to include the \n as part of the size */
2289 if (parsing) {
2290 /* during the writing pass we won't be able to recheck
2291 delivery, so any useless summary for a pline mode
2292 message has to be carried along to the output file */
2293 if (curr_msg->delivery == 'p')
2294 Fprintf(stderr, DUMB_SUM, qt_line);
2295 /* +1 is for terminating newline */
2296 curr_msg->summary_size = (long) (p - summary) + 1L;
2297 } else {
2298 /* caller is writing rather than just parsing;
2299 force newline after the closing bracket */
2300 Strcpy(p, "\n");
2302 return summary;
2304 return (char *) 0;
2307 static void
2308 do_qt_control(s)
2309 char *s;
2311 char code[BUFSZ];
2312 int num, id = 0;
2314 if (!index(s, '\n'))
2315 Fprintf(stderr, CTRL_TRUNC, qt_line);
2317 switch (s[1]) {
2318 case 'C':
2319 if (in_msg) {
2320 Fprintf(stderr, CREC_IN_MSG, qt_line);
2321 break;
2322 } else {
2323 in_msg = TRUE;
2324 if (sscanf(&s[4], "%s %5d", code, &id) != 2) {
2325 Fprintf(stderr, UNREC_CREC, qt_line);
2326 break;
2328 num = get_hdr(code);
2329 if (!num && !new_id(code))
2330 break;
2331 num = get_hdr(code) - 1;
2332 if (known_msg(num, id))
2333 Fprintf(stderr, DUP_MSG, qt_line);
2334 else
2335 new_msg(s, num, id);
2337 break;
2339 case 'E':
2340 if (!in_msg) {
2341 Fprintf(stderr, END_NOT_IN_MSG, qt_line);
2342 } else {
2343 /* sets curr_msg->summary_size if applicable */
2344 (void) valid_qt_summary(s, TRUE);
2345 in_msg = FALSE;
2347 break;
2349 default:
2350 Fprintf(stderr, UNREC_CREC, qt_line);
2351 break;
2355 static void
2356 do_qt_text(s)
2357 char *s;
2359 if (!in_msg) {
2360 Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line);
2361 } else if (!index(s, '\n')) {
2362 Fprintf(stderr, TEXT_TRUNC, qt_line);
2365 curr_msg->size += strlen(s);
2366 return;
2369 static void
2370 adjust_qt_hdrs()
2372 int i, j;
2373 long count = 0L, hdr_offset = sizeof(int)
2374 + (sizeof(char) * LEN_HDR + sizeof(long))
2375 * qt_hdr.n_hdr;
2377 for (i = 0; i < qt_hdr.n_hdr; i++) {
2378 qt_hdr.offset[i] = hdr_offset;
2379 hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg;
2382 for (i = 0; i < qt_hdr.n_hdr; i++)
2383 for (j = 0; j < msg_hdr[i].n_msg; j++) {
2384 msg_hdr[i].qt_msg[j].offset = hdr_offset + count;
2385 count +=
2386 msg_hdr[i].qt_msg[j].size + msg_hdr[i].qt_msg[j].summary_size;
2388 return;
2391 static void
2392 put_qt_hdrs()
2394 int i;
2397 * The main header record.
2399 if (debug)
2400 Fprintf(stderr, "%ld: header info.\n", ftell(ofp));
2401 (void) fwrite((genericptr_t) & (qt_hdr.n_hdr), sizeof(int), 1, ofp);
2402 (void) fwrite((genericptr_t) & (qt_hdr.id[0][0]), sizeof(char) * LEN_HDR,
2403 qt_hdr.n_hdr, ofp);
2404 (void) fwrite((genericptr_t) & (qt_hdr.offset[0]), sizeof(long),
2405 qt_hdr.n_hdr, ofp);
2406 if (debug) {
2407 for (i = 0; i < qt_hdr.n_hdr; i++)
2408 Fprintf(stderr, "%s @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]);
2409 Fprintf(stderr, "\n");
2413 * The individual class headers.
2415 for (i = 0; i < qt_hdr.n_hdr; i++) {
2416 if (debug)
2417 Fprintf(stderr, "%ld: %s header info.\n", ftell(ofp),
2418 qt_hdr.id[i]);
2419 (void) fwrite((genericptr_t) & (msg_hdr[i].n_msg), sizeof(int), 1,
2420 ofp);
2421 (void) fwrite((genericptr_t) & (msg_hdr[i].qt_msg[0]),
2422 sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp);
2423 if (debug) {
2424 int j;
2426 for (j = 0; j < msg_hdr[i].n_msg; j++) {
2427 Fprintf(stderr, "msg %d @ %ld (%ld)",
2428 msg_hdr[i].qt_msg[j].msgnum,
2429 msg_hdr[i].qt_msg[j].offset,
2430 msg_hdr[i].qt_msg[j].size);
2431 if (msg_hdr[i].qt_msg[j].summary_size)
2432 Fprintf(stderr, " [%ld]",
2433 msg_hdr[i].qt_msg[j].summary_size);
2434 Fprintf(stderr, "\n");
2440 void
2441 do_questtxt()
2443 char *line;
2445 Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE);
2446 if (!(ifp = fopen(filename, RDTMODE))) {
2447 perror(filename);
2448 exit(EXIT_FAILURE);
2451 filename[0] = '\0';
2452 #ifdef FILE_PREFIX
2453 Strcat(filename, file_prefix);
2454 #endif
2455 Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE);
2456 if (!(ofp = fopen(filename, WRBMODE))) {
2457 perror(filename);
2458 Fclose(ifp);
2459 exit(EXIT_FAILURE);
2462 qt_hdr.n_hdr = 0;
2463 qt_line = 0;
2464 in_msg = FALSE;
2466 while ((line = fgetline(ifp)) != 0) {
2467 SpinCursor(3);
2469 qt_line++;
2470 if (qt_control(line))
2471 do_qt_control(line);
2472 else if (qt_comment(line)) {
2473 free(line);
2474 continue;
2475 } else
2476 do_qt_text(line);
2477 free(line);
2480 (void) rewind(ifp);
2481 in_msg = FALSE;
2482 adjust_qt_hdrs();
2483 put_qt_hdrs();
2484 while ((line = fgetline(ifp)) != 0) {
2485 if (qt_control(line)) {
2486 char *summary_p = 0;
2488 in_msg = (line[1] == 'C');
2489 if (!in_msg)
2490 summary_p = valid_qt_summary(line, FALSE);
2491 /* don't write anything unless we've got a summary */
2492 if (!summary_p) {
2493 free(line);
2494 continue;
2496 /* we have summary text; replace raw %E record with it */
2497 Strcpy(line, summary_p); /* (guaranteed to fit) */
2498 } else if (qt_comment(line)) {
2499 free(line);
2500 continue;
2502 if (debug)
2503 Fprintf(stderr, "%ld: %s", ftell(stdout), line);
2504 (void) fputs(xcrypt(line), ofp);
2505 free(line);
2507 Fclose(ifp);
2508 Fclose(ofp);
2509 return;
2512 static char temp[32];
2514 static char *limit(name, pref) /* limit a name to 30 characters length */
2515 char *name;
2516 int pref;
2518 (void) strncpy(temp, name, pref ? 26 : 30);
2519 temp[pref ? 26 : 30] = 0;
2520 return temp;
2523 void
2524 do_objs()
2526 int i, sum = 0;
2527 char *c, *objnam;
2528 int nspell = 0;
2529 int prefix = 0;
2530 char class = '\0';
2531 boolean sumerr = FALSE;
2533 filename[0] = '\0';
2534 #ifdef FILE_PREFIX
2535 Strcat(filename, file_prefix);
2536 #endif
2537 Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE);
2538 if (!(ofp = fopen(filename, WRTMODE))) {
2539 perror(filename);
2540 exit(EXIT_FAILURE);
2542 Fprintf(ofp, "%s", Dont_Edit_Code);
2543 Fprintf(ofp, "#ifndef ONAMES_H\n#define ONAMES_H\n\n");
2545 for (i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) {
2546 SpinCursor(3);
2548 objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init */
2549 if (!(objnam = tmpdup(OBJ_NAME(objects[i]))))
2550 continue;
2552 /* make sure probabilities add up to 1000 */
2553 if (objects[i].oc_class != class) {
2554 if (sum && sum != 1000) {
2555 Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
2556 (void) fflush(stderr);
2557 sumerr = TRUE;
2559 class = objects[i].oc_class;
2560 sum = 0;
2563 for (c = objnam; *c; c++)
2564 if (*c >= 'a' && *c <= 'z')
2565 *c -= (char) ('a' - 'A');
2566 else if (*c < 'A' || *c > 'Z')
2567 *c = '_';
2569 switch (class) {
2570 case WAND_CLASS:
2571 Fprintf(ofp, "#define\tWAN_");
2572 prefix = 1;
2573 break;
2574 case RING_CLASS:
2575 Fprintf(ofp, "#define\tRIN_");
2576 prefix = 1;
2577 break;
2578 case POTION_CLASS:
2579 Fprintf(ofp, "#define\tPOT_");
2580 prefix = 1;
2581 break;
2582 case SPBOOK_CLASS:
2583 Fprintf(ofp, "#define\tSPE_");
2584 prefix = 1;
2585 nspell++;
2586 break;
2587 case SCROLL_CLASS:
2588 Fprintf(ofp, "#define\tSCR_");
2589 prefix = 1;
2590 break;
2591 case AMULET_CLASS:
2592 /* avoid trouble with stupid C preprocessors */
2593 Fprintf(ofp, "#define\t");
2594 if (objects[i].oc_material == PLASTIC) {
2595 Fprintf(ofp, "FAKE_AMULET_OF_YENDOR\t%d\n", i);
2596 prefix = -1;
2597 break;
2599 break;
2600 case GEM_CLASS:
2601 /* avoid trouble with stupid C preprocessors */
2602 if (objects[i].oc_material == GLASS) {
2603 Fprintf(ofp, "/* #define\t%s\t%d */\n", objnam, i);
2604 prefix = -1;
2605 break;
2607 default:
2608 Fprintf(ofp, "#define\t");
2610 if (prefix >= 0)
2611 Fprintf(ofp, "%s\t%d\n", limit(objnam, prefix), i);
2612 prefix = 0;
2614 sum += objects[i].oc_prob;
2617 /* check last set of probabilities */
2618 if (sum && sum != 1000) {
2619 Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
2620 (void) fflush(stderr);
2621 sumerr = TRUE;
2624 Fprintf(ofp, "#define\tLAST_GEM\t(JADE)\n");
2625 Fprintf(ofp, "#define\tMAXSPELL\t%d\n", nspell + 1);
2626 Fprintf(ofp, "#define\tNUM_OBJECTS\t%d\n", i);
2628 Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n");
2630 for (i = 1; artifact_names[i]; i++) {
2631 SpinCursor(3);
2633 for (c = objnam = tmpdup(artifact_names[i]); *c; c++)
2634 if (*c >= 'a' && *c <= 'z')
2635 *c -= (char) ('a' - 'A');
2636 else if (*c < 'A' || *c > 'Z')
2637 *c = '_';
2639 if (!strncmp(objnam, "THE_", 4))
2640 objnam += 4;
2641 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
2642 if (!strncmp(objnam, "PLATINUM_", 9))
2643 objnam += 9;
2644 Fprintf(ofp, "#define\tART_%s\t%d\n", limit(objnam, 1), i);
2647 Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i - 1);
2648 Fprintf(ofp, "\n#endif /* ONAMES_H */\n");
2649 Fclose(ofp);
2650 if (sumerr)
2651 exit(EXIT_FAILURE);
2652 return;
2655 /* Read one line from input, up to and including the next newline
2656 * character. Returns a pointer to the heap-allocated string, or a
2657 * null pointer if no characters were read.
2659 static char *
2660 fgetline(fd)
2661 FILE *fd;
2663 static const int inc = 256;
2664 int len = inc;
2665 char *c = malloc(len), *ret;
2667 for (;;) {
2668 ret = fgets(c + len - inc, inc, fd);
2669 if (!ret) {
2670 free(c);
2671 c = NULL;
2672 break;
2673 } else if (index(c, '\n')) {
2674 /* normal case: we have a full line */
2675 break;
2677 len += inc;
2678 c = realloc(c, len);
2680 return c;
2683 static char *
2684 tmpdup(str)
2685 const char *str;
2687 static char buf[128];
2689 if (!str)
2690 return (char *) 0;
2691 (void) strncpy(buf, str, 127);
2692 return buf;
2695 static char *
2696 eos(str)
2697 char *str;
2699 while (*str)
2700 str++;
2701 return str;
2705 * macro used to control vision algorithms:
2706 * VISION_TABLES => generate tables
2709 void
2710 do_vision()
2712 #ifdef VISION_TABLES
2713 int i, j;
2715 /* Everything is clear. xclear may be malloc'ed.
2716 * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
2718 for (i = 0; i < MAX_ROW; i++)
2719 for (j = 0; j < MAX_COL; j++)
2720 if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH)
2721 xclear[i][j] = '\000';
2722 else
2723 xclear[i][j] = '\001';
2724 #endif /* VISION_TABLES */
2726 SpinCursor(3);
2729 * create the include file, "vis_tab.h"
2731 filename[0] = '\0';
2732 #ifdef FILE_PREFIX
2733 Strcat(filename, file_prefix);
2734 #endif
2735 Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
2736 if (!(ofp = fopen(filename, WRTMODE))) {
2737 perror(filename);
2738 exit(EXIT_FAILURE);
2740 Fprintf(ofp, "%s", Dont_Edit_Code);
2741 Fprintf(ofp, "#ifdef VISION_TABLES\n");
2742 #ifdef VISION_TABLES
2743 H_close_gen();
2744 H_far_gen();
2745 #endif /* VISION_TABLES */
2746 Fprintf(ofp, "\n#endif /* VISION_TABLES */\n");
2747 Fclose(ofp);
2749 SpinCursor(3);
2752 * create the source file, "vis_tab.c"
2754 filename[0] = '\0';
2755 #ifdef FILE_PREFIX
2756 Strcat(filename, file_prefix);
2757 #endif
2758 Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C);
2759 if (!(ofp = fopen(filename, WRTMODE))) {
2760 perror(filename);
2761 Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
2762 Unlink(filename);
2763 exit(EXIT_FAILURE);
2765 Fprintf(ofp, "%s", Dont_Edit_Code);
2766 Fprintf(ofp, "#include \"config.h\"\n");
2767 Fprintf(ofp, "#ifdef VISION_TABLES\n");
2768 Fprintf(ofp, "#include \"vis_tab.h\"\n");
2770 SpinCursor(3);
2772 #ifdef VISION_TABLES
2773 C_close_gen();
2774 C_far_gen();
2775 Fprintf(ofp, "\nvoid vis_tab_init() { return; }\n");
2776 #endif /* VISION_TABLES */
2778 SpinCursor(3);
2780 Fprintf(ofp, "\n#endif /* VISION_TABLES */\n");
2781 Fprintf(ofp, "\n/*vis_tab.c*/\n");
2783 Fclose(ofp);
2784 return;
2787 #ifdef VISION_TABLES
2789 /*-------------- vision tables --------------*\
2791 * Generate the close and far tables. This is done by setting up a
2792 * fake dungeon and moving our source to different positions relative
2793 * to a block and finding the first/last visible position. The fake
2794 * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
2795 * by BLOCK_WIDTH) is blocked. Then we move the source around relative
2796 * to the corner of the block. For each new position of the source
2797 * we check positions on rows "kittycorner" from the source. We check
2798 * positions until they are either in sight or out of sight (depends on
2799 * which table we are generating). The picture below shows the setup
2800 * for the generation of the close table. The generation of the far
2801 * table would switch the quadrants of the '@' and the "Check rows
2802 * here".
2805 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2806 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2807 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
2808 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2809 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2810 * ...............................
2811 * ...............................
2812 * .........@.....................
2813 * ...............................
2815 * Table generation figure (close_table). The 'X's are blocked points.
2816 * The 'B' is a special blocked point. The '@' is the source. The ','s
2817 * are the target area. The '.' are just open areas.
2820 * Example usage of close_table[][][].
2822 * The table is as follows:
2824 * dy = |row of '@' - row of 'B'| - 1
2825 * dx = |col of '@' - col of 'B'|
2827 * The first indices are the deltas from the source '@' and the block 'B'.
2828 * You must check for the value inside the abs value bars being zero. If
2829 * so then the block is on the same row and you don't need to do a table
2830 * lookup. The last value:
2832 * dcy = |row of block - row to be checked|
2834 * Is the value of the first visible spot on the check row from the
2835 * block column. So
2837 * first visible col = close_table[dy][dx][dcy] + col of 'B'
2839 \*-------------- vision tables --------------*/
2841 static void
2842 H_close_gen()
2844 Fprintf(ofp, "\n/* Close */\n");
2845 Fprintf(ofp,
2846 "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
2847 TEST_HEIGHT - 1);
2848 Fprintf(ofp,
2849 "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
2850 TEST_WIDTH);
2851 Fprintf(ofp,
2852 "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
2853 TEST_HEIGHT);
2854 Fprintf(ofp, "typedef struct {\n");
2855 Fprintf(ofp,
2856 " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
2857 Fprintf(ofp, "} close2d;\n");
2858 Fprintf(ofp, "extern close2d close_table[CLOSE_MAX_SB_DY];\n");
2859 return;
2862 static void
2863 H_far_gen()
2865 Fprintf(ofp, "\n/* Far */\n");
2866 Fprintf(ofp, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
2867 TEST_HEIGHT);
2868 Fprintf(ofp,
2869 "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
2870 TEST_WIDTH - 1);
2871 Fprintf(ofp,
2872 "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
2873 TEST_HEIGHT - 1);
2874 Fprintf(ofp, "typedef struct {\n");
2875 Fprintf(ofp, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
2876 Fprintf(ofp, "} far2d;\n");
2877 Fprintf(ofp, "extern far2d far_table[FAR_MAX_SB_DY];\n");
2878 return;
2881 static void
2882 C_close_gen()
2884 int i, dx, dy;
2885 int src_row, src_col; /* source */
2886 int block_row, block_col; /* block */
2887 int this_row;
2888 int no_more;
2889 const char *delim;
2891 block_row = BLOCK_HEIGHT - 1;
2892 block_col = BLOCK_WIDTH - 1;
2894 Fprintf(ofp, "\n#ifndef FAR_TABLE_ONLY\n");
2895 Fprintf(ofp, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
2896 #ifndef no_vision_progress
2897 Fprintf(stderr, "\nclose:");
2898 #endif
2900 for (dy = 1; dy < TEST_HEIGHT; dy++) {
2901 src_row = block_row + dy;
2902 Fprintf(ofp, "/* DY = %2d (- 1)*/\n {{\n", dy);
2903 #ifndef no_vision_progress
2904 Fprintf(stderr, " %2d", dy), (void) fflush(stderr);
2905 #endif
2906 for (dx = 0; dx < TEST_WIDTH; dx++) {
2907 src_col = block_col - dx;
2908 Fprintf(ofp, " /*%2d*/ {", dx);
2910 no_more = 0;
2911 for (this_row = 0; this_row < TEST_HEIGHT; this_row++) {
2912 delim = (this_row < TEST_HEIGHT - 1) ? "," : "";
2913 if (no_more) {
2914 Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim);
2915 continue;
2917 SpinCursor(3);
2919 /* Find the first column that we can see. */
2920 for (i = block_col + 1; i < MAX_COL; i++) {
2921 if (clear_path(src_row, src_col, block_row - this_row, i))
2922 break;
2925 if (i == MAX_COL)
2926 no_more = 1;
2927 Fprintf(ofp, "%2d%s", i - block_col, delim);
2929 Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
2931 Fprintf(ofp, " }},\n");
2934 Fprintf(ofp, "}; /* close_table[] */\n"); /* closing brace for table */
2935 Fprintf(ofp, "#endif /* !FAR_TABLE_ONLY */\n");
2936 #ifndef no_vision_progress
2937 Fprintf(stderr, "\n");
2938 #endif
2939 return;
2942 static void
2943 C_far_gen()
2945 int i, dx, dy;
2946 int src_row, src_col; /* source */
2947 int block_row, block_col; /* block */
2948 int this_row;
2949 const char *delim;
2951 block_row = BLOCK_HEIGHT - 1;
2952 block_col = BLOCK_WIDTH - 1;
2954 Fprintf(ofp, "\n#ifndef CLOSE_TABLE_ONLY\n");
2955 Fprintf(ofp, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
2956 #ifndef no_vision_progress
2957 Fprintf(stderr, "\n_far_:");
2958 #endif
2960 for (dy = 0; dy < TEST_HEIGHT; dy++) {
2961 src_row = block_row - dy;
2962 Fprintf(ofp, "/* DY = %2d */\n {{\n", dy);
2963 #ifndef no_vision_progress
2964 Fprintf(stderr, " %2d", dy), (void) fflush(stderr);
2965 #endif
2966 for (dx = 1; dx < TEST_WIDTH; dx++) {
2967 src_col = block_col + dx;
2968 Fprintf(ofp, " /*%2d(-1)*/ {", dx);
2970 for (this_row = block_row + 1; this_row < block_row + TEST_HEIGHT;
2971 this_row++) {
2972 delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : "";
2974 SpinCursor(3);
2975 /* Find first col that we can see. */
2976 for (i = 0; i <= block_col; i++) {
2977 if (clear_path(src_row, src_col, this_row, i))
2978 break;
2981 if (block_col - i < 0)
2982 Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim);
2983 else
2984 Fprintf(ofp, "%2d%s", block_col - i, delim);
2986 Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
2988 Fprintf(ofp, " }},\n");
2991 Fprintf(ofp, "}; /* far_table[] */\n"); /* closing brace for table */
2992 Fprintf(ofp, "#endif /* !CLOSE_TABLE_ONLY */\n");
2993 #ifndef no_vision_progress
2994 Fprintf(stderr, "\n");
2995 #endif
2996 return;
3000 * "Draw" a line from the hero to the given location. Stop if we hit a
3001 * wall.
3003 * Generalized integer Bresenham's algorithm (fast line drawing) for
3004 * all quadrants. From _Procedural Elements for Computer Graphics_, by
3005 * David F. Rogers. McGraw-Hill, 1985.
3007 * I have tried a little bit of optimization by pulling compares out of
3008 * the inner loops.
3010 * NOTE: This had better *not* be called from a position on the
3011 * same row as the hero.
3013 static int
3014 clear_path(you_row, you_col, y2, x2)
3015 int you_row, you_col, y2, x2;
3017 int dx, dy, s1, s2;
3018 register int i, error, x, y, dxs, dys;
3020 x = you_col;
3021 y = you_row;
3022 dx = abs(x2 - you_col);
3023 dy = abs(y2 - you_row);
3024 s1 = sign(x2 - you_col);
3025 s2 = sign(y2 - you_row);
3027 if (s1 == 0) { /* same column */
3028 if (s2 == 1) { /* below (larger y2 value) */
3029 for (i = you_row + 1; i < y2; i++)
3030 if (!xclear[i][you_col])
3031 return 0;
3032 } else { /* above (smaller y2 value) */
3033 for (i = y2 + 1; i < you_row; i++)
3034 if (!xclear[i][you_col])
3035 return 0;
3037 return 1;
3041 * Lines at 0 and 90 degrees have been weeded out.
3043 if (dy > dx) {
3044 error = dx;
3045 dx = dy;
3046 dy = error; /* swap the values */
3047 dxs = dx << 1; /* save the shifted values */
3048 dys = dy << 1;
3049 error = dys - dx; /* NOTE: error is used as a temporary above */
3051 for (i = 0; i < dx; i++) {
3052 if (!xclear[y][x])
3053 return 0; /* plot point */
3055 while (error >= 0) {
3056 x += s1;
3057 error -= dxs;
3059 y += s2;
3060 error += dys;
3062 } else {
3063 dxs = dx << 1; /* save the shifted values */
3064 dys = dy << 1;
3065 error = dys - dx;
3067 for (i = 0; i < dx; i++) {
3068 if (!xclear[y][x])
3069 return 0; /* plot point */
3071 while (error >= 0) {
3072 y += s2;
3073 error -= dxs;
3075 x += s1;
3076 error += dys;
3079 return 1;
3081 #endif /* VISION_TABLES */
3083 #ifdef STRICT_REF_DEF
3084 NEARDATA struct flag flags;
3085 #ifdef ATTRIB_H
3086 struct attribs attrmax, attrmin;
3087 #endif
3088 #endif /* STRICT_REF_DEF */
3090 /*makedefs.c*/