From: jwalz Date: Sat, 5 Jan 2002 21:06:00 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: MOVE2GIT~3623 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=62014c6997ace1cc093b2b07342872ac9483d698;p=nethack *** empty log message *** --- diff --git a/util/makedefs.c b/util/makedefs.c new file mode 100644 index 000000000..bd0e14b32 --- /dev/null +++ b/util/makedefs.c @@ -0,0 +1,2143 @@ +/* SCCS Id: @(#)makedefs.c 3.3 1999/08/16 */ +/* 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 +# ifdef applec /* Means the MPW compiler, I hope */ +# 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.3\t1999/08/16"; +#endif + + /* names of files to be generated */ +#define DATE_FILE "date.h" +#define MONST_FILE "pm.h" +#define ONAME_FILE "onames.h" +#define OPTIONS_FILE "options" +#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 +# ifdef MAC +# define INCLUDE_TEMPLATE ":include:%s" +# define SOURCE_TEMPLATE ":src:%s" +# define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */ +# define DATA_TEMPLATE ":lib:%s" +# define DATA_IN_TEMPLATE ":dat:%s" +# else /* 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 /* 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 /* OS2 */ +# endif /* MAC */ +#endif /* 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 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; +} + +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 +#ifdef TIMED_DELAY + | (1L << 23) +#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.3\t1996/05/17 */\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); + 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 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 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_8514 + "screen control via 8514/A graphics", +# endif +# ifdef SCREEN_BIOS + "screen control via BIOS", +# endif +# ifdef SCREEN_DJGPPFAST + "screen control via DJGPP fast", +# endif +# ifdef SCREEN_VESA + "screen control via VESA graphics", +# endif +# ifdef SCREEN_VGA + "screen control via VGA graphics", +# endif +# ifdef WIN32CON + "screen control via WIN32 console I/O", +# 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(TTY_GRAPHICS)) + "terminal capability library", +# endif +#endif +#ifdef TIMED_DELAY + "timed wait for display effects", +#endif +#ifdef TOURIST + "tourists", +#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 + "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 WIN32_GRAPHICS + "Win32", +#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); + } + + 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.3\t1994/09/10 */\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; +{ + 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.3\t1994/09/10 */\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*/