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 "../japanese/jpatchle.h"
32 #include "patchlevel.h"
34 #include "../japanese/jpatchlevel.h"
40 #if defined(__SC__) || defined(__MRC__) /* MPW compilers */
42 #include <CursorCtl.h>
44 #else /* MAC without MPWTOOL */
45 #define MACsansMPWTOOL
53 #define Fprintf (void) fprintf
54 #define Fclose (void) fclose
55 #define Unlink (void) unlink
56 #if !defined(AMIGA) || defined(AZTEC_C)
57 #define rewind(fp) fseek((fp), 0L, SEEK_SET) /* guarantee a return value */
60 #if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN)
61 static const char SCCS_Id[] = "@(#)makedefs.c\t3.5\t2004/02/01";
64 /* names of files to be generated */
65 #define DATE_FILE "date.h"
66 #define MONST_FILE "pm.h"
67 #define ONAME_FILE "onames.h"
69 #define OPTIONS_FILE "options"
71 #define ORACLE_FILE "oracles"
72 #define DATA_FILE "data"
73 #define RUMOR_FILE "rumors"
74 #define DGN_I_FILE "dungeon.def"
75 #define DGN_O_FILE "dungeon.pdf"
76 #define MON_STR_C "monstr.c"
77 #define QTXT_I_FILE "quest.txt"
78 #define QTXT_O_FILE "quest.dat"
79 #define VIS_TAB_H "vis_tab.h"
80 #define VIS_TAB_C "vis_tab.c"
81 /* locations for those files */
84 #define INCLUDE_TEMPLATE "NH:include/t.%s"
85 #define SOURCE_TEMPLATE "NH:src/%s"
86 #define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */
87 #define DATA_TEMPLATE "NH:slib/%s"
88 #define DATA_IN_TEMPLATE "NH:dat/%s"
90 #if defined(MAC) && !defined(__MACH__)
91 /* MacOS 9 or earlier */
92 #define INCLUDE_TEMPLATE ":include:%s"
93 #define SOURCE_TEMPLATE ":src:%s"
94 #define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */
96 #define DATA_TEMPLATE ":Dungeon:%s"
98 #define DATA_TEMPLATE ":lib:%s"
99 #endif /* __SC__ || __MRC__ */
100 #define DATA_IN_TEMPLATE ":dat:%s"
101 #else /* neither AMIGA nor MAC */
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 #else /* not AMIGA, MAC, or OS2 */
109 #define INCLUDE_TEMPLATE "../include/%s"
110 #define SOURCE_TEMPLATE "../src/%s"
111 #define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */
112 #define DATA_TEMPLATE "../dat/%s"
113 #define DATA_IN_TEMPLATE "../dat/%s"
114 #endif /* else !OS2 */
115 #endif /* else !MAC */
116 #endif /* else !AMIGA */
120 "/* This source file is generated by 'makedefs'. Do not edit. */\n",
122 "#\tThis data file is generated by 'makedefs'. Do not edit. \n";
124 static struct version_info version;
126 /* definitions used for vision tables */
127 #define TEST_WIDTH COLNO
128 #define TEST_HEIGHT ROWNO
129 #define BLOCK_WIDTH (TEST_WIDTH + 10)
130 #define BLOCK_HEIGHT TEST_HEIGHT /* don't need extra spaces */
131 #define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT)
132 #define MAX_COL (BLOCK_WIDTH + TEST_WIDTH)
133 /* Use this as an out-of-bound value in the close table. */
134 #define CLOSE_OFF_TABLE_STRING "99" /* for the close table */
135 #define FAR_OFF_TABLE_STRING "0xff" /* for the far table */
137 #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0))
139 static char xclear[MAX_ROW][MAX_COL];
141 /*-end of vision defs-*/
143 static char filename[600];
146 /* if defined, a first argument not starting with - is
147 * taken as a text string to be prepended to any
148 * output filename generated */
149 char *file_prefix = "";
152 #ifdef MACsansMPWTOOL
153 int FDECL(main, (void));
155 int FDECL(main, (int, char **));
157 void FDECL(do_makedefs, (char *));
160 void NDECL(do_dungeon);
162 void NDECL(do_options);
163 void NDECL(do_monstr);
164 void NDECL(do_permonst);
165 void NDECL(do_questtxt);
166 void NDECL(do_rumors);
167 void NDECL(do_oracles);
168 void NDECL(do_vision);
170 extern void NDECL(monst_init); /* monst.c */
171 extern void NDECL(objects_init); /* objects.c */
173 static void NDECL(make_version);
174 static char *FDECL(version_string, (char *, const char *));
175 static char *FDECL(version_id_string, (char *, const char *));
176 static char *FDECL(bannerc_string, (char *, const char *));
177 static char *FDECL(xcrypt, (const char *));
178 static unsigned long FDECL(read_rumors_file,
179 (const char *, int *, long *, unsigned long));
180 static void FDECL(do_rnd_access_file, (const char *));
181 static boolean FDECL(d_filter, (char *));
182 static boolean FDECL(h_filter, (char *));
183 static boolean FDECL(ranged_attk, (struct permonst *));
184 static int FDECL(mstrength, (struct permonst *));
185 static void NDECL(build_savebones_compat_string);
186 static void FDECL(do_ext_makedefs, (int, char **));
187 static void NDECL(windowing_sanity);
189 static boolean FDECL(qt_comment, (char *));
190 static boolean FDECL(qt_control, (char *));
191 static int FDECL(get_hdr, (char *));
192 static boolean FDECL(new_id, (char *));
193 static boolean FDECL(known_msg, (int, int));
194 static void FDECL(new_msg, (char *, int, int));
195 static char *FDECL(valid_qt_summary, (char *, BOOLEAN_P));
196 static void FDECL(do_qt_control, (char *));
197 static void FDECL(do_qt_text, (char *));
198 static void NDECL(adjust_qt_hdrs);
199 static void NDECL(put_qt_hdrs);
202 static void NDECL(H_close_gen);
203 static void NDECL(H_far_gen);
204 static void NDECL(C_close_gen);
205 static void NDECL(C_far_gen);
206 static int FDECL(clear_path, (int, int, int, int));
209 static char *FDECL(fgetline, (FILE*));
210 static char *FDECL(tmpdup, (const char *));
211 static char *FDECL(limit, (char *, int));
212 static char *FDECL(eos, (char *));
214 /* input, output, tmp */
215 static FILE *ifp, *ofp, *tfp;
217 #if defined(__BORLANDC__) && !defined(_WIN32)
218 extern unsigned _stklen = STKSIZ;
221 #ifdef MACsansMPWTOOL
225 const char *def_options = "odemvpqrshz";
229 printf("Enter options to run: [%s] ", def_options);
231 fgets(buf, 100, stdin);
234 Strcpy(buf, def_options);
236 buf[len - 1] = 0; /* remove return */
238 if (buf[0] == '-' && buf[1] == '-') {
240 split up buf into words
241 do_ext_makedefs(fakeargc, fakeargv);
243 printf("extended makedefs not implemented for Mac OS9\n");
264 && !(argv[1][0] == '-' && argv[1][1] == '-')) {
265 Fprintf(stderr, "Bad arg count (%d).\n", argc - 1);
266 (void) fflush(stderr);
271 if (argc >= 2 && argv[1][0] != '-') {
272 file_prefix = argv[1];
278 if (argv[1][0] == '-' && argv[1][1] == '-') {
279 do_ext_makedefs(argc, argv);
281 do_makedefs(&argv[1][1]);
293 /* Note: these initializers don't do anything except guarantee that
294 we're linked properly.
304 boolean more_than_one;
308 /* construct the current version number */
311 more_than_one = strlen(options) > 1;
314 Fprintf(stderr, "makedefs -%c\n", *options);
352 do_rnd_access_file(EPITAPHFILE);
353 do_rnd_access_file(ENGRAVEFILE);
354 do_rnd_access_file(BOGUSMONFILE);
366 Fprintf(stderr, "Unknown option '%c'.\n", *options);
367 (void) fflush(stderr);
373 Fprintf(stderr, "Completed.\n"); /* feedback */
376 static char namebuf[1000];
378 name_file(template, tag)
382 Sprintf(namebuf, template, tag);
387 delete_file(template, tag)
391 char *name = name_file(template, tag);
396 getfp(template, tag, mode)
401 char *name = name_file(template, tag);
402 FILE *rv = fopen(name, mode);
404 Fprintf(stderr, "Can't open '%s'.\n", name);
410 static boolean debug = FALSE;
412 static FILE *inputfp;
413 static FILE *outputfp;
417 int is_defined; /* 0 undef; 1 defined */
419 /* struct grep_var grep_vars[] and TODO_* constants in include file: */
422 static void NDECL(do_grep);
423 static void NDECL(do_grep_showvars);
424 static struct grep_var *FDECL(grepsearch, (char *));
425 static int grep_trace = 0;
428 do_ext_makedefs(int argc, char **argv)
435 argv++; /* skip program name */
438 if (argv[0][0] != '-')
440 if (argv[0][1] != '-') {
441 Fprintf(stderr, "Can't mix - and -- options.\n");
444 #define IS_OPTION(str) if (!strcmp(&argv[0][2], str))
451 Fprintf(stderr, "missing option\n"); \
452 exit(EXIT_FAILURE); \
456 /* short version string for packaging - note
460 argv++; /* not CONSUME */
463 strcpy(delim, argv[0]);
464 Fprintf(stdout, "%s", version_string(buf, delim));
475 do_makedefs(argv[0]);
481 if (!strcmp(argv[0], "-")) {
484 inputfp = fopen(argv[0], RDTMODE);
486 Fprintf(stderr, "Can't open '%s'.\n", argv[0]);
495 if (!strcmp(argv[0], "-")) {
498 outputfp = fopen(argv[0], WRTMODE);
500 Fprintf(stderr, "Can't open '%s'.\n", argv[0]);
509 Fprintf(stderr, "Can't do grep and something else.\n");
515 IS_OPTION("grep-showvars")
520 IS_OPTION("grep-trace")
525 IS_OPTION("grep-define")
529 p = grepsearch(argv[0]);
533 Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]);
538 IS_OPTION("grep-undef")
542 p = grepsearch(argv[0]);
546 Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]);
557 Fprintf(stderr, "Unknown option '%s'.\n", argv[0]);
561 Fprintf(stderr, "unexpected argument '%s'.\n", argv[0]);
567 Fprintf(stderr, "Confused about what to do?\n");
570 Fprintf(stderr, "Nothing to do?\n");
580 Any line NOT starting with a caret is either suppressed or passed through
581 unchanged depending on the current conditional state.
583 The default conditional state is printing on.
585 Conditionals may be nested.
587 makedefs will exit with a EXIT_FAILURE if any errors are detected; as many
588 errors as possible are detected before giving up.
590 Unknown identifiers are treated as TRUE and also as an error to allow
591 processing to continue past the unknown identifier (note that "#undef" is
592 different than unknown).
594 Any line starting with a caret is a control line; as in C, zero or more
596 may be embedded in the line almost anywhere; the caret MUST be in column 1.
597 (XXX for the moment, no white space is allowed after the caret because
598 existing lines in the docs look like that)
601 ^^ a line starting with a (single) literal caret
602 ^# a comment - the line is ignored
609 #define GREP_MAGIC '^'
610 #define GREP_STACK_SIZE 100
612 static int grep_rewrite = 0; /* need to (possibly) rewrite lines */
614 static int grep_writing = 1; /* need to copy lines to output */
615 static int grep_errors = 0;
616 static int grep_sp = 0;
617 #define ST_LD(old, opp) (!!(old) | (!!(opp) << 1))
618 #define ST_OLD(v) ((v) &1)
619 #define ST_OPP(v) !!((v) &2)
621 static int grep_stack[GREP_STACK_SIZE] = { ST_LD(1, 0) };
622 static int grep_lineno = 0;
628 for (x = 0; x < SIZE(grep_vars) - 1; x++) {
629 printf("%d\t%s\n", grep_vars[x].is_defined, grep_vars[x].name);
633 static struct grep_var *
637 /* XXX make into binary search */
639 while (x < SIZE(grep_vars) - 1) {
640 if (!strcmp(grep_vars[x].name, name))
641 return &grep_vars[x];
652 while (*id && isspace(*id))
655 Fprintf(stderr, "missing identifier in line %d", grep_lineno);
662 Fprintf(outputfp, "ID %d %s\n", rv->is_defined, id);
664 return rv->is_defined;
668 Fprintf(outputfp, "ID U %s\n", id);
670 Fprintf(stderr, "unknown identifier '%s' in line %d.\n", id, grep_lineno);
672 return 2; /* So new features can be checked before makedefs
677 grep_show_wstack(tag)
685 Fprintf(outputfp, "%s w=%d sp=%d\t", tag, grep_writing, grep_sp);
686 for (x = grep_sp; x >= 0 && x > grep_sp - 6; x--) {
687 Fprintf(outputfp, "[%d]=%d ", x, grep_stack[x]);
689 Fprintf(outputfp, "\n");
700 return &buf[-1]; /* XXX see docs above */
702 while (buf[0] && isspace(buf[0]))
706 case '#': /* comment */
708 case '.': /* end of if level */
710 Fprintf(stderr, "unmatched ^. (endif) at line %d.\n",
714 grep_writing = ST_OLD(grep_stack[grep_sp--]);
715 grep_show_wstack("pop");
718 case '!': /* if not ID */
721 case '?': /* if ID */
722 if (grep_sp == GREP_STACK_SIZE - 2) {
723 Fprintf(stderr, "stack overflow at line %d.", grep_lineno);
727 isif = grep_check_id(&buf[1]) ? isif : !isif;
728 grep_stack[++grep_sp] = ST_LD(grep_writing, !isif);
731 grep_stack[++grep_sp] = ST_LD(0, 0);
732 /* grep_writing = 0; */
734 grep_show_wstack("push");
737 if (ST_ELSE & grep_stack[grep_sp]) {
738 Fprintf(stderr, "multiple : for same conditional at line %d.\n",
742 grep_writing = ST_OPP(grep_stack[grep_sp]);
743 grep_stack[grep_sp] |= ST_ELSE;
746 case '(': /* start of expression */
748 case GREP_MAGIC: /* ^^ -> ^ */
752 if (isprint(buf[0])) {
756 sprintf(str, "0x%02x", buf[0]);
758 Fprintf(stderr, "unknown control ^%s at line %d.\n", str,
771 /* no language features use this yet */
776 static void grep0(FILE *, FILE *);
782 Fprintf(stderr, "--grep requires --input\n");
785 Fprintf(stderr, "--grep requires --output\n");
787 if (!inputfp || !outputfp) {
791 grep0(inputfp, outputfp);
795 grep0(inputfp0, outputfp0)
799 char buf[16384]; /* looong, just in case */
801 while (!feof(inputfp0) && !ferror(inputfp0)) {
805 if (fgets(buf, sizeof(buf), inputfp0) == 0)
807 if ((tmp = strchr(buf, '\n')))
811 Fprintf(outputfp0, "%04d %c >%s\n", grep_lineno,
812 grep_writing ? ' ' : '#', buf);
815 if (buf[0] == GREP_MAGIC) {
816 buf1 = do_grep_control(&buf[1]);
824 do_grep_rewrite(buf1);
827 Fprintf(outputfp0, "%s\n", buf1);
829 if (ferror(inputfp0)) {
830 Fprintf(stderr, "read error!\n");
833 if (ferror(outputfp0)) {
834 Fprintf(stderr, "write error!\n");
840 Fprintf(stderr, "%d unterminated conditional level%s\n", grep_sp,
841 grep_sp == 1 ? "" : "s");
845 Fprintf(stderr, "%d error%s detected.\n", grep_errors,
846 grep_errors == 1 ? "" : "s");
851 /* trivial text encryption routine which can't be broken with `tr' */
855 { /* duplicated in src/hacklib.c */
856 static char buf[BUFSZ];
857 register const char *p;
859 register int bitmask;
861 for (bitmask = 1, p = str, q = buf; *p; q++) {
865 if ((bitmask <<= 1) >= 32)
872 #define PAD_RUMORS_TO 60
873 /* common code for do_rumors(). Return 0 on error. */
875 read_rumors_file(file_ext, rumor_count, rumor_size, old_rumor_offset)
876 const char *file_ext;
879 unsigned long old_rumor_offset;
883 unsigned long rumor_offset;
885 Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE);
886 Strcat(infile, file_ext);
887 if (!(ifp = fopen(infile, RDTMODE))) {
892 /* copy the rumors */
893 while ((line = fgetline(ifp)) != 0) {
895 /* rumor selection is accomplished by seeking to a random
896 position in the file, advancing to newline, and taking
897 the next line; therefore, rumors which follow long-line
898 rumors are most likely to be chosen and rumors which
899 follow short-line rumors are least likely to be chosen;
900 we ameliorate the latter by padding the shortest lines,
901 increasing the chance of the random seek landing in them */
902 int len = (int) strlen(line);
904 if (len <= PAD_RUMORS_TO) {
905 char *base = index(line, '\n');
906 /* this is only safe because fgetline() overallocates */
907 while (len++ < PAD_RUMORS_TO) {
916 /*[if we forced binary output, this would be sufficient]*/
917 *rumor_size += strlen(line); /* includes newline */
919 (void) fputs(xcrypt(line), tfp);
922 /* record the current position; next rumors section will start here */
923 rumor_offset = (unsigned long) ftell(tfp);
924 Fclose(ifp); /* all done with rumors.file_ext */
926 /* the calculated value for *_rumor_count assumes that
927 a single-byte line terminator is in use; for platforms
928 which use two byte CR+LF, we need to override that value
929 [it's much simpler to do so unconditionally, rendering
930 the loop's accumulation above obsolete] */
931 *rumor_size = (long) (rumor_offset - old_rumor_offset);
936 do_rnd_access_file(fname)
941 Sprintf(filename, DATA_IN_TEMPLATE, fname);
942 Strcat(filename, ".txt");
943 if (!(ifp = fopen(filename, RDTMODE))) {
949 Strcat(filename, file_prefix);
951 Sprintf(eos(filename), DATA_TEMPLATE, fname);
952 if (!(ofp = fopen(filename, WRTMODE))) {
956 Fprintf(ofp, "%s", Dont_Edit_Data);
958 tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE);
960 ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE);
962 while ((line = fgetline(ifp)) != 0) {
963 if (line[0] != '#' && line[0] != '\n')
964 (void) fputs(xcrypt(line), ofp);
970 delete_file(DATA_TEMPLATE, "grep.tmp");
978 static const char rumors_header[] =
979 "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n";
981 int true_rumor_count, false_rumor_count;
982 long true_rumor_size, false_rumor_size;
983 unsigned long true_rumor_offset, false_rumor_offset, eof_offset;
985 Sprintf(tempfile, DATA_TEMPLATE, "rumors.tmp");
988 Strcat(filename, file_prefix);
990 Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE);
991 if (!(ofp = fopen(filename, WRTMODE))) {
995 if (!(tfp = fopen(tempfile, WRTMODE))) {
1001 true_rumor_count = false_rumor_count = 0;
1002 true_rumor_size = false_rumor_size = 0L;
1003 true_rumor_offset = false_rumor_offset = eof_offset = 0L;
1005 /* output a dummy header record; we'll replace it in final output */
1006 Fprintf(tfp, rumors_header, Dont_Edit_Data, true_rumor_count,
1007 true_rumor_size, true_rumor_offset, false_rumor_count,
1008 false_rumor_size, false_rumor_offset, eof_offset);
1009 /* record the current position; true rumors will start here */
1010 true_rumor_offset = ftell(tfp);
1012 false_rumor_offset = read_rumors_file(
1013 ".tru", &true_rumor_count, &true_rumor_size, true_rumor_offset);
1014 if (!false_rumor_offset)
1015 goto rumors_failure;
1017 eof_offset = read_rumors_file(".fal", &false_rumor_count,
1018 &false_rumor_size, false_rumor_offset);
1020 goto rumors_failure;
1022 /* get ready to transfer the contents of temp file to output file */
1024 Sprintf(line, "rewind of \"%s\"", tempfile);
1025 if (rewind(tfp) != 0) {
1028 goto rumors_failure;
1032 /* output the header record */
1033 Fprintf(ofp, rumors_header, Dont_Edit_Data, true_rumor_count,
1034 true_rumor_size, true_rumor_offset, false_rumor_count,
1035 false_rumor_size, false_rumor_offset, eof_offset);
1036 /* skip the temp file's dummy header */
1037 if (!(line = fgetline(tfp))) { /* "Don't Edit" */
1039 goto rumors_failure;
1042 if (!(line = fgetline(tfp))) { /* count,size,offset */
1044 goto rumors_failure;
1047 /* copy the rest of the temp file into the final output file */
1048 while ((line = fgetline(tfp)) != 0) {
1049 (void) fputs(line, ofp);
1052 /* all done; delete temp file */
1060 Unlink(filename); /* kill empty or incomplete output file */
1062 Unlink(tempfile); /* and temporary file */
1067 * Use this to explicitly mask out features during version checks.
1069 * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features
1070 * that the port/plaform which wrote the savefile was capable of
1071 * dealing with. Don't reject a savefile just because the port
1072 * reading the savefile doesn't match on all/some of them.
1073 * The actual compression features used to produce the savefile are
1074 * recorded in the savefile_info structure immediately following the
1075 * version_info, and that is what needs to be checked against the
1076 * feature set of the port that is reading the savefile back in.
1077 * That check is done in src/restore.c now.
1080 #define IGNORED_FEATURES \
1081 (0L | (1L << 19) /* SCORE_ON_BOTL */ \
1082 | (1L << 27) /* ZEROCOMP */ \
1083 | (1L << 28) /* RLECOMP */ \
1092 * integer version number
1094 version.incarnation = ((unsigned long) VERSION_MAJOR << 24)
1095 | ((unsigned long) VERSION_MINOR << 16)
1096 | ((unsigned long) PATCHLEVEL << 8)
1097 | ((unsigned long) EDITLEVEL);
1099 * encoded feature list
1100 * Note: if any of these magic numbers are changed or reassigned,
1101 * EDITLEVEL in patchlevel.h should be incremented at the same time.
1102 * The actual values have no special meaning, and the category
1103 * groupings are just for convenience.
1105 version.feature_set = (unsigned long) (0L
1106 /* levels and/or topology (0..4) */
1107 /* monsters (5..9) */
1111 /* objects (10..14) */
1112 /* flag bits and/or other global variables (15..26) */
1119 #ifdef SCORE_ON_BOTL
1122 /* data format (27..31)
1123 * External compression methods such as COMPRESS and ZLIB_COMP
1124 * do not affect the contents and are thus excluded from here */
1133 * Value used for object & monster sanity check.
1134 * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
1136 for (i = 1; artifact_names[i]; i++)
1138 version.entity_count = (unsigned long) (i - 1);
1139 for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++)
1141 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
1142 for (i = 0; mons[i].mlet; i++)
1144 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
1146 * Value used for compiler (word size/field alignment/padding) check.
1148 version.struct_sizes1 =
1149 (((unsigned long) sizeof(struct context_info) << 24)
1150 | ((unsigned long) sizeof(struct obj) << 17)
1151 | ((unsigned long) sizeof(struct monst) << 10)
1152 | ((unsigned long) sizeof(struct you)));
1153 version.struct_sizes2 = (((unsigned long) sizeof(struct flag) << 10) |
1154 /* free bits in here */
1156 ((unsigned long) sizeof(struct sysflag)));
1158 ((unsigned long) 0L));
1164 version_string(outbuf, delim)
1168 Sprintf(outbuf, "%d%s%d%s%d", VERSION_MAJOR, delim, VERSION_MINOR, delim,
1171 Sprintf(eos(outbuf), "-%d", EDITLEVEL);
1177 version_id_string(outbuf, build_date)
1179 const char *build_date;
1181 char subbuf[64], versbuf[64];
1186 Strcpy(&subbuf[1], PORT_SUB_ID);
1189 Strcat(subbuf, " Beta");
1192 Sprintf(outbuf, "%s NetHack%s Version %s - last build %s.", PORT_ID,
1193 subbuf, version_string(versbuf, "."), build_date);
1199 jversion_id_string(outbuf, build_date)
1201 const char *build_date;
1203 char subbuf[64], versbuf[64];
1207 Strcat(subbuf, " Beta");
1210 Sprintf(outbuf, "%s JNetHack%s Version %s-%d.%d.", PORT_ID,
1211 subbuf, version_string(versbuf, "."), JVERSION_MAJOR, JVERSION_MINOR);
1217 bannerc_string(outbuf, build_date)
1219 const char *build_date;
1221 char subbuf[64], versbuf[64];
1226 Strcpy(&subbuf[1], PORT_SUB_ID);
1229 Strcat(subbuf, " Beta");
1232 Sprintf(outbuf, " Version %s %s%s, built %s.",
1233 version_string(versbuf, "."), PORT_ID, subbuf, &build_date[4]);
1235 Sprintf(outbuf, "%s NetHack%s %s Copyright 1985-%s (built %s)",
1236 PORT_ID, subbuf, version_string(versbuf,"."), RELEASE_YEAR,
1248 time_t clocktim = 0;
1250 char *c, cbuf[60], buf[BUFSZ];
1253 /* before creating date.h, make sure that xxx_GRAPHICS and
1254 DEFAULT_WINDOW_SYS have been set up in a viable fashion */
1259 Strcat(filename, file_prefix);
1261 Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE);
1262 if (!(ofp = fopen(filename, WRTMODE))) {
1266 /* NB: We've moved on from SCCS, but this way this line
1267 * won't get clobbered when downstream projects import
1268 * this file into something more modern. */
1269 Fprintf(ofp, "%s", Dont_Edit_Code);
1271 (void) time(&clocktim);
1272 Strcpy(cbuf, ctime(&clocktim));
1274 for (c = cbuf; *c; c++)
1277 *c = '\0'; /* strip off the '\n' */
1278 Fprintf(ofp, "#define BUILD_DATE \"%s\"\n", cbuf);
1279 Fprintf(ofp, "#define BUILD_TIME (%ldL)\n", (long) clocktim);
1286 Fprintf(ofp, "#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation,
1288 Fprintf(ofp, "#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set,
1290 #ifdef IGNORED_FEATURES
1291 Fprintf(ofp, "#define IGNORED_FEATURES 0x%08lx%s\n",
1292 (unsigned long) IGNORED_FEATURES, ul_sfx);
1294 Fprintf(ofp, "#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count,
1296 Fprintf(ofp, "#define VERSION_SANITY2 0x%08lx%s\n", version.struct_sizes1,
1298 Fprintf(ofp, "#define VERSION_SANITY3 0x%08lx%s\n", version.struct_sizes2,
1301 Fprintf(ofp, "#define VERSION_STRING \"%s\"\n", version_string(buf, "."));
1302 Fprintf(ofp, "#define VERSION_ID \\\n \"%s\"\n",
1303 version_id_string(buf, cbuf));
1305 Fprintf(ofp,"#define JVERSION_ID \\\n \"%s\"\n",
1306 jversion_id_string(buf, cbuf));
1308 Fprintf(ofp, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n",
1309 bannerc_string(buf, cbuf));
1313 struct tm *tm = localtime((time_t *) &clocktim);
1314 Fprintf(ofp, "#define AMIGA_VERSION_STRING ");
1315 Fprintf(ofp, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
1316 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, tm->tm_mday,
1317 tm->tm_mon + 1, tm->tm_year + 1900);
1324 static char save_bones_compat_buf[BUFSZ];
1327 build_savebones_compat_string()
1329 #ifdef VERSION_COMPATIBILITY
1330 unsigned long uver = VERSION_COMPATIBILITY;
1332 Strcpy(save_bones_compat_buf,
1333 "save and bones files accepted from version");
1334 #ifdef VERSION_COMPATIBILITY
1335 Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d",
1336 ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16),
1337 ((uver & 0x0000FF00L) >> 8), VERSION_MAJOR, VERSION_MINOR,
1340 Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only", VERSION_MAJOR,
1341 VERSION_MINOR, PATCHLEVEL);
1345 static const char *build_opts[] = {
1347 "Amiga WorkBench support",
1350 "ANSI default terminal",
1356 "command line completion",
1359 "Conway's Game of Life",
1362 "data file compression",
1365 "ZLIB data file compression",
1371 "floppy drive support",
1374 "insurance files for recovering from crashes",
1376 #ifdef HOLD_LOCKFILE_OPEN
1377 "exclusive lock on level 0 file",
1386 "MSDOS protected mode",
1403 "restore saved games via menu",
1405 #ifdef SCORE_ON_BOTL
1406 "score on status line",
1413 "screen control via mactty",
1416 "screen control via BIOS",
1418 #ifdef SCREEN_DJGPPFAST
1419 "screen control via DJGPP fast",
1422 "screen control via VGA graphics",
1425 "screen control via WIN32 console I/O",
1435 "terminal info library",
1437 #if defined(TERMLIB) \
1438 || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS))
1439 "terminal capability library",
1443 "timed wait for display effects",
1448 #ifdef PREFIXES_IN_USE
1449 "variable playground",
1451 #ifdef VISION_TABLES
1455 "zero-compressed save files",
1458 "run-length compression of map in save files",
1461 "system configuration at run-time",
1463 save_bones_compat_buf, "and basic NetHack features"
1467 const char *id, /* DEFAULT_WINDOW_SYS string */
1468 *name; /* description, often same as id */
1470 static struct win_info window_opts[] = {
1472 { "tty", "traditional tty-based graphics" },
1480 #ifdef GNOME_GRAPHICS
1481 { "Gnome", "Gnome" },
1486 #ifdef AMIGA_INTUITION
1487 { "amii", "Amiga Intuition" },
1492 #ifdef MSWIN_GRAPHICS
1493 { "mswin", "mswin" },
1495 #ifdef BEOS_GRAPHICS
1496 { "BeOS", "BeOS InterfaceKit" },
1504 #ifndef DEFAULT_WINDOW_SYS
1505 /* pre-standard compilers didn't support #error; wait til run-time */
1507 "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n");
1511 /* put in a dummy value so that do_options() will compile and makedefs
1512 will build, otherwise the message above won't ever get delivered */
1513 #define DEFAULT_WINDOW_SYS "<undefined>"
1514 #else /*DEFAULT_WINDOW_SYS*/
1516 if (!window_opts[0].id) {
1517 Fprintf(stderr, "Configuration error: no windowing systems "
1518 "(TTY_GRAPHICS, &c) enabled.\n");
1525 for (i = 0; window_opts[i].id; ++i)
1526 if (!strcmp(window_opts[i].id, DEFAULT_WINDOW_SYS))
1529 .id) { /* went through whole list without a match */
1530 Fprintf(stderr, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n",
1531 DEFAULT_WINDOW_SYS);
1533 " does not match any enabled windowing system (%s%s).\n",
1534 window_opts[0].id, window_opts[1].id ? ", &c" : "");
1538 #endif /*DEFAULT_WINDOW_SYS*/
1544 static const char indent[] = " ";
1545 const char *str, *sep;
1546 char *word, buf[BUFSZ];
1547 int i, length, winsyscnt;
1553 Strcat(filename, file_prefix);
1555 Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE);
1556 if (!(ofp = fopen(filename, WRTMODE))) {
1561 build_savebones_compat_string();
1564 "\n NetHack version %d.%d.%d [beta]\n",
1566 "\n NetHack version %d.%d.%d\n",
1568 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
1570 Fprintf(ofp, "\nOptions compiled into this edition:\n");
1571 length = COLNO + 1; /* force 1st item onto new line */
1572 for (i = 0; i < SIZE(build_opts); i++) {
1573 str = strcpy(buf, build_opts[i]);
1575 word = index(str, ' ');
1578 if (length + strlen(str) > COLNO - 5)
1579 Fprintf(ofp, "\n%s", indent), length = strlen(indent);
1581 Fprintf(ofp, " "), length++;
1582 Fprintf(ofp, "%s", str), length += strlen(str);
1583 str += strlen(str) + (word ? 1 : 0);
1585 Fprintf(ofp, (i < SIZE(build_opts) - 1) ? "," : "."), length++;
1588 winsyscnt = SIZE(window_opts) - 1;
1589 Fprintf(ofp, "\n\nSupported windowing system%s:\n",
1590 (winsyscnt > 1) ? "s" : "");
1591 length = COLNO + 1; /* force 1st item onto new line */
1592 for (i = 0; i < winsyscnt; i++) {
1593 str = window_opts[i].name;
1594 if (length + strlen(str) > COLNO - 5)
1595 Fprintf(ofp, "\n%s", indent), length = strlen(indent);
1597 Fprintf(ofp, " "), length++;
1598 Fprintf(ofp, "%s", str), length += strlen(str);
1599 sep = (winsyscnt == 1)
1602 ? ((i == 0) ? " and" : "")
1603 : (i < winsyscnt - 2)
1605 : ((i == winsyscnt - 2) ? ", and" : "");
1606 Fprintf(ofp, "%s", sep), length += strlen(sep);
1609 Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS);
1610 Fprintf(ofp, "\n\n");
1616 /* routine to decide whether to discard something from data.base */
1622 return TRUE; /* ignore comment lines */
1628 New format (v3.1) of 'data' file which allows much faster lookups [pr]
1629 "do not edit" first record is a comment line
1630 01234567 hexadecimal formatted offset to text area
1631 name-a first name of interest
1632 123,4 offset to name's text, and number of lines for it
1633 name-b next name of interest
1634 name-c multiple names which share same description also
1635 456,7 share a single offset,count line
1636 . sentinel to mark end of names
1637 789,0 dummy record containing offset, count of EOF
1638 text-a 4 lines of descriptive text for name-a
1639 text-a at file position 0x01234567L + 123L
1642 text-b/text-c 7 lines of text for names-b and -c
1643 text-b/text-c at fseek(0x01234567L + 456L)
1651 char infile[60], tempfile[60];
1654 int entry_cnt, line_cnt;
1657 Sprintf(tempfile, DATA_TEMPLATE, "database.tmp");
1660 Strcat(filename, file_prefix);
1662 Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE);
1663 Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE);
1664 #ifdef SHORT_FILENAMES
1665 Strcat(infile, ".bas");
1667 Strcat(infile, ".base");
1669 if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */
1673 if (!(ofp = fopen(filename, WRTMODE))) { /* data */
1678 if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */
1686 /* output a dummy header record; we'll rewind and overwrite it later */
1687 Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L);
1689 entry_cnt = line_cnt = 0;
1690 /* read through the input file and split it into two sections */
1691 while ((line = fgetline(ifp)) != 0) {
1693 if (d_filter(line)) {
1697 if (*line > ' ') { /* got an entry name */
1700 uc = *((unsigned char *)line);
1701 if (d_filter(line)) continue;
1702 if (uc > ' ') { /* got an entry name */
1704 /* first finish previous entry */
1706 Fprintf(ofp, "%d\n", line_cnt), line_cnt = 0;
1707 /* output the entry name */
1708 (void) fputs(line, ofp);
1709 entry_cnt++; /* update number of entries */
1710 } else if (entry_cnt) { /* got some descriptive text */
1711 /* update previous entry with current text offset */
1713 Fprintf(ofp, "%ld,", ftell(tfp));
1714 /* save the text line in the scratch file */
1715 (void) fputs(line, tfp);
1716 line_cnt++; /* update line counter */
1720 /* output an end marker and then record the current position */
1722 Fprintf(ofp, "%d\n", line_cnt);
1723 Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0);
1724 txt_offset = ftell(ofp);
1725 Fclose(ifp); /* all done with original input file */
1727 /* reprocess the scratch file; 1st format an error msg, just in case */
1729 Sprintf(line, "rewind of \"%s\"", tempfile);
1730 if (rewind(tfp) != 0)
1733 /* copy all lines of text from the scratch file into the output file */
1734 while ((line = fgetline(tfp)) != 0) {
1735 (void) fputs(line, ofp);
1739 /* finished with scratch file */
1741 Unlink(tempfile); /* remove it */
1743 /* update the first record of the output file; prepare error msg 1st */
1745 Sprintf(line, "rewind of \"%s\"", filename);
1746 ok = (rewind(ofp) == 0);
1748 Sprintf(line, "header rewrite of \"%s\"", filename);
1749 ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data,
1750 (unsigned long) txt_offset) >= 0);
1754 perror(line); /* report the problem */
1756 /* close and kill the aborted output file, then give up */
1769 /* routine to decide whether to discard something from oracles.txt */
1774 static boolean skip = FALSE;
1780 return TRUE; /* ignore comment lines */
1782 tag = malloc(strlen(line));
1783 if (sscanf(line, "----- %s", tag) == 1) {
1785 } else if (skip && !strncmp(line, "-----", 5))
1791 static const char *special_oracle[] = {
1793 "\"...it is rather disconcerting to be confronted with the",
1794 "following theorem from [Baker, Gill, and Solovay, 1975].", "",
1795 "Theorem 7.18 There exist recursive languages A and B such that",
1796 " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "",
1797 "This provides impressive evidence that the techniques that are",
1798 "currently available will not suffice for proving that P != NP or "
1800 "that P == NP.\" [Garey and Johnson, p. 185.]"
1802 "
\81u
\8e\9f\82Ì
\92è
\97\9d[Baker, Gill, and Solovay, 1975]
\82É
\92¼
\96Ê
\82·
\82é
\82±
\82Æ
\82Í",
1803 "
\82Þ
\82µ
\82ë
\8d¢
\98f
\82·
\82é
\82±
\82Æ
\82Å
\82 \82é
\81D",
1805 "
\92è
\97\9d 7.18
\8e\9f\82Ì
\82æ
\82¤
\82È
\8dÄ
\8bA
\93I
\8c¾
\8cê A
\81CB
\82ª
\91¶
\8dÝ
\82·
\82é",
1806 " (1) P(A) == NP(A)
\81C
\82©
\82Â",
1807 " (2) P(B) != NP(B)",
1809 "
\82±
\82ê
\82Í
\8c»
\8dÝ P != NP
\82Å
\82 \82é
\82©
\82Ü
\82½
\82Í P == NP
\82Å
\82 \82é
\82©
\82ð
\8fØ
\96¾
\82·
\82é",
1810 "
\97L
\8cø
\82È
\8eè
\96@
\82ª
\82È
\82¢
\82±
\82Æ
\82ð
\8b
\82
\8e¦
\82µ
\82Ä
\82¢
\82é
\81D
\81v",
1811 "[Garey and Johnson, p. 185.]"
1816 The oracle file consists of a "do not edit" comment, a decimal count N
1817 and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
1818 records, separated by "---" lines. The first oracle is a special case.
1819 The input data contains just those multi-line records, separated by
1826 char infile[60], tempfile[60];
1827 boolean in_oracle, ok;
1829 unsigned long txt_offset, offset;
1834 Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp");
1837 Strcat(filename, file_prefix);
1839 Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE);
1840 Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE);
1841 Strcat(infile, ".txt");
1842 if (!(ifp = fopen(infile, RDTMODE))) {
1846 if (!(ofp = fopen(filename, WRTMODE))) {
1851 if (!(tfp = fopen(tempfile, WRTMODE))) { /* oracles.tmp */
1859 /* output a dummy header record; we'll rewind and overwrite it later */
1860 Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0);
1862 /* handle special oracle; it must come first */
1863 (void) fputs("---\n", tfp);
1864 offset = (unsigned long) ftell(tfp);
1865 Fprintf(ofp, "%05lx\n", offset); /* start pos of special oracle */
1866 for (i = 0; i < SIZE(special_oracle); i++) {
1867 (void) fputs(xcrypt(special_oracle[i]), tfp);
1868 (void) fputc('\n', tfp);
1873 (void) fputs("---\n", tfp);
1874 offset = (unsigned long) ftell(tfp);
1875 Fprintf(ofp, "%05lx\n", offset); /* start pos of first oracle */
1878 while ((line = fgetline(ifp)) != 0) {
1881 if (h_filter(line)) {
1885 if (!strncmp(line, "-----", 5)) {
1892 (void) fputs("---\n", tfp);
1893 offset = (unsigned long) ftell(tfp);
1894 Fprintf(ofp, "%05lx\n", offset); /* start pos of this oracle */
1897 (void) fputs(xcrypt(line), tfp);
1902 if (in_oracle) { /* need to terminate last oracle */
1904 (void) fputs("---\n", tfp);
1905 offset = (unsigned long) ftell(tfp);
1906 Fprintf(ofp, "%05lx\n", offset); /* eof position */
1909 /* record the current position */
1910 txt_offset = (unsigned long) ftell(ofp);
1911 Fclose(ifp); /* all done with original input file */
1913 /* reprocess the scratch file; 1st format an error msg, just in case */
1915 Sprintf(line, "rewind of \"%s\"", tempfile);
1916 if (rewind(tfp) != 0)
1919 /* copy all lines of text from the scratch file into the output file */
1920 while ((line = fgetline(tfp)) != 0) {
1921 (void) fputs(line, ofp);
1925 /* finished with scratch file */
1927 Unlink(tempfile); /* remove it */
1929 /* update the first record of the output file; prepare error msg 1st */
1931 Sprintf(line, "rewind of \"%s\"", filename);
1932 ok = (rewind(ofp) == 0);
1934 Sprintf(line, "header rewrite of \"%s\"", filename);
1935 ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >= 0);
1938 Sprintf(line, "data rewrite of \"%s\"", filename);
1939 for (i = 0; i <= oracle_cnt; i++) {
1940 #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */
1941 if (!(ok = (fflush(ofp) == 0)))
1944 if (!(ok = (fpos = ftell(ofp)) >= 0))
1946 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0)))
1948 if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1)))
1953 MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL
1954 (ANSI C Libraries) needs this rewind or else the fprintf
1955 stops working. This may also be true for CW11, but has
1961 if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0)))
1963 offset += txt_offset;
1964 if (!(ok = (fprintf(ofp, "%05lx\n", offset) >= 0)))
1970 perror(line); /* report the problem */
1972 /* close and kill the aborted output file, then give up */
1991 Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE);
1992 if (!(ifp = fopen(filename, RDTMODE))) {
1998 Strcat(filename, file_prefix);
2000 Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE);
2001 if (!(ofp = fopen(filename, WRTMODE))) {
2005 Fprintf(ofp, "%s", Dont_Edit_Data);
2007 tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE);
2009 ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE);
2011 while ((line = fgetline(ifp)) != 0) {
2015 if (line[0] == '#') {
2017 continue; /* discard comments */
2019 (void) fputs(line, ofp);
2025 delete_file(DATA_TEMPLATE, "grep.tmp");
2030 ranged_attk(ptr) /* returns TRUE if monster can attack at range */
2031 register struct permonst *ptr;
2034 register int atk_mask = (1 << AT_BREA) | (1 << AT_SPIT) | (1 << AT_GAZE);
2036 for (i = 0; i < NATTK; i++) {
2037 if ((j = ptr->mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1 << j)))
2044 /* This routine is designed to return an integer value which represents
2045 * an approximation of monster strength. It uses a similar method of
2046 * determination as "experience()" to arrive at the strength.
2050 struct permonst *ptr;
2052 int i, tmp2, n, tmp = ptr->mlevel;
2054 if (tmp > 49) /* special fixed hp monster */
2055 tmp = 2 * (tmp - 6) / 4;
2057 /* For creation in groups */
2058 n = (!!(ptr->geno & G_SGROUP));
2059 n += (!!(ptr->geno & G_LGROUP)) << 1;
2061 /* For ranged attacks */
2062 if (ranged_attk(ptr))
2065 /* For higher ac values */
2069 /* For very fast monsters */
2070 n += (ptr->mmove >= 18);
2072 /* For each attack and "special" attack */
2073 for (i = 0; i < NATTK; i++) {
2074 tmp2 = ptr->mattk[i].aatyp;
2076 n += (tmp2 == AT_MAGC);
2077 n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG));
2080 /* For each "special" damage type */
2081 for (i = 0; i < NATTK; i++) {
2082 tmp2 = ptr->mattk[i].adtyp;
2083 if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST)
2084 || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE))
2086 else if (strcmp(ptr->mname, "grid bug"))
2087 n += (tmp2 != AD_PHYS);
2088 n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23);
2091 /* Leprechauns are special cases. They have many hit dice so they can
2092 hit and are hard to kill, but they don't really do much damage. */
2093 if (!strcmp(ptr->mname, "leprechaun"))
2096 /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */
2104 return (tmp >= 0) ? tmp : 0;
2110 register struct permonst *ptr;
2114 * create the source file, "monstr.c"
2118 Strcat(filename, file_prefix);
2120 Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C);
2121 if (!(ofp = fopen(filename, WRTMODE))) {
2125 Fprintf(ofp, "%s", Dont_Edit_Code);
2126 Fprintf(ofp, "#include \"config.h\"\n");
2127 Fprintf(ofp, "\nconst int monstr[] = {\n");
2128 for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) {
2132 Fprintf(ofp, "%2d,%c", i, (++j & 15) ? ' ' : '\n');
2134 /* might want to insert a final 0 entry here instead of just newline */
2135 Fprintf(ofp, "%s};\n", (j & 15) ? "\n" : "");
2137 Fprintf(ofp, "\nvoid NDECL(monstr_init);\n");
2138 Fprintf(ofp, "\nvoid\n");
2139 Fprintf(ofp, "monstr_init()\n");
2140 Fprintf(ofp, "{\n");
2141 Fprintf(ofp, " return;\n");
2142 Fprintf(ofp, "}\n");
2143 Fprintf(ofp, "\n/*monstr.c*/\n");
2157 Strcat(filename, file_prefix);
2159 Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE);
2160 if (!(ofp = fopen(filename, WRTMODE))) {
2164 Fprintf(ofp, "%s", Dont_Edit_Code);
2165 Fprintf(ofp, "#ifndef PM_H\n#define PM_H\n");
2167 if (strcmp(mons[0].mname, "playermon") != 0)
2168 Fprintf(ofp, "\n#define\tPM_PLAYERMON\t(-1)");
2170 for (i = 0; mons[i].mlet; i++) {
2173 Fprintf(ofp, "\n#define\tPM_");
2174 if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].mname, "were", 4))
2175 Fprintf(ofp, "HUMAN_");
2176 for (nam = c = tmpdup(mons[i].mname); *c; c++)
2177 if (*c >= 'a' && *c <= 'z')
2178 *c -= (char) ('a' - 'A');
2179 else if (*c < 'A' || *c > 'Z')
2181 Fprintf(ofp, "%s\t%d", nam, i);
2183 Fprintf(ofp, "\n\n#define\tNUMMONS\t%d\n", i);
2184 Fprintf(ofp, "\n#endif /* PM_H */\n");
2189 /* Start of Quest text file processing. */
2192 static struct qthdr qt_hdr;
2193 static struct msghdr msg_hdr[N_HDR];
2194 static struct qtmsg *curr_msg;
2198 static boolean in_msg;
2199 #define NO_MSG 1 /* strlen of a null line returned by fgets() */
2207 return (boolean) (!in_msg && strlen(s) == NO_MSG);
2214 return (boolean) (s[0] == '%' && (s[1] == 'C' || s[1] == 'E'));
2223 for (i = 0; i < qt_hdr.n_hdr; i++)
2224 if (!strncmp(code, qt_hdr.id[i], LEN_HDR))
2234 if (qt_hdr.n_hdr >= N_HDR) {
2235 Fprintf(stderr, OUT_OF_HEADERS, qt_line);
2239 strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR);
2240 msg_hdr[qt_hdr.n_hdr].n_msg = 0;
2241 qt_hdr.offset[qt_hdr.n_hdr++] = 0L;
2251 for (i = 0; i < msg_hdr[num].n_msg; i++)
2252 if (msg_hdr[num].qt_msg[i].msgnum == id)
2263 struct qtmsg *qt_msg;
2265 if (msg_hdr[num].n_msg >= N_MSG) {
2266 Fprintf(stderr, OUT_OF_MESSAGES, qt_line);
2268 qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]);
2269 qt_msg->msgnum = id;
2270 qt_msg->delivery = s[2];
2271 qt_msg->offset = qt_msg->size = qt_msg->summary_size = 0L;
2277 /* check %E record for "[summary text]" that nethack can stuff into the
2278 message history buffer when delivering text via window instead of pline */
2280 valid_qt_summary(s, parsing)
2281 char *s; /* end record: "%E" optionally followed by " [summary]" */
2282 boolean parsing; /* curr_msg is valid iff this is True */
2284 static char summary[BUFSZ];
2287 if (*s != '%' || *(s + 1) != 'E')
2289 if ((p = index(s, '[')) == 0)
2291 /* note: opening '[' and closing ']' will be retained in the output;
2292 anything after ']' will be discarded by putting a newline there */
2295 /* have an opening bracket; summary[] holds it and all text that follows
2298 /* find closing bracket */
2299 while (p > summary && *(p - 1) != ']')
2303 /* we backed up all the way to the start without finding a bracket */
2304 if (parsing) /* malformed summary */
2305 Fprintf(stderr, MAL_SUM, qt_line);
2306 } else if (p == summary + 1) {
2307 ; /* ignore empty [] */
2308 } else { /* got something */
2309 /* p points one spot past ']', usually to '\n';
2310 we need to include the \n as part of the size */
2312 /* during the writing pass we won't be able to recheck
2313 delivery, so any useless summary for a pline mode
2314 message has to be carried along to the output file */
2315 if (curr_msg->delivery == 'p')
2316 Fprintf(stderr, DUMB_SUM, qt_line);
2317 /* +1 is for terminating newline */
2318 curr_msg->summary_size = (long) (p - summary) + 1L;
2320 /* caller is writing rather than just parsing;
2321 force newline after the closing bracket */
2336 if (!index(s, '\n'))
2337 Fprintf(stderr, CTRL_TRUNC, qt_line);
2342 Fprintf(stderr, CREC_IN_MSG, qt_line);
2346 if (sscanf(&s[4], "%s %5d", code, &id) != 2) {
2347 Fprintf(stderr, UNREC_CREC, qt_line);
2350 num = get_hdr(code);
2351 if (!num && !new_id(code))
2353 num = get_hdr(code) - 1;
2354 if (known_msg(num, id))
2355 Fprintf(stderr, DUP_MSG, qt_line);
2357 new_msg(s, num, id);
2363 Fprintf(stderr, END_NOT_IN_MSG, qt_line);
2365 /* sets curr_msg->summary_size if applicable */
2366 (void) valid_qt_summary(s, TRUE);
2372 Fprintf(stderr, UNREC_CREC, qt_line);
2382 Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line);
2383 } else if (!index(s, '\n')) {
2384 Fprintf(stderr, TEXT_TRUNC, qt_line);
2387 curr_msg->size += strlen(s);
2395 long count = 0L, hdr_offset = sizeof(int)
2396 + (sizeof(char) * LEN_HDR + sizeof(long))
2399 for (i = 0; i < qt_hdr.n_hdr; i++) {
2400 qt_hdr.offset[i] = hdr_offset;
2401 hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg;
2404 for (i = 0; i < qt_hdr.n_hdr; i++)
2405 for (j = 0; j < msg_hdr[i].n_msg; j++) {
2406 msg_hdr[i].qt_msg[j].offset = hdr_offset + count;
2408 msg_hdr[i].qt_msg[j].size + msg_hdr[i].qt_msg[j].summary_size;
2419 * The main header record.
2422 Fprintf(stderr, "%ld: header info.\n", ftell(ofp));
2423 (void) fwrite((genericptr_t) & (qt_hdr.n_hdr), sizeof(int), 1, ofp);
2424 (void) fwrite((genericptr_t) & (qt_hdr.id[0][0]), sizeof(char) * LEN_HDR,
2426 (void) fwrite((genericptr_t) & (qt_hdr.offset[0]), sizeof(long),
2429 for (i = 0; i < qt_hdr.n_hdr; i++)
2430 Fprintf(stderr, "%s @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]);
2431 Fprintf(stderr, "\n");
2435 * The individual class headers.
2437 for (i = 0; i < qt_hdr.n_hdr; i++) {
2439 Fprintf(stderr, "%ld: %s header info.\n", ftell(ofp),
2441 (void) fwrite((genericptr_t) & (msg_hdr[i].n_msg), sizeof(int), 1,
2443 (void) fwrite((genericptr_t) & (msg_hdr[i].qt_msg[0]),
2444 sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp);
2448 for (j = 0; j < msg_hdr[i].n_msg; j++) {
2449 Fprintf(stderr, "msg %d @ %ld (%ld)",
2450 msg_hdr[i].qt_msg[j].msgnum,
2451 msg_hdr[i].qt_msg[j].offset,
2452 msg_hdr[i].qt_msg[j].size);
2453 if (msg_hdr[i].qt_msg[j].summary_size)
2454 Fprintf(stderr, " [%ld]",
2455 msg_hdr[i].qt_msg[j].summary_size);
2456 Fprintf(stderr, "\n");
2467 Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE);
2468 if (!(ifp = fopen(filename, RDTMODE))) {
2475 Strcat(filename, file_prefix);
2477 Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE);
2478 if (!(ofp = fopen(filename, WRBMODE))) {
2488 while ((line = fgetline(ifp)) != 0) {
2492 if (qt_control(line))
2493 do_qt_control(line);
2494 else if (qt_comment(line)) {
2506 while ((line = fgetline(ifp)) != 0) {
2507 if (qt_control(line)) {
2508 char *summary_p = 0;
2510 in_msg = (line[1] == 'C');
2512 summary_p = valid_qt_summary(line, FALSE);
2513 /* don't write anything unless we've got a summary */
2518 /* we have summary text; replace raw %E record with it */
2519 Strcpy(line, summary_p); /* (guaranteed to fit) */
2520 } else if (qt_comment(line)) {
2525 Fprintf(stderr, "%ld: %s", ftell(stdout), line);
2526 (void) fputs(xcrypt(line), ofp);
2534 static char temp[32];
2536 static char *limit(name, pref) /* limit a name to 30 characters length */
2540 (void) strncpy(temp, name, pref ? 26 : 30);
2541 temp[pref ? 26 : 30] = 0;
2553 boolean sumerr = FALSE;
2557 Strcat(filename, file_prefix);
2559 Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE);
2560 if (!(ofp = fopen(filename, WRTMODE))) {
2564 Fprintf(ofp, "%s", Dont_Edit_Code);
2565 Fprintf(ofp, "#ifndef ONAMES_H\n#define ONAMES_H\n\n");
2567 for (i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) {
2570 objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init */
2571 if (!(objnam = tmpdup(OBJ_NAME(objects[i]))))
2574 /* make sure probabilities add up to 1000 */
2575 if (objects[i].oc_class != class) {
2576 if (sum && sum != 1000) {
2577 Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
2578 (void) fflush(stderr);
2581 class = objects[i].oc_class;
2585 for (c = objnam; *c; c++)
2586 if (*c >= 'a' && *c <= 'z')
2587 *c -= (char) ('a' - 'A');
2588 else if (*c < 'A' || *c > 'Z')
2593 Fprintf(ofp, "#define\tWAN_");
2597 Fprintf(ofp, "#define\tRIN_");
2601 Fprintf(ofp, "#define\tPOT_");
2605 Fprintf(ofp, "#define\tSPE_");
2610 Fprintf(ofp, "#define\tSCR_");
2614 /* avoid trouble with stupid C preprocessors */
2615 Fprintf(ofp, "#define\t");
2616 if (objects[i].oc_material == PLASTIC) {
2617 Fprintf(ofp, "FAKE_AMULET_OF_YENDOR\t%d\n", i);
2623 /* avoid trouble with stupid C preprocessors */
2624 if (objects[i].oc_material == GLASS) {
2625 Fprintf(ofp, "/* #define\t%s\t%d */\n", objnam, i);
2630 Fprintf(ofp, "#define\t");
2633 Fprintf(ofp, "%s\t%d\n", limit(objnam, prefix), i);
2636 sum += objects[i].oc_prob;
2639 /* check last set of probabilities */
2640 if (sum && sum != 1000) {
2641 Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
2642 (void) fflush(stderr);
2646 Fprintf(ofp, "#define\tLAST_GEM\t(JADE)\n");
2647 Fprintf(ofp, "#define\tMAXSPELL\t%d\n", nspell + 1);
2648 Fprintf(ofp, "#define\tNUM_OBJECTS\t%d\n", i);
2650 Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n");
2652 for (i = 1; artifact_names[i]; i++) {
2655 for (c = objnam = tmpdup(artifact_names[i]); *c; c++)
2656 if (*c >= 'a' && *c <= 'z')
2657 *c -= (char) ('a' - 'A');
2658 else if (*c < 'A' || *c > 'Z')
2661 if (!strncmp(objnam, "THE_", 4))
2663 /* fudge _platinum_ YENDORIAN EXPRESS CARD */
2664 if (!strncmp(objnam, "PLATINUM_", 9))
2666 Fprintf(ofp, "#define\tART_%s\t%d\n", limit(objnam, 1), i);
2669 Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i - 1);
2670 Fprintf(ofp, "\n#endif /* ONAMES_H */\n");
2677 /* Read one line from input, up to and including the next newline
2678 * character. Returns a pointer to the heap-allocated string, or a
2679 * null pointer if no characters were read.
2685 static const int inc = 256;
2687 char *c = malloc(len), *ret;
2690 ret = fgets(c + len - inc, inc, fd);
2695 } else if (index(c, '\n')) {
2696 /* normal case: we have a full line */
2700 c = realloc(c, len);
2709 static char buf[128];
2713 (void) strncpy(buf, str, 127);
2727 * macro used to control vision algorithms:
2728 * VISION_TABLES => generate tables
2734 #ifdef VISION_TABLES
2737 /* Everything is clear. xclear may be malloc'ed.
2738 * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
2740 for (i = 0; i < MAX_ROW; i++)
2741 for (j = 0; j < MAX_COL; j++)
2742 if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH)
2743 xclear[i][j] = '\000';
2745 xclear[i][j] = '\001';
2746 #endif /* VISION_TABLES */
2751 * create the include file, "vis_tab.h"
2755 Strcat(filename, file_prefix);
2757 Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
2758 if (!(ofp = fopen(filename, WRTMODE))) {
2762 Fprintf(ofp, "%s", Dont_Edit_Code);
2763 Fprintf(ofp, "#ifdef VISION_TABLES\n");
2764 #ifdef VISION_TABLES
2767 #endif /* VISION_TABLES */
2768 Fprintf(ofp, "\n#endif /* VISION_TABLES */\n");
2774 * create the source file, "vis_tab.c"
2778 Strcat(filename, file_prefix);
2780 Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C);
2781 if (!(ofp = fopen(filename, WRTMODE))) {
2783 Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
2787 Fprintf(ofp, "%s", Dont_Edit_Code);
2788 Fprintf(ofp, "#include \"config.h\"\n");
2789 Fprintf(ofp, "#ifdef VISION_TABLES\n");
2790 Fprintf(ofp, "#include \"vis_tab.h\"\n");
2794 #ifdef VISION_TABLES
2797 Fprintf(ofp, "\nvoid vis_tab_init() { return; }\n");
2798 #endif /* VISION_TABLES */
2802 Fprintf(ofp, "\n#endif /* VISION_TABLES */\n");
2803 Fprintf(ofp, "\n/*vis_tab.c*/\n");
2809 #ifdef VISION_TABLES
2811 /*-------------- vision tables --------------*\
2813 * Generate the close and far tables. This is done by setting up a
2814 * fake dungeon and moving our source to different positions relative
2815 * to a block and finding the first/last visible position. The fake
2816 * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
2817 * by BLOCK_WIDTH) is blocked. Then we move the source around relative
2818 * to the corner of the block. For each new position of the source
2819 * we check positions on rows "kittycorner" from the source. We check
2820 * positions until they are either in sight or out of sight (depends on
2821 * which table we are generating). The picture below shows the setup
2822 * for the generation of the close table. The generation of the far
2823 * table would switch the quadrants of the '@' and the "Check rows
2827 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2828 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2829 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
2830 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2831 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
2832 * ...............................
2833 * ...............................
2834 * .........@.....................
2835 * ...............................
2837 * Table generation figure (close_table). The 'X's are blocked points.
2838 * The 'B' is a special blocked point. The '@' is the source. The ','s
2839 * are the target area. The '.' are just open areas.
2842 * Example usage of close_table[][][].
2844 * The table is as follows:
2846 * dy = |row of '@' - row of 'B'| - 1
2847 * dx = |col of '@' - col of 'B'|
2849 * The first indices are the deltas from the source '@' and the block 'B'.
2850 * You must check for the value inside the abs value bars being zero. If
2851 * so then the block is on the same row and you don't need to do a table
2852 * lookup. The last value:
2854 * dcy = |row of block - row to be checked|
2856 * Is the value of the first visible spot on the check row from the
2859 * first visible col = close_table[dy][dx][dcy] + col of 'B'
2861 \*-------------- vision tables --------------*/
2866 Fprintf(ofp, "\n/* Close */\n");
2868 "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
2871 "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
2874 "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
2876 Fprintf(ofp, "typedef struct {\n");
2878 " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
2879 Fprintf(ofp, "} close2d;\n");
2880 Fprintf(ofp, "extern close2d close_table[CLOSE_MAX_SB_DY];\n");
2887 Fprintf(ofp, "\n/* Far */\n");
2888 Fprintf(ofp, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
2891 "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
2894 "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
2896 Fprintf(ofp, "typedef struct {\n");
2897 Fprintf(ofp, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
2898 Fprintf(ofp, "} far2d;\n");
2899 Fprintf(ofp, "extern far2d far_table[FAR_MAX_SB_DY];\n");
2907 int src_row, src_col; /* source */
2908 int block_row, block_col; /* block */
2913 block_row = BLOCK_HEIGHT - 1;
2914 block_col = BLOCK_WIDTH - 1;
2916 Fprintf(ofp, "\n#ifndef FAR_TABLE_ONLY\n");
2917 Fprintf(ofp, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
2918 #ifndef no_vision_progress
2919 Fprintf(stderr, "\nclose:");
2922 for (dy = 1; dy < TEST_HEIGHT; dy++) {
2923 src_row = block_row + dy;
2924 Fprintf(ofp, "/* DY = %2d (- 1)*/\n {{\n", dy);
2925 #ifndef no_vision_progress
2926 Fprintf(stderr, " %2d", dy), (void) fflush(stderr);
2928 for (dx = 0; dx < TEST_WIDTH; dx++) {
2929 src_col = block_col - dx;
2930 Fprintf(ofp, " /*%2d*/ {", dx);
2933 for (this_row = 0; this_row < TEST_HEIGHT; this_row++) {
2934 delim = (this_row < TEST_HEIGHT - 1) ? "," : "";
2936 Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim);
2941 /* Find the first column that we can see. */
2942 for (i = block_col + 1; i < MAX_COL; i++) {
2943 if (clear_path(src_row, src_col, block_row - this_row, i))
2949 Fprintf(ofp, "%2d%s", i - block_col, delim);
2951 Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
2953 Fprintf(ofp, " }},\n");
2956 Fprintf(ofp, "}; /* close_table[] */\n"); /* closing brace for table */
2957 Fprintf(ofp, "#endif /* !FAR_TABLE_ONLY */\n");
2958 #ifndef no_vision_progress
2959 Fprintf(stderr, "\n");
2968 int src_row, src_col; /* source */
2969 int block_row, block_col; /* block */
2973 block_row = BLOCK_HEIGHT - 1;
2974 block_col = BLOCK_WIDTH - 1;
2976 Fprintf(ofp, "\n#ifndef CLOSE_TABLE_ONLY\n");
2977 Fprintf(ofp, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
2978 #ifndef no_vision_progress
2979 Fprintf(stderr, "\n_far_:");
2982 for (dy = 0; dy < TEST_HEIGHT; dy++) {
2983 src_row = block_row - dy;
2984 Fprintf(ofp, "/* DY = %2d */\n {{\n", dy);
2985 #ifndef no_vision_progress
2986 Fprintf(stderr, " %2d", dy), (void) fflush(stderr);
2988 for (dx = 1; dx < TEST_WIDTH; dx++) {
2989 src_col = block_col + dx;
2990 Fprintf(ofp, " /*%2d(-1)*/ {", dx);
2992 for (this_row = block_row + 1; this_row < block_row + TEST_HEIGHT;
2994 delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : "";
2997 /* Find first col that we can see. */
2998 for (i = 0; i <= block_col; i++) {
2999 if (clear_path(src_row, src_col, this_row, i))
3003 if (block_col - i < 0)
3004 Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim);
3006 Fprintf(ofp, "%2d%s", block_col - i, delim);
3008 Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n");
3010 Fprintf(ofp, " }},\n");
3013 Fprintf(ofp, "}; /* far_table[] */\n"); /* closing brace for table */
3014 Fprintf(ofp, "#endif /* !CLOSE_TABLE_ONLY */\n");
3015 #ifndef no_vision_progress
3016 Fprintf(stderr, "\n");
3022 * "Draw" a line from the hero to the given location. Stop if we hit a
3025 * Generalized integer Bresenham's algorithm (fast line drawing) for
3026 * all quadrants. From _Procedural Elements for Computer Graphics_, by
3027 * David F. Rogers. McGraw-Hill, 1985.
3029 * I have tried a little bit of optimization by pulling compares out of
3032 * NOTE: This had better *not* be called from a position on the
3033 * same row as the hero.
3036 clear_path(you_row, you_col, y2, x2)
3037 int you_row, you_col, y2, x2;
3040 register int i, error, x, y, dxs, dys;
3044 dx = abs(x2 - you_col);
3045 dy = abs(y2 - you_row);
3046 s1 = sign(x2 - you_col);
3047 s2 = sign(y2 - you_row);
3049 if (s1 == 0) { /* same column */
3050 if (s2 == 1) { /* below (larger y2 value) */
3051 for (i = you_row + 1; i < y2; i++)
3052 if (!xclear[i][you_col])
3054 } else { /* above (smaller y2 value) */
3055 for (i = y2 + 1; i < you_row; i++)
3056 if (!xclear[i][you_col])
3063 * Lines at 0 and 90 degrees have been weeded out.
3068 dy = error; /* swap the values */
3069 dxs = dx << 1; /* save the shifted values */
3071 error = dys - dx; /* NOTE: error is used as a temporary above */
3073 for (i = 0; i < dx; i++) {
3075 return 0; /* plot point */
3077 while (error >= 0) {
3085 dxs = dx << 1; /* save the shifted values */
3089 for (i = 0; i < dx; i++) {
3091 return 0; /* plot point */
3093 while (error >= 0) {
3103 #endif /* VISION_TABLES */
3105 #ifdef STRICT_REF_DEF
3106 NEARDATA struct flag flags;
3108 struct attribs attrmax, attrmin;
3110 #endif /* STRICT_REF_DEF */