// Back and drink mods made 20/12/99. CRTH
#include <stdio.h>
#include	<stdlib.h>
#include	"config.h"
#include	"utils.h"
#include	"structs.h"
#include	"command.h"
#include "db.h"
#include "functions.h"
#include	"weather.h"
#include	"skills.h"

/* EXTERNAL VARIABLES */
extern long levels[];
extern struct descriptor_data *desc_list, *next_desc;
extern struct room_data *tmp_room;
extern char  buf[SMALL_BUFSIZE];
extern char  buf1[SMALL_BUFSIZE];
extern char  buf2[SMALL_BUFSIZE];
extern char  buf3[SMALL_BUFSIZE];

/* Pease put in ALPHABETICAL order */
struct _command_ {
	char	name[12];			/* Note: commands must be 12 characters or less */
	void	(*pointer)();
	char	arg1;					/* An arguement to pass to the function (flag a routine) */
	char	arg2;					/* An unused arguement flag */
	char	level;
	char	position;
} command[] = {
/***********************************************************************************/
/* COMMAND        ROUTINE        ARGUMENT      UNUSED    MIN LEVEL    MIN POSITION */
/***********************************************************************************/
	":",				do_emote,		0,            0,          0,	       POS_SITTING,
	"?",				do_commands,	0,				  0,          0,         POS_ASLEEP,
	"attack",		do_attack,		0,            0,          0,		    POS_STANDING,
	"autoloc",		do_autoloc,		0,				  0,			  0,		    POS_DEAD,
	"autoloot",		do_autoloot,	0,				  0,			  0,			 POS_DEAD,
	"brief",       do_no_msg,		0,			     0,          0,         POS_SITTING,
	"build",       do_build,      0,            0,          5,         POS_STANDING,
	"buy",         do_buy,        0,            0,          5,         POS_STANDING,
	"clone",       do_clone,      ALWAYS,       0,          WIZARD,    POS_DEAD,
	"close",   (void *) do_open,  CLOSED,       0,          0,         POS_STANDING,
	"commands",		do_commands,	0,			     0,          0,         POS_ASLEEP,
	"consider",		do_con,			0,				  0,			  0,			 POS_SITTING,
	"create",      do_create,     0,            0,          IMP,       POS_ASLEEP,
	"date",		   do_date,	      0,	           0,	        0,	       POS_DEAD,
	"detox",			do_detox,		0,				  0,          IMP,			 POS_DEAD,
	"drink",       do_drink,      0,            0,          0,         POS_SITTING,	
	"drop",			do_drop,			0,			     0,          0,         POS_SITTING,
	"eat",			do_eat,			0,				  0,          0,         POS_SITTING,
	"emote",			do_emote,		0,			     0,          0,         POS_SITTING,
	"equipment",	do_equipment,	0,			     0,          0,         POS_SITTING,
	"examine",		do_look,			0,			     0,          0,         POS_SITTING,
	"exits",			do_exit,			0,			     0,          0,         POS_STANDING,
	"flee",			do_flee,			0,			     0,          0,         POS_FIGHTING,
	"follow",		do_follow,		0,			     0,          0,         POS_STANDING,
   "get",      (void *) do_get,  0,            0,          0,         POS_SITTING,
	"give",        do_give,       0,            0,          0,         POS_STANDING,
	"gossip",		do_gossip,		0,			     0,          0,         POS_INCAP,
	"goto",			do_goto,			0,            0,          WIZARD,    POS_STANDING,
	"group",			do_group,		0,			     0,          0,         POS_ASLEEP,	
   "heal",        do_heal,       0,            0,          0,         POS_STANDING,
	"help",			do_commands,	0,			     0,          0,         POS_ASLEEP,
	"inventory",	do_inventory,	0,			     0,          0,         POS_SITTING,
	"invis",			do_invis,		0,            0,          WIZARD,    POS_SITTING,
	"invite",		do_invite,		0,				  0,		     0,         POS_ASLEEP,
	"join",			do_join,			0,				  0,          0,         POS_ASLEEP,
	"kill",			do_attack,		0,			     0,          0,         POS_STANDING,
	"list",			do_list,			0,            0,          WIZARD,    POS_DEAD,
	"lock",   (void *)do_unlock,  LOCKED,       0,          0,         POS_STANDING,
	"look",			do_look,			0,			     0,          0,         POS_SITTING,
	"lstskils",		do_lstskills,	0,				  0,			  0,		 	 POS_DEAD,
	"muffle",		do_no_msg,		0,			     0,          0,         POS_ASLEEP,
	"nogossip",		do_no_msg,		0,			     0,          0,         POS_SITTING,
	"notell",		do_no_msg,		0,			     0,          0,         POS_SITTING,
	"open",    (void *)do_open,   OPEN,         0,          0,         POS_STANDING,
	"pardon",		do_pardon,		0,            0,          GOD,       POS_DEAD,
	"private",		do_private,		0,				  0,	        5,		    POS_ASLEEP,
	"pset",			do_pset,			0,            0,          IMP,       POS_DEAD,
	"quit",			do_quit,			0,			     0,          0,         POS_STANDING,
	"remove",		do_remove,		0,			     0,          0,         POS_SITTING,
	"reroll",		do_reroll,		0,            0,          IMP,       POS_DEAD,
	"rest",			do_position,	0,			     0,          0,         POS_ASLEEP,
	"restrict",		do_restrict,	0,            0,          IMP,       POS_DEAD,
	"save",			do_save,			0,			     0,          0,         POS_ASLEEP,
	"say",			do_say,			0,			     0,          0,         POS_RESTING,
	"scan",			do_scan,			0,				  0,			  0,			 POS_DEAD,
	"score",			do_score,		0,			     0,          0,         POS_DEAD,
	"sdate",			do_savedate,	0,			     0,          IMP,       POS_ASLEEP,
	"sell",        do_sell,       0,            0,          5,         POS_STANDING,
	"send",			do_send,			0,				  0,		     GOD,		 POS_DEAD,
	"shutdown",		do_shutdown,	0,			     0,          0,         POS_DEAD,
	"sit",			do_position,	0,			     0,          0,         POS_ASLEEP,
	"skills",		do_skills,		0,				  0,			  0,			 POS_DEAD,
	"sleep",			do_position,	0,			     0,          0,         POS_ASLEEP,
	"stand",			do_position,	0,			     0,          0,         POS_ASLEEP,
	"stat",			do_stat,			0,            0,          IMP,       POS_DEAD,
	"take",     (void *) do_get,  0,            0,          0,         POS_SITTING,
	"teach",		do_giveSkill,	0,				  0,			  8,		 POS_SITTING,
	"tell",			do_tell,			0,			     0,          0,         POS_ASLEEP,
	"time",	      do_time,      	0,            0,          0,         POS_DEAD,
	"title",			do_title,		0,			     0,          0,         POS_ASLEEP,
	"tohand",      do_tohand,     0,            0,          WIZARD,    POS_DEAD,
	"ungroup",		do_ungroup,		0,		    	  0,          0,         POS_ASLEEP,
	"unlock", (void *)do_unlock,  CLOSED,       0,          0,         POS_STANDING,
	"value",       do_value,      0,            0,          0,         POS_STANDING,
	"wake",			do_position,	0,			     0,          0,         POS_ASLEEP,
	"wear",			do_wear,			0,			     0,          0,         POS_SITTING,
	"weather",     do_WeatherRep, 0,            0,          0,         POS_DEAD,
	"who",			do_who,			0,			     0,          0,         POS_DEAD,
	"wield",			do_wield,		0,			     0,          0,         POS_SITTING,
	"Xskills",	   do_Xskills,		0,				  0,			  0,		 	 POS_DEAD,
};
#define BCTOP ((sizeof(command) / sizeof(struct _command_)) -1)

void command_parser(struct char_data *ch, char *arg)
{
	int	c,i;

	/* check if we have a command */
	if(!*arg) {
		ch->desc->prompt=1;
		return;
	}

	/* First (for the benefit of idle people) check if it is a direction */
	for(i=0;i<10;i++) {
		if(!shrt_cmp(arg,exit_list[i].name) || !shrt_cmp(arg,exit_list[i].brief)) {
			if(ch->POSITION > POS_SITTING && ch->STATE > STAT_DRUNK)
         {
			   do_direction(ch,i);
			   return;
         }
			else
			{
				if(ch->POSITION <= POS_SITTING && ch->STATE <= STAT_DRUNK)
				{
					sprintf(buf1,"%sand %s",pos_allowed[ch->POSITION],
						stat_allowed[ch->STATE]);
					send_2_output(buf1,ch->desc);
				
				}
				else
				{
					if(ch->POSITION <= POS_SITTING)
						send_2_output(pos_allowed[ch->POSITION],ch->desc);
					if(ch->STATE <= STAT_DRUNK)
						send_2_output(stat_allowed[ch->STATE],ch->desc);
				}
				
				return;
			}
		}
	}

	/* Need to check for aliases */

	/*******************************************************
		Search our list of commands for the instruction that
		our most prized and intelligent user has entered.
	*******************************************************/
	if((i=get_command(arg)) < 0) {
	/*******************************************************
		Search our carried and wielded objects to see if we
		are carrying an object that has specific commands 
		associated with it...
	*******************************************************/
		for(c=0;c<=MAX_WEAR;c++) {
			if(ch->wearing[c] != 0) {
 				if(ch->wearing[c]->OBJ_SPECIAL) {
					if(((*obj_spec[ch->wearing[c]->OBJ_SPECIAL])(ch,ch->wearing[c],arg)) != 0)
						return;
				}
			}
		}
		// The command could be a skill !!! CRTH...
		for(c=0;show_skill[c].useby != LAST_SKL;c++)
		{
			if(!shrt_cmp(show_skill[c].name,arg))
			{
				do_use_skill(ch,arg);
				return;
			}
		}
		send_2_output("Not understood...\n\r",ch->desc);
		return;
	} else if(ch->LEVEL < command[i].level) {
		send_2_output("Not understood...\n\r",ch->desc);
		return;
	} else if(ch->POSITION < command[i].position) {
		/* check we are in a position to do this */
		send_2_output(pos_allowed[ch->POSITION],ch->desc);
		return;
	} else {
		/* Execute the command! */
		((*command[i].pointer)(ch,arg,command[i].arg1,command[i].arg2));
		return;	
	}
	
}

void	do_score(struct char_data *ch)
{
	sprintf(buf,"\033[36m=========================\033[0m[ \033[1m\033[33mSTATISTICS \033[0m]\033[36m====="
		"===================\033[0m\n");
	send_2_output(buf,ch->desc);
	
	sprintf(buf," You are \033[1m\033[33m%s \033[36m%-20s \033[0m(\033[36mlevel: \033[34m%3d\033[0m)\n\r",
		ch->name,ch->title,ch->LEVEL);
	send_2_output(buf,ch->desc);
	sprintf(buf," Class: %s\n\r",class[ch->CLASS].full);
	send_2_output(buf,ch->desc);
	sprintf(buf," Age: \033[32m%02d\033[0m         Height: \033[32m%02d\033[0m cm     Weight: \033[32m%02d"
		"\033[0m lbs\n\r",ch->AGE,ch->HEIGHT,ch->WEIGHT);
	send_2_output(buf,ch->desc);	

	sprintf(buf," STR: \033[36m%d\033[0m/\033[36m%d\033[0m \t INT: \033[36m%d\033[0m"
		" \n\r WIS: \033[36m%d\033[0m \t DEX: \033[36m%d\033[0m \n\r CON: \033[36m%d\033[0m \t AC : \033[1m\033[34m%d\033[0m/\033[1m\033[34m10\033[0m\n\r",
		ch->STR,ch->STR_ADD,ch->INT,ch->WIS,ch->DEX,ch->CON,ch->ARMOR);
	send_2_output(buf,ch->desc);

	sprintf(buf," EXP: \033[1m\033[37m%ld\033[0m \t Next Lvl : \033[1m\033[37m%ld\033[0m\n\r",ch->EXP,levels[ch->LEVEL]);
	send_2_output(buf,ch->desc);

	sprintf(buf," TOHIT: \033[36m%d\033[0m \t TODAM: \033[31m%d"
		"\033[0m\n\r",ch->TOHIT,ch->TODAM);
	send_2_output(buf,ch->desc);
   	sprintf(buf," You have \033[31m%d\033[0m(\033[1m\033[31m%d\033[0m) hits, \033[35m%d\033[0m("
		"\033[1m\033[35m%d\033[0m) mana and \033[32m%d\033[0m(\033[1m\033[32m%d\033[0m) "
		"movement points.\n\r",ch->HIT,ch->MAX_HIT,ch->MANA,ch->MAX_MANA,ch->MOVE,ch->MAX_MOVE);
   	send_2_output(buf,ch->desc);	
	

	sprintf(buf," You are carrying \033[33m%d\033[0m(\033[33m%d\033[0m) lbs , and your alignment is "
		"\033[36m%s\033[0m.\n\r",ch->CUR_WGHT,ch->MAX_WGHT,align[ch->ALIGN/660]);
	send_2_output(buf,ch->desc);

	sprintf(buf," You are \033[35m%s\033[0m.\n\r",show_pos[ch->POSITION].shrt);
	send_2_output(buf,ch->desc);

	if(BTST(ch->PREFS,NO_GOSS))
		send_2_output("\033[35mYou have nogossip on.\033[0m\n\r",ch->desc);
	if(BTST(ch->PREFS,NO_TELL))
		send_2_output("\033[1mYou have notell on.\033[0m\n\r",ch->desc);
	sprintf(buf," You feel %s, %s, %s\n\r",show_stat[ch->STATE].shrt,
		drink[ch->THIRST/20].shrt,food[ch->HUNGER/20].shrt);
	send_2_output(buf,ch->desc);
	sprintf(buf," You have \033[32m%d\033[0m General Skill points.\n\r",ch->GEN_SKILL);
	send_2_output(buf,ch->desc);
	sprintf(buf," You have \033[31m%d\033[0m %s skill points.\n\r",ch->SP_SKILL,class[ch->CLASS].full);
	send_2_output(buf,ch->desc);
	sprintf(buf,"\033[36m===============================================================\033[0m\n");
	send_2_output(buf,ch->desc);	

	return;
}

void	do_commands(struct char_data *ch)
{
	int	i,c;

	send_2_output("A raw list of commands available to you:\n",ch->desc);
	for(i=c=0;i<=BCTOP;i++) {
		if(ch->LEVEL >= command[i].level) {
			if(c<4) {
				sprintf(buf,"%12s",command[i].name);
				c++;
			} else {
				sprintf(buf,"%12s\n",command[i].name);
				c=0;
			}
			send_2_output(buf,ch->desc);
		}
	}
	if(c != 0)
		send_2_output("\n",ch->desc);
	return;
}

void	do_quit(struct char_data *ch, char *arg)
{
	get_arg(buf,arg,0);			/* Need a '\0' terminated string */
	if(ch->POSITION == POS_FIGHTING) {
		send_2_output("You can't quit in the middle of a fight!\n\r",ch->desc);
		return;
	} else if(str_cmp(buf,"quit")) {
		send_2_output("You must type 'quit' in full!\n\r",ch->desc);
		return;
	}
	send_2_output("Saving character...\n\rBye!\n\r",ch->desc);
	save_char(ch);

	change_status(ch, CON_CLOSE);
}

void  do_invis(struct char_data *ch, char *arg)
{
   int   invis=0;

	if((get_arg(buf,arg,1)) && !_numeric(&invis,buf)) {
		send_2_output("The arguement must be numeric.\n\r",ch->desc);
   } else if(invis > ch->LEVEL) {
      send_2_output("You can't do that.\n\r",ch->desc);
   } else if(invis > 1) {
      sprintf(buf,"\033[1m\033[34mYou are now invisible to everyone below level \033[36m%d\033[0m.\n\r",invis);
   	send_2_output(buf,ch->desc);
   } else if(invis) {
      send_2_output("\033[1m\033[34mYou are now invisible.\033[0m\n\r",ch->desc);
   } else if(ch->INVIS) {
      send_2_output("\033[1m\033[34mYou are now completely visible.\033[0m\n\r",ch->desc);
   } else {
      send_2_output("\033[1m\033[34mYou are now invisible.\033[0m\n\r",ch->desc);
      invis=ch->LEVEL;
   }
   ch->INVIS=invis;
   return;
}

/****************************************************
      Save the player characters
****************************************************/
void  save_all(void)
{
	extern struct descriptor_data *desc_list;
	struct descriptor_data *desc, *desc_next;

	for(desc=desc_list;desc;desc=desc_next) {
		desc_next=desc->next_in_list;
		do_save(desc->character);
	}
}

void	do_save(struct char_data *ch)
{
	save_char(ch);
	send_2_output("Character saved.\n\r",ch->desc);
}
/***************************************************/

void	do_shutdown(struct char_data *ch, char *arg)
{
	extern long countdown;
	extern char _shutdown;
	struct descriptor_data *point, *next_point;
	int    size;

	get_arg(buf,arg,0);  /* We need a null terminated string */
	if(!get_arg(buf1,arg,1)) {
		if(_shutdown == SHUTDOWN_COUNTING) {
			sprintf(buf1,"Shutdown active: %d minute(s) %d second(s) left\n\r",(countdown/60),(countdown % 60));
			send_2_output(buf1,ch->desc);
		} else if(_shutdown == SHUTDOWN_HALTED) {
			sprintf(buf1,"Shutdown halted: %d minute(s) %d second(s) left\n\r",(countdown/60),(countdown % 60));
			send_2_output(buf1,ch->desc);
		} else {
			send_2_output("No shutdown in operation\n\r",ch->desc);
		}
	} else if(ch->LEVEL < IMP) {
		send_2_output("Sorry, but you can't do that!\n\r",ch->desc);
	} else if(str_cmp(buf,"shutdown")) {
		send_2_output("You must type 'shutdown' in full!\n\r",ch->desc);
	} else if(!_numeric(&size,buf1)) {
		if(!str_cmp(buf1,"clear")) {
			if(countdown) {
				countdown = 0;
				_shutdown  = SHUTDOWN_RUNNING;		/* no shutdown */
				send_2_output("Shutdown stopped\n\r",ch->desc);
				send_2_all(ch,"\n\rSYSTEM: Shutdown stopped\n\r");
			} else {
				send_2_output("No shutdown in operation\n\r",ch->desc);
			}
		} else if(!str_cmp(buf1,"halt")) {
			if(_shutdown == SHUTDOWN_COUNTING) {
				_shutdown = SHUTDOWN_HALTED;
				sprintf(buf,"\n\rSYSTEM: shutdown halted at %d minute(s) %d second(s)\n\r",(countdown/60),(countdown % 60));
				send_2_all(0,buf);
			} else if(_shutdown == SHUTDOWN_HALTED) {
				send_2_output("Shutdown is already halted\n\r",ch->desc);
			} else {
				send_2_output("Shutdown was not running.\n\r",ch->desc);
			}
		} else if(!str_cmp(buf1,"resume")) {
			if(_shutdown == SHUTDOWN_HALTED) {
				_shutdown = SHUTDOWN_COUNTING;
				sprintf(buf,"\n\rSYSTEM: Shutdown resumed at %d minute(s) %d second(s)\n\r",(countdown/60),(countdown % 60));
				send_2_all(0,buf);
			} else {
				send_2_output("Shutdown was not paused!\n\r",ch->desc);
			}
		} else {
			send_2_output("Usage: shutdown <time in minutes> | 'clear' | 'halt' | 'resume'\n\r",ch->desc);
		}
	} else {
		_shutdown = SHUTDOWN_COUNTING;				/* Set shutdown as counting */
		countdown = (size * 60);					/* Convert it to seconds */
		if(countdown < 60) {
			send_2_all(ch, "\n\rSYSTEM: Shutdown now!\n\r");
			countdown = 1;		/* Need to set it to 1 so that characters get saved! */
		} else {
			sprintf(buf,"\n\rSYSTEM: Shutdown in %d minute(s)\n\r",(countdown/60));
			send_2_all(ch, buf);
		}
		sprintf(buf,"Game will shutdown in %d minute(s)\n\r",(countdown/60));
		send_2_output(buf,ch->desc);
	}
}

int	get_command(char *arg)
{
	int	top=BCTOP;
	int	mid,found,low=0;

	while(low <= top) {
		mid = (low+top)/2;
		if((found = shrt_cmp(arg,command[mid].name)) > 0)
			low = mid +1 ;
		else if(found < 0)
			top = mid -1;
		else
			return(mid);
	}
	return(-1);
}

void	do_title(struct char_data *ch, char *arg)
{
	if(!get_arg(buf,arg,-1)) {
		send_2_output("Your title remains unchanged\n\r",ch->desc);
	} else if(strlen(buf)>40) {
		send_2_output("Title is too long (not changed)\n\r",ch->desc);
	} else {
		sprintf(buf1,"You are now %s %s\n\r",ch->name,buf);
		send_2_output(buf1,ch->desc);
		strcpy(ch->title,buf);
	}
	return;
}
///////////////////CRTH
void	do_WeatherRep(struct char_data *ch)
{
   if(BTST(ch->in_room->flags,OUTSIDE))
   {
      send_2_output(WeatherRep,ch->desc);
      SetWeather();
      send_2_output(Weather,ch->desc);
   }
   else
      send_2_output(WeatherRep,ch->desc);  
}

void	do_date(struct char_data *ch)
{	
   char   tmp[200+1];
	
   sprintf(tmp,"\033[36mIt's the \033[0m%s \033[36mday of \033[37m%s \033[36min the \033[0m%s "
      "\033[36myear of AXIA.\033[0m\n\r",DY[DAYS-1].desc,MON[MONTHS].desc,DY[YEARS-1].desc);

   send_2_output(tmp,ch->desc);

}
void	do_time(struct char_data *ch)
{
   char   tmp[200+1];

   sprintf(tmp,"\033[36mIt is %s%s\033[0m\n\r",TODAY[TICKS].time,TODAY[TICKS].desc);
	
   send_2_output(tmp,ch->desc);

}
void	do_savedate(struct char_data *ch)
{
   if(SaveSeasonDate())
      send_2_output("Date Saved.\n\r",ch->desc);
   else
      send_2_output("Date Save Failed.\n\r",ch->desc);
}
void do_detox(struct char_data *ch, char *arg)
{
	extern struct descriptor_data *desc_list;
	struct descriptor_data *desc, *desc_next;

	if(!get_arg(buf,arg,-1))
		send_2_output("Detox who???\n\r",ch->desc);
	else
	{	
		if(!shrt_cmp(buf,ch->name))
		{
			ch->DRUNK = 0;
			ch->POISEN = 0;
			ch->DISEASE = 0;
			ch->HIT = ch->MAX_HIT;
			ch->STATE = STAT_OK;
		   ch->POSITION = POS_STANDING;
			ch->POISENSTR = 0;
			ch->MOVE = ch->MAX_MOVE;
			ch->MANA = ch->MAX_MANA;
			send_2_output("You are cleand of all ill's...\n\r",ch->desc);
		}
		else
		{
			char ok = 0;

			for(desc=desc_list;desc;desc=desc_next) 
			{
				desc_next=desc->next_in_list;
				if(!shrt_cmp(buf,desc->character->name))
				{
					ok = 1;
					desc->character->DRUNK = 0;
					desc->character->POISEN = 0;
					desc->character->DISEASE = 0;
					desc->character->HIT = desc->character->MAX_HIT;
					desc->character->STATE = STAT_OK;
				   desc->character->POSITION = POS_STANDING;
					desc->character->POISENSTR = 0;
					desc->character->MOVE = desc->character->MAX_MOVE;
					desc->character->MANA = desc->character->MAX_MANA;
					sprintf(buf,"You have cleaned \033[1m\033[33m%s\033[0m of all %s ill's.\n\r",desc->character->name,sex[desc->character->SEX].b);
					send_2_output(buf,ch->desc);
					sprintf(buf,"\033[1m\033[33m%s\033[0m has cleand you of all your ill's.\n\r",ch->name);
					send_2_output(buf,desc->character->desc);
					break;
				}
			}
			if(!ok)
				send_2_output("They don't seem to be here to detox...\n\r",ch->desc);

		}
	}
}
///////////////////CRTH

