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",
1327 "command line completion",
1330 "Conway's Game of Life",
1333 "data file compression",
1336 "ZLIB data file compression",
1342 "floppy drive support",
1345 "insurance files for recovering from crashes",
1347 #ifdef HOLD_LOCKFILE_OPEN
1348 "exclusive lock on level 0 file",
1357 "MSDOS protected mode",
1374 "restore saved games via menu",
1376 #ifdef SCORE_ON_BOTL
1377 "score on status line",
1384 "screen control via mactty",
1387 "screen control via BIOS",
1389 #ifdef SCREEN_DJGPPFAST
1390 "screen control via DJGPP fast",
1393 "screen control via VGA graphics",
1396 "screen control via WIN32 console I/O",
1406 "terminal info library",
1408 #if defined(TERMLIB) \
1409 || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
1410 "terminal capability library",
1414 "timed wait for display effects",
1419 #ifdef PREFIXES_IN_USE
1420 "variable playground",
1422 #ifdef VISION_TABLES
1426 "zero-compressed save files",
1429 "run-length compression of map in save files",
1432 "system configuration at run-time",
1434 save_bones_compat_buf
, "and basic NetHack features"
1438 const char *id
, /* DEFAULT_WINDOW_SYS string */
1439 *name
; /* description, often same as id */
1441 static struct win_info window_opts
[] = {
1443 { "tty", "traditional tty-based graphics" },
1451 #ifdef GNOME_GRAPHICS
1452 { "Gnome", "Gnome" },
1457 #ifdef AMIGA_INTUITION
1458 { "amii", "Amiga Intuition" },
1463 #ifdef MSWIN_GRAPHICS
1464 { "mswin", "mswin" },
1466 #ifdef BEOS_GRAPHICS
1467 { "BeOS", "BeOS InterfaceKit" },
1475 #ifndef DEFAULT_WINDOW_SYS
1476 /* pre-standard compilers didn't support #error; wait til run-time */
1478 "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n");
1482 /* put in a dummy value so that do_options() will compile and makedefs
1483 will build, otherwise the message above won't ever get delivered */
1484 #define DEFAULT_WINDOW_SYS "<undefined>"
1485 #else /*DEFAULT_WINDOW_SYS*/
1487 if (!window_opts
[0].id
) {
1488 Fprintf(stderr
, "Configuration error: no windowing systems "
1489 "(TTY_GRAPHICS, &c) enabled.\n");
1496 for (i
= 0; window_opts
[i
].id
; ++i
)
1497 if (!strcmp(window_opts
[i
].id
, DEFAULT_WINDOW_SYS
))
1500 .id
) { /* went through whole list without a match */
1501 Fprintf(stderr
, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n",
1502 DEFAULT_WINDOW_SYS
);
1504 " does not match any enabled windowing system (%s%s).\n",
1505 window_opts
[0].id
, window_opts
[1].id
? ", &c" : "");
1509 #endif /*DEFAULT_WINDOW_SYS*/
1515 static const char indent
[] = " ";
1516 const char *str
, *sep
;
1517 char *word
, buf
[BUFSZ
];
1518 int i
, length
, winsyscnt
;
1524 Strcat(filename
, file_prefix
);
1526 Sprintf(eos(filename
), DATA_TEMPLATE
, OPTIONS_FILE
);
1527 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1532 build_savebones_compat_string();
1535 "\n NetHack version %d.%d.%d [beta]\n",
1537 "\n NetHack version %d.%d.%d\n",
1539 VERSION_MAJOR
, VERSION_MINOR
, PATCHLEVEL
);
1541 Fprintf(ofp
, "\nOptions compiled into this edition:\n");
1542 length
= COLNO
+ 1; /* force 1st item onto new line */
1543 for (i
= 0; i
< SIZE(build_opts
); i
++) {
1544 str
= strcpy(buf
, build_opts
[i
]);
1546 word
= index(str
, ' ');
1549 if (length
+ strlen(str
) > COLNO
- 5)
1550 Fprintf(ofp
, "\n%s", indent
), length
= strlen(indent
);
1552 Fprintf(ofp
, " "), length
++;
1553 Fprintf(ofp
, "%s", str
), length
+= strlen(str
);
1554 str
+= strlen(str
) + (word
? 1 : 0);
1556 Fprintf(ofp
, (i
< SIZE(build_opts
) - 1) ? "," : "."), length
++;
1559 winsyscnt
= SIZE(window_opts
) - 1;
1560 Fprintf(ofp
, "\n\nSupported windowing system%s:\n",
1561 (winsyscnt
> 1) ? "s" : "");
1562 length
= COLNO
+ 1; /* force 1st item onto new line */
1563 for (i
= 0; i
< winsyscnt
; i
++) {
1564 str
= window_opts
[i
].name
;
1565 if (length
+ strlen(str
) > COLNO
- 5)
1566 Fprintf(ofp
, "\n%s", indent
), length
= strlen(indent
);
1568 Fprintf(ofp
, " "), length
++;
1569 Fprintf(ofp
, "%s", str
), length
+= strlen(str
);
1570 sep
= (winsyscnt
== 1)
1573 ? ((i
== 0) ? " and" : "")
1574 : (i
< winsyscnt
- 2)
1576 : ((i
== winsyscnt
- 2) ? ", and" : "");
1577 Fprintf(ofp
, "%s", sep
), length
+= strlen(sep
);
1580 Fprintf(ofp
, "\n%swith a default of %s.", indent
, DEFAULT_WINDOW_SYS
);
1581 Fprintf(ofp
, "\n\n");
1587 /* routine to decide whether to discard something from data.base */
1593 return TRUE
; /* ignore comment lines */
1599 New format (v3.1) of 'data' file which allows much faster lookups [pr]
1600 "do not edit" first record is a comment line
1601 01234567 hexadecimal formatted offset to text area
1602 name-a first name of interest
1603 123,4 offset to name's text, and number of lines for it
1604 name-b next name of interest
1605 name-c multiple names which share same description also
1606 456,7 share a single offset,count line
1607 . sentinel to mark end of names
1608 789,0 dummy record containing offset, count of EOF
1609 text-a 4 lines of descriptive text for name-a
1610 text-a at file position 0x01234567L + 123L
1613 text-b/text-c 7 lines of text for names-b and -c
1614 text-b/text-c at fseek(0x01234567L + 456L)
1622 char infile
[60], tempfile
[60];
1625 int entry_cnt
, line_cnt
;
1628 Sprintf(tempfile
, DATA_TEMPLATE
, "database.tmp");
1631 Strcat(filename
, file_prefix
);
1633 Sprintf(eos(filename
), DATA_TEMPLATE
, DATA_FILE
);
1634 Sprintf(infile
, DATA_IN_TEMPLATE
, DATA_FILE
);
1635 #ifdef SHORT_FILENAMES
1636 Strcat(infile
, ".bas");
1638 Strcat(infile
, ".base");
1640 if (!(ifp
= fopen(infile
, RDTMODE
))) { /* data.base */
1644 if (!(ofp
= fopen(filename
, WRTMODE
))) { /* data */
1649 if (!(tfp
= fopen(tempfile
, WRTMODE
))) { /* database.tmp */
1657 /* output a dummy header record; we'll rewind and overwrite it later */
1658 Fprintf(ofp
, "%s%08lx\n", Dont_Edit_Data
, 0L);
1660 entry_cnt
= line_cnt
= 0;
1661 /* read through the input file and split it into two sections */
1662 while ((line
= fgetline(ifp
)) != 0) {
1663 if (d_filter(line
)) {
1667 if (*line
> ' ') { /* got an entry name */
1668 /* first finish previous entry */
1670 Fprintf(ofp
, "%d\n", line_cnt
), line_cnt
= 0;
1671 /* output the entry name */
1672 (void) fputs(line
, ofp
);
1673 entry_cnt
++; /* update number of entries */
1674 } else if (entry_cnt
) { /* got some descriptive text */
1675 /* update previous entry with current text offset */
1677 Fprintf(ofp
, "%ld,", ftell(tfp
));
1678 /* save the text line in the scratch file */
1679 (void) fputs(line
, tfp
);
1680 line_cnt
++; /* update line counter */
1684 /* output an end marker and then record the current position */
1686 Fprintf(ofp
, "%d\n", line_cnt
);
1687 Fprintf(ofp
, ".\n%ld,%d\n", ftell(tfp
), 0);
1688 txt_offset
= ftell(ofp
);
1689 Fclose(ifp
); /* all done with original input file */
1691 /* reprocess the scratch file; 1st format an error msg, just in case */
1693 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1694 if (rewind(tfp
) != 0)
1697 /* copy all lines of text from the scratch file into the output file */
1698 while ((line
= fgetline(tfp
)) != 0) {
1699 (void) fputs(line
, ofp
);
1703 /* finished with scratch file */
1705 Unlink(tempfile
); /* remove it */
1707 /* update the first record of the output file; prepare error msg 1st */
1709 Sprintf(line
, "rewind of \"%s\"", filename
);
1710 ok
= (rewind(ofp
) == 0);
1712 Sprintf(line
, "header rewrite of \"%s\"", filename
);
1713 ok
= (fprintf(ofp
, "%s%08lx\n", Dont_Edit_Data
,
1714 (unsigned long) txt_offset
) >= 0);
1718 perror(line
); /* report the problem */
1720 /* close and kill the aborted output file, then give up */
1733 /* routine to decide whether to discard something from oracles.txt */
1738 static boolean skip
= FALSE
;
1744 return TRUE
; /* ignore comment lines */
1746 tag
= malloc(strlen(line
));
1747 if (sscanf(line
, "----- %s", tag
) == 1) {
1749 } else if (skip
&& !strncmp(line
, "-----", 5))
1755 static const char *special_oracle
[] = {
1756 "\"...it is rather disconcerting to be confronted with the",
1757 "following theorem from [Baker, Gill, and Solovay, 1975].", "",
1758 "Theorem 7.18 There exist recursive languages A and B such that",
1759 " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "",
1760 "This provides impressive evidence that the techniques that are",
1761 "currently available will not suffice for proving that P != NP or "
1763 "that P == NP.\" [Garey and Johnson, p. 185.]"
1767 The oracle file consists of a "do not edit" comment, a decimal count N
1768 and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
1769 records, separated by "---" lines. The first oracle is a special case.
1770 The input data contains just those multi-line records, separated by
1777 char infile
[60], tempfile
[60];
1778 boolean in_oracle
, ok
;
1780 unsigned long txt_offset
, offset
;
1785 Sprintf(tempfile
, DATA_TEMPLATE
, "oracles.tmp");
1788 Strcat(filename
, file_prefix
);
1790 Sprintf(eos(filename
), DATA_TEMPLATE
, ORACLE_FILE
);
1791 Sprintf(infile
, DATA_IN_TEMPLATE
, ORACLE_FILE
);
1792 Strcat(infile
, ".txt");
1793 if (!(ifp
= fopen(infile
, RDTMODE
))) {
1797 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1802 if (!(tfp
= fopen(tempfile
, WRTMODE
))) { /* oracles.tmp */
1810 /* output a dummy header record; we'll rewind and overwrite it later */
1811 Fprintf(ofp
, "%s%5d\n", Dont_Edit_Data
, 0);
1813 /* handle special oracle; it must come first */
1814 (void) fputs("---\n", tfp
);
1815 offset
= (unsigned long) ftell(tfp
);
1816 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of special oracle */
1817 for (i
= 0; i
< SIZE(special_oracle
); i
++) {
1818 (void) fputs(xcrypt(special_oracle
[i
]), tfp
);
1819 (void) fputc('\n', tfp
);
1824 (void) fputs("---\n", tfp
);
1825 offset
= (unsigned long) ftell(tfp
);
1826 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of first oracle */
1829 while ((line
= fgetline(ifp
)) != 0) {
1832 if (h_filter(line
)) {
1836 if (!strncmp(line
, "-----", 5)) {
1843 (void) fputs("---\n", tfp
);
1844 offset
= (unsigned long) ftell(tfp
);
1845 Fprintf(ofp
, "%05lx\n", offset
); /* start pos of this oracle */
1848 (void) fputs(xcrypt(line
), tfp
);
1853 if (in_oracle
) { /* need to terminate last oracle */
1855 (void) fputs("---\n", tfp
);
1856 offset
= (unsigned long) ftell(tfp
);
1857 Fprintf(ofp
, "%05lx\n", offset
); /* eof position */
1860 /* record the current position */
1861 txt_offset
= (unsigned long) ftell(ofp
);
1862 Fclose(ifp
); /* all done with original input file */
1864 /* reprocess the scratch file; 1st format an error msg, just in case */
1866 Sprintf(line
, "rewind of \"%s\"", tempfile
);
1867 if (rewind(tfp
) != 0)
1870 /* copy all lines of text from the scratch file into the output file */
1871 while ((line
= fgetline(tfp
)) != 0) {
1872 (void) fputs(line
, ofp
);
1876 /* finished with scratch file */
1878 Unlink(tempfile
); /* remove it */
1880 /* update the first record of the output file; prepare error msg 1st */
1882 Sprintf(line
, "rewind of \"%s\"", filename
);
1883 ok
= (rewind(ofp
) == 0);
1885 Sprintf(line
, "header rewrite of \"%s\"", filename
);
1886 ok
= (fprintf(ofp
, "%s%5d\n", Dont_Edit_Data
, oracle_cnt
) >= 0);
1889 Sprintf(line
, "data rewrite of \"%s\"", filename
);
1890 for (i
= 0; i
<= oracle_cnt
; i
++) {
1891 #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */
1892 if (!(ok
= (fflush(ofp
) == 0)))
1895 if (!(ok
= (fpos
= ftell(ofp
)) >= 0))
1897 if (!(ok
= (fseek(ofp
, fpos
, SEEK_SET
) >= 0)))
1899 if (!(ok
= (fscanf(ofp
, "%5lx", &offset
) == 1)))
1904 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
1905 (ANSI C Libraries) needs this rewind or else the fprintf
1906 stops working. This may also be true for CW11, but has
1912 if (!(ok
= (fseek(ofp
, fpos
, SEEK_SET
) >= 0)))
1914 offset
+= txt_offset
;
1915 if (!(ok
= (fprintf(ofp
, "%05lx\n", offset
) >= 0)))
1921 perror(line
); /* report the problem */
1923 /* close and kill the aborted output file, then give up */
1942 Sprintf(filename
, DATA_IN_TEMPLATE
, DGN_I_FILE
);
1943 if (!(ifp
= fopen(filename
, RDTMODE
))) {
1949 Strcat(filename
, file_prefix
);
1951 Sprintf(eos(filename
), DGN_TEMPLATE
, DGN_O_FILE
);
1952 if (!(ofp
= fopen(filename
, WRTMODE
))) {
1956 Fprintf(ofp
, "%s", Dont_Edit_Data
);
1958 tfp
= getfp(DATA_TEMPLATE
, "grep.tmp", WRTMODE
);
1960 ifp
= getfp(DATA_TEMPLATE
, "grep.tmp", RDTMODE
);
1962 while ((line
= fgetline(ifp
)) != 0) {
1966 if (line
[0] == '#') {
1968 continue; /* discard comments */
1970 (void) fputs(line
, ofp
);
1976 delete_file(DATA_TEMPLATE
, "grep.tmp");
1981 ranged_attk(ptr
) /* returns TRUE if monster can attack at range */
1982 register struct permonst
*ptr
;
1985 register int atk_mask
= (1 << AT_BREA
) | (1 << AT_SPIT
) | (1 << AT_GAZE
);
1987 for (i
= 0; i
< NATTK
; i
++) {
1988 if ((j
= ptr
->mattk
[i
].aatyp
) >= AT_WEAP
|| (atk_mask
& (1 << j
)))
1995 /* This routine is designed to return an integer value which represents
1996 * an approximation of monster strength. It uses a similar method of
1997 * determination as "experience()" to arrive at the strength.
2001 struct permonst
*ptr
;
2003 int i
, tmp2
, n
, tmp
= ptr
->mlevel
;
2005 if (tmp
> 49) /* special fixed hp monster */
2006 tmp
= 2 * (tmp
- 6) / 4;
2008 /* For creation in groups */
2009 n
= (!!(ptr
->geno
& G_SGROUP
));
2010 n
+= (!!(ptr
->geno
& G_LGROUP
)) << 1;
2012 /* For ranged attacks */
2013 if (ranged_attk(ptr
))
2016 /* For higher ac values */
2020 /* For very fast monsters */
2021 n
+= (ptr
->mmove
>= 18);
2023 /* For each attack and "special" attack */
2024 for (i
= 0; i
< NATTK
; i
++) {
2025 tmp2
= ptr
->mattk
[i
].aatyp
;
2027 n
+= (tmp2
== AT_MAGC
);
2028 n
+= (tmp2
== AT_WEAP
&& (ptr
->mflags2
& M2_STRONG
));
2031 /* For each "special" damage type */
2032 for (i
= 0; i
< NATTK
; i
++) {
2033 tmp2
= ptr
->mattk
[i
].adtyp
;
2034 if ((tmp2
== AD_DRLI
) || (tmp2
== AD_STON
) || (tmp2
== AD_DRST
)
2035 || (tmp2
== AD_DRDX
) || (tmp2
== AD_DRCO
) || (tmp2
== AD_WERE
))
2037 else if (strcmp(ptr
->mname
, "grid bug"))
2038 n
+= (tmp2
!= AD_PHYS
);
2039 n
+= ((int) (ptr
->mattk
[i
].damd
* ptr
->mattk
[i
].damn
) > 23);
2042 /* Leprechauns are special cases. They have many hit dice so they can
2043 hit and are hard to kill, but they don't really do much damage. */
2044 if (!strcmp(ptr
->mname
, "leprechaun"))
2047 /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */
2055 return (tmp
>= 0) ? tmp
: 0;
2061 register struct permonst
*ptr
;
2065 * create the source file, "monstr.c"
2069 Strcat(filename
, file_prefix
);
2071 Sprintf(eos(filename
), SOURCE_TEMPLATE
, MON_STR_C
);
2072 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2076 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2077 Fprintf(ofp
, "#include \"config.h\"\n");
2078 Fprintf(ofp
, "\nconst int monstr[] = {\n");
2079 for (ptr
= &mons
[0], j
= 0; ptr
->mlet
; ptr
++) {
2083 Fprintf(ofp
, "%2d,%c", i
, (++j
& 15) ? ' ' : '\n');
2085 /* might want to insert a final 0 entry here instead of just newline */
2086 Fprintf(ofp
, "%s};\n", (j
& 15) ? "\n" : "");
2088 Fprintf(ofp
, "\nvoid NDECL(monstr_init);\n");
2089 Fprintf(ofp
, "\nvoid\n");
2090 Fprintf(ofp
, "monstr_init()\n");
2091 Fprintf(ofp
, "{\n");
2092 Fprintf(ofp
, " return;\n");
2093 Fprintf(ofp
, "}\n");
2094 Fprintf(ofp
, "\n/*monstr.c*/\n");
2108 Strcat(filename
, file_prefix
);
2110 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, MONST_FILE
);
2111 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2115 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2116 Fprintf(ofp
, "#ifndef PM_H\n#define PM_H\n");
2118 if (strcmp(mons
[0].mname
, "playermon") != 0)
2119 Fprintf(ofp
, "\n#define\tPM_PLAYERMON\t(-1)");
2121 for (i
= 0; mons
[i
].mlet
; i
++) {
2124 Fprintf(ofp
, "\n#define\tPM_");
2125 if (mons
[i
].mlet
== S_HUMAN
&& !strncmp(mons
[i
].mname
, "were", 4))
2126 Fprintf(ofp
, "HUMAN_");
2127 for (nam
= c
= tmpdup(mons
[i
].mname
); *c
; c
++)
2128 if (*c
>= 'a' && *c
<= 'z')
2129 *c
-= (char) ('a' - 'A');
2130 else if (*c
< 'A' || *c
> 'Z')
2132 Fprintf(ofp
, "%s\t%d", nam
, i
);
2134 Fprintf(ofp
, "\n\n#define\tNUMMONS\t%d\n", i
);
2135 Fprintf(ofp
, "\n#endif /* PM_H */\n");
2140 /* Start of Quest text file processing. */
2143 static struct qthdr qt_hdr
;
2144 static struct msghdr msg_hdr
[N_HDR
];
2145 static struct qtmsg
*curr_msg
;
2149 static boolean in_msg
;
2150 #define NO_MSG 1 /* strlen of a null line returned by fgets() */
2158 return (boolean
) (!in_msg
&& strlen(s
) == NO_MSG
);
2165 return (boolean
) (s
[0] == '%' && (s
[1] == 'C' || s
[1] == 'E'));
2174 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2175 if (!strncmp(code
, qt_hdr
.id
[i
], LEN_HDR
))
2185 if (qt_hdr
.n_hdr
>= N_HDR
) {
2186 Fprintf(stderr
, OUT_OF_HEADERS
, qt_line
);
2190 strncpy(&qt_hdr
.id
[qt_hdr
.n_hdr
][0], code
, LEN_HDR
);
2191 msg_hdr
[qt_hdr
.n_hdr
].n_msg
= 0;
2192 qt_hdr
.offset
[qt_hdr
.n_hdr
++] = 0L;
2202 for (i
= 0; i
< msg_hdr
[num
].n_msg
; i
++)
2203 if (msg_hdr
[num
].qt_msg
[i
].msgnum
== id
)
2214 struct qtmsg
*qt_msg
;
2216 if (msg_hdr
[num
].n_msg
>= N_MSG
) {
2217 Fprintf(stderr
, OUT_OF_MESSAGES
, qt_line
);
2219 qt_msg
= &(msg_hdr
[num
].qt_msg
[msg_hdr
[num
].n_msg
++]);
2220 qt_msg
->msgnum
= id
;
2221 qt_msg
->delivery
= s
[2];
2222 qt_msg
->offset
= qt_msg
->size
= qt_msg
->summary_size
= 0L;
2228 /* check %E record for "[summary text]" that nethack can stuff into the
2229 message history buffer when delivering text via window instead of pline */
2231 valid_qt_summary(s
, parsing
)
2232 char *s
; /* end record: "%E" optionally followed by " [summary]" */
2233 boolean parsing
; /* curr_msg is valid iff this is True */
2235 static char summary
[BUFSZ
];
2238 if (*s
!= '%' || *(s
+ 1) != 'E')
2240 if ((p
= index(s
, '[')) == 0)
2242 /* note: opening '[' and closing ']' will be retained in the output;
2243 anything after ']' will be discarded by putting a newline there */
2246 /* have an opening bracket; summary[] holds it and all text that follows
2249 /* find closing bracket */
2250 while (p
> summary
&& *(p
- 1) != ']')
2254 /* we backed up all the way to the start without finding a bracket */
2255 if (parsing
) /* malformed summary */
2256 Fprintf(stderr
, MAL_SUM
, qt_line
);
2257 } else if (p
== summary
+ 1) {
2258 ; /* ignore empty [] */
2259 } else { /* got something */
2260 /* p points one spot past ']', usually to '\n';
2261 we need to include the \n as part of the size */
2263 /* during the writing pass we won't be able to recheck
2264 delivery, so any useless summary for a pline mode
2265 message has to be carried along to the output file */
2266 if (curr_msg
->delivery
== 'p')
2267 Fprintf(stderr
, DUMB_SUM
, qt_line
);
2268 /* +1 is for terminating newline */
2269 curr_msg
->summary_size
= (long) (p
- summary
) + 1L;
2271 /* caller is writing rather than just parsing;
2272 force newline after the closing bracket */
2287 if (!index(s
, '\n'))
2288 Fprintf(stderr
, CTRL_TRUNC
, qt_line
);
2293 Fprintf(stderr
, CREC_IN_MSG
, qt_line
);
2297 if (sscanf(&s
[4], "%s %5d", code
, &id
) != 2) {
2298 Fprintf(stderr
, UNREC_CREC
, qt_line
);
2301 num
= get_hdr(code
);
2302 if (!num
&& !new_id(code
))
2304 num
= get_hdr(code
) - 1;
2305 if (known_msg(num
, id
))
2306 Fprintf(stderr
, DUP_MSG
, qt_line
);
2308 new_msg(s
, num
, id
);
2314 Fprintf(stderr
, END_NOT_IN_MSG
, qt_line
);
2316 /* sets curr_msg->summary_size if applicable */
2317 (void) valid_qt_summary(s
, TRUE
);
2323 Fprintf(stderr
, UNREC_CREC
, qt_line
);
2333 Fprintf(stderr
, TEXT_NOT_IN_MSG
, qt_line
);
2334 } else if (!index(s
, '\n')) {
2335 Fprintf(stderr
, TEXT_TRUNC
, qt_line
);
2338 curr_msg
->size
+= strlen(s
);
2346 long count
= 0L, hdr_offset
= sizeof(int)
2347 + (sizeof(char) * LEN_HDR
+ sizeof(long))
2350 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++) {
2351 qt_hdr
.offset
[i
] = hdr_offset
;
2352 hdr_offset
+= sizeof(int) + sizeof(struct qtmsg
) * msg_hdr
[i
].n_msg
;
2355 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2356 for (j
= 0; j
< msg_hdr
[i
].n_msg
; j
++) {
2357 msg_hdr
[i
].qt_msg
[j
].offset
= hdr_offset
+ count
;
2359 msg_hdr
[i
].qt_msg
[j
].size
+ msg_hdr
[i
].qt_msg
[j
].summary_size
;
2370 * The main header record.
2373 Fprintf(stderr
, "%ld: header info.\n", ftell(ofp
));
2374 (void) fwrite((genericptr_t
) & (qt_hdr
.n_hdr
), sizeof(int), 1, ofp
);
2375 (void) fwrite((genericptr_t
) & (qt_hdr
.id
[0][0]), sizeof(char) * LEN_HDR
,
2377 (void) fwrite((genericptr_t
) & (qt_hdr
.offset
[0]), sizeof(long),
2380 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++)
2381 Fprintf(stderr
, "%s @ %ld, ", qt_hdr
.id
[i
], qt_hdr
.offset
[i
]);
2382 Fprintf(stderr
, "\n");
2386 * The individual class headers.
2388 for (i
= 0; i
< qt_hdr
.n_hdr
; i
++) {
2390 Fprintf(stderr
, "%ld: %s header info.\n", ftell(ofp
),
2392 (void) fwrite((genericptr_t
) & (msg_hdr
[i
].n_msg
), sizeof(int), 1,
2394 (void) fwrite((genericptr_t
) & (msg_hdr
[i
].qt_msg
[0]),
2395 sizeof(struct qtmsg
), msg_hdr
[i
].n_msg
, ofp
);
2399 for (j
= 0; j
< msg_hdr
[i
].n_msg
; j
++) {
2400 Fprintf(stderr
, "msg %d @ %ld (%ld)",
2401 msg_hdr
[i
].qt_msg
[j
].msgnum
,
2402 msg_hdr
[i
].qt_msg
[j
].offset
,
2403 msg_hdr
[i
].qt_msg
[j
].size
);
2404 if (msg_hdr
[i
].qt_msg
[j
].summary_size
)
2405 Fprintf(stderr
, " [%ld]",
2406 msg_hdr
[i
].qt_msg
[j
].summary_size
);
2407 Fprintf(stderr
, "\n");
2418 Sprintf(filename
, DATA_IN_TEMPLATE
, QTXT_I_FILE
);
2419 if (!(ifp
= fopen(filename
, RDTMODE
))) {
2426 Strcat(filename
, file_prefix
);
2428 Sprintf(eos(filename
), DATA_TEMPLATE
, QTXT_O_FILE
);
2429 if (!(ofp
= fopen(filename
, WRBMODE
))) {
2439 while ((line
= fgetline(ifp
)) != 0) {
2443 if (qt_control(line
))
2444 do_qt_control(line
);
2445 else if (qt_comment(line
)) {
2457 while ((line
= fgetline(ifp
)) != 0) {
2458 if (qt_control(line
)) {
2459 char *summary_p
= 0;
2461 in_msg
= (line
[1] == 'C');
2463 summary_p
= valid_qt_summary(line
, FALSE
);
2464 /* don't write anything unless we've got a summary */
2469 /* we have summary text; replace raw %E record with it */
2470 Strcpy(line
, summary_p
); /* (guaranteed to fit) */
2471 } else if (qt_comment(line
)) {
2476 Fprintf(stderr
, "%ld: %s", ftell(stdout
), line
);
2477 (void) fputs(xcrypt(line
), ofp
);
2485 static char temp
[32];
2487 static char *limit(name
, pref
) /* limit a name to 30 characters length */
2491 (void) strncpy(temp
, name
, pref
? 26 : 30);
2492 temp
[pref
? 26 : 30] = 0;
2504 boolean sumerr
= FALSE
;
2508 Strcat(filename
, file_prefix
);
2510 Sprintf(eos(filename
), INCLUDE_TEMPLATE
, ONAME_FILE
);
2511 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2515 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2516 Fprintf(ofp
, "#ifndef ONAMES_H\n#define ONAMES_H\n\n");
2518 for (i
= 0; !i
|| objects
[i
].oc_class
!= ILLOBJ_CLASS
; i
++) {
2521 objects
[i
].oc_name_idx
= objects
[i
].oc_descr_idx
= i
; /* init */
2522 if (!(objnam
= tmpdup(OBJ_NAME(objects
[i
]))))
2525 /* make sure probabilities add up to 1000 */
2526 if (objects
[i
].oc_class
!= class) {
2527 if (sum
&& sum
!= 1000) {
2528 Fprintf(stderr
, "prob error for class %d (%d%%)", class, sum
);
2529 (void) fflush(stderr
);
2532 class = objects
[i
].oc_class
;
2536 for (c
= objnam
; *c
; c
++)
2537 if (*c
>= 'a' && *c
<= 'z')
2538 *c
-= (char) ('a' - 'A');
2539 else if (*c
< 'A' || *c
> 'Z')
2544 Fprintf(ofp
, "#define\tWAN_");
2548 Fprintf(ofp
, "#define\tRIN_");
2552 Fprintf(ofp
, "#define\tPOT_");
2556 Fprintf(ofp
, "#define\tSPE_");
2561 Fprintf(ofp
, "#define\tSCR_");
2565 /* avoid trouble with stupid C preprocessors */
2566 Fprintf(ofp
, "#define\t");
2567 if (objects
[i
].oc_material
== PLASTIC
) {
2568 Fprintf(ofp
, "FAKE_AMULET_OF_YENDOR\t%d\n", i
);
2574 /* avoid trouble with stupid C preprocessors */
2575 if (objects
[i
].oc_material
== GLASS
) {
2576 Fprintf(ofp
, "/* #define\t%s\t%d */\n", objnam
, i
);
2581 Fprintf(ofp
, "#define\t");
2584 Fprintf(ofp
, "%s\t%d\n", limit(objnam
, prefix
), i
);
2587 sum
+= objects
[i
].oc_prob
;
2590 /* check last set of probabilities */
2591 if (sum
&& sum
!= 1000) {
2592 Fprintf(stderr
, "prob error for class %d (%d%%)", class, sum
);
2593 (void) fflush(stderr
);
2597 Fprintf(ofp
, "#define\tLAST_GEM\t(JADE)\n");
2598 Fprintf(ofp
, "#define\tMAXSPELL\t%d\n", nspell
+ 1);
2599 Fprintf(ofp
, "#define\tNUM_OBJECTS\t%d\n", i
);
2601 Fprintf(ofp
, "\n/* Artifacts (unique objects) */\n\n");
2603 for (i
= 1; artifact_names
[i
]; i
++) {
2606 for (c
= objnam
= tmpdup(artifact_names
[i
]); *c
; c
++)
2607 if (*c
>= 'a' && *c
<= 'z')
2608 *c
-= (char) ('a' - 'A');
2609 else if (*c
< 'A' || *c
> 'Z')
2612 if (!strncmp(objnam
, "THE_", 4))
2614 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
2615 if (!strncmp(objnam
, "PLATINUM_", 9))
2617 Fprintf(ofp
, "#define\tART_%s\t%d\n", limit(objnam
, 1), i
);
2620 Fprintf(ofp
, "#define\tNROFARTIFACTS\t%d\n", i
- 1);
2621 Fprintf(ofp
, "\n#endif /* ONAMES_H */\n");
2628 /* Read one line from input, up to and including the next newline
2629 * character. Returns a pointer to the heap-allocated string, or a
2630 * null pointer if no characters were read.
2636 static const int inc
= 256;
2638 char *c
= malloc(len
), *ret
;
2641 ret
= fgets(c
+ len
- inc
, inc
, fd
);
2646 } else if (index(c
, '\n')) {
2647 /* normal case: we have a full line */
2651 c
= realloc(c
, len
);
2660 static char buf
[128];
2664 (void) strncpy(buf
, str
, 127);
2678 * macro used to control vision algorithms:
2679 * VISION_TABLES => generate tables
2685 #ifdef VISION_TABLES
2688 /* Everything is clear. xclear may be malloc'ed.
2689 * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
2691 for (i
= 0; i
< MAX_ROW
; i
++)
2692 for (j
= 0; j
< MAX_COL
; j
++)
2693 if (i
< BLOCK_HEIGHT
&& j
< BLOCK_WIDTH
)
2694 xclear
[i
][j
] = '\000';
2696 xclear
[i
][j
] = '\001';
2697 #endif /* VISION_TABLES */
2702 * create the include file, "vis_tab.h"
2706 Strcat(filename
, file_prefix
);
2708 Sprintf(filename
, INCLUDE_TEMPLATE
, VIS_TAB_H
);
2709 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2713 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2714 Fprintf(ofp
, "#ifdef VISION_TABLES\n");
2715 #ifdef VISION_TABLES
2718 #endif /* VISION_TABLES */
2719 Fprintf(ofp
, "\n#endif /* VISION_TABLES */\n");
2725 * create the source file, "vis_tab.c"
2729 Strcat(filename
, file_prefix
);
2731 Sprintf(filename
, SOURCE_TEMPLATE
, VIS_TAB_C
);
2732 if (!(ofp
= fopen(filename
, WRTMODE
))) {
2734 Sprintf(filename
, INCLUDE_TEMPLATE
, VIS_TAB_H
);
2738 Fprintf(ofp
, "%s", Dont_Edit_Code
);
2739 Fprintf(ofp
, "#include \"config.h\"\n");
2740 Fprintf(ofp
, "#ifdef VISION_TABLES\n");
2741 Fprintf(ofp
, "#include \"vis_tab.h\"\n");
2745 #ifdef VISION_TABLES
2748 Fprintf(ofp
, "\nvoid vis_tab_init() { return; }\n");
2749 #endif /* VISION_TABLES */
2753 Fprintf(ofp
, "\n#endif /* VISION_TABLES */\n");
2754 Fprintf(ofp
, "\n/*vis_tab.c*/\n");
2760 #ifdef VISION_TABLES
2762 /*-------------- vision tables --------------*\
2764 * Generate the close and far tables. This is done by setting up a
2765 * fake dungeon and moving our source to different positions relative
2766 * to a block and finding the first/last visible position. The fake
2767 * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
2768 * by BLOCK_WIDTH) is blocked. Then we move the source around relative
2769 * to the corner of the block. For each new position of the source
2770 * we check positions on rows "kittycorner" from the source. We check
2771 * positions until they are either in sight or out of sight (depends on
2772 * which table we are generating). The picture below shows the setup
2773 * for the generation of the close table. The generation of the far
2774 * table would switch the quadrants of the '@' and the "Check rows
2778 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2779 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2780 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
2781 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2782 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2783 * ...............................
2784 * ...............................
2785 * .........@.....................
2786 * ...............................
2788 * Table generation figure (close_table). The 'X's are blocked points.
2789 * The 'B' is a special blocked point. The '@' is the source. The ','s
2790 * are the target area. The '.' are just open areas.
2793 * Example usage of close_table[][][].
2795 * The table is as follows:
2797 * dy = |row of '@' - row of 'B'| - 1
2798 * dx = |col of '@' - col of 'B'|
2800 * The first indices are the deltas from the source '@' and the block 'B'.
2801 * You must check for the value inside the abs value bars being zero. If
2802 * so then the block is on the same row and you don't need to do a table
2803 * lookup. The last value:
2805 * dcy = |row of block - row to be checked|
2807 * Is the value of the first visible spot on the check row from the
2810 * first visible col = close_table[dy][dx][dcy] + col of 'B'
2812 \*-------------- vision tables --------------*/
2817 Fprintf(ofp
, "\n/* Close */\n");
2819 "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
2822 "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
2825 "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
2827 Fprintf(ofp
, "typedef struct {\n");
2829 " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
2830 Fprintf(ofp
, "} close2d;\n");
2831 Fprintf(ofp
, "extern close2d close_table[CLOSE_MAX_SB_DY];\n");
2838 Fprintf(ofp
, "\n/* Far */\n");
2839 Fprintf(ofp
, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
2842 "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
2845 "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
2847 Fprintf(ofp
, "typedef struct {\n");
2848 Fprintf(ofp
, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
2849 Fprintf(ofp
, "} far2d;\n");
2850 Fprintf(ofp
, "extern far2d far_table[FAR_MAX_SB_DY];\n");
2858 int src_row
, src_col
; /* source */
2859 int block_row
, block_col
; /* block */
2864 block_row
= BLOCK_HEIGHT
- 1;
2865 block_col
= BLOCK_WIDTH
- 1;
2867 Fprintf(ofp
, "\n#ifndef FAR_TABLE_ONLY\n");
2868 Fprintf(ofp
, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
2869 #ifndef no_vision_progress
2870 Fprintf(stderr
, "\nclose:");
2873 for (dy
= 1; dy
< TEST_HEIGHT
; dy
++) {
2874 src_row
= block_row
+ dy
;
2875 Fprintf(ofp
, "/* DY = %2d (- 1)*/\n {{\n", dy
);
2876 #ifndef no_vision_progress
2877 Fprintf(stderr
, " %2d", dy
), (void) fflush(stderr
);
2879 for (dx
= 0; dx
< TEST_WIDTH
; dx
++) {
2880 src_col
= block_col
- dx
;
2881 Fprintf(ofp
, " /*%2d*/ {", dx
);
2884 for (this_row
= 0; this_row
< TEST_HEIGHT
; this_row
++) {
2885 delim
= (this_row
< TEST_HEIGHT
- 1) ? "," : "";
2887 Fprintf(ofp
, "%s%s", CLOSE_OFF_TABLE_STRING
, delim
);
2892 /* Find the first column that we can see. */
2893 for (i
= block_col
+ 1; i
< MAX_COL
; i
++) {
2894 if (clear_path(src_row
, src_col
, block_row
- this_row
, i
))
2900 Fprintf(ofp
, "%2d%s", i
- block_col
, delim
);
2902 Fprintf(ofp
, "}%s", (dx
< TEST_WIDTH
- 1) ? ",\n" : "\n");
2904 Fprintf(ofp
, " }},\n");
2907 Fprintf(ofp
, "}; /* close_table[] */\n"); /* closing brace for table */
2908 Fprintf(ofp
, "#endif /* !FAR_TABLE_ONLY */\n");
2909 #ifndef no_vision_progress
2910 Fprintf(stderr
, "\n");
2919 int src_row
, src_col
; /* source */
2920 int block_row
, block_col
; /* block */
2924 block_row
= BLOCK_HEIGHT
- 1;
2925 block_col
= BLOCK_WIDTH
- 1;
2927 Fprintf(ofp
, "\n#ifndef CLOSE_TABLE_ONLY\n");
2928 Fprintf(ofp
, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
2929 #ifndef no_vision_progress
2930 Fprintf(stderr
, "\n_far_:");
2933 for (dy
= 0; dy
< TEST_HEIGHT
; dy
++) {
2934 src_row
= block_row
- dy
;
2935 Fprintf(ofp
, "/* DY = %2d */\n {{\n", dy
);
2936 #ifndef no_vision_progress
2937 Fprintf(stderr
, " %2d", dy
), (void) fflush(stderr
);
2939 for (dx
= 1; dx
< TEST_WIDTH
; dx
++) {
2940 src_col
= block_col
+ dx
;
2941 Fprintf(ofp
, " /*%2d(-1)*/ {", dx
);
2943 for (this_row
= block_row
+ 1; this_row
< block_row
+ TEST_HEIGHT
;
2945 delim
= (this_row
< block_row
+ TEST_HEIGHT
- 1) ? "," : "";
2948 /* Find first col that we can see. */
2949 for (i
= 0; i
<= block_col
; i
++) {
2950 if (clear_path(src_row
, src_col
, this_row
, i
))
2954 if (block_col
- i
< 0)
2955 Fprintf(ofp
, "%s%s", FAR_OFF_TABLE_STRING
, delim
);
2957 Fprintf(ofp
, "%2d%s", block_col
- i
, delim
);
2959 Fprintf(ofp
, "}%s", (dx
< TEST_WIDTH
- 1) ? ",\n" : "\n");
2961 Fprintf(ofp
, " }},\n");
2964 Fprintf(ofp
, "}; /* far_table[] */\n"); /* closing brace for table */
2965 Fprintf(ofp
, "#endif /* !CLOSE_TABLE_ONLY */\n");
2966 #ifndef no_vision_progress
2967 Fprintf(stderr
, "\n");
2973 * "Draw" a line from the hero to the given location. Stop if we hit a
2976 * Generalized integer Bresenham's algorithm (fast line drawing) for
2977 * all quadrants. From _Procedural Elements for Computer Graphics_, by
2978 * David F. Rogers. McGraw-Hill, 1985.
2980 * I have tried a little bit of optimization by pulling compares out of
2983 * NOTE: This had better *not* be called from a position on the
2984 * same row as the hero.
2987 clear_path(you_row
, you_col
, y2
, x2
)
2988 int you_row
, you_col
, y2
, x2
;
2991 register int i
, error
, x
, y
, dxs
, dys
;
2995 dx
= abs(x2
- you_col
);
2996 dy
= abs(y2
- you_row
);
2997 s1
= sign(x2
- you_col
);
2998 s2
= sign(y2
- you_row
);
3000 if (s1
== 0) { /* same column */
3001 if (s2
== 1) { /* below (larger y2 value) */
3002 for (i
= you_row
+ 1; i
< y2
; i
++)
3003 if (!xclear
[i
][you_col
])
3005 } else { /* above (smaller y2 value) */
3006 for (i
= y2
+ 1; i
< you_row
; i
++)
3007 if (!xclear
[i
][you_col
])
3014 * Lines at 0 and 90 degrees have been weeded out.
3019 dy
= error
; /* swap the values */
3020 dxs
= dx
<< 1; /* save the shifted values */
3022 error
= dys
- dx
; /* NOTE: error is used as a temporary above */
3024 for (i
= 0; i
< dx
; i
++) {
3026 return 0; /* plot point */
3028 while (error
>= 0) {
3036 dxs
= dx
<< 1; /* save the shifted values */
3040 for (i
= 0; i
< dx
; i
++) {
3042 return 0; /* plot point */
3044 while (error
>= 0) {
3054 #endif /* VISION_TABLES */
3056 #ifdef STRICT_REF_DEF
3057 NEARDATA
struct flag flags
;
3059 struct attribs attrmax
, attrmin
;
3061 #endif /* STRICT_REF_DEF */