smaug1.8/area/imc/
smaug1.8/boards/
smaug1.8/councils/
smaug1.8/deity/
smaug1.8/doc/mudprogs/
smaug1.8/gods/
smaug1.8/houses/
smaug1.8/log/
smaug1.8/vault/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops, Fireblade, Edmond, Conran                         |             *
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 * 			Variable Handling Module (Thoric)		    *
 ****************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"
#ifdef USE_IMC
#include "imc-mercbase.h"
#include "icec-mercbase.h"
#endif


#if defined(KEY)
#undef KEY
#endif

#define KEY( literal, field, value )					\
				if ( !str_cmp( word, literal ) )	\
				{					\
				    field  = value;			\
				    fMatch = TRUE;			\
				    break;				\
				}


VARIABLE_DATA *make_variable(char type, int vnum, char *tag)
{
    VARIABLE_DATA *var;

    CREATE(var, VARIABLE_DATA, 1);
    var->next = NULL;
    var->type = type;
    var->flags = 0;
    var->vnum = vnum;
    var->tag = str_dup(tag);
    var->c_time = current_time;
    var->m_time = current_time;
    var->r_time = 0;
    var->timer = 0;
    switch(type)
    {
	case vtINT:
	    var->data = NULL;
	    break;
	case vtXBIT:
	    CREATE(var->data, EXT_BV, 1);
	    break;
	case vtSTR:
	    var->data = NULL;
    }
    return var;
}

void delete_vdata(VARIABLE_DATA *var)
{
    switch(var->type)
    {
	case vtXBIT:
	case vtSTR:
	    if ( var->data )
		DISPOSE(var->data);
	    break;
    }
}

void delete_variable(VARIABLE_DATA *var)
{
    delete_vdata(var);
    DISPOSE(var->tag);
    DISPOSE(var);
}

/*
 * Return the specified tag from a character
 */
VARIABLE_DATA *get_tag(CHAR_DATA *ch, char *tag, int vnum)
{
    VARIABLE_DATA *vd;

    for ( vd = ch->variables; vd; vd = vd->next )
	if ( (!vnum || vnum == vd->vnum) && !str_cmp(tag, vd->tag) )
	    return vd;
    return NULL;
}

/*
 * Remove the specified tag from a character
 */
bool remove_tag(CHAR_DATA *ch, char *tag, int vnum)
{
    VARIABLE_DATA *vd_next, *vd = ch->variables;

    if ( !vd )
	return FALSE;

    if ( (!vnum || vnum == vd->vnum) && !str_cmp(tag, vd->tag) )
    {
	ch->variables = vd->next;
	delete_variable(vd);
	return TRUE;
    }

    for ( ; vd && vd->next; vd = vd_next )
    {
	vd_next = vd->next;
	if ( (!vnum || vnum == vd_next->vnum) && !str_cmp(tag, vd_next->tag) )
	{
	    vd->next = vd_next->next;
	    delete_variable(vd_next);
	    return TRUE;
	}
    }
    return FALSE;
}

/*
 * Tag a variable onto a character  Will replace if specified to do so,
 * otherwise if already exists, fail
 */
int tag_char(CHAR_DATA *ch, VARIABLE_DATA *var, int replace)
{
    VARIABLE_DATA *vd, *pvd;
    bool found = FALSE;

    pvd = vd = ch->variables;
    for ( ; vd; vd = vd->next )
    {
	if ( vd == var )	/* same variable -- leave it be */
	{
	    var->m_time = current_time;
	    return 0;
	}
	if ( vd->vnum == var->vnum && !str_cmp(vd->tag, var->tag) )
	{
	    if ( !replace )
		return -1;
	    found = TRUE;
	    break;
	}
	pvd = vd;
    }

    if ( found )
    {
	var->m_time = current_time;
	var->c_time = vd->c_time;
	var->r_time = vd->r_time;
	var->next = vd->next;
	if ( vd == ch->variables )
	    ch->variables = var;
	else
	    pvd->next = var;
	delete_variable(vd);
	return 0;
    }
    var->next = ch->variables;
    ch->variables = var;

    return 0;
}

bool is_valid_tag(const char *tagname)
{
  if (!isalpha(*tagname))
    return FALSE;
  for (++tagname; *tagname; ++tagname)
     if (!isalnum(*tagname) && *tagname != '_')
       return FALSE;
   return TRUE;
}


/*
 *  "tag" is a text identifier to refer to the variable and can
 *  be suffixed with a colon and a mob vnum  ie:  questobj:1101
 *  vnum 0 is used to denote a global tag (local to the victim)
 *  otherwise tags are separated by vnum
 *
 *  mptag	<victim> <tag> [value]
 *  mprmtag	<victim> <tag>
 *  mpflag	<victim> <tag> <flag>
 *  mprmflag    <victim> <tag> <flag>
 *
 *  if istagged($n,tag) [== value]
 *  if isflagged($n,tag[,bit])
 */


/*
 * mptag <victim> <tag> [value]
 */
void do_mptag( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA	  *victim;
    VARIABLE_DATA *vd;
    char	  *p;
    char	   arg1[MAX_INPUT_LENGTH];
    char	   arg2[MAX_INPUT_LENGTH];
    int		   vnum = 0, exp = 0;
    bool	   error = FALSE;

    if ( (!IS_NPC(ch) && get_trust(ch) < LEVEL_GREATER)
    ||     IS_CHARMED(ch) )
    {
          send_to_char( "Huh?\n\r", ch );
          return;
    }

    argument = one_argument( argument, arg1 );
    if ( !str_cmp(arg1, "noexpire") )
    {
	exp = 0;
	argument = one_argument( argument, arg1 );
    }
    else if ( !str_cmp(arg1, "timer") )
    {
	argument = one_argument( argument, arg1 );
	exp = atoi(arg1);
	argument = one_argument( argument, arg1 );
    }
    else
	exp = ch->level * get_curr_int(ch);
    argument = one_argument( argument, arg2 );

    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "MPtag whom with what?\n\r", ch );
	return;
    }

    if ( (victim=get_char_room(ch, arg1)) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

    if ( (p=strchr(arg2, ':')) != NULL )
    {
	*p++ = '\0';
	vnum = atoi(p);
    }
    else
    {
	vnum = ch->pIndexData ? ch->pIndexData->vnum : 0;
    }

    if ( !is_valid_tag(arg2) )
    {
	progbug( "Mptag:  invalid characters in tag", ch );
	return;
    }
    error = FALSE;
    for ( p = argument; *p; p++ )
    {
	if ( !isdigit(*p) && !isspace(*p) )
	{
	    error = TRUE;
	    break;
	}
    }
    if ( error )
    {
	vd = make_variable(vtSTR, vnum, arg2);
	vd->data = str_dup(argument);
    }
    else
    {
	vd = make_variable(vtINT, vnum, arg2);
	(int)vd->data = atoi(argument);
    }
    vd->timer = exp;
    tag_char(victim, vd, 1);
}

/*
 * mprmtag <victim> <tag>
 */
void do_mprmtag( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA	  *victim;
    char	  *p;
    char	   arg1[MAX_INPUT_LENGTH];
    char	   arg2[MAX_INPUT_LENGTH];
    int		   vnum = 0;

    if ( (!IS_NPC(ch) && get_trust(ch) < LEVEL_GREATER)
    ||     IS_CHARMED(ch) )
    {
          send_to_char( "Huh?\n\r", ch );
          return;
    }

    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );

    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "MPtag whom with what?\n\r", ch );
	return;
    }

    if ( (victim=get_char_room(ch, arg1)) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

    if ( (p=strchr(arg2, ':')) != NULL )
    {
	*p++ = '\0';
	vnum = atoi(p);
    }
    else
    {
	vnum = ch->pIndexData ? ch->pIndexData->vnum : 0;
    }

	if ( !is_valid_tag( arg2 ) )
    {
	progbug( "Mptag:  invalid characters in tag", ch );
	return;
    }

    if ( !remove_tag(victim, arg2, vnum) )
    {
	progbug( "Mptag:  could not find tag", ch );
    }
}

/*
 * mpflag <victim> <tag> <flag>
 */
void do_mpflag( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA	  *victim;
    VARIABLE_DATA *vd;
    char	  *p;
    char	   arg1[MAX_INPUT_LENGTH];
    char	   arg2[MAX_INPUT_LENGTH];
    char	   arg3[MAX_INPUT_LENGTH];
    int		   vnum = 0, exp = 0, def = 0, flag = 0;
    bool	   error = FALSE;

    if ( (!IS_NPC(ch) && get_trust(ch) < LEVEL_GREATER)
    ||     IS_CHARMED(ch) )
    {
          send_to_char( "Huh?\n\r", ch );
          return;
    }

    argument = one_argument( argument, arg1 );
    if ( !str_cmp(arg1, "noexpire") )
    {
	exp = 0;
	argument = one_argument( argument, arg1 );
    }
    else if ( !str_cmp(arg1, "timer") )
    {
	argument = one_argument( argument, arg1 );
	exp = atoi(arg1);
	argument = one_argument( argument, arg1 );
    }
    else
    {
	exp = ch->level * get_curr_int(ch);
	def = 1;
    }
    argument = one_argument( argument, arg2 );
    argument = one_argument( argument, arg3 );

    if ( arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0' )
    {
	send_to_char( "MPflag whom with what?\n\r", ch );
	return;
    }

    if ( (victim=get_char_room(ch, arg1)) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

    if ( (p=strchr(arg2, ':')) != NULL )
    {
	*p++ = '\0';
	vnum = atoi(p);
    }
    else
    {
	vnum = ch->pIndexData ? ch->pIndexData->vnum : 0;
    }

    if ( !is_valid_tag(arg2) )
    {
	progbug( "Mpflag:  invalid characters in tag", ch );
	return;
    }
    error = FALSE;
    for ( p = arg3; *p; p++ )
    {
	if ( !isdigit(*p) && !isspace(*p) )
	{
	    error = TRUE;
	    break;
	}
    }
    flag = atoi(arg3);
    if ( error || flag < 0 || flag >= MAX_BITS )
    {
	progbug( "Mpflag:  invalid flag value", ch );
	return;
    }
    if ( (vd=get_tag(victim, arg2, vnum)) != NULL )
    {
	if ( vd->type != vtXBIT )
	{
	    progbug( "Mpflag:  type mismatch", ch );
	    return;
	}
	if ( !def )
	    vd->timer = exp;
    }
    else
    {
	vd = make_variable(vtXBIT, vnum, arg2);
	vd->timer = exp;
    }
    xSET_BIT(*(EXT_BV*)vd->data, flag);
    tag_char(victim, vd, 1);
}


/*
 * mprmflag <victim> <tag> <flag>
 */
void do_mprmflag( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA	  *victim;
    VARIABLE_DATA *vd;
    char	  *p;
    char	   arg1[MAX_INPUT_LENGTH];
    char	   arg2[MAX_INPUT_LENGTH];
    char	   arg3[MAX_INPUT_LENGTH];
    int		   vnum = 0;
    bool	   error = FALSE;

    if ( (!IS_NPC(ch) && get_trust(ch) < LEVEL_GREATER)
    ||     IS_CHARMED(ch) )
    {
          send_to_char( "Huh?\n\r", ch );
          return;
    }

    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    argument = one_argument( argument, arg3 );

    if ( arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0' )
    {
	send_to_char( "MPrmflag whom with what?\n\r", ch );
	return;
    }

    if ( (victim=get_char_room(ch, arg1)) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

    if ( (p=strchr(arg2, ':')) != NULL )
    {
	*p++ = '\0';
	vnum = atoi(p);
    }
    else
    {
	vnum = ch->pIndexData ? ch->pIndexData->vnum : 0;
    }

    if ( !is_valid_tag( arg2 ) )
    {
	progbug( "Mprmflag:  invalid characters in tag", ch );
	return;
    }
    error = FALSE;
    for ( p = arg3; *p; p++ )
    {
	if ( !isdigit(*p) && !isspace(*p) )
	{
	    error = TRUE;
	    break;
	}
    }
    if ( error )
    {
	progbug( "Mprmflag:  invalid flag value", ch );
	return;
    }
    /*
     * Only bother doing anything if the tag exists
     */
    if ( (vd=get_tag(victim, arg2, vnum)) != NULL )
    {
	if ( vd->type != vtXBIT )
	{
	    progbug( "Mprmflag:  type mismatch", ch );
	    return;
	}
	if ( !vd->data )
	{
	    progbug( "Mprmflag:  missing data???", ch );
	    return;
	}
	xREMOVE_BIT(*(EXT_BV*)vd->data, atoi(arg3));
	tag_char(victim, vd, 1);
    }
}

void fwrite_variables(CHAR_DATA *ch, FILE *fp)
{
    VARIABLE_DATA *vd;

    for ( vd = ch->variables; vd; vd = vd->next )
    {
	fprintf(fp, "#VARIABLE\n");
	fprintf(fp, "Type    %d\n",	vd->type);
	fprintf(fp, "Flags   %d\n", vd->flags);
	fprintf(fp, "Vnum    %d\n", vd->vnum);
	fprintf(fp, "Ctime   %ld\n", vd->c_time);
	fprintf(fp, "Mtime   %ld\n", vd->m_time);
	fprintf(fp, "Rtime   %ld\n", vd->r_time);
	fprintf(fp, "Timer   %d\n", vd->timer);
	fprintf(fp, "Tag     %s~\n", vd->tag);
	switch(vd->type)
	{
	    case vtSTR:
		fprintf(fp, "Str     %s~\n", (char *)vd->data);
		break;
	    case vtXBIT:
		fprintf(fp, "Xbit    %s\n", print_bitvector((EXT_BV*)vd->data));
		break;
	    case vtINT:
		fprintf(fp, "Int     %d\n", (int)vd->data);
		break;
	}
	fprintf(fp, "End\n\n");
    }
}

void fread_variable(CHAR_DATA *ch, FILE *fp)
{
    VARIABLE_DATA *pvd;
    char *word;
    bool fMatch;

    CREATE(pvd, VARIABLE_DATA, 1);
    for ( ; ; )
    {
	word   = feof( fp ) ? "End" : fread_word( fp );
	fMatch = FALSE;

	switch ( UPPER(word[0]) )
	{
	    case '*':
		fMatch = TRUE;
		fread_to_eol( fp );
		break;

	    case 'C':
		KEY( "Ctime",	pvd->c_time,		fread_number( fp ) );
		break;

	    case 'E':
		if ( !str_cmp( word, "End" ) )
		{
			switch(pvd->type)
			{
		    default:
		    {
			bug("Fread_variable: invalid/incomplete variable %s", pvd->tag);
			if ( pvd->tag )
			    DISPOSE(pvd->tag);
				DISPOSE(pvd);
		    break;
			}
			case vtSTR:
		    case vtXBIT:
			if ( !pvd->data )
			{
				bug("Fread_variable: invalid/incomplete variable %s", pvd->tag);
				if ( pvd->tag )
			   	 DISPOSE(pvd->tag);
				 DISPOSE(pvd);
				break;
			}
		    case vtINT:
				tag_char(ch, pvd, 1);
				break;
		    }
		    return;
		}
		break;

	    case 'F':
		KEY( "Flags",	pvd->flags,		fread_number( fp ) );
		break;

	    case 'I':
		if ( !str_cmp(word, "Int") )
		{
		    if ( pvd->type != vtINT )
			bug("Fread_variable: Type mismatch -- type(%d) != vtInt", pvd->type);
		    else
		    {
			(int)pvd->data = fread_number(fp);
			fMatch = TRUE;
		    }
		    break;
		}
		break;

	    case 'M':
		KEY( "Mtime",	pvd->m_time,		fread_number( fp ) );
		break;

	    case 'R':
		KEY( "Rtime",	pvd->r_time,		fread_number( fp ) );
		break;

	    case 'S':
		if ( !str_cmp(word, "Str") )
		{
		    if ( pvd->type != vtSTR )
			bug("Fread_variable: Type mismatch -- type(%d) != vtSTR", pvd->type);
		    else
		    {
			(char *)pvd->data = fread_string_nohash(fp);
			fMatch = TRUE;
		    }
		    break;
		}
		break;
	
	    case 'T':
		KEY( "Tag",	pvd->tag,		fread_string_nohash( fp ) );
		KEY( "Timer",	pvd->timer,		fread_number( fp ) );
		KEY( "Type",	pvd->type,		fread_number( fp ) );
		break;

	    case 'V':
		KEY( "Vnum",	pvd->vnum,		fread_number( fp ) );
		break;

	    case 'X':
		if ( !str_cmp(word, "Xbit") )
		{
		    if ( pvd->type != vtXBIT )
			bug("Fread_variable: Type mismatch -- type(%d) != vtXBIT", pvd->type);
		    else
		    {
			CREATE(pvd->data, EXT_BV, 1);
			*(EXT_BV *)pvd->data = fread_bitvector(fp);
			fMatch = TRUE;
		    }
		    break;
		}
		break;
	}
	
	if ( !fMatch )
	{
	    bug( "Fread_variable: no match: %s", word );
	}
    }
}