/* tok.c */
#include "header.h"

#define FLUSHNO 5
#define MAXUM 52	/* maximum number of user re-named monsters */
#define MAXMNAME 40	/* max length of a monster re-name */

static char lastok=0;
int yrepcount=0,dayplay=0;
#ifdef BSD
static int flushno=FLUSHNO;	/* input queue flushing threshold */
#endif /* BSD */
static char usermonster[MAXUM][MAXMNAME]; 
static char usermpoint=0;			/* the user monster pointer */

/*
  lexical analyzer for larn
  */
yylex()
{
  char cc;
  int i, ic;
  
  if (hit2flag) { 
    hit2flag=0;  
    yrepcount=0;  
    return(' '); 
  }
  if (yrepcount>0)	{ 
    --yrepcount;  
    return(lastok);	
  } 
  else yrepcount=0;
  
  /*show where the player is*/
  if (yrepcount==0) { 
    bottomdo(); 
    showplayer(); 
  }	
  lflush();  
  while (1) {
    c[BYTESIN]++;
    if (ckpflag)
      /* check for periodic checkpointing */
      if ( c[BYTESIN] == 1 || (c[BYTESIN] % 400) == 0) {
#ifdef __MSDOS__
	savegame(ckpfile);
#else
	wait((int *)0);/* wait for other forks to finish */
	if (fork() == 0) { 
	  savegame(ckpfile); 
	  exit(0); 
	}
#endif /* __MSDOS__ */
      }
    flushall();
    cc = getcharacter();
    
    if (cc == '!')	/* shell escape */
    { 	
      resetscroll();  
      clear();
      sncbr();
      cl_dn(0,0);
      lflush();
#ifdef __MSDOS__
      system("COMMAND");
#else
      if ((ic=fork())==0) {
	execl("/bin/csh", "/bin/csh", (char *)0);	
	exit(1);
      }
      do { 
	i = wait(0);
      } while (i != ic && i != -1);
      
      if (ic<0) { 	
	fprintf(stderr,"Can't fork /bin/csh!\n"); 
	fflush(stderr);
	nap(2200);
      }
#endif
      setscroll();
      scbr();
      return(lastok = 'L'-0x40);	/* ^L == redisplay screen */
    };
    if ((cc <= '9') && (cc >= '0')){ 
      yrepcount = yrepcount*10 + cc - '0'; 
    }else{
      if (yrepcount>0) --yrepcount;  
      return(lastok = cc); 
    };
  }
}

/*
 *	flushall()	Function to flush all type-ahead in the input buffer
 */
flushall()
{
#ifdef BSD
  char cc;
  int ic;
  
  for (;;)/* if keyboard input buffer is too big, flush some of it */
  {
    ioctl(0,FIONREAD,&ic);
    if (ic<=0) return;
    while (ic>0)   { 
      read(0,&cc,1); 
      --ic; 
    } /* gobble up the byte */
  }
#else /* SYSV */
# ifdef __MSDOS__
  while (kbhit()) (void)getch();
# else
#  ifdef TCIFLUSH
  tcflush(0, TCIFLUSH);		/* SYSV w/POSIX 1003 tcflush() */
#  else
  ioctl(0, TCFLSH);		/* standard ioctl */
#  endif /* TCIFLUSH */
# endif /* __MSDOS__ */
#endif /* BSD */
}

/*
  function to set the desired hardness 
  enter with hard= -1 for default hardness, else any desired hardness
  */
sethard(hard)
     int hard;
{
  register int j,k;
  long i;
  
  if (restorflag==0)  {      /* don't set c[HARDGAME] if restoring game */
    if (hashewon() == 0) {
      if (hard >= 0) 
	c[HARDGAME] = hard;
    }
    else  if (hard > c[HARDGAME]) c[HARDGAME] = hard;
  }
  
  if ((k=c[HARDGAME])!=0)
    for (j=0; j<=MAXMONST+8; j++) {
      i = ((6+k)*monster[j].hitpoints+1)/6;
      monster[j].hitpoints = (i<0) ? 32767 : i;
      i = ((6+k)*monster[j].damage+1)/5;
      monster[j].damage = (i>127) ? 127 : i;
      i = (10*monster[j].gold)/(10+k);
      monster[j].gold = (i>32767) ? 32767 : i;
      i = monster[j].armorclass - k;
      monster[j].armorclass = (i< -127) ? -127 : i;
      i = (7*monster[j].experience)/(7+k) + 1;
      monster[j].experience = (i<=0) ? 1 : i;
    }				
}

static int char_picked = 0;

typedef struct CHAR_TAG {
  char *name;
  int strength;
  int intelligence;
  int wisdom;
  int constitution;
  int dexterity;
  int charisma;
  int hitpts;
  int *init_arr;
  int wield;
  int wear;
  int n_spells;
  int spellmax;
} CHARTYP;

#define Op       OPOTION
#define Os       OSCROLL
#define Ol       OLEATHER
#define Om       OSTUDLEATHER
#define Od       ODAGGER
#define Si       static int 
#define Rbt      (0x800)    /* call rund() ? */
#define Rb6      (Rbt | 6)
#define Rms      (0x7FF)    /* mask to delete Rbt */

Si init_o[] = { Op, Rb6,     Op, Rb6, NO_OBJ,              S_MLE, S_NON};
Si init_w[] = { Op, P_TRS_F, Os, Rb6, Os, Rb6,     NO_OBJ, S_MLE, S_CHM, S_NON};
Si init_k[] = { Om, 1,       Op, Rb6, NO_OBJ,              S_SSP, S_NON};
Si init_e[] = { Ol, 1,       Os, Rb6, NO_OBJ,              S_PRO, S_NON};
Si init_r[] = { Od, 1,       Ol, 1,   Os, R_STEAL, NO_OBJ, S_MLE, S_NON};
Si init_g[] = { Ol, Rb6,     Od, Rb6, NO_OBJ,              S_PRO, S_MLE, S_NON};
Si init_d[] = { OSPEAR, 0,   NO_OBJ,                       S_PRO, S_NON};
Si init_b[] = { OLANCE, 0,   NO_OBJ,                       S_NON};
Si init_l[] = { NO_OBJ,                                    S_STP, S_NON};

static CHARTYP chartyps[] = {
  {{"Ogre"},      18,  4,  6, 16,  6,  4, 16, init_o, -1, -1, 1, 1}
 ,{{"Wizard"},     8, 16, 16,  6,  6,  8,  8, init_w, -1, -1, 2, 2}
 ,{{"Klingon"},   14, 12,  4, 12,  8,  3, 14, init_k, -1,  0, 1, 1}
 ,{{"Elf"},        8, 14, 12,  8,  8, 14,  8, init_e, -1,  0, 1, 2}
 ,{{"Rogue"},      8, 12,  8, 10, 14,  6, 12, init_r,  1,  0, 1, 1}
 ,{{"Geek"},      12, 12, 12, 12, 12, 12, 10, init_g, -1, -1, 1, 1}
 ,{{"Dwarf"},     16,  6,  8, 16,  4,  4, 12, init_d,  0, -1, 1, 1}
 ,{{"Rambo"},      3,  3,  3,  3,  3,  3,  1, init_b,  0, -1, 0, 0}
 ,{{"Rincewind"},  6, 18, 12,  4,  4,  4,  1, init_l, -1, -1, 0, 9}
};

#undef Op
#undef Os
#undef Ol
#undef Om
#undef Od
#undef Si
#undef Rb6

#define W_ILLEG(x) ((((x) < 'a') || ((x) >= ('a'+ N_ELEM(chartyps)))) \
                 && (((x) < 'A') || ((x) >= ('A'+ N_ELEM(chartyps)))))

pick_char()
{
  int i, j, inx;
  int *pi;
  
  nosignal = 1; /* disable signals */

  if ( W_ILLEG(char_picked) ) {
    clear();
    lprcat("\t\tThe Addiction of Ularn\n\n");
    lprcat("Pick a character class...\n\n\n");
    lprcat("\t\t    Character\n\n");
    
    for (i=0; i < N_ELEM(chartyps)-1; i++){   /* not displaying the last */
      lprintf("\t\t%c)  %s\n", i+ 'a', chartyps[i].name);
    };
    
    cursors();
    lprcat("\nSo, what are ya? ");
    lflush();
    
    do {
      char_picked = getcharacter();
    } while ( W_ILLEG(char_picked) );
  };
      
  for (j=0; i<NINVT; i++)  
    iven[j] = 0;
  c[SHIELD]       = -1;
  c[LEVEL]        = 1;		/*	player starts at level one	*/
  c[REGENCOUNTER] = 16;
  c[ECOUNTER]     = 96;		/*start regeneration correctly*/
  
  i = char_picked - 'a';
  if ( i < 0 ) i += 'a'-'A';
  strcpy(char_class, chartyps[i].name);
  c[STRENGTH]     = chartyps[i].strength;
  c[INTELLIGENCE] = chartyps[i].intelligence;
  c[WISDOM]       = chartyps[i].wisdom;
  c[CONSTITUTION] = chartyps[i].constitution;
  c[DEXTERITY]    = chartyps[i].dexterity;
  c[CHARISMA]     = chartyps[i].charisma;
  c[HPMAX]        =  
  c[HP]           = chartyps[i].hitpts;
  for (pi=chartyps[i].init_arr, inx=0; (j = pi[0]) != NO_OBJ; pi +=2, inx++) {
    iven[inx]     = j;
    j             = pi[1];
    if ( j & Rbt ) {
      j           = rund( j & Rms );
    };
    ivenarg[inx]  = j;
  };
  for (; (inx = pi[0]) != S_NON; pi++) {
    spelknow[inx] = 1;
  }; 
  c[WIELD]        = chartyps[i].wield;
  c[WEAR]         = chartyps[i].wear;
  c[SPELLMAX]     = chartyps[i].spellmax;
  c[SPELLS]       = chartyps[i].n_spells;

  if ( c[SPELLMAX] == 9 ){     /* Rincewind: run fast, live longer */
    c[AGGRAVATE]     = 99999L;
    c[INVISIBILITY]  = 99999L;
    c[HASTESELF]     = 99999L;
    c[CANCELLATION]  = 99999L;
    c[WTW]           = 99999L;
    c[TIMESTOP]      = 45;
    c[AWARENESS]     = 99999L;
  };

  nosignal = 0;
} /* end pick_char */

#undef Rbt
#undef Rms
#undef W_ILLEG


/*
  function to read and process the larn options file
  */
readopts()
{
  register char *i, *pch2;
  register int j,k;
  int flag=1, hab_ihm, eos, ch1, ch2;
  
  if (lopen(optsfile, 0) < 0) {
    strcpy(logname,loginname); 
    return -1; /* user name if no character name */
  }
  i = " ";
  while (*i) {
    if ((i=(char *)lgetw()) == 0) break; /* check for EOF */
    while ((*i==' ') || (*i=='\t')) i++; /* eat leading whitespace*/
    switch(*i) {
    case 'b':	
              if (strcmp(i,"bold-off") == 0)  
		boldon=0;
#ifdef __MSDOS__
	      else if (strcmp(i, "background:") == 0) {
		extern int bg_color;
		if ((i = lgetw())==0) break;
		bg_color = parse_color(i, bg_color);
	      }
#endif
	      break;

    case 'e':	
	      if (strcmp(i,"enable-checkpointing") == 0) 
		ckpflag=1;
	      break;

    case 'f':	
	      if (strcmp(i,"female") == 0)	
		is_male=0; /* female */
#ifdef __MSDOS__
	      else if (strcmp(i, "foreground:") == 0) {
		extern int fg_color;
		if ((i = lgetw())==0) break;
		fg_color = parse_color(i, fg_color);
	      }
#endif
	      break;

			/* name favorite monster */
    case 'm':	
	      if (strcmp(i,"monster:")== 0)   {
		if ((i=lgetw())==0) break;
		if (strlen(i)>=MAXMNAME) i[MAXMNAME-1]=0;
		strcpy(usermonster[usermpoint],i);
		/* defined all of em */
		if (usermpoint >= MAXUM) break; 
		if (isalpha(j=usermonster[usermpoint][0])) {
		  for (k=1; k<MAXMONST+8; k++)
		    if (monstnamelist[k] == j) {
		      monster[k].name = &usermonster[usermpoint++][0];
		      break;
		    }
		}
	      }
	      else if (strcmp(i,"male") == 0)	is_male=1;
	      break;

    case 'n':	
	      if (strcmp(i,"name:") == 0) {
		if ((i=lgetw())==0) break;
		if (strlen(i)>=LOGNAMESIZE) 
		  i[LOGNAMESIZE-1]=0;
		strcpy(logname,i); 
		flag=0;
	      }
	      else if (strcmp(i,"no-introduction") == 0) 
		nowelcome=1;
	      else if (strcmp(i,"no-beep") == 0) 
		nobeep=1;
#ifdef __MSDOS__
	      else if (strcmp(i, "nansi") == 0) {
		extern int nansi;
		nansi=1;
	      }
#endif
	      break;

    case 'c':
	      if ( (strcmp(i,"character:") == 0) && (i=lgetw()) ) { 
		for (j=0, hab_ihm=FALSE; ! ( (j >= N_ELEM(chartyps)) || hab_ihm ); j++){
		  pch2 = chartyps[j].name;
		  for (eos=FALSE; ! eos; i++, pch2++){ /* strcmp in lower case */
		    ch1 = *i;
		    if ( (ch1 >= 'A') && (ch1 <= 'Z') ){ ch1 += 0x20; };
		    ch2 = *pch2;
		    if ( (ch2 >= 'A') && (ch2 <= 'Z') ){ ch2 += 0x20; };
		    hab_ihm = (ch1 == ch2);
		    eos     = (ch1 == 0) || (ch2 == 0) || (! hab_ihm);
		  }; 
		  char_picked = j +'a';  /* the last value is the one */
		};
	      };
	      if ( ! hab_ihm ) { char_picked = 0; };
	      break;
    case 's':	
	      if (strcmp(i,"savefile:") == 0) {
		if ((i=lgetw())==0) break;
		if (strlen(i)>=SAVEFILENAMESIZE)
		  i[SAVEFILENAMESIZE-1]=0;
		strcpy(savefilename,i); 
	      }
	      break;
    case 'g':
	      if (strcmp(i, "graphics:") == 0) {
		int c;
		if ((i=lgetw())==0) break;
		c = atoi(i);
		if (c <= 0 || c > 255) break;
		objnamelist[0] = c;
		monstnamelist[INVISIBLESTALKER] = c;
		monstnamelist[DEMONLORD  ] = c;
		monstnamelist[DEMONLORD+1] = c;
		monstnamelist[DEMONLORD+2] = c;
		monstnamelist[DEMONLORD+3] = c;
		monstnamelist[DEMONLORD+4] = c;
		monstnamelist[DEMONLORD+5] = c;
		monstnamelist[DEMONLORD+6] = c;
		monstnamelist[DEMONPRINCE] = c;
		monstnamelist[LUCIFER]     = c;
		objnamelist[OTRAPARROWIV]  = c;
		objnamelist[OIVDARTRAP]    = c;
		objnamelist[OIVTRAPDOOR]   = c;
		objnamelist[OIVTELETRAP]   = c;
		if ((i=lgetw())==0) break;
		c = atoi(i);
		if (c <= 0 || c > 255) break;
		objnamelist[OWALL] = c;
	      }
	      break;
#ifdef __MSDOS__
    case 'k':
	      if (strcmp(i, "keypad") == 0) {
		extern int keypad;
		keypad = 1;
	      }
	      break;
    case 'r':
	      if (strcmp(i, "rawio") == 0) {
		extern int rawio;
		rawio = 1;
	      }
	      break;
    case 'l':
	      if (strcmp(i, "larn-path:") == 0) {
		extern char larnpath[];
		if ((i=lgetw())==0) break;
		if (strlen(i)>=SAVEFILENAMESIZE-1)
		  i[SAVEFILENAMESIZE-2]=0;
		strcpy(larnpath,i); 
		i = larnpath + strlen(larnpath) - 1;
		if (i >= larnpath &&
		    !(*i == '/' || *i == '\\')) {
		  *++i = '\\';
		  *++i = '\0';
		}
		i = " ";
	      }
	      break;

#endif
    };
  }
  if (flag)  strcpy(logname,loginname);
  return 0;
}


#ifdef __MSDOS__

static char *colors[8] = { "bla", "r", "g", "y", "blu", "m", "c", "w" };

int parse_color(name, old)
     char *name;
     int old;
{
  int i;
  
  for (i=0; i<8; i++)
    if (strncmp(name, colors[i], strlen(colors[i])) == 0) return i;
  
  printf("Unknown color name %s\n", name);
  nap(2000);
  
  return old;
}

#endif  /* __MSDOS__ */






