/* SCCS Id: @(#)makedefs.c 3.4 2002/08/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) M. Stephenson, 1990, 1991. */ /* Copyright (c) Dean Luick, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #define MAKEDEFS_C /* use to conditionally include file sections */ /* #define DEBUG */ /* uncomment for debugging info */ #include "config.h" #include "permonst.h" #include "objclass.h" #include "monsym.h" #include "artilist.h" #include "dungeon.h" #include "obj.h" #include "monst.h" #include "you.h" #include "flag.h" #include "dlb.h" /* version information */ #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif #ifdef MAC # if defined(__SC__) || defined(__MRC__) /* MPW compilers */ # define MPWTOOL #include #include #include # else /* MAC without MPWTOOL */ # define MACsansMPWTOOL # endif #endif /* MAC */ #ifndef MPWTOOL # define SpinCursor(x) #endif #define Fprintf (void) fprintf #define Fclose (void) fclose #define Unlink (void) unlink #if !defined(AMIGA) || defined(AZTEC_C) #define rewind(fp) fseek((fp),0L,SEEK_SET) /* guarantee a return value */ #endif #if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN) static const char SCCS_Id[] = "@(#)makedefs.c\t3.4\t2002/02/03"; #endif /* names of files to be generated */ #define DATE_FILE "date.h" #define MONST_FILE "pm.h" #define ONAME_FILE "onames.h" #ifndef OPTIONS_FILE #define OPTIONS_FILE "options" #endif #define ORACLE_FILE "oracles" #define DATA_FILE "data" #define RUMOR_FILE "rumors" #define DGN_I_FILE "dungeon.def" #define DGN_O_FILE "dungeon.pdf" #define MON_STR_C "monstr.c" #define QTXT_I_FILE "quest.txt" #define QTXT_O_FILE "quest.dat" #define VIS_TAB_H "vis_tab.h" #define VIS_TAB_C "vis_tab.c" /* locations for those files */ #ifdef AMIGA # define FILE_PREFIX # define INCLUDE_TEMPLATE "NH:include/t.%s" # define SOURCE_TEMPLATE "NH:src/%s" # define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */ # define DATA_TEMPLATE "NH:slib/%s" # define DATA_IN_TEMPLATE "NH:dat/%s" #else /* not AMIGA */ # if defined(MAC) && !defined(__MACH__) /* MacOS 9 or earlier */ # define INCLUDE_TEMPLATE ":include:%s" # define SOURCE_TEMPLATE ":src:%s" # define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */ # if __SC__ || __MRC__ # define DATA_TEMPLATE ":Dungeon:%s" # else # define DATA_TEMPLATE ":lib:%s" # endif /* __SC__ || __MRC__ */ # define DATA_IN_TEMPLATE ":dat:%s" # else /* neither AMIGA nor MAC */ # ifdef OS2 # define INCLUDE_TEMPLATE "..\\include\\%s" # define SOURCE_TEMPLATE "..\\src\\%s" # define DGN_TEMPLATE "..\\dat\\%s" /* where dungeon.pdf file goes */ # define DATA_TEMPLATE "..\\dat\\%s" # define DATA_IN_TEMPLATE "..\\dat\\%s" # else /* not AMIGA, MAC, or OS2 */ # define INCLUDE_TEMPLATE "../include/%s" # define SOURCE_TEMPLATE "../src/%s" # define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */ # define DATA_TEMPLATE "../dat/%s" # define DATA_IN_TEMPLATE "../dat/%s" # endif /* else !OS2 */ # endif /* else !MAC */ #endif /* else !AMIGA */ static const char *Dont_Edit_Code = "/* This source file is generated by 'makedefs'. Do not edit. */\n", *Dont_Edit_Data = "#\tThis data file is generated by 'makedefs'. Do not edit. \n"; static struct version_info version; /* definitions used for vision tables */ #define TEST_WIDTH COLNO #define TEST_HEIGHT ROWNO #define BLOCK_WIDTH (TEST_WIDTH + 10) #define BLOCK_HEIGHT TEST_HEIGHT /* don't need extra spaces */ #define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT) #define MAX_COL (BLOCK_WIDTH + TEST_WIDTH) /* Use this as an out-of-bound value in the close table. */ #define CLOSE_OFF_TABLE_STRING "99" /* for the close table */ #define FAR_OFF_TABLE_STRING "0xff" /* for the far table */ #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0)) #ifdef VISION_TABLES static char xclear[MAX_ROW][MAX_COL]; #endif /*-end of vision defs-*/ static char in_line[256], filename[60]; #ifdef FILE_PREFIX /* if defined, a first argument not starting with - is * taken as a text string to be prepended to any * output filename generated */ char *file_prefix=""; #endif #ifdef MACsansMPWTOOL int FDECL(main, (void)); #else int FDECL(main, (int,char **)); #endif void FDECL(do_makedefs, (char *)); void NDECL(do_objs); void NDECL(do_data); void NDECL(do_dungeon); void NDECL(do_date); void NDECL(do_options); void NDECL(do_monstr); void NDECL(do_permonst); void NDECL(do_questtxt); void NDECL(do_rumors); void NDECL(do_oracles); void NDECL(do_vision); extern void NDECL(monst_init); /* monst.c */ extern void NDECL(objects_init); /* objects.c */ static void NDECL(make_version); static char *FDECL(version_string, (char *)); static char *FDECL(version_id_string, (char *,const char *)); static char *FDECL(xcrypt, (const char *)); static int FDECL(check_control, (char *)); static char *FDECL(without_control, (char *)); static boolean FDECL(d_filter, (char *)); static boolean FDECL(h_filter, (char *)); static boolean FDECL(ranged_attk,(struct permonst*)); static int FDECL(mstrength,(struct permonst *)); static void NDECL(build_savebones_compat_string); static boolean FDECL(qt_comment, (char *)); static boolean FDECL(qt_control, (char *)); static int FDECL(get_hdr, (char *)); static boolean FDECL(new_id, (char *)); static boolean FDECL(known_msg, (int,int)); static void FDECL(new_msg, (char *,int,int)); static void FDECL(do_qt_control, (char *)); static void FDECL(do_qt_text, (char *)); static void NDECL(adjust_qt_hdrs); static void NDECL(put_qt_hdrs); #ifdef VISION_TABLES static void NDECL(H_close_gen); static void NDECL(H_far_gen); static void NDECL(C_close_gen); static void NDECL(C_far_gen); static int FDECL(clear_path, (int,int,int,int)); #endif static char *FDECL(tmpdup, (const char *)); static char *FDECL(limit, (char *,int)); static char *FDECL(eos, (char *)); /* input, output, tmp */ static FILE *ifp, *ofp, *tfp; #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif #ifdef MACsansMPWTOOL int main(void) { const char *def_options = "odemvpqrhz"; char buf[100]; int len; printf("Enter options to run: [%s] ", def_options); fflush(stdout); fgets(buf, 100, stdin); len = strlen(buf); if (len <= 1) Strcpy(buf, def_options); else buf[len-1] = 0; /* remove return */ do_makedefs(buf); exit(EXIT_SUCCESS); return 0; } #else /* ! MAC */ int main(argc, argv) int argc; char *argv[]; { if ( (argc != 2) #ifdef FILE_PREFIX && (argc != 3) #endif ) { Fprintf(stderr, "Bad arg count (%d).\n", argc-1); (void) fflush(stderr); return 1; } #ifdef FILE_PREFIX if(argc >=2 && argv[1][0]!='-'){ file_prefix=argv[1]; argc--;argv++; } #endif do_makedefs(&argv[1][1]); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif void do_makedefs(options) char *options; { boolean more_than_one; /* Note: these initializers don't do anything except guarantee that we're linked properly. */ monst_init(); objects_init(); /* construct the current version number */ make_version(); more_than_one = strlen(options) > 1; while (*options) { if (more_than_one) Fprintf(stderr, "makedefs -%c\n", *options); switch (*options) { case 'o': case 'O': do_objs(); break; case 'd': case 'D': do_data(); break; case 'e': case 'E': do_dungeon(); break; case 'm': case 'M': do_monstr(); break; case 'v': case 'V': do_date(); do_options(); break; case 'p': case 'P': do_permonst(); break; case 'q': case 'Q': do_questtxt(); break; case 'r': case 'R': do_rumors(); break; case 'h': case 'H': do_oracles(); break; case 'z': case 'Z': do_vision(); break; default: Fprintf(stderr, "Unknown option '%c'.\n", *options); (void) fflush(stderr); exit(EXIT_FAILURE); } options++; } if (more_than_one) Fprintf(stderr, "Completed.\n"); /* feedback */ } /* trivial text encryption routine which can't be broken with `tr' */ static char *xcrypt(str) const char *str; { /* duplicated in src/hacklib.c */ static char buf[BUFSZ]; register const char *p; register char *q; register int bitmask; for (bitmask = 1, p = str, q = buf; *p; q++) { *q = *p++; if (*q & (32|64)) *q ^= bitmask; if ((bitmask <<= 1) >= 32) bitmask = 1; } *q = '\0'; return buf; } void do_rumors() { char infile[60]; long true_rumor_size; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename,file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Data); Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE); Strcat(infile, ".tru"); if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); Fclose(ofp); Unlink(filename); /* kill empty output file */ exit(EXIT_FAILURE); } /* get size of true rumors file */ #ifndef VMS (void) fseek(ifp, 0L, SEEK_END); true_rumor_size = ftell(ifp); #else /* seek+tell is only valid for stream format files; since rumors.%%% might be in record format, count the actual data bytes instead. */ true_rumor_size = 0; while (fgets(in_line, sizeof in_line, ifp) != 0) true_rumor_size += strlen(in_line); /* includes newline */ #endif /* VMS */ Fprintf(ofp,"%06lx\n", true_rumor_size); (void) fseek(ifp, 0L, SEEK_SET); /* copy true rumors */ while (fgets(in_line, sizeof in_line, ifp) != 0) (void) fputs(xcrypt(in_line), ofp); Fclose(ifp); Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE); Strcat(infile, ".fal"); if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); Fclose(ofp); Unlink(filename); /* kill incomplete output file */ exit(EXIT_FAILURE); } /* copy false rumors */ while (fgets(in_line, sizeof in_line, ifp) != 0) (void) fputs(xcrypt(in_line), ofp); Fclose(ifp); Fclose(ofp); return; } /* * Use this to explicitly mask out features during version checks. */ #define IGNORED_FEATURES ( 0L \ | (1L << 12) /* GOLDOBJ */ \ ) static void make_version() { register int i; /* * integer version number */ version.incarnation = ((unsigned long)VERSION_MAJOR << 24) | ((unsigned long)VERSION_MINOR << 16) | ((unsigned long)PATCHLEVEL << 8) | ((unsigned long)EDITLEVEL); /* * encoded feature list * Note: if any of these magic numbers are changed or reassigned, * EDITLEVEL in patchlevel.h should be incremented at the same time. * The actual values have no special meaning, and the category * groupings are just for convenience. */ version.feature_set = (unsigned long)(0L /* levels and/or topology (0..4) */ #ifdef REINCARNATION | (1L << 1) #endif #ifdef SINKS | (1L << 2) #endif /* monsters (5..9) */ #ifdef KOPS | (1L << 6) #endif #ifdef MAIL | (1L << 7) #endif /* objects (10..14) */ #ifdef TOURIST | (1L << 10) #endif #ifdef STEED | (1L << 11) #endif #ifdef GOLDOBJ | (1L << 12) #endif /* flag bits and/or other global variables (15..26) */ #ifdef TEXTCOLOR | (1L << 17) #endif #ifdef INSURANCE | (1L << 18) #endif #ifdef ELBERETH | (1L << 19) #endif #ifdef EXP_ON_BOTL | (1L << 20) #endif #ifdef SCORE_ON_BOTL | (1L << 21) #endif /* data format [COMPRESS excluded] (27..31) */ #ifdef ZEROCOMP | (1L << 27) #endif #ifdef RLECOMP | (1L << 28) #endif ); /* * Value used for object & monster sanity check. * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0) */ for (i = 1; artifact_names[i]; i++) continue; version.entity_count = (unsigned long)(i - 1); for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++) continue; version.entity_count = (version.entity_count << 12) | (unsigned long)i; for (i = 0; mons[i].mlet; i++) continue; version.entity_count = (version.entity_count << 12) | (unsigned long)i; /* * Value used for compiler (word size/field alignment/padding) check. */ version.struct_sizes = (((unsigned long)sizeof (struct flag) << 24) | ((unsigned long)sizeof (struct obj) << 17) | ((unsigned long)sizeof (struct monst) << 10) | ((unsigned long)sizeof (struct you))); return; } static char * version_string(outbuf) char *outbuf; { Sprintf(outbuf, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); #ifdef BETA Sprintf(eos(outbuf), "-%d", EDITLEVEL); #endif return outbuf; } static char * version_id_string(outbuf, build_date) char *outbuf; const char *build_date; { char subbuf[64], versbuf[64]; subbuf[0] = '\0'; #ifdef PORT_SUB_ID subbuf[0] = ' '; Strcpy(&subbuf[1], PORT_SUB_ID); #endif #ifdef BETA Strcat(subbuf, " Beta"); #endif Sprintf(outbuf, "%s NetHack%s Version %s - last build %s.", PORT_ID, subbuf, version_string(versbuf), build_date); return outbuf; } void do_date() { long clocktim = 0; char *c, cbuf[60], buf[BUFSZ]; const char *ul_sfx; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename,file_prefix); #endif Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,"/*\tSCCS Id: @(#)date.h\t3.4\t2002/02/03 */\n\n"); Fprintf(ofp,Dont_Edit_Code); #ifdef KR1ED (void) time(&clocktim); Strcpy(cbuf, ctime(&clocktim)); #else (void) time((time_t *)&clocktim); Strcpy(cbuf, ctime((time_t *)&clocktim)); #endif for (c = cbuf; *c; c++) if (*c == '\n') break; *c = '\0'; /* strip off the '\n' */ Fprintf(ofp,"#define BUILD_DATE \"%s\"\n", cbuf); Fprintf(ofp,"#define BUILD_TIME (%ldL)\n", clocktim); Fprintf(ofp,"\n"); #ifdef NHSTDC ul_sfx = "UL"; #else ul_sfx = "L"; #endif Fprintf(ofp,"#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation, ul_sfx); Fprintf(ofp,"#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set, ul_sfx); #ifdef IGNORED_FEATURES Fprintf(ofp,"#define IGNORED_FEATURES 0x%08lx%s\n", (unsigned long) IGNORED_FEATURES, ul_sfx); #endif Fprintf(ofp,"#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count, ul_sfx); Fprintf(ofp,"#define VERSION_SANITY2 0x%08lx%s\n", version.struct_sizes, ul_sfx); Fprintf(ofp,"\n"); Fprintf(ofp,"#define VERSION_STRING \"%s\"\n", version_string(buf)); Fprintf(ofp,"#define VERSION_ID \\\n \"%s\"\n", version_id_string(buf, cbuf)); Fprintf(ofp,"\n"); #ifdef AMIGA { struct tm *tm = localtime((time_t *) &clocktim); Fprintf(ofp,"#define AMIGA_VERSION_STRING "); Fprintf(ofp,"\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900); } #endif Fclose(ofp); return; } static char save_bones_compat_buf[BUFSZ]; static void build_savebones_compat_string() { #ifdef VERSION_COMPATIBILITY unsigned long uver = VERSION_COMPATIBILITY; #endif Strcpy(save_bones_compat_buf, "save and bones files accepted from version"); #ifdef VERSION_COMPATIBILITY Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d", ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16), ((uver & 0x0000FF00L) >> 8), VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); #else Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); #endif } static const char *build_opts[] = { #ifdef AMIGA_WBENCH "Amiga WorkBench support", #endif #ifdef ANSI_DEFAULT "ANSI default terminal", #endif #ifdef TEXTCOLOR "color", #endif #ifdef COM_COMPL "command line completion", #endif #ifdef COMPRESS "data file compression", #endif #ifdef DLB "data librarian", #endif #ifdef WIZARD "debug mode", #endif #ifdef ELBERETH "Elbereth", #endif #ifdef EXP_ON_BOTL "experience points on status line", #endif #ifdef MFLOPPY "floppy drive support", #endif #ifdef GOLDOBJ "gold object in inventories", #endif #ifdef INSURANCE "insurance files for recovering from crashes", #endif #ifdef KOPS "Keystone Kops", #endif #ifdef HOLD_LOCKFILE_OPEN "exclusive lock on level 0 file", #endif #ifdef LOGFILE "log file", #endif #ifdef MAIL "mail daemon", #endif #ifdef GNUDOS "MSDOS protected mode", #endif #ifdef NEWS "news file", #endif #ifdef OVERLAY # ifdef MOVERLAY "MOVE overlays", # else # ifdef VROOMM "VROOMM overlays", # else "overlays", # endif # endif #endif #ifdef REDO "redo command", #endif #ifdef REINCARNATION "rogue level", #endif #ifdef STEED "saddles and riding", #endif #ifdef SCORE_ON_BOTL "score on status line", #endif #ifdef CLIPPING "screen clipping", #endif #ifdef NO_TERMS # ifdef MAC "screen control via mactty", # endif # ifdef SCREEN_BIOS "screen control via BIOS", # endif # ifdef SCREEN_DJGPPFAST "screen control via DJGPP fast", # endif # ifdef SCREEN_VGA "screen control via VGA graphics", # endif # ifndef MSWIN_GRAPHICS # ifdef WIN32CON "screen control via WIN32 console I/O", # endif # endif #endif #ifdef SEDUCE "seduction", #endif #ifdef SHELL "shell command", #endif #ifdef SINKS "sinks", #endif #ifdef SUSPEND "suspend command", #endif #ifdef TERMINFO "terminal info library", #else # if defined(TERMLIB) || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS)) "terminal capability library", # endif #endif #ifdef TIMED_DELAY "timed wait for display effects", #endif #ifdef TOURIST "tourists", #endif #ifdef USER_SOUNDS # ifdef USER_SOUNDS_REGEX "user sounds via regular expressions", # else "user sounds via pmatch", # endif #endif #ifdef PREFIXES_IN_USE "variable playground", #endif #ifdef VISION_TABLES "vision tables", #endif #ifdef WALLIFIED_MAZE "walled mazes", #endif #ifdef ZEROCOMP "zero-compressed save files", #endif save_bones_compat_buf, "basic NetHack features" }; static const char *window_opts[] = { #ifdef TTY_GRAPHICS "traditional tty-based graphics", #endif #ifdef X11_GRAPHICS "X11", #endif #ifdef QT_GRAPHICS "Qt", #endif #ifdef GNOME_GRAPHICS "Gnome", #endif #ifdef MAC "Mac", #endif #ifdef AMIGA_INTUITION "Amiga Intuition", #endif #ifdef GEM_GRAPHICS "Gem", #endif #ifdef MSWIN_GRAPHICS "mswin", #endif #ifdef BEOS_GRAPHICS "BeOS InterfaceKit", #endif 0 }; void do_options() { register int i, length; register const char *str, *indent = " "; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename,file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } build_savebones_compat_string(); Fprintf(ofp, #ifdef BETA "\n NetHack version %d.%d.%d [beta]\n", #else "\n NetHack version %d.%d.%d\n", #endif VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); Fprintf(ofp,"\nOptions compiled into this edition:\n"); length = COLNO + 1; /* force 1st item onto new line */ for (i = 0; i < SIZE(build_opts); i++) { str = build_opts[i]; if (length + strlen(str) > COLNO - 5) Fprintf(ofp,"\n%s", indent), length = strlen(indent); else Fprintf(ofp," "), length++; Fprintf(ofp,"%s", str), length += strlen(str); Fprintf(ofp,(i < SIZE(build_opts) - 1) ? "," : "."), length++; } Fprintf(ofp,"\n\nSupported windowing systems:\n"); length = COLNO + 1; /* force 1st item onto new line */ for (i = 0; i < SIZE(window_opts) - 1; i++) { str = window_opts[i]; if (length + strlen(str) > COLNO - 5) Fprintf(ofp,"\n%s", indent), length = strlen(indent); else Fprintf(ofp," "), length++; Fprintf(ofp,"%s", str), length += strlen(str); Fprintf(ofp, ","), length++; } Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS); Fprintf(ofp,"\n\n"); Fclose(ofp); return; } /* routine to decide whether to discard something from data.base */ static boolean d_filter(line) char *line; { if (*line == '#') return TRUE; /* ignore comment lines */ return FALSE; } /* * New format (v3.1) of 'data' file which allows much faster lookups [pr] "do not edit" first record is a comment line 01234567 hexadecimal formatted offset to text area name-a first name of interest 123,4 offset to name's text, and number of lines for it name-b next name of interest name-c multiple names which share same description also 456,7 share a single offset,count line . sentinel to mark end of names 789,0 dummy record containing offset, count of EOF text-a 4 lines of descriptive text for name-a text-a at file position 0x01234567L + 123L text-a text-a text-b/text-c 7 lines of text for names-b and -c text-b/text-c at fseek(0x01234567L + 456L) ... * */ void do_data() { char infile[60], tempfile[60]; boolean ok; long txt_offset; int entry_cnt, line_cnt; Sprintf(tempfile, DATA_TEMPLATE, "database.tmp"); filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename,file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE); Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE); Strcat(infile, #ifdef SHORT_FILENAMES ".bas" #else ".base" #endif ); if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */ perror(infile); exit(EXIT_FAILURE); } if (!(ofp = fopen(filename, WRTMODE))) { /* data */ perror(filename); Fclose(ifp); exit(EXIT_FAILURE); } if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */ perror(tempfile); Fclose(ifp); Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* output a dummy header record; we'll rewind and overwrite it later */ Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L); entry_cnt = line_cnt = 0; /* read through the input file and split it into two sections */ while (fgets(in_line, sizeof in_line, ifp)) { if (d_filter(in_line)) continue; if (*in_line > ' ') { /* got an entry name */ /* first finish previous entry */ if (line_cnt) Fprintf(ofp, "%d\n", line_cnt), line_cnt = 0; /* output the entry name */ (void) fputs(in_line, ofp); entry_cnt++; /* update number of entries */ } else if (entry_cnt) { /* got some descriptive text */ /* update previous entry with current text offset */ if (!line_cnt) Fprintf(ofp, "%ld,", ftell(tfp)); /* save the text line in the scratch file */ (void) fputs(in_line, tfp); line_cnt++; /* update line counter */ } } /* output an end marker and then record the current position */ if (line_cnt) Fprintf(ofp, "%d\n", line_cnt); Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0); txt_offset = ftell(ofp); Fclose(ifp); /* all done with original input file */ /* reprocess the scratch file; 1st format an error msg, just in case */ Sprintf(in_line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; /* copy all lines of text from the scratch file into the output file */ while (fgets(in_line, sizeof in_line, tfp)) (void) fputs(in_line, ofp); /* finished with scratch file */ Fclose(tfp); Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ Sprintf(in_line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { Sprintf(in_line, "header rewrite of \"%s\"", filename); ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, txt_offset) >= 0); } if (!ok) { dead_data: perror(in_line); /* report the problem */ /* close and kill the aborted output file, then give up */ Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* all done */ Fclose(ofp); return; } /* routine to decide whether to discard something from oracles.txt */ static boolean h_filter(line) char *line; { static boolean skip = FALSE; char tag[sizeof in_line]; SpinCursor(3); if (*line == '#') return TRUE; /* ignore comment lines */ if (sscanf(line, "----- %s", tag) == 1) { skip = FALSE; #ifndef SINKS if (!strcmp(tag, "SINKS")) skip = TRUE; #endif #ifndef ELBERETH if (!strcmp(tag, "ELBERETH")) skip = TRUE; #endif } else if (skip && !strncmp(line, "-----", 5)) skip = FALSE; return skip; } static const char *special_oracle[] = { "\"...it is rather disconcerting to be confronted with the", "following theorem from [Baker, Gill, and Solovay, 1975].", "", "Theorem 7.18 There exist recursive languages A and B such that", " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "", "This provides impressive evidence that the techniques that are", "currently available will not suffice for proving that P != NP or ", "that P == NP.\" [Garey and Johnson, p. 185.]" }; /* The oracle file consists of a "do not edit" comment, a decimal count N and set of N+1 hexadecimal fseek offsets, followed by N multiple-line records, separated by "---" lines. The first oracle is a special case. The input data contains just those multi-line records, separated by "-----" lines. */ void do_oracles() { char infile[60], tempfile[60]; boolean in_oracle, ok; long txt_offset, offset, fpos; int oracle_cnt; register int i; Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp"); filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE); Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE); Strcat(infile, ".txt"); if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); exit(EXIT_FAILURE); } if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); Fclose(ifp); exit(EXIT_FAILURE); } if (!(tfp = fopen(tempfile, WRTMODE))) { /* oracles.tmp */ perror(tempfile); Fclose(ifp); Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* output a dummy header record; we'll rewind and overwrite it later */ Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0); /* handle special oracle; it must come first */ (void) fputs("---\n", tfp); Fprintf(ofp, "%05lx\n", ftell(tfp)); /* start pos of special oracle */ for (i = 0; i < SIZE(special_oracle); i++) { (void) fputs(xcrypt(special_oracle[i]), tfp); (void) fputc('\n', tfp); } SpinCursor(3); oracle_cnt = 1; (void) fputs("---\n", tfp); Fprintf(ofp, "%05lx\n", ftell(tfp)); /* start pos of first oracle */ in_oracle = FALSE; while (fgets(in_line, sizeof in_line, ifp)) { SpinCursor(3); if (h_filter(in_line)) continue; if (!strncmp(in_line, "-----", 5)) { if (!in_oracle) continue; in_oracle = FALSE; oracle_cnt++; (void) fputs("---\n", tfp); Fprintf(ofp, "%05lx\n", ftell(tfp)); /* start pos of this oracle */ } else { in_oracle = TRUE; (void) fputs(xcrypt(in_line), tfp); } } if (in_oracle) { /* need to terminate last oracle */ oracle_cnt++; (void) fputs("---\n", tfp); Fprintf(ofp, "%05lx\n", ftell(tfp)); /* eof position */ } /* record the current position */ txt_offset = ftell(ofp); Fclose(ifp); /* all done with original input file */ /* reprocess the scratch file; 1st format an error msg, just in case */ Sprintf(in_line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; /* copy all lines of text from the scratch file into the output file */ while (fgets(in_line, sizeof in_line, tfp)) (void) fputs(in_line, ofp); /* finished with scratch file */ Fclose(tfp); Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ Sprintf(in_line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { Sprintf(in_line, "header rewrite of \"%s\"", filename); ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >=0); } if (ok) { Sprintf(in_line, "data rewrite of \"%s\"", filename); for (i = 0; i <= oracle_cnt; i++) { #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */ if (!(ok = (fflush(ofp) == 0))) break; #endif if (!(ok = (fpos = ftell(ofp)) >= 0)) break; if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break; if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1))) break; #ifdef MAC # ifdef __MWERKS__ /* MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL (ANSI C Libraries) needs this rewind or else the fprintf stops working. This may also be true for CW11, but has never been checked. */ rewind(ofp); # endif #endif if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break; if (!(ok = (fprintf(ofp, "%05lx\n", offset + txt_offset) >= 0))) break; } } if (!ok) { dead_data: perror(in_line); /* report the problem */ /* close and kill the aborted output file, then give up */ Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* all done */ Fclose(ofp); return; } static struct deflist { const char *defname; boolean true_or_false; } deflist[] = { #ifdef REINCARNATION { "REINCARNATION", TRUE }, #else { "REINCARNATION", FALSE }, #endif { 0, 0 } }; static int check_control(s) char *s; { int i; if(s[0] != '%') return(-1); for(i = 0; deflist[i].defname; i++) if(!strncmp(deflist[i].defname, s+1, strlen(deflist[i].defname))) return(i); return(-1); } static char * without_control(s) char *s; { return(s + 1 + strlen(deflist[check_control(in_line)].defname)); } void do_dungeon() { int rcnt = 0; Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE); if (!(ifp = fopen(filename, RDTMODE))) { perror(filename); exit(EXIT_FAILURE); } filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Data); while (fgets(in_line, sizeof in_line, ifp) != 0) { SpinCursor(3); rcnt++; if(in_line[0] == '#') continue; /* discard comments */ recheck: if(in_line[0] == '%') { int i = check_control(in_line); if(i >= 0) { if(!deflist[i].true_or_false) { while (fgets(in_line, sizeof in_line, ifp) != 0) if(check_control(in_line) != i) goto recheck; } else (void) fputs(without_control(in_line),ofp); } else { Fprintf(stderr, "Unknown control option '%s' in file %s at line %d.\n", in_line, DGN_I_FILE, rcnt); exit(EXIT_FAILURE); } } else (void) fputs(in_line,ofp); } Fclose(ifp); Fclose(ofp); return; } static boolean ranged_attk(ptr) /* returns TRUE if monster can attack at range */ register struct permonst *ptr; { register int i, j; register int atk_mask = (1<mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1<mlevel; if(tmp > 49) /* special fixed hp monster */ tmp = 2*(tmp - 6) / 4; /* For creation in groups */ n = (!!(ptr->geno & G_SGROUP)); n += (!!(ptr->geno & G_LGROUP)) << 1; /* For ranged attacks */ if (ranged_attk(ptr)) n++; /* For higher ac values */ n += (ptr->ac < 4); n += (ptr->ac < 0); /* For very fast monsters */ n += (ptr->mmove >= 18); /* For each attack and "special" attack */ for(i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].aatyp; n += (tmp2 > 0); n += (tmp2 == AT_MAGC); n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG)); } /* For each "special" damage type */ for(i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].adtyp; if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST) || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE)) n += 2; else if (strcmp(ptr->mname, "grid bug")) n += (tmp2 != AD_PHYS); n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23); } /* Leprechauns are special cases. They have many hit dice so they can hit and are hard to kill, but they don't really do much damage. */ if (!strcmp(ptr->mname, "leprechaun")) n -= 2; /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */ if(n == 0) tmp--; else if(n >= 6) tmp += ( n / 2 ); else tmp += ( n / 3 + 1); return((tmp >= 0) ? tmp : 0); } void do_monstr() { register struct permonst *ptr; register int i, j; /* * create the source file, "monstr.c" */ filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#include \"config.h\"\n"); Fprintf(ofp,"\nconst int monstr[] = {\n"); for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) { SpinCursor(3); i = mstrength(ptr); Fprintf(ofp,"%2d,%c", i, (++j & 15) ? ' ' : '\n'); } /* might want to insert a final 0 entry here instead of just newline */ Fprintf(ofp,"%s};\n", (j & 15) ? "\n" : ""); Fprintf(ofp,"\nvoid NDECL(monstr_init);\n"); Fprintf(ofp,"\nvoid\n"); Fprintf(ofp,"monstr_init()\n"); Fprintf(ofp,"{\n"); Fprintf(ofp," return;\n"); Fprintf(ofp,"}\n"); Fprintf(ofp,"\n/*monstr.c*/\n"); Fclose(ofp); return; } void do_permonst() { int i; char *c, *nam; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,"/*\tSCCS Id: @(#)pm.h\t3.4\t2002/02/03 */\n\n"); Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#ifndef PM_H\n#define PM_H\n"); if (strcmp(mons[0].mname, "playermon") != 0) Fprintf(ofp,"\n#define\tPM_PLAYERMON\t(-1)"); for (i = 0; mons[i].mlet; i++) { SpinCursor(3); Fprintf(ofp,"\n#define\tPM_"); if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].mname, "were", 4)) Fprintf(ofp, "HUMAN_"); for (nam = c = tmpdup(mons[i].mname); *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A'); else if (*c < 'A' || *c > 'Z') *c = '_'; Fprintf(ofp,"%s\t%d", nam, i); } Fprintf(ofp,"\n\n#define\tNUMMONS\t%d\n", i); Fprintf(ofp,"\n#endif /* PM_H */\n"); Fclose(ofp); return; } /* Start of Quest text file processing. */ #include "qtext.h" static struct qthdr qt_hdr; static struct msghdr msg_hdr[N_HDR]; static struct qtmsg *curr_msg; static int qt_line; static boolean in_msg; #define NO_MSG 1 /* strlen of a null line returned by fgets() */ static boolean qt_comment(s) char *s; { if(s[0] == '#') return(TRUE); return((boolean)(!in_msg && strlen(s) == NO_MSG)); } static boolean qt_control(s) char *s; { return((boolean)(s[0] == '%' && (s[1] == 'C' || s[1] == 'E'))); } static int get_hdr (code) char *code; { int i; for(i = 0; i < qt_hdr.n_hdr; i++) if(!strncmp(code, qt_hdr.id[i], LEN_HDR)) return (++i); return(0); } static boolean new_id (code) char *code; { if(qt_hdr.n_hdr >= N_HDR) { Fprintf(stderr, OUT_OF_HEADERS, qt_line); return(FALSE); } strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR); msg_hdr[qt_hdr.n_hdr].n_msg = 0; qt_hdr.offset[qt_hdr.n_hdr++] = 0L; return(TRUE); } static boolean known_msg(num, id) int num, id; { int i; for(i = 0; i < msg_hdr[num].n_msg; i++) if(msg_hdr[num].qt_msg[i].msgnum == id) return(TRUE); return(FALSE); } static void new_msg(s, num, id) char *s; int num, id; { struct qtmsg *qt_msg; if(msg_hdr[num].n_msg >= N_MSG) { Fprintf(stderr, OUT_OF_MESSAGES, qt_line); } else { qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]); qt_msg->msgnum = id; qt_msg->delivery = s[2]; qt_msg->offset = qt_msg->size = 0L; curr_msg = qt_msg; } } static void do_qt_control(s) char *s; { char code[BUFSZ]; int num, id = 0; switch(s[1]) { case 'C': if(in_msg) { Fprintf(stderr, CREC_IN_MSG, qt_line); break; } else { in_msg = TRUE; if (sscanf(&s[4], "%s %5d", code, &id) != 2) { Fprintf(stderr, UNREC_CREC, qt_line); break; } num = get_hdr(code); if (!num && !new_id(code)) break; num = get_hdr(code)-1; if(known_msg(num, id)) Fprintf(stderr, DUP_MSG, qt_line); else new_msg(s, num, id); } break; case 'E': if(!in_msg) { Fprintf(stderr, END_NOT_IN_MSG, qt_line); break; } else in_msg = FALSE; break; default: Fprintf(stderr, UNREC_CREC, qt_line); break; } } static void do_qt_text(s) char *s; { if (!in_msg) { Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line); } curr_msg->size += strlen(s); return; } static void adjust_qt_hdrs() { int i, j; long count = 0L, hdr_offset = sizeof(int) + (sizeof(char)*LEN_HDR + sizeof(long)) * qt_hdr.n_hdr; for(i = 0; i < qt_hdr.n_hdr; i++) { qt_hdr.offset[i] = hdr_offset; hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg; } for(i = 0; i < qt_hdr.n_hdr; i++) for(j = 0; j < msg_hdr[i].n_msg; j++) { msg_hdr[i].qt_msg[j].offset = hdr_offset + count; count += msg_hdr[i].qt_msg[j].size; } return; } static void put_qt_hdrs() { int i; /* * The main header record. */ #ifdef DEBUG Fprintf(stderr, "%ld: header info.\n", ftell(ofp)); #endif (void) fwrite((genericptr_t)&(qt_hdr.n_hdr), sizeof(int), 1, ofp); (void) fwrite((genericptr_t)&(qt_hdr.id[0][0]), sizeof(char)*LEN_HDR, qt_hdr.n_hdr, ofp); (void) fwrite((genericptr_t)&(qt_hdr.offset[0]), sizeof(long), qt_hdr.n_hdr, ofp); #ifdef DEBUG for(i = 0; i < qt_hdr.n_hdr; i++) Fprintf(stderr, "%c @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]); Fprintf(stderr, "\n"); #endif /* * The individual class headers. */ for(i = 0; i < qt_hdr.n_hdr; i++) { #ifdef DEBUG Fprintf(stderr, "%ld: %c header info.\n", ftell(ofp), qt_hdr.id[i]); #endif (void) fwrite((genericptr_t)&(msg_hdr[i].n_msg), sizeof(int), 1, ofp); (void) fwrite((genericptr_t)&(msg_hdr[i].qt_msg[0]), sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp); #ifdef DEBUG { int j; for(j = 0; j < msg_hdr[i].n_msg; j++) Fprintf(stderr, "msg %d @ %ld (%ld)\n", msg_hdr[i].qt_msg[j].msgnum, msg_hdr[i].qt_msg[j].offset, msg_hdr[i].qt_msg[j].size); } #endif } } void do_questtxt() { Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE); if(!(ifp = fopen(filename, RDTMODE))) { perror(filename); exit(EXIT_FAILURE); } filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE); if(!(ofp = fopen(filename, WRBMODE))) { perror(filename); Fclose(ifp); exit(EXIT_FAILURE); } qt_hdr.n_hdr = 0; qt_line = 0; in_msg = FALSE; while (fgets(in_line, 80, ifp) != 0) { SpinCursor (3); qt_line++; if(qt_control(in_line)) do_qt_control(in_line); else if(qt_comment(in_line)) continue; else do_qt_text(in_line); } (void) rewind(ifp); in_msg = FALSE; adjust_qt_hdrs(); put_qt_hdrs(); while (fgets(in_line, 80, ifp) != 0) { if(qt_control(in_line)) { in_msg = (in_line[1] == 'C'); continue; } else if(qt_comment(in_line)) continue; #ifdef DEBUG Fprintf(stderr, "%ld: %s", ftell(stdout), in_line); #endif (void) fputs(xcrypt(in_line), ofp); } Fclose(ifp); Fclose(ofp); return; } static char temp[32]; static char * limit(name,pref) /* limit a name to 30 characters length */ char *name; int pref; { (void) strncpy(temp, name, pref ? 26 : 30); temp[pref ? 26 : 30] = 0; return temp; } void do_objs() { int i, sum = 0; char *c, *objnam; int nspell = 0; int prefix = 0; char class = '\0'; boolean sumerr = FALSE; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,"/*\tSCCS Id: @(#)onames.h\t3.4\t2002/02/03 */\n\n"); Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#ifndef ONAMES_H\n#define ONAMES_H\n\n"); for(i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) { SpinCursor(3); objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init */ if (!(objnam = tmpdup(OBJ_NAME(objects[i])))) continue; /* make sure probabilities add up to 1000 */ if(objects[i].oc_class != class) { if (sum && sum != 1000) { Fprintf(stderr, "prob error for class %d (%d%%)", class, sum); (void) fflush(stderr); sumerr = TRUE; } class = objects[i].oc_class; sum = 0; } for (c = objnam; *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A'); else if (*c < 'A' || *c > 'Z') *c = '_'; switch (class) { case WAND_CLASS: Fprintf(ofp,"#define\tWAN_"); prefix = 1; break; case RING_CLASS: Fprintf(ofp,"#define\tRIN_"); prefix = 1; break; case POTION_CLASS: Fprintf(ofp,"#define\tPOT_"); prefix = 1; break; case SPBOOK_CLASS: Fprintf(ofp,"#define\tSPE_"); prefix = 1; nspell++; break; case SCROLL_CLASS: Fprintf(ofp,"#define\tSCR_"); prefix = 1; break; case AMULET_CLASS: /* avoid trouble with stupid C preprocessors */ Fprintf(ofp,"#define\t"); if(objects[i].oc_material == PLASTIC) { Fprintf(ofp,"FAKE_AMULET_OF_YENDOR\t%d\n", i); prefix = -1; break; } break; case GEM_CLASS: /* avoid trouble with stupid C preprocessors */ if(objects[i].oc_material == GLASS) { Fprintf(ofp,"/* #define\t%s\t%d */\n", objnam, i); prefix = -1; break; } default: Fprintf(ofp,"#define\t"); } if (prefix >= 0) Fprintf(ofp,"%s\t%d\n", limit(objnam, prefix), i); prefix = 0; sum += objects[i].oc_prob; } /* check last set of probabilities */ if (sum && sum != 1000) { Fprintf(stderr, "prob error for class %d (%d%%)", class, sum); (void) fflush(stderr); sumerr = TRUE; } Fprintf(ofp,"#define\tLAST_GEM\t(JADE)\n"); Fprintf(ofp,"#define\tMAXSPELL\t%d\n", nspell+1); Fprintf(ofp,"#define\tNUM_OBJECTS\t%d\n", i); Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n"); for (i = 1; artifact_names[i]; i++) { SpinCursor(3); for (c = objnam = tmpdup(artifact_names[i]); *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A'); else if (*c < 'A' || *c > 'Z') *c = '_'; if (!strncmp(objnam, "THE_", 4)) objnam += 4; #ifdef TOURIST /* fudge _platinum_ YENDORIAN EXPRESS CARD */ if (!strncmp(objnam, "PLATINUM_", 9)) objnam += 9; #endif Fprintf(ofp,"#define\tART_%s\t%d\n", limit(objnam, 1), i); } Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i-1); Fprintf(ofp,"\n#endif /* ONAMES_H */\n"); Fclose(ofp); if (sumerr) exit(EXIT_FAILURE); return; } static char * tmpdup(str) const char *str; { static char buf[128]; if (!str) return (char *)0; (void)strncpy(buf, str, 127); return buf; } static char * eos(str) char *str; { while (*str) str++; return str; } /* * macro used to control vision algorithms: * VISION_TABLES => generate tables */ void do_vision() { #ifdef VISION_TABLES int i, j; /* Everything is clear. xclear may be malloc'ed. * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH) */ for (i = 0; i < MAX_ROW; i++) for (j = 0; j < MAX_COL; j++) if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH) xclear[i][j] = '\000'; else xclear[i][j] = '\001'; #endif /* VISION_TABLES */ SpinCursor(3); /* * create the include file, "vis_tab.h" */ filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#ifdef VISION_TABLES\n"); #ifdef VISION_TABLES H_close_gen(); H_far_gen(); #endif /* VISION_TABLES */ Fprintf(ofp,"\n#endif /* VISION_TABLES */\n"); Fclose(ofp); SpinCursor(3); /* * create the source file, "vis_tab.c" */ filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H); Unlink(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#include \"config.h\"\n"); Fprintf(ofp,"#ifdef VISION_TABLES\n"); Fprintf(ofp,"#include \"vis_tab.h\"\n"); SpinCursor(3); #ifdef VISION_TABLES C_close_gen(); C_far_gen(); Fprintf(ofp,"\nvoid vis_tab_init() { return; }\n"); #endif /* VISION_TABLES */ SpinCursor(3); Fprintf(ofp,"\n#endif /* VISION_TABLES */\n"); Fprintf(ofp,"\n/*vis_tab.c*/\n"); Fclose(ofp); return; } #ifdef VISION_TABLES /*-------------- vision tables --------------*\ * * Generate the close and far tables. This is done by setting up a * fake dungeon and moving our source to different positions relative * to a block and finding the first/last visible position. The fake * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT * by BLOCK_WIDTH) is blocked. Then we move the source around relative * to the corner of the block. For each new position of the source * we check positions on rows "kittycorner" from the source. We check * positions until they are either in sight or out of sight (depends on * which table we are generating). The picture below shows the setup * for the generation of the close table. The generation of the far * table would switch the quadrants of the '@' and the "Check rows * here". * * * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * ............................... * ............................... * .........@..................... * ............................... * * Table generation figure (close_table). The 'X's are blocked points. * The 'B' is a special blocked point. The '@' is the source. The ','s * are the target area. The '.' are just open areas. * * * Example usage of close_table[][][]. * * The table is as follows: * * dy = |row of '@' - row of 'B'| - 1 * dx = |col of '@' - col of 'B'| * * The first indices are the deltas from the source '@' and the block 'B'. * You must check for the value inside the abs value bars being zero. If * so then the block is on the same row and you don't need to do a table * lookup. The last value: * * dcy = |row of block - row to be checked| * * Is the value of the first visible spot on the check row from the * block column. So * * first visible col = close_table[dy][dx][dcy] + col of 'B' * \*-------------- vision tables --------------*/ static void H_close_gen() { Fprintf(ofp,"\n/* Close */\n"); Fprintf(ofp,"#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n", TEST_HEIGHT-1); Fprintf(ofp,"#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n", TEST_WIDTH); Fprintf(ofp,"#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n", TEST_HEIGHT); Fprintf(ofp,"typedef struct {\n"); Fprintf(ofp," unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n"); Fprintf(ofp,"} close2d;\n"); Fprintf(ofp,"extern close2d close_table[CLOSE_MAX_SB_DY];\n"); return; } static void H_far_gen() { Fprintf(ofp,"\n/* Far */\n"); Fprintf(ofp,"#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n", TEST_HEIGHT); Fprintf(ofp,"#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n", TEST_WIDTH-1); Fprintf(ofp,"#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n", TEST_HEIGHT-1); Fprintf(ofp,"typedef struct {\n"); Fprintf(ofp," unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n"); Fprintf(ofp,"} far2d;\n"); Fprintf(ofp,"extern far2d far_table[FAR_MAX_SB_DY];\n"); return; } static void C_close_gen() { int i,dx,dy; int src_row, src_col; /* source */ int block_row, block_col; /* block */ int this_row; int no_more; const char *delim; block_row = BLOCK_HEIGHT-1; block_col = BLOCK_WIDTH-1; Fprintf(ofp,"\n#ifndef FAR_TABLE_ONLY\n"); Fprintf(ofp,"\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n"); #ifndef no_vision_progress Fprintf(stderr,"\nclose:"); #endif for (dy = 1; dy < TEST_HEIGHT; dy++) { src_row = block_row + dy; Fprintf(ofp, "/* DY = %2d (- 1)*/\n {{\n", dy); #ifndef no_vision_progress Fprintf(stderr," %2d",dy), (void)fflush(stderr); #endif for (dx = 0; dx < TEST_WIDTH; dx++) { src_col = block_col - dx; Fprintf(ofp, " /*%2d*/ {", dx); no_more = 0; for (this_row = 0; this_row < TEST_HEIGHT; this_row++) { delim = (this_row < TEST_HEIGHT - 1) ? "," : ""; if (no_more) { Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim); continue; } SpinCursor(3); /* Find the first column that we can see. */ for (i = block_col+1; i < MAX_COL; i++) { if (clear_path(src_row,src_col,block_row-this_row,i)) break; } if (i == MAX_COL) no_more = 1; Fprintf(ofp, "%2d%s", i - block_col, delim); } Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n"); } Fprintf(ofp," }},\n"); } Fprintf(ofp,"}; /* close_table[] */\n"); /* closing brace for table */ Fprintf(ofp,"#endif /* !FAR_TABLE_ONLY */\n"); #ifndef no_vision_progress Fprintf(stderr,"\n"); #endif return; } static void C_far_gen() { int i,dx,dy; int src_row, src_col; /* source */ int block_row, block_col; /* block */ int this_row; const char *delim; block_row = BLOCK_HEIGHT-1; block_col = BLOCK_WIDTH-1; Fprintf(ofp,"\n#ifndef CLOSE_TABLE_ONLY\n"); Fprintf(ofp,"\nfar2d far_table[FAR_MAX_SB_DY] = {\n"); #ifndef no_vision_progress Fprintf(stderr,"\n_far_:"); #endif for (dy = 0; dy < TEST_HEIGHT; dy++) { src_row = block_row - dy; Fprintf(ofp, "/* DY = %2d */\n {{\n", dy); #ifndef no_vision_progress Fprintf(stderr," %2d",dy), (void)fflush(stderr); #endif for (dx = 1; dx < TEST_WIDTH; dx++) { src_col = block_col + dx; Fprintf(ofp, " /*%2d(-1)*/ {", dx); for (this_row = block_row+1; this_row < block_row+TEST_HEIGHT; this_row++) { delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : ""; SpinCursor(3); /* Find first col that we can see. */ for (i = 0; i <= block_col; i++) { if (clear_path(src_row,src_col,this_row,i)) break; } if (block_col-i < 0) Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim); else Fprintf(ofp, "%2d%s", block_col - i, delim); } Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n"); } Fprintf(ofp," }},\n"); } Fprintf(ofp,"}; /* far_table[] */\n"); /* closing brace for table */ Fprintf(ofp,"#endif /* !CLOSE_TABLE_ONLY */\n"); #ifndef no_vision_progress Fprintf(stderr,"\n"); #endif return; } /* * "Draw" a line from the hero to the given location. Stop if we hit a * wall. * * Generalized integer Bresenham's algorithm (fast line drawing) for * all quadrants. From _Procedural Elements for Computer Graphics_, by * David F. Rogers. McGraw-Hill, 1985. * * I have tried a little bit of optimization by pulling compares out of * the inner loops. * * NOTE: This had better *not* be called from a position on the * same row as the hero. */ static int clear_path(you_row,you_col,y2,x2) int you_row, you_col, y2, x2; { int dx, dy, s1, s2; register int i, error, x, y, dxs, dys; x = you_col; y = you_row; dx = abs(x2-you_col); dy = abs(y2-you_row); s1 = sign(x2-you_col); s2 = sign(y2-you_row); if (s1 == 0) { /* same column */ if (s2 == 1) { /* below (larger y2 value) */ for (i = you_row+1; i < y2; i++) if (!xclear[i][you_col]) return 0; } else { /* above (smaller y2 value) */ for (i = y2+1; i < you_row; i++) if (!xclear[i][you_col]) return 0; } return 1; } /* * Lines at 0 and 90 degrees have been weeded out. */ if (dy > dx) { error = dx; dx = dy; dy = error; /* swap the values */ dxs = dx << 1; /* save the shifted values */ dys = dy << 1; error = dys - dx; /* NOTE: error is used as a temporary above */ for (i = 0; i < dx; i++) { if (!xclear[y][x]) return 0; /* plot point */ while (error >= 0) { x += s1; error -= dxs; } y += s2; error += dys; } } else { dxs = dx << 1; /* save the shifted values */ dys = dy << 1; error = dys - dx; for (i = 0; i < dx; i++) { if (!xclear[y][x]) return 0; /* plot point */ while (error >= 0) { y += s2; error -= dxs; } x += s1; error += dys; } } return 1; } #endif /* VISION_TABLES */ #ifdef STRICT_REF_DEF NEARDATA struct flag flags; # ifdef ATTRIB_H struct attribs attrmax, attrmin; # endif #endif /* STRICT_REF_DEF */ /*makedefs.c*/