1 /* NetHack 3.6 makedefs.c $NHDT-Date: 1455357861 2016/02/13 10:04:21 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.109 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* Copyright (c) M. Stephenson, 1990, 1991. */
4 /* Copyright (c) Dean Luick, 1990. */
5 /* NetHack may be freely redistributed. See license for details. */
7 #define MAKEDEFS_C /* use to conditionally include file sections */
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 through
583 unchanged depending on the current conditional state.
585 The default conditional state is printing on.
587 Conditionals may be nested.
589 makedefs will exit with a EXIT_FAILURE if any errors are detected; as many
590 errors as possible are detected before giving up.
592 Unknown identifiers are treated as TRUE and also as an error to allow
593 processing to continue past the unknown identifier (note that "#undef" is
594 different than unknown).
596 Any line starting with a caret is a control line; as in C, zero or more
598 may be embedded in the line almost anywhere; the caret MUST be in column 1.
599 (XXX for the moment, no white space is allowed after the caret because
600 existing lines in the docs look like that)
603 ^^ a line starting with a (single) literal caret
604 ^# a comment - the line is ignored
611 #define GREP_MAGIC '^'
612 #define GREP_STACK_SIZE 100
614 static int grep_rewrite
= 0; /* need to (possibly) rewrite lines */
616 static int grep_writing
= 1; /* need to copy lines to output */
617 static int grep_errors
= 0;
618 static int grep_sp
= 0;
619 #define ST_LD(old, opp) (!!(old) | (!!(opp) << 1))
620 #define ST_OLD(v) ((v) &1)
621 #define ST_OPP(v) !!((v) &2)
623 static int grep_stack
[GREP_STACK_SIZE
] = { ST_LD(1, 0) };
624 static int grep_lineno
= 0;
631 for (x
= 0; x
< SIZE(grep_vars
) - 1; x
++) {
632 printf("%d\t%s\n", grep_vars
[x
].is_defined
, grep_vars
[x
].name
);
636 static struct grep_var
*
640 /* XXX make into binary search */
643 while (x
< SIZE(grep_vars
) - 1) {
644 if (!strcmp(grep_vars
[x
].name
, name
))
645 return &grep_vars
[x
];
657 while (*id
&& isspace(*id
))
660 Fprintf(stderr
, "missing identifier in line %d", grep_lineno
);
667 Fprintf(outputfp
, "ID %d %s\n", rv
->is_defined
, id
);
669 return rv
->is_defined
;
673 Fprintf(outputfp
, "ID U %s\n", id
);
675 Fprintf(stderr
, "unknown identifier '%s' in line %d.\n", id
, grep_lineno
);
677 return 2; /* So new features can be checked before makedefs
682 grep_show_wstack(tag
)
690 Fprintf(outputfp
, "%s w=%d sp=%d\t", tag
, grep_writing
, grep_sp
);
691 for (x
= grep_sp
; x
>= 0 && x
> grep_sp
- 6; x
--) {
692 Fprintf(outputfp
, "[%d]=%d ", x
, grep_stack
[x
]);
694 Fprintf(outputfp
, "\n");
705 return &buf
[-1]; /* XXX see docs above */
707 while (buf
[0] && isspace(buf
[0]))
711 case '#': /* comment */
713 case '.': /* end of if level */
715 Fprintf(stderr
, "unmatched ^. (endif) at line %d.\n",
719 grep_writing
= ST_OLD(grep_stack
[grep_sp
--]);
720 grep_show_wstack("pop");
723 case '!': /* if not ID */
726 case '?': /* if ID */
727 if (grep_sp
== GREP_STACK_SIZE
- 2) {
728 Fprintf(stderr
, "stack overflow at line %d.", grep_lineno
);
732 isif
= grep_check_id(&buf
[1]) ? isif
: !isif
;
733 grep_stack
[++grep_sp
] = ST_LD(grep_writing
, !isif
);
736 grep_stack
[++grep_sp
] = ST_LD(0, 0);
737 /* grep_writing = 0; */
739 grep_show_wstack("push");
742 if (ST_ELSE
& grep_stack
[grep_sp
]) {
743 Fprintf(stderr
, "multiple : for same conditional at line %d.\n",
747 grep_writing
= ST_OPP(grep_stack
[grep_sp
]);
748 grep_stack
[grep_sp
] |= ST_ELSE
;
751 case '(': /* start of expression */
753 case GREP_MAGIC
: /* ^^ -> ^ */
758 if (isprint(buf
[0])) {
762 sprintf(str
, "0x%02x", buf
[0]);
764 Fprintf(stderr
, "unknown control ^%s at line %d.\n", str
,
777 /* no language features use this yet */
782 static void grep0(FILE *, FILE *);
788 Fprintf(stderr
, "--grep requires --input\n");
791 Fprintf(stderr
, "--grep requires --output\n");
793 if (!inputfp
|| !outputfp
) {
797 grep0(inputfp
, outputfp
);
801 grep0(inputfp0
, outputfp0
)
805 char buf
[16384]; /* looong, just in case */
807 while (!feof(inputfp0
) && !ferror(inputfp0
)) {
811 if (fgets(buf
, sizeof(buf
), inputfp0
) == 0)
813 if ((tmp
= strchr(buf
, '\n')))
817 Fprintf(outputfp0
, "%04d %c >%s\n", grep_lineno
,
818 grep_writing
? ' ' : '#', buf
);
821 if (buf
[0] == GREP_MAGIC
) {
822 buf1
= do_grep_control(&buf
[1]);
830 do_grep_rewrite(buf1
);
833 Fprintf(outputfp0
, "%s\n", buf1
);
835 if (ferror(inputfp0
)) {
836 Fprintf(stderr
, "read error!\n");
839 if (ferror(outputfp0
)) {
840 Fprintf(stderr
, "write error!\n");
846 Fprintf(stderr
, "%d unterminated conditional level%s\n", grep_sp
,
847 grep_sp
== 1 ? "" : "s");
851 Fprintf(stderr
, "%d error%s detected.\n", grep_errors
,
852 grep_errors
== 1 ? "" : "s");
857 /* trivial text encryption routine which can't be broken with `tr' */
861 { /* duplicated in src/hacklib.c */
862 static char buf
[BUFSZ
];
863 register const char *p
;
865 register int bitmask
;
867 for (bitmask
= 1, p
= str
, q
= buf
; *p
; q
++) {
871 if ((bitmask
<<= 1) >= 32)
878 #define PAD_RUMORS_TO 60
879 /* common code for do_rumors(). Return 0 on error. */
881 read_rumors_file(file_ext
, rumor_count
, rumor_size
, old_rumor_offset
)
882 const char *file_ext
;
885 unsigned long old_rumor_offset
;
889 unsigned long rumor_offset
;
891 Sprintf(infile
, DATA_IN_TEMPLATE
, RUMOR_FILE
);
892 Strcat(infile
, file_ext
);
893 if (!(ifp
= fopen(infile
, RDTMODE
))) {
898 /* copy the rumors */
899 while ((line
= fgetline(ifp
)) != 0) {
901 /* rumor selection is accomplished by seeking to a random
902 position in the file, advancing to newline, and taking
903 the next line; therefore, rumors which follow long-line
904 rumors are most likely to be chosen and rumors which
905 follow short-line rumors are least likely to be chosen;
906 we ameliorate the latter by padding the shortest lines,
907 increasing the chance of the random seek landing in them */
908 int len
= (int) strlen(line
);
910 if (len
<= PAD_RUMORS_TO
) {
911 char *base
= index(line
, '\n');
912 /* this is only safe because fgetline() overallocates */
913 while (len
++ < PAD_RUMORS_TO
) {
922 /*[if we forced binary output, this would be sufficient]*/
923 *rumor_size
+= strlen(line
); /* includes newline */
925 (void) fputs(xcrypt(line
), tfp
);
928 /* record the current position; next rumors section will start here */
929 rumor_offset
= (unsigned long) ftell(tfp
);
930 Fclose(ifp
); /* all done with rumors.file_ext */
932 /* the calculated value for *_rumor_count assumes that
933 a single-byte line terminator is in use; for platforms
934 which use two byte CR+LF, we need to override that value
935 [it's much simpler to do so unconditionally, rendering
936 the loop's accumulation above obsolete] */
937 *rumor_size
= (long) (rumor_offset
- old_rumor_offset
);
942 do_rnd_access_file(fname
)
947 Sprintf(filename
, DATA_IN_TEMPLATE
, fname
);
948 Strcat(filename
, ".txt");
949 if (!(ifp
= fopen(filename
, RDTMODE
))) {
955 Strcat(filename
, file_prefix
);
957 Sprintf(eos(filename
), DATA_TEMPLATE
, fname
);
958 if (!(ofp
= fopen(filename
, WRTMODE
))) {
962 Fprintf(ofp
, "%s", Dont_Edit_Data
);
964 tfp
= getfp(DATA_TEMPLATE
, "grep.tmp", WRTMODE
);
966 ifp
= getfp(DATA_TEMPLATE
, "grep.tmp", RDTMODE
);
968 while ((line
= fgetline(ifp
)) != 0) {
969 if (line
[0] != '#' && line
[0] != '\n')
970 (void) fputs(xcrypt(line
), ofp
);
976 delete_file(DATA_TEMPLATE
, "grep.tmp");
984 static const char rumors_header
[] =
985 "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n";
987 int true_rumor_count
, false_rumor_count
;
988 long true_rumor_size
, false_rumor_size
;
989 unsigned long true_rumor_offset
, false_rumor_offset
, eof_offset
;
991 Sprintf(tempfile
, DATA_TEMPLATE
, "rumors.tmp");
994 Strcat(filename
, file_prefix
);
996 Sprintf(eos(filename
), DATA_TEMPLATE
, RUMOR_FILE
);
997 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1001 if (!(tfp
= fopen(tempfile
, WRTMODE
))) {
1007 true_rumor_count
= false_rumor_count
= 0;
1008 true_rumor_size
= false_rumor_size
= 0L;
1009 true_rumor_offset
= false_rumor_offset
= eof_offset
= 0L;
1011 /* output a dummy header record; we'll replace it in final output */
1012 Fprintf(tfp
, rumors_header
, Dont_Edit_Data
, true_rumor_count
,
1013 true_rumor_size
, true_rumor_offset
, false_rumor_count
,
1014 false_rumor_size
, false_rumor_offset
, eof_offset
);
1015 /* record the current position; true rumors will start here */
1016 true_rumor_offset
= ftell(tfp
);
1018 false_rumor_offset
= read_rumors_file(
1019 ".tru", &true_rumor_count
, &true_rumor_size
, true_rumor_offset
);
1020 if (!false_rumor_offset
)
1021 goto rumors_failure
;
1023 eof_offset
= read_rumors_file(".fal", &false_rumor_count
,
1024 &false_rumor_size
, false_rumor_offset
);
1026 goto rumors_failure
;
1028 /* get ready to transfer the contents of temp file to output file */
1030 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1031 if (rewind(tfp
) != 0) {
1034 goto rumors_failure
;
1038 /* output the header record */
1039 Fprintf(ofp
, rumors_header
, Dont_Edit_Data
, true_rumor_count
,
1040 true_rumor_size
, true_rumor_offset
, false_rumor_count
,
1041 false_rumor_size
, false_rumor_offset
, eof_offset
);
1042 /* skip the temp file's dummy header */
1043 if (!(line
= fgetline(tfp
))) { /* "Don't Edit" */
1045 goto rumors_failure
;
1048 if (!(line
= fgetline(tfp
))) { /* count,size,offset */
1050 goto rumors_failure
;
1053 /* copy the rest of the temp file into the final output file */
1054 while ((line
= fgetline(tfp
)) != 0) {
1055 (void) fputs(line
, ofp
);
1058 /* all done; delete temp file */
1066 Unlink(filename
); /* kill empty or incomplete output file */
1068 Unlink(tempfile
); /* and temporary file */
1073 * Use this to explicitly mask out features during version checks.
1075 * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features
1076 * that the port/plaform which wrote the savefile was capable of
1077 * dealing with. Don't reject a savefile just because the port
1078 * reading the savefile doesn't match on all/some of them.
1079 * The actual compression features used to produce the savefile are
1080 * recorded in the savefile_info structure immediately following the
1081 * version_info, and that is what needs to be checked against the
1082 * feature set of the port that is reading the savefile back in.
1083 * That check is done in src/restore.c now.
1086 #define IGNORED_FEATURES \
1087 (0L | (1L << 19) /* SCORE_ON_BOTL */ \
1088 | (1L << 27) /* ZEROCOMP */ \
1089 | (1L << 28) /* RLECOMP */ \
1098 * integer version number
1100 version
.incarnation
= ((unsigned long) VERSION_MAJOR
<< 24)
1101 | ((unsigned long) VERSION_MINOR
<< 16)
1102 | ((unsigned long) PATCHLEVEL
<< 8)
1103 | ((unsigned long) EDITLEVEL
);
1105 * encoded feature list
1106 * Note: if any of these magic numbers are changed or reassigned,
1107 * EDITLEVEL in patchlevel.h should be incremented at the same time.
1108 * The actual values have no special meaning, and the category
1109 * groupings are just for convenience.
1111 version
.feature_set
= (unsigned long) (0L
1112 /* levels and/or topology (0..4) */
1113 /* monsters (5..9) */
1117 /* objects (10..14) */
1118 /* flag bits and/or other global variables (15..26) */
1125 #ifdef SCORE_ON_BOTL
1128 /* data format (27..31)
1129 * External compression methods such as COMPRESS and ZLIB_COMP
1130 * do not affect the contents and are thus excluded from here */
1139 * Value used for object & monster sanity check.
1140 * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
1142 for (i
= 1; artifact_names
[i
]; i
++)
1144 version
.entity_count
= (unsigned long) (i
- 1);
1145 for (i
= 1; objects
[i
].oc_class
!= ILLOBJ_CLASS
; i
++)
1147 version
.entity_count
= (version
.entity_count
<< 12) | (unsigned long) i
;
1148 for (i
= 0; mons
[i
].mlet
; i
++)
1150 version
.entity_count
= (version
.entity_count
<< 12) | (unsigned long) i
;
1152 * Value used for compiler (word size/field alignment/padding) check.
1154 version
.struct_sizes1
=
1155 (((unsigned long) sizeof(struct context_info
) << 24)
1156 | ((unsigned long) sizeof(struct obj
) << 17)
1157 | ((unsigned long) sizeof(struct monst
) << 10)
1158 | ((unsigned long) sizeof(struct you
)));
1159 version
.struct_sizes2
= (((unsigned long) sizeof(struct flag
) << 10) |
1160 /* free bits in here */
1162 ((unsigned long) sizeof(struct sysflag
)));
1164 ((unsigned long) 0L));
1170 version_string(outbuf
, delim
)
1174 Sprintf(outbuf
, "%d%s%d%s%d", VERSION_MAJOR
, delim
, VERSION_MINOR
, delim
,
1177 Sprintf(eos(outbuf
), "-%d", EDITLEVEL
);
1183 version_id_string(outbuf
, build_date
)
1185 const char *build_date
;
1187 char subbuf
[64], versbuf
[64];
1192 Strcpy(&subbuf
[1], PORT_SUB_ID
);
1195 Strcat(subbuf
, " Beta");
1198 Sprintf(outbuf
, "%s NetHack%s Version %s - last build %s.", PORT_ID
,
1199 subbuf
, version_string(versbuf
, "."), build_date
);
1204 bannerc_string(outbuf
, build_date
)
1206 const char *build_date
;
1208 char subbuf
[64], versbuf
[64];
1213 Strcpy(&subbuf
[1], PORT_SUB_ID
);
1216 Strcat(subbuf
, " Beta");
1219 Sprintf(outbuf
, " Version %s %s%s, built %s.",
1220 version_string(versbuf
, "."), PORT_ID
, subbuf
, &build_date
[4]);
1222 Sprintf(outbuf
, "%s NetHack%s %s Copyright 1985-%s (built %s)",
1223 PORT_ID
, subbuf
, version_string(versbuf
,"."), RELEASE_YEAR
,
1235 time_t clocktim
= 0;
1237 char *c
, cbuf
[60], buf
[BUFSZ
];
1240 /* before creating date.h, make sure that xxx_GRAPHICS and
1241 DEFAULT_WINDOW_SYS have been set up in a viable fashion */
1246 Strcat(filename
, file_prefix
);
1248 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, DATE_FILE
);
1249 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1253 /* NB: We've moved on from SCCS, but this way this line
1254 * won't get clobbered when downstream projects import
1255 * this file into something more modern. */
1256 Fprintf(ofp
, "%s", Dont_Edit_Code
);
1258 (void) time(&clocktim
);
1259 Strcpy(cbuf
, ctime(&clocktim
));
1261 for (c
= cbuf
; *c
; c
++)
1264 *c
= '\0'; /* strip off the '\n' */
1265 Fprintf(ofp
, "#define BUILD_DATE \"%s\"\n", cbuf
);
1266 Fprintf(ofp
, "#define BUILD_TIME (%ldL)\n", (long) clocktim
);
1273 Fprintf(ofp
, "#define VERSION_NUMBER 0x%08lx%s\n", version
.incarnation
,
1275 Fprintf(ofp
, "#define VERSION_FEATURES 0x%08lx%s\n", version
.feature_set
,
1277 #ifdef IGNORED_FEATURES
1278 Fprintf(ofp
, "#define IGNORED_FEATURES 0x%08lx%s\n",
1279 (unsigned long) IGNORED_FEATURES
, ul_sfx
);
1281 Fprintf(ofp
, "#define VERSION_SANITY1 0x%08lx%s\n", version
.entity_count
,
1283 Fprintf(ofp
, "#define VERSION_SANITY2 0x%08lx%s\n", version
.struct_sizes1
,
1285 Fprintf(ofp
, "#define VERSION_SANITY3 0x%08lx%s\n", version
.struct_sizes2
,
1288 Fprintf(ofp
, "#define VERSION_STRING \"%s\"\n", version_string(buf
, "."));
1289 Fprintf(ofp
, "#define VERSION_ID \\\n \"%s\"\n",
1290 version_id_string(buf
, cbuf
));
1291 Fprintf(ofp
, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n",
1292 bannerc_string(buf
, cbuf
));
1296 struct tm
*tm
= localtime((time_t *) &clocktim
);
1297 Fprintf(ofp
, "#define AMIGA_VERSION_STRING ");
1298 Fprintf(ofp
, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
1299 VERSION_MAJOR
, VERSION_MINOR
, PATCHLEVEL
, tm
->tm_mday
,
1300 tm
->tm_mon
+ 1, tm
->tm_year
+ 1900);
1307 static char save_bones_compat_buf
[BUFSZ
];
1310 build_savebones_compat_string()
1312 #ifdef VERSION_COMPATIBILITY
1313 unsigned long uver
= VERSION_COMPATIBILITY
;
1315 Strcpy(save_bones_compat_buf
,
1316 "save and bones files accepted from version");
1317 #ifdef VERSION_COMPATIBILITY
1318 Sprintf(eos(save_bones_compat_buf
), "s %lu.%lu.%lu through %d.%d.%d",
1319 ((uver
& 0xFF000000L
) >> 24), ((uver
& 0x00FF0000L
) >> 16),
1320 ((uver
& 0x0000FF00L
) >> 8), VERSION_MAJOR
, VERSION_MINOR
,
1323 Sprintf(eos(save_bones_compat_buf
), " %d.%d.%d only", VERSION_MAJOR
,
1324 VERSION_MINOR
, PATCHLEVEL
);
1328 static const char *build_opts
[] = {
1330 "Amiga WorkBench support",
1333 "ANSI default terminal",
1338 #ifdef TTY_TILES_ESCCODES
1339 "console escape codes for tile hinting",
1342 "command line completion",
1345 "Conway's Game of Life",
1348 "data file compression",
1351 "ZLIB data file compression",
1357 "floppy drive support",
1360 "insurance files for recovering from crashes",
1362 #ifdef HOLD_LOCKFILE_OPEN
1363 "exclusive lock on level 0 file",
1365 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
1366 "external program as a message handler",
1375 "MSDOS protected mode",
1392 "restore saved games via menu",
1394 #ifdef SCORE_ON_BOTL
1395 "score on status line",
1402 "screen control via mactty",
1405 "screen control via BIOS",
1407 #ifdef SCREEN_DJGPPFAST
1408 "screen control via DJGPP fast",
1411 "screen control via VGA graphics",
1414 "screen control via WIN32 console I/O",
1420 #ifdef STATUS_VIA_WINDOWPORT
1421 # ifdef STATUS_HILITES
1422 "status via windowport with highlighting",
1424 "status via windowport without highlighting",
1427 "traditional status display",
1433 "terminal info library",
1435 #if defined(TERMLIB) \
1436 || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
1437 "terminal capability library",
1441 "timed wait for display effects",
1446 #ifdef PREFIXES_IN_USE
1447 "variable playground",
1449 #ifdef VISION_TABLES
1453 "zero-compressed save files",
1456 "run-length compression of map in save files",
1459 "system configuration at run-time",
1461 save_bones_compat_buf
, "and basic NetHack features"
1465 const char *id
, /* DEFAULT_WINDOW_SYS string */
1466 *name
; /* description, often same as id */
1468 static struct win_info window_opts
[] = {
1470 { "tty", "traditional tty-based graphics" },
1478 #ifdef GNOME_GRAPHICS
1479 { "Gnome", "Gnome" },
1484 #ifdef AMIGA_INTUITION
1485 { "amii", "Amiga Intuition" },
1490 #ifdef MSWIN_GRAPHICS
1491 { "mswin", "mswin" },
1493 #ifdef BEOS_GRAPHICS
1494 { "BeOS", "BeOS InterfaceKit" },
1502 #ifndef DEFAULT_WINDOW_SYS
1503 /* pre-standard compilers didn't support #error; wait til run-time */
1505 "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n");
1509 /* put in a dummy value so that do_options() will compile and makedefs
1510 will build, otherwise the message above won't ever get delivered */
1511 #define DEFAULT_WINDOW_SYS "<undefined>"
1512 #else /*DEFAULT_WINDOW_SYS*/
1514 if (!window_opts
[0].id
) {
1515 Fprintf(stderr
, "Configuration error: no windowing systems "
1516 "(TTY_GRAPHICS, &c) enabled.\n");
1523 for (i
= 0; window_opts
[i
].id
; ++i
)
1524 if (!strcmp(window_opts
[i
].id
, DEFAULT_WINDOW_SYS
))
1527 .id
) { /* went through whole list without a match */
1528 Fprintf(stderr
, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n",
1529 DEFAULT_WINDOW_SYS
);
1531 " does not match any enabled windowing system (%s%s).\n",
1532 window_opts
[0].id
, window_opts
[1].id
? ", &c" : "");
1536 #endif /*DEFAULT_WINDOW_SYS*/
1542 static const char indent
[] = " ";
1543 const char *str
, *sep
;
1544 char *word
, buf
[BUFSZ
];
1545 int i
, length
, winsyscnt
;
1551 Strcat(filename
, file_prefix
);
1553 Sprintf(eos(filename
), DATA_TEMPLATE
, OPTIONS_FILE
);
1554 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1559 build_savebones_compat_string();
1562 "\n NetHack version %d.%d.%d [beta]\n",
1564 "\n NetHack version %d.%d.%d\n",
1566 VERSION_MAJOR
, VERSION_MINOR
, PATCHLEVEL
);
1568 Fprintf(ofp
, "\nOptions compiled into this edition:\n");
1569 length
= COLNO
+ 1; /* force 1st item onto new line */
1570 for (i
= 0; i
< SIZE(build_opts
); i
++) {
1571 str
= strcpy(buf
, build_opts
[i
]);
1573 word
= index(str
, ' ');
1576 if (length
+ strlen(str
) > COLNO
- 5)
1577 Fprintf(ofp
, "\n%s", indent
), length
= strlen(indent
);
1579 Fprintf(ofp
, " "), length
++;
1580 Fprintf(ofp
, "%s", str
), length
+= strlen(str
);
1581 str
+= strlen(str
) + (word
? 1 : 0);
1583 Fprintf(ofp
, (i
< SIZE(build_opts
) - 1) ? "," : "."), length
++;
1586 winsyscnt
= SIZE(window_opts
) - 1;
1587 Fprintf(ofp
, "\n\nSupported windowing system%s:\n",
1588 (winsyscnt
> 1) ? "s" : "");
1589 length
= COLNO
+ 1; /* force 1st item onto new line */
1590 for (i
= 0; i
< winsyscnt
; i
++) {
1591 str
= window_opts
[i
].name
;
1592 if (length
+ strlen(str
) > COLNO
- 5)
1593 Fprintf(ofp
, "\n%s", indent
), length
= strlen(indent
);
1595 Fprintf(ofp
, " "), length
++;
1596 Fprintf(ofp
, "%s", str
), length
+= strlen(str
);
1597 sep
= (winsyscnt
== 1)
1600 ? ((i
== 0) ? " and" : "")
1601 : (i
< winsyscnt
- 2)
1603 : ((i
== winsyscnt
- 2) ? ", and" : "");
1604 Fprintf(ofp
, "%s", sep
), length
+= strlen(sep
);
1607 Fprintf(ofp
, "\n%swith a default of %s.", indent
, DEFAULT_WINDOW_SYS
);
1608 Fprintf(ofp
, "\n\n");
1614 /* routine to decide whether to discard something from data.base */
1620 return TRUE
; /* ignore comment lines */
1626 New format (v3.1) of 'data' file which allows much faster lookups [pr]
1627 "do not edit" first record is a comment line
1628 01234567 hexadecimal formatted offset to text area
1629 name-a first name of interest
1630 123,4 offset to name's text, and number of lines for it
1631 name-b next name of interest
1632 name-c multiple names which share same description also
1633 456,7 share a single offset,count line
1634 . sentinel to mark end of names
1635 789,0 dummy record containing offset, count of EOF
1636 text-a 4 lines of descriptive text for name-a
1637 text-a at file position 0x01234567L + 123L
1640 text-b/text-c 7 lines of text for names-b and -c
1641 text-b/text-c at fseek(0x01234567L + 456L)
1649 char infile
[60], tempfile
[60];
1652 int entry_cnt
, line_cnt
;
1655 Sprintf(tempfile
, DATA_TEMPLATE
, "database.tmp");
1658 Strcat(filename
, file_prefix
);
1660 Sprintf(eos(filename
), DATA_TEMPLATE
, DATA_FILE
);
1661 Sprintf(infile
, DATA_IN_TEMPLATE
, DATA_FILE
);
1662 #ifdef SHORT_FILENAMES
1663 Strcat(infile
, ".bas");
1665 Strcat(infile
, ".base");
1667 if (!(ifp
= fopen(infile
, RDTMODE
))) { /* data.base */
1671 if (!(ofp
= fopen(filename
, WRTMODE
))) { /* data */
1676 if (!(tfp
= fopen(tempfile
, WRTMODE
))) { /* database.tmp */
1684 /* output a dummy header record; we'll rewind and overwrite it later */
1685 Fprintf(ofp
, "%s%08lx\n", Dont_Edit_Data
, 0L);
1687 entry_cnt
= line_cnt
= 0;
1688 /* read through the input file and split it into two sections */
1689 while ((line
= fgetline(ifp
)) != 0) {
1690 if (d_filter(line
)) {
1694 if (*line
> ' ') { /* got an entry name */
1695 /* first finish previous entry */
1697 Fprintf(ofp
, "%d\n", line_cnt
), line_cnt
= 0;
1698 /* output the entry name */
1699 (void) fputs(line
, ofp
);
1700 entry_cnt
++; /* update number of entries */
1701 } else if (entry_cnt
) { /* got some descriptive text */
1702 /* update previous entry with current text offset */
1704 Fprintf(ofp
, "%ld,", ftell(tfp
));
1705 /* save the text line in the scratch file */
1706 (void) fputs(line
, tfp
);
1707 line_cnt
++; /* update line counter */
1711 /* output an end marker and then record the current position */
1713 Fprintf(ofp
, "%d\n", line_cnt
);
1714 Fprintf(ofp
, ".\n%ld,%d\n", ftell(tfp
), 0);
1715 txt_offset
= ftell(ofp
);
1716 Fclose(ifp
); /* all done with original input file */
1718 /* reprocess the scratch file; 1st format an error msg, just in case */
1720 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1721 if (rewind(tfp
) != 0)
1724 /* copy all lines of text from the scratch file into the output file */
1725 while ((line
= fgetline(tfp
)) != 0) {
1726 (void) fputs(line
, ofp
);
1730 /* finished with scratch file */
1732 Unlink(tempfile
); /* remove it */
1734 /* update the first record of the output file; prepare error msg 1st */
1736 Sprintf(line
, "rewind of \"%s\"", filename
);
1737 ok
= (rewind(ofp
) == 0);
1739 Sprintf(line
, "header rewrite of \"%s\"", filename
);
1740 ok
= (fprintf(ofp
, "%s%08lx\n", Dont_Edit_Data
,
1741 (unsigned long) txt_offset
) >= 0);
1745 perror(line
); /* report the problem */
1747 /* close and kill the aborted output file, then give up */
1760 /* routine to decide whether to discard something from oracles.txt */
1765 static boolean skip
= FALSE
;
1771 return TRUE
; /* ignore comment lines */
1773 tag
= malloc(strlen(line
));
1774 if (sscanf(line
, "----- %s", tag
) == 1) {
1776 } else if (skip
&& !strncmp(line
, "-----", 5))
1782 static const char *special_oracle
[] = {
1783 "\"...it is rather disconcerting to be confronted with the",
1784 "following theorem from [Baker, Gill, and Solovay, 1975].", "",
1785 "Theorem 7.18 There exist recursive languages A and B such that",
1786 " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "",
1787 "This provides impressive evidence that the techniques that are",
1788 "currently available will not suffice for proving that P != NP or "
1790 "that P == NP.\" [Garey and Johnson, p. 185.]"
1794 The oracle file consists of a "do not edit" comment, a decimal count N
1795 and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
1796 records, separated by "---" lines. The first oracle is a special case.
1797 The input data contains just those multi-line records, separated by
1804 char infile
[60], tempfile
[60];
1805 boolean in_oracle
, ok
;
1807 unsigned long txt_offset
, offset
;
1812 Sprintf(tempfile
, DATA_TEMPLATE
, "oracles.tmp");
1815 Strcat(filename
, file_prefix
);
1817 Sprintf(eos(filename
), DATA_TEMPLATE
, ORACLE_FILE
);
1818 Sprintf(infile
, DATA_IN_TEMPLATE
, ORACLE_FILE
);
1819 Strcat(infile
, ".txt");
1820 if (!(ifp
= fopen(infile
, RDTMODE
))) {
1824 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1829 if (!(tfp
= fopen(tempfile
, WRTMODE
))) { /* oracles.tmp */
1837 /* output a dummy header record; we'll rewind and overwrite it later */
1838 Fprintf(ofp
, "%s%5d\n", Dont_Edit_Data
, 0);
1840 /* handle special oracle; it must come first */
1841 (void) fputs("---\n", tfp
);
1842 offset
= (unsigned long) ftell(tfp
);
1843 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of special oracle */
1844 for (i
= 0; i
< SIZE(special_oracle
); i
++) {
1845 (void) fputs(xcrypt(special_oracle
[i
]), tfp
);
1846 (void) fputc('\n', tfp
);
1851 (void) fputs("---\n", tfp
);
1852 offset
= (unsigned long) ftell(tfp
);
1853 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of first oracle */
1856 while ((line
= fgetline(ifp
)) != 0) {
1859 if (h_filter(line
)) {
1863 if (!strncmp(line
, "-----", 5)) {
1870 (void) fputs("---\n", tfp
);
1871 offset
= (unsigned long) ftell(tfp
);
1872 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of this oracle */
1875 (void) fputs(xcrypt(line
), tfp
);
1880 if (in_oracle
) { /* need to terminate last oracle */
1882 (void) fputs("---\n", tfp
);
1883 offset
= (unsigned long) ftell(tfp
);
1884 Fprintf(ofp
, "%05lx\n", offset
); /* eof position */
1887 /* record the current position */
1888 txt_offset
= (unsigned long) ftell(ofp
);
1889 Fclose(ifp
); /* all done with original input file */
1891 /* reprocess the scratch file; 1st format an error msg, just in case */
1893 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1894 if (rewind(tfp
) != 0)
1897 /* copy all lines of text from the scratch file into the output file */
1898 while ((line
= fgetline(tfp
)) != 0) {
1899 (void) fputs(line
, ofp
);
1903 /* finished with scratch file */
1905 Unlink(tempfile
); /* remove it */
1907 /* update the first record of the output file; prepare error msg 1st */
1909 Sprintf(line
, "rewind of \"%s\"", filename
);
1910 ok
= (rewind(ofp
) == 0);
1912 Sprintf(line
, "header rewrite of \"%s\"", filename
);
1913 ok
= (fprintf(ofp
, "%s%5d\n", Dont_Edit_Data
, oracle_cnt
) >= 0);
1916 Sprintf(line
, "data rewrite of \"%s\"", filename
);
1917 for (i
= 0; i
<= oracle_cnt
; i
++) {
1918 #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */
1919 if (!(ok
= (fflush(ofp
) == 0)))
1922 if (!(ok
= (fpos
= ftell(ofp
)) >= 0))
1924 if (!(ok
= (fseek(ofp
, fpos
, SEEK_SET
) >= 0)))
1926 if (!(ok
= (fscanf(ofp
, "%5lx", &offset
) == 1)))
1931 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
1932 (ANSI C Libraries) needs this rewind or else the fprintf
1933 stops working. This may also be true for CW11, but has
1939 if (!(ok
= (fseek(ofp
, fpos
, SEEK_SET
) >= 0)))
1941 offset
+= txt_offset
;
1942 if (!(ok
= (fprintf(ofp
, "%05lx\n", offset
) >= 0)))
1948 perror(line
); /* report the problem */
1950 /* close and kill the aborted output file, then give up */
1969 Sprintf(filename
, DATA_IN_TEMPLATE
, DGN_I_FILE
);
1970 if (!(ifp
= fopen(filename
, RDTMODE
))) {
1976 Strcat(filename
, file_prefix
);
1978 Sprintf(eos(filename
), DGN_TEMPLATE
, DGN_O_FILE
);
1979 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1983 Fprintf(ofp
, "%s", Dont_Edit_Data
);
1985 tfp
= getfp(DATA_TEMPLATE
, "grep.tmp", WRTMODE
);
1987 ifp
= getfp(DATA_TEMPLATE
, "grep.tmp", RDTMODE
);
1989 while ((line
= fgetline(ifp
)) != 0) {
1993 if (line
[0] == '#') {
1995 continue; /* discard comments */
1997 (void) fputs(line
, ofp
);
2003 delete_file(DATA_TEMPLATE
, "grep.tmp");
2008 ranged_attk(ptr
) /* returns TRUE if monster can attack at range */
2009 register struct permonst
*ptr
;
2012 register int atk_mask
= (1 << AT_BREA
) | (1 << AT_SPIT
) | (1 << AT_GAZE
);
2014 for (i
= 0; i
< NATTK
; i
++) {
2015 if ((j
= ptr
->mattk
[i
].aatyp
) >= AT_WEAP
|| (atk_mask
& (1 << j
)))
2022 /* This routine is designed to return an integer value which represents
2023 * an approximation of monster strength. It uses a similar method of
2024 * determination as "experience()" to arrive at the strength.
2028 struct permonst
*ptr
;
2030 int i
, tmp2
, n
, tmp
= ptr
->mlevel
;
2032 if (tmp
> 49) /* special fixed hp monster */
2033 tmp
= 2 * (tmp
- 6) / 4;
2035 /* For creation in groups */
2036 n
= (!!(ptr
->geno
& G_SGROUP
));
2037 n
+= (!!(ptr
->geno
& G_LGROUP
)) << 1;
2039 /* For ranged attacks */
2040 if (ranged_attk(ptr
))
2043 /* For higher ac values */
2047 /* For very fast monsters */
2048 n
+= (ptr
->mmove
>= 18);
2050 /* For each attack and "special" attack */
2051 for (i
= 0; i
< NATTK
; i
++) {
2052 tmp2
= ptr
->mattk
[i
].aatyp
;
2054 n
+= (tmp2
== AT_MAGC
);
2055 n
+= (tmp2
== AT_WEAP
&& (ptr
->mflags2
& M2_STRONG
));
2058 /* For each "special" damage type */
2059 for (i
= 0; i
< NATTK
; i
++) {
2060 tmp2
= ptr
->mattk
[i
].adtyp
;
2061 if ((tmp2
== AD_DRLI
) || (tmp2
== AD_STON
) || (tmp2
== AD_DRST
)
2062 || (tmp2
== AD_DRDX
) || (tmp2
== AD_DRCO
) || (tmp2
== AD_WERE
))
2064 else if (strcmp(ptr
->mname
, "grid bug"))
2065 n
+= (tmp2
!= AD_PHYS
);
2066 n
+= ((int) (ptr
->mattk
[i
].damd
* ptr
->mattk
[i
].damn
) > 23);
2069 /* Leprechauns are special cases. They have many hit dice so they can
2070 hit and are hard to kill, but they don't really do much damage. */
2071 if (!strcmp(ptr
->mname
, "leprechaun"))
2074 /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */
2082 return (tmp
>= 0) ? tmp
: 0;
2088 register struct permonst
*ptr
;
2092 * create the source file, "monstr.c"
2096 Strcat(filename
, file_prefix
);
2098 Sprintf(eos(filename
), SOURCE_TEMPLATE
, MON_STR_C
);
2099 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2103 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2104 Fprintf(ofp
, "#include \"config.h\"\n");
2105 Fprintf(ofp
, "\nconst int monstr[] = {\n");
2106 for (ptr
= &mons
[0], j
= 0; ptr
->mlet
; ptr
++) {
2110 Fprintf(ofp
, "%2d,%c", i
, (++j
& 15) ? ' ' : '\n');
2112 /* might want to insert a final 0 entry here instead of just newline */
2113 Fprintf(ofp
, "%s};\n", (j
& 15) ? "\n" : "");
2115 Fprintf(ofp
, "\nvoid NDECL(monstr_init);\n");
2116 Fprintf(ofp
, "\nvoid\n");
2117 Fprintf(ofp
, "monstr_init()\n");
2118 Fprintf(ofp
, "{\n");
2119 Fprintf(ofp
, " return;\n");
2120 Fprintf(ofp
, "}\n");
2121 Fprintf(ofp
, "\n/*monstr.c*/\n");
2135 Strcat(filename
, file_prefix
);
2137 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, MONST_FILE
);
2138 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2142 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2143 Fprintf(ofp
, "#ifndef PM_H\n#define PM_H\n");
2145 if (strcmp(mons
[0].mname
, "playermon") != 0)
2146 Fprintf(ofp
, "\n#define\tPM_PLAYERMON\t(-1)");
2148 for (i
= 0; mons
[i
].mlet
; i
++) {
2151 Fprintf(ofp
, "\n#define\tPM_");
2152 if (mons
[i
].mlet
== S_HUMAN
&& !strncmp(mons
[i
].mname
, "were", 4))
2153 Fprintf(ofp
, "HUMAN_");
2154 for (nam
= c
= tmpdup(mons
[i
].mname
); *c
; c
++)
2155 if (*c
>= 'a' && *c
<= 'z')
2156 *c
-= (char) ('a' - 'A');
2157 else if (*c
< 'A' || *c
> 'Z')
2159 Fprintf(ofp
, "%s\t%d", nam
, i
);
2161 Fprintf(ofp
, "\n\n#define\tNUMMONS\t%d\n", i
);
2162 Fprintf(ofp
, "\n#endif /* PM_H */\n");
2167 /* Start of Quest text file processing. */
2170 static struct qthdr qt_hdr
;
2171 static struct msghdr msg_hdr
[N_HDR
];
2172 static struct qtmsg
*curr_msg
;
2176 static boolean in_msg
;
2177 #define NO_MSG 1 /* strlen of a null line returned by fgets() */
2185 return (boolean
) (!in_msg
&& strlen(s
) == NO_MSG
);
2192 return (boolean
) (s
[0] == '%' && (s
[1] == 'C' || s
[1] == 'E'));
2201 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2202 if (!strncmp(code
, qt_hdr
.id
[i
], LEN_HDR
))
2212 if (qt_hdr
.n_hdr
>= N_HDR
) {
2213 Fprintf(stderr
, OUT_OF_HEADERS
, qt_line
);
2217 strncpy(&qt_hdr
.id
[qt_hdr
.n_hdr
][0], code
, LEN_HDR
);
2218 msg_hdr
[qt_hdr
.n_hdr
].n_msg
= 0;
2219 qt_hdr
.offset
[qt_hdr
.n_hdr
++] = 0L;
2229 for (i
= 0; i
< msg_hdr
[num
].n_msg
; i
++)
2230 if (msg_hdr
[num
].qt_msg
[i
].msgnum
== id
)
2241 struct qtmsg
*qt_msg
;
2243 if (msg_hdr
[num
].n_msg
>= N_MSG
) {
2244 Fprintf(stderr
, OUT_OF_MESSAGES
, qt_line
);
2246 qt_msg
= &(msg_hdr
[num
].qt_msg
[msg_hdr
[num
].n_msg
++]);
2247 qt_msg
->msgnum
= id
;
2248 qt_msg
->delivery
= s
[2];
2249 qt_msg
->offset
= qt_msg
->size
= qt_msg
->summary_size
= 0L;
2255 /* check %E record for "[summary text]" that nethack can stuff into the
2256 message history buffer when delivering text via window instead of pline */
2258 valid_qt_summary(s
, parsing
)
2259 char *s
; /* end record: "%E" optionally followed by " [summary]" */
2260 boolean parsing
; /* curr_msg is valid iff this is True */
2262 static char summary
[BUFSZ
];
2265 if (*s
!= '%' || *(s
+ 1) != 'E')
2267 if ((p
= index(s
, '[')) == 0)
2269 /* note: opening '[' and closing ']' will be retained in the output;
2270 anything after ']' will be discarded by putting a newline there */
2273 /* have an opening bracket; summary[] holds it and all text that follows
2276 /* find closing bracket */
2277 while (p
> summary
&& *(p
- 1) != ']')
2281 /* we backed up all the way to the start without finding a bracket */
2282 if (parsing
) /* malformed summary */
2283 Fprintf(stderr
, MAL_SUM
, qt_line
);
2284 } else if (p
== summary
+ 1) {
2285 ; /* ignore empty [] */
2286 } else { /* got something */
2287 /* p points one spot past ']', usually to '\n';
2288 we need to include the \n as part of the size */
2290 /* during the writing pass we won't be able to recheck
2291 delivery, so any useless summary for a pline mode
2292 message has to be carried along to the output file */
2293 if (curr_msg
->delivery
== 'p')
2294 Fprintf(stderr
, DUMB_SUM
, qt_line
);
2295 /* +1 is for terminating newline */
2296 curr_msg
->summary_size
= (long) (p
- summary
) + 1L;
2298 /* caller is writing rather than just parsing;
2299 force newline after the closing bracket */
2314 if (!index(s
, '\n'))
2315 Fprintf(stderr
, CTRL_TRUNC
, qt_line
);
2320 Fprintf(stderr
, CREC_IN_MSG
, qt_line
);
2324 if (sscanf(&s
[4], "%s %5d", code
, &id
) != 2) {
2325 Fprintf(stderr
, UNREC_CREC
, qt_line
);
2328 num
= get_hdr(code
);
2329 if (!num
&& !new_id(code
))
2331 num
= get_hdr(code
) - 1;
2332 if (known_msg(num
, id
))
2333 Fprintf(stderr
, DUP_MSG
, qt_line
);
2335 new_msg(s
, num
, id
);
2341 Fprintf(stderr
, END_NOT_IN_MSG
, qt_line
);
2343 /* sets curr_msg->summary_size if applicable */
2344 (void) valid_qt_summary(s
, TRUE
);
2350 Fprintf(stderr
, UNREC_CREC
, qt_line
);
2360 Fprintf(stderr
, TEXT_NOT_IN_MSG
, qt_line
);
2361 } else if (!index(s
, '\n')) {
2362 Fprintf(stderr
, TEXT_TRUNC
, qt_line
);
2365 curr_msg
->size
+= strlen(s
);
2373 long count
= 0L, hdr_offset
= sizeof(int)
2374 + (sizeof(char) * LEN_HDR
+ sizeof(long))
2377 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++) {
2378 qt_hdr
.offset
[i
] = hdr_offset
;
2379 hdr_offset
+= sizeof(int) + sizeof(struct qtmsg
) * msg_hdr
[i
].n_msg
;
2382 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2383 for (j
= 0; j
< msg_hdr
[i
].n_msg
; j
++) {
2384 msg_hdr
[i
].qt_msg
[j
].offset
= hdr_offset
+ count
;
2386 msg_hdr
[i
].qt_msg
[j
].size
+ msg_hdr
[i
].qt_msg
[j
].summary_size
;
2397 * The main header record.
2400 Fprintf(stderr
, "%ld: header info.\n", ftell(ofp
));
2401 (void) fwrite((genericptr_t
) & (qt_hdr
.n_hdr
), sizeof(int), 1, ofp
);
2402 (void) fwrite((genericptr_t
) & (qt_hdr
.id
[0][0]), sizeof(char) * LEN_HDR
,
2404 (void) fwrite((genericptr_t
) & (qt_hdr
.offset
[0]), sizeof(long),
2407 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2408 Fprintf(stderr
, "%s @ %ld, ", qt_hdr
.id
[i
], qt_hdr
.offset
[i
]);
2409 Fprintf(stderr
, "\n");
2413 * The individual class headers.
2415 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++) {
2417 Fprintf(stderr
, "%ld: %s header info.\n", ftell(ofp
),
2419 (void) fwrite((genericptr_t
) & (msg_hdr
[i
].n_msg
), sizeof(int), 1,
2421 (void) fwrite((genericptr_t
) & (msg_hdr
[i
].qt_msg
[0]),
2422 sizeof(struct qtmsg
), msg_hdr
[i
].n_msg
, ofp
);
2426 for (j
= 0; j
< msg_hdr
[i
].n_msg
; j
++) {
2427 Fprintf(stderr
, "msg %d @ %ld (%ld)",
2428 msg_hdr
[i
].qt_msg
[j
].msgnum
,
2429 msg_hdr
[i
].qt_msg
[j
].offset
,
2430 msg_hdr
[i
].qt_msg
[j
].size
);
2431 if (msg_hdr
[i
].qt_msg
[j
].summary_size
)
2432 Fprintf(stderr
, " [%ld]",
2433 msg_hdr
[i
].qt_msg
[j
].summary_size
);
2434 Fprintf(stderr
, "\n");
2445 Sprintf(filename
, DATA_IN_TEMPLATE
, QTXT_I_FILE
);
2446 if (!(ifp
= fopen(filename
, RDTMODE
))) {
2453 Strcat(filename
, file_prefix
);
2455 Sprintf(eos(filename
), DATA_TEMPLATE
, QTXT_O_FILE
);
2456 if (!(ofp
= fopen(filename
, WRBMODE
))) {
2466 while ((line
= fgetline(ifp
)) != 0) {
2470 if (qt_control(line
))
2471 do_qt_control(line
);
2472 else if (qt_comment(line
)) {
2484 while ((line
= fgetline(ifp
)) != 0) {
2485 if (qt_control(line
)) {
2486 char *summary_p
= 0;
2488 in_msg
= (line
[1] == 'C');
2490 summary_p
= valid_qt_summary(line
, FALSE
);
2491 /* don't write anything unless we've got a summary */
2496 /* we have summary text; replace raw %E record with it */
2497 Strcpy(line
, summary_p
); /* (guaranteed to fit) */
2498 } else if (qt_comment(line
)) {
2503 Fprintf(stderr
, "%ld: %s", ftell(stdout
), line
);
2504 (void) fputs(xcrypt(line
), ofp
);
2512 static char temp
[32];
2514 static char *limit(name
, pref
) /* limit a name to 30 characters length */
2518 (void) strncpy(temp
, name
, pref
? 26 : 30);
2519 temp
[pref
? 26 : 30] = 0;
2531 boolean sumerr
= FALSE
;
2535 Strcat(filename
, file_prefix
);
2537 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, ONAME_FILE
);
2538 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2542 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2543 Fprintf(ofp
, "#ifndef ONAMES_H\n#define ONAMES_H\n\n");
2545 for (i
= 0; !i
|| objects
[i
].oc_class
!= ILLOBJ_CLASS
; i
++) {
2548 objects
[i
].oc_name_idx
= objects
[i
].oc_descr_idx
= i
; /* init */
2549 if (!(objnam
= tmpdup(OBJ_NAME(objects
[i
]))))
2552 /* make sure probabilities add up to 1000 */
2553 if (objects
[i
].oc_class
!= class) {
2554 if (sum
&& sum
!= 1000) {
2555 Fprintf(stderr
, "prob error for class %d (%d%%)", class, sum
);
2556 (void) fflush(stderr
);
2559 class = objects
[i
].oc_class
;
2563 for (c
= objnam
; *c
; c
++)
2564 if (*c
>= 'a' && *c
<= 'z')
2565 *c
-= (char) ('a' - 'A');
2566 else if (*c
< 'A' || *c
> 'Z')
2571 Fprintf(ofp
, "#define\tWAN_");
2575 Fprintf(ofp
, "#define\tRIN_");
2579 Fprintf(ofp
, "#define\tPOT_");
2583 Fprintf(ofp
, "#define\tSPE_");
2588 Fprintf(ofp
, "#define\tSCR_");
2592 /* avoid trouble with stupid C preprocessors */
2593 Fprintf(ofp
, "#define\t");
2594 if (objects
[i
].oc_material
== PLASTIC
) {
2595 Fprintf(ofp
, "FAKE_AMULET_OF_YENDOR\t%d\n", i
);
2601 /* avoid trouble with stupid C preprocessors */
2602 if (objects
[i
].oc_material
== GLASS
) {
2603 Fprintf(ofp
, "/* #define\t%s\t%d */\n", objnam
, i
);
2608 Fprintf(ofp
, "#define\t");
2611 Fprintf(ofp
, "%s\t%d\n", limit(objnam
, prefix
), i
);
2614 sum
+= objects
[i
].oc_prob
;
2617 /* check last set of probabilities */
2618 if (sum
&& sum
!= 1000) {
2619 Fprintf(stderr
, "prob error for class %d (%d%%)", class, sum
);
2620 (void) fflush(stderr
);
2624 Fprintf(ofp
, "#define\tLAST_GEM\t(JADE)\n");
2625 Fprintf(ofp
, "#define\tMAXSPELL\t%d\n", nspell
+ 1);
2626 Fprintf(ofp
, "#define\tNUM_OBJECTS\t%d\n", i
);
2628 Fprintf(ofp
, "\n/* Artifacts (unique objects) */\n\n");
2630 for (i
= 1; artifact_names
[i
]; i
++) {
2633 for (c
= objnam
= tmpdup(artifact_names
[i
]); *c
; c
++)
2634 if (*c
>= 'a' && *c
<= 'z')
2635 *c
-= (char) ('a' - 'A');
2636 else if (*c
< 'A' || *c
> 'Z')
2639 if (!strncmp(objnam
, "THE_", 4))
2641 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
2642 if (!strncmp(objnam
, "PLATINUM_", 9))
2644 Fprintf(ofp
, "#define\tART_%s\t%d\n", limit(objnam
, 1), i
);
2647 Fprintf(ofp
, "#define\tNROFARTIFACTS\t%d\n", i
- 1);
2648 Fprintf(ofp
, "\n#endif /* ONAMES_H */\n");
2655 /* Read one line from input, up to and including the next newline
2656 * character. Returns a pointer to the heap-allocated string, or a
2657 * null pointer if no characters were read.
2663 static const int inc
= 256;
2665 char *c
= malloc(len
), *ret
;
2668 ret
= fgets(c
+ len
- inc
, inc
, fd
);
2673 } else if (index(c
, '\n')) {
2674 /* normal case: we have a full line */
2678 c
= realloc(c
, len
);
2687 static char buf
[128];
2691 (void) strncpy(buf
, str
, 127);
2705 * macro used to control vision algorithms:
2706 * VISION_TABLES => generate tables
2712 #ifdef VISION_TABLES
2715 /* Everything is clear. xclear may be malloc'ed.
2716 * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
2718 for (i
= 0; i
< MAX_ROW
; i
++)
2719 for (j
= 0; j
< MAX_COL
; j
++)
2720 if (i
< BLOCK_HEIGHT
&& j
< BLOCK_WIDTH
)
2721 xclear
[i
][j
] = '\000';
2723 xclear
[i
][j
] = '\001';
2724 #endif /* VISION_TABLES */
2729 * create the include file, "vis_tab.h"
2733 Strcat(filename
, file_prefix
);
2735 Sprintf(filename
, INCLUDE_TEMPLATE
, VIS_TAB_H
);
2736 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2740 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2741 Fprintf(ofp
, "#ifdef VISION_TABLES\n");
2742 #ifdef VISION_TABLES
2745 #endif /* VISION_TABLES */
2746 Fprintf(ofp
, "\n#endif /* VISION_TABLES */\n");
2752 * create the source file, "vis_tab.c"
2756 Strcat(filename
, file_prefix
);
2758 Sprintf(filename
, SOURCE_TEMPLATE
, VIS_TAB_C
);
2759 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2761 Sprintf(filename
, INCLUDE_TEMPLATE
, VIS_TAB_H
);
2765 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2766 Fprintf(ofp
, "#include \"config.h\"\n");
2767 Fprintf(ofp
, "#ifdef VISION_TABLES\n");
2768 Fprintf(ofp
, "#include \"vis_tab.h\"\n");
2772 #ifdef VISION_TABLES
2775 Fprintf(ofp
, "\nvoid vis_tab_init() { return; }\n");
2776 #endif /* VISION_TABLES */
2780 Fprintf(ofp
, "\n#endif /* VISION_TABLES */\n");
2781 Fprintf(ofp
, "\n/*vis_tab.c*/\n");
2787 #ifdef VISION_TABLES
2789 /*-------------- vision tables --------------*\
2791 * Generate the close and far tables. This is done by setting up a
2792 * fake dungeon and moving our source to different positions relative
2793 * to a block and finding the first/last visible position. The fake
2794 * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
2795 * by BLOCK_WIDTH) is blocked. Then we move the source around relative
2796 * to the corner of the block. For each new position of the source
2797 * we check positions on rows "kittycorner" from the source. We check
2798 * positions until they are either in sight or out of sight (depends on
2799 * which table we are generating). The picture below shows the setup
2800 * for the generation of the close table. The generation of the far
2801 * table would switch the quadrants of the '@' and the "Check rows
2805 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2806 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2807 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
2808 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2809 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2810 * ...............................
2811 * ...............................
2812 * .........@.....................
2813 * ...............................
2815 * Table generation figure (close_table). The 'X's are blocked points.
2816 * The 'B' is a special blocked point. The '@' is the source. The ','s
2817 * are the target area. The '.' are just open areas.
2820 * Example usage of close_table[][][].
2822 * The table is as follows:
2824 * dy = |row of '@' - row of 'B'| - 1
2825 * dx = |col of '@' - col of 'B'|
2827 * The first indices are the deltas from the source '@' and the block 'B'.
2828 * You must check for the value inside the abs value bars being zero. If
2829 * so then the block is on the same row and you don't need to do a table
2830 * lookup. The last value:
2832 * dcy = |row of block - row to be checked|
2834 * Is the value of the first visible spot on the check row from the
2837 * first visible col = close_table[dy][dx][dcy] + col of 'B'
2839 \*-------------- vision tables --------------*/
2844 Fprintf(ofp
, "\n/* Close */\n");
2846 "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
2849 "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
2852 "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
2854 Fprintf(ofp
, "typedef struct {\n");
2856 " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
2857 Fprintf(ofp
, "} close2d;\n");
2858 Fprintf(ofp
, "extern close2d close_table[CLOSE_MAX_SB_DY];\n");
2865 Fprintf(ofp
, "\n/* Far */\n");
2866 Fprintf(ofp
, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
2869 "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
2872 "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
2874 Fprintf(ofp
, "typedef struct {\n");
2875 Fprintf(ofp
, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
2876 Fprintf(ofp
, "} far2d;\n");
2877 Fprintf(ofp
, "extern far2d far_table[FAR_MAX_SB_DY];\n");
2885 int src_row
, src_col
; /* source */
2886 int block_row
, block_col
; /* block */
2891 block_row
= BLOCK_HEIGHT
- 1;
2892 block_col
= BLOCK_WIDTH
- 1;
2894 Fprintf(ofp
, "\n#ifndef FAR_TABLE_ONLY\n");
2895 Fprintf(ofp
, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
2896 #ifndef no_vision_progress
2897 Fprintf(stderr
, "\nclose:");
2900 for (dy
= 1; dy
< TEST_HEIGHT
; dy
++) {
2901 src_row
= block_row
+ dy
;
2902 Fprintf(ofp
, "/* DY = %2d (- 1)*/\n {{\n", dy
);
2903 #ifndef no_vision_progress
2904 Fprintf(stderr
, " %2d", dy
), (void) fflush(stderr
);
2906 for (dx
= 0; dx
< TEST_WIDTH
; dx
++) {
2907 src_col
= block_col
- dx
;
2908 Fprintf(ofp
, " /*%2d*/ {", dx
);
2911 for (this_row
= 0; this_row
< TEST_HEIGHT
; this_row
++) {
2912 delim
= (this_row
< TEST_HEIGHT
- 1) ? "," : "";
2914 Fprintf(ofp
, "%s%s", CLOSE_OFF_TABLE_STRING
, delim
);
2919 /* Find the first column that we can see. */
2920 for (i
= block_col
+ 1; i
< MAX_COL
; i
++) {
2921 if (clear_path(src_row
, src_col
, block_row
- this_row
, i
))
2927 Fprintf(ofp
, "%2d%s", i
- block_col
, delim
);
2929 Fprintf(ofp
, "}%s", (dx
< TEST_WIDTH
- 1) ? ",\n" : "\n");
2931 Fprintf(ofp
, " }},\n");
2934 Fprintf(ofp
, "}; /* close_table[] */\n"); /* closing brace for table */
2935 Fprintf(ofp
, "#endif /* !FAR_TABLE_ONLY */\n");
2936 #ifndef no_vision_progress
2937 Fprintf(stderr
, "\n");
2946 int src_row
, src_col
; /* source */
2947 int block_row
, block_col
; /* block */
2951 block_row
= BLOCK_HEIGHT
- 1;
2952 block_col
= BLOCK_WIDTH
- 1;
2954 Fprintf(ofp
, "\n#ifndef CLOSE_TABLE_ONLY\n");
2955 Fprintf(ofp
, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
2956 #ifndef no_vision_progress
2957 Fprintf(stderr
, "\n_far_:");
2960 for (dy
= 0; dy
< TEST_HEIGHT
; dy
++) {
2961 src_row
= block_row
- dy
;
2962 Fprintf(ofp
, "/* DY = %2d */\n {{\n", dy
);
2963 #ifndef no_vision_progress
2964 Fprintf(stderr
, " %2d", dy
), (void) fflush(stderr
);
2966 for (dx
= 1; dx
< TEST_WIDTH
; dx
++) {
2967 src_col
= block_col
+ dx
;
2968 Fprintf(ofp
, " /*%2d(-1)*/ {", dx
);
2970 for (this_row
= block_row
+ 1; this_row
< block_row
+ TEST_HEIGHT
;
2972 delim
= (this_row
< block_row
+ TEST_HEIGHT
- 1) ? "," : "";
2975 /* Find first col that we can see. */
2976 for (i
= 0; i
<= block_col
; i
++) {
2977 if (clear_path(src_row
, src_col
, this_row
, i
))
2981 if (block_col
- i
< 0)
2982 Fprintf(ofp
, "%s%s", FAR_OFF_TABLE_STRING
, delim
);
2984 Fprintf(ofp
, "%2d%s", block_col
- i
, delim
);
2986 Fprintf(ofp
, "}%s", (dx
< TEST_WIDTH
- 1) ? ",\n" : "\n");
2988 Fprintf(ofp
, " }},\n");
2991 Fprintf(ofp
, "}; /* far_table[] */\n"); /* closing brace for table */
2992 Fprintf(ofp
, "#endif /* !CLOSE_TABLE_ONLY */\n");
2993 #ifndef no_vision_progress
2994 Fprintf(stderr
, "\n");
3000 * "Draw" a line from the hero to the given location. Stop if we hit a
3003 * Generalized integer Bresenham's algorithm (fast line drawing) for
3004 * all quadrants. From _Procedural Elements for Computer Graphics_, by
3005 * David F. Rogers. McGraw-Hill, 1985.
3007 * I have tried a little bit of optimization by pulling compares out of
3010 * NOTE: This had better *not* be called from a position on the
3011 * same row as the hero.
3014 clear_path(you_row
, you_col
, y2
, x2
)
3015 int you_row
, you_col
, y2
, x2
;
3018 register int i
, error
, x
, y
, dxs
, dys
;
3022 dx
= abs(x2
- you_col
);
3023 dy
= abs(y2
- you_row
);
3024 s1
= sign(x2
- you_col
);
3025 s2
= sign(y2
- you_row
);
3027 if (s1
== 0) { /* same column */
3028 if (s2
== 1) { /* below (larger y2 value) */
3029 for (i
= you_row
+ 1; i
< y2
; i
++)
3030 if (!xclear
[i
][you_col
])
3032 } else { /* above (smaller y2 value) */
3033 for (i
= y2
+ 1; i
< you_row
; i
++)
3034 if (!xclear
[i
][you_col
])
3041 * Lines at 0 and 90 degrees have been weeded out.
3046 dy
= error
; /* swap the values */
3047 dxs
= dx
<< 1; /* save the shifted values */
3049 error
= dys
- dx
; /* NOTE: error is used as a temporary above */
3051 for (i
= 0; i
< dx
; i
++) {
3053 return 0; /* plot point */
3055 while (error
>= 0) {
3063 dxs
= dx
<< 1; /* save the shifted values */
3067 for (i
= 0; i
< dx
; i
++) {
3069 return 0; /* plot point */
3071 while (error
>= 0) {
3081 #endif /* VISION_TABLES */
3083 #ifdef STRICT_REF_DEF
3084 NEARDATA
struct flag flags
;
3086 struct attribs attrmax
, attrmin
;
3088 #endif /* STRICT_REF_DEF */