/*
 * COMMAND1.C:
 *
 *	Command handling/parsing routines.
 *
 *	Copyright (C) 1991, 1992, 1993 Brett J. Vickers
 *
 */

#include "mstruct.h"
#include "mextern.h"
#include <ctype.h>
#include <string.h>
#ifdef DMALLOC
  #include "/usr/local/include/dmalloc.h"
#endif
/**********************************************************************/
/*				login				      */
/**********************************************************************/

/* This function is the first function that gets input from a player when */
/* he logs in.  It asks for the player's name and password, and performs  */
/* the according function calls.					  */

void login(fd, param, str)
int 	fd;
int	param;
char	*str;
{
	int		i, match=0;
	extern int	Numplayers;
	char		tempstr[20], str2[50];
	long 		t, x;
	creature	*ply_ptr;


	switch(param) {
	case 0:
		if(strcmp(Ply[fd].extr->tempstr[0], str)) {
			disconnect(fd);
			return;
		}
		print(fd, "\nPlease enter name: ");
		RETURN(fd, login, 1);
	case 1:


		if(!isalpha(str[0])) {
			print(fd, "Please enter name: ");
			RETURN(fd, login, 1);
		}

#ifdef PARANOID

		
	/* Check for ident */
        if((!strcmp(Ply[fd].io->userid, "no_port") || !strcmp(Ply[fd].io->userid, "unknown")) && (strcmp(Ply[fd].io->address, "moria.bio.uci.edu") || strcmp(Ply[fd].io->address, "128.200.21.101"))) {
                        print(fd, "\n\nI am unable to get authorization from your server.\n");
			print(fd, "Please try connecting from another host, or contact\n");
			print(fd, "your system administrator to request RFC 931 auth/identd.\n\n");
			print(fd, "If you have connected from this account in the past,\n");
			print(fd, "try logging in more slowly.\n\n");
			print(fd, "\n      Send any questions to:\n");
			print(fd, "      imail@moria.bio.uci.edu\n\n");
			output_buf();
                        disconnect(fd);
                        return;
                }
#endif

		/* Check for double log */
	for(i=0; i<Tablesize; i++) {
                if(!Ply[i].ply) continue;
                if(Ply[i].ply->fd < 0) continue;
		if(strcmp(Ply[i].io->userid, "no_port") || strcmp(Ply[i].io->userid, "unknown")) continue;
                if(!strcmp(Ply[i].io->userid, Ply[fd].io->userid)) {
                        match += 1;
                        if(match > 0){
                                print(fd, "\n\nYour account is already in Isengard.\n");
                                print(fd, "Please only play one character at a time.\n\n");
				output_buf();
                                disconnect(fd);
                                return;
                        }
                }
        }


		if(strlen(str) < 3) {
			print(fd, "Name must be at least 3 characters.\n\n");
			print(fd, "Please enter name: ");
			RETURN(fd, login, 1);
		}
		if(strlen(str) >= 20) {
			print(fd, "Name must be less than 20 characters.\n\n");
			print(fd, "Please enter name: ");
			RETURN(fd, login, 1);
		}

		for(i=0; i<strlen(str); i++)
			if(!isalpha(str[i])) {
				print(fd, "Name must be alphabetic.\n\n");
				print(fd, "Please enter name: ");
				RETURN(fd, login, 1);
			}

		lowercize(str, 1);
		str[25]=0;
		if(load_ply(str, &ply_ptr) < 0) {
			strcpy(Ply[fd].extr->tempstr[0], str);
			print(fd, "\n%s? Did I get that right? ", str);
			RETURN(fd, login, 2);
		}

		else {
			ply_ptr->fd = -1;
			Ply[fd].ply = ply_ptr;
#ifdef CHECKDOUBLE
			if(checkdouble(ply_ptr->name)) {
				scwrite(fd, "No simultaneous playing.\n\r", 26);
				disconnect(fd);
				return;
			}
#endif /* CHECKDOUBLE */

			print(fd, "%c%c%cPlease enter password: ", 255, 251, 1); 
			RETURN(fd, login, 3);
		}

	case 2:
		if(str[0] != 'y' && str[0] != 'Y') {
			Ply[fd].extr->tempstr[0][0] = 0;
			print(fd, "Please enter name: ");
			RETURN(fd, login, 1);
		}
		else {
			print(fd, "\nHit return: ");
			RETURN(fd, create_ply, 1);
		}

	case 3:
		if(strcmp(str, Ply[fd].ply->password)) {
			scwrite(fd, "\255\252\1\n\rIncorrect.\n\r", 17);
			disconnect(fd);
			return;
		}
		else {
			print(fd, "%c%c%c\n\r", 255, 252, 1);
			strcpy(tempstr, Ply[fd].ply->name);
			for(i=0; i<Tablesize; i++)
				if(Ply[i].ply && i != fd)
					if(!strcmp(Ply[i].ply->name, 
					   Ply[fd].ply->name))
						disconnect(i);	
			free_crt(Ply[fd].ply);

/* It used to cause a crash if a player suicided at the same time */
/* as creating a new charater, this fixes it.			  */

		if(load_ply(tempstr, &Ply[fd].ply) < 0)
		{
			scwrite(fd, "Player nolonger exits!\n\r", 24);
                        t = time(0);
                        strcpy(str2, (char *)ctime(&t));
                        str2[strlen(str2)-1] = 0;
                        logn("sui_crash","%s: %s (%s) suicided.\n", 
				str2, Ply[fd].ply->name, Ply[fd].io->address);         
			disconnect(fd);
			return;
		}
			Ply[fd].ply->fd = fd;
			init_ply(Ply[fd].ply);
			RETURN(fd, command, 1);
		}
	}
}

/**********************************************************************/
/*				create_ply			      */
/**********************************************************************/

/* This function allows a new player to create his or her character. */

void create_ply(fd, param, str)
int	fd;
int	param;
char	*str;
{
	int 	i, k, l, n, sum;
	int	num[5];

	switch(param) {
	case 1:
		print(fd,"\n\n");
		Ply[fd].ply = (creature *)malloc(sizeof(creature));
		if(!Ply[fd].ply)
			merror("create_ply", FATAL);
		zero(Ply[fd].ply, sizeof(creature));
		Ply[fd].ply->fd = -1;
		Ply[fd].ply->rom_num = 1;
		print(fd, "Male or Female: ");
		RETURN(fd, create_ply, 2);
	case 2:
		if(low(str[0]) != 'm' && low(str[0]) != 'f') {
			print(fd, "Male or Female: ");
			RETURN(fd, create_ply, 2);
		}
		if(low(str[0]) == 'm')
			F_SET(Ply[fd].ply, PMALES);
		print(fd, "\nAvailable classes:\n");
		print(fd, "Assassin, Barbarian, Bard, Cleric, Fighter,\n");
		print(fd, "Mage, Monk, Paladin, Ranger, Thief\n");
		print(fd, "Choose one: ");
		RETURN(fd, create_ply, 3);
	case 3:
		switch(low(str[0])) {
			case 'a': Ply[fd].ply->class = ASSASSIN; break;
			case 'b': switch(low(str[3])) {
				case 'b':Ply[fd].ply->class = BARBARIAN; break;
				case 'd':Ply[fd].ply->class = BARD; break;
				}
				break;
			case 'c': Ply[fd].ply->class = CLERIC; break;
			case 'f': Ply[fd].ply->class = FIGHTER; break;
			case 'm': switch(low(str[1])) {
				case 'a':Ply[fd].ply->class = MAGE; break;
				case 'o':Ply[fd].ply->class = MONK; break;
				}
				break;
			case 'p': Ply[fd].ply->class = PALADIN; break;
			case 'r': Ply[fd].ply->class = RANGER; break;
			case 't': Ply[fd].ply->class = THIEF; break;
			default: print(fd, "Choose one: "); 
				 RETURN(fd, create_ply, 3);
		}
		if(!Ply[fd].ply->class) {
			print(fd, "Invalid selection: %s", str);
			print(fd, "\nChoose one: ");
			RETURN(fd, create_ply, 3);
		}

		print(fd, "\nYou have 54 points to distribute among your 5 stats. Please enter your 5\nnumbers in the following order: Strength, Dexterity, Constitution,\nIntelligence, Piety.  No stat may be smaller than 3 or larger than 18.\nUse the following format: ## ## ## ## ##\n");
		print(fd, ": ");
		RETURN(fd, create_ply, 4);
	case 4:
		n = strlen(str); l = 0; k = 0;
		for(i=0; i<=n; i++) {
			if(str[i]==' ' || str[i]==0) {
				str[i] = 0;
				num[k++] = atoi(&str[l]);
				l = i+1;
			}
			if(k>4) break;
		}
		if(k<5) {
			print(fd, "Please enter all 5 numbers.\n");
			print(fd, ": ");
			RETURN(fd, create_ply, 4);
		}
		sum = 0;
		for(i=0; i<5; i++) {
			if(num[i] < 3 || num[i] > 18) {
				print(fd, "No stats < 3 or > 18 please.\n");
				print(fd, ": ");
				RETURN(fd, create_ply, 4);
			}
			sum += num[i];
		}
		if(sum > 54) {
			print(fd, "Stat total may not exceed 54.\n");
			print(fd, ": ");
			RETURN(fd, create_ply, 4);
		}
		Ply[fd].ply->strength = num[0];
		Ply[fd].ply->dexterity = num[1];
		Ply[fd].ply->constitution = num[2];
		Ply[fd].ply->intelligence = num[3];
		Ply[fd].ply->piety = num[4];
		print(fd, "\nChoose a weapons proficiency:\n");
		print(fd, "Sharp, Thrusting, Blunt, Pole, Missile.\n");
		print(fd, ": ");
		RETURN(fd, create_ply, 5);
	case 5:
		switch(low(str[0])) {
			case 's': Ply[fd].ply->proficiency[0]=1024; break;
			case 't': Ply[fd].ply->proficiency[1]=1024; break;
			case 'b': Ply[fd].ply->proficiency[2]=1024; break;
			case 'p': Ply[fd].ply->proficiency[3]=1024; break;
			case 'm': Ply[fd].ply->proficiency[4]=1024; break;
			default: print(fd, "Try again.\n: ");
				 RETURN(fd, create_ply, 5);
		}
		print(fd, "\nLawful players cannot attack or steal from other players, nor can they\nbe attacked or stolen from by other players.");
		print(fd, "\nChaotic players may attack or steal from other chaotic players, and they can\nbe attacked or stolen from by other chaotic players.\n");
		print(fd, "\nChoose an alignment, Chaotic or Lawful: ");
		RETURN(fd, create_ply, 6);
	case 6:
		if(low(str[0]) == 'c')
			F_SET(Ply[fd].ply, PCHAOS);
		else if(low(str[0]) == 'l')
			F_CLR(Ply[fd].ply, PCHAOS);
		else {
			print(fd, "Chaotic or Lawful: ");
			RETURN(fd, create_ply, 6);
		}
		print(fd, "\nAvailable races:");
		print(fd, "\nDwarf, Dark-elf, Elf, Gnome, Goblin, Half-elf,");
		print(fd, "\nHalf-giant, Half-orc, Hobbit, Human, Ogre, Orc, Troll");
		print(fd, "\nChoose one: ");
		RETURN(fd, create_ply, 7);
	case 7:
		switch(low(str[0])) {
		case 'd': switch(low(str[1])) {
 			case 'a': Ply[fd].ply->race = DARKELF; break;
			case 'w': Ply[fd].ply->race = DWARF; break;
			}
			break;
		case 'e': Ply[fd].ply->race = ELF; break;
		case 'g': switch(low(str[1])) { 
			case 'n': Ply[fd].ply->race = GNOME; break;
			case 'o': Ply[fd].ply->race = GOBLIN; break;
			}
			break;
		case 'o': switch(low(str[1])) {
			case 'g': Ply[fd].ply->race = OGRE; break;
			case 'r': Ply[fd].ply->race = ORC; break;
			}
			break;
		case 't': Ply[fd].ply->race = TROLL; break;
		case 'h': switch(low(str[1])) {
			case 'a': switch(low(str[5])) {
				case 'e': Ply[fd].ply->race = HALFELF; break;
				case 'g': Ply[fd].ply->race = HALFGIANT; break;
				case 'o': Ply[fd].ply->race = HALFORC; break;
				}
				break;
			case 'o': Ply[fd].ply->race = HOBBIT; break;
			case 'u': Ply[fd].ply->race = HUMAN; break;
			}
			break;
		}
		if(!Ply[fd].ply->race) {
			print(fd, "\nChoose one: ");
			RETURN(fd, create_ply, 7);
		}

		switch(Ply[fd].ply->race) {
		case DARKELF:
			Ply[fd].ply->intelligence+=1;
			Ply[fd].ply->constitution+=1;
			Ply[fd].ply->piety-=2;
			break;
		case DWARF: 
			Ply[fd].ply->strength++; 
			Ply[fd].ply->piety--; 
			break;
		case ELF: 
			Ply[fd].ply->intelligence+=2;
			Ply[fd].ply->constitution--;
			Ply[fd].ply->strength--; 
			break;
		case GOBLIN:
			Ply[fd].ply->intelligence-=2;
			Ply[fd].ply->constitution++;
			Ply[fd].ply->strength++;
			break;
		case GNOME:
			Ply[fd].ply->piety++;
			Ply[fd].ply->strength--;
			break;
		case HALFELF: 
			Ply[fd].ply->intelligence++; 
			Ply[fd].ply->constitution--; 
			break;
		case HALFORC:
			Ply[fd].ply->constitution--;
			break;			
		case HOBBIT: 
			Ply[fd].ply->dexterity++; 
			Ply[fd].ply->strength--; 
			break;
		case HUMAN: 
			Ply[fd].ply->constitution++; 
			break;
		case OGRE:
			Ply[fd].ply->strength++;
			Ply[fd].ply->piety--;
			break;
		case ORC: 
			Ply[fd].ply->strength++; 
			Ply[fd].ply->constitution++;
			Ply[fd].ply->dexterity--; 
			Ply[fd].ply->intelligence--;
			break;
		case TROLL: 
			Ply[fd].ply->strength++; 
			Ply[fd].ply->intelligence--;
			break;
		case HALFGIANT: 
			Ply[fd].ply->strength+=2; 
			Ply[fd].ply->intelligence--; 
			Ply[fd].ply->piety--; 
			break;
		}

		print(fd, "\nChoose a password (up to 14 chars): ");
		RETURN(fd, create_ply, 8);
	case 8:
		if(strlen(str) > 14) {
			print(fd, "Too long.\nChoose a password: ");
			RETURN(fd, create_ply, 8);
		}
		if(strlen(str) < 3) {
			print(fd, "Too short.\nChoose a password: ");
			RETURN(fd, create_ply, 8);
		}
		strncpy(Ply[fd].ply->password, str, 14);
		strcpy(Ply[fd].ply->name, Ply[fd].extr->tempstr[0]);
		up_level(Ply[fd].ply);
		Ply[fd].ply->fd = fd;
		init_ply(Ply[fd].ply);
		save_ply(Ply[fd].ply->name, Ply[fd].ply);
		print(fd, "\n");
		F_SET(Ply[fd].ply, PNOAAT);
		print(fd, "Type 'welcome' at prompt to get more info on the game\nand help you get started.\n");

		RETURN(fd, command, 1);
	}
}

/**********************************************************************/
/*				command			 	      */
/**********************************************************************/

/* This function handles the main prompt commands, and calls the   	*/
/* appropriate function, depending on what service is requested by the 	*/
/* player.								*/

void command(fd, param, str)
int	fd;
int	param;
char	*str;
{
	cmd	cmnd;
	int	n;
	unsigned char ch;

#ifdef RECORD_ALL
/*
this logn command will print out all the commands entered by players.
It should be used in extreme cases when trying to isolate a players
input which may be causing a crash.
*/

logn("all_cmd","\n%s-%d (%d): %s\n",Ply[fd].ply->name,fd,Ply[fd].ply->rom_num,str);  
#endif /* RECORD_ALL */ 

	switch(param) {
	case 1:

		if(F_ISSET(Ply[fd].ply, PHEXLN)) {
			for(n=0;n<strlen(str);n++) {
				ch = str[n];
				print(fd, "%02X", ch);
			}
			print(fd, "\n");
		}

		if(!strcmp(str, "!"))
			strncpy(str, Ply[fd].extr->lastcommand, 79);

		if(str[0]) {
			for(n=0; str[n] && str[n] == ' '; n++) ;
			strncpy(Ply[fd].extr->lastcommand, &str[n], 79);
		}

		strncpy(cmnd.fullstr, str, 255);
		lowercize(str, 0);
		parse(str, &cmnd); n = 0;

		if(cmnd.num)
			n = process_cmd(fd, &cmnd);
		else
			n = PROMPT;

		if(n == DISCONNECT) {
			scwrite(fd, "Goodbye!\n\r\n\r", 11);
			disconnect(fd);
			return;
		}
		else if(n == PROMPT) {
			if(F_ISSET(Ply[fd].ply, PPROMP))
				sprintf(str, "(%d H %d M): ", 
					Ply[fd].ply->hpcur, Ply[fd].ply->mpcur);
			else
				strcpy(str, ": ");
			scwrite(fd, str, strlen(str));
		}

		if(n != DOPROMPT) {
			RETURN(fd, command, 1);
		}
		else
			return;
	}
}

/**********************************************************************/
/*				parse				      */
/**********************************************************************/

/* This function takes the string in the first parameter and breaks it */
/* up into its component words, stripping out useless words.  The      */
/* resulting words are stored in a command structure pointed to by the */
/* second argument. 						       */

void parse(str, cmnd)
char	*str;
cmd	*cmnd;
{
	int	i, j, l, m, n, o, art;
	char	tempstr[25];

	l = m = n = 0;
	j = strlen(str);

	for(i=0; i<=j; i++) {
		if(str[i] == ' ' || str[i] == '#' || str[i] == 0) {
			str[i] = 0;	/* tokenize */

			/* Strip extra white-space */
			while((str[i+1] == ' ' || str[i] == '#') && i < j+1)
				str[++i] = 0;

			strncpy(tempstr, &str[l], 24); tempstr[24] = 0;
			l = i+1;
			if(!strlen(tempstr)) continue;

			/* Ignore article/useless words */
			o = art = 0;
			while(article[o][0] != '@') {
				if(!strcmp(article[o++], tempstr)) {
					art = 1;
					break;
				}
			}
			if(art) continue;

			/* Copy into command structure */
			if(n == m) {
				strncpy(cmnd->str[n++], tempstr, 20);
				cmnd->val[m] = 1L;
			}
			else if(isdigit(tempstr[0]) || (tempstr[0] == '-' &&
				isdigit(tempstr[1]))) {
				cmnd->val[m++] = atol(tempstr);
			}
			else {
				strncpy(cmnd->str[n++], tempstr, 20);
				cmnd->val[m++] = 1L;
			}

		}
		if(m >= COMMANDMAX) {
			n = 5;
			break;
		}
	}

	if(n > m)
		cmnd->val[m++] = 1L;
	cmnd->num = n;

}

/**********************************************************************/
/*				process_cmd			      */
/**********************************************************************/

/* This function takes the command structure of the person at the socket */
/* in the first parameter and interprets the person's command.		 */

int process_cmd(fd, cmnd)
int	fd;
cmd	*cmnd;
{
	int	match=0, cmdno=0, c=0, n;

	do {
		if(!strcmp(cmnd->str[0], cmdlist[c].cmdstr)) {
			match = 1;
			cmdno = c;
			break;
		}
		else if(!strncmp(cmnd->str[0], cmdlist[c].cmdstr, 
			strlen(cmnd->str[0]))) {
			match++;
			cmdno = c;
		}
		c++;
	} while(cmdlist[c].cmdno);

	if(match == 0) {
		print(fd, "The command \"%s\" does not exist.\n",
		      cmnd->str[0]);
		RETURN(fd, command, 1);
	}

	else if(match > 1) {
		print(fd, "Command is not unique.\n");
		RETURN(fd, command, 1);
	}

	if(cmdlist[cmdno].cmdno < 0)
		return(special_cmd(Ply[fd].ply, 0-cmdlist[cmdno].cmdno, cmnd));
	
	return((*cmdlist[cmdno].cmdfn)(Ply[fd].ply, cmnd));

}

#ifdef CHECKDOUBLE

int checkdouble(name)
char *name;
{
	char	path[128], tempname[80];
	FILE 	*fp;
	int	rtn=0;

	sprintf(path, "%s/simul/%s", PLAYERPATH, name);
	fp = fopen(path, "r");
	if(!fp)
		return(0);

	while(!feof(fp)) {
		fgets(tempname, 80, fp);
		tempname[strlen(tempname)-1] = 0;
		if(!strcmp(tempname, name))
			continue;
		if(find_who(tempname)) {
			rtn = 1;
			break;
		}
	}

	fclose(fp);
	return(rtn);
}

#endif /* CHECKDOUBLE */
