OSDN Git Service

23dace27b250df6320a837ff3385f065ba71d7b5
[nethackexpress/trunk.git] / util / makedefs.c
1 /*      SCCS Id: @(#)makedefs.c 3.4     2002/08/14      */
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. */
6
7 #define MAKEDEFS_C      /* use to conditionally include file sections */
8 /* #define DEBUG */     /* uncomment for debugging info */
9
10 #include "config.h"
11 #include "permonst.h"
12 #include "objclass.h"
13 #include "monsym.h"
14 #include "artilist.h"
15 #include "dungeon.h"
16 #include "obj.h"
17 #include "monst.h"
18 #include "you.h"
19 #include "flag.h"
20 #include "dlb.h"
21
22 /* version information */
23 #ifdef SHORT_FILENAMES
24 #include "patchlev.h"
25 #else
26 #include "patchlevel.h"
27 #endif
28
29 #ifdef MAC
30 # if defined(__SC__) || defined(__MRC__)        /* MPW compilers */
31 #  define MPWTOOL
32 #include <CursorCtl.h>
33 #include <string.h>
34 #include <ctype.h>
35 # else          /* MAC without MPWTOOL */
36 #  define MACsansMPWTOOL
37 # endif
38 #endif /* MAC */
39
40 #ifndef MPWTOOL
41 # define SpinCursor(x)
42 #endif
43
44 #define Fprintf (void) fprintf
45 #define Fclose  (void) fclose
46 #define Unlink  (void) unlink
47 #if !defined(AMIGA) || defined(AZTEC_C)
48 #define rewind(fp) fseek((fp),0L,SEEK_SET)      /* guarantee a return value */
49 #endif
50
51 #if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN)
52 static  const char      SCCS_Id[] = "@(#)makedefs.c\t3.4\t2002/02/03";
53 #endif
54
55         /* names of files to be generated */
56 #define DATE_FILE       "date.h"
57 #define MONST_FILE      "pm.h"
58 #define ONAME_FILE      "onames.h"
59 #ifndef OPTIONS_FILE
60 #define OPTIONS_FILE    "options"
61 #endif
62 #define ORACLE_FILE     "oracles"
63 #define DATA_FILE       "data"
64 #define RUMOR_FILE      "rumors"
65 #define DGN_I_FILE      "dungeon.def"
66 #define DGN_O_FILE      "dungeon.pdf"
67 #define MON_STR_C       "monstr.c"
68 #define QTXT_I_FILE     "quest.txt"
69 #define QTXT_O_FILE     "quest.dat"
70 #define VIS_TAB_H       "vis_tab.h"
71 #define VIS_TAB_C       "vis_tab.c"
72         /* locations for those files */
73 #ifdef AMIGA
74 # define FILE_PREFIX
75 # define INCLUDE_TEMPLATE       "NH:include/t.%s"
76 # define SOURCE_TEMPLATE        "NH:src/%s"
77 # define DGN_TEMPLATE           "NH:dat/%s"  /* where dungeon.pdf file goes */
78 # define DATA_TEMPLATE          "NH:slib/%s"
79 # define DATA_IN_TEMPLATE       "NH:dat/%s"
80 #else /* not AMIGA */
81 # if defined(MAC) && !defined(__MACH__)
82     /* MacOS 9 or earlier */
83 #   define INCLUDE_TEMPLATE     ":include:%s"
84 #   define SOURCE_TEMPLATE      ":src:%s"
85 #   define DGN_TEMPLATE         ":dat:%s"  /* where dungeon.pdf file goes */
86 #  if __SC__ || __MRC__
87 #   define DATA_TEMPLATE        ":Dungeon:%s"
88 #  else
89 #   define DATA_TEMPLATE        ":lib:%s"
90 #  endif /* __SC__ || __MRC__ */
91 #   define DATA_IN_TEMPLATE     ":dat:%s"
92 # else /* neither AMIGA nor MAC */
93 #  ifdef OS2
94 #   define INCLUDE_TEMPLATE     "..\\include\\%s"
95 #   define SOURCE_TEMPLATE      "..\\src\\%s"
96 #   define DGN_TEMPLATE         "..\\dat\\%s"  /* where dungeon.pdf file goes */
97 #   define DATA_TEMPLATE        "..\\dat\\%s"
98 #   define DATA_IN_TEMPLATE     "..\\dat\\%s"
99 #  else /* not AMIGA, MAC, or OS2 */
100 #   define INCLUDE_TEMPLATE     "../include/%s"
101 #   define SOURCE_TEMPLATE      "../src/%s"
102 #   define DGN_TEMPLATE         "../dat/%s"  /* where dungeon.pdf file goes */
103 #   define DATA_TEMPLATE        "../dat/%s"
104 #   define DATA_IN_TEMPLATE     "../dat/%s"
105 #  endif /* else !OS2 */
106 # endif /* else !MAC */
107 #endif  /* else !AMIGA */
108
109 static const char
110     *Dont_Edit_Code =
111         "/* This source file is generated by 'makedefs'.  Do not edit. */\n",
112     *Dont_Edit_Data =
113         "#\tThis data file is generated by 'makedefs'.  Do not edit. \n";
114
115 static struct version_info version;
116
117 /* definitions used for vision tables */
118 #define TEST_WIDTH  COLNO
119 #define TEST_HEIGHT ROWNO
120 #define BLOCK_WIDTH (TEST_WIDTH + 10)
121 #define BLOCK_HEIGHT TEST_HEIGHT        /* don't need extra spaces */
122 #define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT)
123 #define MAX_COL (BLOCK_WIDTH + TEST_WIDTH)
124 /* Use this as an out-of-bound value in the close table.  */
125 #define CLOSE_OFF_TABLE_STRING "99"     /* for the close table */
126 #define FAR_OFF_TABLE_STRING "0xff"     /* for the far table */
127
128 #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0))
129 #ifdef VISION_TABLES
130 static char xclear[MAX_ROW][MAX_COL];
131 #endif
132 /*-end of vision defs-*/
133
134 static char     in_line[256], filename[60];
135
136 #ifdef FILE_PREFIX
137                 /* if defined, a first argument not starting with - is
138                  * taken as a text string to be prepended to any
139                  * output filename generated */
140 char *file_prefix="";
141 #endif
142
143 #ifdef MACsansMPWTOOL
144 int FDECL(main, (void));
145 #else
146 int FDECL(main, (int,char **));
147 #endif
148 void FDECL(do_makedefs, (char *));
149 void NDECL(do_objs);
150 void NDECL(do_data);
151 void NDECL(do_dungeon);
152 void NDECL(do_date);
153 void NDECL(do_options);
154 void NDECL(do_monstr);
155 void NDECL(do_permonst);
156 void NDECL(do_questtxt);
157 void NDECL(do_rumors);
158 void NDECL(do_oracles);
159 void NDECL(do_vision);
160
161 extern void NDECL(monst_init);          /* monst.c */
162 extern void NDECL(objects_init);        /* objects.c */
163
164 static void NDECL(make_version);
165 static char *FDECL(version_string, (char *));
166 static char *FDECL(version_id_string, (char *,const char *));
167 static char *FDECL(xcrypt, (const char *));
168 static int FDECL(check_control, (char *));
169 static char *FDECL(without_control, (char *));
170 static boolean FDECL(d_filter, (char *));
171 static boolean FDECL(h_filter, (char *));
172 static boolean FDECL(ranged_attk,(struct permonst*));
173 static int FDECL(mstrength,(struct permonst *));
174 static void NDECL(build_savebones_compat_string);
175
176 static boolean FDECL(qt_comment, (char *));
177 static boolean FDECL(qt_control, (char *));
178 static int FDECL(get_hdr, (char *));
179 static boolean FDECL(new_id, (char *));
180 static boolean FDECL(known_msg, (int,int));
181 static void FDECL(new_msg, (char *,int,int));
182 static void FDECL(do_qt_control, (char *));
183 static void FDECL(do_qt_text, (char *));
184 static void NDECL(adjust_qt_hdrs);
185 static void NDECL(put_qt_hdrs);
186
187 #ifdef VISION_TABLES
188 static void NDECL(H_close_gen);
189 static void NDECL(H_far_gen);
190 static void NDECL(C_close_gen);
191 static void NDECL(C_far_gen);
192 static int FDECL(clear_path, (int,int,int,int));
193 #endif
194
195 static char *FDECL(tmpdup, (const char *));
196 static char *FDECL(limit, (char *,int));
197 static char *FDECL(eos, (char *));
198
199 /* input, output, tmp */
200 static FILE *ifp, *ofp, *tfp;
201
202 #if defined(__BORLANDC__) && !defined(_WIN32)
203 extern unsigned _stklen = STKSIZ;
204 #endif
205
206
207 #ifdef MACsansMPWTOOL
208 int
209 main(void)
210 {
211     const char *def_options = "odemvpqrhz";
212     char buf[100];
213     int len;
214
215     printf("Enter options to run: [%s] ", def_options);
216     fflush(stdout);
217     fgets(buf, 100, stdin);
218     len = strlen(buf);
219     if (len <= 1)
220         Strcpy(buf, def_options);
221     else
222         buf[len-1] = 0;                 /* remove return */
223
224     do_makedefs(buf);
225     exit(EXIT_SUCCESS);
226     return 0;
227 }
228
229 #else /* ! MAC */
230
231 int
232 main(argc, argv)
233 int     argc;
234 char    *argv[];
235 {
236         if ( (argc != 2)
237 #ifdef FILE_PREFIX
238                 && (argc != 3)
239 #endif
240         ) {
241             Fprintf(stderr, "Bad arg count (%d).\n", argc-1);
242             (void) fflush(stderr);
243             return 1;
244         }
245
246 #ifdef FILE_PREFIX
247         if(argc >=2 && argv[1][0]!='-'){
248             file_prefix=argv[1];
249             argc--;argv++;
250         }
251 #endif
252         do_makedefs(&argv[1][1]);
253         exit(EXIT_SUCCESS);
254         /*NOTREACHED*/
255         return 0;
256 }
257
258 #endif
259
260 void
261 do_makedefs(options)
262 char    *options;
263 {
264         boolean more_than_one;
265
266         /* Note:  these initializers don't do anything except guarantee that
267                 we're linked properly.
268         */
269         monst_init();
270         objects_init();
271
272         /* construct the current version number */
273         make_version();
274
275
276         more_than_one = strlen(options) > 1;
277         while (*options) {
278             if (more_than_one)
279                 Fprintf(stderr, "makedefs -%c\n", *options);
280
281             switch (*options) {
282                 case 'o':
283                 case 'O':       do_objs();
284                                 break;
285                 case 'd':
286                 case 'D':       do_data();
287                                 break;
288                 case 'e':
289                 case 'E':       do_dungeon();
290                                 break;
291                 case 'm':
292                 case 'M':       do_monstr();
293                                 break;
294                 case 'v':
295                 case 'V':       do_date();
296                                 do_options();
297                                 break;
298                 case 'p':
299                 case 'P':       do_permonst();
300                                 break;
301                 case 'q':
302                 case 'Q':       do_questtxt();
303                                 break;
304                 case 'r':
305                 case 'R':       do_rumors();
306                                 break;
307                 case 'h':
308                 case 'H':       do_oracles();
309                                 break;
310                 case 'z':
311                 case 'Z':       do_vision();
312                                 break;
313
314                 default:        Fprintf(stderr, "Unknown option '%c'.\n",
315                                         *options);
316                                 (void) fflush(stderr);
317                                 exit(EXIT_FAILURE);
318                 
319             }
320             options++;
321         }
322         if (more_than_one) Fprintf(stderr, "Completed.\n");     /* feedback */
323
324 }
325
326
327 /* trivial text encryption routine which can't be broken with `tr' */
328 static
329 char *xcrypt(str)
330 const char *str;
331 {                               /* duplicated in src/hacklib.c */
332         static char buf[BUFSZ];
333         register const char *p;
334         register char *q;
335         register int bitmask;
336
337         for (bitmask = 1, p = str, q = buf; *p; q++) {
338                 *q = *p++;
339                 if (*q & (32|64)) *q ^= bitmask;
340                 if ((bitmask <<= 1) >= 32) bitmask = 1;
341         }
342         *q = '\0';
343         return buf;
344 }
345
346 void
347 do_rumors()
348 {
349         char    infile[60];
350         long    true_rumor_size;
351
352         filename[0]='\0';
353 #ifdef FILE_PREFIX
354         Strcat(filename,file_prefix);
355 #endif
356         Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE);
357         if (!(ofp = fopen(filename, WRTMODE))) {
358                 perror(filename);
359                 exit(EXIT_FAILURE);
360         }
361         Fprintf(ofp,Dont_Edit_Data);
362
363         Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
364         Strcat(infile, ".tru");
365         if (!(ifp = fopen(infile, RDTMODE))) {
366                 perror(infile);
367                 Fclose(ofp);
368                 Unlink(filename);       /* kill empty output file */
369                 exit(EXIT_FAILURE);
370         }
371
372         /* get size of true rumors file */
373 #ifndef VMS
374         (void) fseek(ifp, 0L, SEEK_END);
375         true_rumor_size = ftell(ifp);
376 #else
377         /* seek+tell is only valid for stream format files; since rumors.%%%
378            might be in record format, count the actual data bytes instead.
379          */
380         true_rumor_size = 0;
381         while (fgets(in_line, sizeof in_line, ifp) != 0)
382                 true_rumor_size += strlen(in_line);     /* includes newline */
383 #endif /* VMS */
384         Fprintf(ofp,"%06lx\n", true_rumor_size);
385         (void) fseek(ifp, 0L, SEEK_SET);
386
387         /* copy true rumors */
388         while (fgets(in_line, sizeof in_line, ifp) != 0)
389                 (void) fputs(xcrypt(in_line), ofp);
390
391         Fclose(ifp);
392
393         Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
394         Strcat(infile, ".fal");
395         if (!(ifp = fopen(infile, RDTMODE))) {
396                 perror(infile);
397                 Fclose(ofp);
398                 Unlink(filename);       /* kill incomplete output file */
399                 exit(EXIT_FAILURE);
400         }
401
402         /* copy false rumors */
403         while (fgets(in_line, sizeof in_line, ifp) != 0)
404                 (void) fputs(xcrypt(in_line), ofp);
405
406         Fclose(ifp);
407         Fclose(ofp);
408         return;
409 }
410
411 /*
412  * 3.4.1: way back in 3.2.1 `flags.nap' became unconditional but
413  * TIMED_DELAY was erroneously left in VERSION_FEATURES and has
414  * been there up through 3.4.0.  Simply removing it now would
415  * break save file compatibility with 3.4.0 files, so we will
416  * explicitly mask it out during version checks.
417  * This should go away in the next version update.
418  */
419 #define IGNORED_FEATURES        ( 0L \
420                                 | (1L << 23)    /* TIMED_DELAY */ \
421                                 )
422
423 static void
424 make_version()
425 {
426         register int i;
427
428         /*
429          * integer version number
430          */
431         version.incarnation = ((unsigned long)VERSION_MAJOR << 24) |
432                                 ((unsigned long)VERSION_MINOR << 16) |
433                                 ((unsigned long)PATCHLEVEL << 8) |
434                                 ((unsigned long)EDITLEVEL);
435         /*
436          * encoded feature list
437          * Note:  if any of these magic numbers are changed or reassigned,
438          * EDITLEVEL in patchlevel.h should be incremented at the same time.
439          * The actual values have no special meaning, and the category
440          * groupings are just for convenience.
441          */
442         version.feature_set = (unsigned long)(0L
443                 /* levels and/or topology (0..4) */
444 #ifdef REINCARNATION
445                         | (1L <<  1)
446 #endif
447 #ifdef SINKS
448                         | (1L <<  2)
449 #endif
450                 /* monsters (5..9) */
451 #ifdef KOPS
452                         | (1L <<  6)
453 #endif
454 #ifdef MAIL
455                         | (1L <<  7)
456 #endif
457                 /* objects (10..14) */
458 #ifdef TOURIST
459                         | (1L << 10)
460 #endif
461 #ifdef STEED
462                         | (1L << 11)
463 #endif
464 #ifdef GOLDOBJ
465                         | (1L << 12)
466 #endif
467                 /* flag bits and/or other global variables (15..26) */
468 #ifdef TEXTCOLOR
469                         | (1L << 17)
470 #endif
471 #ifdef INSURANCE
472                         | (1L << 18)
473 #endif
474 #ifdef ELBERETH
475                         | (1L << 19)
476 #endif
477 #ifdef EXP_ON_BOTL
478                         | (1L << 20)
479 #endif
480 #ifdef SCORE_ON_BOTL
481                         | (1L << 21)
482 #endif
483                 /* data format [COMPRESS excluded] (27..31) */
484 #ifdef ZEROCOMP
485                         | (1L << 27)
486 #endif
487 #ifdef RLECOMP
488                         | (1L << 28)
489 #endif
490                         );
491         /*
492          * Value used for object & monster sanity check.
493          *    (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
494          */
495         for (i = 1; artifact_names[i]; i++) continue;
496         version.entity_count = (unsigned long)(i - 1);
497         for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++) continue;
498         version.entity_count = (version.entity_count << 12) | (unsigned long)i;
499         for (i = 0; mons[i].mlet; i++) continue;
500         version.entity_count = (version.entity_count << 12) | (unsigned long)i;
501         /*
502          * Value used for compiler (word size/field alignment/padding) check.
503          */
504         version.struct_sizes = (((unsigned long)sizeof (struct flag)  << 24) |
505                                 ((unsigned long)sizeof (struct obj)   << 17) |
506                                 ((unsigned long)sizeof (struct monst) << 10) |
507                                 ((unsigned long)sizeof (struct you)));
508         return;
509 }
510
511 static char *
512 version_string(outbuf)
513 char *outbuf;
514 {
515     Sprintf(outbuf, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
516 #ifdef BETA
517     Sprintf(eos(outbuf), "-%d", EDITLEVEL);
518 #endif
519     return outbuf;
520 }
521
522 static char *
523 version_id_string(outbuf, build_date)
524 char *outbuf;
525 const char *build_date;
526 {
527     char subbuf[64], versbuf[64];
528
529     subbuf[0] = '\0';
530 #ifdef PORT_SUB_ID
531     subbuf[0] = ' ';
532     Strcpy(&subbuf[1], PORT_SUB_ID);
533 #endif
534 #ifdef BETA
535     Strcat(subbuf, " Beta");
536 #endif
537
538     Sprintf(outbuf, "%s NetHack%s Version %s - last build %s.",
539             PORT_ID, subbuf, version_string(versbuf), build_date);
540     return outbuf;
541 }
542
543 void
544 do_date()
545 {
546         long clocktim = 0;
547         char *c, cbuf[60], buf[BUFSZ];
548         const char *ul_sfx;
549
550         filename[0]='\0';
551 #ifdef FILE_PREFIX
552         Strcat(filename,file_prefix);
553 #endif
554         Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE);
555         if (!(ofp = fopen(filename, WRTMODE))) {
556                 perror(filename);
557                 exit(EXIT_FAILURE);
558         }
559         Fprintf(ofp,"/*\tSCCS Id: @(#)date.h\t3.4\t2002/02/03 */\n\n");
560         Fprintf(ofp,Dont_Edit_Code);
561
562 #ifdef KR1ED
563         (void) time(&clocktim);
564         Strcpy(cbuf, ctime(&clocktim));
565 #else
566         (void) time((time_t *)&clocktim);
567         Strcpy(cbuf, ctime((time_t *)&clocktim));
568 #endif
569         for (c = cbuf; *c; c++) if (*c == '\n') break;
570         *c = '\0';      /* strip off the '\n' */
571         Fprintf(ofp,"#define BUILD_DATE \"%s\"\n", cbuf);
572         Fprintf(ofp,"#define BUILD_TIME (%ldL)\n", clocktim);
573         Fprintf(ofp,"\n");
574 #ifdef NHSTDC
575         ul_sfx = "UL";
576 #else
577         ul_sfx = "L";
578 #endif
579         Fprintf(ofp,"#define VERSION_NUMBER 0x%08lx%s\n",
580                 version.incarnation, ul_sfx);
581         Fprintf(ofp,"#define VERSION_FEATURES 0x%08lx%s\n",
582                 version.feature_set, ul_sfx);
583 #ifdef IGNORED_FEATURES
584         Fprintf(ofp,"#define IGNORED_FEATURES 0x%08lx%s\n",
585                 (unsigned long) IGNORED_FEATURES, ul_sfx);
586 #endif
587         Fprintf(ofp,"#define VERSION_SANITY1 0x%08lx%s\n",
588                 version.entity_count, ul_sfx);
589         Fprintf(ofp,"#define VERSION_SANITY2 0x%08lx%s\n",
590                 version.struct_sizes, ul_sfx);
591         Fprintf(ofp,"\n");
592         Fprintf(ofp,"#define VERSION_STRING \"%s\"\n", version_string(buf));
593         Fprintf(ofp,"#define VERSION_ID \\\n \"%s\"\n",
594                 version_id_string(buf, cbuf));
595         Fprintf(ofp,"\n");
596 #ifdef AMIGA
597         {
598         struct tm *tm = localtime((time_t *) &clocktim);
599         Fprintf(ofp,"#define AMIGA_VERSION_STRING ");
600         Fprintf(ofp,"\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
601                 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
602                 tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900);
603         }
604 #endif
605         Fclose(ofp);
606         return;
607 }
608
609 static char save_bones_compat_buf[BUFSZ];
610
611 static void
612 build_savebones_compat_string()
613 {
614 #ifdef VERSION_COMPATIBILITY
615         unsigned long uver = VERSION_COMPATIBILITY;
616 #endif
617         Strcpy(save_bones_compat_buf,
618                 "save and bones files accepted from version");
619 #ifdef VERSION_COMPATIBILITY
620         Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d",
621                 ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16),
622                 ((uver & 0x0000FF00L) >> 8),
623                 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
624 #else
625         Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only",
626                 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
627 #endif
628 }
629
630 static const char *build_opts[] = {
631 #ifdef AMIGA_WBENCH
632                 "Amiga WorkBench support",
633 #endif
634 #ifdef ANSI_DEFAULT
635                 "ANSI default terminal",
636 #endif
637 #ifdef AUTOPICKUP_EXCEPTIONS
638                 "autopickup_exceptions",
639 #endif
640 #ifdef TEXTCOLOR
641                 "color",
642 #endif
643 #ifdef COM_COMPL
644                 "command line completion",
645 #endif
646 #ifdef COMPRESS
647                 "data file compression",
648 #endif
649 #ifdef DLB
650                 "data librarian",
651 #endif
652 #ifdef WIZARD
653                 "debug mode",
654 #endif
655 #ifdef ELBERETH
656                 "Elbereth",
657 #endif
658 #ifdef EXP_ON_BOTL
659                 "experience points on status line",
660 #endif
661 #ifdef MFLOPPY
662                 "floppy drive support",
663 #endif
664 #ifdef GOLDOBJ
665                 "gold object in inventories",
666 #endif
667 #ifdef INSURANCE
668                 "insurance files for recovering from crashes",
669 #endif
670 #ifdef KOPS
671                 "Keystone Kops",
672 #endif
673 #ifdef HOLD_LOCKFILE_OPEN
674                 "exclusive lock on level 0 file",
675 #endif
676 #ifdef LOGFILE
677                 "log file",
678 #endif
679 #ifdef MAIL
680                 "mail daemon",
681 #endif
682 #ifdef GNUDOS
683                 "MSDOS protected mode",
684 #endif
685 #ifdef NEWS
686                 "news file",
687 #endif
688 #ifdef OVERLAY
689 # ifdef MOVERLAY
690                 "MOVE overlays",
691 # else
692 #  ifdef VROOMM
693                 "VROOMM overlays",
694 #  else
695                 "overlays",
696 #  endif
697 # endif
698 #endif
699 #ifdef REDO
700                 "redo command",
701 #endif
702 #ifdef REINCARNATION
703                 "rogue level",
704 #endif
705 #ifdef STEED
706                 "saddles and riding",
707 #endif
708 #ifdef SCORE_ON_BOTL
709                 "score on status line",
710 #endif
711 #ifdef CLIPPING
712                 "screen clipping",
713 #endif
714 #ifdef NO_TERMS
715 # ifdef MAC
716                 "screen control via mactty",
717 # endif
718 # ifdef SCREEN_BIOS
719                 "screen control via BIOS",
720 # endif
721 # ifdef SCREEN_DJGPPFAST
722                 "screen control via DJGPP fast",
723 # endif
724 # ifdef SCREEN_VGA
725                 "screen control via VGA graphics",
726 # endif
727 # ifndef MSWIN_GRAPHICS
728 #  ifdef WIN32CON
729                 "screen control via WIN32 console I/O",
730 #  endif
731 # endif
732 #endif
733 #ifdef SEDUCE
734                 "seduction",
735 #endif
736 #ifdef SHELL
737                 "shell command",
738 #endif
739 #ifdef SINKS
740                 "sinks",
741 #endif
742 #ifdef SUSPEND
743                 "suspend command",
744 #endif
745 #ifdef TERMINFO
746                 "terminal info library",
747 #else
748 # if defined(TERMLIB) || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
749                 "terminal capability library",
750 # endif
751 #endif
752 #ifdef TIMED_DELAY
753                 "timed wait for display effects",
754 #endif
755 #ifdef TOURIST
756                 "tourists",
757 #endif
758 #ifdef USER_SOUNDS
759 # ifdef USER_SOUNDS_REGEX
760                 "user sounds via regular expressions",
761 # else
762                 "user sounds via pmatch",
763 # endif
764 #endif
765 #ifdef PREFIXES_IN_USE
766                 "variable playground",
767 #endif
768 #ifdef VISION_TABLES
769                 "vision tables",
770 #endif
771 #ifdef WALLIFIED_MAZE
772                 "walled mazes",
773 #endif
774 #ifdef ZEROCOMP
775                 "zero-compressed save files",
776 #endif
777                 save_bones_compat_buf,
778                 "basic NetHack features"
779         };
780
781 static const char *window_opts[] = {
782 #ifdef TTY_GRAPHICS
783                 "traditional tty-based graphics",
784 #endif
785 #ifdef X11_GRAPHICS
786                 "X11",
787 #endif
788 #ifdef QT_GRAPHICS
789                 "Qt",
790 #endif
791 #ifdef GNOME_GRAPHICS
792                 "Gnome",
793 #endif
794 #ifdef MAC
795                 "Mac",
796 #endif
797 #ifdef AMIGA_INTUITION
798                 "Amiga Intuition",
799 #endif
800 #ifdef GEM_GRAPHICS
801                 "Gem",
802 #endif
803 #ifdef MSWIN_GRAPHICS
804                 "mswin",
805 #endif
806 #ifdef BEOS_GRAPHICS
807                 "BeOS InterfaceKit",
808 #endif
809                 0
810         };
811
812 void
813 do_options()
814 {
815         register int i, length;
816         register const char *str, *indent = "    ";
817
818         filename[0]='\0';
819 #ifdef FILE_PREFIX
820         Strcat(filename,file_prefix);
821 #endif
822         Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE);
823         if (!(ofp = fopen(filename, WRTMODE))) {
824                 perror(filename);
825                 exit(EXIT_FAILURE);
826         }
827
828         build_savebones_compat_string();
829         Fprintf(ofp,
830 #ifdef BETA
831                 "\n    NetHack version %d.%d.%d [beta]\n",
832 #else
833                 "\n    NetHack version %d.%d.%d\n",
834 #endif
835                 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
836
837         Fprintf(ofp,"\nOptions compiled into this edition:\n");
838
839         length = COLNO + 1;     /* force 1st item onto new line */
840         for (i = 0; i < SIZE(build_opts); i++) {
841             str = build_opts[i];
842             if (length + strlen(str) > COLNO - 5)
843                 Fprintf(ofp,"\n%s", indent),  length = strlen(indent);
844             else
845                 Fprintf(ofp," "),  length++;
846             Fprintf(ofp,"%s", str),  length += strlen(str);
847             Fprintf(ofp,(i < SIZE(build_opts) - 1) ? "," : "."),  length++;
848         }
849
850         Fprintf(ofp,"\n\nSupported windowing systems:\n");
851
852         length = COLNO + 1;     /* force 1st item onto new line */
853         for (i = 0; i < SIZE(window_opts) - 1; i++) {
854             str = window_opts[i];
855             if (length + strlen(str) > COLNO - 5)
856                 Fprintf(ofp,"\n%s", indent),  length = strlen(indent);
857             else
858                 Fprintf(ofp," "),  length++;
859             Fprintf(ofp,"%s", str),  length += strlen(str);
860             Fprintf(ofp, ","),  length++;
861         }
862         Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS);
863         Fprintf(ofp,"\n\n");
864
865         Fclose(ofp);
866         return;
867 }
868
869 /* routine to decide whether to discard something from data.base */
870 static boolean
871 d_filter(line)
872     char *line;
873 {
874     if (*line == '#') return TRUE;      /* ignore comment lines */
875     return FALSE;
876 }
877
878    /*
879     *
880         New format (v3.1) of 'data' file which allows much faster lookups [pr]
881 "do not edit"           first record is a comment line
882 01234567                hexadecimal formatted offset to text area
883 name-a                  first name of interest
884 123,4                   offset to name's text, and number of lines for it
885 name-b                  next name of interest
886 name-c                  multiple names which share same description also
887 456,7                   share a single offset,count line
888 .                       sentinel to mark end of names
889 789,0                   dummy record containing offset, count of EOF
890 text-a                  4 lines of descriptive text for name-a
891 text-a                  at file position 0x01234567L + 123L
892 text-a
893 text-a
894 text-b/text-c           7 lines of text for names-b and -c
895 text-b/text-c           at fseek(0x01234567L + 456L)
896 ...
897     *
898     */
899
900 void
901 do_data()
902 {
903         char    infile[60], tempfile[60];
904         boolean ok;
905         long    txt_offset;
906         int     entry_cnt, line_cnt;
907
908         Sprintf(tempfile, DATA_TEMPLATE, "database.tmp");
909         filename[0]='\0';
910 #ifdef FILE_PREFIX
911         Strcat(filename,file_prefix);
912 #endif
913         Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE);
914         Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE);
915         Strcat(infile,
916 #ifdef SHORT_FILENAMES
917                 ".bas"
918 #else
919                 ".base"
920 #endif
921                 );
922         if (!(ifp = fopen(infile, RDTMODE))) {          /* data.base */
923                 perror(infile);
924                 exit(EXIT_FAILURE);
925         }
926         if (!(ofp = fopen(filename, WRTMODE))) {        /* data */
927                 perror(filename);
928                 Fclose(ifp);
929                 exit(EXIT_FAILURE);
930         }
931         if (!(tfp = fopen(tempfile, WRTMODE))) {        /* database.tmp */
932                 perror(tempfile);
933                 Fclose(ifp);
934                 Fclose(ofp);
935                 Unlink(filename);
936                 exit(EXIT_FAILURE);
937         }
938
939         /* output a dummy header record; we'll rewind and overwrite it later */
940         Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L);
941
942         entry_cnt = line_cnt = 0;
943         /* read through the input file and split it into two sections */
944         while (fgets(in_line, sizeof in_line, ifp)) {
945             if (d_filter(in_line)) continue;
946             if (*in_line > ' ') {       /* got an entry name */
947                 /* first finish previous entry */
948                 if (line_cnt)  Fprintf(ofp, "%d\n", line_cnt),  line_cnt = 0;
949                 /* output the entry name */
950                 (void) fputs(in_line, ofp);
951                 entry_cnt++;            /* update number of entries */
952             } else if (entry_cnt) {     /* got some descriptive text */
953                 /* update previous entry with current text offset */
954                 if (!line_cnt)  Fprintf(ofp, "%ld,", ftell(tfp));
955                 /* save the text line in the scratch file */
956                 (void) fputs(in_line, tfp);
957                 line_cnt++;             /* update line counter */
958             }
959         }
960         /* output an end marker and then record the current position */
961         if (line_cnt)  Fprintf(ofp, "%d\n", line_cnt);
962         Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0);
963         txt_offset = ftell(ofp);
964         Fclose(ifp);            /* all done with original input file */
965
966         /* reprocess the scratch file; 1st format an error msg, just in case */
967         Sprintf(in_line, "rewind of \"%s\"", tempfile);
968         if (rewind(tfp) != 0)  goto dead_data;
969         /* copy all lines of text from the scratch file into the output file */
970         while (fgets(in_line, sizeof in_line, tfp))
971             (void) fputs(in_line, ofp);
972
973         /* finished with scratch file */
974         Fclose(tfp);
975         Unlink(tempfile);       /* remove it */
976
977         /* update the first record of the output file; prepare error msg 1st */
978         Sprintf(in_line, "rewind of \"%s\"", filename);
979         ok = (rewind(ofp) == 0);
980         if (ok) {
981            Sprintf(in_line, "header rewrite of \"%s\"", filename);
982            ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, txt_offset) >= 0);
983         }
984         if (!ok) {
985 dead_data:  perror(in_line);    /* report the problem */
986             /* close and kill the aborted output file, then give up */
987             Fclose(ofp);
988             Unlink(filename);
989             exit(EXIT_FAILURE);
990         }
991
992         /* all done */
993         Fclose(ofp);
994
995         return;
996 }
997
998 /* routine to decide whether to discard something from oracles.txt */
999 static boolean
1000 h_filter(line)
1001     char *line;
1002 {
1003     static boolean skip = FALSE;
1004     char tag[sizeof in_line];
1005
1006     SpinCursor(3);
1007
1008     if (*line == '#') return TRUE;      /* ignore comment lines */
1009     if (sscanf(line, "----- %s", tag) == 1) {
1010         skip = FALSE;
1011 #ifndef SINKS
1012         if (!strcmp(tag, "SINKS")) skip = TRUE;
1013 #endif
1014 #ifndef ELBERETH
1015         if (!strcmp(tag, "ELBERETH")) skip = TRUE;
1016 #endif
1017     } else if (skip && !strncmp(line, "-----", 5))
1018         skip = FALSE;
1019     return skip;
1020 }
1021
1022 static const char *special_oracle[] = {
1023         "\"...it is rather disconcerting to be confronted with the",
1024         "following theorem from [Baker, Gill, and Solovay, 1975].",
1025         "",
1026         "Theorem 7.18  There exist recursive languages A and B such that",
1027         "  (1)  P(A) == NP(A), and",
1028         "  (2)  P(B) != NP(B)",
1029         "",
1030         "This provides impressive evidence that the techniques that are",
1031         "currently available will not suffice for proving that P != NP or          ",
1032         "that P == NP.\"  [Garey and Johnson, p. 185.]"
1033 };
1034
1035 /*
1036    The oracle file consists of a "do not edit" comment, a decimal count N
1037    and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
1038    records, separated by "---" lines.  The first oracle is a special case.
1039    The input data contains just those multi-line records, separated by
1040    "-----" lines.
1041  */
1042
1043 void
1044 do_oracles()
1045 {
1046         char    infile[60], tempfile[60];
1047         boolean in_oracle, ok;
1048         long    txt_offset, offset, fpos;
1049         int     oracle_cnt;
1050         register int i;
1051
1052         Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp");
1053         filename[0]='\0';
1054 #ifdef FILE_PREFIX
1055         Strcat(filename, file_prefix);
1056 #endif
1057         Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE);
1058         Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE);
1059         Strcat(infile, ".txt");
1060         if (!(ifp = fopen(infile, RDTMODE))) {
1061                 perror(infile);
1062                 exit(EXIT_FAILURE);
1063         }
1064         if (!(ofp = fopen(filename, WRTMODE))) {
1065                 perror(filename);
1066                 Fclose(ifp);
1067                 exit(EXIT_FAILURE);
1068         }
1069         if (!(tfp = fopen(tempfile, WRTMODE))) {        /* oracles.tmp */
1070                 perror(tempfile);
1071                 Fclose(ifp);
1072                 Fclose(ofp);
1073                 Unlink(filename);
1074                 exit(EXIT_FAILURE);
1075         }
1076
1077         /* output a dummy header record; we'll rewind and overwrite it later */
1078         Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0);
1079
1080         /* handle special oracle; it must come first */
1081         (void) fputs("---\n", tfp);
1082         Fprintf(ofp, "%05lx\n", ftell(tfp));  /* start pos of special oracle */
1083         for (i = 0; i < SIZE(special_oracle); i++) {
1084             (void) fputs(xcrypt(special_oracle[i]), tfp);
1085             (void) fputc('\n', tfp);
1086         }
1087         SpinCursor(3);
1088
1089         oracle_cnt = 1;
1090         (void) fputs("---\n", tfp);
1091         Fprintf(ofp, "%05lx\n", ftell(tfp));    /* start pos of first oracle */
1092         in_oracle = FALSE;
1093
1094         while (fgets(in_line, sizeof in_line, ifp)) {
1095             SpinCursor(3);
1096
1097             if (h_filter(in_line)) continue;
1098             if (!strncmp(in_line, "-----", 5)) {
1099                 if (!in_oracle) continue;
1100                 in_oracle = FALSE;
1101                 oracle_cnt++;
1102                 (void) fputs("---\n", tfp);
1103                 Fprintf(ofp, "%05lx\n", ftell(tfp));
1104                 /* start pos of this oracle */
1105             } else {
1106                 in_oracle = TRUE;
1107                 (void) fputs(xcrypt(in_line), tfp);
1108             }
1109         }
1110
1111         if (in_oracle) {        /* need to terminate last oracle */
1112             oracle_cnt++;
1113             (void) fputs("---\n", tfp);
1114             Fprintf(ofp, "%05lx\n", ftell(tfp));        /* eof position */
1115         }
1116
1117         /* record the current position */
1118         txt_offset = ftell(ofp);
1119         Fclose(ifp);            /* all done with original input file */
1120
1121         /* reprocess the scratch file; 1st format an error msg, just in case */
1122         Sprintf(in_line, "rewind of \"%s\"", tempfile);
1123         if (rewind(tfp) != 0)  goto dead_data;
1124         /* copy all lines of text from the scratch file into the output file */
1125         while (fgets(in_line, sizeof in_line, tfp))
1126             (void) fputs(in_line, ofp);
1127
1128         /* finished with scratch file */
1129         Fclose(tfp);
1130         Unlink(tempfile);       /* remove it */
1131
1132         /* update the first record of the output file; prepare error msg 1st */
1133         Sprintf(in_line, "rewind of \"%s\"", filename);
1134         ok = (rewind(ofp) == 0);
1135         if (ok) {
1136             Sprintf(in_line, "header rewrite of \"%s\"", filename);
1137             ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >=0);
1138         }
1139         if (ok) {
1140             Sprintf(in_line, "data rewrite of \"%s\"", filename);
1141             for (i = 0; i <= oracle_cnt; i++) {
1142 #ifndef VMS     /* alpha/vms v1.0; this fflush seems to confuse ftell */
1143                 if (!(ok = (fflush(ofp) == 0))) break;
1144 #endif
1145                 if (!(ok = (fpos = ftell(ofp)) >= 0)) break;
1146                 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
1147                 if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1))) break;
1148 #ifdef MAC
1149 # ifdef __MWERKS__
1150                 /*
1151                 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
1152                 (ANSI C Libraries) needs this rewind or else the fprintf
1153                 stops working.  This may also be true for CW11, but has
1154                 never been checked.
1155                 */
1156                 rewind(ofp);
1157 # endif
1158 #endif
1159                 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
1160                 if (!(ok = (fprintf(ofp, "%05lx\n", offset + txt_offset) >= 0)))
1161                     break;
1162             }
1163         }
1164         if (!ok) {
1165 dead_data:  perror(in_line);    /* report the problem */
1166             /* close and kill the aborted output file, then give up */
1167             Fclose(ofp);
1168             Unlink(filename);
1169             exit(EXIT_FAILURE);
1170         }
1171
1172         /* all done */
1173         Fclose(ofp);
1174
1175         return;
1176 }
1177
1178
1179 static  struct deflist {
1180
1181         const char      *defname;
1182         boolean true_or_false;
1183 } deflist[] = {
1184 #ifdef REINCARNATION
1185               { "REINCARNATION", TRUE },
1186 #else
1187               { "REINCARNATION", FALSE },
1188 #endif
1189               { 0, 0 } };
1190
1191 static int
1192 check_control(s)
1193         char    *s;
1194 {
1195         int     i;
1196
1197         if(s[0] != '%') return(-1);
1198
1199         for(i = 0; deflist[i].defname; i++)
1200             if(!strncmp(deflist[i].defname, s+1, strlen(deflist[i].defname)))
1201                 return(i);
1202
1203         return(-1);
1204 }
1205
1206 static char *
1207 without_control(s)
1208         char *s;
1209 {
1210         return(s + 1 + strlen(deflist[check_control(in_line)].defname));
1211 }
1212
1213 void
1214 do_dungeon()
1215 {
1216         int rcnt = 0;
1217
1218         Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE);
1219         if (!(ifp = fopen(filename, RDTMODE))) {
1220                 perror(filename);
1221                 exit(EXIT_FAILURE);
1222         }
1223         filename[0]='\0';
1224 #ifdef FILE_PREFIX
1225         Strcat(filename, file_prefix);
1226 #endif
1227         Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE);
1228         if (!(ofp = fopen(filename, WRTMODE))) {
1229                 perror(filename);
1230                 exit(EXIT_FAILURE);
1231         }
1232         Fprintf(ofp,Dont_Edit_Data);
1233
1234         while (fgets(in_line, sizeof in_line, ifp) != 0) {
1235             SpinCursor(3);
1236
1237             rcnt++;
1238             if(in_line[0] == '#') continue;     /* discard comments */
1239 recheck:
1240             if(in_line[0] == '%') {
1241                 int i = check_control(in_line);
1242                 if(i >= 0) {
1243                     if(!deflist[i].true_or_false)  {
1244                         while (fgets(in_line, sizeof in_line, ifp) != 0)
1245                             if(check_control(in_line) != i) goto recheck;
1246                     } else
1247                         (void) fputs(without_control(in_line),ofp);
1248                 } else {
1249                     Fprintf(stderr, "Unknown control option '%s' in file %s at line %d.\n",
1250                             in_line, DGN_I_FILE, rcnt);
1251                     exit(EXIT_FAILURE);
1252                 }
1253             } else
1254                 (void) fputs(in_line,ofp);
1255         }
1256         Fclose(ifp);
1257         Fclose(ofp);
1258
1259         return;
1260 }
1261
1262 static boolean
1263 ranged_attk(ptr)        /* returns TRUE if monster can attack at range */
1264         register struct permonst *ptr;
1265 {
1266         register int    i, j;
1267         register int atk_mask = (1<<AT_BREA) | (1<<AT_SPIT) | (1<<AT_GAZE);
1268
1269         for(i = 0; i < NATTK; i++) {
1270             if((j=ptr->mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1<<j)))
1271                 return TRUE;
1272         }
1273
1274         return(FALSE);
1275 }
1276
1277 /* This routine is designed to return an integer value which represents
1278  * an approximation of monster strength.  It uses a similar method of
1279  * determination as "experience()" to arrive at the strength.
1280  */
1281 static int
1282 mstrength(ptr)
1283 struct permonst *ptr;
1284 {
1285         int     i, tmp2, n, tmp = ptr->mlevel;
1286
1287         if(tmp > 49)            /* special fixed hp monster */
1288             tmp = 2*(tmp - 6) / 4;
1289
1290 /*      For creation in groups */
1291         n = (!!(ptr->geno & G_SGROUP));
1292         n += (!!(ptr->geno & G_LGROUP)) << 1;
1293
1294 /*      For ranged attacks */
1295         if (ranged_attk(ptr)) n++;
1296
1297 /*      For higher ac values */
1298         n += (ptr->ac < 4);
1299         n += (ptr->ac < 0);
1300
1301 /*      For very fast monsters */
1302         n += (ptr->mmove >= 18);
1303
1304 /*      For each attack and "special" attack */
1305         for(i = 0; i < NATTK; i++) {
1306
1307             tmp2 = ptr->mattk[i].aatyp;
1308             n += (tmp2 > 0);
1309             n += (tmp2 == AT_MAGC);
1310             n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG));
1311         }
1312
1313 /*      For each "special" damage type */
1314         for(i = 0; i < NATTK; i++) {
1315
1316             tmp2 = ptr->mattk[i].adtyp;
1317             if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST)
1318                 || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE))
1319                         n += 2;
1320             else if (strcmp(ptr->mname, "grid bug")) n += (tmp2 != AD_PHYS);
1321             n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23);
1322         }
1323
1324 /*      Leprechauns are special cases.  They have many hit dice so they
1325         can hit and are hard to kill, but they don't really do much damage. */
1326         if (!strcmp(ptr->mname, "leprechaun")) n -= 2;
1327
1328 /*      Finally, adjust the monster level  0 <= n <= 24 (approx.) */
1329         if(n == 0) tmp--;
1330         else if(n >= 6) tmp += ( n / 2 );
1331         else tmp += ( n / 3 + 1);
1332
1333         return((tmp >= 0) ? tmp : 0);
1334 }
1335
1336 void
1337 do_monstr()
1338 {
1339     register struct permonst *ptr;
1340     register int i, j;
1341
1342     /*
1343      * create the source file, "monstr.c"
1344      */
1345     filename[0]='\0';
1346 #ifdef FILE_PREFIX
1347     Strcat(filename, file_prefix);
1348 #endif
1349     Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C);
1350     if (!(ofp = fopen(filename, WRTMODE))) {
1351         perror(filename);
1352         exit(EXIT_FAILURE);
1353     }
1354     Fprintf(ofp,Dont_Edit_Code);
1355     Fprintf(ofp,"#include \"config.h\"\n");
1356     Fprintf(ofp,"\nconst int monstr[] = {\n");
1357     for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) {
1358
1359         SpinCursor(3);
1360
1361         i = mstrength(ptr);
1362         Fprintf(ofp,"%2d,%c", i, (++j & 15) ? ' ' : '\n');
1363     }
1364     /* might want to insert a final 0 entry here instead of just newline */
1365     Fprintf(ofp,"%s};\n", (j & 15) ? "\n" : "");
1366
1367     Fprintf(ofp,"\nvoid NDECL(monstr_init);\n");
1368     Fprintf(ofp,"\nvoid\n");
1369     Fprintf(ofp,"monstr_init()\n");
1370     Fprintf(ofp,"{\n");
1371     Fprintf(ofp,"    return;\n");
1372     Fprintf(ofp,"}\n");
1373     Fprintf(ofp,"\n/*monstr.c*/\n");
1374
1375     Fclose(ofp);
1376     return;
1377 }
1378
1379 void
1380 do_permonst()
1381 {
1382         int     i;
1383         char    *c, *nam;
1384
1385         filename[0]='\0';
1386 #ifdef FILE_PREFIX
1387         Strcat(filename, file_prefix);
1388 #endif
1389         Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE);
1390         if (!(ofp = fopen(filename, WRTMODE))) {
1391                 perror(filename);
1392                 exit(EXIT_FAILURE);
1393         }
1394         Fprintf(ofp,"/*\tSCCS Id: @(#)pm.h\t3.4\t2002/02/03 */\n\n");
1395         Fprintf(ofp,Dont_Edit_Code);
1396         Fprintf(ofp,"#ifndef PM_H\n#define PM_H\n");
1397
1398         if (strcmp(mons[0].mname, "playermon") != 0)
1399                 Fprintf(ofp,"\n#define\tPM_PLAYERMON\t(-1)");
1400
1401         for (i = 0; mons[i].mlet; i++) {
1402                 SpinCursor(3);
1403
1404                 Fprintf(ofp,"\n#define\tPM_");
1405                 if (mons[i].mlet == S_HUMAN &&
1406                                 !strncmp(mons[i].mname, "were", 4))
1407                     Fprintf(ofp, "HUMAN_");
1408                 for (nam = c = tmpdup(mons[i].mname); *c; c++)
1409                     if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
1410                     else if (*c < 'A' || *c > 'Z') *c = '_';
1411                 Fprintf(ofp,"%s\t%d", nam, i);
1412         }
1413         Fprintf(ofp,"\n\n#define\tNUMMONS\t%d\n", i);
1414         Fprintf(ofp,"\n#endif /* PM_H */\n");
1415         Fclose(ofp);
1416         return;
1417 }
1418
1419
1420 /*      Start of Quest text file processing. */
1421 #include "qtext.h"
1422
1423 static struct qthdr     qt_hdr;
1424 static struct msghdr    msg_hdr[N_HDR];
1425 static struct qtmsg     *curr_msg;
1426
1427 static int      qt_line;
1428
1429 static boolean  in_msg;
1430 #define NO_MSG  1       /* strlen of a null line returned by fgets() */
1431
1432 static boolean
1433 qt_comment(s)
1434         char *s;
1435 {
1436         if(s[0] == '#') return(TRUE);
1437         return((boolean)(!in_msg  && strlen(s) == NO_MSG));
1438 }
1439
1440 static boolean
1441 qt_control(s)
1442         char *s;
1443 {
1444         return((boolean)(s[0] == '%' && (s[1] == 'C' || s[1] == 'E')));
1445 }
1446
1447 static int
1448 get_hdr (code)
1449         char *code;
1450 {
1451         int     i;
1452
1453         for(i = 0; i < qt_hdr.n_hdr; i++)
1454             if(!strncmp(code, qt_hdr.id[i], LEN_HDR)) return (++i);
1455
1456         return(0);
1457 }
1458
1459 static boolean
1460 new_id (code)
1461         char *code;
1462 {
1463         if(qt_hdr.n_hdr >= N_HDR) {
1464             Fprintf(stderr, OUT_OF_HEADERS, qt_line);
1465             return(FALSE);
1466         }
1467
1468         strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR);
1469         msg_hdr[qt_hdr.n_hdr].n_msg = 0;
1470         qt_hdr.offset[qt_hdr.n_hdr++] = 0L;
1471         return(TRUE);
1472 }
1473
1474 static boolean
1475 known_msg(num, id)
1476         int num, id;
1477 {
1478         int i;
1479
1480         for(i = 0; i < msg_hdr[num].n_msg; i++)
1481             if(msg_hdr[num].qt_msg[i].msgnum == id) return(TRUE);
1482
1483         return(FALSE);
1484 }
1485
1486
1487 static void
1488 new_msg(s, num, id)
1489         char *s;
1490         int num, id;
1491 {
1492         struct  qtmsg   *qt_msg;
1493
1494         if(msg_hdr[num].n_msg >= N_MSG) {
1495                 Fprintf(stderr, OUT_OF_MESSAGES, qt_line);
1496         } else {
1497                 qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]);
1498                 qt_msg->msgnum = id;
1499                 qt_msg->delivery = s[2];
1500                 qt_msg->offset = qt_msg->size = 0L;
1501
1502                 curr_msg = qt_msg;
1503         }
1504 }
1505
1506 static void
1507 do_qt_control(s)
1508         char *s;
1509 {
1510         char code[BUFSZ];
1511         int num, id = 0;
1512
1513         switch(s[1]) {
1514
1515             case 'C':   if(in_msg) {
1516                             Fprintf(stderr, CREC_IN_MSG, qt_line);
1517                             break;
1518                         } else {
1519                             in_msg = TRUE;
1520                             if (sscanf(&s[4], "%s %5d", code, &id) != 2) {
1521                                 Fprintf(stderr, UNREC_CREC, qt_line);
1522                                 break;
1523                             }
1524                             num = get_hdr(code);
1525                             if (!num && !new_id(code))
1526                                 break;
1527                             num = get_hdr(code)-1;
1528                             if(known_msg(num, id))
1529                                 Fprintf(stderr, DUP_MSG, qt_line);
1530                             else new_msg(s, num, id);
1531                         }
1532                         break;
1533
1534             case 'E':   if(!in_msg) {
1535                             Fprintf(stderr, END_NOT_IN_MSG, qt_line);
1536                             break;
1537                         } else in_msg = FALSE;
1538                         break;
1539
1540             default:    Fprintf(stderr, UNREC_CREC, qt_line);
1541                         break;
1542         }
1543 }
1544
1545 static void
1546 do_qt_text(s)
1547         char *s;
1548 {
1549         if (!in_msg) {
1550             Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line);
1551         }
1552         curr_msg->size += strlen(s);
1553         return;
1554 }
1555
1556 static void
1557 adjust_qt_hdrs()
1558 {
1559         int     i, j;
1560         long count = 0L, hdr_offset = sizeof(int) +
1561                         (sizeof(char)*LEN_HDR + sizeof(long)) * qt_hdr.n_hdr;
1562
1563         for(i = 0; i < qt_hdr.n_hdr; i++) {
1564             qt_hdr.offset[i] = hdr_offset;
1565             hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg;
1566         }
1567
1568         for(i = 0; i < qt_hdr.n_hdr; i++)
1569             for(j = 0; j < msg_hdr[i].n_msg; j++) {
1570
1571                 msg_hdr[i].qt_msg[j].offset = hdr_offset + count;
1572                 count += msg_hdr[i].qt_msg[j].size;
1573             }
1574         return;
1575 }
1576
1577 static void
1578 put_qt_hdrs()
1579 {
1580         int     i;
1581
1582         /*
1583          *      The main header record.
1584          */
1585 #ifdef DEBUG
1586         Fprintf(stderr, "%ld: header info.\n", ftell(ofp));
1587 #endif
1588         (void) fwrite((genericptr_t)&(qt_hdr.n_hdr), sizeof(int), 1, ofp);
1589         (void) fwrite((genericptr_t)&(qt_hdr.id[0][0]), sizeof(char)*LEN_HDR,
1590                                                         qt_hdr.n_hdr, ofp);
1591         (void) fwrite((genericptr_t)&(qt_hdr.offset[0]), sizeof(long),
1592                                                         qt_hdr.n_hdr, ofp);
1593 #ifdef DEBUG
1594         for(i = 0; i < qt_hdr.n_hdr; i++)
1595                 Fprintf(stderr, "%c @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]);
1596
1597         Fprintf(stderr, "\n");
1598 #endif
1599
1600         /*
1601          *      The individual class headers.
1602          */
1603         for(i = 0; i < qt_hdr.n_hdr; i++) {
1604
1605 #ifdef DEBUG
1606             Fprintf(stderr, "%ld: %c header info.\n", ftell(ofp),
1607                     qt_hdr.id[i]);
1608 #endif
1609             (void) fwrite((genericptr_t)&(msg_hdr[i].n_msg), sizeof(int),
1610                                                         1, ofp);
1611             (void) fwrite((genericptr_t)&(msg_hdr[i].qt_msg[0]),
1612                             sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp);
1613 #ifdef DEBUG
1614             { int j;
1615               for(j = 0; j < msg_hdr[i].n_msg; j++)
1616                 Fprintf(stderr, "msg %d @ %ld (%ld)\n",
1617                         msg_hdr[i].qt_msg[j].msgnum,
1618                         msg_hdr[i].qt_msg[j].offset,
1619                         msg_hdr[i].qt_msg[j].size);
1620             }
1621 #endif
1622         }
1623 }
1624
1625 void
1626 do_questtxt()
1627 {
1628         Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE);
1629         if(!(ifp = fopen(filename, RDTMODE))) {
1630                 perror(filename);
1631                 exit(EXIT_FAILURE);
1632         }
1633
1634         filename[0]='\0';
1635 #ifdef FILE_PREFIX
1636         Strcat(filename, file_prefix);
1637 #endif
1638         Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE);
1639         if(!(ofp = fopen(filename, WRBMODE))) {
1640                 perror(filename);
1641                 Fclose(ifp);
1642                 exit(EXIT_FAILURE);
1643         }
1644
1645         qt_hdr.n_hdr = 0;
1646         qt_line = 0;
1647         in_msg = FALSE;
1648
1649         while (fgets(in_line, 80, ifp) != 0) {
1650             SpinCursor (3);
1651
1652             qt_line++;
1653             if(qt_control(in_line)) do_qt_control(in_line);
1654             else if(qt_comment(in_line)) continue;
1655             else                    do_qt_text(in_line);
1656         }
1657
1658         (void) rewind(ifp);
1659         in_msg = FALSE;
1660         adjust_qt_hdrs();
1661         put_qt_hdrs();
1662         while (fgets(in_line, 80, ifp) != 0) {
1663
1664                 if(qt_control(in_line)) {
1665                     in_msg = (in_line[1] == 'C');
1666                     continue;
1667                 } else if(qt_comment(in_line)) continue;
1668 #ifdef DEBUG
1669                 Fprintf(stderr, "%ld: %s", ftell(stdout), in_line);
1670 #endif
1671                 (void) fputs(xcrypt(in_line), ofp);
1672         }
1673         Fclose(ifp);
1674         Fclose(ofp);
1675         return;
1676 }
1677
1678
1679 static  char    temp[32];
1680
1681 static char *
1682 limit(name,pref)        /* limit a name to 30 characters length */
1683 char    *name;
1684 int     pref;
1685 {
1686         (void) strncpy(temp, name, pref ? 26 : 30);
1687         temp[pref ? 26 : 30] = 0;
1688         return temp;
1689 }
1690
1691 void
1692 do_objs()
1693 {
1694         int i, sum = 0;
1695         char *c, *objnam;
1696         int nspell = 0;
1697         int prefix = 0;
1698         char class = '\0';
1699         boolean sumerr = FALSE;
1700
1701         filename[0]='\0';
1702 #ifdef FILE_PREFIX
1703         Strcat(filename, file_prefix);
1704 #endif
1705         Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE);
1706         if (!(ofp = fopen(filename, WRTMODE))) {
1707                 perror(filename);
1708                 exit(EXIT_FAILURE);
1709         }
1710         Fprintf(ofp,"/*\tSCCS Id: @(#)onames.h\t3.4\t2002/02/03 */\n\n");
1711         Fprintf(ofp,Dont_Edit_Code);
1712         Fprintf(ofp,"#ifndef ONAMES_H\n#define ONAMES_H\n\n");
1713
1714         for(i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) {
1715                 SpinCursor(3);
1716
1717                 objects[i].oc_name_idx = objects[i].oc_descr_idx = i;   /* init */
1718                 if (!(objnam = tmpdup(OBJ_NAME(objects[i])))) continue;
1719
1720                 /* make sure probabilities add up to 1000 */
1721                 if(objects[i].oc_class != class) {
1722                         if (sum && sum != 1000) {
1723                             Fprintf(stderr, "prob error for class %d (%d%%)",
1724                                     class, sum);
1725                             (void) fflush(stderr);
1726                             sumerr = TRUE;
1727                         }
1728                         class = objects[i].oc_class;
1729                         sum = 0;
1730                 }
1731
1732                 for (c = objnam; *c; c++)
1733                     if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
1734                     else if (*c < 'A' || *c > 'Z') *c = '_';
1735
1736                 switch (class) {
1737                     case WAND_CLASS:
1738                         Fprintf(ofp,"#define\tWAN_"); prefix = 1; break;
1739                     case RING_CLASS:
1740                         Fprintf(ofp,"#define\tRIN_"); prefix = 1; break;
1741                     case POTION_CLASS:
1742                         Fprintf(ofp,"#define\tPOT_"); prefix = 1; break;
1743                     case SPBOOK_CLASS:
1744                         Fprintf(ofp,"#define\tSPE_"); prefix = 1; nspell++; break;
1745                     case SCROLL_CLASS:
1746                         Fprintf(ofp,"#define\tSCR_"); prefix = 1; break;
1747                     case AMULET_CLASS:
1748                         /* avoid trouble with stupid C preprocessors */
1749                         Fprintf(ofp,"#define\t");
1750                         if(objects[i].oc_material == PLASTIC) {
1751                             Fprintf(ofp,"FAKE_AMULET_OF_YENDOR\t%d\n", i);
1752                             prefix = -1;
1753                             break;
1754                         }
1755                         break;
1756                     case GEM_CLASS:
1757                         /* avoid trouble with stupid C preprocessors */
1758                         if(objects[i].oc_material == GLASS) {
1759                             Fprintf(ofp,"/* #define\t%s\t%d */\n",
1760                                                         objnam, i);
1761                             prefix = -1;
1762                             break;
1763                         }
1764                     default:
1765                         Fprintf(ofp,"#define\t");
1766                 }
1767                 if (prefix >= 0)
1768                         Fprintf(ofp,"%s\t%d\n", limit(objnam, prefix), i);
1769                 prefix = 0;
1770
1771                 sum += objects[i].oc_prob;
1772         }
1773
1774         /* check last set of probabilities */
1775         if (sum && sum != 1000) {
1776             Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
1777             (void) fflush(stderr);
1778             sumerr = TRUE;
1779         }
1780
1781         Fprintf(ofp,"#define\tLAST_GEM\t(JADE)\n");
1782         Fprintf(ofp,"#define\tMAXSPELL\t%d\n", nspell+1);
1783         Fprintf(ofp,"#define\tNUM_OBJECTS\t%d\n", i);
1784
1785         Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n");
1786
1787         for (i = 1; artifact_names[i]; i++) {
1788                 SpinCursor(3);
1789
1790                 for (c = objnam = tmpdup(artifact_names[i]); *c; c++)
1791                     if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
1792                     else if (*c < 'A' || *c > 'Z') *c = '_';
1793
1794                 if (!strncmp(objnam, "THE_", 4))
1795                         objnam += 4;
1796 #ifdef TOURIST
1797                 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
1798                 if (!strncmp(objnam, "PLATINUM_", 9))
1799                         objnam += 9;
1800 #endif
1801                 Fprintf(ofp,"#define\tART_%s\t%d\n", limit(objnam, 1), i);
1802         }
1803
1804         Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i-1);
1805         Fprintf(ofp,"\n#endif /* ONAMES_H */\n");
1806         Fclose(ofp);
1807         if (sumerr) exit(EXIT_FAILURE);
1808         return;
1809 }
1810
1811 static char *
1812 tmpdup(str)
1813 const char *str;
1814 {
1815         static char buf[128];
1816
1817         if (!str) return (char *)0;
1818         (void)strncpy(buf, str, 127);
1819         return buf;
1820 }
1821
1822 static char *
1823 eos(str)
1824 char *str;
1825 {
1826     while (*str) str++;
1827     return str;
1828 }
1829
1830 /*
1831  * macro used to control vision algorithms:
1832  *      VISION_TABLES => generate tables
1833  */
1834
1835 void
1836 do_vision()
1837 {
1838 #ifdef VISION_TABLES
1839     int i, j;
1840
1841     /* Everything is clear.  xclear may be malloc'ed.
1842      * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
1843      */
1844     for (i = 0; i < MAX_ROW; i++)
1845         for (j = 0; j < MAX_COL; j++)
1846             if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH)
1847                 xclear[i][j] = '\000';
1848             else
1849                 xclear[i][j] = '\001';
1850 #endif /* VISION_TABLES */
1851
1852     SpinCursor(3);
1853
1854     /*
1855      * create the include file, "vis_tab.h"
1856      */
1857     filename[0]='\0';
1858 #ifdef FILE_PREFIX
1859     Strcat(filename, file_prefix);
1860 #endif
1861     Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
1862     if (!(ofp = fopen(filename, WRTMODE))) {
1863         perror(filename);
1864         exit(EXIT_FAILURE);
1865     }
1866     Fprintf(ofp,Dont_Edit_Code);
1867     Fprintf(ofp,"#ifdef VISION_TABLES\n");
1868 #ifdef VISION_TABLES
1869     H_close_gen();
1870     H_far_gen();
1871 #endif /* VISION_TABLES */
1872     Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
1873     Fclose(ofp);
1874
1875     SpinCursor(3);
1876
1877     /*
1878      * create the source file, "vis_tab.c"
1879      */
1880     filename[0]='\0';
1881 #ifdef FILE_PREFIX
1882     Strcat(filename, file_prefix);
1883 #endif
1884     Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C);
1885     if (!(ofp = fopen(filename, WRTMODE))) {
1886         perror(filename);
1887         Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
1888         Unlink(filename);
1889         exit(EXIT_FAILURE);
1890     }
1891     Fprintf(ofp,Dont_Edit_Code);
1892     Fprintf(ofp,"#include \"config.h\"\n");
1893     Fprintf(ofp,"#ifdef VISION_TABLES\n");
1894     Fprintf(ofp,"#include \"vis_tab.h\"\n");
1895
1896     SpinCursor(3);
1897
1898 #ifdef VISION_TABLES
1899     C_close_gen();
1900     C_far_gen();
1901     Fprintf(ofp,"\nvoid vis_tab_init() { return; }\n");
1902 #endif /* VISION_TABLES */
1903
1904     SpinCursor(3);
1905
1906     Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
1907     Fprintf(ofp,"\n/*vis_tab.c*/\n");
1908
1909     Fclose(ofp);
1910     return;
1911 }
1912
1913 #ifdef VISION_TABLES
1914
1915 /*--------------  vision tables  --------------*\
1916  *
1917  *  Generate the close and far tables.  This is done by setting up a
1918  *  fake dungeon and moving our source to different positions relative
1919  *  to a block and finding the first/last visible position.  The fake
1920  *  dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
1921  *  by BLOCK_WIDTH) is blocked.  Then we move the source around relative
1922  *  to the corner of the block.  For each new position of the source
1923  *  we check positions on rows "kittycorner" from the source.  We check
1924  *  positions until they are either in sight or out of sight (depends on
1925  *  which table we are generating).  The picture below shows the setup
1926  *  for the generation of the close table.  The generation of the far
1927  *  table would switch the quadrants of the '@' and the "Check rows
1928  *  here".
1929  *
1930  *
1931  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1932  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1933  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
1934  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1935  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1936  *  ...............................
1937  *  ...............................
1938  *  .........@.....................
1939  *  ...............................
1940  *
1941  *      Table generation figure (close_table).  The 'X's are blocked points.
1942  *      The 'B' is a special blocked point.  The '@' is the source.  The ','s
1943  *      are the target area.  The '.' are just open areas.
1944  *
1945  *
1946  *  Example usage of close_table[][][].
1947  *
1948  *  The table is as follows:
1949  *
1950  *      dy = |row of '@' - row of 'B'|  - 1
1951  *      dx = |col of '@' - col of 'B'|
1952  *
1953  *  The first indices are the deltas from the source '@' and the block 'B'.
1954  *  You must check for the value inside the abs value bars being zero.  If
1955  *  so then the block is on the same row and you don't need to do a table
1956  *  lookup.  The last value:
1957  *
1958  *      dcy = |row of block - row to be checked|
1959  *
1960  *  Is the value of the first visible spot on the check row from the
1961  *  block column.  So
1962  *
1963  *  first visible col = close_table[dy][dx][dcy] + col of 'B'
1964  *
1965 \*--------------  vision tables  --------------*/
1966
1967 static void
1968 H_close_gen()
1969 {
1970     Fprintf(ofp,"\n/* Close */\n");
1971     Fprintf(ofp,"#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
1972             TEST_HEIGHT-1);
1973     Fprintf(ofp,"#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
1974             TEST_WIDTH);
1975     Fprintf(ofp,"#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
1976             TEST_HEIGHT);
1977     Fprintf(ofp,"typedef struct {\n");
1978     Fprintf(ofp,"    unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
1979     Fprintf(ofp,"} close2d;\n");
1980     Fprintf(ofp,"extern close2d close_table[CLOSE_MAX_SB_DY];\n");
1981     return;
1982 }
1983
1984 static void
1985 H_far_gen()
1986 {
1987     Fprintf(ofp,"\n/* Far */\n");
1988     Fprintf(ofp,"#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
1989             TEST_HEIGHT);
1990     Fprintf(ofp,"#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
1991             TEST_WIDTH-1);
1992     Fprintf(ofp,"#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
1993             TEST_HEIGHT-1);
1994     Fprintf(ofp,"typedef struct {\n");
1995     Fprintf(ofp,"    unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
1996     Fprintf(ofp,"} far2d;\n");
1997     Fprintf(ofp,"extern far2d far_table[FAR_MAX_SB_DY];\n");
1998     return;
1999 }
2000
2001 static void
2002 C_close_gen()
2003 {
2004     int i,dx,dy;
2005     int src_row, src_col;       /* source */
2006     int block_row, block_col;   /* block */
2007     int this_row;
2008     int no_more;
2009     const char *delim;
2010
2011     block_row = BLOCK_HEIGHT-1;
2012     block_col = BLOCK_WIDTH-1;
2013
2014     Fprintf(ofp,"\n#ifndef FAR_TABLE_ONLY\n");
2015     Fprintf(ofp,"\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
2016 #ifndef no_vision_progress
2017     Fprintf(stderr,"\nclose:");
2018 #endif
2019
2020     for (dy = 1; dy < TEST_HEIGHT; dy++) {
2021         src_row = block_row + dy;
2022         Fprintf(ofp, "/* DY = %2d (- 1)*/\n  {{\n", dy);
2023 #ifndef no_vision_progress
2024         Fprintf(stderr," %2d",dy),  (void)fflush(stderr);
2025 #endif
2026         for (dx = 0; dx < TEST_WIDTH; dx++) {
2027             src_col = block_col - dx;
2028             Fprintf(ofp, "  /*%2d*/ {", dx);
2029
2030             no_more = 0;
2031             for (this_row = 0; this_row < TEST_HEIGHT; this_row++) {
2032                 delim = (this_row < TEST_HEIGHT - 1) ? "," : "";
2033                 if (no_more) {
2034                     Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim);
2035                     continue;
2036                 }
2037                 SpinCursor(3);
2038
2039                 /* Find the first column that we can see. */
2040                 for (i = block_col+1; i < MAX_COL; i++) {
2041                     if (clear_path(src_row,src_col,block_row-this_row,i))
2042                         break;
2043                 }
2044
2045                 if (i == MAX_COL) no_more = 1;
2046                 Fprintf(ofp, "%2d%s", i - block_col, delim);
2047             }
2048             Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
2049         }
2050         Fprintf(ofp,"  }},\n");
2051     }
2052
2053     Fprintf(ofp,"}; /* close_table[] */\n");            /* closing brace for table */
2054     Fprintf(ofp,"#endif /* !FAR_TABLE_ONLY */\n");
2055 #ifndef no_vision_progress
2056     Fprintf(stderr,"\n");
2057 #endif
2058     return;
2059 }
2060
2061 static void
2062 C_far_gen()
2063 {
2064     int i,dx,dy;
2065     int src_row, src_col;       /* source */
2066     int block_row, block_col;   /* block */
2067     int this_row;
2068     const char *delim;
2069
2070     block_row = BLOCK_HEIGHT-1;
2071     block_col = BLOCK_WIDTH-1;
2072
2073     Fprintf(ofp,"\n#ifndef CLOSE_TABLE_ONLY\n");
2074     Fprintf(ofp,"\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
2075 #ifndef no_vision_progress
2076     Fprintf(stderr,"\n_far_:");
2077 #endif
2078
2079     for (dy = 0; dy < TEST_HEIGHT; dy++) {
2080         src_row = block_row - dy;
2081         Fprintf(ofp, "/* DY = %2d */\n  {{\n", dy);
2082 #ifndef no_vision_progress
2083         Fprintf(stderr," %2d",dy),  (void)fflush(stderr);
2084 #endif
2085         for (dx = 1; dx < TEST_WIDTH; dx++) {
2086             src_col = block_col + dx;
2087             Fprintf(ofp, "  /*%2d(-1)*/ {", dx);
2088
2089             for (this_row = block_row+1; this_row < block_row+TEST_HEIGHT;
2090                                                                 this_row++) {
2091                 delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : "";
2092
2093                 SpinCursor(3);
2094                 /* Find first col that we can see. */
2095                 for (i = 0; i <= block_col; i++) {
2096                     if (clear_path(src_row,src_col,this_row,i)) break;
2097                 }
2098
2099                 if (block_col-i < 0)
2100                     Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim);
2101                 else
2102                     Fprintf(ofp, "%2d%s", block_col - i, delim);
2103             }
2104             Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
2105         }
2106         Fprintf(ofp,"  }},\n");
2107     }
2108
2109     Fprintf(ofp,"}; /* far_table[] */\n");      /* closing brace for table */
2110     Fprintf(ofp,"#endif /* !CLOSE_TABLE_ONLY */\n");
2111 #ifndef no_vision_progress
2112     Fprintf(stderr,"\n");
2113 #endif
2114     return;
2115 }
2116
2117 /*
2118  *  "Draw" a line from the hero to the given location.  Stop if we hit a
2119  *  wall.
2120  *
2121  *  Generalized integer Bresenham's algorithm (fast line drawing) for
2122  *  all quadrants.  From _Procedural Elements for Computer Graphics_, by
2123  *  David F. Rogers.  McGraw-Hill, 1985.
2124  *
2125  *  I have tried a little bit of optimization by pulling compares out of
2126  *  the inner loops.
2127  *
2128  *  NOTE:  This had better *not* be called from a position on the
2129  *  same row as the hero.
2130  */
2131 static int
2132 clear_path(you_row,you_col,y2,x2)
2133     int you_row, you_col, y2, x2;
2134 {
2135     int dx, dy, s1, s2;
2136     register int i, error, x, y, dxs, dys;
2137
2138     x  = you_col;               y  = you_row;
2139     dx = abs(x2-you_col);       dy = abs(y2-you_row);
2140     s1 = sign(x2-you_col);      s2 = sign(y2-you_row);
2141
2142     if (s1 == 0) {      /* same column */
2143         if (s2 == 1) {  /* below (larger y2 value) */
2144             for (i = you_row+1; i < y2; i++)
2145                 if (!xclear[i][you_col]) return 0;
2146         } else {        /* above (smaller y2 value) */
2147             for (i = y2+1; i < you_row; i++)
2148                 if (!xclear[i][you_col]) return 0;
2149         }
2150         return 1;
2151     }
2152
2153     /*
2154      *  Lines at 0 and 90 degrees have been weeded out.
2155      */
2156     if (dy > dx) {
2157         error = dx; dx = dy; dy = error;        /* swap the values */
2158         dxs = dx << 1;          /* save the shifted values */
2159         dys = dy << 1;
2160         error = dys - dx;       /* NOTE: error is used as a temporary above */
2161
2162         for (i = 0; i < dx; i++) {
2163             if (!xclear[y][x]) return 0;        /* plot point */
2164
2165             while (error >= 0) {
2166                 x += s1;
2167                 error -= dxs;
2168             }
2169             y += s2;
2170             error += dys;
2171         }
2172     } else {
2173         dxs = dx << 1;          /* save the shifted values */
2174         dys = dy << 1;
2175         error = dys - dx;
2176
2177         for (i = 0; i < dx; i++) {
2178             if (!xclear[y][x]) return 0;        /* plot point */
2179
2180             while (error >= 0) {
2181                 y += s2;
2182                 error -= dxs;
2183             }
2184             x += s1;
2185             error += dys;
2186         }
2187     }
2188     return 1;
2189 }
2190 #endif /* VISION_TABLES */
2191
2192 #ifdef STRICT_REF_DEF
2193 NEARDATA struct flag flags;
2194 # ifdef ATTRIB_H
2195 struct attribs attrmax, attrmin;
2196 # endif
2197 #endif /* STRICT_REF_DEF */
2198
2199 /*makedefs.c*/