roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * command1.cpp
 *	 Command handling/parsing routines.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "login.h"
#include "commands.h"
#include "factions.h"
#include "calendar.h"
#include <sys/stat.h>
#include <sstream>
#include <iomanip>
#include <locale>

//static int	newline;
//static int	color;

//#include <arpa/telnet.h>
//#define TELOPT_COMPRESS2       86


//*********************************************************************
//						cmdNoExist
//*********************************************************************
// This function tells the player the command does not exist.

int cmdNoExist(Player* player, cmd* cmnd) {
	player->print("The command \"%s\" does not exist.\n", cmnd->str[0]);
	return(0);
}

//*********************************************************************
//						cmdNoAuth
//*********************************************************************
// This function tells the player they're not allowed to use that command

int cmdNoAuth(Player* player) {
	player->print("You do not have the proper authorization to use that command.\n");
	return(0);
}

//*********************************************************************
//						getFailFd
//*********************************************************************
// This function grabs the fd to print error messages to.
// A check of "fd != ffd" means messages are going to different places,
// hence fd is a pet and ffd is a player. "fd == ffd" means a
// player is running the command.

int getFailFd(Creature *user) {
	if(!user)
		return(-1);
	return(user->isPet() ? user->following->fd : user->fd);
}


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

void command(Socket* sock, char* str) {
	cmd cmnd;
	bool needFree = false;
	int	n;
	Player* ply = sock->getPlayer();

	ASSERTLOG( ply );

	/*
	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.
	*/
	//zero(&cmnd, sizeof(cmd));


	if(ply->getClass() == CARETAKER && !dmIson() )
		log_immort(false, ply, "%s-%d (%s): %s\n", ply->name, sock->getFd(),
			ply->getRoom()->fullName().c_str(), str);

	if(!strcmp(str, "!")) {
		str = strdup(ply->getLastCommand().c_str());
		needFree = true;
		//strncpy(str, ply->lastcommand, 79);
	}
	if(str[0])
		ply->setLastCommand(str);


	strncpy(cmnd.fullstr, str, 255);

	stripBadChars(str); // removes '.' and '/'
	lowercize(str, 0);
	parse(str, &cmnd);

	if(needFree)
		free(str);

	n = 0;
	if(cmnd.num)
		n = cmdProcess(ply, &cmnd);
	else
		n = PROMPT;

	if(n == DISCONNECT) {
		sock->write("Goodbye!\n\r\n\r");
		sock->disconnect();
	} else if(n == PROMPT) {
		ply->sendPrompt();
	}

}

//#ifdef NEW_PARSER

//*********************************************************************
//						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(char *str, cmd *cmnd) {
	int		i=0, j=0, l=0, n=0;
	char	token[MAX_TOKEN_SIZE];
	int		isquote=0;

	j = strlen(str);

	for(i=0; i<=j; i++) {

		// look for first non space or comment
		if(str[i] == ' ')
			continue;

		// ok we at first non space
		if(str[i] == '\"') {
			isquote = 1;
			// skip quote char
			i++;
		}
		// save this position as the begining of a token
		l = i;

		// now find the end of the token
		if(isquote) {
			while(str[i] != '\0' && str[i] != '\"')
				i++;

			// terminate the token
			if(str[i] == '\"')
				str[i] = '\0';
		} else {
			while(str[i] != '\0' && str[i] != ' ')
				i++;

			// terminate the token
			str[i] = '\0';
		}

		// don't overflow the buffers
		strncpy(token, &str[l], MAX_TOKEN_SIZE);
		token[MAX_TOKEN_SIZE - 1] = 0;

		/* whas there any thing here? */
		if(!strlen(token)) {
			isquote = 0;
			continue;
		}

		if(isquote) {
			strncpy(cmnd->str[n], token, MAX_TOKEN_SIZE);
			cmnd->str[n][MAX_TOKEN_SIZE - 1] = '\0';
			cmnd->val[n] = 1L;
			isquote = 0;
		} else {
			// Copy into command structure
			if(n == 0) {
				strncpy(cmnd->str[n], token, MAX_TOKEN_SIZE);
				cmnd->str[n][MAX_TOKEN_SIZE - 1] = '\0';
				// set the value to 1 in case there is non following
				cmnd->val[n] = 1L;
				n++;
			}
			else if(isdigit((int)token[0]) || (token[0] == '-' &&
					isdigit((int)token[1]))) {
				// this is a value for the previous command
				cmnd->val[MAX(0, n - 1)] = atol(token);
			} else {
				strncpy(cmnd->str[n], token, MAX_TOKEN_SIZE);
				cmnd->str[n][MAX_TOKEN_SIZE - 1] = '\0';
				// set the value to 1 in case there is non following
				cmnd->val[n] = 1L;
				n++;
			}
		}

		if(n >= COMMANDMAX)
			break;
	}

	// set the number of tokens in the command struct
	cmnd->num = n;
}
//void parse(char	*str, cmd* cmnd) {
//	int	i, j, l, n, o, art;
//	char	tempstr[25];
//	int		isquote;
//
//	l = n = 0;
//	j = strlen(str);
//	isquote = 0;
//
//	for(i=0; i<=j; i++) {
//
//		// look for first non space
//		// apparently # is treated like a space
//		if(str[i] == ' ')//  || str[i] == '#' )
//			continue;
//
//		// ok we at first non space
//		if( str[i] == '\"' ) {
//			isquote = 1;
//			// skip quote char
//			i++;
//		}
//
//		// save this position as the begining of a token
//		l = i;
//
//		// now find the end of the token
//		if( isquote ) {
//			while( str[i] != '\0' && str[i] != '\"' ) {
//				i++;
//			}
//
//			// terminate the token
//			if( str[i] == '\"' ) {
//				str[i] = '\0';
//			}
//		} else {
//			while( str[i] != '\0' && str[i] != ' ' && str[i] != '#') {
//				i++;
//			}
//
//			// terminate the token
//			str[i] = '\0';
//		}
//
//		strncpy(tempstr, &str[l], 24);
//		tempstr[24] = 0;
//
//		// whas there any thing here?
//		if(!strlen(tempstr)) {
//			isquote = 0;
//			continue;
//		}
//
//		if( isquote ) {
//			strncpy(cmnd->str[n], tempstr, 20);
//			cmnd->str[n][21] = '\0';
//			cmnd->val[n] = 1L;
//			isquote = 0;
//			n++;
//		} else {
//			// Copy into command structure
//			if(n == 0) {
//				strncpy(cmnd->str[n], tempstr, 20);
//				cmnd->str[n][21] = '\0';
//				// set the value to 1 in case there is non following
//				cmnd->val[n] = 1L;
//				n++;
//			} else if(isdigit(tempstr[0]) || (tempstr[0] == '-' &&
//				isdigit(tempstr[1]))) {
//				// this is a value for the previous command
//				cmnd->val[MAX(0, n - 1)] = atol(tempstr);
//			} else {
//				strncpy(cmnd->str[n], tempstr, 20);
//				cmnd->str[n][21] = '\0';
//				// set the value to 1 in case there is non following
//				cmnd->val[n] = 1L;
//				n++;
//			}
//		}
//
//		if(n >= COMMANDMAX) {
//			break;
//		}
//	}
//
//	// set the number of tokens in the command struct
//	cmnd->num = n;
//
//	return;
//}
//


#if 0

//*********************************************************************
//						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(char	*str, cmd* cmnd) {
	int	i, j, l, m, n;
	//int 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) {
		if(str[i] == ' ' || str[i] == 0) {
			str[i] = 0;	// tokenize

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

			strncpy(tempstr, &str[l], 24);
			tempstr[24] = 0;
			l = i+1;
			if(!strlen(tempstr))
				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;

}


#endif


//*********************************************************************
//						checkdouble
//*********************************************************************

void checkdouble(int fd, int i) {
//	ASSERTLOG(fd);
//	ASSERTLOG(i);
//
//	if(strstr(sock->getHostname().c_str(), "localhost"))
//		return;
//	if(!ply->name[0] || ply->name[0] == ' ' || ply->name[0] == '\0'
//		|| ply->name[0] == 0)
//		return;
//	if(!Ply[i].ply->name[0] || Ply[i].ply->name[0] == ' ' || Ply[i].ply->name[0] == '\0'
//		|| Ply[i].ply->name[0] == 0)
//		return;
//	if(!Ply[i].ply || !ply)
//		return;
//	if(Ply[i].ply->flagIsSet(P_ON_PROXY) || ply->flagIsSet(P_ON_PROXY))
//		return;
//	if(Ply[i].ply->isWatcher() || ply->isWatcher())
//		return;
//	if(ply->isCt() || Ply[i].ply->isCt())
//		return;
//	if(Ply[i].ply->flagIsSet(P_LINKDEAD) || ply->flagIsSet(P_LINKDEAD))
//		return;
//
//	{
//		Ply[i].ply->print("The watcher just arrived.\nThe watcher says, \"Don't double log or I'm going to jail you.\"\nThe watcher just wandered away.\n");
//		ply->print("The watcher just arrived.\nThe watcher says, \"Don't double log or I'm going to jail you.\"\nThe watcher just wandered away.\n");
//		logn("log.double", "%s and %s were doublelogging (%s).\n", ply->name, Ply[i].ply->name, Ply[i].sock->getHostname().c_str());
//		if(
//			ply->getClass() != CARETAKER &&
//			Ply[i].ply->getClass() != CARETAKER &&
//			ply->getClass() != BUILDER &&
//			Ply[i].ply->getClass() != BUILDER
//		) {
//			broadcast(isWatcher, "^C%s%s and %s%s were double logging (%s) - (%s/%s).\n", ply->name,
//				(ply->flagIsSet(P_ON_PROXY) ? "(Proxy)":""), Ply[i].ply->name,
//				(Ply[i].ply->flagIsSet(P_ON_PROXY) ? "(proxy)":""), Ply[i].sock->getHostname().c_str(),
//				ply->getRoom()->fullName().c_str(), Ply[i].ply->getRoom()->fullName().c_str());
//		} else {
//			broadcast(isCt, "^y%s%s and %s%s were double logging (%s) - (%s/%s).\n", ply->name,
//				(ply->flagIsSet(P_ON_PROXY) ? "(Proxy)":""), Ply[i].ply->name,
//				(Ply[i].ply->flagIsSet(P_ON_PROXY) ? "(proxy)":""), Ply[i].sock->getHostname().c_str(),
//				ply->getRoom()->fullName().c_str(), Ply[i].ply->getRoom()->fullName().c_str());
//		}
//
//		if(gConfig->checkDouble)
//			disconnect(i);
//
//	}
}

//*********************************************************************
//						pushObj
//*********************************************************************

int pushObj(Player* player, cmd* cmnd) {
	return(special_cmd(player, 2, cmnd));
}


//*********************************************************************
//						doFinger
//*********************************************************************
// sending 0 to cls means we're not a player and we want reduced padding

bstring doFinger(const Player* player, bstring name, unsigned short cls) {
	struct stat f_stat;
	char	tmp[80];
	Player*	target=0;
	std::ostringstream oStr;
	bool online=true;

	// set left aligned
	oStr.setf(std::ios::left, std::ios::adjustfield);
	oStr.imbue(std::locale(""));

	if(name == "")
		return("Finger who?\n");

	name = name.toLower();
	name.setAt(0, up(name.getAt(0)));
	target = gServer->findPlayer(name);

	if(!target) {
		if(!loadPlayer(name.c_str(), &target))
			return("Player does not exist.\n");

		online = false;
	}

	if(target->isStaff() && cls < target->getClass()) {
		if(!online)
			free_crt(target);
		return("You are currently unable to finger that player.\n");
	}

	// cls=0 means we don't want padding
	if(cls) {
		oStr << std::setw(25) << target->name << " "
			 << std::setw(15) << gConfig->getRace(target->getDisplayRace())->getName();
		// will they see through the illusion?
		if(player && player->willIgnoreIllusion() && target->getDisplayRace() != target->getRace())
			oStr << " (" << gConfig->getRace(target->getRace())->getName() << ")";
		oStr << " "
			 << target->getTitle() << "\n";
	} else {
		oStr << target->name << " the "
			 << gConfig->getRace(target->getDisplayRace())->getAdjective();
		// will they see through the illusion?
		if(player && player->willIgnoreIllusion() && target->getDisplayRace() != target->getRace())
			oStr << " (" << gConfig->getRace(target->getRace())->getAdjective() << ")";
		oStr << " "
			 << target->getTitle() << "\n";
	}

	sprintf(tmp, "%s/%s.txt", POSTPATH, name.c_str());
	if(stat(tmp, &f_stat))
		oStr << "No mail.\n";
	else if(f_stat.st_atime > f_stat.st_mtime)
		oStr << "No unread mail since: " << ctime(&f_stat.st_atime);
	else
		oStr << "New mail since: " << ctime(&f_stat.st_mtime);

	if(target->getForum() != "")
		oStr << "Forum account: " << target->getForum() << "\n";

	if(online) {
		oStr << "Currently logged on.\n";
	} else {
		long t = target->getLastLogin();
		free_crt(target);
		oStr << "Last login: " << ctime(&t);
	}

	return(oStr.str());
}

//*********************************************************************
//						cmdFinger
//*********************************************************************

int cmdFinger(Player* player, cmd* cmnd) {
	player->clearFlag(P_AFK);

	if(!player->ableToDoCommand())
		return(0);

	player->print("%s", doFinger(player, cmnd->str[1], player->getClass()).c_str());
	return(0);
}


//*********************************************************************
//						cmdPayToll
//*********************************************************************
// This function will allow players to pay to get through exits. Two
// flags are used for it: X_TOLL_TO_PASS, and X_LEVEL_BASED_TOLL. X_TOLL_TO_PASS sets the exit as
// a toll booth. A toll field will be required in the Exit structure
// defined as a long. X_LEVEL_BASED_TOLL will make the toll vary depending on the
// players' level, making the cost equal exit->toll*player->getLevel().

int cmdPayToll(Player* player, cmd* cmnd) {
	Monster* target=0;
	BaseRoom	*newRoom=0;
	Exit	*exit=0;
	unsigned long tc=0, amt=0;

	if(cmnd->num < 4) {
		player->print("Pay what to whom to get in where?\n");
		player->print("Syntax: pay $(amount) (target) (exit name)\n");
		return(0);
	}

	if(cmnd->num < 3) {
		player->print("Pay to get in where?\n");
		player->print("Syntax: pay $(amount) (target) (exit name)\n");
		return(0);
	}


	if(cmnd->str[1][0] != '$') {
		player->print("Syntax: pay $(amount) (target) (exit name)\n");
		return(0);
	}

	amt = atol(&cmnd->str[1][1]);
	if(!amt || amt < 1) {
		player->print("Please enter the amount to pay the tollkeeper.\n");
		return(0);
	}

	amt = MIN(amt, 30000);

	target = player->getRoom()->findMonster(player, cmnd, 2);
	if(!target) {
		player->print("That creature is not here.\n");
		return(0);
	}

	if(!Faction::willDoBusinessWith(player, target->getPrimeFaction())) {
		player->print("%M refuses to do business with you.\n", target);
		return(0);
	}

	if(!target->flagIsSet(M_TOLLKEEPER)) {
		player->print("%M doesn't take toll payments.\n", target);
		return(0);
	}

	exit = findExit(player, cmnd, 3);
	if(!exit) {
		player->print("That exit is not here.\n");
		return(0);
	}
	if(!exit->flagIsSet(X_TOLL_TO_PASS)) {
		player->print("That is not a tolled exit.\n");
		return(0);
	}


	tc = tollcost(player, exit, target);


	if(player->coins[GOLD] < amt) {
		player->print("You do not have that much gold on you.\n");
		return(0);
	}

	if(amt < tc) {
		player->print("You must pay at least %ld gold coins to pass through the %s.\n", tc, exit->name);
		return(0);
	}

	if(amt > tc) {
		player->print("That is too much. The cost to pass through %s is %ld gold coins.\n", exit->name, tc);
		return(0);
	}

	newRoom = exit->target.loadRoom(player);
	if(!newRoom) {
		player->print("The %s appears to be jammed shut.\nPlease try again later.\n", exit->name);
		return(0);
	}

	Room* uRoom = newRoom->getUniqueRoom();
	if(uRoom && !player->canEnter(uRoom, true))
		return(0);

	player->coins.sub(amt, GOLD);

	player->print("%M accepts your toll and ushers you through the %s.\n", target, exit->name);
	broadcast(player->getSock(), player->getRoom(), "%M pays %N some coins and goes through the %s.", player, target, exit->name);

	player->deleteFromRoom();
	player->addToRoom(newRoom);
	player->doPetFollow();
	return(0);
}

//*********************************************************************
//						tollcost
//*********************************************************************

unsigned long tollcost(const Player* player, const Exit* exit, Monster* keeper) {
	unsigned long cost = exit->getToll() ? exit->getToll() : DEFAULT_TOLL;
	if(!player)
		return(cost);
	if(exit->flagIsSet(X_LEVEL_BASED_TOLL))
		cost = cost * player->getLevel() * 2;

	if(!keeper)
		keeper = player->getRoom()->getTollkeeper();
	if(keeper) {
		Money money;
		money.set(cost, GOLD);
		money = Faction::adjustPrice(player, keeper->getPrimeFaction(), money, true);
		cost = money[GOLD];
	}
	return(cost);
}

//*********************************************************************
//						infoGamestat
//*********************************************************************

int infoGamestat(Player* player, cmd* cmnd) {
	int		players=0, immorts=0;
	int		daytime=0;
	long	t=0, days=0, hours=0, minutes=0;
	char	*str;

	std::pair<bstring, Player*> p;
	Player* target=0;
	foreach(p, gServer->players) {
		target = p.second;

		if(!target->isConnected())
			continue;

		if(target->isStaff())
			immorts++;
		if(!target->isStaff())
			players++;
	}

	player->print("\nCurrent Realms Gamestat Information\n\n");

	t = time(0);
	daytime = gConfig->currentHour();

	days = (t - StartTime) / (60*60*24);
	hours = (t - StartTime) / (60*60);
	hours %= 24;
	minutes = (t - StartTime) / 60L;
	minutes %= 60;

	player->printColor("^cGame-Time: %d:%02d %s.  %s.\n",
		gConfig->currentHour(true),
		gConfig->currentMinutes(),
		daytime > 11 ? "PM" : "AM",
		isDay() ? "It is day" : "It is night"
	);

	if(player->isCt())
		player->printColor("^gThe mud has been running for %d game days.\n", gConfig->calendar->getTotalDays());

	str = ctime(&t);
	str[strlen(str) - 1] = 0;

	player->printColor("^MReal-Time: %s (%s).\n", str, gServer->getTimeZone().c_str());

	if(!days)
		player->printColor("^RRealms Uptime: %02ld:%02ld:%02ld\n", hours, minutes, (t - StartTime) % 60L);
	else if(days == 1)
		player->printColor("^RRealms Uptime: %ld day %02ld:%02ld:%02ld\n", days, hours, minutes, (t - StartTime) % 60L);
	else
		player->printColor("^RRealms Uptime: %ld days %02ld:%02ld:%02ld\n", days, hours, minutes, (t - StartTime) % 60L);

	player->printColor("^yTotal players currently online: %d\n", players);
	if(player->isDm())
		player->printColor("^yTotal staffs online: %d\n", immorts);

	player->print("\n");

	return(0);
}

//*********************************************************************
//						cmdDescription
//*********************************************************************
// this allows a player to set his/her description that is seen when you
// look at them.

int cmdDescription(Player* player, cmd* cmnd) {
	player->clearFlag(P_AFK);

	if(!player->ableToDoCommand())
		return(0);

	if(cmnd->num < 2) {
		player->print("Syntax: description [text|-d]\n.");
		return(0);
	}
	if(!strcmp(cmnd->str[1], "-d")) {
		player->print("Description cleared.\n");
		player->setDescription("");
		return(0);
	}

	player->setDescription(getFullstrText(cmnd->fullstr, 1));
	player->escapeText();
	player->print("Description set.\n");
	return(0);
}