OSDN Git Service

add copyright
[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 #ifdef KR1ED
547         long clocktim = 0;
548 #else
549         time_t clocktim;
550 #endif
551         char *c, cbuf[256], buf[BUFSZ];
552         const char *ul_sfx;
553
554         filename[0]='\0';
555 #ifdef FILE_PREFIX
556         Strcat(filename,file_prefix);
557 #endif
558         Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE);
559         if (!(ofp = fopen(filename, WRTMODE))) {
560                 perror(filename);
561                 exit(EXIT_FAILURE);
562         }
563         Fprintf(ofp,"/*\tSCCS Id: @(#)date.h\t3.4\t2002/02/03 */\n\n");
564         Fprintf(ofp,Dont_Edit_Code);
565
566 #ifdef KR1ED
567         (void) time(&clocktim);
568         Strcpy(cbuf, ctime(&clocktim));
569 #else
570         (void) time((time_t *)&clocktim);
571         Strcpy(cbuf, ctime((time_t *)&clocktim));
572 #endif
573         for (c = cbuf; *c; c++) if (*c == '\n') break;
574         *c = '\0';      /* strip off the '\n' */
575         Fprintf(ofp,"#define BUILD_DATE \"%s\"\n", cbuf);
576         Fprintf(ofp,"#define BUILD_TIME (%ldL)\n", clocktim);
577         Fprintf(ofp,"\n");
578 #ifdef NHSTDC
579         ul_sfx = "UL";
580 #else
581         ul_sfx = "L";
582 #endif
583         Fprintf(ofp,"#define VERSION_NUMBER 0x%08lx%s\n",
584                 version.incarnation, ul_sfx);
585         Fprintf(ofp,"#define VERSION_FEATURES 0x%08lx%s\n",
586                 version.feature_set, ul_sfx);
587 #ifdef IGNORED_FEATURES
588         Fprintf(ofp,"#define IGNORED_FEATURES 0x%08lx%s\n",
589                 (unsigned long) IGNORED_FEATURES, ul_sfx);
590 #endif
591         Fprintf(ofp,"#define VERSION_SANITY1 0x%08lx%s\n",
592                 version.entity_count, ul_sfx);
593         Fprintf(ofp,"#define VERSION_SANITY2 0x%08lx%s\n",
594                 version.struct_sizes, ul_sfx);
595         Fprintf(ofp,"\n");
596         Fprintf(ofp,"#define VERSION_STRING \"%s\"\n", version_string(buf));
597         Fprintf(ofp,"#define VERSION_ID \\\n \"%s\"\n",
598                 version_id_string(buf, cbuf));
599         Fprintf(ofp,"\n");
600 #ifdef AMIGA
601         {
602         struct tm *tm = localtime((time_t *) &clocktim);
603         Fprintf(ofp,"#define AMIGA_VERSION_STRING ");
604         Fprintf(ofp,"\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
605                 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
606                 tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900);
607         }
608 #endif
609         Fclose(ofp);
610         return;
611 }
612
613 static char save_bones_compat_buf[BUFSZ];
614
615 static void
616 build_savebones_compat_string()
617 {
618 #ifdef VERSION_COMPATIBILITY
619         unsigned long uver = VERSION_COMPATIBILITY;
620 #endif
621         Strcpy(save_bones_compat_buf,
622                 "save and bones files accepted from version");
623 #ifdef VERSION_COMPATIBILITY
624         Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d",
625                 ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16),
626                 ((uver & 0x0000FF00L) >> 8),
627                 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
628 #else
629         Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only",
630                 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
631 #endif
632 }
633
634 static const char *build_opts[] = {
635 #ifdef AMIGA_WBENCH
636                 "Amiga WorkBench support",
637 #endif
638 #ifdef ANSI_DEFAULT
639                 "ANSI default terminal",
640 #endif
641 #ifdef AUTOPICKUP_EXCEPTIONS
642                 "autopickup_exceptions",
643 #endif
644 #ifdef TEXTCOLOR
645                 "color",
646 #endif
647 #ifdef COM_COMPL
648                 "command line completion",
649 #endif
650 #ifdef COMPRESS
651                 "data file compression",
652 #endif
653 #ifdef DLB
654                 "data librarian",
655 #endif
656 #ifdef WIZARD
657                 "debug mode",
658 #endif
659 #ifdef ELBERETH
660                 "Elbereth",
661 #endif
662 #ifdef EXP_ON_BOTL
663                 "experience points on status line",
664 #endif
665 #ifdef MFLOPPY
666                 "floppy drive support",
667 #endif
668 #ifdef GOLDOBJ
669                 "gold object in inventories",
670 #endif
671 #ifdef INSURANCE
672                 "insurance files for recovering from crashes",
673 #endif
674 #ifdef KOPS
675                 "Keystone Kops",
676 #endif
677 #ifdef HOLD_LOCKFILE_OPEN
678                 "exclusive lock on level 0 file",
679 #endif
680 #ifdef LOGFILE
681                 "log file",
682 #endif
683 #ifdef MAIL
684                 "mail daemon",
685 #endif
686 #ifdef GNUDOS
687                 "MSDOS protected mode",
688 #endif
689 #ifdef NEWS
690                 "news file",
691 #endif
692 #ifdef OVERLAY
693 # ifdef MOVERLAY
694                 "MOVE overlays",
695 # else
696 #  ifdef VROOMM
697                 "VROOMM overlays",
698 #  else
699                 "overlays",
700 #  endif
701 # endif
702 #endif
703 #ifdef REDO
704                 "redo command",
705 #endif
706 #ifdef REINCARNATION
707                 "rogue level",
708 #endif
709 #ifdef STEED
710                 "saddles and riding",
711 #endif
712 #ifdef SCORE_ON_BOTL
713                 "score on status line",
714 #endif
715 #ifdef CLIPPING
716                 "screen clipping",
717 #endif
718 #ifdef NO_TERMS
719 # ifdef MAC
720                 "screen control via mactty",
721 # endif
722 # ifdef SCREEN_BIOS
723                 "screen control via BIOS",
724 # endif
725 # ifdef SCREEN_DJGPPFAST
726                 "screen control via DJGPP fast",
727 # endif
728 # ifdef SCREEN_VGA
729                 "screen control via VGA graphics",
730 # endif
731 # ifndef MSWIN_GRAPHICS
732 #  ifdef WIN32CON
733                 "screen control via WIN32 console I/O",
734 #  endif
735 # endif
736 #endif
737 #ifdef SEDUCE
738                 "seduction",
739 #endif
740 #ifdef SHELL
741                 "shell command",
742 #endif
743 #ifdef SINKS
744                 "sinks",
745 #endif
746 #ifdef SUSPEND
747                 "suspend command",
748 #endif
749 #ifdef TERMINFO
750                 "terminal info library",
751 #else
752 # if defined(TERMLIB) || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
753                 "terminal capability library",
754 # endif
755 #endif
756 #ifdef TIMED_DELAY
757                 "timed wait for display effects",
758 #endif
759 #ifdef TOURIST
760                 "tourists",
761 #endif
762 #ifdef USER_SOUNDS
763 # ifdef USER_SOUNDS_REGEX
764                 "user sounds via regular expressions",
765 # else
766                 "user sounds via pmatch",
767 # endif
768 #endif
769 #ifdef PREFIXES_IN_USE
770                 "variable playground",
771 #endif
772 #ifdef VISION_TABLES
773                 "vision tables",
774 #endif
775 #ifdef WALLIFIED_MAZE
776                 "walled mazes",
777 #endif
778 #ifdef ZEROCOMP
779                 "zero-compressed save files",
780 #endif
781                 save_bones_compat_buf,
782                 "basic NetHack features"
783         };
784
785 static const char *window_opts[] = {
786 #ifdef TTY_GRAPHICS
787                 "traditional tty-based graphics",
788 #endif
789 #ifdef X11_GRAPHICS
790                 "X11",
791 #endif
792 #ifdef QT_GRAPHICS
793                 "Qt",
794 #endif
795 #ifdef GNOME_GRAPHICS
796                 "Gnome",
797 #endif
798 #ifdef MAC
799                 "Mac",
800 #endif
801 #ifdef AMIGA_INTUITION
802                 "Amiga Intuition",
803 #endif
804 #ifdef GEM_GRAPHICS
805                 "Gem",
806 #endif
807 #ifdef MSWIN_GRAPHICS
808                 "mswin",
809 #endif
810 #ifdef BEOS_GRAPHICS
811                 "BeOS InterfaceKit",
812 #endif
813                 0
814         };
815
816 void
817 do_options()
818 {
819         register int i, length;
820         register const char *str, *indent = "    ";
821
822         filename[0]='\0';
823 #ifdef FILE_PREFIX
824         Strcat(filename,file_prefix);
825 #endif
826         Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE);
827         if (!(ofp = fopen(filename, WRTMODE))) {
828                 perror(filename);
829                 exit(EXIT_FAILURE);
830         }
831
832         build_savebones_compat_string();
833         Fprintf(ofp,
834 #ifdef BETA
835                 "\n    NetHack version %d.%d.%d [beta]\n",
836 #else
837                 "\n    NetHack version %d.%d.%d\n",
838 #endif
839                 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
840
841         Fprintf(ofp,"\nOptions compiled into this edition:\n");
842
843         length = COLNO + 1;     /* force 1st item onto new line */
844         for (i = 0; i < SIZE(build_opts); i++) {
845             str = build_opts[i];
846             if (length + strlen(str) > COLNO - 5)
847                 Fprintf(ofp,"\n%s", indent),  length = strlen(indent);
848             else
849                 Fprintf(ofp," "),  length++;
850             Fprintf(ofp,"%s", str),  length += strlen(str);
851             Fprintf(ofp,(i < SIZE(build_opts) - 1) ? "," : "."),  length++;
852         }
853
854         Fprintf(ofp,"\n\nSupported windowing systems:\n");
855
856         length = COLNO + 1;     /* force 1st item onto new line */
857         for (i = 0; i < SIZE(window_opts) - 1; i++) {
858             str = window_opts[i];
859             if (length + strlen(str) > COLNO - 5)
860                 Fprintf(ofp,"\n%s", indent),  length = strlen(indent);
861             else
862                 Fprintf(ofp," "),  length++;
863             Fprintf(ofp,"%s", str),  length += strlen(str);
864             Fprintf(ofp, ","),  length++;
865         }
866         Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS);
867         Fprintf(ofp,"\n\n");
868
869         Fclose(ofp);
870         return;
871 }
872
873 /* routine to decide whether to discard something from data.base */
874 static boolean
875 d_filter(line)
876     char *line;
877 {
878     if (*line == '#') return TRUE;      /* ignore comment lines */
879     return FALSE;
880 }
881
882    /*
883     *
884         New format (v3.1) of 'data' file which allows much faster lookups [pr]
885 "do not edit"           first record is a comment line
886 01234567                hexadecimal formatted offset to text area
887 name-a                  first name of interest
888 123,4                   offset to name's text, and number of lines for it
889 name-b                  next name of interest
890 name-c                  multiple names which share same description also
891 456,7                   share a single offset,count line
892 .                       sentinel to mark end of names
893 789,0                   dummy record containing offset, count of EOF
894 text-a                  4 lines of descriptive text for name-a
895 text-a                  at file position 0x01234567L + 123L
896 text-a
897 text-a
898 text-b/text-c           7 lines of text for names-b and -c
899 text-b/text-c           at fseek(0x01234567L + 456L)
900 ...
901     *
902     */
903
904 void
905 do_data()
906 {
907         char    infile[60], tempfile[60];
908         boolean ok;
909         long    txt_offset;
910         int     entry_cnt, line_cnt;
911
912         Sprintf(tempfile, DATA_TEMPLATE, "database.tmp");
913         filename[0]='\0';
914 #ifdef FILE_PREFIX
915         Strcat(filename,file_prefix);
916 #endif
917         Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE);
918         Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE);
919         Strcat(infile,
920 #ifdef SHORT_FILENAMES
921                 ".bas"
922 #else
923                 ".base"
924 #endif
925                 );
926         if (!(ifp = fopen(infile, RDTMODE))) {          /* data.base */
927                 perror(infile);
928                 exit(EXIT_FAILURE);
929         }
930         if (!(ofp = fopen(filename, WRTMODE))) {        /* data */
931                 perror(filename);
932                 Fclose(ifp);
933                 exit(EXIT_FAILURE);
934         }
935         if (!(tfp = fopen(tempfile, WRTMODE))) {        /* database.tmp */
936                 perror(tempfile);
937                 Fclose(ifp);
938                 Fclose(ofp);
939                 Unlink(filename);
940                 exit(EXIT_FAILURE);
941         }
942
943         /* output a dummy header record; we'll rewind and overwrite it later */
944         Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L);
945
946         entry_cnt = line_cnt = 0;
947         /* read through the input file and split it into two sections */
948         while (fgets(in_line, sizeof in_line, ifp)) {
949             if (d_filter(in_line)) continue;
950             if (*in_line > ' ') {       /* got an entry name */
951                 /* first finish previous entry */
952                 if (line_cnt)  Fprintf(ofp, "%d\n", line_cnt),  line_cnt = 0;
953                 /* output the entry name */
954                 (void) fputs(in_line, ofp);
955                 entry_cnt++;            /* update number of entries */
956             } else if (entry_cnt) {     /* got some descriptive text */
957                 /* update previous entry with current text offset */
958                 if (!line_cnt)  Fprintf(ofp, "%ld,", ftell(tfp));
959                 /* save the text line in the scratch file */
960                 (void) fputs(in_line, tfp);
961                 line_cnt++;             /* update line counter */
962             }
963         }
964         /* output an end marker and then record the current position */
965         if (line_cnt)  Fprintf(ofp, "%d\n", line_cnt);
966         Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0);
967         txt_offset = ftell(ofp);
968         Fclose(ifp);            /* all done with original input file */
969
970         /* reprocess the scratch file; 1st format an error msg, just in case */
971         Sprintf(in_line, "rewind of \"%s\"", tempfile);
972         if (rewind(tfp) != 0)  goto dead_data;
973         /* copy all lines of text from the scratch file into the output file */
974         while (fgets(in_line, sizeof in_line, tfp))
975             (void) fputs(in_line, ofp);
976
977         /* finished with scratch file */
978         Fclose(tfp);
979         Unlink(tempfile);       /* remove it */
980
981         /* update the first record of the output file; prepare error msg 1st */
982         Sprintf(in_line, "rewind of \"%s\"", filename);
983         ok = (rewind(ofp) == 0);
984         if (ok) {
985            Sprintf(in_line, "header rewrite of \"%s\"", filename);
986            ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, txt_offset) >= 0);
987         }
988         if (!ok) {
989 dead_data:  perror(in_line);    /* report the problem */
990             /* close and kill the aborted output file, then give up */
991             Fclose(ofp);
992             Unlink(filename);
993             exit(EXIT_FAILURE);
994         }
995
996         /* all done */
997         Fclose(ofp);
998
999         return;
1000 }
1001
1002 /* routine to decide whether to discard something from oracles.txt */
1003 static boolean
1004 h_filter(line)
1005     char *line;
1006 {
1007     static boolean skip = FALSE;
1008     char tag[sizeof in_line];
1009
1010     SpinCursor(3);
1011
1012     if (*line == '#') return TRUE;      /* ignore comment lines */
1013     if (sscanf(line, "----- %s", tag) == 1) {
1014         skip = FALSE;
1015 #ifndef SINKS
1016         if (!strcmp(tag, "SINKS")) skip = TRUE;
1017 #endif
1018 #ifndef ELBERETH
1019         if (!strcmp(tag, "ELBERETH")) skip = TRUE;
1020 #endif
1021     } else if (skip && !strncmp(line, "-----", 5))
1022         skip = FALSE;
1023     return skip;
1024 }
1025
1026 static const char *special_oracle[] = {
1027         "\"...it is rather disconcerting to be confronted with the",
1028         "following theorem from [Baker, Gill, and Solovay, 1975].",
1029         "",
1030         "Theorem 7.18  There exist recursive languages A and B such that",
1031         "  (1)  P(A) == NP(A), and",
1032         "  (2)  P(B) != NP(B)",
1033         "",
1034         "This provides impressive evidence that the techniques that are",
1035         "currently available will not suffice for proving that P != NP or          ",
1036         "that P == NP.\"  [Garey and Johnson, p. 185.]"
1037 };
1038
1039 /*
1040    The oracle file consists of a "do not edit" comment, a decimal count N
1041    and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
1042    records, separated by "---" lines.  The first oracle is a special case.
1043    The input data contains just those multi-line records, separated by
1044    "-----" lines.
1045  */
1046
1047 void
1048 do_oracles()
1049 {
1050         char    infile[60], tempfile[60];
1051         boolean in_oracle, ok;
1052         long    txt_offset, offset, fpos;
1053         int     oracle_cnt;
1054         register int i;
1055
1056         Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp");
1057         filename[0]='\0';
1058 #ifdef FILE_PREFIX
1059         Strcat(filename, file_prefix);
1060 #endif
1061         Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE);
1062         Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE);
1063         Strcat(infile, ".txt");
1064         if (!(ifp = fopen(infile, RDTMODE))) {
1065                 perror(infile);
1066                 exit(EXIT_FAILURE);
1067         }
1068         if (!(ofp = fopen(filename, WRTMODE))) {
1069                 perror(filename);
1070                 Fclose(ifp);
1071                 exit(EXIT_FAILURE);
1072         }
1073         if (!(tfp = fopen(tempfile, WRTMODE))) {        /* oracles.tmp */
1074                 perror(tempfile);
1075                 Fclose(ifp);
1076                 Fclose(ofp);
1077                 Unlink(filename);
1078                 exit(EXIT_FAILURE);
1079         }
1080
1081         /* output a dummy header record; we'll rewind and overwrite it later */
1082         Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0);
1083
1084         /* handle special oracle; it must come first */
1085         (void) fputs("---\n", tfp);
1086         Fprintf(ofp, "%05lx\n", ftell(tfp));  /* start pos of special oracle */
1087         for (i = 0; i < SIZE(special_oracle); i++) {
1088             (void) fputs(xcrypt(special_oracle[i]), tfp);
1089             (void) fputc('\n', tfp);
1090         }
1091         SpinCursor(3);
1092
1093         oracle_cnt = 1;
1094         (void) fputs("---\n", tfp);
1095         Fprintf(ofp, "%05lx\n", ftell(tfp));    /* start pos of first oracle */
1096         in_oracle = FALSE;
1097
1098         while (fgets(in_line, sizeof in_line, ifp)) {
1099             SpinCursor(3);
1100
1101             if (h_filter(in_line)) continue;
1102             if (!strncmp(in_line, "-----", 5)) {
1103                 if (!in_oracle) continue;
1104                 in_oracle = FALSE;
1105                 oracle_cnt++;
1106                 (void) fputs("---\n", tfp);
1107                 Fprintf(ofp, "%05lx\n", ftell(tfp));
1108                 /* start pos of this oracle */
1109             } else {
1110                 in_oracle = TRUE;
1111                 (void) fputs(xcrypt(in_line), tfp);
1112             }
1113         }
1114
1115         if (in_oracle) {        /* need to terminate last oracle */
1116             oracle_cnt++;
1117             (void) fputs("---\n", tfp);
1118             Fprintf(ofp, "%05lx\n", ftell(tfp));        /* eof position */
1119         }
1120
1121         /* record the current position */
1122         txt_offset = ftell(ofp);
1123         Fclose(ifp);            /* all done with original input file */
1124
1125         /* reprocess the scratch file; 1st format an error msg, just in case */
1126         Sprintf(in_line, "rewind of \"%s\"", tempfile);
1127         if (rewind(tfp) != 0)  goto dead_data;
1128         /* copy all lines of text from the scratch file into the output file */
1129         while (fgets(in_line, sizeof in_line, tfp))
1130             (void) fputs(in_line, ofp);
1131
1132         /* finished with scratch file */
1133         Fclose(tfp);
1134         Unlink(tempfile);       /* remove it */
1135
1136         /* update the first record of the output file; prepare error msg 1st */
1137         Sprintf(in_line, "rewind of \"%s\"", filename);
1138         ok = (rewind(ofp) == 0);
1139         if (ok) {
1140             Sprintf(in_line, "header rewrite of \"%s\"", filename);
1141             ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >=0);
1142         }
1143         if (ok) {
1144             Sprintf(in_line, "data rewrite of \"%s\"", filename);
1145             for (i = 0; i <= oracle_cnt; i++) {
1146 #ifndef VMS     /* alpha/vms v1.0; this fflush seems to confuse ftell */
1147                 if (!(ok = (fflush(ofp) == 0))) break;
1148 #endif
1149                 if (!(ok = (fpos = ftell(ofp)) >= 0)) break;
1150                 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
1151                 if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1))) break;
1152 #ifdef MAC
1153 # ifdef __MWERKS__
1154                 /*
1155                 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
1156                 (ANSI C Libraries) needs this rewind or else the fprintf
1157                 stops working.  This may also be true for CW11, but has
1158                 never been checked.
1159                 */
1160                 rewind(ofp);
1161 # endif
1162 #endif
1163                 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
1164                 if (!(ok = (fprintf(ofp, "%05lx\n", offset + txt_offset) >= 0)))
1165                     break;
1166             }
1167         }
1168         if (!ok) {
1169 dead_data:  perror(in_line);    /* report the problem */
1170             /* close and kill the aborted output file, then give up */
1171             Fclose(ofp);
1172             Unlink(filename);
1173             exit(EXIT_FAILURE);
1174         }
1175
1176         /* all done */
1177         Fclose(ofp);
1178
1179         return;
1180 }
1181
1182
1183 static  struct deflist {
1184
1185         const char      *defname;
1186         boolean true_or_false;
1187 } deflist[] = {
1188 #ifdef REINCARNATION
1189               { "REINCARNATION", TRUE },
1190 #else
1191               { "REINCARNATION", FALSE },
1192 #endif
1193               { 0, 0 } };
1194
1195 static int
1196 check_control(s)
1197         char    *s;
1198 {
1199         int     i;
1200
1201         if(s[0] != '%') return(-1);
1202
1203         for(i = 0; deflist[i].defname; i++)
1204             if(!strncmp(deflist[i].defname, s+1, strlen(deflist[i].defname)))
1205                 return(i);
1206
1207         return(-1);
1208 }
1209
1210 static char *
1211 without_control(s)
1212         char *s;
1213 {
1214         return(s + 1 + strlen(deflist[check_control(in_line)].defname));
1215 }
1216
1217 void
1218 do_dungeon()
1219 {
1220         int rcnt = 0;
1221
1222         Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE);
1223         if (!(ifp = fopen(filename, RDTMODE))) {
1224                 perror(filename);
1225                 exit(EXIT_FAILURE);
1226         }
1227         filename[0]='\0';
1228 #ifdef FILE_PREFIX
1229         Strcat(filename, file_prefix);
1230 #endif
1231         Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE);
1232         if (!(ofp = fopen(filename, WRTMODE))) {
1233                 perror(filename);
1234                 exit(EXIT_FAILURE);
1235         }
1236         Fprintf(ofp,Dont_Edit_Data);
1237
1238         while (fgets(in_line, sizeof in_line, ifp) != 0) {
1239             SpinCursor(3);
1240
1241             rcnt++;
1242             if(in_line[0] == '#') continue;     /* discard comments */
1243 recheck:
1244             if(in_line[0] == '%') {
1245                 int i = check_control(in_line);
1246                 if(i >= 0) {
1247                     if(!deflist[i].true_or_false)  {
1248                         while (fgets(in_line, sizeof in_line, ifp) != 0)
1249                             if(check_control(in_line) != i) goto recheck;
1250                     } else
1251                         (void) fputs(without_control(in_line),ofp);
1252                 } else {
1253                     Fprintf(stderr, "Unknown control option '%s' in file %s at line %d.\n",
1254                             in_line, DGN_I_FILE, rcnt);
1255                     exit(EXIT_FAILURE);
1256                 }
1257             } else
1258                 (void) fputs(in_line,ofp);
1259         }
1260         Fclose(ifp);
1261         Fclose(ofp);
1262
1263         return;
1264 }
1265
1266 static boolean
1267 ranged_attk(ptr)        /* returns TRUE if monster can attack at range */
1268         register struct permonst *ptr;
1269 {
1270         register int    i, j;
1271         register int atk_mask = (1<<AT_BREA) | (1<<AT_SPIT) | (1<<AT_GAZE);
1272
1273         for(i = 0; i < NATTK; i++) {
1274             if((j=ptr->mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1<<j)))
1275                 return TRUE;
1276         }
1277
1278         return(FALSE);
1279 }
1280
1281 /* This routine is designed to return an integer value which represents
1282  * an approximation of monster strength.  It uses a similar method of
1283  * determination as "experience()" to arrive at the strength.
1284  */
1285 static int
1286 mstrength(ptr)
1287 struct permonst *ptr;
1288 {
1289         int     i, tmp2, n, tmp = ptr->mlevel;
1290
1291         if(tmp > 49)            /* special fixed hp monster */
1292             tmp = 2*(tmp - 6) / 4;
1293
1294 /*      For creation in groups */
1295         n = (!!(ptr->geno & G_SGROUP));
1296         n += (!!(ptr->geno & G_LGROUP)) << 1;
1297
1298 /*      For ranged attacks */
1299         if (ranged_attk(ptr)) n++;
1300
1301 /*      For higher ac values */
1302         n += (ptr->ac < 4);
1303         n += (ptr->ac < 0);
1304
1305 /*      For very fast monsters */
1306         n += (ptr->mmove >= 18);
1307
1308 /*      For each attack and "special" attack */
1309         for(i = 0; i < NATTK; i++) {
1310
1311             tmp2 = ptr->mattk[i].aatyp;
1312             n += (tmp2 > 0);
1313             n += (tmp2 == AT_MAGC);
1314             n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG));
1315         }
1316
1317 /*      For each "special" damage type */
1318         for(i = 0; i < NATTK; i++) {
1319
1320             tmp2 = ptr->mattk[i].adtyp;
1321             if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST)
1322                 || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE))
1323                         n += 2;
1324             else if (strcmp(ptr->mname, "grid bug")) n += (tmp2 != AD_PHYS);
1325             n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23);
1326         }
1327
1328 /*      Leprechauns are special cases.  They have many hit dice so they
1329         can hit and are hard to kill, but they don't really do much damage. */
1330         if (!strcmp(ptr->mname, "leprechaun")) n -= 2;
1331
1332 /*      Finally, adjust the monster level  0 <= n <= 24 (approx.) */
1333         if(n == 0) tmp--;
1334         else if(n >= 6) tmp += ( n / 2 );
1335         else tmp += ( n / 3 + 1);
1336
1337         return((tmp >= 0) ? tmp : 0);
1338 }
1339
1340 void
1341 do_monstr()
1342 {
1343     register struct permonst *ptr;
1344     register int i, j;
1345
1346     /*
1347      * create the source file, "monstr.c"
1348      */
1349     filename[0]='\0';
1350 #ifdef FILE_PREFIX
1351     Strcat(filename, file_prefix);
1352 #endif
1353     Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C);
1354     if (!(ofp = fopen(filename, WRTMODE))) {
1355         perror(filename);
1356         exit(EXIT_FAILURE);
1357     }
1358     Fprintf(ofp,Dont_Edit_Code);
1359     Fprintf(ofp,"#include \"config.h\"\n");
1360     Fprintf(ofp,"\nconst int monstr[] = {\n");
1361     for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) {
1362
1363         SpinCursor(3);
1364
1365         i = mstrength(ptr);
1366         Fprintf(ofp,"%2d,%c", i, (++j & 15) ? ' ' : '\n');
1367     }
1368     /* might want to insert a final 0 entry here instead of just newline */
1369     Fprintf(ofp,"%s};\n", (j & 15) ? "\n" : "");
1370
1371     Fprintf(ofp,"\nvoid NDECL(monstr_init);\n");
1372     Fprintf(ofp,"\nvoid\n");
1373     Fprintf(ofp,"monstr_init()\n");
1374     Fprintf(ofp,"{\n");
1375     Fprintf(ofp,"    return;\n");
1376     Fprintf(ofp,"}\n");
1377     Fprintf(ofp,"\n/*monstr.c*/\n");
1378
1379     Fclose(ofp);
1380     return;
1381 }
1382
1383 void
1384 do_permonst()
1385 {
1386         int     i;
1387         char    *c, *nam;
1388
1389         filename[0]='\0';
1390 #ifdef FILE_PREFIX
1391         Strcat(filename, file_prefix);
1392 #endif
1393         Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE);
1394         if (!(ofp = fopen(filename, WRTMODE))) {
1395                 perror(filename);
1396                 exit(EXIT_FAILURE);
1397         }
1398         Fprintf(ofp,"/*\tSCCS Id: @(#)pm.h\t3.4\t2002/02/03 */\n\n");
1399         Fprintf(ofp,Dont_Edit_Code);
1400         Fprintf(ofp,"#ifndef PM_H\n#define PM_H\n");
1401
1402         if (strcmp(mons[0].mname, "playermon") != 0)
1403                 Fprintf(ofp,"\n#define\tPM_PLAYERMON\t(-1)");
1404
1405         for (i = 0; mons[i].mlet; i++) {
1406                 SpinCursor(3);
1407
1408                 Fprintf(ofp,"\n#define\tPM_");
1409                 if (mons[i].mlet == S_HUMAN &&
1410                                 !strncmp(mons[i].mname, "were", 4))
1411                     Fprintf(ofp, "HUMAN_");
1412                 for (nam = c = tmpdup(mons[i].mname); *c; c++)
1413                     if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
1414                     else if (*c < 'A' || *c > 'Z') *c = '_';
1415                 Fprintf(ofp,"%s\t%d", nam, i);
1416         }
1417         Fprintf(ofp,"\n\n#define\tNUMMONS\t%d\n", i);
1418         Fprintf(ofp,"\n#endif /* PM_H */\n");
1419         Fclose(ofp);
1420         return;
1421 }
1422
1423
1424 /*      Start of Quest text file processing. */
1425 #include "qtext.h"
1426
1427 static struct qthdr     qt_hdr;
1428 static struct msghdr    msg_hdr[N_HDR];
1429 static struct qtmsg     *curr_msg;
1430
1431 static int      qt_line;
1432
1433 static boolean  in_msg;
1434 #define NO_MSG  1       /* strlen of a null line returned by fgets() */
1435
1436 static boolean
1437 qt_comment(s)
1438         char *s;
1439 {
1440         if(s[0] == '#') return(TRUE);
1441         return((boolean)(!in_msg  && strlen(s) == NO_MSG));
1442 }
1443
1444 static boolean
1445 qt_control(s)
1446         char *s;
1447 {
1448         return((boolean)(s[0] == '%' && (s[1] == 'C' || s[1] == 'E')));
1449 }
1450
1451 static int
1452 get_hdr (code)
1453         char *code;
1454 {
1455         int     i;
1456
1457         for(i = 0; i < qt_hdr.n_hdr; i++)
1458             if(!strncmp(code, qt_hdr.id[i], LEN_HDR)) return (++i);
1459
1460         return(0);
1461 }
1462
1463 static boolean
1464 new_id (code)
1465         char *code;
1466 {
1467         if(qt_hdr.n_hdr >= N_HDR) {
1468             Fprintf(stderr, OUT_OF_HEADERS, qt_line);
1469             return(FALSE);
1470         }
1471
1472         strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR);
1473         msg_hdr[qt_hdr.n_hdr].n_msg = 0;
1474         qt_hdr.offset[qt_hdr.n_hdr++] = 0L;
1475         return(TRUE);
1476 }
1477
1478 static boolean
1479 known_msg(num, id)
1480         int num, id;
1481 {
1482         int i;
1483
1484         for(i = 0; i < msg_hdr[num].n_msg; i++)
1485             if(msg_hdr[num].qt_msg[i].msgnum == id) return(TRUE);
1486
1487         return(FALSE);
1488 }
1489
1490
1491 static void
1492 new_msg(s, num, id)
1493         char *s;
1494         int num, id;
1495 {
1496         struct  qtmsg   *qt_msg;
1497
1498         if(msg_hdr[num].n_msg >= N_MSG) {
1499                 Fprintf(stderr, OUT_OF_MESSAGES, qt_line);
1500         } else {
1501                 qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]);
1502                 qt_msg->msgnum = id;
1503                 qt_msg->delivery = s[2];
1504                 qt_msg->offset = qt_msg->size = 0L;
1505
1506                 curr_msg = qt_msg;
1507         }
1508 }
1509
1510 static void
1511 do_qt_control(s)
1512         char *s;
1513 {
1514         char code[BUFSZ];
1515         int num, id = 0;
1516
1517         switch(s[1]) {
1518
1519             case 'C':   if(in_msg) {
1520                             Fprintf(stderr, CREC_IN_MSG, qt_line);
1521                             break;
1522                         } else {
1523                             in_msg = TRUE;
1524                             if (sscanf(&s[4], "%s %5d", code, &id) != 2) {
1525                                 Fprintf(stderr, UNREC_CREC, qt_line);
1526                                 break;
1527                             }
1528                             num = get_hdr(code);
1529                             if (!num && !new_id(code))
1530                                 break;
1531                             num = get_hdr(code)-1;
1532                             if(known_msg(num, id))
1533                                 Fprintf(stderr, DUP_MSG, qt_line);
1534                             else new_msg(s, num, id);
1535                         }
1536                         break;
1537
1538             case 'E':   if(!in_msg) {
1539                             Fprintf(stderr, END_NOT_IN_MSG, qt_line);
1540                             break;
1541                         } else in_msg = FALSE;
1542                         break;
1543
1544             default:    Fprintf(stderr, UNREC_CREC, qt_line);
1545                         break;
1546         }
1547 }
1548
1549 static void
1550 do_qt_text(s)
1551         char *s;
1552 {
1553         if (!in_msg) {
1554             Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line);
1555         }
1556         curr_msg->size += strlen(s);
1557         return;
1558 }
1559
1560 static void
1561 adjust_qt_hdrs()
1562 {
1563         int     i, j;
1564         long count = 0L, hdr_offset = sizeof(int) +
1565                         (sizeof(char)*LEN_HDR + sizeof(long)) * qt_hdr.n_hdr;
1566
1567         for(i = 0; i < qt_hdr.n_hdr; i++) {
1568             qt_hdr.offset[i] = hdr_offset;
1569             hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg;
1570         }
1571
1572         for(i = 0; i < qt_hdr.n_hdr; i++)
1573             for(j = 0; j < msg_hdr[i].n_msg; j++) {
1574
1575                 msg_hdr[i].qt_msg[j].offset = hdr_offset + count;
1576                 count += msg_hdr[i].qt_msg[j].size;
1577             }
1578         return;
1579 }
1580
1581 static void
1582 put_qt_hdrs()
1583 {
1584         int     i;
1585
1586         /*
1587          *      The main header record.
1588          */
1589 #ifdef DEBUG
1590         Fprintf(stderr, "%ld: header info.\n", ftell(ofp));
1591 #endif
1592         (void) fwrite((genericptr_t)&(qt_hdr.n_hdr), sizeof(int), 1, ofp);
1593         (void) fwrite((genericptr_t)&(qt_hdr.id[0][0]), sizeof(char)*LEN_HDR,
1594                                                         qt_hdr.n_hdr, ofp);
1595         (void) fwrite((genericptr_t)&(qt_hdr.offset[0]), sizeof(long),
1596                                                         qt_hdr.n_hdr, ofp);
1597 #ifdef DEBUG
1598         for(i = 0; i < qt_hdr.n_hdr; i++)
1599                 Fprintf(stderr, "%c @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]);
1600
1601         Fprintf(stderr, "\n");
1602 #endif
1603
1604         /*
1605          *      The individual class headers.
1606          */
1607         for(i = 0; i < qt_hdr.n_hdr; i++) {
1608
1609 #ifdef DEBUG
1610             Fprintf(stderr, "%ld: %c header info.\n", ftell(ofp),
1611                     qt_hdr.id[i]);
1612 #endif
1613             (void) fwrite((genericptr_t)&(msg_hdr[i].n_msg), sizeof(int),
1614                                                         1, ofp);
1615             (void) fwrite((genericptr_t)&(msg_hdr[i].qt_msg[0]),
1616                             sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp);
1617 #ifdef DEBUG
1618             { int j;
1619               for(j = 0; j < msg_hdr[i].n_msg; j++)
1620                 Fprintf(stderr, "msg %d @ %ld (%ld)\n",
1621                         msg_hdr[i].qt_msg[j].msgnum,
1622                         msg_hdr[i].qt_msg[j].offset,
1623                         msg_hdr[i].qt_msg[j].size);
1624             }
1625 #endif
1626         }
1627 }
1628
1629 void
1630 do_questtxt()
1631 {
1632         Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE);
1633         if(!(ifp = fopen(filename, RDTMODE))) {
1634                 perror(filename);
1635                 exit(EXIT_FAILURE);
1636         }
1637
1638         filename[0]='\0';
1639 #ifdef FILE_PREFIX
1640         Strcat(filename, file_prefix);
1641 #endif
1642         Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE);
1643         if(!(ofp = fopen(filename, WRBMODE))) {
1644                 perror(filename);
1645                 Fclose(ifp);
1646                 exit(EXIT_FAILURE);
1647         }
1648
1649         qt_hdr.n_hdr = 0;
1650         qt_line = 0;
1651         in_msg = FALSE;
1652
1653         while (fgets(in_line, 80, ifp) != 0) {
1654             SpinCursor (3);
1655
1656             qt_line++;
1657             if(qt_control(in_line)) do_qt_control(in_line);
1658             else if(qt_comment(in_line)) continue;
1659             else                    do_qt_text(in_line);
1660         }
1661
1662         (void) rewind(ifp);
1663         in_msg = FALSE;
1664         adjust_qt_hdrs();
1665         put_qt_hdrs();
1666         while (fgets(in_line, 80, ifp) != 0) {
1667
1668                 if(qt_control(in_line)) {
1669                     in_msg = (in_line[1] == 'C');
1670                     continue;
1671                 } else if(qt_comment(in_line)) continue;
1672 #ifdef DEBUG
1673                 Fprintf(stderr, "%ld: %s", ftell(stdout), in_line);
1674 #endif
1675                 (void) fputs(xcrypt(in_line), ofp);
1676         }
1677         Fclose(ifp);
1678         Fclose(ofp);
1679         return;
1680 }
1681
1682
1683 static  char    temp[32];
1684
1685 static char *
1686 limit(name,pref)        /* limit a name to 30 characters length */
1687 char    *name;
1688 int     pref;
1689 {
1690         (void) strncpy(temp, name, pref ? 26 : 30);
1691         temp[pref ? 26 : 30] = 0;
1692         return temp;
1693 }
1694
1695 void
1696 do_objs()
1697 {
1698         int i, sum = 0;
1699         char *c, *objnam;
1700         int nspell = 0;
1701         int prefix = 0;
1702         char class = '\0';
1703         boolean sumerr = FALSE;
1704
1705         filename[0]='\0';
1706 #ifdef FILE_PREFIX
1707         Strcat(filename, file_prefix);
1708 #endif
1709         Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE);
1710         if (!(ofp = fopen(filename, WRTMODE))) {
1711                 perror(filename);
1712                 exit(EXIT_FAILURE);
1713         }
1714         Fprintf(ofp,"/*\tSCCS Id: @(#)onames.h\t3.4\t2002/02/03 */\n\n");
1715         Fprintf(ofp,Dont_Edit_Code);
1716         Fprintf(ofp,"#ifndef ONAMES_H\n#define ONAMES_H\n\n");
1717
1718         for(i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) {
1719                 SpinCursor(3);
1720
1721                 objects[i].oc_name_idx = objects[i].oc_descr_idx = i;   /* init */
1722                 if (!(objnam = tmpdup(OBJ_NAME(objects[i])))) continue;
1723
1724                 /* make sure probabilities add up to 1000 */
1725                 if(objects[i].oc_class != class) {
1726                         if (sum && sum != 1000) {
1727                             Fprintf(stderr, "prob error for class %d (%d%%)",
1728                                     class, sum);
1729                             (void) fflush(stderr);
1730                             sumerr = TRUE;
1731                         }
1732                         class = objects[i].oc_class;
1733                         sum = 0;
1734                 }
1735
1736                 for (c = objnam; *c; c++)
1737                     if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
1738                     else if (*c < 'A' || *c > 'Z') *c = '_';
1739
1740                 switch (class) {
1741                     case WAND_CLASS:
1742                         Fprintf(ofp,"#define\tWAN_"); prefix = 1; break;
1743                     case RING_CLASS:
1744                         Fprintf(ofp,"#define\tRIN_"); prefix = 1; break;
1745                     case POTION_CLASS:
1746                         Fprintf(ofp,"#define\tPOT_"); prefix = 1; break;
1747                     case SPBOOK_CLASS:
1748                         Fprintf(ofp,"#define\tSPE_"); prefix = 1; nspell++; break;
1749                     case SCROLL_CLASS:
1750                         Fprintf(ofp,"#define\tSCR_"); prefix = 1; break;
1751                     case AMULET_CLASS:
1752                         /* avoid trouble with stupid C preprocessors */
1753                         Fprintf(ofp,"#define\t");
1754                         if(objects[i].oc_material == PLASTIC) {
1755                             Fprintf(ofp,"FAKE_AMULET_OF_YENDOR\t%d\n", i);
1756                             prefix = -1;
1757                             break;
1758                         }
1759                         break;
1760                     case GEM_CLASS:
1761                         /* avoid trouble with stupid C preprocessors */
1762                         if(objects[i].oc_material == GLASS) {
1763                             Fprintf(ofp,"/* #define\t%s\t%d */\n",
1764                                                         objnam, i);
1765                             prefix = -1;
1766                             break;
1767                         }
1768                     default:
1769                         Fprintf(ofp,"#define\t");
1770                 }
1771                 if (prefix >= 0)
1772                         Fprintf(ofp,"%s\t%d\n", limit(objnam, prefix), i);
1773                 prefix = 0;
1774
1775                 sum += objects[i].oc_prob;
1776         }
1777
1778         /* check last set of probabilities */
1779         if (sum && sum != 1000) {
1780             Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
1781             (void) fflush(stderr);
1782             sumerr = TRUE;
1783         }
1784
1785         Fprintf(ofp,"#define\tLAST_GEM\t(JADE)\n");
1786         Fprintf(ofp,"#define\tMAXSPELL\t%d\n", nspell+1);
1787         Fprintf(ofp,"#define\tNUM_OBJECTS\t%d\n", i);
1788
1789         Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n");
1790
1791         for (i = 1; artifact_names[i]; i++) {
1792                 SpinCursor(3);
1793
1794                 for (c = objnam = tmpdup(artifact_names[i]); *c; c++)
1795                     if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
1796                     else if (*c < 'A' || *c > 'Z') *c = '_';
1797
1798                 if (!strncmp(objnam, "THE_", 4))
1799                         objnam += 4;
1800 #ifdef TOURIST
1801                 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
1802                 if (!strncmp(objnam, "PLATINUM_", 9))
1803                         objnam += 9;
1804 #endif
1805                 Fprintf(ofp,"#define\tART_%s\t%d\n", limit(objnam, 1), i);
1806         }
1807
1808         Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i-1);
1809         Fprintf(ofp,"\n#endif /* ONAMES_H */\n");
1810         Fclose(ofp);
1811         if (sumerr) exit(EXIT_FAILURE);
1812         return;
1813 }
1814
1815 static char *
1816 tmpdup(str)
1817 const char *str;
1818 {
1819         static char buf[128];
1820
1821         if (!str) return (char *)0;
1822         (void)strncpy(buf, str, 127);
1823         return buf;
1824 }
1825
1826 static char *
1827 eos(str)
1828 char *str;
1829 {
1830     while (*str) str++;
1831     return str;
1832 }
1833
1834 /*
1835  * macro used to control vision algorithms:
1836  *      VISION_TABLES => generate tables
1837  */
1838
1839 void
1840 do_vision()
1841 {
1842 #ifdef VISION_TABLES
1843     int i, j;
1844
1845     /* Everything is clear.  xclear may be malloc'ed.
1846      * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
1847      */
1848     for (i = 0; i < MAX_ROW; i++)
1849         for (j = 0; j < MAX_COL; j++)
1850             if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH)
1851                 xclear[i][j] = '\000';
1852             else
1853                 xclear[i][j] = '\001';
1854 #endif /* VISION_TABLES */
1855
1856     SpinCursor(3);
1857
1858     /*
1859      * create the include file, "vis_tab.h"
1860      */
1861     filename[0]='\0';
1862 #ifdef FILE_PREFIX
1863     Strcat(filename, file_prefix);
1864 #endif
1865     Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
1866     if (!(ofp = fopen(filename, WRTMODE))) {
1867         perror(filename);
1868         exit(EXIT_FAILURE);
1869     }
1870     Fprintf(ofp,Dont_Edit_Code);
1871     Fprintf(ofp,"#ifdef VISION_TABLES\n");
1872 #ifdef VISION_TABLES
1873     H_close_gen();
1874     H_far_gen();
1875 #endif /* VISION_TABLES */
1876     Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
1877     Fclose(ofp);
1878
1879     SpinCursor(3);
1880
1881     /*
1882      * create the source file, "vis_tab.c"
1883      */
1884     filename[0]='\0';
1885 #ifdef FILE_PREFIX
1886     Strcat(filename, file_prefix);
1887 #endif
1888     Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C);
1889     if (!(ofp = fopen(filename, WRTMODE))) {
1890         perror(filename);
1891         Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
1892         Unlink(filename);
1893         exit(EXIT_FAILURE);
1894     }
1895     Fprintf(ofp,Dont_Edit_Code);
1896     Fprintf(ofp,"#include \"config.h\"\n");
1897     Fprintf(ofp,"#ifdef VISION_TABLES\n");
1898     Fprintf(ofp,"#include \"vis_tab.h\"\n");
1899
1900     SpinCursor(3);
1901
1902 #ifdef VISION_TABLES
1903     C_close_gen();
1904     C_far_gen();
1905     Fprintf(ofp,"\nvoid vis_tab_init() { return; }\n");
1906 #endif /* VISION_TABLES */
1907
1908     SpinCursor(3);
1909
1910     Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
1911     Fprintf(ofp,"\n/*vis_tab.c*/\n");
1912
1913     Fclose(ofp);
1914     return;
1915 }
1916
1917 #ifdef VISION_TABLES
1918
1919 /*--------------  vision tables  --------------*\
1920  *
1921  *  Generate the close and far tables.  This is done by setting up a
1922  *  fake dungeon and moving our source to different positions relative
1923  *  to a block and finding the first/last visible position.  The fake
1924  *  dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
1925  *  by BLOCK_WIDTH) is blocked.  Then we move the source around relative
1926  *  to the corner of the block.  For each new position of the source
1927  *  we check positions on rows "kittycorner" from the source.  We check
1928  *  positions until they are either in sight or out of sight (depends on
1929  *  which table we are generating).  The picture below shows the setup
1930  *  for the generation of the close table.  The generation of the far
1931  *  table would switch the quadrants of the '@' and the "Check rows
1932  *  here".
1933  *
1934  *
1935  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1936  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1937  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
1938  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1939  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1940  *  ...............................
1941  *  ...............................
1942  *  .........@.....................
1943  *  ...............................
1944  *
1945  *      Table generation figure (close_table).  The 'X's are blocked points.
1946  *      The 'B' is a special blocked point.  The '@' is the source.  The ','s
1947  *      are the target area.  The '.' are just open areas.
1948  *
1949  *
1950  *  Example usage of close_table[][][].
1951  *
1952  *  The table is as follows:
1953  *
1954  *      dy = |row of '@' - row of 'B'|  - 1
1955  *      dx = |col of '@' - col of 'B'|
1956  *
1957  *  The first indices are the deltas from the source '@' and the block 'B'.
1958  *  You must check for the value inside the abs value bars being zero.  If
1959  *  so then the block is on the same row and you don't need to do a table
1960  *  lookup.  The last value:
1961  *
1962  *      dcy = |row of block - row to be checked|
1963  *
1964  *  Is the value of the first visible spot on the check row from the
1965  *  block column.  So
1966  *
1967  *  first visible col = close_table[dy][dx][dcy] + col of 'B'
1968  *
1969 \*--------------  vision tables  --------------*/
1970
1971 static void
1972 H_close_gen()
1973 {
1974     Fprintf(ofp,"\n/* Close */\n");
1975     Fprintf(ofp,"#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
1976             TEST_HEIGHT-1);
1977     Fprintf(ofp,"#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
1978             TEST_WIDTH);
1979     Fprintf(ofp,"#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
1980             TEST_HEIGHT);
1981     Fprintf(ofp,"typedef struct {\n");
1982     Fprintf(ofp,"    unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
1983     Fprintf(ofp,"} close2d;\n");
1984     Fprintf(ofp,"extern close2d close_table[CLOSE_MAX_SB_DY];\n");
1985     return;
1986 }
1987
1988 static void
1989 H_far_gen()
1990 {
1991     Fprintf(ofp,"\n/* Far */\n");
1992     Fprintf(ofp,"#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
1993             TEST_HEIGHT);
1994     Fprintf(ofp,"#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
1995             TEST_WIDTH-1);
1996     Fprintf(ofp,"#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
1997             TEST_HEIGHT-1);
1998     Fprintf(ofp,"typedef struct {\n");
1999     Fprintf(ofp,"    unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
2000     Fprintf(ofp,"} far2d;\n");
2001     Fprintf(ofp,"extern far2d far_table[FAR_MAX_SB_DY];\n");
2002     return;
2003 }
2004
2005 static void
2006 C_close_gen()
2007 {
2008     int i,dx,dy;
2009     int src_row, src_col;       /* source */
2010     int block_row, block_col;   /* block */
2011     int this_row;
2012     int no_more;
2013     const char *delim;
2014
2015     block_row = BLOCK_HEIGHT-1;
2016     block_col = BLOCK_WIDTH-1;
2017
2018     Fprintf(ofp,"\n#ifndef FAR_TABLE_ONLY\n");
2019     Fprintf(ofp,"\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
2020 #ifndef no_vision_progress
2021     Fprintf(stderr,"\nclose:");
2022 #endif
2023
2024     for (dy = 1; dy < TEST_HEIGHT; dy++) {
2025         src_row = block_row + dy;
2026         Fprintf(ofp, "/* DY = %2d (- 1)*/\n  {{\n", dy);
2027 #ifndef no_vision_progress
2028         Fprintf(stderr," %2d",dy),  (void)fflush(stderr);
2029 #endif
2030         for (dx = 0; dx < TEST_WIDTH; dx++) {
2031             src_col = block_col - dx;
2032             Fprintf(ofp, "  /*%2d*/ {", dx);
2033
2034             no_more = 0;
2035             for (this_row = 0; this_row < TEST_HEIGHT; this_row++) {
2036                 delim = (this_row < TEST_HEIGHT - 1) ? "," : "";
2037                 if (no_more) {
2038                     Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim);
2039                     continue;
2040                 }
2041                 SpinCursor(3);
2042
2043                 /* Find the first column that we can see. */
2044                 for (i = block_col+1; i < MAX_COL; i++) {
2045                     if (clear_path(src_row,src_col,block_row-this_row,i))
2046                         break;
2047                 }
2048
2049                 if (i == MAX_COL) no_more = 1;
2050                 Fprintf(ofp, "%2d%s", i - block_col, delim);
2051             }
2052             Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
2053         }
2054         Fprintf(ofp,"  }},\n");
2055     }
2056
2057     Fprintf(ofp,"}; /* close_table[] */\n");            /* closing brace for table */
2058     Fprintf(ofp,"#endif /* !FAR_TABLE_ONLY */\n");
2059 #ifndef no_vision_progress
2060     Fprintf(stderr,"\n");
2061 #endif
2062     return;
2063 }
2064
2065 static void
2066 C_far_gen()
2067 {
2068     int i,dx,dy;
2069     int src_row, src_col;       /* source */
2070     int block_row, block_col;   /* block */
2071     int this_row;
2072     const char *delim;
2073
2074     block_row = BLOCK_HEIGHT-1;
2075     block_col = BLOCK_WIDTH-1;
2076
2077     Fprintf(ofp,"\n#ifndef CLOSE_TABLE_ONLY\n");
2078     Fprintf(ofp,"\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
2079 #ifndef no_vision_progress
2080     Fprintf(stderr,"\n_far_:");
2081 #endif
2082
2083     for (dy = 0; dy < TEST_HEIGHT; dy++) {
2084         src_row = block_row - dy;
2085         Fprintf(ofp, "/* DY = %2d */\n  {{\n", dy);
2086 #ifndef no_vision_progress
2087         Fprintf(stderr," %2d",dy),  (void)fflush(stderr);
2088 #endif
2089         for (dx = 1; dx < TEST_WIDTH; dx++) {
2090             src_col = block_col + dx;
2091             Fprintf(ofp, "  /*%2d(-1)*/ {", dx);
2092
2093             for (this_row = block_row+1; this_row < block_row+TEST_HEIGHT;
2094                                                                 this_row++) {
2095                 delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : "";
2096
2097                 SpinCursor(3);
2098                 /* Find first col that we can see. */
2099                 for (i = 0; i <= block_col; i++) {
2100                     if (clear_path(src_row,src_col,this_row,i)) break;
2101                 }
2102
2103                 if (block_col-i < 0)
2104                     Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim);
2105                 else
2106                     Fprintf(ofp, "%2d%s", block_col - i, delim);
2107             }
2108             Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
2109         }
2110         Fprintf(ofp,"  }},\n");
2111     }
2112
2113     Fprintf(ofp,"}; /* far_table[] */\n");      /* closing brace for table */
2114     Fprintf(ofp,"#endif /* !CLOSE_TABLE_ONLY */\n");
2115 #ifndef no_vision_progress
2116     Fprintf(stderr,"\n");
2117 #endif
2118     return;
2119 }
2120
2121 /*
2122  *  "Draw" a line from the hero to the given location.  Stop if we hit a
2123  *  wall.
2124  *
2125  *  Generalized integer Bresenham's algorithm (fast line drawing) for
2126  *  all quadrants.  From _Procedural Elements for Computer Graphics_, by
2127  *  David F. Rogers.  McGraw-Hill, 1985.
2128  *
2129  *  I have tried a little bit of optimization by pulling compares out of
2130  *  the inner loops.
2131  *
2132  *  NOTE:  This had better *not* be called from a position on the
2133  *  same row as the hero.
2134  */
2135 static int
2136 clear_path(you_row,you_col,y2,x2)
2137     int you_row, you_col, y2, x2;
2138 {
2139     int dx, dy, s1, s2;
2140     register int i, error, x, y, dxs, dys;
2141
2142     x  = you_col;               y  = you_row;
2143     dx = abs(x2-you_col);       dy = abs(y2-you_row);
2144     s1 = sign(x2-you_col);      s2 = sign(y2-you_row);
2145
2146     if (s1 == 0) {      /* same column */
2147         if (s2 == 1) {  /* below (larger y2 value) */
2148             for (i = you_row+1; i < y2; i++)
2149                 if (!xclear[i][you_col]) return 0;
2150         } else {        /* above (smaller y2 value) */
2151             for (i = y2+1; i < you_row; i++)
2152                 if (!xclear[i][you_col]) return 0;
2153         }
2154         return 1;
2155     }
2156
2157     /*
2158      *  Lines at 0 and 90 degrees have been weeded out.
2159      */
2160     if (dy > dx) {
2161         error = dx; dx = dy; dy = error;        /* swap the values */
2162         dxs = dx << 1;          /* save the shifted values */
2163         dys = dy << 1;
2164         error = dys - dx;       /* NOTE: error is used as a temporary above */
2165
2166         for (i = 0; i < dx; i++) {
2167             if (!xclear[y][x]) return 0;        /* plot point */
2168
2169             while (error >= 0) {
2170                 x += s1;
2171                 error -= dxs;
2172             }
2173             y += s2;
2174             error += dys;
2175         }
2176     } else {
2177         dxs = dx << 1;          /* save the shifted values */
2178         dys = dy << 1;
2179         error = dys - dx;
2180
2181         for (i = 0; i < dx; i++) {
2182             if (!xclear[y][x]) return 0;        /* plot point */
2183
2184             while (error >= 0) {
2185                 y += s2;
2186                 error -= dxs;
2187             }
2188             x += s1;
2189             error += dys;
2190         }
2191     }
2192     return 1;
2193 }
2194 #endif /* VISION_TABLES */
2195
2196 #ifdef STRICT_REF_DEF
2197 NEARDATA struct flag flags;
2198 # ifdef ATTRIB_H
2199 struct attribs attrmax, attrmin;
2200 # endif
2201 #endif /* STRICT_REF_DEF */
2202
2203 /*makedefs.c*/