1 /* aNetHack 0.0.1 makedefs.c $ANH-Date: 1459208813 2016/03/28 23:46:53 $ $ANH-Branch: master $:$ANH-Revision: 1.110 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* Copyright (c) M. Stephenson, 1990, 1991. */
4 /* Copyright (c) Dean Luick, 1990. */
5 /* aNetHack may be freely redistributed. See license for details. */
7 #define MAKEDEFS_C /* use to conditionally include file sections */
11 #undef free /* makedefs doesn't use the alloc and free in src/alloc.c */
25 /* version information */
26 #ifdef SHORT_FILENAMES
29 #include "patchlevel.h"
34 #if defined(__SC__) || defined(__MRC__) /* MPW compilers */
36 #include <CursorCtl.h>
38 #else /* MAC without MPWTOOL */
39 #define MACsansMPWTOOL
47 #define Fprintf (void) fprintf
48 #define Fclose (void) fclose
49 #define Unlink (void) unlink
50 #if !defined(AMIGA) || defined(AZTEC_C)
51 #define rewind(fp) fseek((fp), 0L, SEEK_SET) /* guarantee a return value */
54 #if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN)
55 static const char SCCS_Id
[] = "@(#)makedefs.c\t3.6\t2016/02/12";
58 /* names of files to be generated */
59 #define DATE_FILE "date.h"
60 #define MONST_FILE "pm.h"
61 #define ONAME_FILE "onames.h"
63 #define OPTIONS_FILE "options"
65 #define ORACLE_FILE "oracles"
66 #define DATA_FILE "data"
67 #define RUMOR_FILE "rumors"
68 #define DGN_I_FILE "dungeon.def"
69 #define DGN_O_FILE "dungeon.pdf"
70 #define MON_STR_C "monstr.c"
71 #define QTXT_I_FILE "quest.txt"
72 #define QTXT_O_FILE "quest.dat"
73 #define VIS_TAB_H "vis_tab.h"
74 #define VIS_TAB_C "vis_tab.c"
75 /* locations for those files */
78 #define INCLUDE_TEMPLATE "NH:include/t.%s"
79 #define SOURCE_TEMPLATE "NH:src/%s"
80 #define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */
81 #define DATA_TEMPLATE "NH:slib/%s"
82 #define DATA_IN_TEMPLATE "NH:dat/%s"
84 #if defined(MAC) && !defined(__MACH__)
85 /* MacOS 9 or earlier */
86 #define INCLUDE_TEMPLATE ":include:%s"
87 #define SOURCE_TEMPLATE ":src:%s"
88 #define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */
90 #define DATA_TEMPLATE ":Dungeon:%s"
92 #define DATA_TEMPLATE ":lib:%s"
93 #endif /* __SC__ || __MRC__ */
94 #define DATA_IN_TEMPLATE ":dat:%s"
95 #else /* neither AMIGA nor MAC */
97 #define INCLUDE_TEMPLATE "..\\include\\%s"
98 #define SOURCE_TEMPLATE "..\\src\\%s"
99 #define DGN_TEMPLATE "..\\dat\\%s" /* where dungeon.pdf file goes */
100 #define DATA_TEMPLATE "..\\dat\\%s"
101 #define DATA_IN_TEMPLATE "..\\dat\\%s"
102 #else /* not AMIGA, MAC, or OS2 */
103 #define INCLUDE_TEMPLATE "../include/%s"
104 #define SOURCE_TEMPLATE "../src/%s"
105 #define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */
106 #define DATA_TEMPLATE "../dat/%s"
107 #define DATA_IN_TEMPLATE "../dat/%s"
108 #endif /* else !OS2 */
109 #endif /* else !MAC */
110 #endif /* else !AMIGA */
114 "/* This source file is generated by 'makedefs'. Do not edit. */\n",
116 "#\tThis data file is generated by 'makedefs'. Do not edit. \n";
118 static struct version_info version
;
120 /* definitions used for vision tables */
121 #define TEST_WIDTH COLNO
122 #define TEST_HEIGHT ROWNO
123 #define BLOCK_WIDTH (TEST_WIDTH + 10)
124 #define BLOCK_HEIGHT TEST_HEIGHT /* don't need extra spaces */
125 #define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT)
126 #define MAX_COL (BLOCK_WIDTH + TEST_WIDTH)
127 /* Use this as an out-of-bound value in the close table. */
128 #define CLOSE_OFF_TABLE_STRING "99" /* for the close table */
129 #define FAR_OFF_TABLE_STRING "0xff" /* for the far table */
131 #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0))
133 static char xclear
[MAX_ROW
][MAX_COL
];
135 /*-end of vision defs-*/
137 static char filename
[600];
140 /* if defined, a first argument not starting with - is
141 * taken as a text string to be prepended to any
142 * output filename generated */
143 char *file_prefix
= "";
146 #ifdef MACsansMPWTOOL
147 int FDECL(main
, (void));
149 int FDECL(main
, (int, char **));
151 void FDECL(do_makedefs
, (char *));
154 void NDECL(do_dungeon
);
156 void NDECL(do_options
);
157 void NDECL(do_monstr
);
158 void NDECL(do_permonst
);
159 void NDECL(do_questtxt
);
160 void NDECL(do_rumors
);
161 void NDECL(do_oracles
);
162 void NDECL(do_vision
);
164 extern void NDECL(monst_init
); /* monst.c */
165 extern void NDECL(objects_init
); /* objects.c */
167 static void NDECL(link_sanity_check
);
168 static char *FDECL(name_file
, (const char *, const char *));
169 static void FDECL(delete_file
, (const char *template, const char *));
170 static FILE *FDECL(getfp
, (const char *, const char *, const char *));
171 static void FDECL(do_ext_makedefs
, (int, char **));
173 static void NDECL(make_version
);
174 static char *FDECL(version_string
, (char *, const char *));
175 static char *FDECL(version_id_string
, (char *, const char *));
176 static char *FDECL(bannerc_string
, (char *, const char *));
177 static char *FDECL(xcrypt
, (const char *));
178 static unsigned long FDECL(read_rumors_file
,
179 (const char *, int *, long *, unsigned long));
180 static void FDECL(do_rnd_access_file
, (const char *));
181 static boolean
FDECL(d_filter
, (char *));
182 static boolean
FDECL(h_filter
, (char *));
183 static boolean
FDECL(ranged_attk
, (struct permonst
*));
184 static int FDECL(mstrength
, (struct permonst
*));
185 static void NDECL(build_savebones_compat_string
);
186 static void NDECL(windowing_sanity
);
188 static boolean
FDECL(qt_comment
, (char *));
189 static boolean
FDECL(qt_control
, (char *));
190 static int FDECL(get_hdr
, (char *));
191 static boolean
FDECL(new_id
, (char *));
192 static boolean
FDECL(known_msg
, (int, int));
193 static void FDECL(new_msg
, (char *, int, int));
194 static char *FDECL(valid_qt_summary
, (char *, BOOLEAN_P
));
195 static void FDECL(do_qt_control
, (char *));
196 static void FDECL(do_qt_text
, (char *));
197 static void NDECL(adjust_qt_hdrs
);
198 static void NDECL(put_qt_hdrs
);
201 static void NDECL(H_close_gen
);
202 static void NDECL(H_far_gen
);
203 static void NDECL(C_close_gen
);
204 static void NDECL(C_far_gen
);
205 static int FDECL(clear_path
, (int, int, int, int));
208 static char *FDECL(fgetline
, (FILE*));
209 static char *FDECL(tmpdup
, (const char *));
210 static char *FDECL(limit
, (char *, int));
211 static char *FDECL(eos
, (char *));
213 /* input, output, tmp */
214 static FILE *ifp
, *ofp
, *tfp
;
216 #if defined(__BORLANDC__) && !defined(_WIN32)
217 extern unsigned _stklen
= STKSIZ
;
220 #ifdef MACsansMPWTOOL
224 const char *def_options
= "odemvpqrshz";
228 printf("Enter options to run: [%s] ", def_options
);
230 fgets(buf
, 100, stdin
);
233 Strcpy(buf
, def_options
);
235 buf
[len
- 1] = 0; /* remove return */
237 if (buf
[0] == '-' && buf
[1] == '-') {
239 split up buf into words
240 do_ext_makedefs(fakeargc
, fakeargv
);
242 printf("extended makedefs not implemented for Mac OS9\n");
263 && !(argv
[1][0] == '-' && argv
[1][1] == '-')) {
264 Fprintf(stderr
, "Bad arg count (%d).\n", argc
- 1);
265 (void) fflush(stderr
);
270 if (argc
>= 2 && argv
[1][0] != '-') {
271 file_prefix
= argv
[1];
277 if (argv
[1][0] == '-' && argv
[1][1] == '-') {
278 do_ext_makedefs(argc
, argv
);
280 do_makedefs(&argv
[1][1]);
292 /* Note: these initializers don't do anything except guarantee that
293 we're linked properly.
303 boolean more_than_one
;
307 /* construct the current version number */
310 more_than_one
= strlen(options
) > 1;
313 Fprintf(stderr
, "makedefs -%c\n", *options
);
351 do_rnd_access_file(EPITAPHFILE
);
352 do_rnd_access_file(ENGRAVEFILE
);
353 do_rnd_access_file(BOGUSMONFILE
);
365 Fprintf(stderr
, "Unknown option '%c'.\n", *options
);
366 (void) fflush(stderr
);
372 Fprintf(stderr
, "Completed.\n"); /* feedback */
375 static char namebuf
[1000];
378 name_file(template, tag
)
379 const char *template;
382 Sprintf(namebuf
, template, tag
);
387 delete_file(template, tag
)
388 const char *template;
391 char *name
= name_file(template, tag
);
397 getfp(template, tag
, mode
)
398 const char *template;
402 char *name
= name_file(template, tag
);
403 FILE *rv
= fopen(name
, mode
);
406 Fprintf(stderr
, "Can't open '%s'.\n", name
);
412 static boolean debug
= FALSE
;
414 static FILE *inputfp
;
415 static FILE *outputfp
;
419 int is_defined
; /* 0 undef; 1 defined */
421 /* struct grep_var grep_vars[] and TODO_* constants in include file: */
424 static void NDECL(do_grep_showvars
);
425 static struct grep_var
*FDECL(grepsearch
, (const char *));
426 static int FDECL(grep_check_id
, (const char *));
427 static void FDECL(grep_show_wstack
, (const char *));
428 static char *FDECL(do_grep_control
, (char *));
429 static void NDECL(do_grep
);
430 static void FDECL(grep0
, (FILE *, FILE *));
432 static int grep_trace
= 0;
434 #define IS_OPTION(str) if (!strcmp(&argv[0][2], str))
441 Fprintf(stderr, "missing option\n"); \
442 exit(EXIT_FAILURE); \
446 do_ext_makedefs(int argc
, char **argv
)
453 argv
++; /* skip program name */
456 if (argv
[0][0] != '-')
458 if (argv
[0][1] != '-') {
459 Fprintf(stderr
, "Can't mix - and -- options.\n");
463 /* short version string for packaging - note no \n */
467 argv
++; /* not CONSUME */
470 strcpy(delim
, argv
[0]);
471 Fprintf(stdout
, "%s", version_string(buf
, delim
));
480 do_makedefs(argv
[0]);
485 if (!strcmp(argv
[0], "-")) {
488 inputfp
= fopen(argv
[0], RDTMODE
);
490 Fprintf(stderr
, "Can't open '%s'.\n", argv
[0]);
496 IS_OPTION("output") {
498 if (!strcmp(argv
[0], "-")) {
501 outputfp
= fopen(argv
[0], WRTMODE
);
503 Fprintf(stderr
, "Can't open '%s'.\n", argv
[0]);
511 Fprintf(stderr
, "Can't do grep and something else.\n");
517 IS_OPTION("grep-showvars") {
521 IS_OPTION("grep-trace") {
525 IS_OPTION("grep-define") {
529 p
= grepsearch(argv
[0]);
533 Fprintf(stderr
, "Unknown symbol '%s'\n", argv
[0]);
538 IS_OPTION("grep-undef") {
542 p
= grepsearch(argv
[0]);
546 Fprintf(stderr
, "Unknown symbol '%s'\n", argv
[0]);
555 Fprintf(stderr
, "Unknown option '%s'.\n", argv
[0]);
559 Fprintf(stderr
, "unexpected argument '%s'.\n", argv
[0]);
565 Fprintf(stderr
, "Confused about what to do?\n");
568 Fprintf(stderr
, "Nothing to do?\n");
582 * Any line NOT starting with a caret is either suppressed or passed
583 * through unchanged depending on the current conditional state.
585 * The default conditional state is printing on.
587 * Conditionals may be nested.
589 * makedefs will exit with a EXIT_FAILURE if any errors are detected;
590 * as many errors as possible are detected before giving up.
592 * Unknown identifiers are treated as TRUE and also as an error to
593 * allow processing to continue past the unknown identifier (note
594 * that "#undef" is different than unknown).
596 * Any line starting with a caret is a control line; as in C, zero or
597 * more spaces may be embedded in the line almost anywhere; the caret
598 * MUST be in column 1.
599 * (XXX for the moment, no white space is allowed after the caret because
600 * existing lines in the docs look like that.)
603 * ^^ a line starting with a (single) literal caret
604 * ^# a comment - the line is ignored
605 * ^?ID if defined(ID)
606 * ^!ID if !defined(ID)
610 #define GREP_MAGIC '^'
611 #define GREP_STACK_SIZE 100
613 static int grep_rewrite
= 0; /* need to (possibly) rewrite lines */
615 static int grep_writing
= 1; /* need to copy lines to output */
616 static int grep_errors
= 0;
617 static int grep_sp
= 0;
618 #define ST_LD(old, opp) (((old) ? 1 : 0) | ((opp) ? 2 : 0))
619 #define ST_OLD(v) (((v) & 1) != 0)
620 #define ST_OPP(v) (((v) & 2) != 0)
622 static int grep_stack
[GREP_STACK_SIZE
] = { ST_LD(1, 0) };
623 static int grep_lineno
= 0;
630 for (x
= 0; x
< SIZE(grep_vars
) - 1; x
++) {
631 printf("%d\t%s\n", grep_vars
[x
].is_defined
, grep_vars
[x
].name
);
635 static struct grep_var
*
639 /* XXX make into binary search */
642 while (x
< SIZE(grep_vars
) - 1) {
643 if (!strcmp(grep_vars
[x
].name
, name
))
644 return &grep_vars
[x
];
656 while (*id
&& isspace((uchar
) *id
))
659 Fprintf(stderr
, "missing identifier in line %d", grep_lineno
);
666 Fprintf(outputfp
, "ID %d %s\n", rv
->is_defined
, id
);
668 return rv
->is_defined
;
672 Fprintf(outputfp
, "ID U %s\n", id
);
674 Fprintf(stderr
, "unknown identifier '%s' in line %d.\n", id
, grep_lineno
);
676 return 2; /* So new features can be checked before makedefs
681 grep_show_wstack(tag
)
689 Fprintf(outputfp
, "%s w=%d sp=%d\t", tag
, grep_writing
, grep_sp
);
690 for (x
= grep_sp
; x
>= 0 && x
> grep_sp
- 6; x
--) {
691 Fprintf(outputfp
, "[%d]=%d ", x
, grep_stack
[x
]);
693 Fprintf(outputfp
, "\n");
703 if (isspace((uchar
) buf
[0]))
704 return &buf
[-1]; /* XXX see docs above */
706 while (buf
[0] && isspace((uchar
) buf
[0]))
710 case '#': /* comment */
712 case '.': /* end of if level */
714 Fprintf(stderr
, "unmatched ^. (endif) at line %d.\n",
718 grep_writing
= ST_OLD(grep_stack
[grep_sp
--]);
719 grep_show_wstack("pop");
722 case '!': /* if not ID */
725 case '?': /* if ID */
726 if (grep_sp
== GREP_STACK_SIZE
- 2) {
727 Fprintf(stderr
, "stack overflow at line %d.", grep_lineno
);
731 isif
= grep_check_id(&buf
[1]) ? isif
: !isif
;
732 grep_stack
[++grep_sp
] = ST_LD(grep_writing
, !isif
);
735 grep_stack
[++grep_sp
] = ST_LD(0, 0);
736 /* grep_writing = 0; */
738 grep_show_wstack("push");
741 if (ST_ELSE
& grep_stack
[grep_sp
]) {
742 Fprintf(stderr
, "multiple : for same conditional at line %d.\n",
746 grep_writing
= ST_OPP(grep_stack
[grep_sp
]);
747 grep_stack
[grep_sp
] |= ST_ELSE
;
750 case '(': /* start of expression */
752 case GREP_MAGIC
: /* ^^ -> ^ */
757 if (isprint((uchar
) buf
[0])) {
761 sprintf(str
, "0x%02x", buf
[0]);
763 Fprintf(stderr
, "unknown control ^%s at line %d.\n", str
,
776 /* no language features use this yet */
781 static void grep0(FILE *, FILE *);
787 Fprintf(stderr
, "--grep requires --input\n");
790 Fprintf(stderr
, "--grep requires --output\n");
792 if (!inputfp
|| !outputfp
) {
796 grep0(inputfp
, outputfp
);
800 grep0(inputfp0
, outputfp0
)
804 char buf
[16384]; /* looong, just in case */
806 while (!feof(inputfp0
) && !ferror(inputfp0
)) {
810 if (fgets(buf
, sizeof(buf
), inputfp0
) == 0)
812 if ((tmp
= strchr(buf
, '\n')))
816 Fprintf(outputfp0
, "%04d %c >%s\n", grep_lineno
,
817 grep_writing
? ' ' : '#', buf
);
820 if (buf
[0] == GREP_MAGIC
) {
821 buf1
= do_grep_control(&buf
[1]);
829 do_grep_rewrite(buf1
);
832 Fprintf(outputfp0
, "%s\n", buf1
);
834 if (ferror(inputfp0
)) {
835 Fprintf(stderr
, "read error!\n");
838 if (ferror(outputfp0
)) {
839 Fprintf(stderr
, "write error!\n");
845 Fprintf(stderr
, "%d unterminated conditional level%s\n", grep_sp
,
846 grep_sp
== 1 ? "" : "s");
850 Fprintf(stderr
, "%d error%s detected.\n", grep_errors
,
851 grep_errors
== 1 ? "" : "s");
856 /* trivial text encryption routine which can't be broken with `tr' */
860 { /* duplicated in src/hacklib.c */
861 static char buf
[BUFSZ
];
862 register const char *p
;
864 register int bitmask
;
866 for (bitmask
= 1, p
= str
, q
= buf
; *p
; q
++) {
870 if ((bitmask
<<= 1) >= 32)
877 #define PAD_RUMORS_TO 60
878 /* common code for do_rumors(). Return 0 on error. */
880 read_rumors_file(file_ext
, rumor_count
, rumor_size
, old_rumor_offset
)
881 const char *file_ext
;
884 unsigned long old_rumor_offset
;
888 unsigned long rumor_offset
;
890 Sprintf(infile
, DATA_IN_TEMPLATE
, RUMOR_FILE
);
891 Strcat(infile
, file_ext
);
892 if (!(ifp
= fopen(infile
, RDTMODE
))) {
897 /* copy the rumors */
898 while ((line
= fgetline(ifp
)) != 0) {
900 /* rumor selection is accomplished by seeking to a random
901 position in the file, advancing to newline, and taking
902 the next line; therefore, rumors which follow long-line
903 rumors are most likely to be chosen and rumors which
904 follow short-line rumors are least likely to be chosen;
905 we ameliorate the latter by padding the shortest lines,
906 increasing the chance of the random seek landing in them */
907 int len
= (int) strlen(line
);
909 if (len
<= PAD_RUMORS_TO
) {
910 char *base
= index(line
, '\n');
911 /* this is only safe because fgetline() overallocates */
912 while (len
++ < PAD_RUMORS_TO
) {
921 /*[if we forced binary output, this would be sufficient]*/
922 *rumor_size
+= strlen(line
); /* includes newline */
924 (void) fputs(xcrypt(line
), tfp
);
927 /* record the current position; next rumors section will start here */
928 rumor_offset
= (unsigned long) ftell(tfp
);
929 Fclose(ifp
); /* all done with rumors.file_ext */
931 /* the calculated value for *_rumor_count assumes that
932 a single-byte line terminator is in use; for platforms
933 which use two byte CR+LF, we need to override that value
934 [it's much simpler to do so unconditionally, rendering
935 the loop's accumulation above obsolete] */
936 *rumor_size
= (long) (rumor_offset
- old_rumor_offset
);
941 do_rnd_access_file(fname
)
946 Sprintf(filename
, DATA_IN_TEMPLATE
, fname
);
947 Strcat(filename
, ".txt");
948 if (!(ifp
= fopen(filename
, RDTMODE
))) {
954 Strcat(filename
, file_prefix
);
956 Sprintf(eos(filename
), DATA_TEMPLATE
, fname
);
957 if (!(ofp
= fopen(filename
, WRTMODE
))) {
961 Fprintf(ofp
, "%s", Dont_Edit_Data
);
963 tfp
= getfp(DATA_TEMPLATE
, "grep.tmp", WRTMODE
);
965 ifp
= getfp(DATA_TEMPLATE
, "grep.tmp", RDTMODE
);
967 while ((line
= fgetline(ifp
)) != 0) {
968 if (line
[0] != '#' && line
[0] != '\n')
969 (void) fputs(xcrypt(line
), ofp
);
975 delete_file(DATA_TEMPLATE
, "grep.tmp");
983 static const char rumors_header
[] =
984 "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n";
986 int true_rumor_count
, false_rumor_count
;
987 long true_rumor_size
, false_rumor_size
;
988 unsigned long true_rumor_offset
, false_rumor_offset
, eof_offset
;
990 Sprintf(tempfile
, DATA_TEMPLATE
, "rumors.tmp");
993 Strcat(filename
, file_prefix
);
995 Sprintf(eos(filename
), DATA_TEMPLATE
, RUMOR_FILE
);
996 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1000 if (!(tfp
= fopen(tempfile
, WRTMODE
))) {
1006 true_rumor_count
= false_rumor_count
= 0;
1007 true_rumor_size
= false_rumor_size
= 0L;
1008 true_rumor_offset
= false_rumor_offset
= eof_offset
= 0L;
1010 /* output a dummy header record; we'll replace it in final output */
1011 Fprintf(tfp
, rumors_header
, Dont_Edit_Data
, true_rumor_count
,
1012 true_rumor_size
, true_rumor_offset
, false_rumor_count
,
1013 false_rumor_size
, false_rumor_offset
, eof_offset
);
1014 /* record the current position; true rumors will start here */
1015 true_rumor_offset
= ftell(tfp
);
1017 false_rumor_offset
= read_rumors_file(
1018 ".tru", &true_rumor_count
, &true_rumor_size
, true_rumor_offset
);
1019 if (!false_rumor_offset
)
1020 goto rumors_failure
;
1022 eof_offset
= read_rumors_file(".fal", &false_rumor_count
,
1023 &false_rumor_size
, false_rumor_offset
);
1025 goto rumors_failure
;
1027 /* get ready to transfer the contents of temp file to output file */
1029 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1030 if (rewind(tfp
) != 0) {
1033 goto rumors_failure
;
1037 /* output the header record */
1038 Fprintf(ofp
, rumors_header
, Dont_Edit_Data
, true_rumor_count
,
1039 true_rumor_size
, true_rumor_offset
, false_rumor_count
,
1040 false_rumor_size
, false_rumor_offset
, eof_offset
);
1041 /* skip the temp file's dummy header */
1042 if (!(line
= fgetline(tfp
))) { /* "Don't Edit" */
1044 goto rumors_failure
;
1047 if (!(line
= fgetline(tfp
))) { /* count,size,offset */
1049 goto rumors_failure
;
1052 /* copy the rest of the temp file into the final output file */
1053 while ((line
= fgetline(tfp
)) != 0) {
1054 (void) fputs(line
, ofp
);
1057 /* all done; delete temp file */
1065 Unlink(filename
); /* kill empty or incomplete output file */
1067 Unlink(tempfile
); /* and temporary file */
1072 * Use this to explicitly mask out features during version checks.
1074 * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features
1075 * that the port/plaform which wrote the savefile was capable of
1076 * dealing with. Don't reject a savefile just because the port
1077 * reading the savefile doesn't match on all/some of them.
1078 * The actual compression features used to produce the savefile are
1079 * recorded in the savefile_info structure immediately following the
1080 * version_info, and that is what needs to be checked against the
1081 * feature set of the port that is reading the savefile back in.
1082 * That check is done in src/restore.c now.
1085 #define IGNORED_FEATURES \
1086 (0L | (1L << 19) /* SCORE_ON_BOTL */ \
1087 | (1L << 27) /* ZEROCOMP */ \
1088 | (1L << 28) /* RLECOMP */ \
1097 * integer version number
1099 version
.incarnation
= ((unsigned long) VERSION_MAJOR
<< 24)
1100 | ((unsigned long) VERSION_MINOR
<< 16)
1101 | ((unsigned long) PATCHLEVEL
<< 8)
1102 | ((unsigned long) EDITLEVEL
);
1104 * encoded feature list
1105 * Note: if any of these magic numbers are changed or reassigned,
1106 * EDITLEVEL in patchlevel.h should be incremented at the same time.
1107 * The actual values have no special meaning, and the category
1108 * groupings are just for convenience.
1110 version
.feature_set
= (unsigned long) (0L
1111 /* levels and/or topology (0..4) */
1112 /* monsters (5..9) */
1116 /* objects (10..14) */
1117 /* flag bits and/or other global variables (15..26) */
1124 #ifdef SCORE_ON_BOTL
1127 /* data format (27..31)
1128 * External compression methods such as COMPRESS and ZLIB_COMP
1129 * do not affect the contents and are thus excluded from here */
1138 * Value used for object & monster sanity check.
1139 * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
1141 for (i
= 1; artifact_names
[i
]; i
++)
1143 version
.entity_count
= (unsigned long) (i
- 1);
1144 for (i
= 1; objects
[i
].oc_class
!= ILLOBJ_CLASS
; i
++)
1146 version
.entity_count
= (version
.entity_count
<< 12) | (unsigned long) i
;
1147 for (i
= 0; mons
[i
].mlet
; i
++)
1149 version
.entity_count
= (version
.entity_count
<< 12) | (unsigned long) i
;
1151 * Value used for compiler (word size/field alignment/padding) check.
1153 version
.struct_sizes1
=
1154 (((unsigned long) sizeof(struct context_info
) << 24)
1155 | ((unsigned long) sizeof(struct obj
) << 17)
1156 | ((unsigned long) sizeof(struct monst
) << 10)
1157 | ((unsigned long) sizeof(struct you
)));
1158 version
.struct_sizes2
= (((unsigned long) sizeof(struct flag
) << 10) |
1159 /* free bits in here */
1161 ((unsigned long) sizeof(struct sysflag
)));
1163 ((unsigned long) 0L));
1168 /* REPRODUCIBLE_BUILD will change this to TRUE */
1169 static boolean date_via_env
= FALSE
;
1172 version_string(outbuf
, delim
)
1176 Sprintf(outbuf
, "%d%s%d%s%d", VERSION_MAJOR
, delim
, VERSION_MINOR
, delim
,
1179 Sprintf(eos(outbuf
), "-%d", EDITLEVEL
);
1185 version_id_string(outbuf
, build_date
)
1187 const char *build_date
;
1189 char subbuf
[64], versbuf
[64];
1194 Strcpy(&subbuf
[1], PORT_SUB_ID
);
1197 Strcat(subbuf
, " Beta");
1200 Sprintf(outbuf
, "%s aNetHack%s Version %s - last %s %s.", PORT_ID
,
1201 subbuf
, version_string(versbuf
, "."),
1202 date_via_env
? "revision" : "build", build_date
);
1207 bannerc_string(outbuf
, build_date
)
1209 const char *build_date
;
1211 char subbuf
[64], versbuf
[64];
1216 Strcpy(&subbuf
[1], PORT_SUB_ID
);
1219 Strcat(subbuf
, " Beta");
1222 Sprintf(outbuf
, " Version %s %s%s, %s %s.",
1223 version_string(versbuf
, "."), PORT_ID
, subbuf
,
1224 date_via_env
? "revised" : "built", &build_date
[4]);
1226 Sprintf(outbuf
, "%s aNetHack%s %s Copyright 1985-%s (built %s)",
1227 PORT_ID
, subbuf
, version_string(versbuf
,"."), RELEASE_YEAR
,
1239 time_t clocktim
= 0;
1241 char *c
, cbuf
[60], buf
[BUFSZ
];
1244 /* before creating date.h, make sure that xxx_GRAPHICS and
1245 DEFAULT_WINDOW_SYS have been set up in a viable fashion */
1250 Strcat(filename
, file_prefix
);
1252 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, DATE_FILE
);
1253 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1257 /* NB: We've moved on from SCCS, but this way this line
1258 * won't get clobbered when downstream projects import
1259 * this file into something more modern. */
1260 Fprintf(ofp
, "%s", Dont_Edit_Code
);
1262 (void) time(&clocktim
);
1263 #ifdef REPRODUCIBLE_BUILD
1266 * Use date+time of latest source file revision (set up in
1267 * our environment rather than derived by scanning sources)
1268 * instead of current date+time, so that later rebuilds of
1269 * the same sources specifying the same configuration will
1270 * produce the same result.
1272 * Changing the configuration should be done by modifying
1273 * config.h or <port>conf.h and setting SOURCE_DATE_EPOCH
1274 * based on whichever changed most recently, not by using
1275 * make CFLAGS='-Dthis -Dthat'
1276 * to make alterations on the fly.
1278 * Limited validation is performed to prevent dates in the
1279 * future (beyond a leeway of 24 hours) or distant past.
1281 * Assumes the value of time_t is in seconds, which is
1282 * fundamental for Unix and mandated by POSIX. For any ports
1283 * where that isn't true, leaving REPRODUCIBLE_BUILD disabled
1284 * is probably preferrable to hacking this code....
1286 static struct tm nh360
; /* static init should yield UTC timezone */
1287 unsigned long sd_num
, sd_earliest
, sd_latest
;
1288 const char *sd_str
= getenv("SOURCE_DATE_EPOCH");
1291 sd_num
= strtoul(sd_str
, (char **) 0, 10);
1293 * Note: this does not need to be updated for future
1294 * releases. It serves as a sanity check for potentially
1295 * mis-set environment, not a hard baseline for when the
1296 * current version could have first been built.
1298 /* oldest date we'll accept: 7-Dec-2015 (release of 3.6.0) */
1300 nh360
.tm_mon
= 12 - 1;
1301 nh360
.tm_year
= 2015 - 1900;
1302 sd_earliest
= (unsigned long) mktime(&nh360
);
1303 /* 'youngest' date we'll accept: 24 hours in the future */
1304 sd_latest
= (unsigned long) clocktim
+ 24L * 60L * 60L;
1306 if (sd_num
>= sd_earliest
&& sd_num
<= sd_latest
) {
1307 /* use SOURCE_DATE_EPOCH value */
1308 clocktim
= (time_t) sd_num
;
1309 date_via_env
= TRUE
;
1311 Fprintf(stderr
, "? Invalid value for SOURCE_DATE_EPOCH (%lu)",
1313 if (sd_num
> 0L && sd_num
< sd_earliest
)
1314 Fprintf(stderr
, ", older than %lu", sd_earliest
);
1315 else if (sd_num
> sd_latest
)
1316 Fprintf(stderr
, ", newer than %lu", sd_latest
);
1317 Fprintf(stderr
, ".\n");
1318 Fprintf(stderr
, ": Reverting to current date+time (%lu).\n",
1319 (unsigned long) clocktim
);
1320 (void) fflush(stderr
);
1323 /* REPRODUCIBLE_BUILD enabled but SOURCE_DATE_EPOCH is missing */
1324 Fprintf(stderr
, "? No value for SOURCE_DATE_EPOCH.\n");
1325 Fprintf(stderr
, ": Using current date+time (%lu).\n",
1326 (unsigned long) clocktim
);
1327 (void) fflush(stderr
);
1329 Strcpy(cbuf
, asctime(gmtime(&clocktim
)));
1332 /* ordinary build: use current date+time */
1333 Strcpy(cbuf
, ctime(&clocktim
));
1336 if ((c
= index(cbuf
, '\n')) != 0)
1337 *c
= '\0'; /* strip off the '\n' */
1344 Fprintf(ofp
, "#define SOURCE_DATE_EPOCH (%lu%s) /* via getenv() */\n",
1345 (unsigned long) clocktim
, ul_sfx
);
1346 Fprintf(ofp
, "#define BUILD_DATE \"%s\"\n", cbuf
);
1348 Fprintf(ofp
, "#define BUILD_TIME SOURCE_DATE_EPOCH\n");
1350 Fprintf(ofp
, "#define BUILD_TIME (%lu%s)\n",
1351 (unsigned long) clocktim
, ul_sfx
);
1353 Fprintf(ofp
, "#define VERSION_NUMBER 0x%08lx%s\n", version
.incarnation
,
1355 Fprintf(ofp
, "#define VERSION_FEATURES 0x%08lx%s\n", version
.feature_set
,
1357 #ifdef IGNORED_FEATURES
1358 Fprintf(ofp
, "#define IGNORED_FEATURES 0x%08lx%s\n",
1359 (unsigned long) IGNORED_FEATURES
, ul_sfx
);
1361 Fprintf(ofp
, "#define VERSION_SANITY1 0x%08lx%s\n", version
.entity_count
,
1363 Fprintf(ofp
, "#define VERSION_SANITY2 0x%08lx%s\n", version
.struct_sizes1
,
1365 Fprintf(ofp
, "#define VERSION_SANITY3 0x%08lx%s\n", version
.struct_sizes2
,
1368 Fprintf(ofp
, "#define VERSION_STRING \"%s\"\n", version_string(buf
, "."));
1369 Fprintf(ofp
, "#define VERSION_ID \\\n \"%s\"\n",
1370 version_id_string(buf
, cbuf
));
1371 Fprintf(ofp
, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n",
1372 bannerc_string(buf
, cbuf
));
1376 struct tm
*tm
= localtime((time_t *) &clocktim
);
1378 Fprintf(ofp
, "#define AMIGA_VERSION_STRING ");
1379 Fprintf(ofp
, "\"\\0$VER: aNetHack %d.%d.%d (%d.%d.%d)\"\n",
1380 VERSION_MAJOR
, VERSION_MINOR
, PATCHLEVEL
,
1381 tm
->tm_mday
, tm
->tm_mon
+ 1, tm
->tm_year
+ 1900);
1388 static char save_bones_compat_buf
[BUFSZ
];
1391 build_savebones_compat_string()
1393 #ifdef VERSION_COMPATIBILITY
1394 unsigned long uver
= VERSION_COMPATIBILITY
;
1396 Strcpy(save_bones_compat_buf
,
1397 "save and bones files accepted from version");
1398 #ifdef VERSION_COMPATIBILITY
1399 Sprintf(eos(save_bones_compat_buf
), "s %lu.%lu.%lu through %d.%d.%d",
1400 ((uver
& 0xFF000000L
) >> 24), ((uver
& 0x00FF0000L
) >> 16),
1401 ((uver
& 0x0000FF00L
) >> 8), VERSION_MAJOR
, VERSION_MINOR
,
1404 Sprintf(eos(save_bones_compat_buf
), " %d.%d.%d only", VERSION_MAJOR
,
1405 VERSION_MINOR
, PATCHLEVEL
);
1409 static const char *build_opts
[] = {
1411 "Amiga WorkBench support",
1414 "ANSI default terminal",
1419 #ifdef TTY_TILES_ESCCODES
1420 "console escape codes for tile hinting",
1423 "command line completion",
1426 "Conway's Game of Life",
1429 "data file compression",
1432 "ZLIB data file compression",
1438 "end-of-game dumplogs",
1441 "floppy drive support",
1444 "insurance files for recovering from crashes",
1446 #ifdef HOLD_LOCKFILE_OPEN
1447 "exclusive lock on level 0 file",
1449 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
1450 "external program as a message handler",
1459 "MSDOS protected mode",
1476 "restore saved games via menu",
1478 #ifdef SCORE_ON_BOTL
1479 "score on status line",
1486 "screen control via mactty",
1489 "screen control via BIOS",
1491 #ifdef SCREEN_DJGPPFAST
1492 "screen control via DJGPP fast",
1495 "screen control via VGA graphics",
1498 "screen control via WIN32 console I/O",
1504 #ifdef STATUS_VIA_WINDOWPORT
1505 # ifdef STATUS_HILITES
1506 "status via windowport with highlighting",
1508 "status via windowport without highlighting",
1511 "traditional status display",
1517 "terminal info library",
1519 #if defined(TERMLIB) \
1520 || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
1521 "terminal capability library",
1525 "timed wait for display effects",
1530 #ifdef PREFIXES_IN_USE
1531 "variable playground",
1533 #ifdef VISION_TABLES
1537 "zero-compressed save files",
1540 "run-length compression of map in save files",
1543 "system configuration at run-time",
1545 save_bones_compat_buf
, "and basic aNetHack features"
1549 const char *id
, /* DEFAULT_WINDOW_SYS string */
1550 *name
; /* description, often same as id */
1552 static struct win_info window_opts
[] = {
1554 { "tty", "traditional tty-based graphics" },
1562 #ifdef GNOME_GRAPHICS
1563 { "Gnome", "Gnome" },
1568 #ifdef AMIGA_INTUITION
1569 { "amii", "Amiga Intuition" },
1574 #ifdef MSWIN_GRAPHICS
1575 { "mswin", "mswin" },
1577 #ifdef BEOS_GRAPHICS
1578 { "BeOS", "BeOS InterfaceKit" },
1586 #ifndef DEFAULT_WINDOW_SYS
1587 /* pre-standard compilers didn't support #error; wait til run-time */
1589 "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n");
1593 /* put in a dummy value so that do_options() will compile and makedefs
1594 will build, otherwise the message above won't ever get delivered */
1595 #define DEFAULT_WINDOW_SYS "<undefined>"
1596 #else /*DEFAULT_WINDOW_SYS*/
1598 if (!window_opts
[0].id
) {
1599 Fprintf(stderr
, "Configuration error: no windowing systems "
1600 "(TTY_GRAPHICS, &c) enabled.\n");
1607 for (i
= 0; window_opts
[i
].id
; ++i
)
1608 if (!strcmp(window_opts
[i
].id
, DEFAULT_WINDOW_SYS
))
1611 .id
) { /* went through whole list without a match */
1612 Fprintf(stderr
, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n",
1613 DEFAULT_WINDOW_SYS
);
1615 " does not match any enabled windowing system (%s%s).\n",
1616 window_opts
[0].id
, window_opts
[1].id
? ", &c" : "");
1620 #endif /*DEFAULT_WINDOW_SYS*/
1626 static const char indent
[] = " ";
1627 const char *str
, *sep
;
1628 char *word
, buf
[BUFSZ
];
1629 int i
, length
, winsyscnt
;
1635 Strcat(filename
, file_prefix
);
1637 Sprintf(eos(filename
), DATA_TEMPLATE
, OPTIONS_FILE
);
1638 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1643 build_savebones_compat_string();
1646 "\n aNetHack version %d.%d.%d [beta]\n",
1648 "\n aNetHack version %d.%d.%d\n",
1650 VERSION_MAJOR
, VERSION_MINOR
, PATCHLEVEL
);
1652 Fprintf(ofp
, "\nOptions compiled into this edition:\n");
1653 length
= COLNO
+ 1; /* force 1st item onto new line */
1654 for (i
= 0; i
< SIZE(build_opts
); i
++) {
1655 str
= strcpy(buf
, build_opts
[i
]);
1657 word
= index(str
, ' ');
1660 if (length
+ strlen(str
) > COLNO
- 5)
1661 Fprintf(ofp
, "\n%s", indent
), length
= strlen(indent
);
1663 Fprintf(ofp
, " "), length
++;
1664 Fprintf(ofp
, "%s", str
), length
+= strlen(str
);
1665 str
+= strlen(str
) + (word
? 1 : 0);
1667 Fprintf(ofp
, (i
< SIZE(build_opts
) - 1) ? "," : "."), length
++;
1670 winsyscnt
= SIZE(window_opts
) - 1;
1671 Fprintf(ofp
, "\n\nSupported windowing system%s:\n",
1672 (winsyscnt
> 1) ? "s" : "");
1673 length
= COLNO
+ 1; /* force 1st item onto new line */
1674 for (i
= 0; i
< winsyscnt
; i
++) {
1675 str
= window_opts
[i
].name
;
1676 if (length
+ strlen(str
) > COLNO
- 5)
1677 Fprintf(ofp
, "\n%s", indent
), length
= strlen(indent
);
1679 Fprintf(ofp
, " "), length
++;
1680 Fprintf(ofp
, "%s", str
), length
+= strlen(str
);
1681 sep
= (winsyscnt
== 1)
1684 ? ((i
== 0) ? " and" : "")
1685 : (i
< winsyscnt
- 2)
1687 : ((i
== winsyscnt
- 2) ? ", and" : "");
1688 Fprintf(ofp
, "%s", sep
), length
+= strlen(sep
);
1691 Fprintf(ofp
, "\n%swith a default of %s.", indent
, DEFAULT_WINDOW_SYS
);
1692 Fprintf(ofp
, "\n\n");
1698 /* routine to decide whether to discard something from data.base */
1704 return TRUE
; /* ignore comment lines */
1710 New format (v3.1) of 'data' file which allows much faster lookups [pr]
1711 "do not edit" first record is a comment line
1712 01234567 hexadecimal formatted offset to text area
1713 name-a first name of interest
1714 123,4 offset to name's text, and number of lines for it
1715 name-b next name of interest
1716 name-c multiple names which share same description also
1717 456,7 share a single offset,count line
1718 . sentinel to mark end of names
1719 789,0 dummy record containing offset, count of EOF
1720 text-a 4 lines of descriptive text for name-a
1721 text-a at file position 0x01234567L + 123L
1724 text-b/text-c 7 lines of text for names-b and -c
1725 text-b/text-c at fseek(0x01234567L + 456L)
1733 char infile
[60], tempfile
[60];
1736 int entry_cnt
, line_cnt
;
1739 Sprintf(tempfile
, DATA_TEMPLATE
, "database.tmp");
1742 Strcat(filename
, file_prefix
);
1744 Sprintf(eos(filename
), DATA_TEMPLATE
, DATA_FILE
);
1745 Sprintf(infile
, DATA_IN_TEMPLATE
, DATA_FILE
);
1746 #ifdef SHORT_FILENAMES
1747 Strcat(infile
, ".bas");
1749 Strcat(infile
, ".base");
1751 if (!(ifp
= fopen(infile
, RDTMODE
))) { /* data.base */
1755 if (!(ofp
= fopen(filename
, WRTMODE
))) { /* data */
1760 if (!(tfp
= fopen(tempfile
, WRTMODE
))) { /* database.tmp */
1768 /* output a dummy header record; we'll rewind and overwrite it later */
1769 Fprintf(ofp
, "%s%08lx\n", Dont_Edit_Data
, 0L);
1771 entry_cnt
= line_cnt
= 0;
1772 /* read through the input file and split it into two sections */
1773 while ((line
= fgetline(ifp
)) != 0) {
1774 if (d_filter(line
)) {
1778 if (*line
> ' ') { /* got an entry name */
1779 /* first finish previous entry */
1781 Fprintf(ofp
, "%d\n", line_cnt
), line_cnt
= 0;
1782 /* output the entry name */
1783 (void) fputs(line
, ofp
);
1784 entry_cnt
++; /* update number of entries */
1785 } else if (entry_cnt
) { /* got some descriptive text */
1786 /* update previous entry with current text offset */
1788 Fprintf(ofp
, "%ld,", ftell(tfp
));
1789 /* save the text line in the scratch file */
1790 (void) fputs(line
, tfp
);
1791 line_cnt
++; /* update line counter */
1795 /* output an end marker and then record the current position */
1797 Fprintf(ofp
, "%d\n", line_cnt
);
1798 Fprintf(ofp
, ".\n%ld,%d\n", ftell(tfp
), 0);
1799 txt_offset
= ftell(ofp
);
1800 Fclose(ifp
); /* all done with original input file */
1802 /* reprocess the scratch file; 1st format an error msg, just in case */
1804 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1805 if (rewind(tfp
) != 0)
1808 /* copy all lines of text from the scratch file into the output file */
1809 while ((line
= fgetline(tfp
)) != 0) {
1810 (void) fputs(line
, ofp
);
1814 /* finished with scratch file */
1816 Unlink(tempfile
); /* remove it */
1818 /* update the first record of the output file; prepare error msg 1st */
1820 Sprintf(line
, "rewind of \"%s\"", filename
);
1821 ok
= (rewind(ofp
) == 0);
1823 Sprintf(line
, "header rewrite of \"%s\"", filename
);
1824 ok
= (fprintf(ofp
, "%s%08lx\n", Dont_Edit_Data
,
1825 (unsigned long) txt_offset
) >= 0);
1829 perror(line
); /* report the problem */
1831 /* close and kill the aborted output file, then give up */
1844 /* routine to decide whether to discard something from oracles.txt */
1849 static boolean skip
= FALSE
;
1855 return TRUE
; /* ignore comment lines */
1857 tag
= malloc(strlen(line
));
1858 if (sscanf(line
, "----- %s", tag
) == 1) {
1860 } else if (skip
&& !strncmp(line
, "-----", 5))
1866 static const char *special_oracle
[] = {
1867 "\"...it is rather disconcerting to be confronted with the",
1868 "following theorem from [Baker, Gill, and Solovay, 1975].", "",
1869 "Theorem 7.18 There exist recursive languages A and B such that",
1870 " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "",
1871 "This provides impressive evidence that the techniques that are",
1872 "currently available will not suffice for proving that P != NP or "
1874 "that P == NP.\" [Garey and Johnson, p. 185.]"
1878 The oracle file consists of a "do not edit" comment, a decimal count N
1879 and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
1880 records, separated by "---" lines. The first oracle is a special case.
1881 The input data contains just those multi-line records, separated by
1888 char infile
[60], tempfile
[60];
1889 boolean in_oracle
, ok
;
1891 unsigned long txt_offset
, offset
;
1896 Sprintf(tempfile
, DATA_TEMPLATE
, "oracles.tmp");
1899 Strcat(filename
, file_prefix
);
1901 Sprintf(eos(filename
), DATA_TEMPLATE
, ORACLE_FILE
);
1902 Sprintf(infile
, DATA_IN_TEMPLATE
, ORACLE_FILE
);
1903 Strcat(infile
, ".txt");
1904 if (!(ifp
= fopen(infile
, RDTMODE
))) {
1908 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1913 if (!(tfp
= fopen(tempfile
, WRTMODE
))) { /* oracles.tmp */
1921 /* output a dummy header record; we'll rewind and overwrite it later */
1922 Fprintf(ofp
, "%s%5d\n", Dont_Edit_Data
, 0);
1924 /* handle special oracle; it must come first */
1925 (void) fputs("---\n", tfp
);
1926 offset
= (unsigned long) ftell(tfp
);
1927 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of special oracle */
1928 for (i
= 0; i
< SIZE(special_oracle
); i
++) {
1929 (void) fputs(xcrypt(special_oracle
[i
]), tfp
);
1930 (void) fputc('\n', tfp
);
1935 (void) fputs("---\n", tfp
);
1936 offset
= (unsigned long) ftell(tfp
);
1937 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of first oracle */
1940 while ((line
= fgetline(ifp
)) != 0) {
1943 if (h_filter(line
)) {
1947 if (!strncmp(line
, "-----", 5)) {
1954 (void) fputs("---\n", tfp
);
1955 offset
= (unsigned long) ftell(tfp
);
1956 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of this oracle */
1959 (void) fputs(xcrypt(line
), tfp
);
1964 if (in_oracle
) { /* need to terminate last oracle */
1966 (void) fputs("---\n", tfp
);
1967 offset
= (unsigned long) ftell(tfp
);
1968 Fprintf(ofp
, "%05lx\n", offset
); /* eof position */
1971 /* record the current position */
1972 txt_offset
= (unsigned long) ftell(ofp
);
1973 Fclose(ifp
); /* all done with original input file */
1975 /* reprocess the scratch file; 1st format an error msg, just in case */
1977 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1978 if (rewind(tfp
) != 0)
1981 /* copy all lines of text from the scratch file into the output file */
1982 while ((line
= fgetline(tfp
)) != 0) {
1983 (void) fputs(line
, ofp
);
1987 /* finished with scratch file */
1989 Unlink(tempfile
); /* remove it */
1991 /* update the first record of the output file; prepare error msg 1st */
1993 Sprintf(line
, "rewind of \"%s\"", filename
);
1994 ok
= (rewind(ofp
) == 0);
1996 Sprintf(line
, "header rewrite of \"%s\"", filename
);
1997 ok
= (fprintf(ofp
, "%s%5d\n", Dont_Edit_Data
, oracle_cnt
) >= 0);
2000 Sprintf(line
, "data rewrite of \"%s\"", filename
);
2001 for (i
= 0; i
<= oracle_cnt
; i
++) {
2002 #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */
2003 if (!(ok
= (fflush(ofp
) == 0)))
2006 if (!(ok
= (fpos
= ftell(ofp
)) >= 0))
2008 if (!(ok
= (fseek(ofp
, fpos
, SEEK_SET
) >= 0)))
2010 if (!(ok
= (fscanf(ofp
, "%5lx", &offset
) == 1)))
2015 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
2016 (ANSI C Libraries) needs this rewind or else the fprintf
2017 stops working. This may also be true for CW11, but has
2023 if (!(ok
= (fseek(ofp
, fpos
, SEEK_SET
) >= 0)))
2025 offset
+= txt_offset
;
2026 if (!(ok
= (fprintf(ofp
, "%05lx\n", offset
) >= 0)))
2032 perror(line
); /* report the problem */
2034 /* close and kill the aborted output file, then give up */
2052 Sprintf(filename
, DATA_IN_TEMPLATE
, DGN_I_FILE
);
2053 if (!(ifp
= fopen(filename
, RDTMODE
))) {
2059 Strcat(filename
, file_prefix
);
2061 Sprintf(eos(filename
), DGN_TEMPLATE
, DGN_O_FILE
);
2062 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2066 Fprintf(ofp
, "%s", Dont_Edit_Data
);
2068 tfp
= getfp(DATA_TEMPLATE
, "grep.tmp", WRTMODE
);
2070 ifp
= getfp(DATA_TEMPLATE
, "grep.tmp", RDTMODE
);
2072 while ((line
= fgetline(ifp
)) != 0) {
2075 if (line
[0] == '#') {
2077 continue; /* discard comments */
2079 (void) fputs(line
, ofp
);
2085 delete_file(DATA_TEMPLATE
, "grep.tmp");
2090 ranged_attk(ptr
) /* returns TRUE if monster can attack at range */
2091 register struct permonst
*ptr
;
2094 register int atk_mask
= (1 << AT_BREA
) | (1 << AT_SPIT
) | (1 << AT_GAZE
);
2096 for (i
= 0; i
< NATTK
; i
++) {
2097 if ((j
= ptr
->mattk
[i
].aatyp
) >= AT_WEAP
|| (atk_mask
& (1 << j
)))
2104 /* This routine is designed to return an integer value which represents
2105 * an approximation of monster strength. It uses a similar method of
2106 * determination as "experience()" to arrive at the strength.
2110 struct permonst
*ptr
;
2112 int i
, tmp2
, n
, tmp
= ptr
->mlevel
;
2114 if (tmp
> 49) /* special fixed hp monster */
2115 tmp
= 2 * (tmp
- 6) / 4;
2117 /* For creation in groups */
2118 n
= (!!(ptr
->geno
& G_SGROUP
));
2119 n
+= (!!(ptr
->geno
& G_LGROUP
)) << 1;
2121 /* For ranged attacks */
2122 if (ranged_attk(ptr
))
2125 /* For higher ac values */
2129 /* For very fast monsters */
2130 n
+= (ptr
->mmove
>= 18);
2132 /* For each attack and "special" attack */
2133 for (i
= 0; i
< NATTK
; i
++) {
2134 tmp2
= ptr
->mattk
[i
].aatyp
;
2136 n
+= (tmp2
== AT_MAGC
);
2137 n
+= (tmp2
== AT_WEAP
&& (ptr
->mflags2
& M2_STRONG
));
2140 /* For each "special" damage type */
2141 for (i
= 0; i
< NATTK
; i
++) {
2142 tmp2
= ptr
->mattk
[i
].adtyp
;
2143 if ((tmp2
== AD_DRLI
) || (tmp2
== AD_STON
) || (tmp2
== AD_DRST
)
2144 || (tmp2
== AD_DRDX
) || (tmp2
== AD_DRCO
) || (tmp2
== AD_WERE
))
2146 else if (strcmp(ptr
->mname
, "grid bug"))
2147 n
+= (tmp2
!= AD_PHYS
);
2148 n
+= ((int) (ptr
->mattk
[i
].damd
* ptr
->mattk
[i
].damn
) > 23);
2151 /* Leprechauns are special cases. They have many hit dice so they can
2152 hit and are hard to kill, but they don't really do much damage. */
2153 if (!strcmp(ptr
->mname
, "leprechaun"))
2156 /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */
2164 return (tmp
>= 0) ? tmp
: 0;
2170 register struct permonst
*ptr
;
2174 * create the source file, "monstr.c"
2178 Strcat(filename
, file_prefix
);
2180 Sprintf(eos(filename
), SOURCE_TEMPLATE
, MON_STR_C
);
2181 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2185 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2186 Fprintf(ofp
, "#include \"config.h\"\n");
2187 Fprintf(ofp
, "\nconst int monstr[] = {\n");
2188 for (ptr
= &mons
[0], j
= 0; ptr
->mlet
; ptr
++) {
2192 Fprintf(ofp
, "%2d,%c", i
, (++j
& 15) ? ' ' : '\n');
2194 /* might want to insert a final 0 entry here instead of just newline */
2195 Fprintf(ofp
, "%s};\n", (j
& 15) ? "\n" : "");
2197 Fprintf(ofp
, "\nvoid NDECL(monstr_init);\n");
2198 Fprintf(ofp
, "\nvoid\n");
2199 Fprintf(ofp
, "monstr_init()\n");
2200 Fprintf(ofp
, "{\n");
2201 Fprintf(ofp
, " return;\n");
2202 Fprintf(ofp
, "}\n");
2203 Fprintf(ofp
, "\n/*monstr.c*/\n");
2217 Strcat(filename
, file_prefix
);
2219 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, MONST_FILE
);
2220 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2224 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2225 Fprintf(ofp
, "#ifndef PM_H\n#define PM_H\n");
2227 if (strcmp(mons
[0].mname
, "playermon") != 0)
2228 Fprintf(ofp
, "\n#define\tPM_PLAYERMON\t(-1)");
2230 for (i
= 0; mons
[i
].mlet
; i
++) {
2233 Fprintf(ofp
, "\n#define\tPM_");
2234 if (mons
[i
].mlet
== S_HUMAN
&& !strncmp(mons
[i
].mname
, "were", 4))
2235 Fprintf(ofp
, "HUMAN_");
2236 for (nam
= c
= tmpdup(mons
[i
].mname
); *c
; c
++)
2237 if (*c
>= 'a' && *c
<= 'z')
2238 *c
-= (char) ('a' - 'A');
2239 else if (*c
< 'A' || *c
> 'Z')
2241 Fprintf(ofp
, "%s\t%d", nam
, i
);
2243 Fprintf(ofp
, "\n\n#define\tNUMMONS\t%d\n", i
);
2244 Fprintf(ofp
, "\n#endif /* PM_H */\n");
2249 /* Start of Quest text file processing. */
2252 static struct qthdr qt_hdr
;
2253 static struct msghdr msg_hdr
[N_HDR
];
2254 static struct qtmsg
*curr_msg
;
2258 static boolean in_msg
;
2259 #define NO_MSG 1 /* strlen of a null line returned by fgets() */
2267 return (boolean
) (!in_msg
&& strlen(s
) == NO_MSG
);
2274 return (boolean
) (s
[0] == '%' && (s
[1] == 'C' || s
[1] == 'E'));
2283 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2284 if (!strncmp(code
, qt_hdr
.id
[i
], LEN_HDR
))
2294 if (qt_hdr
.n_hdr
>= N_HDR
) {
2295 Fprintf(stderr
, OUT_OF_HEADERS
, qt_line
);
2299 strncpy(&qt_hdr
.id
[qt_hdr
.n_hdr
][0], code
, LEN_HDR
);
2300 msg_hdr
[qt_hdr
.n_hdr
].n_msg
= 0;
2301 qt_hdr
.offset
[qt_hdr
.n_hdr
++] = 0L;
2311 for (i
= 0; i
< msg_hdr
[num
].n_msg
; i
++)
2312 if (msg_hdr
[num
].qt_msg
[i
].msgnum
== id
)
2323 struct qtmsg
*qt_msg
;
2325 if (msg_hdr
[num
].n_msg
>= N_MSG
) {
2326 Fprintf(stderr
, OUT_OF_MESSAGES
, qt_line
);
2328 qt_msg
= &(msg_hdr
[num
].qt_msg
[msg_hdr
[num
].n_msg
++]);
2329 qt_msg
->msgnum
= id
;
2330 qt_msg
->delivery
= s
[2];
2331 qt_msg
->offset
= qt_msg
->size
= qt_msg
->summary_size
= 0L;
2337 /* check %E record for "[summary text]" that anethack can stuff into the
2338 message history buffer when delivering text via window instead of pline */
2340 valid_qt_summary(s
, parsing
)
2341 char *s
; /* end record: "%E" optionally followed by " [summary]" */
2342 boolean parsing
; /* curr_msg is valid iff this is True */
2344 static char summary
[BUFSZ
];
2347 if (*s
!= '%' || *(s
+ 1) != 'E')
2349 if ((p
= index(s
, '[')) == 0)
2351 /* note: opening '[' and closing ']' will be retained in the output;
2352 anything after ']' will be discarded by putting a newline there */
2355 /* have an opening bracket; summary[] holds it and all text that follows
2358 /* find closing bracket */
2359 while (p
> summary
&& *(p
- 1) != ']')
2363 /* we backed up all the way to the start without finding a bracket */
2364 if (parsing
) /* malformed summary */
2365 Fprintf(stderr
, MAL_SUM
, qt_line
);
2366 } else if (p
== summary
+ 1) {
2367 ; /* ignore empty [] */
2368 } else { /* got something */
2369 /* p points one spot past ']', usually to '\n';
2370 we need to include the \n as part of the size */
2372 /* during the writing pass we won't be able to recheck
2373 delivery, so any useless summary for a pline mode
2374 message has to be carried along to the output file */
2375 if (curr_msg
->delivery
== 'p')
2376 Fprintf(stderr
, DUMB_SUM
, qt_line
);
2377 /* +1 is for terminating newline */
2378 curr_msg
->summary_size
= (long) (p
- summary
) + 1L;
2380 /* caller is writing rather than just parsing;
2381 force newline after the closing bracket */
2396 if (!index(s
, '\n'))
2397 Fprintf(stderr
, CTRL_TRUNC
, qt_line
);
2402 Fprintf(stderr
, CREC_IN_MSG
, qt_line
);
2406 if (sscanf(&s
[4], "%s %5d", code
, &id
) != 2) {
2407 Fprintf(stderr
, UNREC_CREC
, qt_line
);
2410 num
= get_hdr(code
);
2411 if (!num
&& !new_id(code
))
2413 num
= get_hdr(code
) - 1;
2414 if (known_msg(num
, id
))
2415 Fprintf(stderr
, DUP_MSG
, qt_line
);
2417 new_msg(s
, num
, id
);
2423 Fprintf(stderr
, END_NOT_IN_MSG
, qt_line
);
2425 /* sets curr_msg->summary_size if applicable */
2426 (void) valid_qt_summary(s
, TRUE
);
2432 Fprintf(stderr
, UNREC_CREC
, qt_line
);
2442 Fprintf(stderr
, TEXT_NOT_IN_MSG
, qt_line
);
2443 } else if (!index(s
, '\n')) {
2444 Fprintf(stderr
, TEXT_TRUNC
, qt_line
);
2447 curr_msg
->size
+= strlen(s
);
2455 long count
= 0L, hdr_offset
= sizeof(int)
2456 + (sizeof(char) * LEN_HDR
+ sizeof(long))
2459 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++) {
2460 qt_hdr
.offset
[i
] = hdr_offset
;
2461 hdr_offset
+= sizeof(int) + sizeof(struct qtmsg
) * msg_hdr
[i
].n_msg
;
2464 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2465 for (j
= 0; j
< msg_hdr
[i
].n_msg
; j
++) {
2466 msg_hdr
[i
].qt_msg
[j
].offset
= hdr_offset
+ count
;
2468 msg_hdr
[i
].qt_msg
[j
].size
+ msg_hdr
[i
].qt_msg
[j
].summary_size
;
2479 * The main header record.
2482 Fprintf(stderr
, "%ld: header info.\n", ftell(ofp
));
2483 (void) fwrite((genericptr_t
) & (qt_hdr
.n_hdr
), sizeof(int), 1, ofp
);
2484 (void) fwrite((genericptr_t
) & (qt_hdr
.id
[0][0]), sizeof(char) * LEN_HDR
,
2486 (void) fwrite((genericptr_t
) & (qt_hdr
.offset
[0]), sizeof(long),
2489 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2490 Fprintf(stderr
, "%s @ %ld, ", qt_hdr
.id
[i
], qt_hdr
.offset
[i
]);
2491 Fprintf(stderr
, "\n");
2495 * The individual class headers.
2497 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++) {
2499 Fprintf(stderr
, "%ld: %s header info.\n", ftell(ofp
),
2501 (void) fwrite((genericptr_t
) & (msg_hdr
[i
].n_msg
), sizeof(int), 1,
2503 (void) fwrite((genericptr_t
) & (msg_hdr
[i
].qt_msg
[0]),
2504 sizeof(struct qtmsg
), msg_hdr
[i
].n_msg
, ofp
);
2508 for (j
= 0; j
< msg_hdr
[i
].n_msg
; j
++) {
2509 Fprintf(stderr
, "msg %d @ %ld (%ld)",
2510 msg_hdr
[i
].qt_msg
[j
].msgnum
,
2511 msg_hdr
[i
].qt_msg
[j
].offset
,
2512 msg_hdr
[i
].qt_msg
[j
].size
);
2513 if (msg_hdr
[i
].qt_msg
[j
].summary_size
)
2514 Fprintf(stderr
, " [%ld]",
2515 msg_hdr
[i
].qt_msg
[j
].summary_size
);
2516 Fprintf(stderr
, "\n");
2527 Sprintf(filename
, DATA_IN_TEMPLATE
, QTXT_I_FILE
);
2528 if (!(ifp
= fopen(filename
, RDTMODE
))) {
2535 Strcat(filename
, file_prefix
);
2537 Sprintf(eos(filename
), DATA_TEMPLATE
, QTXT_O_FILE
);
2538 if (!(ofp
= fopen(filename
, WRBMODE
))) {
2548 while ((line
= fgetline(ifp
)) != 0) {
2552 if (qt_control(line
))
2553 do_qt_control(line
);
2554 else if (qt_comment(line
)) {
2566 while ((line
= fgetline(ifp
)) != 0) {
2567 if (qt_control(line
)) {
2568 char *summary_p
= 0;
2570 in_msg
= (line
[1] == 'C');
2572 summary_p
= valid_qt_summary(line
, FALSE
);
2573 /* don't write anything unless we've got a summary */
2578 /* we have summary text; replace raw %E record with it */
2579 Strcpy(line
, summary_p
); /* (guaranteed to fit) */
2580 } else if (qt_comment(line
)) {
2585 Fprintf(stderr
, "%ld: %s", ftell(stdout
), line
);
2586 (void) fputs(xcrypt(line
), ofp
);
2594 static char temp
[32];
2596 static char *limit(name
, pref
) /* limit a name to 30 characters length */
2600 (void) strncpy(temp
, name
, pref
? 26 : 30);
2601 temp
[pref
? 26 : 30] = 0;
2613 boolean sumerr
= FALSE
;
2617 Strcat(filename
, file_prefix
);
2619 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, ONAME_FILE
);
2620 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2624 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2625 Fprintf(ofp
, "#ifndef ONAMES_H\n#define ONAMES_H\n\n");
2627 for (i
= 0; !i
|| objects
[i
].oc_class
!= ILLOBJ_CLASS
; i
++) {
2630 objects
[i
].oc_name_idx
= objects
[i
].oc_descr_idx
= i
; /* init */
2631 if (!(objnam
= tmpdup(OBJ_NAME(objects
[i
]))))
2634 /* make sure probabilities add up to 1000 */
2635 if (objects
[i
].oc_class
!= class) {
2636 if (sum
&& sum
!= 1000) {
2637 Fprintf(stderr
, "prob error for class %d (%d%%)", class, sum
);
2638 (void) fflush(stderr
);
2641 class = objects
[i
].oc_class
;
2645 for (c
= objnam
; *c
; c
++)
2646 if (*c
>= 'a' && *c
<= 'z')
2647 *c
-= (char) ('a' - 'A');
2648 else if (*c
< 'A' || *c
> 'Z')
2653 Fprintf(ofp
, "#define\tWAN_");
2657 Fprintf(ofp
, "#define\tRIN_");
2661 Fprintf(ofp
, "#define\tPOT_");
2665 Fprintf(ofp
, "#define\tSPE_");
2670 Fprintf(ofp
, "#define\tSCR_");
2674 /* avoid trouble with stupid C preprocessors */
2675 Fprintf(ofp
, "#define\t");
2676 if (objects
[i
].oc_material
== PLASTIC
) {
2677 Fprintf(ofp
, "FAKE_AMULET_OF_YENDOR\t%d\n", i
);
2683 /* avoid trouble with stupid C preprocessors */
2684 if (objects
[i
].oc_material
== GLASS
) {
2685 Fprintf(ofp
, "/* #define\t%s\t%d */\n", objnam
, i
);
2690 Fprintf(ofp
, "#define\t");
2693 Fprintf(ofp
, "%s\t%d\n", limit(objnam
, prefix
), i
);
2696 sum
+= objects
[i
].oc_prob
;
2699 /* check last set of probabilities */
2700 if (sum
&& sum
!= 1000) {
2701 Fprintf(stderr
, "prob error for class %d (%d%%)", class, sum
);
2702 (void) fflush(stderr
);
2706 Fprintf(ofp
, "#define\tLAST_GEM\t(JADE)\n");
2707 Fprintf(ofp
, "#define\tMAXSPELL\t%d\n", nspell
+ 1);
2708 Fprintf(ofp
, "#define\tNUM_OBJECTS\t%d\n", i
);
2710 Fprintf(ofp
, "\n/* Artifacts (unique objects) */\n\n");
2712 for (i
= 1; artifact_names
[i
]; i
++) {
2715 for (c
= objnam
= tmpdup(artifact_names
[i
]); *c
; c
++)
2716 if (*c
>= 'a' && *c
<= 'z')
2717 *c
-= (char) ('a' - 'A');
2718 else if (*c
< 'A' || *c
> 'Z')
2721 if (!strncmp(objnam
, "THE_", 4))
2723 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
2724 if (!strncmp(objnam
, "PLATINUM_", 9))
2726 Fprintf(ofp
, "#define\tART_%s\t%d\n", limit(objnam
, 1), i
);
2729 Fprintf(ofp
, "#define\tNROFARTIFACTS\t%d\n", i
- 1);
2730 Fprintf(ofp
, "\n#endif /* ONAMES_H */\n");
2737 /* Read one line from input, up to and including the next newline
2738 * character. Returns a pointer to the heap-allocated string, or a
2739 * null pointer if no characters were read.
2745 static const int inc
= 256;
2747 char *c
= malloc(len
), *ret
;
2750 ret
= fgets(c
+ len
- inc
, inc
, fd
);
2755 } else if (index(c
, '\n')) {
2756 /* normal case: we have a full line */
2760 c
= realloc(c
, len
);
2769 static char buf
[128];
2773 (void) strncpy(buf
, str
, 127);
2787 * macro used to control vision algorithms:
2788 * VISION_TABLES => generate tables
2794 #ifdef VISION_TABLES
2797 /* Everything is clear. xclear may be malloc'ed.
2798 * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
2800 for (i
= 0; i
< MAX_ROW
; i
++)
2801 for (j
= 0; j
< MAX_COL
; j
++)
2802 if (i
< BLOCK_HEIGHT
&& j
< BLOCK_WIDTH
)
2803 xclear
[i
][j
] = '\000';
2805 xclear
[i
][j
] = '\001';
2806 #endif /* VISION_TABLES */
2811 * create the include file, "vis_tab.h"
2815 Strcat(filename
, file_prefix
);
2817 Sprintf(filename
, INCLUDE_TEMPLATE
, VIS_TAB_H
);
2818 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2822 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2823 Fprintf(ofp
, "#ifdef VISION_TABLES\n");
2824 #ifdef VISION_TABLES
2827 #endif /* VISION_TABLES */
2828 Fprintf(ofp
, "\n#endif /* VISION_TABLES */\n");
2834 * create the source file, "vis_tab.c"
2838 Strcat(filename
, file_prefix
);
2840 Sprintf(filename
, SOURCE_TEMPLATE
, VIS_TAB_C
);
2841 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2843 Sprintf(filename
, INCLUDE_TEMPLATE
, VIS_TAB_H
);
2847 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2848 Fprintf(ofp
, "#include \"config.h\"\n");
2849 Fprintf(ofp
, "#ifdef VISION_TABLES\n");
2850 Fprintf(ofp
, "#include \"vis_tab.h\"\n");
2854 #ifdef VISION_TABLES
2857 Fprintf(ofp
, "\nvoid vis_tab_init() { return; }\n");
2858 #endif /* VISION_TABLES */
2862 Fprintf(ofp
, "\n#endif /* VISION_TABLES */\n");
2863 Fprintf(ofp
, "\n/*vis_tab.c*/\n");
2869 #ifdef VISION_TABLES
2871 /*-------------- vision tables --------------*\
2873 * Generate the close and far tables. This is done by setting up a
2874 * fake dungeon and moving our source to different positions relative
2875 * to a block and finding the first/last visible position. The fake
2876 * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
2877 * by BLOCK_WIDTH) is blocked. Then we move the source around relative
2878 * to the corner of the block. For each new position of the source
2879 * we check positions on rows "kittycorner" from the source. We check
2880 * positions until they are either in sight or out of sight (depends on
2881 * which table we are generating). The picture below shows the setup
2882 * for the generation of the close table. The generation of the far
2883 * table would switch the quadrants of the '@' and the "Check rows
2887 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2888 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2889 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
2890 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2891 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2892 * ...............................
2893 * ...............................
2894 * .........@.....................
2895 * ...............................
2897 * Table generation figure (close_table). The 'X's are blocked points.
2898 * The 'B' is a special blocked point. The '@' is the source. The ','s
2899 * are the target area. The '.' are just open areas.
2902 * Example usage of close_table[][][].
2904 * The table is as follows:
2906 * dy = |row of '@' - row of 'B'| - 1
2907 * dx = |col of '@' - col of 'B'|
2909 * The first indices are the deltas from the source '@' and the block 'B'.
2910 * You must check for the value inside the abs value bars being zero. If
2911 * so then the block is on the same row and you don't need to do a table
2912 * lookup. The last value:
2914 * dcy = |row of block - row to be checked|
2916 * Is the value of the first visible spot on the check row from the
2919 * first visible col = close_table[dy][dx][dcy] + col of 'B'
2921 \*-------------- vision tables --------------*/
2926 Fprintf(ofp
, "\n/* Close */\n");
2928 "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
2931 "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
2934 "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
2936 Fprintf(ofp
, "typedef struct {\n");
2938 " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
2939 Fprintf(ofp
, "} close2d;\n");
2940 Fprintf(ofp
, "extern close2d close_table[CLOSE_MAX_SB_DY];\n");
2947 Fprintf(ofp
, "\n/* Far */\n");
2948 Fprintf(ofp
, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
2951 "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
2954 "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
2956 Fprintf(ofp
, "typedef struct {\n");
2957 Fprintf(ofp
, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
2958 Fprintf(ofp
, "} far2d;\n");
2959 Fprintf(ofp
, "extern far2d far_table[FAR_MAX_SB_DY];\n");
2967 int src_row
, src_col
; /* source */
2968 int block_row
, block_col
; /* block */
2973 block_row
= BLOCK_HEIGHT
- 1;
2974 block_col
= BLOCK_WIDTH
- 1;
2976 Fprintf(ofp
, "\n#ifndef FAR_TABLE_ONLY\n");
2977 Fprintf(ofp
, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
2978 #ifndef no_vision_progress
2979 Fprintf(stderr
, "\nclose:");
2982 for (dy
= 1; dy
< TEST_HEIGHT
; dy
++) {
2983 src_row
= block_row
+ dy
;
2984 Fprintf(ofp
, "/* DY = %2d (- 1)*/\n {{\n", dy
);
2985 #ifndef no_vision_progress
2986 Fprintf(stderr
, " %2d", dy
), (void) fflush(stderr
);
2988 for (dx
= 0; dx
< TEST_WIDTH
; dx
++) {
2989 src_col
= block_col
- dx
;
2990 Fprintf(ofp
, " /*%2d*/ {", dx
);
2993 for (this_row
= 0; this_row
< TEST_HEIGHT
; this_row
++) {
2994 delim
= (this_row
< TEST_HEIGHT
- 1) ? "," : "";
2996 Fprintf(ofp
, "%s%s", CLOSE_OFF_TABLE_STRING
, delim
);
3001 /* Find the first column that we can see. */
3002 for (i
= block_col
+ 1; i
< MAX_COL
; i
++) {
3003 if (clear_path(src_row
, src_col
, block_row
- this_row
, i
))
3009 Fprintf(ofp
, "%2d%s", i
- block_col
, delim
);
3011 Fprintf(ofp
, "}%s", (dx
< TEST_WIDTH
- 1) ? ",\n" : "\n");
3013 Fprintf(ofp
, " }},\n");
3016 Fprintf(ofp
, "}; /* close_table[] */\n"); /* closing brace for table */
3017 Fprintf(ofp
, "#endif /* !FAR_TABLE_ONLY */\n");
3018 #ifndef no_vision_progress
3019 Fprintf(stderr
, "\n");
3028 int src_row
, src_col
; /* source */
3029 int block_row
, block_col
; /* block */
3033 block_row
= BLOCK_HEIGHT
- 1;
3034 block_col
= BLOCK_WIDTH
- 1;
3036 Fprintf(ofp
, "\n#ifndef CLOSE_TABLE_ONLY\n");
3037 Fprintf(ofp
, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
3038 #ifndef no_vision_progress
3039 Fprintf(stderr
, "\n_far_:");
3042 for (dy
= 0; dy
< TEST_HEIGHT
; dy
++) {
3043 src_row
= block_row
- dy
;
3044 Fprintf(ofp
, "/* DY = %2d */\n {{\n", dy
);
3045 #ifndef no_vision_progress
3046 Fprintf(stderr
, " %2d", dy
), (void) fflush(stderr
);
3048 for (dx
= 1; dx
< TEST_WIDTH
; dx
++) {
3049 src_col
= block_col
+ dx
;
3050 Fprintf(ofp
, " /*%2d(-1)*/ {", dx
);
3052 for (this_row
= block_row
+ 1; this_row
< block_row
+ TEST_HEIGHT
;
3054 delim
= (this_row
< block_row
+ TEST_HEIGHT
- 1) ? "," : "";
3057 /* Find first col that we can see. */
3058 for (i
= 0; i
<= block_col
; i
++) {
3059 if (clear_path(src_row
, src_col
, this_row
, i
))
3063 if (block_col
- i
< 0)
3064 Fprintf(ofp
, "%s%s", FAR_OFF_TABLE_STRING
, delim
);
3066 Fprintf(ofp
, "%2d%s", block_col
- i
, delim
);
3068 Fprintf(ofp
, "}%s", (dx
< TEST_WIDTH
- 1) ? ",\n" : "\n");
3070 Fprintf(ofp
, " }},\n");
3073 Fprintf(ofp
, "}; /* far_table[] */\n"); /* closing brace for table */
3074 Fprintf(ofp
, "#endif /* !CLOSE_TABLE_ONLY */\n");
3075 #ifndef no_vision_progress
3076 Fprintf(stderr
, "\n");
3082 * "Draw" a line from the hero to the given location. Stop if we hit a
3085 * Generalized integer Bresenham's algorithm (fast line drawing) for
3086 * all quadrants. From _Procedural Elements for Computer Graphics_, by
3087 * David F. Rogers. McGraw-Hill, 1985.
3089 * I have tried a little bit of optimization by pulling compares out of
3092 * NOTE: This had better *not* be called from a position on the
3093 * same row as the hero.
3096 clear_path(you_row
, you_col
, y2
, x2
)
3097 int you_row
, you_col
, y2
, x2
;
3100 register int i
, error
, x
, y
, dxs
, dys
;
3104 dx
= abs(x2
- you_col
);
3105 dy
= abs(y2
- you_row
);
3106 s1
= sign(x2
- you_col
);
3107 s2
= sign(y2
- you_row
);
3109 if (s1
== 0) { /* same column */
3110 if (s2
== 1) { /* below (larger y2 value) */
3111 for (i
= you_row
+ 1; i
< y2
; i
++)
3112 if (!xclear
[i
][you_col
])
3114 } else { /* above (smaller y2 value) */
3115 for (i
= y2
+ 1; i
< you_row
; i
++)
3116 if (!xclear
[i
][you_col
])
3123 * Lines at 0 and 90 degrees have been weeded out.
3128 dy
= error
; /* swap the values */
3129 dxs
= dx
<< 1; /* save the shifted values */
3131 error
= dys
- dx
; /* NOTE: error is used as a temporary above */
3133 for (i
= 0; i
< dx
; i
++) {
3135 return 0; /* plot point */
3137 while (error
>= 0) {
3145 dxs
= dx
<< 1; /* save the shifted values */
3149 for (i
= 0; i
< dx
; i
++) {
3151 return 0; /* plot point */
3153 while (error
>= 0) {
3163 #endif /* VISION_TABLES */
3165 #ifdef STRICT_REF_DEF
3166 NEARDATA
struct flag flags
;
3168 struct attribs attrmax
, attrmin
;
3170 #endif /* STRICT_REF_DEF */