1 /* NetHack 3.6 makedefs.c $NHDT-Date: 1447062431 2015/11/09 09:47:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.105 $ */
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.5\t2004/02/01";
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(make_version
);
168 static char *FDECL(version_string
, (char *, const char *));
169 static char *FDECL(version_id_string
, (char *, const char *));
170 static char *FDECL(bannerc_string
, (char *, const char *));
171 static char *FDECL(xcrypt
, (const char *));
172 static unsigned long FDECL(read_rumors_file
,
173 (const char *, int *, long *, unsigned long));
174 static void FDECL(do_rnd_access_file
, (const char *));
175 static boolean
FDECL(d_filter
, (char *));
176 static boolean
FDECL(h_filter
, (char *));
177 static boolean
FDECL(ranged_attk
, (struct permonst
*));
178 static int FDECL(mstrength
, (struct permonst
*));
179 static void NDECL(build_savebones_compat_string
);
180 static void FDECL(do_ext_makedefs
, (int, char **));
181 static void NDECL(windowing_sanity
);
183 static boolean
FDECL(qt_comment
, (char *));
184 static boolean
FDECL(qt_control
, (char *));
185 static int FDECL(get_hdr
, (char *));
186 static boolean
FDECL(new_id
, (char *));
187 static boolean
FDECL(known_msg
, (int, int));
188 static void FDECL(new_msg
, (char *, int, int));
189 static char *FDECL(valid_qt_summary
, (char *, BOOLEAN_P
));
190 static void FDECL(do_qt_control
, (char *));
191 static void FDECL(do_qt_text
, (char *));
192 static void NDECL(adjust_qt_hdrs
);
193 static void NDECL(put_qt_hdrs
);
196 static void NDECL(H_close_gen
);
197 static void NDECL(H_far_gen
);
198 static void NDECL(C_close_gen
);
199 static void NDECL(C_far_gen
);
200 static int FDECL(clear_path
, (int, int, int, int));
203 static char *FDECL(fgetline
, (FILE*));
204 static char *FDECL(tmpdup
, (const char *));
205 static char *FDECL(limit
, (char *, int));
206 static char *FDECL(eos
, (char *));
208 /* input, output, tmp */
209 static FILE *ifp
, *ofp
, *tfp
;
211 #if defined(__BORLANDC__) && !defined(_WIN32)
212 extern unsigned _stklen
= STKSIZ
;
215 #ifdef MACsansMPWTOOL
219 const char *def_options
= "odemvpqrshz";
223 printf("Enter options to run: [%s] ", def_options
);
225 fgets(buf
, 100, stdin
);
228 Strcpy(buf
, def_options
);
230 buf
[len
- 1] = 0; /* remove return */
232 if (buf
[0] == '-' && buf
[1] == '-') {
234 split up buf into words
235 do_ext_makedefs(fakeargc
, fakeargv
);
237 printf("extended makedefs not implemented for Mac OS9\n");
258 && !(argv
[1][0] == '-' && argv
[1][1] == '-')) {
259 Fprintf(stderr
, "Bad arg count (%d).\n", argc
- 1);
260 (void) fflush(stderr
);
265 if (argc
>= 2 && argv
[1][0] != '-') {
266 file_prefix
= argv
[1];
272 if (argv
[1][0] == '-' && argv
[1][1] == '-') {
273 do_ext_makedefs(argc
, argv
);
275 do_makedefs(&argv
[1][1]);
287 /* Note: these initializers don't do anything except guarantee that
288 we're linked properly.
298 boolean more_than_one
;
302 /* construct the current version number */
305 more_than_one
= strlen(options
) > 1;
308 Fprintf(stderr
, "makedefs -%c\n", *options
);
346 do_rnd_access_file(EPITAPHFILE
);
347 do_rnd_access_file(ENGRAVEFILE
);
348 do_rnd_access_file(BOGUSMONFILE
);
360 Fprintf(stderr
, "Unknown option '%c'.\n", *options
);
361 (void) fflush(stderr
);
367 Fprintf(stderr
, "Completed.\n"); /* feedback */
370 static char namebuf
[1000];
372 name_file(template, tag
)
376 Sprintf(namebuf
, template, tag
);
381 delete_file(template, tag
)
385 char *name
= name_file(template, tag
);
390 getfp(template, tag
, mode
)
395 char *name
= name_file(template, tag
);
396 FILE *rv
= fopen(name
, mode
);
398 Fprintf(stderr
, "Can't open '%s'.\n", name
);
404 static boolean debug
= FALSE
;
406 static FILE *inputfp
;
407 static FILE *outputfp
;
411 int is_defined
; /* 0 undef; 1 defined */
413 /* struct grep_var grep_vars[] and TODO_* constants in include file: */
416 static void NDECL(do_grep
);
417 static void NDECL(do_grep_showvars
);
418 static struct grep_var
*FDECL(grepsearch
, (char *));
419 static int grep_trace
= 0;
422 do_ext_makedefs(int argc
, char **argv
)
429 argv
++; /* skip program name */
432 if (argv
[0][0] != '-')
434 if (argv
[0][1] != '-') {
435 Fprintf(stderr
, "Can't mix - and -- options.\n");
438 #define IS_OPTION(str) if (!strcmp(&argv[0][2], str))
445 Fprintf(stderr, "missing option\n"); \
446 exit(EXIT_FAILURE); \
450 /* short version string for packaging - note
454 argv
++; /* not CONSUME */
457 strcpy(delim
, argv
[0]);
458 Fprintf(stdout
, "%s", version_string(buf
, delim
));
469 do_makedefs(argv
[0]);
475 if (!strcmp(argv
[0], "-")) {
478 inputfp
= fopen(argv
[0], RDTMODE
);
480 Fprintf(stderr
, "Can't open '%s'.\n", argv
[0]);
489 if (!strcmp(argv
[0], "-")) {
492 outputfp
= fopen(argv
[0], WRTMODE
);
494 Fprintf(stderr
, "Can't open '%s'.\n", argv
[0]);
503 Fprintf(stderr
, "Can't do grep and something else.\n");
509 IS_OPTION("grep-showvars")
514 IS_OPTION("grep-trace")
519 IS_OPTION("grep-define")
523 p
= grepsearch(argv
[0]);
527 Fprintf(stderr
, "Unknown symbol '%s'\n", argv
[0]);
532 IS_OPTION("grep-undef")
536 p
= grepsearch(argv
[0]);
540 Fprintf(stderr
, "Unknown symbol '%s'\n", argv
[0]);
551 Fprintf(stderr
, "Unknown option '%s'.\n", argv
[0]);
555 Fprintf(stderr
, "unexpected argument '%s'.\n", argv
[0]);
561 Fprintf(stderr
, "Confused about what to do?\n");
564 Fprintf(stderr
, "Nothing to do?\n");
574 Any line NOT starting with a caret is either suppressed or passed through
575 unchanged depending on the current conditional state.
577 The default conditional state is printing on.
579 Conditionals may be nested.
581 makedefs will exit with a EXIT_FAILURE if any errors are detected; as many
582 errors as possible are detected before giving up.
584 Unknown identifiers are treated as TRUE and also as an error to allow
585 processing to continue past the unknown identifier (note that "#undef" is
586 different than unknown).
588 Any line starting with a caret is a control line; as in C, zero or more
590 may be embedded in the line almost anywhere; the caret MUST be in column 1.
591 (XXX for the moment, no white space is allowed after the caret because
592 existing lines in the docs look like that)
595 ^^ a line starting with a (single) literal caret
596 ^# a comment - the line is ignored
603 #define GREP_MAGIC '^'
604 #define GREP_STACK_SIZE 100
606 static int grep_rewrite
= 0; /* need to (possibly) rewrite lines */
608 static int grep_writing
= 1; /* need to copy lines to output */
609 static int grep_errors
= 0;
610 static int grep_sp
= 0;
611 #define ST_LD(old, opp) (!!(old) | (!!(opp) << 1))
612 #define ST_OLD(v) ((v) &1)
613 #define ST_OPP(v) !!((v) &2)
615 static int grep_stack
[GREP_STACK_SIZE
] = { ST_LD(1, 0) };
616 static int grep_lineno
= 0;
622 for (x
= 0; x
< SIZE(grep_vars
) - 1; x
++) {
623 printf("%d\t%s\n", grep_vars
[x
].is_defined
, grep_vars
[x
].name
);
627 static struct grep_var
*
631 /* XXX make into binary search */
633 while (x
< SIZE(grep_vars
) - 1) {
634 if (!strcmp(grep_vars
[x
].name
, name
))
635 return &grep_vars
[x
];
646 while (*id
&& isspace(*id
))
649 Fprintf(stderr
, "missing identifier in line %d", grep_lineno
);
656 Fprintf(outputfp
, "ID %d %s\n", rv
->is_defined
, id
);
658 return rv
->is_defined
;
662 Fprintf(outputfp
, "ID U %s\n", id
);
664 Fprintf(stderr
, "unknown identifier '%s' in line %d.\n", id
, grep_lineno
);
666 return 2; /* So new features can be checked before makedefs
671 grep_show_wstack(tag
)
679 Fprintf(outputfp
, "%s w=%d sp=%d\t", tag
, grep_writing
, grep_sp
);
680 for (x
= grep_sp
; x
>= 0 && x
> grep_sp
- 6; x
--) {
681 Fprintf(outputfp
, "[%d]=%d ", x
, grep_stack
[x
]);
683 Fprintf(outputfp
, "\n");
694 return &buf
[-1]; /* XXX see docs above */
696 while (buf
[0] && isspace(buf
[0]))
700 case '#': /* comment */
702 case '.': /* end of if level */
704 Fprintf(stderr
, "unmatched ^. (endif) at line %d.\n",
708 grep_writing
= ST_OLD(grep_stack
[grep_sp
--]);
709 grep_show_wstack("pop");
712 case '!': /* if not ID */
715 case '?': /* if ID */
716 if (grep_sp
== GREP_STACK_SIZE
- 2) {
717 Fprintf(stderr
, "stack overflow at line %d.", grep_lineno
);
721 isif
= grep_check_id(&buf
[1]) ? isif
: !isif
;
722 grep_stack
[++grep_sp
] = ST_LD(grep_writing
, !isif
);
725 grep_stack
[++grep_sp
] = ST_LD(0, 0);
726 /* grep_writing = 0; */
728 grep_show_wstack("push");
731 if (ST_ELSE
& grep_stack
[grep_sp
]) {
732 Fprintf(stderr
, "multiple : for same conditional at line %d.\n",
736 grep_writing
= ST_OPP(grep_stack
[grep_sp
]);
737 grep_stack
[grep_sp
] |= ST_ELSE
;
740 case '(': /* start of expression */
742 case GREP_MAGIC
: /* ^^ -> ^ */
746 if (isprint(buf
[0])) {
750 sprintf(str
, "0x%02x", buf
[0]);
752 Fprintf(stderr
, "unknown control ^%s at line %d.\n", str
,
765 /* no language features use this yet */
770 static void grep0(FILE *, FILE *);
776 Fprintf(stderr
, "--grep requires --input\n");
779 Fprintf(stderr
, "--grep requires --output\n");
781 if (!inputfp
|| !outputfp
) {
785 grep0(inputfp
, outputfp
);
789 grep0(inputfp0
, outputfp0
)
793 char buf
[16384]; /* looong, just in case */
795 while (!feof(inputfp0
) && !ferror(inputfp0
)) {
799 if (fgets(buf
, sizeof(buf
), inputfp0
) == 0)
801 if ((tmp
= strchr(buf
, '\n')))
805 Fprintf(outputfp0
, "%04d %c >%s\n", grep_lineno
,
806 grep_writing
? ' ' : '#', buf
);
809 if (buf
[0] == GREP_MAGIC
) {
810 buf1
= do_grep_control(&buf
[1]);
818 do_grep_rewrite(buf1
);
821 Fprintf(outputfp0
, "%s\n", buf1
);
823 if (ferror(inputfp0
)) {
824 Fprintf(stderr
, "read error!\n");
827 if (ferror(outputfp0
)) {
828 Fprintf(stderr
, "write error!\n");
834 Fprintf(stderr
, "%d unterminated conditional level%s\n", grep_sp
,
835 grep_sp
== 1 ? "" : "s");
839 Fprintf(stderr
, "%d error%s detected.\n", grep_errors
,
840 grep_errors
== 1 ? "" : "s");
845 /* trivial text encryption routine which can't be broken with `tr' */
849 { /* duplicated in src/hacklib.c */
850 static char buf
[BUFSZ
];
851 register const char *p
;
853 register int bitmask
;
855 for (bitmask
= 1, p
= str
, q
= buf
; *p
; q
++) {
859 if ((bitmask
<<= 1) >= 32)
866 #define PAD_RUMORS_TO 60
867 /* common code for do_rumors(). Return 0 on error. */
869 read_rumors_file(file_ext
, rumor_count
, rumor_size
, old_rumor_offset
)
870 const char *file_ext
;
873 unsigned long old_rumor_offset
;
877 unsigned long rumor_offset
;
879 Sprintf(infile
, DATA_IN_TEMPLATE
, RUMOR_FILE
);
880 Strcat(infile
, file_ext
);
881 if (!(ifp
= fopen(infile
, RDTMODE
))) {
886 /* copy the rumors */
887 while ((line
= fgetline(ifp
)) != 0) {
889 /* rumor selection is accomplished by seeking to a random
890 position in the file, advancing to newline, and taking
891 the next line; therefore, rumors which follow long-line
892 rumors are most likely to be chosen and rumors which
893 follow short-line rumors are least likely to be chosen;
894 we ameliorate the latter by padding the shortest lines,
895 increasing the chance of the random seek landing in them */
896 int len
= (int) strlen(line
);
898 if (len
<= PAD_RUMORS_TO
) {
899 char *base
= index(line
, '\n');
900 /* this is only safe because fgetline() overallocates */
901 while (len
++ < PAD_RUMORS_TO
) {
910 /*[if we forced binary output, this would be sufficient]*/
911 *rumor_size
+= strlen(line
); /* includes newline */
913 (void) fputs(xcrypt(line
), tfp
);
916 /* record the current position; next rumors section will start here */
917 rumor_offset
= (unsigned long) ftell(tfp
);
918 Fclose(ifp
); /* all done with rumors.file_ext */
920 /* the calculated value for *_rumor_count assumes that
921 a single-byte line terminator is in use; for platforms
922 which use two byte CR+LF, we need to override that value
923 [it's much simpler to do so unconditionally, rendering
924 the loop's accumulation above obsolete] */
925 *rumor_size
= (long) (rumor_offset
- old_rumor_offset
);
930 do_rnd_access_file(fname
)
935 Sprintf(filename
, DATA_IN_TEMPLATE
, fname
);
936 Strcat(filename
, ".txt");
937 if (!(ifp
= fopen(filename
, RDTMODE
))) {
943 Strcat(filename
, file_prefix
);
945 Sprintf(eos(filename
), DATA_TEMPLATE
, fname
);
946 if (!(ofp
= fopen(filename
, WRTMODE
))) {
950 Fprintf(ofp
, "%s", Dont_Edit_Data
);
952 tfp
= getfp(DATA_TEMPLATE
, "grep.tmp", WRTMODE
);
954 ifp
= getfp(DATA_TEMPLATE
, "grep.tmp", RDTMODE
);
956 while ((line
= fgetline(ifp
)) != 0) {
957 if (line
[0] != '#' && line
[0] != '\n')
958 (void) fputs(xcrypt(line
), ofp
);
964 delete_file(DATA_TEMPLATE
, "grep.tmp");
972 static const char rumors_header
[] =
973 "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n";
975 int true_rumor_count
, false_rumor_count
;
976 long true_rumor_size
, false_rumor_size
;
977 unsigned long true_rumor_offset
, false_rumor_offset
, eof_offset
;
979 Sprintf(tempfile
, DATA_TEMPLATE
, "rumors.tmp");
982 Strcat(filename
, file_prefix
);
984 Sprintf(eos(filename
), DATA_TEMPLATE
, RUMOR_FILE
);
985 if (!(ofp
= fopen(filename
, WRTMODE
))) {
989 if (!(tfp
= fopen(tempfile
, WRTMODE
))) {
995 true_rumor_count
= false_rumor_count
= 0;
996 true_rumor_size
= false_rumor_size
= 0L;
997 true_rumor_offset
= false_rumor_offset
= eof_offset
= 0L;
999 /* output a dummy header record; we'll replace it in final output */
1000 Fprintf(tfp
, rumors_header
, Dont_Edit_Data
, true_rumor_count
,
1001 true_rumor_size
, true_rumor_offset
, false_rumor_count
,
1002 false_rumor_size
, false_rumor_offset
, eof_offset
);
1003 /* record the current position; true rumors will start here */
1004 true_rumor_offset
= ftell(tfp
);
1006 false_rumor_offset
= read_rumors_file(
1007 ".tru", &true_rumor_count
, &true_rumor_size
, true_rumor_offset
);
1008 if (!false_rumor_offset
)
1009 goto rumors_failure
;
1011 eof_offset
= read_rumors_file(".fal", &false_rumor_count
,
1012 &false_rumor_size
, false_rumor_offset
);
1014 goto rumors_failure
;
1016 /* get ready to transfer the contents of temp file to output file */
1018 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1019 if (rewind(tfp
) != 0) {
1022 goto rumors_failure
;
1026 /* output the header record */
1027 Fprintf(ofp
, rumors_header
, Dont_Edit_Data
, true_rumor_count
,
1028 true_rumor_size
, true_rumor_offset
, false_rumor_count
,
1029 false_rumor_size
, false_rumor_offset
, eof_offset
);
1030 /* skip the temp file's dummy header */
1031 if (!(line
= fgetline(tfp
))) { /* "Don't Edit" */
1033 goto rumors_failure
;
1036 if (!(line
= fgetline(tfp
))) { /* count,size,offset */
1038 goto rumors_failure
;
1041 /* copy the rest of the temp file into the final output file */
1042 while ((line
= fgetline(tfp
)) != 0) {
1043 (void) fputs(line
, ofp
);
1046 /* all done; delete temp file */
1054 Unlink(filename
); /* kill empty or incomplete output file */
1056 Unlink(tempfile
); /* and temporary file */
1061 * Use this to explicitly mask out features during version checks.
1063 * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features
1064 * that the port/plaform which wrote the savefile was capable of
1065 * dealing with. Don't reject a savefile just because the port
1066 * reading the savefile doesn't match on all/some of them.
1067 * The actual compression features used to produce the savefile are
1068 * recorded in the savefile_info structure immediately following the
1069 * version_info, and that is what needs to be checked against the
1070 * feature set of the port that is reading the savefile back in.
1071 * That check is done in src/restore.c now.
1074 #define IGNORED_FEATURES \
1075 (0L | (1L << 19) /* SCORE_ON_BOTL */ \
1076 | (1L << 27) /* ZEROCOMP */ \
1077 | (1L << 28) /* RLECOMP */ \
1086 * integer version number
1088 version
.incarnation
= ((unsigned long) VERSION_MAJOR
<< 24)
1089 | ((unsigned long) VERSION_MINOR
<< 16)
1090 | ((unsigned long) PATCHLEVEL
<< 8)
1091 | ((unsigned long) EDITLEVEL
);
1093 * encoded feature list
1094 * Note: if any of these magic numbers are changed or reassigned,
1095 * EDITLEVEL in patchlevel.h should be incremented at the same time.
1096 * The actual values have no special meaning, and the category
1097 * groupings are just for convenience.
1099 version
.feature_set
= (unsigned long) (0L
1100 /* levels and/or topology (0..4) */
1101 /* monsters (5..9) */
1105 /* objects (10..14) */
1106 /* flag bits and/or other global variables (15..26) */
1113 #ifdef SCORE_ON_BOTL
1116 /* data format (27..31)
1117 * External compression methods such as COMPRESS and ZLIB_COMP
1118 * do not affect the contents and are thus excluded from here */
1127 * Value used for object & monster sanity check.
1128 * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
1130 for (i
= 1; artifact_names
[i
]; i
++)
1132 version
.entity_count
= (unsigned long) (i
- 1);
1133 for (i
= 1; objects
[i
].oc_class
!= ILLOBJ_CLASS
; i
++)
1135 version
.entity_count
= (version
.entity_count
<< 12) | (unsigned long) i
;
1136 for (i
= 0; mons
[i
].mlet
; i
++)
1138 version
.entity_count
= (version
.entity_count
<< 12) | (unsigned long) i
;
1140 * Value used for compiler (word size/field alignment/padding) check.
1142 version
.struct_sizes1
=
1143 (((unsigned long) sizeof(struct context_info
) << 24)
1144 | ((unsigned long) sizeof(struct obj
) << 17)
1145 | ((unsigned long) sizeof(struct monst
) << 10)
1146 | ((unsigned long) sizeof(struct you
)));
1147 version
.struct_sizes2
= (((unsigned long) sizeof(struct flag
) << 10) |
1148 /* free bits in here */
1150 ((unsigned long) sizeof(struct sysflag
)));
1152 ((unsigned long) 0L));
1158 version_string(outbuf
, delim
)
1162 Sprintf(outbuf
, "%d%s%d%s%d", VERSION_MAJOR
, delim
, VERSION_MINOR
, delim
,
1165 Sprintf(eos(outbuf
), "-%d", EDITLEVEL
);
1171 version_id_string(outbuf
, build_date
)
1173 const char *build_date
;
1175 char subbuf
[64], versbuf
[64];
1180 Strcpy(&subbuf
[1], PORT_SUB_ID
);
1183 Strcat(subbuf
, " Beta");
1186 Sprintf(outbuf
, "%s NetHack%s Version %s - last build %s.", PORT_ID
,
1187 subbuf
, version_string(versbuf
, "."), build_date
);
1192 bannerc_string(outbuf
, build_date
)
1194 const char *build_date
;
1196 char subbuf
[64], versbuf
[64];
1201 Strcpy(&subbuf
[1], PORT_SUB_ID
);
1204 Strcat(subbuf
, " Beta");
1207 Sprintf(outbuf
, " Version %s %s%s, built %s.",
1208 version_string(versbuf
, "."), PORT_ID
, subbuf
, &build_date
[4]);
1210 Sprintf(outbuf
, "%s NetHack%s %s Copyright 1985-%s (built %s)",
1211 PORT_ID
, subbuf
, version_string(versbuf
,"."), RELEASE_YEAR
,
1223 time_t clocktim
= 0;
1225 char *c
, cbuf
[60], buf
[BUFSZ
];
1228 /* before creating date.h, make sure that xxx_GRAPHICS and
1229 DEFAULT_WINDOW_SYS have been set up in a viable fashion */
1234 Strcat(filename
, file_prefix
);
1236 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, DATE_FILE
);
1237 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1241 /* NB: We've moved on from SCCS, but this way this line
1242 * won't get clobbered when downstream projects import
1243 * this file into something more modern. */
1244 Fprintf(ofp
, "%s", Dont_Edit_Code
);
1246 (void) time(&clocktim
);
1247 Strcpy(cbuf
, ctime(&clocktim
));
1249 for (c
= cbuf
; *c
; c
++)
1252 *c
= '\0'; /* strip off the '\n' */
1253 Fprintf(ofp
, "#define BUILD_DATE \"%s\"\n", cbuf
);
1254 Fprintf(ofp
, "#define BUILD_TIME (%ldL)\n", (long) clocktim
);
1261 Fprintf(ofp
, "#define VERSION_NUMBER 0x%08lx%s\n", version
.incarnation
,
1263 Fprintf(ofp
, "#define VERSION_FEATURES 0x%08lx%s\n", version
.feature_set
,
1265 #ifdef IGNORED_FEATURES
1266 Fprintf(ofp
, "#define IGNORED_FEATURES 0x%08lx%s\n",
1267 (unsigned long) IGNORED_FEATURES
, ul_sfx
);
1269 Fprintf(ofp
, "#define VERSION_SANITY1 0x%08lx%s\n", version
.entity_count
,
1271 Fprintf(ofp
, "#define VERSION_SANITY2 0x%08lx%s\n", version
.struct_sizes1
,
1273 Fprintf(ofp
, "#define VERSION_SANITY3 0x%08lx%s\n", version
.struct_sizes2
,
1276 Fprintf(ofp
, "#define VERSION_STRING \"%s\"\n", version_string(buf
, "."));
1277 Fprintf(ofp
, "#define VERSION_ID \\\n \"%s\"\n",
1278 version_id_string(buf
, cbuf
));
1279 Fprintf(ofp
, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n",
1280 bannerc_string(buf
, cbuf
));
1284 struct tm
*tm
= localtime((time_t *) &clocktim
);
1285 Fprintf(ofp
, "#define AMIGA_VERSION_STRING ");
1286 Fprintf(ofp
, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
1287 VERSION_MAJOR
, VERSION_MINOR
, PATCHLEVEL
, tm
->tm_mday
,
1288 tm
->tm_mon
+ 1, tm
->tm_year
+ 1900);
1295 static char save_bones_compat_buf
[BUFSZ
];
1298 build_savebones_compat_string()
1300 #ifdef VERSION_COMPATIBILITY
1301 unsigned long uver
= VERSION_COMPATIBILITY
;
1303 Strcpy(save_bones_compat_buf
,
1304 "save and bones files accepted from version");
1305 #ifdef VERSION_COMPATIBILITY
1306 Sprintf(eos(save_bones_compat_buf
), "s %lu.%lu.%lu through %d.%d.%d",
1307 ((uver
& 0xFF000000L
) >> 24), ((uver
& 0x00FF0000L
) >> 16),
1308 ((uver
& 0x0000FF00L
) >> 8), VERSION_MAJOR
, VERSION_MINOR
,
1311 Sprintf(eos(save_bones_compat_buf
), " %d.%d.%d only", VERSION_MAJOR
,
1312 VERSION_MINOR
, PATCHLEVEL
);
1316 static const char *build_opts
[] = {
1318 "Amiga WorkBench support",
1321 "ANSI default terminal",
1326 #ifdef TTY_TILES_ESCCODES
1327 "console escape codes for tile hinting",
1330 "command line completion",
1333 "Conway's Game of Life",
1336 "data file compression",
1339 "ZLIB data file compression",
1345 "floppy drive support",
1348 "insurance files for recovering from crashes",
1350 #ifdef HOLD_LOCKFILE_OPEN
1351 "exclusive lock on level 0 file",
1353 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
1354 "external program as a message handler",
1363 "MSDOS protected mode",
1380 "restore saved games via menu",
1382 #ifdef SCORE_ON_BOTL
1383 "score on status line",
1390 "screen control via mactty",
1393 "screen control via BIOS",
1395 #ifdef SCREEN_DJGPPFAST
1396 "screen control via DJGPP fast",
1399 "screen control via VGA graphics",
1402 "screen control via WIN32 console I/O",
1408 #ifdef STATUS_VIA_WINDOWPORT
1409 # ifdef STATUS_HILITES
1410 "status via windowport with highlighting",
1412 "status via windowport without highlighting",
1415 "traditional status display",
1421 "terminal info library",
1423 #if defined(TERMLIB) \
1424 || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
1425 "terminal capability library",
1429 "timed wait for display effects",
1434 #ifdef PREFIXES_IN_USE
1435 "variable playground",
1437 #ifdef VISION_TABLES
1441 "zero-compressed save files",
1444 "run-length compression of map in save files",
1447 "system configuration at run-time",
1449 save_bones_compat_buf
, "and basic NetHack features"
1453 const char *id
, /* DEFAULT_WINDOW_SYS string */
1454 *name
; /* description, often same as id */
1456 static struct win_info window_opts
[] = {
1458 { "tty", "traditional tty-based graphics" },
1466 #ifdef GNOME_GRAPHICS
1467 { "Gnome", "Gnome" },
1472 #ifdef AMIGA_INTUITION
1473 { "amii", "Amiga Intuition" },
1478 #ifdef MSWIN_GRAPHICS
1479 { "mswin", "mswin" },
1481 #ifdef BEOS_GRAPHICS
1482 { "BeOS", "BeOS InterfaceKit" },
1490 #ifndef DEFAULT_WINDOW_SYS
1491 /* pre-standard compilers didn't support #error; wait til run-time */
1493 "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n");
1497 /* put in a dummy value so that do_options() will compile and makedefs
1498 will build, otherwise the message above won't ever get delivered */
1499 #define DEFAULT_WINDOW_SYS "<undefined>"
1500 #else /*DEFAULT_WINDOW_SYS*/
1502 if (!window_opts
[0].id
) {
1503 Fprintf(stderr
, "Configuration error: no windowing systems "
1504 "(TTY_GRAPHICS, &c) enabled.\n");
1511 for (i
= 0; window_opts
[i
].id
; ++i
)
1512 if (!strcmp(window_opts
[i
].id
, DEFAULT_WINDOW_SYS
))
1515 .id
) { /* went through whole list without a match */
1516 Fprintf(stderr
, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n",
1517 DEFAULT_WINDOW_SYS
);
1519 " does not match any enabled windowing system (%s%s).\n",
1520 window_opts
[0].id
, window_opts
[1].id
? ", &c" : "");
1524 #endif /*DEFAULT_WINDOW_SYS*/
1530 static const char indent
[] = " ";
1531 const char *str
, *sep
;
1532 char *word
, buf
[BUFSZ
];
1533 int i
, length
, winsyscnt
;
1539 Strcat(filename
, file_prefix
);
1541 Sprintf(eos(filename
), DATA_TEMPLATE
, OPTIONS_FILE
);
1542 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1547 build_savebones_compat_string();
1550 "\n NetHack version %d.%d.%d [beta]\n",
1552 "\n NetHack version %d.%d.%d\n",
1554 VERSION_MAJOR
, VERSION_MINOR
, PATCHLEVEL
);
1556 Fprintf(ofp
, "\nOptions compiled into this edition:\n");
1557 length
= COLNO
+ 1; /* force 1st item onto new line */
1558 for (i
= 0; i
< SIZE(build_opts
); i
++) {
1559 str
= strcpy(buf
, build_opts
[i
]);
1561 word
= index(str
, ' ');
1564 if (length
+ strlen(str
) > COLNO
- 5)
1565 Fprintf(ofp
, "\n%s", indent
), length
= strlen(indent
);
1567 Fprintf(ofp
, " "), length
++;
1568 Fprintf(ofp
, "%s", str
), length
+= strlen(str
);
1569 str
+= strlen(str
) + (word
? 1 : 0);
1571 Fprintf(ofp
, (i
< SIZE(build_opts
) - 1) ? "," : "."), length
++;
1574 winsyscnt
= SIZE(window_opts
) - 1;
1575 Fprintf(ofp
, "\n\nSupported windowing system%s:\n",
1576 (winsyscnt
> 1) ? "s" : "");
1577 length
= COLNO
+ 1; /* force 1st item onto new line */
1578 for (i
= 0; i
< winsyscnt
; i
++) {
1579 str
= window_opts
[i
].name
;
1580 if (length
+ strlen(str
) > COLNO
- 5)
1581 Fprintf(ofp
, "\n%s", indent
), length
= strlen(indent
);
1583 Fprintf(ofp
, " "), length
++;
1584 Fprintf(ofp
, "%s", str
), length
+= strlen(str
);
1585 sep
= (winsyscnt
== 1)
1588 ? ((i
== 0) ? " and" : "")
1589 : (i
< winsyscnt
- 2)
1591 : ((i
== winsyscnt
- 2) ? ", and" : "");
1592 Fprintf(ofp
, "%s", sep
), length
+= strlen(sep
);
1595 Fprintf(ofp
, "\n%swith a default of %s.", indent
, DEFAULT_WINDOW_SYS
);
1596 Fprintf(ofp
, "\n\n");
1602 /* routine to decide whether to discard something from data.base */
1608 return TRUE
; /* ignore comment lines */
1614 New format (v3.1) of 'data' file which allows much faster lookups [pr]
1615 "do not edit" first record is a comment line
1616 01234567 hexadecimal formatted offset to text area
1617 name-a first name of interest
1618 123,4 offset to name's text, and number of lines for it
1619 name-b next name of interest
1620 name-c multiple names which share same description also
1621 456,7 share a single offset,count line
1622 . sentinel to mark end of names
1623 789,0 dummy record containing offset, count of EOF
1624 text-a 4 lines of descriptive text for name-a
1625 text-a at file position 0x01234567L + 123L
1628 text-b/text-c 7 lines of text for names-b and -c
1629 text-b/text-c at fseek(0x01234567L + 456L)
1637 char infile
[60], tempfile
[60];
1640 int entry_cnt
, line_cnt
;
1643 Sprintf(tempfile
, DATA_TEMPLATE
, "database.tmp");
1646 Strcat(filename
, file_prefix
);
1648 Sprintf(eos(filename
), DATA_TEMPLATE
, DATA_FILE
);
1649 Sprintf(infile
, DATA_IN_TEMPLATE
, DATA_FILE
);
1650 #ifdef SHORT_FILENAMES
1651 Strcat(infile
, ".bas");
1653 Strcat(infile
, ".base");
1655 if (!(ifp
= fopen(infile
, RDTMODE
))) { /* data.base */
1659 if (!(ofp
= fopen(filename
, WRTMODE
))) { /* data */
1664 if (!(tfp
= fopen(tempfile
, WRTMODE
))) { /* database.tmp */
1672 /* output a dummy header record; we'll rewind and overwrite it later */
1673 Fprintf(ofp
, "%s%08lx\n", Dont_Edit_Data
, 0L);
1675 entry_cnt
= line_cnt
= 0;
1676 /* read through the input file and split it into two sections */
1677 while ((line
= fgetline(ifp
)) != 0) {
1678 if (d_filter(line
)) {
1682 if (*line
> ' ') { /* got an entry name */
1683 /* first finish previous entry */
1685 Fprintf(ofp
, "%d\n", line_cnt
), line_cnt
= 0;
1686 /* output the entry name */
1687 (void) fputs(line
, ofp
);
1688 entry_cnt
++; /* update number of entries */
1689 } else if (entry_cnt
) { /* got some descriptive text */
1690 /* update previous entry with current text offset */
1692 Fprintf(ofp
, "%ld,", ftell(tfp
));
1693 /* save the text line in the scratch file */
1694 (void) fputs(line
, tfp
);
1695 line_cnt
++; /* update line counter */
1699 /* output an end marker and then record the current position */
1701 Fprintf(ofp
, "%d\n", line_cnt
);
1702 Fprintf(ofp
, ".\n%ld,%d\n", ftell(tfp
), 0);
1703 txt_offset
= ftell(ofp
);
1704 Fclose(ifp
); /* all done with original input file */
1706 /* reprocess the scratch file; 1st format an error msg, just in case */
1708 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1709 if (rewind(tfp
) != 0)
1712 /* copy all lines of text from the scratch file into the output file */
1713 while ((line
= fgetline(tfp
)) != 0) {
1714 (void) fputs(line
, ofp
);
1718 /* finished with scratch file */
1720 Unlink(tempfile
); /* remove it */
1722 /* update the first record of the output file; prepare error msg 1st */
1724 Sprintf(line
, "rewind of \"%s\"", filename
);
1725 ok
= (rewind(ofp
) == 0);
1727 Sprintf(line
, "header rewrite of \"%s\"", filename
);
1728 ok
= (fprintf(ofp
, "%s%08lx\n", Dont_Edit_Data
,
1729 (unsigned long) txt_offset
) >= 0);
1733 perror(line
); /* report the problem */
1735 /* close and kill the aborted output file, then give up */
1748 /* routine to decide whether to discard something from oracles.txt */
1753 static boolean skip
= FALSE
;
1759 return TRUE
; /* ignore comment lines */
1761 tag
= malloc(strlen(line
));
1762 if (sscanf(line
, "----- %s", tag
) == 1) {
1764 } else if (skip
&& !strncmp(line
, "-----", 5))
1770 static const char *special_oracle
[] = {
1771 "\"...it is rather disconcerting to be confronted with the",
1772 "following theorem from [Baker, Gill, and Solovay, 1975].", "",
1773 "Theorem 7.18 There exist recursive languages A and B such that",
1774 " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "",
1775 "This provides impressive evidence that the techniques that are",
1776 "currently available will not suffice for proving that P != NP or "
1778 "that P == NP.\" [Garey and Johnson, p. 185.]"
1782 The oracle file consists of a "do not edit" comment, a decimal count N
1783 and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
1784 records, separated by "---" lines. The first oracle is a special case.
1785 The input data contains just those multi-line records, separated by
1792 char infile
[60], tempfile
[60];
1793 boolean in_oracle
, ok
;
1795 unsigned long txt_offset
, offset
;
1800 Sprintf(tempfile
, DATA_TEMPLATE
, "oracles.tmp");
1803 Strcat(filename
, file_prefix
);
1805 Sprintf(eos(filename
), DATA_TEMPLATE
, ORACLE_FILE
);
1806 Sprintf(infile
, DATA_IN_TEMPLATE
, ORACLE_FILE
);
1807 Strcat(infile
, ".txt");
1808 if (!(ifp
= fopen(infile
, RDTMODE
))) {
1812 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1817 if (!(tfp
= fopen(tempfile
, WRTMODE
))) { /* oracles.tmp */
1825 /* output a dummy header record; we'll rewind and overwrite it later */
1826 Fprintf(ofp
, "%s%5d\n", Dont_Edit_Data
, 0);
1828 /* handle special oracle; it must come first */
1829 (void) fputs("---\n", tfp
);
1830 offset
= (unsigned long) ftell(tfp
);
1831 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of special oracle */
1832 for (i
= 0; i
< SIZE(special_oracle
); i
++) {
1833 (void) fputs(xcrypt(special_oracle
[i
]), tfp
);
1834 (void) fputc('\n', tfp
);
1839 (void) fputs("---\n", tfp
);
1840 offset
= (unsigned long) ftell(tfp
);
1841 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of first oracle */
1844 while ((line
= fgetline(ifp
)) != 0) {
1847 if (h_filter(line
)) {
1851 if (!strncmp(line
, "-----", 5)) {
1858 (void) fputs("---\n", tfp
);
1859 offset
= (unsigned long) ftell(tfp
);
1860 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of this oracle */
1863 (void) fputs(xcrypt(line
), tfp
);
1868 if (in_oracle
) { /* need to terminate last oracle */
1870 (void) fputs("---\n", tfp
);
1871 offset
= (unsigned long) ftell(tfp
);
1872 Fprintf(ofp
, "%05lx\n", offset
); /* eof position */
1875 /* record the current position */
1876 txt_offset
= (unsigned long) ftell(ofp
);
1877 Fclose(ifp
); /* all done with original input file */
1879 /* reprocess the scratch file; 1st format an error msg, just in case */
1881 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1882 if (rewind(tfp
) != 0)
1885 /* copy all lines of text from the scratch file into the output file */
1886 while ((line
= fgetline(tfp
)) != 0) {
1887 (void) fputs(line
, ofp
);
1891 /* finished with scratch file */
1893 Unlink(tempfile
); /* remove it */
1895 /* update the first record of the output file; prepare error msg 1st */
1897 Sprintf(line
, "rewind of \"%s\"", filename
);
1898 ok
= (rewind(ofp
) == 0);
1900 Sprintf(line
, "header rewrite of \"%s\"", filename
);
1901 ok
= (fprintf(ofp
, "%s%5d\n", Dont_Edit_Data
, oracle_cnt
) >= 0);
1904 Sprintf(line
, "data rewrite of \"%s\"", filename
);
1905 for (i
= 0; i
<= oracle_cnt
; i
++) {
1906 #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */
1907 if (!(ok
= (fflush(ofp
) == 0)))
1910 if (!(ok
= (fpos
= ftell(ofp
)) >= 0))
1912 if (!(ok
= (fseek(ofp
, fpos
, SEEK_SET
) >= 0)))
1914 if (!(ok
= (fscanf(ofp
, "%5lx", &offset
) == 1)))
1919 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
1920 (ANSI C Libraries) needs this rewind or else the fprintf
1921 stops working. This may also be true for CW11, but has
1927 if (!(ok
= (fseek(ofp
, fpos
, SEEK_SET
) >= 0)))
1929 offset
+= txt_offset
;
1930 if (!(ok
= (fprintf(ofp
, "%05lx\n", offset
) >= 0)))
1936 perror(line
); /* report the problem */
1938 /* close and kill the aborted output file, then give up */
1957 Sprintf(filename
, DATA_IN_TEMPLATE
, DGN_I_FILE
);
1958 if (!(ifp
= fopen(filename
, RDTMODE
))) {
1964 Strcat(filename
, file_prefix
);
1966 Sprintf(eos(filename
), DGN_TEMPLATE
, DGN_O_FILE
);
1967 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1971 Fprintf(ofp
, "%s", Dont_Edit_Data
);
1973 tfp
= getfp(DATA_TEMPLATE
, "grep.tmp", WRTMODE
);
1975 ifp
= getfp(DATA_TEMPLATE
, "grep.tmp", RDTMODE
);
1977 while ((line
= fgetline(ifp
)) != 0) {
1981 if (line
[0] == '#') {
1983 continue; /* discard comments */
1985 (void) fputs(line
, ofp
);
1991 delete_file(DATA_TEMPLATE
, "grep.tmp");
1996 ranged_attk(ptr
) /* returns TRUE if monster can attack at range */
1997 register struct permonst
*ptr
;
2000 register int atk_mask
= (1 << AT_BREA
) | (1 << AT_SPIT
) | (1 << AT_GAZE
);
2002 for (i
= 0; i
< NATTK
; i
++) {
2003 if ((j
= ptr
->mattk
[i
].aatyp
) >= AT_WEAP
|| (atk_mask
& (1 << j
)))
2010 /* This routine is designed to return an integer value which represents
2011 * an approximation of monster strength. It uses a similar method of
2012 * determination as "experience()" to arrive at the strength.
2016 struct permonst
*ptr
;
2018 int i
, tmp2
, n
, tmp
= ptr
->mlevel
;
2020 if (tmp
> 49) /* special fixed hp monster */
2021 tmp
= 2 * (tmp
- 6) / 4;
2023 /* For creation in groups */
2024 n
= (!!(ptr
->geno
& G_SGROUP
));
2025 n
+= (!!(ptr
->geno
& G_LGROUP
)) << 1;
2027 /* For ranged attacks */
2028 if (ranged_attk(ptr
))
2031 /* For higher ac values */
2035 /* For very fast monsters */
2036 n
+= (ptr
->mmove
>= 18);
2038 /* For each attack and "special" attack */
2039 for (i
= 0; i
< NATTK
; i
++) {
2040 tmp2
= ptr
->mattk
[i
].aatyp
;
2042 n
+= (tmp2
== AT_MAGC
);
2043 n
+= (tmp2
== AT_WEAP
&& (ptr
->mflags2
& M2_STRONG
));
2046 /* For each "special" damage type */
2047 for (i
= 0; i
< NATTK
; i
++) {
2048 tmp2
= ptr
->mattk
[i
].adtyp
;
2049 if ((tmp2
== AD_DRLI
) || (tmp2
== AD_STON
) || (tmp2
== AD_DRST
)
2050 || (tmp2
== AD_DRDX
) || (tmp2
== AD_DRCO
) || (tmp2
== AD_WERE
))
2052 else if (strcmp(ptr
->mname
, "grid bug"))
2053 n
+= (tmp2
!= AD_PHYS
);
2054 n
+= ((int) (ptr
->mattk
[i
].damd
* ptr
->mattk
[i
].damn
) > 23);
2057 /* Leprechauns are special cases. They have many hit dice so they can
2058 hit and are hard to kill, but they don't really do much damage. */
2059 if (!strcmp(ptr
->mname
, "leprechaun"))
2062 /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */
2070 return (tmp
>= 0) ? tmp
: 0;
2076 register struct permonst
*ptr
;
2080 * create the source file, "monstr.c"
2084 Strcat(filename
, file_prefix
);
2086 Sprintf(eos(filename
), SOURCE_TEMPLATE
, MON_STR_C
);
2087 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2091 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2092 Fprintf(ofp
, "#include \"config.h\"\n");
2093 Fprintf(ofp
, "\nconst int monstr[] = {\n");
2094 for (ptr
= &mons
[0], j
= 0; ptr
->mlet
; ptr
++) {
2098 Fprintf(ofp
, "%2d,%c", i
, (++j
& 15) ? ' ' : '\n');
2100 /* might want to insert a final 0 entry here instead of just newline */
2101 Fprintf(ofp
, "%s};\n", (j
& 15) ? "\n" : "");
2103 Fprintf(ofp
, "\nvoid NDECL(monstr_init);\n");
2104 Fprintf(ofp
, "\nvoid\n");
2105 Fprintf(ofp
, "monstr_init()\n");
2106 Fprintf(ofp
, "{\n");
2107 Fprintf(ofp
, " return;\n");
2108 Fprintf(ofp
, "}\n");
2109 Fprintf(ofp
, "\n/*monstr.c*/\n");
2123 Strcat(filename
, file_prefix
);
2125 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, MONST_FILE
);
2126 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2130 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2131 Fprintf(ofp
, "#ifndef PM_H\n#define PM_H\n");
2133 if (strcmp(mons
[0].mname
, "playermon") != 0)
2134 Fprintf(ofp
, "\n#define\tPM_PLAYERMON\t(-1)");
2136 for (i
= 0; mons
[i
].mlet
; i
++) {
2139 Fprintf(ofp
, "\n#define\tPM_");
2140 if (mons
[i
].mlet
== S_HUMAN
&& !strncmp(mons
[i
].mname
, "were", 4))
2141 Fprintf(ofp
, "HUMAN_");
2142 for (nam
= c
= tmpdup(mons
[i
].mname
); *c
; c
++)
2143 if (*c
>= 'a' && *c
<= 'z')
2144 *c
-= (char) ('a' - 'A');
2145 else if (*c
< 'A' || *c
> 'Z')
2147 Fprintf(ofp
, "%s\t%d", nam
, i
);
2149 Fprintf(ofp
, "\n\n#define\tNUMMONS\t%d\n", i
);
2150 Fprintf(ofp
, "\n#endif /* PM_H */\n");
2155 /* Start of Quest text file processing. */
2158 static struct qthdr qt_hdr
;
2159 static struct msghdr msg_hdr
[N_HDR
];
2160 static struct qtmsg
*curr_msg
;
2164 static boolean in_msg
;
2165 #define NO_MSG 1 /* strlen of a null line returned by fgets() */
2173 return (boolean
) (!in_msg
&& strlen(s
) == NO_MSG
);
2180 return (boolean
) (s
[0] == '%' && (s
[1] == 'C' || s
[1] == 'E'));
2189 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2190 if (!strncmp(code
, qt_hdr
.id
[i
], LEN_HDR
))
2200 if (qt_hdr
.n_hdr
>= N_HDR
) {
2201 Fprintf(stderr
, OUT_OF_HEADERS
, qt_line
);
2205 strncpy(&qt_hdr
.id
[qt_hdr
.n_hdr
][0], code
, LEN_HDR
);
2206 msg_hdr
[qt_hdr
.n_hdr
].n_msg
= 0;
2207 qt_hdr
.offset
[qt_hdr
.n_hdr
++] = 0L;
2217 for (i
= 0; i
< msg_hdr
[num
].n_msg
; i
++)
2218 if (msg_hdr
[num
].qt_msg
[i
].msgnum
== id
)
2229 struct qtmsg
*qt_msg
;
2231 if (msg_hdr
[num
].n_msg
>= N_MSG
) {
2232 Fprintf(stderr
, OUT_OF_MESSAGES
, qt_line
);
2234 qt_msg
= &(msg_hdr
[num
].qt_msg
[msg_hdr
[num
].n_msg
++]);
2235 qt_msg
->msgnum
= id
;
2236 qt_msg
->delivery
= s
[2];
2237 qt_msg
->offset
= qt_msg
->size
= qt_msg
->summary_size
= 0L;
2243 /* check %E record for "[summary text]" that nethack can stuff into the
2244 message history buffer when delivering text via window instead of pline */
2246 valid_qt_summary(s
, parsing
)
2247 char *s
; /* end record: "%E" optionally followed by " [summary]" */
2248 boolean parsing
; /* curr_msg is valid iff this is True */
2250 static char summary
[BUFSZ
];
2253 if (*s
!= '%' || *(s
+ 1) != 'E')
2255 if ((p
= index(s
, '[')) == 0)
2257 /* note: opening '[' and closing ']' will be retained in the output;
2258 anything after ']' will be discarded by putting a newline there */
2261 /* have an opening bracket; summary[] holds it and all text that follows
2264 /* find closing bracket */
2265 while (p
> summary
&& *(p
- 1) != ']')
2269 /* we backed up all the way to the start without finding a bracket */
2270 if (parsing
) /* malformed summary */
2271 Fprintf(stderr
, MAL_SUM
, qt_line
);
2272 } else if (p
== summary
+ 1) {
2273 ; /* ignore empty [] */
2274 } else { /* got something */
2275 /* p points one spot past ']', usually to '\n';
2276 we need to include the \n as part of the size */
2278 /* during the writing pass we won't be able to recheck
2279 delivery, so any useless summary for a pline mode
2280 message has to be carried along to the output file */
2281 if (curr_msg
->delivery
== 'p')
2282 Fprintf(stderr
, DUMB_SUM
, qt_line
);
2283 /* +1 is for terminating newline */
2284 curr_msg
->summary_size
= (long) (p
- summary
) + 1L;
2286 /* caller is writing rather than just parsing;
2287 force newline after the closing bracket */
2302 if (!index(s
, '\n'))
2303 Fprintf(stderr
, CTRL_TRUNC
, qt_line
);
2308 Fprintf(stderr
, CREC_IN_MSG
, qt_line
);
2312 if (sscanf(&s
[4], "%s %5d", code
, &id
) != 2) {
2313 Fprintf(stderr
, UNREC_CREC
, qt_line
);
2316 num
= get_hdr(code
);
2317 if (!num
&& !new_id(code
))
2319 num
= get_hdr(code
) - 1;
2320 if (known_msg(num
, id
))
2321 Fprintf(stderr
, DUP_MSG
, qt_line
);
2323 new_msg(s
, num
, id
);
2329 Fprintf(stderr
, END_NOT_IN_MSG
, qt_line
);
2331 /* sets curr_msg->summary_size if applicable */
2332 (void) valid_qt_summary(s
, TRUE
);
2338 Fprintf(stderr
, UNREC_CREC
, qt_line
);
2348 Fprintf(stderr
, TEXT_NOT_IN_MSG
, qt_line
);
2349 } else if (!index(s
, '\n')) {
2350 Fprintf(stderr
, TEXT_TRUNC
, qt_line
);
2353 curr_msg
->size
+= strlen(s
);
2361 long count
= 0L, hdr_offset
= sizeof(int)
2362 + (sizeof(char) * LEN_HDR
+ sizeof(long))
2365 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++) {
2366 qt_hdr
.offset
[i
] = hdr_offset
;
2367 hdr_offset
+= sizeof(int) + sizeof(struct qtmsg
) * msg_hdr
[i
].n_msg
;
2370 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2371 for (j
= 0; j
< msg_hdr
[i
].n_msg
; j
++) {
2372 msg_hdr
[i
].qt_msg
[j
].offset
= hdr_offset
+ count
;
2374 msg_hdr
[i
].qt_msg
[j
].size
+ msg_hdr
[i
].qt_msg
[j
].summary_size
;
2385 * The main header record.
2388 Fprintf(stderr
, "%ld: header info.\n", ftell(ofp
));
2389 (void) fwrite((genericptr_t
) & (qt_hdr
.n_hdr
), sizeof(int), 1, ofp
);
2390 (void) fwrite((genericptr_t
) & (qt_hdr
.id
[0][0]), sizeof(char) * LEN_HDR
,
2392 (void) fwrite((genericptr_t
) & (qt_hdr
.offset
[0]), sizeof(long),
2395 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2396 Fprintf(stderr
, "%s @ %ld, ", qt_hdr
.id
[i
], qt_hdr
.offset
[i
]);
2397 Fprintf(stderr
, "\n");
2401 * The individual class headers.
2403 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++) {
2405 Fprintf(stderr
, "%ld: %s header info.\n", ftell(ofp
),
2407 (void) fwrite((genericptr_t
) & (msg_hdr
[i
].n_msg
), sizeof(int), 1,
2409 (void) fwrite((genericptr_t
) & (msg_hdr
[i
].qt_msg
[0]),
2410 sizeof(struct qtmsg
), msg_hdr
[i
].n_msg
, ofp
);
2414 for (j
= 0; j
< msg_hdr
[i
].n_msg
; j
++) {
2415 Fprintf(stderr
, "msg %d @ %ld (%ld)",
2416 msg_hdr
[i
].qt_msg
[j
].msgnum
,
2417 msg_hdr
[i
].qt_msg
[j
].offset
,
2418 msg_hdr
[i
].qt_msg
[j
].size
);
2419 if (msg_hdr
[i
].qt_msg
[j
].summary_size
)
2420 Fprintf(stderr
, " [%ld]",
2421 msg_hdr
[i
].qt_msg
[j
].summary_size
);
2422 Fprintf(stderr
, "\n");
2433 Sprintf(filename
, DATA_IN_TEMPLATE
, QTXT_I_FILE
);
2434 if (!(ifp
= fopen(filename
, RDTMODE
))) {
2441 Strcat(filename
, file_prefix
);
2443 Sprintf(eos(filename
), DATA_TEMPLATE
, QTXT_O_FILE
);
2444 if (!(ofp
= fopen(filename
, WRBMODE
))) {
2454 while ((line
= fgetline(ifp
)) != 0) {
2458 if (qt_control(line
))
2459 do_qt_control(line
);
2460 else if (qt_comment(line
)) {
2472 while ((line
= fgetline(ifp
)) != 0) {
2473 if (qt_control(line
)) {
2474 char *summary_p
= 0;
2476 in_msg
= (line
[1] == 'C');
2478 summary_p
= valid_qt_summary(line
, FALSE
);
2479 /* don't write anything unless we've got a summary */
2484 /* we have summary text; replace raw %E record with it */
2485 Strcpy(line
, summary_p
); /* (guaranteed to fit) */
2486 } else if (qt_comment(line
)) {
2491 Fprintf(stderr
, "%ld: %s", ftell(stdout
), line
);
2492 (void) fputs(xcrypt(line
), ofp
);
2500 static char temp
[32];
2502 static char *limit(name
, pref
) /* limit a name to 30 characters length */
2506 (void) strncpy(temp
, name
, pref
? 26 : 30);
2507 temp
[pref
? 26 : 30] = 0;
2519 boolean sumerr
= FALSE
;
2523 Strcat(filename
, file_prefix
);
2525 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, ONAME_FILE
);
2526 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2530 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2531 Fprintf(ofp
, "#ifndef ONAMES_H\n#define ONAMES_H\n\n");
2533 for (i
= 0; !i
|| objects
[i
].oc_class
!= ILLOBJ_CLASS
; i
++) {
2536 objects
[i
].oc_name_idx
= objects
[i
].oc_descr_idx
= i
; /* init */
2537 if (!(objnam
= tmpdup(OBJ_NAME(objects
[i
]))))
2540 /* make sure probabilities add up to 1000 */
2541 if (objects
[i
].oc_class
!= class) {
2542 if (sum
&& sum
!= 1000) {
2543 Fprintf(stderr
, "prob error for class %d (%d%%)", class, sum
);
2544 (void) fflush(stderr
);
2547 class = objects
[i
].oc_class
;
2551 for (c
= objnam
; *c
; c
++)
2552 if (*c
>= 'a' && *c
<= 'z')
2553 *c
-= (char) ('a' - 'A');
2554 else if (*c
< 'A' || *c
> 'Z')
2559 Fprintf(ofp
, "#define\tWAN_");
2563 Fprintf(ofp
, "#define\tRIN_");
2567 Fprintf(ofp
, "#define\tPOT_");
2571 Fprintf(ofp
, "#define\tSPE_");
2576 Fprintf(ofp
, "#define\tSCR_");
2580 /* avoid trouble with stupid C preprocessors */
2581 Fprintf(ofp
, "#define\t");
2582 if (objects
[i
].oc_material
== PLASTIC
) {
2583 Fprintf(ofp
, "FAKE_AMULET_OF_YENDOR\t%d\n", i
);
2589 /* avoid trouble with stupid C preprocessors */
2590 if (objects
[i
].oc_material
== GLASS
) {
2591 Fprintf(ofp
, "/* #define\t%s\t%d */\n", objnam
, i
);
2596 Fprintf(ofp
, "#define\t");
2599 Fprintf(ofp
, "%s\t%d\n", limit(objnam
, prefix
), i
);
2602 sum
+= objects
[i
].oc_prob
;
2605 /* check last set of probabilities */
2606 if (sum
&& sum
!= 1000) {
2607 Fprintf(stderr
, "prob error for class %d (%d%%)", class, sum
);
2608 (void) fflush(stderr
);
2612 Fprintf(ofp
, "#define\tLAST_GEM\t(JADE)\n");
2613 Fprintf(ofp
, "#define\tMAXSPELL\t%d\n", nspell
+ 1);
2614 Fprintf(ofp
, "#define\tNUM_OBJECTS\t%d\n", i
);
2616 Fprintf(ofp
, "\n/* Artifacts (unique objects) */\n\n");
2618 for (i
= 1; artifact_names
[i
]; i
++) {
2621 for (c
= objnam
= tmpdup(artifact_names
[i
]); *c
; c
++)
2622 if (*c
>= 'a' && *c
<= 'z')
2623 *c
-= (char) ('a' - 'A');
2624 else if (*c
< 'A' || *c
> 'Z')
2627 if (!strncmp(objnam
, "THE_", 4))
2629 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
2630 if (!strncmp(objnam
, "PLATINUM_", 9))
2632 Fprintf(ofp
, "#define\tART_%s\t%d\n", limit(objnam
, 1), i
);
2635 Fprintf(ofp
, "#define\tNROFARTIFACTS\t%d\n", i
- 1);
2636 Fprintf(ofp
, "\n#endif /* ONAMES_H */\n");
2643 /* Read one line from input, up to and including the next newline
2644 * character. Returns a pointer to the heap-allocated string, or a
2645 * null pointer if no characters were read.
2651 static const int inc
= 256;
2653 char *c
= malloc(len
), *ret
;
2656 ret
= fgets(c
+ len
- inc
, inc
, fd
);
2661 } else if (index(c
, '\n')) {
2662 /* normal case: we have a full line */
2666 c
= realloc(c
, len
);
2675 static char buf
[128];
2679 (void) strncpy(buf
, str
, 127);
2693 * macro used to control vision algorithms:
2694 * VISION_TABLES => generate tables
2700 #ifdef VISION_TABLES
2703 /* Everything is clear. xclear may be malloc'ed.
2704 * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
2706 for (i
= 0; i
< MAX_ROW
; i
++)
2707 for (j
= 0; j
< MAX_COL
; j
++)
2708 if (i
< BLOCK_HEIGHT
&& j
< BLOCK_WIDTH
)
2709 xclear
[i
][j
] = '\000';
2711 xclear
[i
][j
] = '\001';
2712 #endif /* VISION_TABLES */
2717 * create the include file, "vis_tab.h"
2721 Strcat(filename
, file_prefix
);
2723 Sprintf(filename
, INCLUDE_TEMPLATE
, VIS_TAB_H
);
2724 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2728 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2729 Fprintf(ofp
, "#ifdef VISION_TABLES\n");
2730 #ifdef VISION_TABLES
2733 #endif /* VISION_TABLES */
2734 Fprintf(ofp
, "\n#endif /* VISION_TABLES */\n");
2740 * create the source file, "vis_tab.c"
2744 Strcat(filename
, file_prefix
);
2746 Sprintf(filename
, SOURCE_TEMPLATE
, VIS_TAB_C
);
2747 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2749 Sprintf(filename
, INCLUDE_TEMPLATE
, VIS_TAB_H
);
2753 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2754 Fprintf(ofp
, "#include \"config.h\"\n");
2755 Fprintf(ofp
, "#ifdef VISION_TABLES\n");
2756 Fprintf(ofp
, "#include \"vis_tab.h\"\n");
2760 #ifdef VISION_TABLES
2763 Fprintf(ofp
, "\nvoid vis_tab_init() { return; }\n");
2764 #endif /* VISION_TABLES */
2768 Fprintf(ofp
, "\n#endif /* VISION_TABLES */\n");
2769 Fprintf(ofp
, "\n/*vis_tab.c*/\n");
2775 #ifdef VISION_TABLES
2777 /*-------------- vision tables --------------*\
2779 * Generate the close and far tables. This is done by setting up a
2780 * fake dungeon and moving our source to different positions relative
2781 * to a block and finding the first/last visible position. The fake
2782 * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
2783 * by BLOCK_WIDTH) is blocked. Then we move the source around relative
2784 * to the corner of the block. For each new position of the source
2785 * we check positions on rows "kittycorner" from the source. We check
2786 * positions until they are either in sight or out of sight (depends on
2787 * which table we are generating). The picture below shows the setup
2788 * for the generation of the close table. The generation of the far
2789 * table would switch the quadrants of the '@' and the "Check rows
2793 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2794 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2795 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
2796 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2797 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2798 * ...............................
2799 * ...............................
2800 * .........@.....................
2801 * ...............................
2803 * Table generation figure (close_table). The 'X's are blocked points.
2804 * The 'B' is a special blocked point. The '@' is the source. The ','s
2805 * are the target area. The '.' are just open areas.
2808 * Example usage of close_table[][][].
2810 * The table is as follows:
2812 * dy = |row of '@' - row of 'B'| - 1
2813 * dx = |col of '@' - col of 'B'|
2815 * The first indices are the deltas from the source '@' and the block 'B'.
2816 * You must check for the value inside the abs value bars being zero. If
2817 * so then the block is on the same row and you don't need to do a table
2818 * lookup. The last value:
2820 * dcy = |row of block - row to be checked|
2822 * Is the value of the first visible spot on the check row from the
2825 * first visible col = close_table[dy][dx][dcy] + col of 'B'
2827 \*-------------- vision tables --------------*/
2832 Fprintf(ofp
, "\n/* Close */\n");
2834 "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
2837 "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
2840 "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
2842 Fprintf(ofp
, "typedef struct {\n");
2844 " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
2845 Fprintf(ofp
, "} close2d;\n");
2846 Fprintf(ofp
, "extern close2d close_table[CLOSE_MAX_SB_DY];\n");
2853 Fprintf(ofp
, "\n/* Far */\n");
2854 Fprintf(ofp
, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
2857 "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
2860 "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
2862 Fprintf(ofp
, "typedef struct {\n");
2863 Fprintf(ofp
, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
2864 Fprintf(ofp
, "} far2d;\n");
2865 Fprintf(ofp
, "extern far2d far_table[FAR_MAX_SB_DY];\n");
2873 int src_row
, src_col
; /* source */
2874 int block_row
, block_col
; /* block */
2879 block_row
= BLOCK_HEIGHT
- 1;
2880 block_col
= BLOCK_WIDTH
- 1;
2882 Fprintf(ofp
, "\n#ifndef FAR_TABLE_ONLY\n");
2883 Fprintf(ofp
, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
2884 #ifndef no_vision_progress
2885 Fprintf(stderr
, "\nclose:");
2888 for (dy
= 1; dy
< TEST_HEIGHT
; dy
++) {
2889 src_row
= block_row
+ dy
;
2890 Fprintf(ofp
, "/* DY = %2d (- 1)*/\n {{\n", dy
);
2891 #ifndef no_vision_progress
2892 Fprintf(stderr
, " %2d", dy
), (void) fflush(stderr
);
2894 for (dx
= 0; dx
< TEST_WIDTH
; dx
++) {
2895 src_col
= block_col
- dx
;
2896 Fprintf(ofp
, " /*%2d*/ {", dx
);
2899 for (this_row
= 0; this_row
< TEST_HEIGHT
; this_row
++) {
2900 delim
= (this_row
< TEST_HEIGHT
- 1) ? "," : "";
2902 Fprintf(ofp
, "%s%s", CLOSE_OFF_TABLE_STRING
, delim
);
2907 /* Find the first column that we can see. */
2908 for (i
= block_col
+ 1; i
< MAX_COL
; i
++) {
2909 if (clear_path(src_row
, src_col
, block_row
- this_row
, i
))
2915 Fprintf(ofp
, "%2d%s", i
- block_col
, delim
);
2917 Fprintf(ofp
, "}%s", (dx
< TEST_WIDTH
- 1) ? ",\n" : "\n");
2919 Fprintf(ofp
, " }},\n");
2922 Fprintf(ofp
, "}; /* close_table[] */\n"); /* closing brace for table */
2923 Fprintf(ofp
, "#endif /* !FAR_TABLE_ONLY */\n");
2924 #ifndef no_vision_progress
2925 Fprintf(stderr
, "\n");
2934 int src_row
, src_col
; /* source */
2935 int block_row
, block_col
; /* block */
2939 block_row
= BLOCK_HEIGHT
- 1;
2940 block_col
= BLOCK_WIDTH
- 1;
2942 Fprintf(ofp
, "\n#ifndef CLOSE_TABLE_ONLY\n");
2943 Fprintf(ofp
, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
2944 #ifndef no_vision_progress
2945 Fprintf(stderr
, "\n_far_:");
2948 for (dy
= 0; dy
< TEST_HEIGHT
; dy
++) {
2949 src_row
= block_row
- dy
;
2950 Fprintf(ofp
, "/* DY = %2d */\n {{\n", dy
);
2951 #ifndef no_vision_progress
2952 Fprintf(stderr
, " %2d", dy
), (void) fflush(stderr
);
2954 for (dx
= 1; dx
< TEST_WIDTH
; dx
++) {
2955 src_col
= block_col
+ dx
;
2956 Fprintf(ofp
, " /*%2d(-1)*/ {", dx
);
2958 for (this_row
= block_row
+ 1; this_row
< block_row
+ TEST_HEIGHT
;
2960 delim
= (this_row
< block_row
+ TEST_HEIGHT
- 1) ? "," : "";
2963 /* Find first col that we can see. */
2964 for (i
= 0; i
<= block_col
; i
++) {
2965 if (clear_path(src_row
, src_col
, this_row
, i
))
2969 if (block_col
- i
< 0)
2970 Fprintf(ofp
, "%s%s", FAR_OFF_TABLE_STRING
, delim
);
2972 Fprintf(ofp
, "%2d%s", block_col
- i
, delim
);
2974 Fprintf(ofp
, "}%s", (dx
< TEST_WIDTH
- 1) ? ",\n" : "\n");
2976 Fprintf(ofp
, " }},\n");
2979 Fprintf(ofp
, "}; /* far_table[] */\n"); /* closing brace for table */
2980 Fprintf(ofp
, "#endif /* !CLOSE_TABLE_ONLY */\n");
2981 #ifndef no_vision_progress
2982 Fprintf(stderr
, "\n");
2988 * "Draw" a line from the hero to the given location. Stop if we hit a
2991 * Generalized integer Bresenham's algorithm (fast line drawing) for
2992 * all quadrants. From _Procedural Elements for Computer Graphics_, by
2993 * David F. Rogers. McGraw-Hill, 1985.
2995 * I have tried a little bit of optimization by pulling compares out of
2998 * NOTE: This had better *not* be called from a position on the
2999 * same row as the hero.
3002 clear_path(you_row
, you_col
, y2
, x2
)
3003 int you_row
, you_col
, y2
, x2
;
3006 register int i
, error
, x
, y
, dxs
, dys
;
3010 dx
= abs(x2
- you_col
);
3011 dy
= abs(y2
- you_row
);
3012 s1
= sign(x2
- you_col
);
3013 s2
= sign(y2
- you_row
);
3015 if (s1
== 0) { /* same column */
3016 if (s2
== 1) { /* below (larger y2 value) */
3017 for (i
= you_row
+ 1; i
< y2
; i
++)
3018 if (!xclear
[i
][you_col
])
3020 } else { /* above (smaller y2 value) */
3021 for (i
= y2
+ 1; i
< you_row
; i
++)
3022 if (!xclear
[i
][you_col
])
3029 * Lines at 0 and 90 degrees have been weeded out.
3034 dy
= error
; /* swap the values */
3035 dxs
= dx
<< 1; /* save the shifted values */
3037 error
= dys
- dx
; /* NOTE: error is used as a temporary above */
3039 for (i
= 0; i
< dx
; i
++) {
3041 return 0; /* plot point */
3043 while (error
>= 0) {
3051 dxs
= dx
<< 1; /* save the shifted values */
3055 for (i
= 0; i
< dx
; i
++) {
3057 return 0; /* plot point */
3059 while (error
>= 0) {
3069 #endif /* VISION_TABLES */
3071 #ifdef STRICT_REF_DEF
3072 NEARDATA
struct flag flags
;
3074 struct attribs attrmax
, attrmin
;
3076 #endif /* STRICT_REF_DEF */