From decwrl!wyse!mips!zaphod.mps.ohio-state.edu!swrinde!emory!ogicse!zephyr.ens.tek.com!tekred!saab!billr Sat May 19 13:03:17 PDT 1990
Article 899 of comp.sources.games:
Path: decwrl!wyse!mips!zaphod.mps.ohio-state.edu!swrinde!emory!ogicse!zephyr.ens.tek.com!tekred!saab!billr
From: billr@saab.CNA.TEK.COM (Bill Randle)
Newsgroups: comp.sources.games
Subject: v09i075:  umoria3 - single player dungeon simulation (ver. 5.2), Part20/31
Message-ID: <5610@tekred.CNA.TEK.COM>
Date: 17 May 90 16:24:43 GMT
Sender: news@tekred.CNA.TEK.COM
Lines: 2796
Approved: billr@saab.CNA.TEK.COM

Submitted-by: wilson@ernie.Berkeley.EDU (Jim Wilson)
Posting-number: Volume 9, Issue 75
Archive-name: umoria3/Part20
Supersedes: umoria2: Volume 5, Issue 32-37,41-52,87



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 20 (of 31)."
# Contents:  source/io.c util/mc/creature.y
# Wrapped by billr@saab on Wed May 16 11:54:35 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'source/io.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'source/io.c'\"
else
echo shar: Extracting \"'source/io.c'\" \(29702 characters\)
sed "s/^X//" >'source/io.c' <<'END_OF_FILE'
X/* io.c: terminal I/O code, uses the curses package
X
X   Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
X
X   This software may be copied and distributed for educational, research, and
X   not for profit purposes provided that this copyright and statement are
X   included in all such copies. */
X
X#ifdef MSDOS
X#include <stdio.h>
X#include <process.h>
X#endif
X
X#if defined(NLS) && defined(lint)
X/* for AIX, don't let curses include the NL stuff */
X#undef NLS
X#endif
X
X#if !defined(GEMDOS)
X#ifdef MAC
X#include <scrnmgr.h>
X#else
X#include <curses.h>
X#endif
X#else
X#define ATARIST_MWC
X#include "curses.h"
Xlong wgetch();
X#include <osbind.h>
Xchar *getenv();
X#endif
X
X#include "constant.h"
X#include "config.h"
X#include "types.h"
X#include "externs.h"
X
X#include <ctype.h>
X
X#if defined(SYS_V) && defined(lint)
X/* for AIX, prevent hundreds of unnecessary lint errors, must define before
X   signal.h is included */
X#define _h_IEEETRAP
Xtypedef struct { int stuff; } fpvmach;
X#endif
X
X#if defined(MSDOS)
X#if defined(ANSI)
X#include "ms_ansi.h"
X#endif
X#else /* not msdos */
X#if !defined(ATARIST_MWC) && !defined(MAC)
X#ifndef VMS
X#include <sys/ioctl.h>
X#endif
X#include <signal.h>
X#endif
X#endif
X
X#ifndef USG
X/* only needed for Berkeley UNIX */
X#include <sys/param.h>
X#include <sys/file.h>
X#include <sys/types.h>
X#endif
X
X#ifdef USG
X#ifndef ATARIST_MWC
X#include <string.h>
X#else
X#include "string.h"
X#endif
X#if !defined(MAC) && !defined(MSDOS) && !defined(ATARIST_MWC)
X#include <termio.h>
X#endif
X#else
X#ifndef VMS
X#include <strings.h>
X#if defined(atarist) && defined(__GNUC__)
X/* doesn't have sys/wait.h */
X#else
X#include <sys/wait.h>
X#endif
X#endif
X#endif
X
X#if defined(SYS_V) && defined(lint)
Xstruct screen { int dumb; };
X#endif
X
X/* Fooling lint. Unfortunately, c defines all the TIO.	  -CJS-
X   constants to be long, and lint expects them to be int. Also,
X   ioctl is sometimes called with just two arguments. The
X   following definition keeps lint happy. It may need to be
X   reset for different systems.	 */
X#ifndef MAC
X#ifdef lint
X#ifdef Pyramid
X/* Pyramid makes constants greater than 65535 into long! Gakk! -CJS- */
X/*ARGSUSED*/
X/*VARARGS2*/
Xstatic Ioctl(i, l, p) long l; char *p; { return 0; }
X#else
X/*ARGSUSED*/
X/*VARARGS2*/
Xstatic Ioctl(i, l, p) char *p; { return 0; }
X#endif
X#define ioctl	    Ioctl
X#endif
X
X#if !defined(USG) && defined(lint)
X/* This use_value hack is for curses macros which return a value,
X   but don't shut up about it when you try to tell them (void).	 */
X/* only needed for Berkeley UNIX */
Xint Use_value;
X#define use_value   Use_value +=
X#else
X#define use_value
X#endif
X
X#if defined(SYS_V) && defined(lint)
X/* This use_value2 hack is for curses macros which use a conditional
X   expression, and which say null effect even if you cast to (void). */
X/* only needed for SYS V */
Xint Use_value2;
X#define use_value2  Use_value2 +=
X#else
X#define use_value2
X#endif
X
X#endif
X
X#ifndef MAC
Xchar *getenv();
X#endif
X
X#ifdef USG
Xvoid exit();
Xunsigned sleep();
X#endif
X#ifdef ultrix
Xvoid exit();
Xvoid sleep();
X#endif
X
X#if !defined(MAC) && !defined(MSDOS) && !defined(ATARIST_MWC)
X#ifdef USG
Xstatic struct termio save_termio;
X#else
X#ifndef VMS
Xstatic struct ltchars save_special_chars;
Xstatic struct sgttyb save_ttyb;
Xstatic struct tchars save_tchars;
Xstatic int save_local_chars;
X#endif
X#endif
X#endif
X
X#ifndef MAC
Xstatic int curses_on = FALSE;
Xstatic WINDOW *savescr;		/* Spare window for saving the screen. -CJS- */
X#endif
X
X#ifdef MAC
X/* Attributes of normal and hilighted characters */
X#define ATTR_NORMAL	attrNormal
X#define ATTR_HILITED	attrReversed
X#endif
X
X#ifndef MAC
X#ifdef SIGTSTP
X/* suspend()							   -CJS-
X   Handle the stop and start signals. This ensures that the log
X   is up to date, and that the terminal is fully reset and
X   restored.  */
Xint suspend()
X{
X#ifdef USG
X  /* for USG systems with BSDisms that have SIGTSTP defined, but don't
X     actually implement it */
X#else
X  struct sgttyb tbuf;
X  struct ltchars lcbuf;
X  struct tchars cbuf;
X  int lbuf;
X  long time();
X
X  py.misc.male |= 2;
X  (void) ioctl(0, TIOCGETP, (char *)&tbuf);
X  (void) ioctl(0, TIOCGETC, (char *)&cbuf);
X  (void) ioctl(0, TIOCGLTC, (char *)&lcbuf);
X  (void) ioctl(0, TIOCLGET, (char *)&lbuf);
X  restore_term();
X  (void) kill(0, SIGSTOP);
X  curses_on = TRUE;
X  (void) ioctl(0, TIOCSETP, (char *)&tbuf);
X  (void) ioctl(0, TIOCSETC, (char *)&cbuf);
X  (void) ioctl(0, TIOCSLTC, (char *)&lcbuf);
X  (void) ioctl(0, TIOCLSET, (char *)&lbuf);
X  (void) wrefresh(curscr);
X  py.misc.male &= ~2;
X#endif
X  return 0;
X}
X#endif
X#endif
X
X/* initializes curses routines */
Xvoid init_curses()
X#ifdef MAC
X{
X  /* Primary initialization is done in mac.c since game is restartable */
X  /* Only need to clear the screen here */
X  Rect scrn;
X  
X  scrn.left = scrn.top = 0;
X  scrn.right = SCRN_COLS;
X  scrn.bottom = SCRN_ROWS;
X  EraseScreen(&scrn);
X  UpdateScreen();
X}
X#else
X{
X  int i, y, x;
X
X#ifndef USG
X  (void) ioctl(0, TIOCGLTC, (char *)&save_special_chars);
X  (void) ioctl(0, TIOCGETP, (char *)&save_ttyb);
X  (void) ioctl(0, TIOCGETC, (char *)&save_tchars);
X  (void) ioctl(0, TIOCLGET, (char *)&save_local_chars);
X#else
X#if !defined(VMS) && !defined(MSDOS) && !defined(ATARIST_MWC)
X  (void) ioctl(0, TCGETA, (char *)&save_termio);
X#endif
X#endif
X
X#ifdef ATARIST_MWC
X  WINDOW *newwin();
X  initscr();
X  if (ERR)
X#else
X#if defined(USG) && !defined(PC_CURSES)	/* PC curses returns ERR */
X  if (initscr() == NULL)
X#else
X  if (initscr() == ERR)
X#endif
X#endif
X    {
X      (void) printf("Error allocating screen in curses package.\n");
X      exit(1);
X    }
X  if (LINES < 24 || COLS < 80)	 /* Check we have enough screen. -CJS- */
X    {
X      (void) printf("Screen too small for moria.\n");
X      exit (1);
X    }
X#ifdef SIGTSTP
X  (void) signal (SIGTSTP, suspend);
X#endif
X  if ((savescr = newwin (0, 0, 0, 0)) == NULL)
X    {
X      (void) printf ("Out of memory in starting up curses.\n");
X      exit_game();
X    }
X  (void) clear();
X  (void) refresh();
X  moriaterm ();
X
X  /* check tab settings, exit with error if they are not 8 spaces apart */
X#ifdef ATARIST_MWC
X  move(0, 0);
X#else
X  (void) move(0, 0);
X#endif
X  for (i = 1; i < 10; i++)
X    {
X#ifdef ATARIST_MWC
X      addch('\t');
X#else
X      (void) addch('\t');
X#endif
X      getyx(stdscr, y, x);
X      if (y != 0 || x != i*8)
X	break;
X    }
X  if (i != 10)
X    {
X      msg_print("Tabs must be set 8 spaces apart.");
X      exit_game();
X    }
X}
X#endif
X
X/* Set up the terminal into a suitable state for moria.	 -CJS- */
Xvoid moriaterm()
X#ifdef MAC
X/* Nothing to do on Mac */
X{
X}
X#else
X{
X#if !defined(MSDOS) && !defined(ATARIST_MWC)
X#ifdef USG
X  struct termio tbuf;
X#else
X  struct ltchars lbuf;
X  struct tchars buf;
X#endif
X#endif
X
X  curses_on = TRUE;
X#ifndef BSD4_3
X  use_value crmode();
X#else
X  use_value cbreak();
X#endif
X  use_value noecho();
X  /* can not use nonl(), because some curses do not handle it correctly */
X#ifdef MSDOS
X  msdos_raw();
X#else
X#if !defined(ATARIST_MWC)
X#ifdef USG
X  (void) ioctl(0, TCGETA, (char *)&tbuf);
X  /* disable all of the normal special control characters */
X  tbuf.c_cc[VINTR] = (char)3; /* control-C */
X  tbuf.c_cc[VQUIT] = (char)-1;
X  tbuf.c_cc[VERASE] = (char)-1;
X  tbuf.c_cc[VKILL] = (char)-1;
X  tbuf.c_cc[VEOF] = (char)-1;
X
X  /* don't know what these are for */
X  tbuf.c_cc[VEOL] = (char)-1;
X  tbuf.c_cc[VEOL2] = (char)-1;
X
X  /* stuff needed when !icanon, i.e. cbreak/raw mode */
X  tbuf.c_cc[VMIN] = 1;  /* Input should wait for at least 1 char */
X  tbuf.c_cc[VTIME] = 0; /* no matter how long that takes. */
X
X  (void) ioctl(0, TCSETA, (char *)&tbuf);
X#else
X#ifndef VMS
X  /* disable all of the special characters except the suspend char, interrupt
X     char, and the control flow start/stop characters */
X  (void) ioctl(0, TIOCGLTC, (char *)&lbuf);
X  lbuf.t_suspc = (char)26; /* control-Z */
X  lbuf.t_dsuspc = (char)-1;
X  lbuf.t_rprntc = (char)-1;
X  lbuf.t_flushc = (char)-1;
X  lbuf.t_werasc = (char)-1;
X  lbuf.t_lnextc = (char)-1;
X  (void) ioctl(0, TIOCSLTC, (char *)&lbuf);
X
X  (void) ioctl (0, TIOCGETC, (char *)&buf);
X  buf.t_intrc = (char)3; /* control-C */
X  buf.t_quitc = (char)-1;
X  buf.t_startc = (char)17; /* control-Q */
X  buf.t_stopc = (char)19; /* control-S */
X  buf.t_eofc = (char)-1;
X  buf.t_brkc = (char)-1;
X  (void) ioctl(0, TIOCSETC, (char *)&buf);
X#endif
X#endif
X#endif
X#endif
X}
X#endif
X
X
X/* Dump IO to buffer					-RAK-	*/
Xvoid put_buffer(out_str, row, col)
Xchar *out_str;
Xint row, col;
X#ifdef MAC
X{
X  /* The screen manager handles writes past the edge ok */
X  DSetScreenCursor(col, row);
X  DWriteScreenStringAttr(out_str, ATTR_NORMAL);
X}	
X#else
X{
X  vtype tmp_str;
X
X  /* truncate the string, to make sure that it won't go past right edge of
X     screen */
X  if (col > 79)
X    col = 79;
X  (void) strncpy (tmp_str, out_str, 79 - col);
X  tmp_str [79 - col] = '\0';
X
X#ifndef ATARIST_MWC
X  if (mvaddstr(row, col, tmp_str) == ERR)
X#else
X  mvaddstr(row, col, out_str);
X  if (ERR)
X#endif
X    {
X      abort();
X      /* clear msg_flag to avoid problems with unflushed messages */
X      msg_flag = 0;
X      (void) sprintf(tmp_str, "error in put_buffer, row = %d col = %d\n",
X		     row, col);
X      prt(tmp_str, 0, 0);
X      bell();
X      /* wait so user can see error */
X      (void) sleep(2);
X    }
X}
X#endif
X
X
X/* Dump the IO buffer to terminal			-RAK-	*/
Xvoid put_qio()
X{
X  screen_change = TRUE;	    /* Let inven_command know something has changed. */
X#ifdef MAC
X  UpdateScreen();
X#else
X  (void) refresh();
X#endif
X}
X
X/* Put the terminal in the original mode.			   -CJS- */
Xvoid restore_term()
X#ifdef MAC
X/* Nothing to do on Mac */
X{
X}
X#else
X{
X  if (!curses_on)
X    return;
X  put_qio();  /* Dump any remaining buffer */
X#ifdef MSDOS
X  (void) sleep(2);   /* And let it be read. */
X#endif
X#ifdef VMS
X  pause_line(15);
X#endif
X  /* this moves curses to bottom right corner */
X  mvcur(curscr->_cury, curscr->_curx, LINES-1, 0);
X#ifdef VMS
X  pause_line(15);
X#endif
X  endwin();  /* exit curses */
X  (void) fflush (stdout);
X#ifdef MSDOS
X  msdos_noraw();
X  (void) clear();
X#endif
X  /* restore the saved values of the special chars */
X#ifdef USG
X#if !defined(MSDOS) && !defined(ATARIST_MWC)
X  (void) ioctl(0, TCSETA, (char *)&save_termio);
X#endif
X#else
X#ifndef VMS
X  (void) ioctl(0, TIOCSLTC, (char *)&save_special_chars);
X  (void) ioctl(0, TIOCSETP, (char *)&save_ttyb);
X  (void) ioctl(0, TIOCSETC, (char *)&save_tchars);
X  (void) ioctl(0, TIOCLSET, (char *)&save_local_chars);
X#endif
X#endif
X  curses_on = FALSE;
X}
X#endif
X
X
Xvoid shell_out()
X#ifdef MAC
X{
X  alert_error("This command is not implemented on the Macintosh.");
X}
X#else
X{
X#ifdef USG
X#if !defined(MSDOS) && !defined(ATARIST_MWC)
X  struct termio tbuf;
X#endif
X#else
X  struct sgttyb tbuf;
X  struct ltchars lcbuf;
X  struct tchars cbuf;
X  int lbuf;
X#endif
X#ifdef MSDOS
X  char	*comspec, key;
X#else
X#ifdef ATARIST_MWC
X  char comstr[80];
X  char *str;
X  extern char **environ;
X#else
X  int val;
X  char *str;
X#endif
X#endif
X
X  save_screen();
X  /* clear screen and print 'exit' message */
X  clear_screen();
X#ifndef ATARIST_MWC
X  put_buffer("[Entering shell, type 'exit' to resume your game.]\n",0,0);
X#else
X  put_buffer("[Escaping to shell]\n",0,0);
X#endif
X  put_qio();
X
X#ifdef USG
X#if !defined(MSDOS) && !defined(ATARIST_MWC)
X  (void) ioctl(0, TCGETA, (char *)&tbuf);
X#endif
X#else
X#ifndef VMS
X  (void) ioctl(0, TIOCGETP, (char *)&tbuf);
X  (void) ioctl(0, TIOCGETC, (char *)&cbuf);
X  (void) ioctl(0, TIOCGLTC, (char *)&lcbuf);
X  (void) ioctl(0, TIOCLGET, (char *)&lbuf);
X#endif
X#endif
X  /* would call nl() here if could use nl()/nonl(), see moriaterm() */
X#ifndef BSD4_3
X  use_value nocrmode();
X#else
X  use_value nocbreak();
X#endif
X#ifdef MSDOS
X  use_value msdos_noraw();
X#endif
X  use_value echo();
X  ignore_signals();
X#ifdef MSDOS		/*{*/
X  if ((comspec = getenv("COMSPEC")) == NULL
X  ||  spawnl(P_WAIT, comspec, comspec, (char *) NULL) < 0) {
X	clear_screen();	/* BOSS key if shell failed */
X	put_buffer("M:\\> ", 0, 0);
X	do {
X	  key = inkey(key);
X	} while (key != '!');
X  }
X
X#else		/* MSDOS }{*/
X#ifndef ATARIST_MWC
X  val = fork();
X  if (val == 0)
X    {
X#endif
X      default_signals();
X#ifdef USG
X#if !defined(MSDOS) && !defined(ATARIST_MWC)
X      (void) ioctl(0, TCSETA, (char *)&save_termio);
X#endif
X#else
X#ifndef VMS
X      (void) ioctl(0, TIOCSLTC, (char *)&save_special_chars);
X      (void) ioctl(0, TIOCSETP, (char *)&save_ttyb);
X      (void) ioctl(0, TIOCSETC, (char *)&save_tchars);
X      (void) ioctl(0, TIOCLSET, (char *)&save_local_chars);
X#endif
X#endif
X#ifndef MSDOS
X      /* close scoreboard descriptor */
X      /* it is not open on MSDOS machines */
X#if 0
X      /* this file is not open now, see init_file() in files.c */
X      (void) close(highscore_fd);
X#endif
X#endif
X      if (str = getenv("SHELL"))
X#ifndef ATARIST_MWC
X	(void) execl(str, str, (char *) 0);
X#else
X	system(str);
X#endif
X      else
X#ifndef ATARIST_MWC
X	(void) execl("/bin/sh", "sh", (char *) 0);
X#endif
X      msg_print("Cannot execute shell.");
X#ifndef ATARIST_MWC
X      exit(1);
X    }
X  if (val == -1)
X    {
X      msg_print("Fork failed. Try again.");
X      return;
X    }
X#ifdef USG
X  (void) wait((int *) 0);
X#else
X  (void) wait((union wait *) 0);
X#endif
X#endif /* ATARIST_MWC */
X#endif		 /* MSDOS }*/
X  restore_signals();
X  /* restore the cave to the screen */
X  restore_screen();
X#ifndef BSD4_3
X  use_value crmode();
X#else
X  use_value cbreak();
X#endif
X  use_value noecho();
X  /* would call nonl() here if could use nl()/nonl(), see moriaterm() */
X#ifdef MSDOS
X  msdos_raw();
X#endif
X  /* disable all of the local special characters except the suspend char */
X  /* have to disable ^Y for tunneling */
X#ifdef USG
X#if !defined(MSDOS) && !defined(ATARIST_MWC)
X  (void) ioctl(0, TCSETA, (char *)&tbuf);
X#endif
X#else
X#ifndef VMS
X  (void) ioctl(0, TIOCSLTC, (char *)&lcbuf);
X  (void) ioctl(0, TIOCSETP, (char *)&tbuf);
X  (void) ioctl(0, TIOCSETC, (char *)&cbuf);
X  (void) ioctl(0, TIOCLSET, (char *)&lbuf);
X#endif
X#endif
X  (void) wrefresh(curscr);
X}
X#endif
X
X
X/* Returns a single character input from the terminal.	This silently -CJS-
X   consumes ^R to redraw the screen and reset the terminal, so that this
X   operation can always be performed at any input prompt.  inkey() never
X   returns ^R.	*/
Xchar inkey()
X#ifdef MAC
X/* The Mac does not need ^R, so it just consumes it */
X/* This routine does nothing special with direction keys */
X/* Just returns their keypad ascii value (e.g. '0'-'9') */
X/* Compare with inkeydir() below */
X{
X  char ch;
X  int dir;
X  int shift_flag, ctrl_flag;
X  
X  put_qio();
X  command_count = 0;
X  
X  do {
X    macgetkey(&ch, FALSE);
X  } while (ch == CTRL('R'));
X  
X  dir = extractdir(ch, &shift_flag, &ctrl_flag);
X  if (dir != -1)
X    ch = '0' + dir;
X  
X  return(ch);
X}
X#else
X{
X  int i;
X
X  put_qio();			/* Dump IO buffer		*/
X  command_count = 0;  /* Just to be safe -CJS- */
X  while (TRUE)
X    {
X#ifdef MSDOS
X      i = msdos_getch();
X#else
X      i = getch();
X#endif
X
X      /* some machines may not sign extend. */
X      if (i == EOF)
X	{
X	  eof_flag++;
X	  /* avoid infinite loops while trying to call inkey() for a -more-
X	     prompt. */
X	  msg_flag = FALSE;
X
X	  (void) refresh ();
X	  if (!character_generated || character_saved)
X	    exit_game();
X	  disturb(1, 0);
X	  if (eof_flag > 100)
X	    {
X	      /* just in case, to make sure that the process eventually dies */
X	      panic_save = 1;
X	      (void) strcpy(died_from, "(end of input: panic saved)");
X	      if (!save_char())
X		{
X		  (void) strcpy(died_from, "panic: unexpected eof");
X		  death = TRUE;
X		}
X	      exit_game();
X	    }
X	  return ESCAPE;
X	}
X      if (i != CTRL('R'))
X	return (char)i;
X      (void) wrefresh (curscr);
X      moriaterm();
X    }
X}
X#endif
X
X
X#ifdef MAC
Xchar inkeydir()
X/* The Mac does not need ^R, so it just consumes it */
X/* This routine translates the direction keys in rogue-like mode */
X/* Compare with inkeydir() below */
X{
X  char ch;
X  int dir;
X  int shift_flag, ctrl_flag;
X  static char tab[9] = {
X	'b',		'j',		'n',
X	'h',		'.',		'l',
X	'y',		'k',		'u'
X  };
X  static char shifttab[9] = {
X	'B',		'J',		'N',
X	'H',		'.',		'L',
X	'Y',		'K',		'U'
X  };
X  static char ctrltab[9] = {
X	CTRL('B'),	CTRL('J'),	CTRL('N'),
X	CTRL('H'),	'.',		CTRL('L'),
X	CTRL('Y'),	CTRL('K'),	CTRL('U')
X  };
X  
X  put_qio();
X  command_count = 0;
X  
X  do {
X    macgetkey(&ch, FALSE);
X  } while (ch == CTRL('R'));
X  
X  dir = extractdir(ch, &shift_flag, &ctrl_flag);
X  
X  if (dir != -1) {
X    if (!rogue_like_commands) {
X      ch = '0' + dir;
X    }
X    else {
X      if (ctrl_flag)
X	ch = ctrltab[dir - 1];
X      else if (shift_flag)
X	ch = shifttab[dir - 1];
X      else
X	ch = tab[dir - 1];
X    }
X  }
X  
X  return(ch);
X}
X#endif
X
X
X/* Flush the buffer					-RAK-	*/
Xvoid flush()
X#ifdef MAC
X{
X/* Removed put_qio() call.  Reduces flashing.  Doesn't seem to hurt. */
X  FlushScreenKeys();
X}
X#else
X{
X#ifdef MSDOS
X  while (kbhit())
X	(void) getch();
X#else
X  /* the code originally used ioctls, TIOCDRAIN, or TIOCGETP/TIOCSETP, or
X     TCGETA/TCSETAF, however this occasionally resulted in loss of output,
X     the happened especially often when rlogin from BSD to SYS_V machine,
X     using check_input makes the desired effect a bit clearer */
X  /* wierd things happen on EOF, don't try to flush input in that case */
X  if (!eof_flag)
X    while (check_input(0));
X#endif
X
X  /* used to call put_qio() here to drain output, but it is not necessary */
X}
X#endif
X
X
X/* Clears given line of text				-RAK-	*/
Xvoid erase_line(row, col)
Xint row;
Xint col;
X#ifdef MAC
X{
X  Rect line;
X  
X  if (row == MSG_LINE && msg_flag)
X    msg_print(NULL);
X    
X  line.left = col;
X  line.top = row;
X  line.right = SCRN_COLS;
X  line.bottom = row + 1;
X  DEraseScreen(&line);
X}
X#else
X{
X  if (row == MSG_LINE && msg_flag)
X    msg_print(NULL);
X  (void) move(row, col);
X  clrtoeol();
X}
X#endif
X
X
X/* Clears screen */
Xvoid clear_screen()
X#ifdef MAC
X{
X  Rect area;
X  
X  if (msg_flag)
X    msg_print(NULL);
X    
X  area.left = area.top = 0;
X  area.right = SCRN_COLS;
X  area.bottom = SCRN_ROWS;
X  DEraseScreen(&area);
X}
X#else
X{
X  if (msg_flag)
X    msg_print(NULL);
X  (void) clear();
X}
X#endif
X
Xvoid clear_from (row)
Xint row;
X#ifdef MAC
X{
X  Rect area;
X  
X  area.left = 0;
X  area.top = row;
X  area.right = SCRN_COLS;
X  area.bottom = SCRN_ROWS;
X  DEraseScreen(&area);
X}
X#else
X{
X  (void) move(row, 0);
X  clrtobot();
X}
X#endif
X
X
X/* Outputs a char to a given interpolated y, x position	-RAK-	*/
X/* sign bit of a character used to indicate standout mode. -CJS */
Xvoid print(ch, row, col)
Xchar ch;
Xint row;
Xint col;
X#ifdef MAC
X{
X  char cnow, anow;
X  
X  row -= panel_row_prt;/* Real co-ords convert to screen positions */
X  col -= panel_col_prt;
X  
X  GetScreenCharAttr(&cnow, &anow, col, row);	/* Check current */
X  
X  /* If char is already set, ignore op */
X  if ((cnow != ch) || (anow != ATTR_NORMAL))
X    DSetScreenCharAttr(cnew, anew, col, row);
X}
X#else
X{
X  vtype tmp_str;
X
X  row -= panel_row_prt;/* Real co-ords convert to screen positions */
X  col -= panel_col_prt;
X#if defined(ATARIST_MWC)
X  mvaddch (row, col, ch);
X#else
X  if (mvaddch (row, col, ch) == ERR)
X    {
X      abort();
X      /* clear msg_flag to avoid problems with unflushed messages */
X      msg_flag = 0;
X      (void) sprintf(tmp_str, "error in print, row = %d col = %d\n", row, col);
X      prt(tmp_str, 0, 0);
X      bell ();
X      /* wait so user can see error */
X      (void) sleep(2);
X    }
X#endif
X}
X#endif
X
X
X/* Moves the cursor to a given interpolated y, x position	-RAK-	*/
Xvoid move_cursor_relative(row, col)
Xint row;
Xint col;
X#ifdef MAC
X{
X  row -= panel_row_prt;/* Real co-ords convert to screen positions */
X  col -= panel_col_prt;
X  
X  DSetScreenCursor(col, row);
X}
X#else
X{
X  vtype tmp_str;
X
X  row -= panel_row_prt;/* Real co-ords convert to screen positions */
X  col -= panel_col_prt;
X  if (move (row, col) == ERR)
X    {
X      abort();
X      /* clear msg_flag to avoid problems with unflushed messages */
X      msg_flag = 0;
X      (void) sprintf(tmp_str, "error in move_cursor_relative, row = %d col = %d\n", row, col);
X      prt(tmp_str, 0, 0);
X      bell();
X      /* wait so user can see error */
X      (void) sleep(2);
X    }
X}
X#endif
X
X
X/* Print a message so as not to interrupt a counted command. -CJS- */
Xvoid count_msg_print(p)
Xchar *p;
X{
X  int i;
X
X  i = command_count;
X  msg_print(p);
X  command_count = i;
X}
X
X
X/* Outputs a line to a given y, x position		-RAK-	*/
Xvoid prt(str_buff, row, col)
Xchar *str_buff;
Xint row;
Xint col;
X#ifdef MAC
X{
X  Rect line;
X  
X  if (row == MSG_LINE && msg_flag)
X    msg_print(NULL);
X    
X  line.left = col;
X  line.top = row;
X  line.right = SCRN_COLS;
X  line.bottom = row + 1;
X  DEraseScreen(&line);
X  
X  put_buffer(str_buff, row, col);
X}
X#else
X{
X  if (row == MSG_LINE && msg_flag)
X    msg_print(NULL);
X  (void) move(row, col);
X  clrtoeol();
X  put_buffer(str_buff, row, col);
X}
X#endif
X
X
X/* move cursor to a given y, x position */
Xvoid move_cursor(row, col)
Xint row, col;
X#ifdef MAC
X{
X  DSetScreenCursor(col, row);
X}
X#else
X{
X  (void) move (row, col);
X}
X#endif
X
X
X/* Outputs message to top line of screen				*/
X/* These messages are kept for later reference.	 */
Xvoid msg_print(str_buff)
Xchar *str_buff;
X{
X  register int old_len;
X  char in_char;
X#ifdef MAC
X  Rect line;
X#endif
X
X  if (msg_flag)
X    {
X      old_len = strlen(old_msg[last_msg]) + 1;
X      /* ensure that the complete -more- message is visible. */
X      if (old_len > 73)
X	old_len = 73;
X      put_buffer(" -more-", MSG_LINE, old_len);
X      /* let sigint handler know that we are waiting for a space */
X      wait_for_more = 1;
X      do
X	{
X	  in_char = inkey();
X	}
X      while ((in_char != ' ') && (in_char != ESCAPE) && (in_char != '\n') &&
X	     (in_char != '\r'));
X      wait_for_more = 0;
X    }
X#ifdef MAC
X  line.left = 0;
X  line.top = MSG_LINE;
X  line.right = SCRN_COLS;
X  line.bottom = MSG_LINE+1;
X  DEraseScreen(&line);
X#else
X  (void) move(MSG_LINE, 0);
X  clrtoeol();
X#endif
X
X  /* Make the null string a special case.  -CJS- */
X  if (str_buff)
X    {
X      put_buffer(str_buff, MSG_LINE, 0);
X      command_count = 0;
X      last_msg++;
X      if (last_msg >= MAX_SAVE_MSG)
X	last_msg = 0;
X      (void) strncpy(old_msg[last_msg], str_buff, VTYPESIZ);
X      old_msg[last_msg][VTYPESIZ - 1] = '\0';
X      msg_flag = TRUE;
X    }
X  else
X    msg_flag = FALSE;
X}
X
X
X/* Used to verify a choice - user gets the chance to abort choice.  -CJS- */
Xint get_check(prompt)
Xchar *prompt;
X{
X  int res;
X  int y, x;
X
X  prt(prompt, 0, 0);
X#ifdef MAC
X  GetScreenCursor(&x, &y);
X#else
X  getyx(stdscr, y, x);
X#if defined(lint)
X  /* prevent message 'warning: y is unused' */
X  x = y;
X#endif
X#endif
X
X  if (x > 73)
X#ifdef ATARIST_MWC
X    move(0, 73);
X#else
X    (void) move(0, 73);
X#endif
X#ifdef MAC
X  DWriteScreenStringAttr(" [y/n]", ATTR_NORMAL);
X#else
X  (void) addstr(" [y/n]");
X#endif
X  do
X    {
X      res = inkey();
X    }
X  while(res == ' ');
X  erase_line(0, 0);
X  if (res == 'Y' || res == 'y')
X    return TRUE;
X  else
X    return FALSE;
X}
X
X/* Prompts (optional) and returns ord value of input char	*/
X/* Function returns false if <ESCAPE> is input	*/
Xint get_com(prompt, command)
Xchar *prompt;
Xchar *command;
X{
X  int res;
X
X  if (prompt)
X    prt(prompt, 0, 0);
X  *command = inkey();
X  if (*command == 0 || *command == ESCAPE)
X    res = FALSE;
X  else
X    res = TRUE;
X  erase_line(MSG_LINE, 0);
X  return(res);
X}
X
X#ifdef MAC
X/* Same as get_com(), but translates direction keys from keypad */
Xint get_comdir(prompt, command)
Xchar *prompt;
Xchar *command;
X{
X  int res;
X
X  if (prompt)
X    prt(prompt, 0, 0);
X  *command = inkeydir();
X  if (*command == 0 || *command == ESCAPE)
X    res = FALSE;
X  else
X    res = TRUE;
X  erase_line(MSG_LINE, 0);
X  return(res);
X}
X#endif
X
X
X/* Gets a string terminated by <RETURN>		*/
X/* Function returns false if <ESCAPE> is input	*/
Xint get_string(in_str, row, column, slen)
Xchar *in_str;
Xint row, column, slen;
X{
X  register int start_col, end_col, i;
X  char *p;
X  int flag, aborted;
X#ifdef MAC
X  Rect area;
X#endif
X
X  aborted = FALSE;
X  flag	= FALSE;
X#ifdef MAC
X  area.left = column;
X  area.top = row;
X  area.right = column + slen;
X  area.bottom = row + 1;
X  DEraseScreen(&area);
X  DSetScreenCursor(column, row);
X#else
X  (void) move(row, column);
X  for (i = slen; i > 0; i--)
X    (void) addch(' ');
X  (void) move(row, column);
X#endif
X  start_col = column;
X  end_col = column + slen - 1;
X  if (end_col > 79)
X    {
X      slen = 80 - column;
X      end_col = 79;
X    }
X  p = in_str;
X  do
X    {
X      i = inkey();
X      switch(i)
X	{
X	case ESCAPE:
X	  aborted = TRUE;
X	  break;
X	case CTRL('J'): case CTRL('M'):
X	  flag	= TRUE;
X	  break;
X	case DELETE: case CTRL('H'):
X	  if (column > start_col)
X	    {
X	      column--;
X	      put_buffer(" ", row, column);
X	      move_cursor(row, column);
X	      *--p = '\0';
X	    }
X	  break;
X	default:
X	  if (!isprint(i) || column > end_col)
X	    bell();
X	  else
X	    {
X#ifdef MAC
X	      DSetScreenCursor(column, row);
X	      DWriteScreenCharAttr((char) i, ATTR_NORMAL);
X#else
X	      use_value2 mvaddch(row, column, (char)i);
X#endif
X	      *p++ = i;
X	      column++;
X	    }
X	  break;
X	}
X    }
X  while ((!flag) && (!aborted));
X  if (aborted)
X    return(FALSE);
X  /* Remove trailing blanks	*/
X  while (p > in_str && p[-1] == ' ')
X    p--;
X  *p = '\0';
X  return(TRUE);
X}
X
X
X/* Pauses for user response before returning		-RAK-	*/
Xvoid pause_line(prt_line)
Xint prt_line;
X{
X  prt("[Press any key to continue.]", prt_line, 23);
X  (void) inkey();
X  erase_line(prt_line, 0);
X}
X
X
X/* Pauses for user response before returning		-RAK-	*/
X/* NOTE: Delay is for players trying to roll up "perfect"	*/
X/*	characters.  Make them wait a bit.			*/
Xvoid pause_exit(prt_line, delay)
Xint prt_line;
Xint delay;
X{
X  char dummy;
X
X  prt("[Press any key to continue, or Q to exit.]", prt_line, 10);
X  dummy = inkey();
X  if (dummy == 'Q')
X    {
X      erase_line(prt_line, 0);
X#ifndef MSDOS		/* PCs are slow enough as is  -dgk */
X      if (delay > 0)  (void) sleep((unsigned)delay);
X#endif
X#ifdef MAC
X      enablefilemenu(FALSE);
X      exit_game();
X      enablefilemenu(TRUE);
X#else
X      exit_game();
X#endif
X    }
X  erase_line(prt_line, 0);
X}
X
X#ifdef MAC
Xvoid save_screen()
X{
X  mac_save_screen();
X}
X
Xvoid restore_screen()
X{
X  mac_restore_screen();
X}
X#else
Xvoid save_screen()
X{
X  overwrite(stdscr, savescr);
X}
X
Xvoid restore_screen()
X{
X  overwrite(savescr, stdscr);
X  touchwin(stdscr);
X}
X#endif
X
Xvoid bell()
X{
X  put_qio();
X#ifdef MAC
X  mac_beep();
X#else
X  (void) write(1, "\007", 1);
X#endif
X}
X
X/* definitions used by screen_map() */
X/* index into border character array */
X#define TL 0	/* top left */
X#define TR 1
X#define BL 2
X#define BR 3
X#define HE 4	/* horizontal edge */
X#define VE 5
X
X/* character set to use */
X#ifdef MSDOS
X# ifdef ANSI
X#   define CH(x)	(ansi ? screen_border[0][x] : screen_border[1][x])
X# else
X#   define CH(x)	(screen_border[1][x])
X# endif
X#else
X#   define CH(x)	(screen_border[0][x])
X#endif
X
X  /* Display highest priority object in the RATIO by RATIO area */
X#define	RATIO 3
X
Xvoid screen_map()
X{
X  register int	i, j;
X  static int8u screen_border[2][6] = {
X    {'+', '+', '+', '+', '-', '|'},	/* normal chars */
X    {201, 187, 200, 188, 205, 186}	/* graphics chars */
X  };
X  int8u map[MAX_WIDTH / RATIO + 1];
X  int8u tmp;
X  int priority[256];
X  int row, orow, col, myrow, mycol = 0;
X#ifndef MAC
X  char prntscrnbuf[80];
X#endif
X
X  for (i = 0; i < 256; i++)
X    priority[i] = 0;
X  priority['<'] = 5;
X  priority['>'] = 5;
X  priority['@'] = 10;
X#ifdef MSDOS
X  priority[wallsym] = -5;
X  priority[floorsym] = -10;
X#else
X  priority['#'] = -5;
X  priority['.'] = -10;
X#endif
X  priority['\''] = -3;
X  priority[' '] = -15;
X
X  save_screen();
X  clear_screen();
X#ifdef MAC
X  DSetScreenCursor(0, 0);
X  DWriteScreenCharAttr(CH(TL), ATTR_NORMAL);
X  for (i = 0; i < MAX_WIDTH / RATIO; i++)
X    DWriteScreenCharAttr(CH(HE), ATTR_NORMAL);
X  DWriteScreenCharAttr(CH(TR), ATTR_NORMAL);
X#else
X  use_value2 mvaddch(0, 0, CH(TL));
X  for (i = 0; i < MAX_WIDTH / RATIO; i++)
X    (void) addch(CH(HE));
X  (void) addch(CH(TR));
X#endif
X  orow = -1;
X  map[MAX_WIDTH / RATIO] = '\0';
X  for (i = 0; i < MAX_HEIGHT; i++)
X    {
X      row = i / RATIO;
X      if (row != orow)
X	{
X	  if (orow >= 0)
X	    {
X#ifdef MAC
X	      DSetScreenCursor(0, orow+1);
X	      DWriteScreenCharAttr(CH(VE), ATTR_NORMAL);
X	      DWriteScreenString(map);
X	      DWriteScreenCharAttr(CH(VE), ATTR_NORMAL);
X#else
X	      /* can not use mvprintw() on ibmpc, because PC-Curses is horribly
X		 written, and mvprintw() causes the fp emulation library to be
X		 linked with PC-Moria, makes the program 10K bigger */
X	      (void) sprintf(prntscrnbuf,"%c%s%c",CH(VE), map, CH(VE));
X	      use_value2 mvaddstr(orow+1, 0, prntscrnbuf);
X#endif
X	    }
X	  for (j = 0; j < MAX_WIDTH / RATIO; j++)
X	    map[j] = ' ';
X	  orow = row;
X	}
X      for (j = 0; j < MAX_WIDTH; j++)
X	{
X	  col = j / RATIO;
X	  tmp = loc_symbol(i, j);
X	  if (priority[map[col]] < priority[tmp])
X	    map[col] = tmp;
X	  if (map[col] == '@')
X	    {
X	      mycol = col + 1; /* account for border */
X	      myrow = row + 1;
X	    }
X	}
X    }
X  if (orow >= 0)
X    {
X#ifdef MAC
X      DSetScreenCursor(0, orow+1);
X      DWriteScreenCharAttr(CH(VE), ATTR_NORMAL);
X      DWriteScreenString(map);
X      DWriteScreenCharAttr(CH(VE), ATTR_NORMAL);
X#else
X      (void) sprintf(prntscrnbuf,"%c%s%c",CH(VE), map, CH(VE));
X      use_value2 mvaddstr(orow+1, 0, prntscrnbuf);
X#endif
X    }
X#ifdef MAC
X  DSetScreenCursor(0, orow + 2);
X  DWriteScreenCharAttr(CH(BL), ATTR_NORMAL);
X  for (i = 0; i < MAX_WIDTH / RATIO; i++)
X    DWriteScreenCharAttr(CH(HE), ATTR_NORMAL);
X  DWriteScreenCharAttr(CH(BR), ATTR_NORMAL);
X#else
X  use_value2 mvaddch(orow + 2, 0, CH(BL));
X  for (i = 0; i < MAX_WIDTH / RATIO; i++)
X    (void) addch(CH(HE));
X  (void) addch(CH(BR));
X#endif
X
X#ifdef MAC
X  DSetScreenCursor(23, 23);
X  DWriteScreenStringAttr("Hit any key to continue", ATTR_NORMAL);
X  if (mycol > 0)
X    DSetScreenCursor(mycol, myrow);
X#else
X  use_value2 mvaddstr(23, 23, "Hit any key to continue");
X  if (mycol > 0)
X    (void) move(myrow, mycol);
X#endif
X  (void) inkey();
X  restore_screen();
X}
END_OF_FILE
if test 29702 -ne `wc -c <'source/io.c'`; then
    echo shar: \"'source/io.c'\" unpacked with wrong size!
fi
# end of 'source/io.c'
fi
if test -f 'util/mc/creature.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util/mc/creature.y'\"
else
echo shar: Extracting \"'util/mc/creature.y'\" \(26718 characters\)
sed "s/^X//" >'util/mc/creature.y' <<'END_OF_FILE'
X/*
X * creature_comp.y
X *	a Moria creature definition compiler
X *
X * Copyright 1989 by Joseph Hall.
X * All rights reserved except as stated below.
X * This program may contain portions excerpted from Moria which are
X * copyrighted by others.
X *
X * Jim Wilson and any other holders of copyright on substantial portions
X * of Moria are granted rights to use, modify, and distribute this program
X * as they see fit, so long as the terms of its use, modification and/or
X * distribution are no less restrictive than those applying to Moria,
X * version 5.0 or later, itself, and so long as this use is related to
X * the further development of Moria.
X *
X * Anyone having any other use in mind for this code should contact the
X * author at 4116 Brewster Dr., Raleigh NC 27606 (jnh@ecemwl.ncsu.edu).
X */
X
X%{
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include <math.h>
X
X#ifdef ANSI_LIBS
X#include <stdlib.h>
X#else
Xextern double atof();
Xextern char *malloc();
Xextern char *calloc();
Xextern void free();
X#endif
X
X#include "st.h"
X
X#ifndef TRUE
X#define TRUE 1
X#endif
X
X#ifndef FALSE
X#define FALSE 0
X#endif
X
X#define VERBOSE /* to turn on debugging output */
X
Xtypedef unsigned long  int32u;
Xtypedef long           int32;
Xtypedef unsigned short int16u;
Xtypedef short          int16;
Xtypedef unsigned char  int8u;
X
Xtypedef struct creature_type
X{
X  char *name;           /* Descrip of creature  */
X  int32u cmove;         /* Bit field            */
X  int32u spells;        /* Creature spells      */
X  int16u cdefense;      /* Bit field            */
X  int16u mexp;          /* Exp value for kill   */
X  int8u sleep;          /* Inactive counter/10  */
X  int8u aaf;            /* Area affect radius   */
X  int8u ac;             /* AC                   */
X  int8u speed;          /* Movement speed+10    */
X  int8u cchar;          /* Character rep.       */
X  int8u hd[2];          /* Creatures hit die    */
X  int8u damage[4];      /* Type attack and damage*/
X  int8u level;          /* Level of creature    */
X
X	int32u general;	/* general characteristics; not present in usual */
X			/* moria creature_type */
X} creature_type;
X
X
X
X/*
X * defined_t is used to indicate whether all fields have been defined
X */
X
Xtypedef struct {
X    unsigned	move: 1,
X		special: 1,
X		treasure: 1,
X		spell: 1,
X		breath: 1,
X		defense: 1,
X		mexp: 1,
X		sleep: 1,
X		aaf: 1,
X		ac: 1,
X		speed: 1,
X		cchar: 1,
X		hd: 1,
X		damage: 1,
X		level: 1;
X} defined_t;
X
X
X
X/*
X * template_t contains creature definition & flags
X */
X
Xtypedef struct {
X	creature_type	val;
X	defined_t	def;
X} template_t;
X
X
X
X/*
X * attack_t describes a monster attack
X */
X
Xtypedef struct {
X	int8u		type,
X			desc,
X			dice,
X			sides;
X} attack_t;
X
X
X
X/*
X * symInit_t is used to initialize symbol tables with integer values
X */
X
Xtypedef struct {
X	char		*name;
X	int32u		val;
X} symInit_t;
X
X
X
Xstatic symInit_t defenseInit[] = {
X	{ "dragon", 0 },
X	{ "animal", 1 },
X	{ "evil", 2 },
X	{ "undead", 3 },
X	{ "frost", 4 },
X	{ "fire", 5 },
X	{ "poison", 6 },
X	{ "acid", 7 },
X	{ "light", 8 },
X	{ "stone", 9 },
X	{ "bit_9", 10 },
X	{ "bit_10", 11 },
X	{ "no_sleep", 12 },
X	{ "infra", 13 },
X	{ "max_hp", 14 },
X	{ "bit_15", 15 },
X	{ NULL, 0 }
X};
X
Xstatic symInit_t moveInit[] = {
X	{ "attack_only", 0 },
X	{ "move_normal", 1 },
X	{ "bit_2", 2 },
X	{ "random_20", 3 },
X	{ "random_40", 4 },
X	{ "random_75", 5 },
X	{ NULL, 0 }
X};
X
Xstatic symInit_t specialInit[] = {
X	{ "invisible", 16 },
X	{ "open_door", 17 },
X	{ "phase", 18 },
X	{ "eats_other", 19 },
X	{ "picks_up", 20 },
X	{ "multiply", 21 },
X	{ "win_creature", 31 },
X	{ NULL, 0 }
X};
X
Xstatic symInit_t treasureInit[] = {
X	{ "carry_obj", 24 },
X	{ "carry_gold", 25 },
X	{ "has_random_60", 26 },
X	{ "has_random_90", 27 },
X	{ "has_1d2_obj", 28 },
X	{ "has_2d2_obj", 29 },
X	{ "has_4d2_obj", 30 },
X	{ NULL, 0 }
X};
X
Xstatic symInit_t spellInit[] = {
X	{ "tel_short", 4 },
X	{ "tel_long", 5 },
X	{ "tel_to", 6 },
X	{ "lght_wnd", 7 },
X	{ "ser_wnd", 8 },
X	{ "hold_per", 9 },
X	{ "blind", 10 },
X	{ "confuse", 11 },
X	{ "fear", 12 },
X	{ "summon_mon", 13 },
X	{ "summon_und", 14 },
X	{ "slow_per", 15 },
X	{ "drain_mana", 16 },
X	{ "bit_17", 17 },
X	{ "bit_18", 18 },
X	{ NULL, 0 }
X};
X
Xstatic symInit_t breathInit[] = {
X	{ "light", 19 },
X	{ "gas", 20 },
X	{ "acid", 21 },
X	{ "frost", 22 },
X	{ "fire", 23 },
X	{ NULL, 0 }
X};
X
Xstatic symInit_t attackTypeInit[] = {
X	{ "normal_damage", 1 },
X	{ "lose_str", 2 },
X	{ "confusion", 3 },
X	{ "cause_fear", 4 },
X	{ "fire_damage", 5 },
X	{ "acid_damage", 6 },
X	{ "cold_damage", 7 },
X	{ "lightning_damage", 8 },
X	{ "corrosion", 9 },
X	{ "cause_blindness", 10 },
X	{ "cause_paralysis", 11 },
X	{ "steal_money", 12 },
X	{ "steal_obj", 13 },
X	{ "poison", 14 },
X	{ "lose_dex", 15 },
X	{ "lose_con", 16 },
X	{ "lose_int", 17 },
X	{ "lose_wis", 18 },
X	{ "lose_exp", 19 },
X	{ "aggravation", 20 },
X	{ "disenchant", 21 },
X	{ "eat_food", 22 },
X	{ "eat_light", 23 },
X	{ "eat_charges", 24 },
X	{ "blank", 99 },
X	{ NULL, 0 }
X};
X
Xstatic symInit_t attackDescInit[] = {
X	{ "hits", 1 },
X	{ "bites", 2 },
X	{ "claws", 3 },
X	{ "stings", 4 },
X	{ "touches", 5 },
X	{ "kicks", 6 },
X	{ "gazes", 7 },
X	{ "breathes", 8 },
X	{ "spits", 9 },
X	{ "wails", 10 },
X	{ "embraces", 11 },
X	{ "crawls_on", 12 },
X	{ "releases_spores", 13 },
X	{ "begs_for_money", 14 },
X	{ "slimes", 15 },
X	{ "crushes", 16 },
X	{ "tramples", 17 },
X	{ "drools_on", 18 },
X	{ "insults", 19 },
X	{ "is_repelled", 99 },
X	{ NULL, 0 }
X};
X
X
X
X
X/*
X * Maximum token length = maximum string constant length
X * Also, trim the stack to an "acceptable" size.
X */
X
X#define	MAX_TOK_LEN	64		/* maximum acceptable token length  */
X#define	YYSTACKSIZE	128
X
X#define GEN_TYPE_TMPL	256		/* type of a template for st	    */
X
X/*
X * Globals used by the tokenizer (lexical analyzer)
X */
X
X#define INPUT_BUF_SIZE 256
Xstatic char	inputBuf[INPUT_BUF_SIZE] = { 0 }; 
X					/* input line buffer		    */
Xstatic char	*inputBufp = inputBuf;	/* position in input line buffer    */
Xstatic int	lineNo = 0;		/* number of current line	    */
Xstatic FILE	*input_F;
Xstatic char	tokStr[MAX_TOK_LEN];	/* text of current token	    */
Xstatic	int	tokType;		/* type of current token	    */
Xstatic	double	tokVal;			/* numeric value of current token,  */
X					/* if applicable		    */
X
Xstatic template_t blankTemplate = { 0 }; /* blank template for init-ing     */
Xstatic template_t tmpTemplate;		/* working template for current     */
X					/* class or creature		    */
X
X#define MAX_ATTACK 250
Xstatic attack_t attackList[MAX_ATTACK] = { 0 };
Xstatic int attackCt = 1, creatureAttacks = 0;
Xstatic int maxCreatureLevel = 0;
X
X/*
X * Global symbol tables
X */
X
Xstatic st_Table_Pt keywordT_P,		/* parser's keywords		    */
X		defenseT_P,		/* defense flags		    */
X		moveT_P,		/* movement flags		    */
X		specialT_P,		/* special flags		    */
X		treasureT_P,		/* treasure flags		    */
X		spellT_P,		/* spell flags			    */
X		breathT_P,		/* breath flags			    */
X		attackTypeT_P,		/* attack type flags		    */
X		attackDescT_P,		/* attack desc flags		    */
X		classT_P,		/* class templates		    */
X		creatureT_P;		/* creature definitions		    */
X
X/*
X * Function declarations
X */
X
Xextern void AddDefense();
Xextern void NegDefense();
Xextern void AddMove();
Xextern void NegMove();
Xextern void AddTreasure();
Xextern void NegTreasure();
Xextern void AddSpecial();
Xextern void NegSpecial();
Xextern void AddSpell();
Xextern void NegSpell();
Xextern void AddBreath();
Xextern void NegBreath();
Xextern void AddAttack();
Xextern void WriteCreature();
Xextern void PutClassTemplate();
Xextern template_t GetClassTemplate();
Xextern void PutCreature();
X
X%}
X
X
X/*
X * YACC DEFINITIONS
X */
X
X/*
X * The parser's stack can hold ints, doubles, and strings.
X */
X
X%union {
X	int ival;
X	double dval;
X	char sval[MAX_TOK_LEN];
X	}
X
X/*
X * Reserved words
X */
X
X%token CLASS CREATURE NAMED HD D MOVE SPELL BREATH DEFENSE XP CCHAR SLEEP
X%token RADIUS SPEED ATTACK FOR AC LEVEL TREASURE SPECIAL OF IN
X
X/*
X * Entities
X */
X
X%token <sval> IDENTIFIER	/* identifier, not a keyword		    */
X%token <dval> FLOAT_LIT		/* floating-pt literal			    */
X%token <ival> INT_LIT		/* integer literal			    */
X%token <sval> STRING_LIT	/* string literal			    */
X%token <ival> BOOL_LIT		/* boolean literal			    */
X
X/*
X * ASCII chars are their own tokens
X */
X
X%start	creatures
X
X
X/*
X * THE PARSER
X */
X
X%%
X
Xcreatures	:	class_def ';' creatures
X		|	creature_def ';' creatures
X		|	/* empty */
X		;
X
Xclass_def	:	CLASS IDENTIFIER parent_class '{' features '}'
X				{ PutClassTemplate($<sval>2, &tmpTemplate); }
X		;
X
Xparent_class	:	':' IDENTIFIER
X				{ tmpTemplate = GetClassTemplate($<sval>2);
X				  creatureAttacks = 0; }
X		|	/* empty */
X				{ tmpTemplate = blankTemplate;
X				  creatureAttacks = 0; }
X		;
X
Xcreature_def	:	CREATURE STRING_LIT parent_class 
X			'{' features '}'
X				{ tmpTemplate.val.name = 
X				    (char *) malloc(strlen($<sval>2) + 1);
X				  strcpy(tmpTemplate.val.name, $<sval>2);
X				  PutCreature($<sval>2, &tmpTemplate);
X				}
X		;
X
Xfeatures	:	feature ';' features
X		|	/* empty */
X		;
X
Xfeature		:	LEVEL ':' INT_LIT
X				{ tmpTemplate.val.level = $<ival>3;
X				  tmpTemplate.def.level = TRUE; }
X		|	HD ':' INT_LIT D INT_LIT
X				{ tmpTemplate.val.hd[0] = $<ival>3;
X				  tmpTemplate.val.hd[1] = $<ival>5;
X				  tmpTemplate.def.hd = TRUE; }
X		|	XP ':' INT_LIT
X				{ tmpTemplate.val.mexp = $<ival>3;
X				  tmpTemplate.def.mexp = TRUE; }
X		|	CCHAR ':' STRING_LIT
X				{ tmpTemplate.val.cchar = $<sval>3[0];
X				  tmpTemplate.def.cchar = TRUE; }
X		|	AC ':' INT_LIT
X				{ tmpTemplate.val.ac = $<ival>3;
X				  tmpTemplate.def.ac = TRUE; }
X		|	SLEEP ':' INT_LIT
X				{ tmpTemplate.val.sleep = $<ival>3;
X				  tmpTemplate.def.sleep = TRUE; }
X		|	RADIUS ':' INT_LIT
X				{ tmpTemplate.val.aaf = $<ival>3;
X				  tmpTemplate.def.aaf = TRUE; }
X		|	SPEED ':' INT_LIT
X				{ tmpTemplate.val.speed = $<ival>3 + 10;
X				  tmpTemplate.def.speed = TRUE; }
X		|	ATTACK ':' attacks
X		|	MOVE ':' moves
X		|	SPELL ':' spells
X		|	SPELL INT_LIT '%' ':' spells
X				{ float chance = 100.0 / $<ival>2;
X				  if (chance > 15.0)
X				  	chance = 0.0;
X				  if (chance < 0.0)
X				  	chance = 0.0;
X				  tmpTemplate.val.spells &= ~0xf;
X				  tmpTemplate.val.spells |=
X				  	(int) ceil(chance);
X				  tmpTemplate.def.spell = TRUE; }
X		|	BREATH ':' breaths
X		|	BREATH INT_LIT '%' ':' breaths
X				{ float chance = 100.0 / $<ival>2;
X				  if (chance > 15.0)
X				  	chance = 0.0;
X				  if (chance < 0.0)
X				  	chance = 0.0;
X				  tmpTemplate.val.spells &= ~0xf;
X				  tmpTemplate.val.spells |=
X				  	(int) ceil(chance);
X				  tmpTemplate.def.spell = TRUE; }
X		|	DEFENSE ':' defenses
X		|	TREASURE ':' carries
X		|	SPECIAL ':' specials
X		;
X
Xattacks		:	attack more_attacks
X		;
X
Xattack		:	IDENTIFIER FOR INT_LIT D INT_LIT OF IDENTIFIER
X				{ AddAttack($<sval>1, $<ival>3,
X						$<ival>5, $<sval>7); }
X		;
X
Xmore_attacks	:	',' attack more_attacks
X		|	/* empty */
X		;
X
Xmoves		:	move more_moves
X		;
X
Xmove		:	IDENTIFIER { AddMove($<sval>1); }
X		|	'~' IDENTIFIER { NegMove($<sval>2); }
X		;
X
Xmore_moves	:	',' move more_moves
X		|	/* empty */
X		;
X
Xspells		:	spell more_spells
X		|	/* empty */
X		;
X
Xspell		:	IDENTIFIER { AddSpell($<sval>1); }
X		|	'~' IDENTIFIER { NegSpell($<sval>2); }
X		;
X
Xmore_spells	:	',' spell more_spells
X		|	/* empty */
X		;
X
Xbreaths		:	breath more_breaths
X		;
X
Xbreath		:	IDENTIFIER { AddBreath($<sval>1); }
X		|	'~' IDENTIFIER { NegBreath($<sval>2); }
X		;
X
Xmore_breaths	:	',' breath more_breaths
X		|	/* empty */
X		;
X
Xdefenses	:	defense more_defenses
X		;
X
Xdefense		:	IDENTIFIER { AddDefense($<sval>1); }
X		|	'~' IDENTIFIER { NegDefense($<sval>2); }
X		;
X
Xmore_defenses	:	',' defense more_defenses
X		|	/* empty */
X		;
X
Xcarries		:	carry more_carries
X		;
X
Xcarry		:	IDENTIFIER { AddTreasure($<sval>1); }
X		|	'~' IDENTIFIER { NegTreasure($<sval>2); }
X		;
X
Xmore_carries	:	',' carry more_carries
X		|	/* empty */
X		;
X
Xspecials	:	special more_specials
X		;
X
Xspecial		:	IDENTIFIER { AddSpecial($<sval>1); }
X		|	'~' IDENTIFIER { NegSpecial($<sval>2); }
X		;
X
Xmore_specials	:	',' special more_specials
X		|	/* empty */
X		;
X
X		
X%%
X
Xstatic symInit_t keywordInit[] = {
X	{ "class", CLASS },
X	{ "creature", CREATURE },
X	{ "named", NAMED },
X	{ "hd", HD },
X	{ "d", D },
X	{ "move", MOVE },
X	{ "spell", SPELL },
X	{ "breath", BREATH },
X	{ "defense", DEFENSE },
X	{ "xp", XP },
X	{ "cchar", CCHAR },
X	{ "sleep", SLEEP },
X	{ "radius", RADIUS },
X	{ "speed", SPEED },
X	{ "attack", ATTACK },
X	{ "for", FOR },
X	{ "ac", AC },
X	{ "level", LEVEL },
X	{ "treasure", TREASURE },	
X	{ "special", SPECIAL },
X	{ "of", OF },
X	{ "in", IN },
X	{ NULL, 0 }
X};
X
X
X
X/*
X * MyFGetC--
X *	fgetc with support for comments
X *
X *	# is the comment character.  comment lasts till end of line.
X * Spews out an extra char of whitespace at EOF since something seems to
X * need it.  I'll figure this out eventually...
X */
Xstatic int MyFGetC(input_F)
XFILE *input_F;
X{
X    static int atEof = FALSE;
X    while (!*inputBufp || (*inputBufp == '#')) {
X	fgets(inputBuf, INPUT_BUF_SIZE, input_F);
X    	if (feof(input_F))
X	    return EOF;
X	lineNo++;
X	inputBufp = inputBuf;
X    }
X    return *inputBufp++;
X}
X
X
X
X/*
X * Advance--
X *	Advance to the next token in the input stream and set tokStr, 
X * tokType, tokVal as appropriate.
X *
X *	On error, tokType is set to a negative value.
X */
Xstatic void Advance(input_F)
XFILE *input_F;
X{
X
X    register char
X	    *tok = tokStr;	/* accumulating token string		    */
X    register int
X	    len = 0;		/* length of current token		    */
X    static int c = 32;		/* current character; ' ' is harmless init  */
X
X
X    /*
X     * Skip whitespace in the stream
X     */
X    while ((c != EOF) && isspace(c))
X	c = MyFGetC(input_F);
X
X    /*
X     * At end of file?
X     */
X    if (c == EOF) {
X	tokType = EOF;
X	strcpy(tokStr, "[EOF]");
X	return;
X    }
X
X    /*
X     * Recognize a number [+|-][dddd][.][dddd][{e|E}[+|-]dddd]
X     */
X    if (isdigit(c) || (c == '.') || (c == '+') || (c == '-')) {
X
X	register int 
X		decPt = FALSE,	    /* seen a decimal point yet?	*/
X		hasExp = FALSE;	    /* has an exponent?			*/
X
X	if ((c == '-') || (c == '+')) {
X	    *tok++ = c;
X	    c = MyFGetC(input_F);
X	}
X
X	while ((len < MAX_TOK_LEN - 1) && (isdigit(c) || (c == '.'))) {
X	    if (c == '.') {
X		if (decPt)
X		    break;
X		else
X		    decPt = TRUE;
X	    }
X
X	    *tok++ = c;
X	    c = MyFGetC(input_F);
X	    len++;
X	}
X
X	if ((c == 'e') || (c == 'E')) {
X	    hasExp = TRUE;
X	    *tok++ = c;
X	    c = MyFGetC(input_F);
X	    len++;
X
X	    if ((c == '-') || (c == '+')) {
X		*tok++ = c;
X		c = MyFGetC(input_F);
X		len++;
X	    }
X
X	    while ((len < MAX_TOK_LEN - 1) && isdigit(c)) {
X		*tok++ = c;
X		c = MyFGetC(input_F);
X		len++;
X	    }
X	}
X
X	*tok = 0;
X
X	if (decPt || hasExp) {
X	    tokType = FLOAT_LIT;
X	    yylval.dval = atof(tokStr);
X	} else {
X	    tokType = INT_LIT;
X	    yylval.ival = atoi(tokStr);
X	}
X
X	return;
X
X    }
X
X    /*
X     * Recognize a quoted string
X     */
X    if (c == '\"') {
X
X	c = MyFGetC(input_F);
X
X	while ((len < MAX_TOK_LEN - 1) &&
X			    (c != EOF) && (c != '\n') && (c != '\"')) {
X	    *tok++ = c;
X	    c = MyFGetC(input_F);
X	}
X
X	*tok = 0;
X
X	c = MyFGetC(input_F);
X
X	tokType = STRING_LIT;
X	strncpy(yylval.sval, tokStr, MAX_TOK_LEN - 1);
X	yylval.sval[MAX_TOK_LEN - 1] = 0;
X
X	return;
X
X    }
X
X    /*
X     * Recognize an identifier and try to match it with a keyword.
X     * Identifiers begin with a letter and continue in letters and/or
X     * digits.  Convert it to lowercase.
X     */
X    if (isalpha(c) || (c == '_') || (c == '$')) {
X
X        if (isupper(c))
X	  c = tolower(c);
X        *tok++ = c;
X	c = MyFGetC(input_F);
X	len++;
X
X	while ((len < MAX_TOK_LEN - 1) && (isalpha(c) || isdigit(c) ||
X						(c == '_') || (c == '$'))) {
X	    if (isupper(c))
X	      c = tolower(c);
X	    *tok++ = c;
X	    c = MyFGetC(input_F);
X	    len++;
X	}
X
X	*tok = 0;
X
X	/*
X	 * We've got the identifier; see if it matches any keywords.
X	 */
X
X	{
X		generic_t gval;
X		int type;
X		if (St_GetSym(keywordT_P, tokStr, &type, &gval) ==
X								ST_SYM_FOUND) {
X			tokType = gval.i;
X		        strncpy(yylval.sval, tokStr, MAX_TOK_LEN - 1);
X			yylval.sval[MAX_TOK_LEN - 1] = 0;
X		} else if (!strcmp(tokStr, "true")) {
X		    tokType = BOOL_LIT;
X		    yylval.ival = 1;
X		} else if (!strcmp(tokStr, "false")) {
X		    tokType = BOOL_LIT;
X		    yylval.ival = 0;
X		} else {
X		    tokType = IDENTIFIER;
X		    strncpy(yylval.sval, tokStr, MAX_TOK_LEN - 1);
X		    yylval.sval[MAX_TOK_LEN - 1] = 0;
X		}
X	}
X
X	return;
X
X    }
X
X    /*
X     * Recognize punctuation
X     */
X
X    tokType = c;
X    *tok++ = c;
X    *tok = 0;
X    c = MyFGetC(input_F);
X    return;
X
X}
X
Xvoid ErrMsg(s)
Xchar *s;
X{	
X	int i;
X
X	fprintf(stderr, "Error: %s at line %d\n", s, lineNo);
X	fprintf(stderr, "%s", inputBuf);
X	for (i = 0; i < inputBufp - inputBuf; i++) {
X		fputc((inputBuf[i] == '\t' ? '\t' : ' '), stderr);
X	}
X	fprintf(stderr, "^ before here\n\n");
X}
X
Xint yyerror(s)
Xchar *s;
X{
X	ErrMsg(s);
X}
X
X
Xint yylex()
X{
X	Advance(input_F);
X	return(tokType);
X}
X
Xvoid AddSpell(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(spellT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown spell '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.spells |= (1 << gval.i);
X		tmpTemplate.def.spell = TRUE;
X	}
X}
X	
X
Xvoid NegSpell(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(spellT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown spell '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.spells &= ~(1 << gval.i);
X		tmpTemplate.def.spell = TRUE;
X	}
X}
X	
X
Xvoid AddBreath(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(breathT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown breath '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.spells |= (1 << gval.i);
X		tmpTemplate.def.breath = TRUE;
X	}
X}
X	
X
Xvoid NegBreath(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(breathT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown breath '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.spells &= ~(1 << gval.i);
X		tmpTemplate.def.breath = TRUE;
X	}
X}
X	
X
Xvoid AddSpecial(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(specialT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown special '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.cmove |= (1 << gval.i);
X		tmpTemplate.def.special = TRUE;
X	}
X}
X	
X
Xvoid NegSpecial(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(specialT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown special '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.cmove &= ~(1 << gval.i);
X		tmpTemplate.def.special = TRUE;
X	}
X}
X	
X
Xvoid AddMove(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(moveT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown move '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.cmove |= (1 << gval.i);
X		tmpTemplate.def.move = TRUE;
X	}
X}
X	
X
Xvoid NegMove(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(moveT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown move '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.cmove &= ~(1 << gval.i);
X		tmpTemplate.def.move = TRUE;
X	}
X}
X	
X
Xvoid AddTreasure(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(treasureT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown treasure '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.cmove |= (1 << gval.i);
X		tmpTemplate.def.treasure = TRUE;
X	}
X}
X	
X
Xvoid NegTreasure(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(treasureT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown treasure '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.cmove &= ~(1 << gval.i);
X		tmpTemplate.def.treasure = TRUE;
X	}
X}
X	
X
Xvoid AddDefense(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(defenseT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown defense '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.cdefense |= (1 << gval.i);
X		tmpTemplate.def.defense = TRUE;
X	}
X}
X	
X
Xvoid NegDefense(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(defenseT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "unknown defense '%s'", s);
X		ErrMsg(s1);
X	} else {
X		tmpTemplate.val.cdefense &= ~(1 << gval.i);
X		tmpTemplate.def.defense = TRUE;
X	}
X}
X	
X
Xint PutAttack(attack)
Xattack_t attack;
X{
X	register int i;
X
X	for (i = 0; i < attackCt; i++) {
X		if ((attack.type == attackList[i].type) &&
X		    (attack.desc == attackList[i].desc) &&
X		    (attack.dice == attackList[i].dice) &&
X		    (attack.sides == attackList[i].sides)) {
X		    	return(i);
X		}
X	}
X
X	if (attackCt == MAX_ATTACK) {
X		fprintf(stderr, "fatal error: too many different attacks.\n");
X		fprintf(stderr, "increase MAX_ATTACK.\n");
X		exit(1);
X	}
X
X	attackList[attackCt].type = attack.type;
X	attackList[attackCt].desc = attack.desc;
X	attackList[attackCt].dice = attack.dice;
X	attackList[attackCt].sides = attack.sides;
X	
X	return attackCt++;
X}
X
Xvoid AddAttack(s1, dice, sides, s2)
Xchar *s1, *s2; 
Xint dice, sides; 
X{
X	generic_t gval;
X	int type, aDesc;
X	attack_t attack;
X	char s[256];
X	
X	if (St_GetSym(attackDescT_P, s1, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s, "unknown attack description '%s'", s1);
X		ErrMsg(s);
X		return;
X	} else {
X		aDesc = gval.i;
X	}
X
X	if (St_GetSym(attackTypeT_P, s2, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s, "unknown attack type '%s'", s2);
X		ErrMsg(s);
X	} else {
X		if (creatureAttacks > 3) {
X			sprintf(s, "creature limited to 4 attacks");
X			ErrMsg(s);
X			return;
X		}			
X		attack.type = gval.i;
X		attack.dice = dice;
X		attack.desc = aDesc;
X		attack.sides = sides;
X		tmpTemplate.val.damage[creatureAttacks++] = 
X						PutAttack(attack);
X		tmpTemplate.def.damage = TRUE;
X	}
X}
X
Xst_Table_Pt InitTable(name, init)
Xchar *name;
XsymInit_t *init;
X{
X	int i;
X	st_Table_Pt table_P;
X	generic_t gval;
X
X	table_P = St_NewTable(name, 20);
X	for (i = 0; init[i].name; i++) {
X		gval.i = init[i].val;
X		St_DefSym(table_P, init[i].name, GEN_TYPE_INT, gval);
X	}
X
X	return table_P;
X}
X	
X
Xvoid InitTables()
X{
X	int i;
X	generic_t gval;
X
X	keywordT_P = InitTable("keyword", keywordInit);
X	defenseT_P = InitTable("defense", defenseInit);
X	spellT_P = InitTable("spell", spellInit);
X	moveT_P = InitTable("move", moveInit);
X	specialT_P = InitTable("special", specialInit);
X	breathT_P = InitTable("breath", breathInit);
X	treasureT_P = InitTable("treasure", treasureInit);
X	attackTypeT_P = InitTable("attackType", attackTypeInit);
X	attackDescT_P = InitTable("attackDesc", attackDescInit);
X	
X	classT_P = St_NewTable("class", 40);
X	creatureT_P = St_NewTable("creature", 200);
X}
X
Xvoid WriteCreature(tmpl_P)
Xtemplate_t *tmpl_P;
X{
X	char s[256];
X	strcpy(s, "\"");
X	strcat(s, tmpl_P->val.name);
X	strcat(s, "\"");
X	printf("{%-28s, 0x%08x,0x%06x,0x%04x,%5d,%3d,\n",
X		s, tmpl_P->val.cmove, tmpl_P->val.spells,
X		tmpl_P->val.cdefense, tmpl_P->val.mexp, tmpl_P->val.sleep);
X	printf(" %2d, %3d, %2d, '%c', {%3d,%2d}, {%3d,%3d,%3d,%3d}, %3d},\n",
X		tmpl_P->val.aaf, tmpl_P->val.ac, tmpl_P->val.speed, 
X		tmpl_P->val.cchar,
X		tmpl_P->val.hd[0], tmpl_P->val.hd[1], 
X		tmpl_P->val.damage[0], tmpl_P->val.damage[1], 
X		tmpl_P->val.damage[2], tmpl_P->val.damage[3],
X		tmpl_P->val.level);
X}
X
Xvoid WriteCreatures()
X{
X	char **s_A, **sp;
X	int level, type;
X	generic_t gval;
X	
X	s_A = St_SListTable(creatureT_P);
X	
X	printf("creature_type c_list[MAX_CREATURES] = {\n");
X	
X	for (level = 0; level <= maxCreatureLevel; level++) {
X	    for (sp = s_A; *sp; sp++) {
X		if (St_GetSym(creatureT_P, *sp, &type, &gval) !=
X							ST_SYM_FOUND) {
X			fprintf(stderr, "internal err. in WriteCreatures\n");
X			exit(1);
X		}
X		if ((*(template_t *) gval.v).val.level == level) {
X			WriteCreature((template_t *) gval.v);
X		}
X	   }
X	}
X	
X	printf("};\n\n");
X	
X	St_SListTable(NULL);
X}
X
Xvoid PutClassTemplate(s, tmpl_P)
Xchar *s; 
Xtemplate_t *tmpl_P;
X{
X	generic_t gval;
X	char s1[256];
X	
X	gval.v = malloc(sizeof(template_t));
X	*(template_t *) gval.v = *tmpl_P;
X
X	if (St_DefSym(classT_P, s, GEN_TYPE_TMPL, gval) == ST_SYM_FOUND) {
X		sprintf(s1, "attempt to redefine class '%s'", s);
X		ErrMsg(s1);
X		free(gval.v);
X		return;
X	}
X}	
X	
X
Xtemplate_t GetClassTemplate(s)
Xchar *s;
X{
X	generic_t gval;
X	int type;
X	char s1[256];
X	
X	if (St_GetSym(classT_P, s, &type, &gval) != ST_SYM_FOUND) {
X		sprintf(s1, "class '%s' undefined\n", s);
X		ErrMsg(s1);
X		return blankTemplate;
X	} else {
X		return *(template_t *) gval.v;
X	}
X}
X
X
X
X
Xvoid NotDefined(name, s)
Xchar *name, *s;
X{
X	printf("Warning: %s not defined for \"%s\", line %d\n",
X		s, name, lineNo);
X}
X
X
Xvoid PutCreature(s, tmpl_P)
Xchar *s; 
Xtemplate_t *tmpl_P;
X{
X	generic_t gval;
X	char s1[256];
X	
X	gval.v = malloc(sizeof(template_t));
X	*(template_t *) gval.v = *tmpl_P;
X
X	if (!tmpl_P->def.move)
X		NotDefined(tmpl_P->val.name, "MOVE");
X	if (!tmpl_P->def.treasure)
X		NotDefined(tmpl_P->val.name, "TREASURE");
X	if (!tmpl_P->def.defense)
X		NotDefined(tmpl_P->val.name, "DEFENSE");
X	if (!tmpl_P->def.mexp)
X		NotDefined(tmpl_P->val.name, "XP");
X	if (!tmpl_P->def.sleep)
X		NotDefined(tmpl_P->val.name, "SLEEP");
X	if (!tmpl_P->def.aaf)
X		NotDefined(tmpl_P->val.name, "RADIUS");
X	if (!tmpl_P->def.ac)
X		NotDefined(tmpl_P->val.name, "AC");
X	if (!tmpl_P->def.speed)
X		NotDefined(tmpl_P->val.name, "SPEED");
X	if (!tmpl_P->def.cchar)
X		NotDefined(tmpl_P->val.name, "CCHAR");
X	if (!tmpl_P->def.hd)
X		NotDefined(tmpl_P->val.name, "HD");
X	if (!tmpl_P->def.damage)
X		NotDefined(tmpl_P->val.name, "ATTACK");
X	if (!tmpl_P->def.level)
X		NotDefined(tmpl_P->val.name, "LEVEL");
X		
X	if (St_DefSym(creatureT_P, s, GEN_TYPE_TMPL, gval) == ST_SYM_FOUND) {
X		sprintf(s1, "attempt to redefine creature '%s'\n", s);
X		ErrMsg(s1);
X		free(gval.v);
X		return;
X	}
X
X	if (tmpl_P->val.level > maxCreatureLevel)
X		maxCreatureLevel = tmpl_P->val.level;
X
X}	
X	
Xvoid WriteAttacks()
X{
X	int i;
X	
X	printf("struct m_attack_type monster_attacks[N_MONS_ATTS] = {\n");
X	for (i = 0; i < attackCt; i++) {
X		printf("/* %3d */ { %2d, %2d, %2d, %2d },\n",
X			i, attackList[i].type, attackList[i].desc,
X			attackList[i].dice, attackList[i].sides);
X	};
X	printf("};\n");
X}
X
Xvoid WriteConstants()
X{
X  printf("/* These values should match the values defined in constant.h. */");
X  printf("\n#define MAX_CREATURES\t%d\n", St_TableSize(creatureT_P));
X  printf("#define N_MON_ATTS\t%d\n\n", attackCt);
X}
X
Xvoid WriteMonsterHdr()
X{
X  printf("/* The following code belongs in the file monster.c. */\n\n");
X  printf("/* The following data was generated by the program in util/mc. */\n\n");
X}
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	char inputFilename[256];
X
X	InitTables();
X
X	if (argc > 1) {
X		strncpy(inputFilename, argv[1], 255);
X		inputFilename[255] = 0;
X	} else {
X		fprintf(stderr, "input file: ");
X		scanf("%255s", inputFilename);
X	}
X
X	input_F = fopen(inputFilename, "r");
X	if (!input_F) {
X		printf("Error: couldn't open file.\n");
X		exit(1);
X	}
X
X	if (yyparse()) {
X	    printf("Errors prevent continuation.\n");
X	    exit(1);
X	}
X	
X	WriteConstants();
X	WriteMonsterHdr();
X	WriteCreatures();
X	WriteAttacks();
X}
END_OF_FILE
if test 26718 -ne `wc -c <'util/mc/creature.y'`; then
    echo shar: \"'util/mc/creature.y'\" unpacked with wrong size!
fi
# end of 'util/mc/creature.y'
fi
echo shar: End of archive 20 \(of 31\).
cp /dev/null ark20isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 31 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0


