/*	main.c		*/
/* This game is bad for you. It is evil. It will rot your brain. */
#include "header.h"

static char copyright[]=
  "\nUlarn was created by Phil Cordier and is based on Larn by Noah Morgan\n";

int srcount=0;	/* line counter for showstr()	*/
int dropflag=0; /* if 1 then don't lookforobject() next round */
int rmst=80;	/* random monster creation counter		*/
int userid;	/* the players login user id number */
int stayflag=0;

char 	nowelcome=0,
  nomove=0; /* if (nomove) then don't count next iteration as a move */

static char viewflag=0;
/*	if viewflag then we have done a 99 stay here and 
	don't showcell in the main loop */

char restorflag=0;	/* 1 means restore has been done	*/
#ifdef __MSDOS__

static char cmdhelp[] = "\
Cmd line format: Ularn [-slicnh] [-o<optsfile>] [-##] [++] name\n\
  -s   show the scoreboard\n\
  -i   show scoreboard with inventories\n\
  -c   create new scoreboard (wizard only)\n\
  -n   suppress welcome message on starting game\n\
  -h   print this help text\n\
  -o<optsfile>   specify options file to be used instead of \".Ularnopts\"\n\
  -##  specify level of difficulty (example: Ularn -5)\n\
  ++  restore game checkpoint file\n";

char larnpath[SAVEFILENAMESIZE];

#else /* __MSDOS__ */

static char cmdhelp[] = "\
Cmd line format: Ularn [-slicnh] [-o<optsfile>] [-##] [++]\n\
  -s   show the scoreboard\n\
  -i   show scoreboard with inventories\n\
  -c   create new scoreboard (wizard only)\n\
  -n   suppress welcome message on starting game\n\
  -h   print this help text\n\
  -o<optsfile>   specify .Ularnopts file to be used instead of \"~/.Ularnopts\"\n\
  -##  specify level of difficulty (example: Ularn -5)\n\
  ++  restore game checkpoint file\n";

#endif  /* __MSDOS__ */

/*
 ************
 MAIN PROGRAM
 ************
 */

main(argc,argv)
     int argc;
     char **argv;
{
  register int i;
  int hard;
  int auto_pray;
#ifdef __MSDOS__
  char *p;
#else
  char *ptr=0;
  struct passwd *pwe;
  /* extern	struct passwd *getpwuid(); */
#endif
  
  /*
   *	first task is to identify the player
   */
#ifndef __MSDOS__
  if ((ptr = getlogin()) == NULL)
    if (pwe=getpwuid(geteuid()))
      ptr = pwe->pw_name;
    else if ((ptr = getenv("USER")) == NULL) {
    noone:		    fprintf(stderr, "Can't find your logname.  Who Are You?\n");
      fflush(stderr);
      exit(1);
    }
  if (ptr==NULL) goto noone;
  if (strlen(ptr)==0) goto noone;
#endif /* __MSDOS__ */
  
  /*
   * allocate the memory for the I/O routines
   */
  
  if ( ( lpbuf = malloc ((5* BUFBIG)>>2) ) == (char *)NULL)
    died(-285);
  
  if ( ( inbuffer = malloc( (5*MAXIBUF) >>2) ) == (char *)NULL)
    died(-285);
  
  /*
   *	second task is to prepare the pathnames the player will need
   */
  
#ifdef __MSDOS__
  
  /*
   * try to figure out where our data files are...
   *
   *  first try to find the path where ularn.exe resides.
   */
  
  logname[0] = loginname[0] = '\0';
  
  if (strlen(argv[0])+1 > sizeof(larnpath)-12)
    argv[0][sizeof(larnpath)-1] = '\0';
  strcpy(larnpath, argv[0]);
  
  p = larnpath + strlen(larnpath);
  while (--p >= larnpath)
    if (*p == '/' || *p == '\\' || *p == ':') break;
  *(p + 1) = '\0';
  
  /*
   * if an option file name was specified on the command line, try to open it.
   */
  
  for (i=1; i<argc; i++)
    if (argv[i][0] == '-' && argv[i][1] == 'o') {
      strncpy(optsfile, argv[i]+2, SAVEFILENAMESIZE-1);
      if (readopts() < 0) {
	fprintf(stderr, "Can't open options file %s\n.", optsfile);
	exit(1);
      }
      goto gotopts;
    }
  
  /* now look for an option file in the current directory */
  
  strcpy(optsfile, "ularnopt");
  if (readopts() < 0) {
    
    /* then look for it in the larn exe directory */
    
    strcpy(optsfile, larnpath);
    strcat(optsfile, "ularnopt");
    readopts();
  }
  
 gotopts:
  
  /*
   * if the player game a name on the command line, let it override one
   *  given in the options file
   */
  
  if (argc > 1 && argv[argc-1][0] != '-' && argv[argc-1][0] != '+') {
    --argc;
    strcpy(logname, argv[argc]);
  }
  
  /* if the player didn't specify a name, ask now */
  
  while (logname[0] == '\0') {
    char tmp[LOGNAMESIZE];
    printf("Who are you: ");
    fgets(tmp, sizeof(tmp), stdin);
    p = tmp + strlen(tmp);
    while (--p >= tmp)
      if (*p == '\n' || isspace(*p)) *p = '\0';
      else break;
    for (p=tmp; *p && isspace(*p); p++)
      ;
    strcpy(logname, p);
  }
  
  /*
   * if the save file name wasn't specified in the options file, use the player's
   *  name in the current directory.
   */
  
  if (savefilename[0] == '\0') {
    strcpy(savefilename, logname);
    savefilename[8] = '\0';
    for (p=savefilename; *p; p++)
      if (isspace(*p) || *p == '.' || *p == '\\' || *p == '/') {
	*p = '\0';
	break;
      }
    strcat(savefilename, ".sav");
  }
  
  /* set the paths for the data files */
  
  strcpy(scorefile,  larnpath);
  strcpy(logfile,    larnpath);
  strcpy(helpfile,   larnpath);
  strcpy(larnlevels, larnpath);
  strcpy(fortfile,   larnpath);
  
#else /* __MSDOS__ */
  
  strcpy(loginname,ptr); 
  
  /* save loginname of the user for logging purposes */
  strcpy(logname,ptr);	
  
  /* this will be overwritten with the players name */
  if ((ptr = getenv("HOME")) == NULL) 
    if ((ptr = pwe->pw_dir) == NULL)
      ptr = ".";
  
  /* save file name in home directory */
  strcpy(savefilename, ptr);
  strcat(savefilename, "/Ularn.sav");	
  sprintf(optsfile, "%s/.Ularnopts",ptr);	/* the .Ularnopts filename */
  
#endif  /* __MSDOS__ */
  
  strcat(scorefile, SCORENAME);	/* the Ularn scoreboard filename */
  strcat(logfile, LOGFNAME);
  
  /* Ularn activity logging filename */
  strcat(helpfile, HELPNAME);	/* the Ularn on-line help file */
  strcat(larnlevels, LEVELSNAME);	/* the pre-made cave level data file */
  strcat(fortfile, FORTSNAME);	/* the fortune data file name */
  
  
  init_term();	/*setup the terminal (find out what type) for termcap */
  
  /*
   *	now malloc the memory for the dungeon 
   */
  
  init_cells();
  
  lcreat((char*)0);	
  newgame();		/*	set the initial clock  */ 
  hard= -1;
  
  /*
   *	now make scoreboard if it is not there
   */
  if (readboard(1) < 0) /* not there */
    makeboard();
  
  /*
   *	now process the command line arguments 
   */
  
  for (i=1; i<argc; i++) {
    if (argv[i][0] == '-')
      switch(argv[i][1]) {
      case 's': showscores();  
	exit(0);  /* show scoreboard   */
	
      case 'i': showallscores();  
	exit(0);  /* show all scoreboard */
	
      case 'c': /*anyone with password can create scoreboard*/
	setupvt100();	
	lprcat("Preparing to initialize the scoreboard.\n");
	if (getpassword() != 0) {
	  makeboard(); 
	  showscores();
	}
	exit(0);
	
      case 'n':	nowelcome=1; 
	argv[i][0]=0; 
	break;
	
      case '0': case '1': case '2': case '3': 
      case '4': case '5': case '6': case '7': 
      case '8': case '9':	/* for hardness */
	sscanf(&argv[i][1],"%d",&hard);	
	if (hard > 100) hard = 100;
	break;
	
      case 'h':	/* print out command line arguments */
	fprintf(stderr, "%s", cmdhelp);
	fflush(stderr);
	exit(0);
      case 'o':	/* specify a .Ularnopts filename */
	strncpy(optsfile,argv[i]+2,127);  break;
      default:
	fprintf(stderr,"Unknown option <%s>\n",argv[i]);
	fprintf(stderr,"%s", cmdhelp);  
	fflush(stderr);
	exit(1);
      };
    if (argv[i][0] == '+') {
      clear();	restorflag = 1;
      if (argv[i][1] == '+') {
	hitflag=1; 
	restoregame(ckpfile); 
	/* restore checkpointed game */
      }
      i = argc;
    }
  }
  
  
#ifndef __MSDOS__
  userid = geteuid();	/* obtain the user's effective id number */
#else
  userid = 42;
#endif
  
  sigsetup();	/* trap all needed signals	*/
  sethard(hard);	/* set up the desired difficulty	*/
#ifndef __MSDOS__  /* if __MSDOS__, we've already done this */
  readopts();	/* read the options file if there is one */
#endif
  setupvt100();	/* setup the terminal special mode	*/
  
  /* restore game if need to */
  if (access(savefilename,0)==0)	{
    clear();	
    restorflag = 1;
    hitflag=1;	
    restoregame(savefilename);  
  }
  
  /* create new game */
  if (c[HP]==0) {
    makeplayer();	/*	make the character that will play*/
    newcavelevel(0);/*	make the dungeon */
    predostuff = 1;	
    
    /* tell signals that we are in the welcome screen */
    if (nowelcome==0) 
      welcome();	 /* welcome the player to the game */
  }
  
  drawscreen();	/*	show the initial dungeon */
  
  /* tell the trap functions that they must do a showplayer()
     from here on */
  predostuff = 2;	
  
  yrepcount = hit2flag = 0;
  auto_pray = FALSE;
  /*
   *	M A I N  L O O P
   */
  while (1) {
    if (dropflag==0) 
      lookforobject(auto_pray); /* see if there is an object here*/
    else 
      dropflag=0; /* don't show it just dropped an item */
    
    if (hitflag==0) { 	
      if (c[HASTEMONST]) 
	movemonst(); 
      movemonst(); 
    }	/* move the monsters	*/
    
    if (viewflag==0) 
      showcell(playerx,playery); 
    else viewflag=0;	/* show stuff around player */
    
    if (hit3flag) 
      flushall();
    hitflag = hit3flag = 0;	
    nomove=1;
    bot_linex();	/* update bottom line */
    
    while (nomove)/*	get commands and make moves	*/
    {
      if (hit3flag) 
	flushall();
      nomove=0; 
      parse(&auto_pray);
    }	
    
    regen();	/*	regenerate hp and spells*/
    
    if (c[TIMESTOP]==0)
      if (--rmst <= 0) { 	
	rmst = 120-(level<<2); 
	fillmonst(makemonst(level)); 
      }
  }	/* end main loop */
}	/* end main */

/*
  showstr()
  
  show character's inventory
  */
showstr(may_select)
     int may_select;
{
  
  register int i,number;
  
  number = 3 + nr_object(-1);
  t_setup(number);	
  i = qshowstr(may_select);
  t_endup(number);
  return(i);
}

qshowstr(may_select)
     int may_select;
{
  register int k, l, sigsav;
  
  sigsav=nosignal;  
  nosignal=1; /* don't allow ^c etc */
  if (c[GOLD]) { 	
    lprintf(".)   %d gold pieces",(long)c[GOLD]); 
    srcount++; 
  };
  
  l = 0x20;
  for (k=0; (k < NINVT) && (l == 0x20); k++){
    if ( iven[k] ) {
      l = show3(k, may_select);
    };
  };
  
  if ( l == 0x20 ){
    lprintf("\nElapsed time is %d.  You have %d mobuls left",
	    (long)((gtime+99)/100+1),(long)((TIMELIMIT-gtime)/100));
    l = morex(may_select);
  };
  nosignal=sigsav;
  return ( l );
}

/*
  function to show the things player is wearing only
  */
showwear()
{
  register int j,sigsav,count;
  static int liste[] = { OLEATHER, OPLATE, OCHAIN, ORING, OSTUDLEATHER, 
			   OSPLINT, OPLATEARMOR, OSSPLATE, OSHIELD, OELVENCHAIN};
  
  sigsav=nosignal;  
  nosignal=1; /* don't allow ^c etc */
  
  count = 2 + nr_obj_lst( sizeof(liste) / sizeof(liste[0]), liste );
  t_setup(count);
  
  j = show3allst( sizeof(liste) / sizeof(liste[0]), liste );
  t_endup(count);
  nosignal=sigsav;
  return (j);
}

/*
  function to show the things player can wield only 
  */
showwield()
{
  register int j,sigsav,count;
  static int liste[] = { OPOTION, OSCROLL };
  
  sigsav=nosignal;  
  nosignal=1; /* don't allow ^c etc */
  
  count = 2 + nr_obj_not( sizeof(liste) / sizeof(liste[0]), liste );
  t_setup(count);
  
  j = show3notlst( sizeof(liste) / sizeof(liste[0]), liste );
  t_endup(count);
  nosignal=sigsav;
  return (j);
}

/*
 *	function to show the things player can read only
 */
showread()
{
  register int j,sigsav,count;
  static int liste[] = { OBOOK, OSCROLL };
  
  sigsav=nosignal;  
  nosignal=1; /* don't allow ^c etc */
  
  count = 2 + nr_obj_lst( sizeof(liste) / sizeof(liste[0]), liste );
  t_setup(count);
  
  j = show3allst( sizeof(liste) / sizeof(liste[0]), liste );
  t_endup(count);
  nosignal=sigsav;
  return (j);
}

/*
 *	function to show the things player can eat only
 */
showeat()
{
  register int j,sigsav,count;
  
  sigsav=nosignal;  
  nosignal=1; /* don't allow ^c etc */
  
  count = 2 + nr_object(OCOOKIE);
  t_setup(count);
  
  j = show3all1(OCOOKIE, 1, 1);
  t_endup(count);
  nosignal=sigsav;
  return (j);
}

/*
  function to show the things player can quaff only
  */
showquaff()
{
  register int j,sigsav,count;
  
  sigsav=nosignal;  
  nosignal=1; /* don't allow ^c etc */
  
  count = 2 + nr_object(OPOTION);
  t_setup(count);
  
  j = show3all1(OPOTION, 1, 1);
  t_endup(count);
  nosignal=sigsav;
  return (j);
}

show3all1(what, may_select, no_space)
     int what;
{
  int j, k;
  
  k = 0x20;
  for (j=0; (j < NINVT) && (k == 0x20); j++){
    if ( (iven[j] == what) ){
      k = show3(j, may_select);
    };
  };
  if ( k == 0x20 ){
    k = morex(may_select);
    if ( (k == 0x20) && no_space ){
      k = '.';
    };
  };
  return ( k );
}


show3allst(n, liste)
     int n;
     int liste[];
{
  int j, k, l;
  
  l = 0x20;
  for (k=0; (k < n)  && (l == 0x20); k++){
    for (j=0; (j < NINVT) && (l == 0x20); j++){
      if ( iven[j] == liste[k] ){
	l = show3(j, 1);
      };
    };
  };
  if ( l == 0x20 ){
    l = morex(1);
    if ( l == 0x20 ){
      l = '.';
    };
  };
  return ( l );
}


show3notlst(n, liste)
     int n;
     int liste[];
{
  int i, j, k, l, not_in_list;
  
  l = 0x20;
  for (i=22; (i < 93) && (l == 0x20); i++){      /* sorted list */
    for (j=0; (j < NINVT) && (l == 0x20); j++){
      if ( (iven[j] != 0) && (i == iven[j]) ){
	not_in_list = 1;
	for (k=0; (k < n) && not_in_list; k++){
	  not_in_list = (iven[j] != liste[k]);
	};
	if ( not_in_list ){
	  l = show3(j, 1);
	};
      };
    };
  };
  if ( l == 0x20 ){
    l = morex(1);
    if ( l == 0x20 ) {
      l = '.';
    };
  };
  return ( l );
}


show3(index, may_select)
     register int index;
     int may_select;
{
  int res;
  
  switch(iven[index]) {
  case OPOTION:	show1(index,potionname);  break;
  case OSCROLL:	show1(index,scrollname);  break;
  case OLARNEYE:		
  case OBOOK:			
  case OSPIRITSCARAB:
  case ODIAMOND:		
  case ORUBY:			
  case OCUBEofUNDEAD:
  case OEMERALD:		
  case OCHEST:		
  case OCOOKIE:
  case OSAPPHIRE:		
  case OORB:	
  case OHANDofFEAR:
  case OBRASSLAMP:
  case OURN:
  case OWWAND:
  case OSPHTALISMAN:
  case ONOTHEFT:		show1(index,(char **)0);  break;
    
  default:	
    lprintf("\n%c)   %s",index+'a',objectname[iven[index]]);
    if (ivenarg[index]>0) 
      lprintf(" + %d",(long)ivenarg[index]);
    else if (ivenarg[index]<0) 
      lprintf(" %d",(long)ivenarg[index]);
    break;
  }
  if (c[WIELD]==index) 
    lprcat(" (weapon in hand)");
  if ((c[WEAR]==index) || (c[SHIELD]==index))  
    lprcat(" (being worn)");
  res = 0x20;
  if (++srcount>=22) { 
    srcount=0; 
    res = morex(may_select); 
    clear(); 
  };
  return ( res );
}


show1(idx,str2)
     register int idx;
     register char *str2[];
{
  if ( (str2==0) || (*str2[ivenarg[idx]]==0) ) 
    lprintf("\n%c)   %s",idx+'a',objectname[iven[idx]]);
  else 
    lprintf("\n%c)   %s of%s",
	    idx+'a',objectname[iven[idx]],str2[ivenarg[idx]]);
}



/*
 *	subroutine to clear screen depending on # lines to display
 */
t_setup(count)
     register int count;
{
  if (count<20)  {
    cl_up(79,count);  
    cursor(1,1);
  } else {
    resetscroll(); 
    clear();
  };
  srcount = 0;
}

/*
 *	subroutine to restore normal display screen depending on t_setup()
 */
t_endup(count)
     register int count;
{
  if (count<18)  /* how did we clear the screen? */
    draws(0,MAXX,0,(count>MAXY) ? MAXY : count);
  else {
    drawscreen(); 
    setscroll();
  };
  cursors();
}
/*
  subroutine to randomly create monsters if needed
  */
randmonst()
{	/*	don't make monsters if time is stopped	*/
  if (c[TIMESTOP]) return;	
  if (--rmst <= 0) {
    rmst = 120 - (level<<2);  
    fillmonst(makemonst(level));
  }
}

/*
  parse()
  
  get and execute a command
  */

parse(auto_pray)
     int  *auto_pray;
{
  int          ast;
  register int i,j,k,flag;

  *auto_pray = FALSE;
  ast = 0;
  while	(1) {
    k = yylex();
    if( ast && index("hjklyubn",(char) k) ){
      k = k & 0x5F; /* to uppercase */
    };
    /* get the token from the input and switch on it	*/
    switch(k)	{
    case '*':       ast = 1;
      break;
      
    case 'A':	if (wizard) 
                  diag(); 
                yrepcount=0;
                return;
    case 'h':	moveplayer(4);        return;	/* west	*/
    case 'H':	run(4);               return;	/* west	*/
    case 'l':	moveplayer(2);        return;	/* east	*/
    case 'L':	run(2);	              return;	/* east	*/
    case 'j':	moveplayer(1);        return;	/* south */
    case 'J':	run(1);	              return;	/* south */
    case 'k':	moveplayer(3);        return;	/* north */
    case 'K':	run(3);	              return;	/* north */
    case 'u':	moveplayer(5);	      return;	/* northeast */
    case 'U':	run(5);		      return;	/* northeast */
    case 'y':	moveplayer(6);        return;	/* northwest */
    case 'Y':	run(6);		      return;	/* northwest */
    case 'n':	moveplayer(7);	      return;	/* southeast */
    case 'N':	run(7);		      return;	/* southeast */
    case 'b':	moveplayer(8);	      return;	/* southwest */
    case 'B':	run(8);		      return;	/* southwest */
    case '-':   if( get_nxt1_dir() ){
                  moveplayer(get_nxt1_dir());
                };
                return; /* zig-zag   */
    case '+':   if( get_nxt2_dir() ){
                  moveplayer(get_nxt2_dir());
                };
                return; /* zig-zig-zag-zag */
      
    case 'P'-0x40:	                  /* ^P == stay here & auto_pray */
                if( (c[GOLD] < 50) || (nearbymonst()) ){
                   nomove = 1;
		 }else{
                   *auto_pray = 1;
		   if (yrepcount) 
                      viewflag=1;
		 }; 
                
                    /* fallthrough */ 
    case '.':	if (yrepcount) 
                  viewflag=1; 
                return;	/* stay here */
      
    case 'w':	yrepcount=0;	
                wield();	
                return;	/* wield a weapon */
      
    case 'W':	yrepcount=0;	
                wear();		
                return;	/* wear armor	*/
      
    case 'r':	yrepcount=0;
                if (c[BLINDCOUNT]) { 
		  cursors(); 
		  lprcat("\nYou can't read anything when you're blind!"); 
		} else if (c[TIMESTOP]==0) 
		  readscr(); 
                return;	/* to read a scroll */
      
    case 'q':	yrepcount=0;	
                if (c[TIMESTOP]==0) 
		  quaff();	
                return;	/* quaff a potion */
      
    case 'd':	yrepcount=0;	
                if (c[TIMESTOP]==0) 
		  dropobj(); 
                return;	/* to drop an object */
      
    case 'c':	yrepcount=0;	
                cast();		
                return;	/* cast a spell	*/
      
    case 'i':	yrepcount=0;	
                nomove=1;  
                (void) showstr(0);	
                return;	/* status */
      
    case 'e':	yrepcount=0;
                if (c[TIMESTOP]==0) 
		  eatcookie(); 
                return;	/* to eat a fortune cookie */
      
    case 'D':	yrepcount=0;	
                seemagic(0);	
                nomove=1; 
                return;	/*list spells and scrolls */
      
    case '?':	yrepcount=0;	
                help(); 
                nomove=1; 
                return;	/*give the help screen*/
      
    case 'S':	clear();  
                lprcat("Saving . . ."); 
                lflush();  
                savegame(savefilename); 
                wizard=1; 
                died(-257);
               /* save the game - doesn't return */
      
    case 'Z':   yrepcount=0;         	/* teleport yourself	*/
                if (wizard) {
		  int t;
		  cursors();
		  lprcat("\nWhich level do you wish to teleport to? ");
		  t = readnum(20);
		  if (t > 20 || t < 0) {
		    lprcat(" sorry!");
		    return;
		  }
		  playerx = rnd(MAXX-2);	
		  playery = rnd(MAXY-2);
		  newcavelevel(t);  
		  positionplayer();
		  draws(0,MAXX,0,MAXY); 
		  bot_linex();
		}else if (c[LEVEL]>9) { 
		  oteleport(1); 
		}else{
		  cursors();
		  lprcat("\nYou don't know how to teleport yet");
		};
                return;
      
    case '^':                           	/* identify traps */  
                flag=yrepcount=0;  
                cursors();
                lprc('\n');  
                for (j=playery-1; j<playery+2; j++) {
		  if (j < 0) j=0;		
		  if (j >= MAXY) break;
		  for (i=playerx-1; i<playerx+2; i++) {
		    if (i < 0) i=0;	
		    if (i >= MAXX) break;
		    switch(item[i][j]) {
		    case OTRAPDOOR:		
		    case ODARTRAP:
		    case OTRAPARROW:
		    case OTELEPORTER:
		    case OELEVATORUP:
		    case OELEVATORDOWN:
		      lprcat("\nIt's "); 
		      lprcat(objectname[item[i][j]]);
		      flag++;
		    };
		  }
		}
                if (flag==0) 
		  lprcat("\nNo traps are visible");
                return;
      
    case '#':	
                yrepcount=0;	
                cursors(); 
                nomove=1;
                if (getpassword()==0) {
		  scbr(); 
		  return;
		}
                scbr();
                raiseexperience(370 * 1000000);
                bottomline();
                drawscreen();
                return;
      
#if WIZID
    case '_':                      /*this is the fudge player password for wizard mode*/
                yrepcount=0;	
                cursors(); 
                nomove=1;
                if (getpassword()==0) {
		  scbr(); 
		  return;
		}
                wizard=1;  
                scbr(); 
                for (i=0; i<6; i++)  
		  c[i]=70;  
                iven[0]=iven[1]=0;
                take(OPROTRING,50);   
                take(OLANCE,25);  
                for (i=0; i < NINVT; i++)
		  if (iven[i]==OLANCE && ivenarg[i]==25) {
		    c[WIELD]=i;
		    break;
		  }
                c[LANCEDEATH]=1;   
                c[WEAR] = c[SHIELD] = -1;
                raiseexperience(370*1000000); 
                c[AWARENESS] += 25000;
                {
		  register int i,j;
		  for (i=0; i<MAXY; i++)
		    for (j=0; j<MAXX; j++)  
		      know[j][i]=1;
		  for (i=0; i<SPNUM; i++)	
		    spelknow[i]=1;
		  for (i=0; i<MAXSCROLL; i++)  
		    scrollname[i][0]=' ';
		  for (i=0; i<MAXPOTION; i++)  
		    potionname[i][0]=' ';
		}
                for (i=0; i<MAXSCROLL; i++)
		  if (strlen(scrollname[i])>2) 
		  { 	item[i][0]=OSCROLL; 
			iarg[i][0]=i; 
		      }
                for (i=MAXX-1; i>MAXX-1-MAXPOTION; i--)
		  if (strlen(potionname[i-MAXX+MAXPOTION])>2) 
		    /* no null items */
		  { 	item[i][0]=OPOTION; 
			iarg[i][0]=i-MAXX+MAXPOTION; 
		      }
                for (i=1; i<MAXY; i++)
		{ 	item[0][i]=i; 
			iarg[0][i]=0; 
		      }
                for (i=MAXY; i<MAXY+MAXX; i++)
		{ 	item[i-MAXY][MAXY-1]=i; 
			iarg[i-MAXY][MAXY-1]=0; 
		      }
                for (i=MAXX+MAXY; i<MAXX+MAXY+MAXY; i++)
		{ 	item[MAXX-1][i-MAXX-MAXY]=i; 
			iarg[MAXX-1][i-MAXX-MAXY]=0; 
		      }
                c[GOLD]+=250000;
                bottomline();
                drawscreen();	
                return;
#endif /* WIZID */
      
    case 'T':	yrepcount=0;	
                cursors();  
                if (c[SHIELD] != -1) { 
		  c[SHIELD] = -1; 
		  lprcat("\nYour shield is off");
		  bottomline(); 
		} else
		  if (c[WEAR] != -1) { 
		    c[WEAR] = -1; 
		    lprcat("\nYour armor is off"); 
		    bottomline(); 
		  }
		  else lprcat("\nYou aren't wearing anything");
                return;
      
    case 'g':	cursors();
                lprintf("\nThe stuff you are carrying presently weighs %d pounds",
	                (long)packweight());
                break;
      
    case ' ':	yrepcount=0;	
                nomove=1;  
                return;
      
    case 'v':	yrepcount=0;	
                cursors();
                lprintf( "\nThe Addiction of Ularn, by Satyr. Difficulty : %d",
	                (long)c[HARDGAME]);
                if (wizard) lprcat(" (WIZARD)");
                nomove=1;
                if (cheat) lprcat(" (Cheater)");
                lprcat(copyright); 
                return;
      
    case 'Q':	yrepcount=0;
                quit(); /* may exit */
                /* if escaped quitting : */
                nomove=1;	
                return; 	/* quit	*/
      
    case 'L'-0x40: 	yrepcount=0;	
                drawscreen();  
                nomove=1; 
                break;  	/* ^L == look		*/
      
    case 'P':	cursors();
                lprc('\n');
                printtax();
                return;
#if WIZID
    case 'X':	cursors();
                settax(readnum(0), FALSE);
                settax(readnum(0), TRUE);
                lprc('\n');
                printtax();
                return;
#endif
    };
  }
}

parse2()
{
  if (c[HASTEMONST]) 
    movemonst(); 
  movemonst(); /*	move the monsters */
  randmonst();	
  regen();
}

run(dir)
     int dir;
{
  register int i;
  i=1; 
  while (i) {
    i=moveplayer(dir);
    if (i>0) {  	
      if (c[HASTEMONST]) 
	movemonst();  
      movemonst(); 
      randmonst(); 
      regen(); 
    }
    if (hitflag) i=0;
    if (i!=0)  
      showcell(playerx,playery);
  }
}

/*
  function to wield a weapon
  */
wield()	
{
  register int i;
  
  do {
    i = whatitem("wield");
    if (i != '.') {
      if (i=='*') i = showwield(); 
      if (i != '.'){
	if (i=='\33') {
	}else if (iven[i-'a']==0) { 
	  ydhi(i);
	}else if ( (iven[i-'a']==OSCROLL) || (iven[i-'a']==OPOTION) ){ 
	  cursors();
	  lprintf("\nYou can't wield item %c!",i);
	}else if ( (c[SHIELD]!= -1) && (iven[i-'a']==O2SWORD) ){
	  lprcat("\nBut one arm is busy with your shield!");
	}else{
	  c[WIELD]=i-'a'; 
	  c[LANCEDEATH] = (iven[i-'a'] == OLANCE);  
	  bottomline(); 
	};
      };
    }
  } while (i == '.') ;
}

/*
  function to wear armor
  */
wear()
{
  register int i;
  
  do {
    i = whatitem("wear");
    if (i != '.') {
      if (i=='*') i = showwear(); 
      if (i != '.'){
	if (i=='\33') {
	}else switch(iven[i-'a']) {
	case 0:  
	  ydhi(i);
	  break;
	case OLEATHER:  
	case OCHAIN:  
	case OPLATE:	
	case OSTUDLEATHER:
	case ORING:		
	case OSPLINT:	
	case OPLATEARMOR:	
	case OELVENCHAIN:
	case OSSPLATE:
	  if (c[WEAR] != -1) { 
	    lprcat("\nYou're already wearing some armor");
	  }else{
	    c[WEAR]=i-'a';  
	    bottomline();
	  };
	  break;
	  
	case OSHIELD:	
	  if (c[SHIELD] != -1) { 
	    lprcat("\nYou are already wearing a shield");
	  }else if (iven[c[WIELD]]==O2SWORD) {
	    lprcat("\nYour hands are busy with the two handed sword!");
	  }else{
	    c[SHIELD] = i-'a';
	    bottomline();
	  };
	  break;
	  
	default: 
	  lprcat("\nYou can't wear that!");
	  break;
	};
      };
    }
  } while (i == '.') ;
}

/*
  function to drop an object
  */
dropobj()
{
  register int i, can_do;
  register char *p;
  long amt;
  
  p = &item[playerx][playery];
  do{
    i = whatitem("drop");
    if (i=='*') i = showstr(1); 
    can_do =    (i == '.') || (i == '*') || ((i >= '0') && (i <= '9')) 
      || ((i >= 'a') && (i <= 'z')) ;
    if ( can_do ) {
      if (*p) { 
	lprcat("\nThere's something here already!"); 
      }else if ( (i >= 'a') && (i <= 'z') ){
	drop_object(i-'a');
      }else{
	lprcat("\n");
	cl_dn(1, 23);
	lprcat("How much gold do you drop? ");
	if ( i != '.' ){
	  merke(i);
	};
	amt = readnum( (long) c[GOLD]);
	if ( (amt != 0) ){
	  if ( (amt>c[GOLD]) ){ 
	    lprcat("\nYou don't have that much!"); 
	  }else{
	    drop_dough(amt, p);
	  };
	};
      };
    };
  } while ( ! (can_do || (i == '\33')) );
}

drop_dough(amt, p)
     long amt;
     register char *p;
{
  int i;
  
  if (amt<=32767) { 
    *p=OGOLDPILE; 
    i=amt; 
  }else if (amt<=327670L) { 
    *p=ODGOLD; 
    i=amt/10; 
    amt = 10L*i; 
  }else if (amt<=3276700L) { 
    *p=OMAXGOLD; 
    i=amt/100; 
    amt = 100L*i; 
  }else if (amt<=32767000L) { 
    *p=OKGOLD; 
    i=amt/1000; 
    amt = 1000L*i; 
  }else{ 
    *p=OKGOLD; 
    i=32767; 
    amt = 32767000L; 
  };
  c[GOLD] -= amt; 
  lprintf("You drop %d gold pieces",(long)amt);
  iarg[playerx][playery]=i; 
  bottomgold();
  know[playerx][playery]=0; 
  dropflag=1;
}
/*
 *	readscr()		Subroutine to read a scroll / book one is carrying
 */
readscr()
{
  register int i;
  
  do {
    i = whatitem("read");
    if (i != '.') {
      if (i=='*') i = showread(); 
      if (i != '.'){
	if (i=='\33') {
	}else if (iven[i-'a']==OSCROLL) { 
	  read_scroll(ivenarg[i-'a']); 
	  iven[i-'a']=0; 
	}else if (iven[i-'a']==OBOOK)   { 
	  readbook(ivenarg[i-'a']);  
	  iven[i-'a']=0; 
	}else if (iven[i-'a']==0) { 
	  ydhi(i);
	}else{
	  lprcat("\nThere is nothing on it to read");  
	};
      };
    }
  } while (i == '.') ;
}

/*
 *	subroutine to eat a cookie one is carrying
 */
eatcookie()
{
  register int i;
  char *p;
  
  do {
    i = whatitem("eat");
    if (i != '.') {
      if (i=='*') i = showeat(); 
      if (i != '.'){
	if (i=='\33') {
	}else if (iven[i-'a']==OCOOKIE) { 
	  lprcat("\nThe cookie was delicious.");
	  iven[i-'a']=0;
	  if (!c[BLINDCOUNT]) {
	    if ((p=fortune(fortfile))!=0) {
	      lprcat("  Inside you find a scrap of paper that says:\n");
	      lprcat(p);
	    };
	  };
	}else if (iven[i-'a']==0) { 
	  ydhi(i);
	}else{
	  lprcat("\nYou can't eat that!");
	};
      };
    }
  } while (i == '.') ;
}

/*
 *	subroutine to quaff a potion one is carrying
 */
quaff()
{
  register int i;
  
  do {
    i = whatitem("quaff");
    if (i != '.') {
      if (i=='*') i = showquaff(); 
      if (i != '.'){
	if (i=='\33') {
	}else if (iven[i-'a']==OPOTION) { 
	  quaffpotion(ivenarg[i-'a']); 
	  iven[i-'a']=0; 
	}else if (iven[i-'a']==0) { 
	  ydhi(i);
	}else{
	  lprcat("\nYou wouldn't want to quaff that, would you? ");  
	};
      };
    }
  } while (i == '.') ;
}

/*
  function to ask what player wants to do
  */
#define DNONE  (-1)
#define DWIELD (1)
#define DQUAFF (2)
#define DREAD  (3)
#define DWEAR  (4)
#define DEAT   (5)
#define DDROP  (0)

typedef struct ITM_TYPTAG {
  int typ;
  char *actn;
} ITM_TYP;

static  ITM_TYP item_types[] = {
   {DWIELD, {"wield"}}
  ,{DQUAFF, {"quaff"}}
  ,{DREAD,  {"read"}}
  ,{DWEAR,  {"wear"}}
  ,{DEAT,   {"eat"}}
  ,{DDROP,  {"drop"}} 
};

typedef struct OBJ_ACT_TAG {
  int obj_typ;  /* type of object */
  int act_typ;  /* the usual type of action */
} OBJ_ACT;

static OBJ_ACT obj_action[] = {
  {OSWORDofSLASHING, DWIELD}
 ,{OHAMMER,          DWIELD}         
 ,{OSWORD,           DWIELD}
 ,{O2SWORD,          DWIELD}
 ,{OSPEAR,           DWIELD}
 ,{ODAGGER,          DWIELD}
 ,{OBATTLEAXE,       DWIELD}
 ,{OLONGSWORD,       DWIELD}
 ,{OFLAIL,           DWIELD}
 ,{OSLAYER,          DWIELD}
 ,{OLANCE,           DWIELD}
 ,{OPOTION,          DQUAFF}
 ,{OSCROLL,          DREAD}
 ,{OPLATE,           DWEAR}
 ,{OCHAIN,           DWEAR}
 ,{OLEATHER,         DWEAR}
 ,{ORING,            DWEAR}
 ,{OSTUDLEATHER,     DWEAR}
 ,{OSPLINT,          DWEAR}
 ,{OPLATEARMOR,      DWEAR}
 ,{OSSPLATE,         DWEAR}
 ,{OSHIELD,          DWEAR}
 ,{OELVENCHAIN,      DWEAR}
 ,{OCOOKIE,          DEAT}
};


whatitem(str)
     char *str;
{
  register int j, type_obj, type_act, i, k;
  char gack[NINVT];
 
  cursors();
  type_act = DNONE;
  for (i=0; ! ( (i >= N_ELEM(item_types)) || (type_act != DNONE)); i++){
    if (!strcmp(str, item_types[i].actn)) type_act = item_types[i].typ;
  };

  if ( type_act == DNONE ){
    beep();
    lprintf("YOU can't make ME >%s< something !!!!!\n", str);
    /* -... a sure sign of a diseased mind ...*/
    lflush();
    nap(5500);
  }else{
    i = 0;
    for (j=0; j < NINVT; j++) {
      if ( iven[j] ){
	if (type_act == DDROP){ 
	  gack[i++] = j;
	}else{
	  type_obj = DNONE;
	  for (k=0; ! ( (k >= N_ELEM(obj_action)) || (type_obj != DNONE) ); k++){ 
	    if (iven[j] == obj_action[k].obj_typ){
	      type_obj = obj_action[k].act_typ;
	      if (type_obj == type_act){
		gack[i++] = j;
	      };
	    };
	  };
	};
      };
    };
    lprintf("\nWhat do you want to %s [", str);
    if (i) {
      for (j=0;j<i;j++) 
	lprintf("%c",gack[j] + 'a');
      lprcat(", ");
    };
    lprcat("* for list] ?");
    do{ 
      i=getcharacter();
    } while ( ! (   ((i >= 'a') && (i <= 'z')) || (i == '*') || (i == '\33') || (i == '.') 
		 || ((type_act == DDROP) && (( i >= '0') && (i <= '9'))) ) ) ;
    if (i=='\33')  
      lprcat(" aborted");
  };
  return(i);
}
#undef DWIELD
#undef DQUAFF
#undef DREAD
#undef DWEAR
#undef DEAT


/*
  common routine to say you don't have an item
  */
ydhi(x)
     int x;
{
  cursors();  
  lprintf("\nYou don't have item %c!", x);
}



/*
  subroutine to get a number from the player
  and allow * to mean return amt, else return the number entered
  */

static int gemerkt = FALSE;
static int was = 0;

merke(i)
{
  was = i;
  gemerkt = TRUE;
}


long readnum(mx)
     long mx;
{
  register int i;
  long amt=0;
  
  if ( gemerkt ){
    scbr();
    lprc(was);
  };
  sncbr();
  i = (gemerkt ? was : getcharacter() );
  gemerkt = FALSE;
  if ( i == '*' ){  
    amt = mx;   /* allow him to say * for all gold */
  }else{
    while ( (i != '\n') && (i != '\33') ) {
      if (i == '\33') { 
	scbr(); 
	lprcat(" aborted"); 
	amt = 0;
      }else{
	if ((i <= '9') && (i >= '0') && (amt<999999999))
	  amt = amt*10+i-'0';
	i = getcharacter();
      };
    };
  };
  scbr();  
  return(amt);
}




