EmberMUD-0.9.43/
EmberMUD-0.9.43/clan/
EmberMUD-0.9.43/classes/
EmberMUD-0.9.43/gods/
EmberMUD-0.9.43/log/
EmberMUD-0.9.43/player/
EmberMUD-0.9.43/player/temp/
EmberMUD-0.9.43/src/MSVC/
EmberMUD-0.9.43/src/Sleep/
EmberMUD-0.9.43/src/StartMUD/
EmberMUD-0.9.43/src/Win32Common/
/***************************************************************************
 *  File: olc_act.c                                                        *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 *                                                                         *
 *  This code was freely distributed with the The Isles 1.1 source code,   *
 *  and has been used here for OLC - OLC would not be what it is without   *
 *  all the previous coders who released their source code.                *
 *                                                                         *
 ***************************************************************************/
 
/**************************************************************************
 * Mudprogram's (Mobprogram, Objprogram and Roomprogram) originaly 	      *
 * by the SMAUG development team             				              *
 * Ported to EmberMUD by Thanatos and Tyrluk of ToED      		          *
 * (Temple of Eternal Death)    			                     		  *
 * Tyrluk   - morn@telmaron.com or dajy@mindspring.com			          *
 * Thanatos - morn@telmaron.com or jonathan_w._rose@ffic.com              * 
 * Heavily modified by Zane (zane@supernova.org)                          *
 **************************************************************************/

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "olc.h"

char buf[MAX_STRING_LENGTH];
char arg[MAX_INPUT_LENGTH];

/* Return TRUE if area changed, FALSE if not. */
#define REDIT( fun )		bool fun( CHAR_DATA *ch, char *argument )
#define OEDIT( fun )		bool fun( CHAR_DATA *ch, char *argument )
#define MEDIT( fun )		bool fun( CHAR_DATA *ch, char *argument )
#define AEDIT( fun )		bool fun( CHAR_DATA *ch, char *argument )
#define MPEDIT( fun )		bool fun( CHAR_DATA *ch, char *argument )
#define MPGEDIT( fun )		bool fun( CHAR_DATA *ch, char *argument )

struct olc_help_type
{
    char *command;
    const void *structure;
    char *desc;
};



bool show_version( CHAR_DATA *ch, char *argument )
{
    send_to_char( VERSION, ch );
    send_to_char( "\n\r",  ch );
    send_to_char( AUTHOR,  ch );
    send_to_char( "\n\r",  ch );
    send_to_char( DATE,    ch );
    send_to_char( "\n\r",  ch );
    send_to_char( CREDITS, ch );
    send_to_char( "\n\r",  ch );
    send_to_char( ADDONS,  ch );
    send_to_char( "\n\r",  ch );

    return FALSE;
}    

/*
 * This table contains help commands and a brief description of each.
 * ------------------------------------------------------------------
 */
const struct olc_help_type help_table[] =
{
    {	"area",		area_flags,	 "Area attributes."					 },
    {	"room",		room_flags,	 "Room attributes."					 },
    {	"sector",	sector_flags,	 "Sector types, terrain."		 },
    {	"exit",		exit_flags,	 "Exit types."						 },
    {	"type",		type_flags,	 "Types of objects."				 },
    {	"extra",	extra_flags,	 "Object attributes."			 },
    {	"wear",		wear_flags,	 "Where to wear object."			 },
    {	"sex",		sex_flags,	 "Sexes."							 },
    {	"ac",		ac_type,	 "Ac for different attacks."		 },
    {	"act",		act_flags,	 "Mobile attributes."				 },
    {	"affect",	affect_flags,	 "Mobile affects."				 },
    {	"wear-loc",	wear_loc_flags,	 "Where mobile wears object."	 },
    {	"spells",	skill_table,	 "Names of current spells." 	 },
    {	"weapon",	weapon_flags,	 "Type of weapon." 				 },
    {	"container",	container_flags, "Container status."		 },
    {	"liquid",	liquid_flags,	 "Types of liquids."			 },
    {	"mudprogs",	mprog_type_flags,"Types of MudProgs."			 },        

/* ROM specific bits: */

    {	"form",		form_flags,	 "Mobile body form."				 },
    {	"part",		part_flags,	 "Mobile body parts."				 },
    {	"imm",		imm_flags,	 "Mobile immunity."					 },
    {	"res",		res_flags,	 "Mobile resistance."				 },
    {	"vuln",		vuln_flags,	 "Mobile vlnerability."				 },
    {	"off",		off_flags,	 "Mobile offensive behaviour."		 },
    {	"size",		size_flags,	 "Mobile size."						 },
    {   "position",     position_flags,  "Mobile positions."         },
    {	"material",	material_type,	 "Material mob/obj is made from."},
    {   "wclass",       weapon_class,    "Weapon class."             }, 
    {   "wtype",        weapon_type,     "Special weapon type."      },
    {   "randobj",      rnd_obj_flags,   "Random object types."      },

/* Clans */

    {   "joinflags",	clan_join_flags, "Clan join flags."		 },
    {   "clanflags",    clan_flags,      "Clan flags."	         },
    {	"",				0,				 ""		 				 }
};

char *                  mprog_type_to_name      args( ( int type ) );

/*****************************************************************************
 Name:		show_flag_cmds
 Purpose:	Displays settable flags and stats.
 Called by:	show_help(olc_act.c).
 ****************************************************************************/
void show_flag_cmds( CHAR_DATA *ch, const struct flag_type *flag_table )
{
    char buf1 [ MAX_STRING_LENGTH ];
    int  flag;
    int  col;
 
    buf1[0] = '\0';
    col = 0;
    for (flag = 0; flag_table[flag].name[0] != '\0'; flag++)
    {
	if ( flag_table[flag].settable )
	{
	    sprintf( buf, "%-19.18s", flag_table[flag].name );
	    strcat( buf1, buf );
	    if ( ++col % 4 == 0 )
		strcat( buf1, "\n\r" );
	}
    }
 
    if ( col % 4 != 0 )
	strcat( buf1, "\n\r" );

    send_to_char( buf1, ch );
    return;
}


/*****************************************************************************
 Name:		show_skill_cmds
 Purpose:	Displays all skill functions.
 		Does remove those damn immortal commands from the list.
 		Could be improved by:
 		(1) Adding a check for a particular class.
 		(2) Adding a check for a level range.
 Called by:	show_help(olc_act.c).
 ****************************************************************************/
void show_skill_cmds( CHAR_DATA *ch, int tar )
{
    char buf1 [ MAX_STRING_LENGTH*2 ];
    int  sn;
    int  col;
 
    buf1[0] = '\0';
    col = 0;
    for (sn = 0; sn < MAX_SKILL; sn++)
    {
	if ( !skill_table[sn].name )
	    break;

	if ( !str_cmp( skill_table[sn].name, "reserved" )
	  || skill_table[sn].spell_fun == spell_null )
	    continue;

	if ( tar == -1 || skill_table[sn].target == tar )
	{
	    sprintf( buf, "%-19.18s", skill_table[sn].name );
	    strcat( buf1, buf );
	    if ( ++col % 4 == 0 )
		strcat( buf1, "\n\r" );
	}
    }

    if ( col % 4 != 0 )
	strcat( buf1, "\n\r" );

    send_to_char( buf1, ch );
    return;
}



/*****************************************************************************
 Name:		show_help
 Purpose:	Displays help for many tables used in OLC.
 Called by:	olc interpreters.
 ****************************************************************************/
bool show_help( CHAR_DATA *ch, char *argument )
{
    char spell[MAX_INPUT_LENGTH];
    int cnt;

    argument = one_argument( argument, arg );
    one_argument( argument, spell );

    /*
     * Display syntax.
     */
    if ( arg[0] == '\0' )
    {
	send_to_char( "Syntax:  ? [command]\n\r\n\r", ch );
	send_to_char( "[command]  [description]\n\r", ch );
	for (cnt = 0; help_table[cnt].command[0] != '\0'; cnt++)
	{
	    sprintf( buf, "%-10.10s -%s\n\r",
	        capitalize( help_table[cnt].command ),
		help_table[cnt].desc );
	    send_to_char( buf, ch );
	}
	return FALSE;
    }

    /*
     * Find the command, show changeable data.
     * ---------------------------------------
     */
    for (cnt = 0; help_table[cnt].command[0]; cnt++)
    {
        if (  arg[0] == help_table[cnt].command[0]
          && !str_prefix( arg, help_table[cnt].command ) )
	{
	    if ( help_table[cnt].structure == skill_table )
	    {

		if ( !spell[0] )
		{
		    send_to_char( "Syntax:  ? spells "
		        "[ignore/attack/defend/self/object/all]\n\r", ch );
		    return FALSE;
		}

		if ( !str_prefix( spell, "all" ) )
		    show_skill_cmds( ch, -1 );
		else if ( !str_prefix( spell, "ignore" ) )
		    show_skill_cmds( ch, TAR_IGNORE );
		else if ( !str_prefix( spell, "attack" ) )
		    show_skill_cmds( ch, TAR_CHAR_OFFENSIVE );
		else if ( !str_prefix( spell, "defend" ) )
		    show_skill_cmds( ch, TAR_CHAR_DEFENSIVE );
		else if ( !str_prefix( spell, "self" ) )
		    show_skill_cmds( ch, TAR_CHAR_SELF );
		else if ( !str_prefix( spell, "object" ) )
		    show_skill_cmds( ch, TAR_OBJ_INV );
		else
		    send_to_char( "Syntax:  ? spell "
		        "[ignore/attack/defend/self/object/all]\n\r", ch );
		    
		return FALSE;
	    }
	    else
	    {
		show_flag_cmds( ch, help_table[cnt].structure );
		return FALSE;
	    }
	}
    }

    show_help( ch, "" );
    return FALSE;
}



REDIT( redit_mlist )
{
    MOB_INDEX_DATA	*pMobIndex;
    AREA_DATA		*pArea;
    char		buf1 [ MAX_STRING_LENGTH*2 ];
    bool fAll, found;
    int vnum;
    int  col = 0;

    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Syntax:  mlist <all/name>\n\r", ch );
	return FALSE;
    }

    pArea = ch->in_room->area;
    buf1[0] = '\0';
    fAll    = !str_cmp( arg, "all" );
    found   = FALSE;

    for ( vnum = pArea->lvnum; vnum <= pArea->uvnum; vnum++ )
    {
	if ( ( pMobIndex = get_mob_index( vnum ) ) )
	{
	    if ( fAll || is_name( arg, pMobIndex->player_name ) )
	    {
		found = TRUE;
		sprintf( buf, "[%5d] %-17.16s",
		    pMobIndex->vnum, capitalize( pMobIndex->short_descr ) );
		strcat( buf1, buf );
		if ( ++col % 3 == 0 )
		    strcat( buf1, "\n\r" );
	    }
	}
    }

    if ( !found )
    {
	send_to_char( "Mobile(s) not found in this area.\n\r", ch);
	return FALSE;
    }

    if ( col % 3 != 0 )
	strcat( buf1, "\n\r" );

    send_to_char( buf1, ch );
    return FALSE;
}

AEDIT( aedit_rlist )
{
    ROOM_INDEX_DATA	*pRoomIndex;
    AREA_DATA		*pArea;
    char		buf1 [ MAX_STRING_LENGTH*2 ];
    bool found;
    int vnum;
    int  col = 0;

    one_argument( argument, arg );

    pArea = ch->in_room->area;
    buf1[0] = '\0';
    found   = FALSE;

    for ( vnum = pArea->lvnum; vnum <= pArea->uvnum; vnum++ )
    {
	if ( ( pRoomIndex = get_room_index( vnum ) ) )
	{
	    found = TRUE;
	    sprintf( buf, "[%5d] %-17.16s",
	    pRoomIndex->vnum, capitalize( pRoomIndex->name ) );
	    strcat( buf1, buf );
	    if ( ++col % 3 == 0 )
	    strcat( buf1, "\n\r" );
	}
    }

    if ( !found )
    {
	send_to_char( "No rooms found in this area.\n\r", ch);
	return FALSE;
    }

    if ( col % 3 != 0 )
	strcat( buf1, "\n\r" );

    send_to_char( buf1, ch );
    return FALSE;
}



REDIT( redit_olist )
{
    OBJ_INDEX_DATA	*pObjIndex;
    AREA_DATA		*pArea;
    char		buf1 [ MAX_STRING_LENGTH*2 ];
    bool fAll, found;
    int vnum;
    int  col = 0;

    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Syntax:  olist <all/name/item_type>\n\r", ch );
	return FALSE;
    }

    pArea = ch->in_room->area;
    buf1[0] = '\0';
    fAll    = !str_cmp( arg, "all" );
    found   = FALSE;

    for ( vnum = pArea->lvnum; vnum <= pArea->uvnum; vnum++ )
    {
	if ( ( pObjIndex = get_obj_index( vnum ) ) )
	{
	    if ( fAll || is_name( arg, pObjIndex->name )
	    || flag_value( type_flags, arg ) == pObjIndex->item_type )
	    {
		found = TRUE;
		sprintf( buf, "[%5d] %-17.16s",
		    pObjIndex->vnum, capitalize( pObjIndex->short_descr ) );
		strcat( buf1, buf );
		if ( ++col % 3 == 0 )
		    strcat( buf1, "\n\r" );
	    }
	}
    }

    if ( !found )
    {
	send_to_char( "Object(s) not found in this area.\n\r", ch);
	return FALSE;
    }

    if ( col % 3 != 0 )
	strcat( buf1, "\n\r" );

    send_to_char( buf1, ch );
    return FALSE;
}



REDIT( redit_mshow )
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( !argument[0] )
    {
	send_to_char( "Syntax:  mshow <vnum>\n\r", ch );
	return FALSE;
    }

    if ( is_number( argument ) )
    {
	value = atoi( argument );
	if ( !( pMob = get_mob_index( value ) ))
	{
	    send_to_char( "REdit:  That mobile does not exist.\n\r", ch );
	    return FALSE;
	}

	ch->desc->pEdit = (void *)pMob;
    }
 
    medit_show( ch, argument );
    ch->desc->pEdit = (void *)ch->in_room;
    return FALSE; 
}



REDIT( redit_oshow )
{
    OBJ_INDEX_DATA *pObj;
    int value;

    if ( !argument[0] )
    {
	send_to_char( "Syntax:  oshow <vnum>\n\r", ch );
	return FALSE;
    }

    if ( is_number( argument ) )
    {
	value = atoi( argument );
	if ( !( pObj = get_obj_index( value ) ))
	{
	    send_to_char( "REdit:  That object does not exist.\n\r", ch );
	    return FALSE;
	}

	ch->desc->pEdit = (void *)pObj;
    }
 
    oedit_show( ch, argument );
    ch->desc->pEdit = (void *)ch->in_room;
    return FALSE; 
}



/*****************************************************************************
 Name:		check_range( lower vnum, upper vnum )
 Purpose:	Ensures the range spans only one area.
 Called by:	aedit_vnum(olc_act.c).
 ****************************************************************************/
bool check_range( int lower, int upper )
{
    AREA_DATA *pArea;
    int cnt = 0;

    for ( pArea = area_first; pArea; pArea = pArea->next )
    {
	/*
	 * lower < area < upper
	 */
        if ( ( lower <= pArea->lvnum && pArea->lvnum <= upper )
	||   ( lower <= pArea->uvnum && pArea->uvnum <= upper ) )
	    ++cnt;

	if ( cnt > 1 )
	    return FALSE;
    }
    return TRUE;
}



AREA_DATA *get_vnum_area( int vnum )
{
    AREA_DATA *pArea;

    for ( pArea = area_first; pArea; pArea = pArea->next )
    {
        if ( vnum >= pArea->lvnum
          && vnum <= pArea->uvnum )
            return pArea;
    }

    return 0;
}



/*
 * Area Editor Functions.
 */
AEDIT( aedit_show )
{
    AREA_DATA *pArea;

    EDIT_AREA(ch, pArea);

    sprintf( buf, "Name:     [%5d] %s\n\r", pArea->vnum, pArea->name );
    send_to_char( buf, ch );

#if 0  /* ROM OLC */
    sprintf( buf, "Recall:   [%5d] %s\n\r", pArea->recall,
	get_room_index( pArea->recall )
	? get_room_index( pArea->recall )->name : "none" );
    send_to_char( buf, ch );
#endif /* ROM */

    sprintf( buf, "File:     %s\n\r", pArea->filename );
    send_to_char( buf, ch );

    sprintf( buf, "Vnums:    [%d-%d]\n\r", pArea->lvnum, pArea->uvnum );
    send_to_char( buf, ch );

    sprintf( buf, "Age:      [%d]\n\r",	pArea->age );
    send_to_char( buf, ch );

    sprintf( buf, "Players:  [%d]\n\r", pArea->nplayer );
    send_to_char( buf, ch );

    sprintf( buf, "Security: [%d]\n\r", pArea->security );
    send_to_char( buf, ch );

    sprintf( buf, "Builders: [%s]\n\r", pArea->builders );
    send_to_char( buf, ch );

    sprintf( buf, "Flags:    [%s]\n\r", flag_string( area_flags, pArea->area_flags ) );
    send_to_char( buf, ch );

    return FALSE;
}



AEDIT( aedit_reset )
{
    AREA_DATA *pArea;

    EDIT_AREA(ch, pArea);

    reset_area( pArea );
    send_to_char( "Area reset.\n\r", ch );

    return FALSE;
}

AEDIT( aedit_change )
{
    AREA_DATA *pArea;

    EDIT_AREA(ch, pArea);
	
    if ( !IS_SET( pArea->area_flags, AREA_CHANGED ) )
    {
	SET_BIT( pArea->area_flags, AREA_CHANGED );
        send_to_char( "Area flag 'changed' set.\n\r", ch );
    }
    else
    {
        REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
        send_to_char( "Area flag 'changed' removed.\n\r", ch );
    }
    return FALSE;
}



AEDIT( aedit_create )
{
    AREA_DATA *pArea;

    pArea               =   new_area();
    area_last->next     =   pArea;
    area_last		=   pArea;	/* Thanks, Walker. */
    ch->desc->pEdit     =   (void *)pArea;

    SET_BIT( pArea->area_flags, AREA_ADDED );
    send_to_char( "Area Created.\n\r", ch );
    return FALSE;
}



AEDIT( aedit_name )
{
    AREA_DATA *pArea;

    EDIT_AREA(ch, pArea);

    if ( !argument[0] )
    {
	send_to_char( "Syntax:   name [$name]\n\r", ch );
	return FALSE;
    }

    free_string( pArea->name );
    pArea->name = str_dup( argument );

    send_to_char( "Name set.\n\r", ch );
    return TRUE;
}



AEDIT( aedit_file )
{
    AREA_DATA *pArea;
    char file[MAX_INPUT_LENGTH];
    int i, length;

    EDIT_AREA(ch, pArea);

    one_argument( argument, file );	/* Forces Lowercase */

    if ( !argument[0] )
    {
	send_to_char( "Syntax:  filename [$file]\n\r", ch );
	return FALSE;
    }

    /*
     * Simple Syntax Check.
     */
    length = strlen( argument );
    if ( length > 8 )
    {
	send_to_char( "No more than eight characters allowed.\n\r", ch );
	return FALSE;
    }
    
    /*
     * Allow only letters and numbers.
     */
    for ( i = 0; i < length; i++ )
    {
	if ( !isalnum( file[i] ) )
	{
	    send_to_char( "Only letters and numbers are valid.\n\r", ch );
	    return FALSE;
	}
    }    

    free_string( pArea->filename );
    strcat( file, ".are" );
    pArea->filename = str_dup( file );

    send_to_char( "Filename set.\n\r", ch );
    return TRUE;
}



AEDIT( aedit_age )
{
    AREA_DATA *pArea;
    char age[MAX_INPUT_LENGTH];

    EDIT_AREA(ch, pArea);

    one_argument( argument, age );

    if ( !is_number( age ) || !age[0] )
    {
	send_to_char( "Syntax:  age [#age]\n\r", ch );
	return FALSE;
    }

    pArea->age = atoi( age );

    send_to_char( "Age set.\n\r", ch );
    return TRUE;
}


#if 0 /* ROM OLC */
AEDIT( aedit_recall )
{
    AREA_DATA *pArea;
    char room[MAX_INPUT_LENGTH];
    int  value;

    EDIT_AREA(ch, pArea);

    one_argument( argument, room );

    if ( !is_number( argument ) || !argument[0] )
    {
	send_to_char( "Syntax:  recall [#rvnum]\n\r", ch );
	return FALSE;
    }

    value = atoi( room );

    if ( !get_room_index( value ) )
    {
	send_to_char( "AEdit:  Room vnum does not exist.\n\r", ch );
	return FALSE;
    }

    pArea->recall = value;

    send_to_char( "Recall set.\n\r", ch );
    return TRUE;
}
#endif /* ROM OLC */


AEDIT( aedit_security )
{
    AREA_DATA *pArea;
    char sec[MAX_INPUT_LENGTH];
    int  value;

    EDIT_AREA(ch, pArea);

    one_argument( argument, sec );

    if ( !is_number( sec ) || !sec[0] )
    {
	send_to_char( "Syntax:  security [#level]\n\r", ch );
	return FALSE;
    }

    value = atoi( sec );

    if ( value > ch->pcdata->security || value < 0 )
    {
	if ( ch->pcdata->security != 0 )
	{
	    printf_to_char( ch, "Security is 0-%d.\n\r", ch->pcdata->security );
	}
	else
	    send_to_char( "Security is 0 only.\n\r", ch );
	return FALSE;
    }

    pArea->security = value;

    send_to_char( "Security set.\n\r", ch );
    return TRUE;
}



AEDIT( aedit_builder )
{
    AREA_DATA *pArea;
    char name[MAX_INPUT_LENGTH];

    EDIT_AREA(ch, pArea);

    one_argument( argument, name );

    if ( !name[0] )
    {
	send_to_char( "Syntax:  builder [$name]  -toggles builder\n\r", ch );
	send_to_char( "Syntax:  builder All      -allows everyone\n\r", ch );
	return FALSE;
    }

    name[0] = UPPER( name[0] );

    if ( strstr( pArea->builders, name ) )
    {
	pArea->builders = string_replace( pArea->builders, name, "\0" );
	pArea->builders = string_unpad( pArea->builders );

	if ( !pArea->builders[0] )
	{
	    free_string( pArea->builders );
	    pArea->builders = str_dup( "None" );
	}
	send_to_char( "Builder removed.\n\r", ch );
	return TRUE;
    }
    else
    {
	buf[0] = '\0';
	if ( strstr( pArea->builders, "None" ) != '\0' )
	{
	    pArea->builders = string_replace( pArea->builders, "None", "\0" );
	    pArea->builders = string_unpad( pArea->builders );
	}

	if (pArea->builders[0] != '\0' )
	{
	    strcat( buf, pArea->builders );
	    strcat( buf, " " );
	}
	strcat( buf, name );
	free_string( pArea->builders );
	pArea->builders = string_proper( str_dup( buf ) );

	send_to_char( "Builder added.\n\r", ch );
	return TRUE;
    }

    return FALSE;
}



AEDIT( aedit_vnum )
{
    AREA_DATA *pArea;
    char lower[MAX_INPUT_LENGTH];
    char upper[MAX_INPUT_LENGTH];
    int  ilower;
    int  iupper;

    EDIT_AREA(ch, pArea);

    argument = one_argument( argument, lower );
    one_argument( argument, upper );

    if ( !is_number( lower ) || !lower[0]
    || !is_number( upper ) || !upper[0] )
    {
	send_to_char( "Syntax:  vnum [#lower] [#upper]\n\r", ch );
	return FALSE;
    }

    if ( ( ilower = atoi( lower ) ) > ( iupper = atoi( upper ) ) )
    {
	send_to_char( "AEdit:  Upper must be larger then lower.\n\r", ch );
	return FALSE;
    }
    
    if ( !check_range( atoi( lower ), atoi( upper ) ) )
    {
	send_to_char( "AEdit:  Range must include only this area.\n\r", ch );
	return FALSE;
    }

    if ( get_vnum_area( ilower )
    && get_vnum_area( ilower ) != pArea )
    {
	send_to_char( "AEdit:  Lower vnum already assigned.\n\r", ch );
	return FALSE;
    }

    pArea->lvnum = ilower;
    send_to_char( "Lower vnum set.\n\r", ch );

    if ( get_vnum_area( iupper )
    && get_vnum_area( iupper ) != pArea )
    {
	send_to_char( "AEdit:  Upper vnum already assigned.\n\r", ch );
	return TRUE;	/* The lower value has been set. */
    }

    pArea->uvnum = iupper;
    send_to_char( "Upper vnum set.\n\r", ch );

    return TRUE;
}



AEDIT( aedit_lvnum )
{
    AREA_DATA *pArea;
    char lower[MAX_INPUT_LENGTH];
    int  ilower;
    int  iupper;

    EDIT_AREA(ch, pArea);

    one_argument( argument, lower );

    if ( !is_number( lower ) || !lower[0] )
    {
	send_to_char( "Syntax:  lvnum [#lower]\n\r", ch );
	return FALSE;
    }

    if ( ( ilower = atoi( lower ) ) > ( iupper = pArea->uvnum ) )
    {
	send_to_char( "AEdit:  Value must be less than the uvnum.\n\r", ch );
	return FALSE;
    }
    
    if ( !check_range( ilower, iupper ) )
    {
	send_to_char( "AEdit:  Range must include only this area.\n\r", ch );
	return FALSE;
    }

    if ( get_vnum_area( ilower )
    && get_vnum_area( ilower ) != pArea )
    {
	send_to_char( "AEdit:  Lower vnum already assigned.\n\r", ch );
	return FALSE;
    }

    pArea->lvnum = ilower;
    send_to_char( "Lower vnum set.\n\r", ch );
    return TRUE;
}



AEDIT( aedit_uvnum )
{
    AREA_DATA *pArea;
    char upper[MAX_INPUT_LENGTH];
    int  ilower;
    int  iupper;

    EDIT_AREA(ch, pArea);

    one_argument( argument, upper );

    if ( !is_number( upper ) || !upper[0] )
    {
	send_to_char( "Syntax:  uvnum [#upper]\n\r", ch );
	return FALSE;
    }

    if ( ( ilower = pArea->lvnum ) > ( iupper = atoi( upper ) ) )
    {
	send_to_char( "AEdit:  Upper must be larger then lower.\n\r", ch );
	return FALSE;
    }
    
    if ( !check_range( ilower, iupper ) )
    {
	send_to_char( "AEdit:  Range must include only this area.\n\r", ch );
	return FALSE;
    }

    if ( get_vnum_area( iupper )
    && get_vnum_area( iupper ) != pArea )
    {
	send_to_char( "AEdit:  Upper vnum already assigned.\n\r", ch );
	return FALSE;
    }

    pArea->uvnum = iupper;
    send_to_char( "Upper vnum set.\n\r", ch );

    return TRUE;
}



/*
 * Room Editor Functions.
 */
REDIT( redit_show )
{
    ROOM_INDEX_DATA	*pRoom;
    char		buf1 [2*MAX_STRING_LENGTH];
    OBJ_DATA		*obj;
    CHAR_DATA		*rch;
    int			door;
    bool		fcnt;
    
    EDIT_ROOM(ch, pRoom);

    buf1[0] = '\0';
    
    sprintf( buf, "Description:\n\r%s", pRoom->description );
    strcat( buf1, buf );

    sprintf( buf, "Name:       [%s]\n\rArea:       [%5d] %s\n\r",
	    pRoom->name, pRoom->area->vnum, pRoom->area->name );
    strcat( buf1, buf );

    sprintf( buf, "Vnum:       [%5d]\n\rSector:     [%s]\n\r",
	    pRoom->vnum, flag_string( sector_flags, pRoom->sector_type ) );
    strcat( buf1, buf );

    sprintf( buf, "Room flags: [%s]\n\r",
	    flag_string( room_flags, pRoom->room_flags ) );
    strcat( buf1, buf );

    if ( pRoom->extra_descr )
    {
	EXTRA_DESCR_DATA *ed;

	strcat( buf1, "Desc Kwds:  [" );
	for ( ed = pRoom->extra_descr; ed; ed = ed->next )
	{
	    strcat( buf1, ed->keyword );
	    if ( ed->next )
		strcat( buf1, " " );
	}
	strcat( buf1, "]\n\r" );
    }

    strcat( buf1, "Characters: [" );
    fcnt = FALSE;
    for ( rch = pRoom->people; rch; rch = rch->next_in_room )
    {
	one_argument( rch->name, buf );
	strcat( buf1, buf );
	strcat( buf1, " " );
	fcnt = TRUE;
    }

    if ( fcnt )
    {
	int end;

	end = strlen(buf1) - 1;
	buf1[end] = ']';
	strcat( buf1, "\n\r" );
    }
    else
	strcat( buf1, "none]\n\r" );

    strcat( buf1, "Objects:    [" );
    fcnt = FALSE;
    for ( obj = pRoom->contents; obj; obj = obj->next_content )
    {
	one_argument( obj->name, buf );
	strcat( buf1, buf );
	strcat( buf1, " " );
	fcnt = TRUE;
    }

    if ( fcnt )
    {
	int end;

	end = strlen(buf1) - 1;
	buf1[end] = ']';
	strcat( buf1, "\n\r" );
    }
    else
	strcat( buf1, "none]\n\r" );

    for ( door = 0; door < MAX_DIR; door++ )
    {
	EXIT_DATA *pexit;

	if ( ( pexit = pRoom->exit[door] ) )
	{
	    char word[MAX_INPUT_LENGTH];
	    char reset_state[MAX_STRING_LENGTH];
	    char *state;
	    int i, length;

	    sprintf( buf, "%-5s to [%5d] Key: [%5d]",
		capitalize(dir_name[door]),
		pexit->u1.to_room ? pexit->u1.to_room->vnum : 0,      /* ROM OLC */
		pexit->key );
	    strcat( buf1, buf );

	    /*
	     * Format up the exit info.
	     * Capitalize all flags that are not part of the reset info.
	     */
	    strcpy( reset_state, flag_string( exit_flags, pexit->rs_flags ) );
	    state = flag_string( exit_flags, pexit->exit_info );
	    strcat( buf1, " Exit flags: [" );
	    for (; ;)
	    {
		state = one_argument( state, word );

		if ( word[0] == '\0' )
		{
		    int end;

		    end = strlen(buf1) - 1;
		    buf1[end] = ']';
		    strcat( buf1, "\n\r" );
		    break;
		}

		if ( str_infix( word, reset_state ) )
		{
		    length = strlen(word);
		    for (i = 0; i < length; i++)
			word[i] = UPPER(word[i]);
		}
		strcat( buf1, word );
		strcat( buf1, " " );
	    }

	    if ( pexit->keyword && pexit->keyword[0] != '\0' )
	    {
		sprintf( buf, "Kwds: [%s]\n\r", pexit->keyword );
		strcat( buf1, buf );
	    }
	    if ( pexit->description && pexit->description[0] != '\0' )
	    {
		sprintf( buf, "%s", pexit->description );
		strcat( buf1, buf );
	    }
	}
    }

    send_to_char( buf1, ch );
    return FALSE;
}

/* Local function. */
bool change_exit( CHAR_DATA *ch, char *argument, int door )
{
    ROOM_INDEX_DATA *pRoom;
    char command[MAX_INPUT_LENGTH];
    char temp[MAX_INPUT_LENGTH];
    int  value;

    EDIT_ROOM(ch, pRoom);

   
    /*
     * Now parse the arguments.
     */
    argument = one_argument( argument, command );
    one_argument( argument, arg );

    if ( !command[0] && !argument[0] )	/* Move command. */
    {
	move_char( ch, door, TRUE );                    /* ROM OLC */
	return FALSE;
    }

    if ( command[0] == '?')
    {
	do_help( ch, "EXIT" );
	return FALSE;
    }

    if ( !str_cmp( command, "delete" ) )
    {
	ROOM_INDEX_DATA *pToRoom;
	sh_int rev;                                     /* ROM OLC */
	
	if ( !pRoom->exit[door] )
	{
	    send_to_char( "REdit:  Cannot delete a null exit.\n\r", ch );
	    return FALSE;
	}

	/*
	 * Remove ToRoom Exit.
	 */
	rev = rev_dir[door];
	pToRoom = pRoom->exit[door]->u1.to_room;       /* ROM OLC */
	
	if ( pToRoom->exit[rev] )
	{
	    free_exit( pToRoom->exit[rev] );
	    pToRoom->exit[rev] = NULL;
	}

	/*
	 * Remove this exit.
	 */
	free_exit( pRoom->exit[door] );
	pRoom->exit[door] = NULL;

	send_to_char( "Exit unlinked.\n\r", ch );
	return TRUE;
    }

    if ( !str_cmp( command, "link" ) )
    {
	EXIT_DATA *pExit;

	if ( !arg[0] || !is_number( arg ))
	{
	    send_to_char( "Syntax:  [direction] link [vnum] [flag]\n\r", ch );
	    return FALSE;
	}

	value = atoi( arg );

	if ( !get_room_index( value ) )
	{
	    send_to_char( "REdit:  Cannot link to non-existant room.\n\r", ch );
	    return FALSE;
	}

	if ( !IS_BUILDER( ch, get_room_index( value )->area ) )
	{
	    send_to_char( "REdit:  Cannot link to that area.\n\r", ch );
	    return FALSE;
	}

	if ( get_room_index( value )->exit[rev_dir[door]] )
	{
	    send_to_char( "REdit:  Remote side's exit already exists.\n\r", ch );
	    return FALSE;
	}

	if ( !pRoom->exit[door] )
	{
	    pRoom->exit[door] = new_exit();
	}

	pRoom->exit[door]->u1.to_room = get_room_index( value );   /* ROM OLC */
	pRoom->exit[door]->orig_door  = door;
/*	pRoom->exit[door]->vnum = value;                Can't set vnum in ROM */
    
 	pRoom                   = get_room_index( value );
 	door                    = rev_dir[door];
 	pExit                   = new_exit();
 	pExit->u1.to_room       = ch->in_room;
/*	pExit->vnum             = ch->in_room->vnum;    Can't set vnum in ROM */
	pExit->orig_door	= door;
	pRoom->exit[door]       = pExit;

	send_to_char( "Two-way link established.\n\r", ch );
	return TRUE;
    }
        
    if ( !str_cmp( command, "dig" ) )
    {
        char buf1[MAX_INPUT_LENGTH];
        
	if ( !arg[0] || !is_number( arg ) )
	{
	    send_to_char( "Syntax: [direction] dig <vnum> [flag]\n\r", ch );
	    return FALSE;
	}
	one_argument( arg, temp );
	
	if ( !is_number( temp ) )
	    send_to_char( "vnum is not an integer\n\r", ch );
	
	redit_create( ch, temp );
	sprintf( buf1, "link %s", temp );
	change_exit( ch, buf1, door);

	return TRUE;
    }

    if ( !str_cmp( command, "room" ) )
    {
	if ( !arg[0] || !is_number( arg ) )
	{
	    send_to_char( "Syntax:  [direction] room [vnum]\n\r", ch );
	    return FALSE;
	}

	if ( !pRoom->exit[door] )
	{
	    pRoom->exit[door] = new_exit();
	}

	value = atoi( arg );

	if ( !get_room_index( value ) )
	{
	    send_to_char( "REdit:  Cannot link to non-existant room.\n\r", ch );
	    return FALSE;
	}

	pRoom->exit[door]->u1.to_room = get_room_index( value );    /* ROM OLC */
	pRoom->exit[door]->orig_door = door;
/*	pRoom->exit[door]->vnum = value;                 Can't set vnum in ROM */

	send_to_char( "One-way link established.\n\r", ch );
	return TRUE;
    }

    if ( !str_cmp( command, "key" ) )
    {
	if ( !arg[0] || !is_number( arg ) )
	{
	    send_to_char( "Syntax:  [direction] key [vnum]\n\r", ch );
	    return FALSE;
	}

	if ( !pRoom->exit[door] )
	{
	    send_to_char("REdit:  Cannot make a key for a non-existant exit.\n\r", ch );
	    return FALSE;
	}

	value = atoi( arg );

	if ( !get_obj_index( value ) )
	{
	    send_to_char( "REdit:  Item doesn't exist.\n\r", ch );
	    return FALSE;
	}

	if ( get_obj_index( atoi( argument ) )->item_type != ITEM_KEY )
	{
	    send_to_char( "REdit:  Key doesn't exist.\n\r", ch );
	    return FALSE;
	}

	pRoom->exit[door]->key = value;

	send_to_char( "Exit key set.\n\r", ch );
	return TRUE;
    }

    if ( !str_cmp( command, "name" ) )
    {
	if ( !arg[0] )
	{
	    send_to_char( "Syntax:  [direction] name [string]\n\r", ch );
	    return FALSE;
	}

	if ( !pRoom->exit[door] )
	{
	    send_to_char("REdit:  Cannot name a non-existant exit.\n\r", ch);
	    return FALSE;
	}

	free_string( pRoom->exit[door]->keyword );
	pRoom->exit[door]->keyword = str_dup( arg );

	send_to_char( "Exit name set.\n\r", ch );
	return TRUE;
    }

    if ( !str_prefix( command, "description" ) )
    {
	if ( !arg[0] )
	{
	    if ( !pRoom->exit[door] )
	    {
		send_to_char("REdit:  Cannot describe a non-existant exit.\n\r", ch);
		return FALSE;
	    }
	    string_append( ch, &pRoom->exit[door]->description );

	    return TRUE;
	}

	send_to_char( "Syntax:  [direction] desc\n\r", ch );
	return FALSE;
    }
     /*
     * Set the exit flags, needs full argument.
     * ----------------------------------------
     */
    if ( !str_cmp(command, "exit") )
    {
      if ( ( value = flag_value( exit_flags, arg ) ) != NO_FLAG )
      {
	ROOM_INDEX_DATA *pToRoom;
	sh_int rev;                                    /* ROM OLC */

	if ( !pRoom->exit[door] )
	{
	     send_to_char("REdit:  Cannot flag a non-existant exit.\n\r", ch);
	     return FALSE;
	}

	/*
	 * This room.
	 */
	TOGGLE_BIT(pRoom->exit[door]->rs_flags,  value);
	/* Don't toggle exit_info because it can be changed by players. */
	pRoom->exit[door]->exit_info = pRoom->exit[door]->rs_flags;

	/*
	 * Connected room.
	 */
	pToRoom = pRoom->exit[door]->u1.to_room;       /* ROM OLC */
	rev = rev_dir[door];

	/*
	 * If the connected room's exit maps back to us then set it's
	 * flags also.  Otherwise ignore it.
	 */
	if ( pToRoom->exit[rev] && pToRoom->exit[rev]->u1.to_room == pRoom ) 
	{
	    TOGGLE_BIT(pToRoom->exit[rev]->rs_flags,  value);
	    TOGGLE_BIT(pToRoom->exit[rev]->exit_info, value);
	}

    send_to_char( "Exit flag toggled.\n\r", ch );
	return TRUE;
      }
    }

    /* If we make it to here, user has typed an invalid command. */

    send_to_char("That is not a valid exit command!  Type \"help exit\" for help.\n\r", ch);

    return FALSE;
}



REDIT( redit_north )
{
    if ( change_exit( ch, argument, DIR_NORTH ) )
	return TRUE;

    return FALSE;
}



REDIT( redit_south )
{
    if ( change_exit( ch, argument, DIR_SOUTH ) )
	return TRUE;

    return FALSE;
}



REDIT( redit_east )
{
    if ( change_exit( ch, argument, DIR_EAST ) )
	return TRUE;

    return FALSE;
}



REDIT( redit_west )
{
    if ( change_exit( ch, argument, DIR_WEST ) )
	return TRUE;

    return FALSE;
}



REDIT( redit_up )
{
    if ( change_exit( ch, argument, DIR_UP ) )
	return TRUE;

    return FALSE;
}



REDIT( redit_down )
{
    if ( change_exit( ch, argument, DIR_DOWN ) )
	return TRUE;

    return FALSE;
}



REDIT( redit_ed )
{
    ROOM_INDEX_DATA *pRoom;
    EXTRA_DESCR_DATA *ed;
    char command[MAX_INPUT_LENGTH];
    char keyword[MAX_INPUT_LENGTH];

    EDIT_ROOM(ch, pRoom);

    argument = one_argument( argument, command );
    one_argument( argument, keyword );

    if ( !command[0] || !keyword[0] )
    {
	send_to_char( "Syntax:  ed add [keyword]\n\r", ch );
	send_to_char( "         ed edit [keyword]\n\r", ch );
	send_to_char( "         ed delete [keyword]\n\r", ch );
	send_to_char( "         ed format [keyword]\n\r", ch );
	return FALSE;
    }

    if ( !str_cmp( command, "add" ) )
    {
	if ( !keyword[0] )
	{
	    send_to_char( "Syntax:  ed add [keyword]\n\r", ch );
	    return FALSE;
	}

	ed			=   new_extra_descr();
	ed->keyword		=   str_dup( keyword );
	ed->description		=   str_dup( "" );
	ed->next		=   pRoom->extra_descr;
	pRoom->extra_descr	=   ed;

	string_append( ch, &ed->description );

	return TRUE;
    }


    if ( !str_cmp( command, "edit" ) )
    {
	if ( !keyword[0] )
	{
	    send_to_char( "Syntax:  ed edit [keyword]\n\r", ch );
	    return FALSE;
	}

	for ( ed = pRoom->extra_descr; ed; ed = ed->next )
	{
	    if ( is_name( keyword, ed->keyword ) )
		break;
	}

	if ( !ed )
	{
	    send_to_char( "REdit:  Extra description keyword not found.\n\r", ch );
	    return FALSE;
	}

	string_append( ch, &ed->description );

	return TRUE;
    }


    if ( !str_cmp( command, "delete" ) )
    {
	EXTRA_DESCR_DATA *ped = NULL;

	if ( !keyword[0] )
	{
	    send_to_char( "Syntax:  ed delete [keyword]\n\r", ch );
	    return FALSE;
	}

	for ( ed = pRoom->extra_descr; ed; ed = ed->next )
	{
	    if ( is_name( keyword, ed->keyword ) )
		break;
	    ped = ed;
	}

	if ( !ed )
	{
	    send_to_char( "REdit:  Extra description keyword not found.\n\r", ch );
	    return FALSE;
	}

	if ( !ped )
	    pRoom->extra_descr = ed->next;
	else
	    ped->next = ed->next;

	free_extra_descr( ed );

	send_to_char( "Extra description deleted.\n\r", ch );
	return TRUE;
    }


    if ( !str_cmp( command, "format" ) )
    {
	if ( !keyword[0] )
	{
	    send_to_char( "Syntax:  ed format [keyword]\n\r", ch );
	    return FALSE;
	}

	for ( ed = pRoom->extra_descr; ed; ed = ed->next )
	{
	    if ( is_name( keyword, ed->keyword ) )
		break;
	}

	if ( !ed )
	{
	    send_to_char( "REdit:  Extra description keyword not found.\n\r", ch );
	    return FALSE;
	}

	ed->description = format_string( ed->description );

	send_to_char( "Extra description formatted.\n\r", ch );
	return TRUE;
    }

    redit_ed( ch, "" );
    return FALSE;
}



REDIT( redit_create )
{
    AREA_DATA *pArea;
    ROOM_INDEX_DATA *pRoom;
    int value;
    int iHash;
    
    EDIT_ROOM(ch, pRoom);

    value = atoi( argument );

    if ( !argument[0] || value <= 0 )
    {
	send_to_char( "Syntax:  create [vnum > 0]\n\r", ch );
	return FALSE;
    }

    pArea = get_vnum_area( value );
    if ( !pArea )
    {
	send_to_char( "REdit:  That vnum is not assigned an area.\n\r", ch );
	return FALSE;
    }

    if ( !IS_BUILDER( ch, pArea ) )
    {
	send_to_char( "REdit:  Vnum in an area you cannot build in.\n\r", ch );
	return FALSE;
    }

    if ( get_room_index( value ) )
    {
	send_to_char( "REdit:  Room vnum already exists.\n\r", ch );
	return FALSE;
    }

    pRoom			= new_room_index();
    pRoom->area			= pArea;
    pRoom->vnum			= value;

    if ( value > top_vnum_room )
        top_vnum_room = value;

    iHash			= value % MAX_KEY_HASH;
    pRoom->next			= room_index_hash[iHash];
    room_index_hash[iHash]	= pRoom;
    ch->desc->pEdit		= (void *)pRoom;

    send_to_char( "Room created.\n\r", ch );
    return TRUE;
}



REDIT( redit_name )
{
    ROOM_INDEX_DATA *pRoom;

    EDIT_ROOM(ch, pRoom);

    if ( !argument[0] )
    {
	send_to_char( "Syntax:  name [name]\n\r", ch );
	return FALSE;
    }

    free_string( pRoom->name );
    pRoom->name = str_dup( argument );

    send_to_char( "Name set.\n\r", ch );
    return TRUE;
}



REDIT( redit_desc )
{
    ROOM_INDEX_DATA *pRoom;

    EDIT_ROOM(ch, pRoom);

    if ( !argument[0] )
    {
	string_append( ch, &pRoom->description );
	return TRUE;
    }

    send_to_char( "Syntax:  desc\n\r", ch );
    return FALSE;
}




REDIT( redit_format )
{
    ROOM_INDEX_DATA *pRoom;

    EDIT_ROOM(ch, pRoom);

    pRoom->description = format_string( pRoom->description );

    send_to_char( "String formatted.\n\r", ch );
    return TRUE;
}



REDIT( redit_mreset )
{
    ROOM_INDEX_DATA	*pRoom;
    MOB_INDEX_DATA	*pMobIndex;
    CHAR_DATA		*newmob;

    RESET_DATA		*pReset;
    char		output [ MAX_STRING_LENGTH ];

    EDIT_ROOM(ch, pRoom);

    argument = one_argument( argument, arg );

    if ( !arg[0] || !is_number( arg ) )
    {
	send_to_char ( "Syntax:  mreset <vnum> <max #>\n\r", ch );
	return FALSE;
    }

    if ( !( pMobIndex = get_mob_index( atoi( arg ) ) ) )
    {
	send_to_char( "REdit: No mobile has that vnum.\n\r", ch );
	return FALSE;
    }

    if ( pMobIndex->area != pRoom->area )
    {
	send_to_char( "REdit: No such mobile in this area.\n\r", ch );
	return FALSE;
    }

    /*
     * Create the mobile reset.
     */
    pReset              = new_reset_data();
    pReset->command	= 'M';
    pReset->vnum	= pMobIndex->vnum;
    pReset->arg2	= is_number( argument ) ? atoi( argument ) : MAX_MOB;
    pReset->arg3	= pRoom->vnum;
    add_reset( pRoom, pReset, 0/* Last slot*/ );

    /*
     * Create the mobile.
     */
    newmob = create_mobile( pMobIndex );
    char_to_room( newmob, pRoom );

    sprintf( output, "%s (%d) has been loaded and added to resets.\n\r"
	"There will be a maximum of %d loaded to this room.\n\r",
	capitalize( pMobIndex->short_descr ),
	pMobIndex->vnum,
	pReset->arg2 );
    send_to_char( output, ch );
    act( "$n has created $N!", ch, NULL, newmob, TO_ROOM );
    return TRUE;
}



struct wear_type
{
    int	wear_loc;
    int	wear_bit;
};



const struct wear_type wear_table[] =
{
    {	WEAR_NONE,	ITEM_TAKE		},
    {	WEAR_LIGHT,	ITEM_LIGHT		},
    {	WEAR_FINGER_L,	ITEM_WEAR_FINGER	},
    {	WEAR_FINGER_R,	ITEM_WEAR_FINGER	},
    {	WEAR_NECK_1,	ITEM_WEAR_NECK		},
    {	WEAR_NECK_2,	ITEM_WEAR_NECK		},
    {	WEAR_BODY,	ITEM_WEAR_BODY		},
    {	WEAR_HEAD,	ITEM_WEAR_HEAD		},
    {	WEAR_LEGS,	ITEM_WEAR_LEGS		},
    {	WEAR_FEET,	ITEM_WEAR_FEET		},
    {	WEAR_HANDS,	ITEM_WEAR_HANDS		},
    {	WEAR_ARMS,	ITEM_WEAR_ARMS		},
    {	WEAR_SHIELD,	ITEM_WEAR_SHIELD	},
    {	WEAR_ABOUT,	ITEM_WEAR_ABOUT		},
    {	WEAR_WAIST,	ITEM_WEAR_WAIST		},
    {	WEAR_WRIST_L,	ITEM_WEAR_WRIST		},
    {	WEAR_WRIST_R,	ITEM_WEAR_WRIST		},
    {	WEAR_WIELD,	ITEM_WIELD		},
    {	WEAR_HOLD,	ITEM_HOLD		},
    {	NO_FLAG,	NO_FLAG			}
};



/*****************************************************************************
 Name:		wear_loc
 Purpose:	Returns the location of the bit that matches the count.
 		1 = first match, 2 = second match etc.
 Called by:	oedit_reset(olc_act.c).
 ****************************************************************************/
int wear_loc(int bits, int count)
{
    int flag;
 
    for (flag = 0; wear_table[flag].wear_bit != NO_FLAG; flag++)
    {
        if ( IS_SET(bits, wear_table[flag].wear_bit) && --count < 1)
            return wear_table[flag].wear_loc;
    }
 
    return NO_FLAG;
}



/*****************************************************************************
 Name:		wear_bit
 Purpose:	Converts a wear_loc into a bit.
 Called by:	redit_oreset(olc_act.c).
 ****************************************************************************/
int wear_bit(int loc)
{
    int flag;
 
    for (flag = 0; wear_table[flag].wear_loc != NO_FLAG; flag++)
    {
        if ( loc == wear_table[flag].wear_loc )
            return wear_table[flag].wear_bit;
    }
 
    return 0;
}



REDIT( redit_oreset )
{
    ROOM_INDEX_DATA	*pRoom;
    OBJ_INDEX_DATA	*pObjIndex;
    OBJ_DATA		*newobj;
    OBJ_DATA		*to_obj;
    CHAR_DATA		*to_mob;
    char		arg2 [ MAX_INPUT_LENGTH ];
    int			olevel = 0;

    RESET_DATA		*pReset;
    char		output [ MAX_STRING_LENGTH ];

    EDIT_ROOM(ch, pRoom);

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

    if ( arg[0] == '\0' || !is_number( arg ) )
    {
	send_to_char ( "Syntax:  oreset <vnum> <args>\n\r", ch );
	send_to_char ( "        -no_args               = into room\n\r", ch );
	send_to_char ( "        -<obj_name>            = into obj\n\r", ch );
	send_to_char ( "        -<mob_name> <wear_loc> = into mob\n\r", ch );
	return FALSE;
    }

    if ( !( pObjIndex = get_obj_index( atoi( arg ) ) ) )
    {
	send_to_char( "REdit: No object has that vnum.\n\r", ch );
	return FALSE;
    }

    if ( pObjIndex->area != pRoom->area )
    {
	send_to_char( "REdit: No such object in this area.\n\r", ch );
	return FALSE;
    }

    /*
     * Load into room.
     */
    if ( arg2[0] == '\0' )
    {
	pReset		= new_reset_data();
	pReset->command	= 'O';
	pReset->vnum	= pObjIndex->vnum;
	pReset->arg2	= 0;
	pReset->arg3	= pRoom->vnum;
	add_reset( pRoom, pReset, 0/* Last slot*/ );

	newobj = create_object( pObjIndex, number_fuzzy( olevel ) );
	obj_to_room( newobj, pRoom );

	sprintf( output, "%s (%d) has been loaded and added to resets.\n\r",
	    capitalize( pObjIndex->short_descr ),
	    pObjIndex->vnum );
	send_to_char( output, ch );
    }
    else
    /*
     * Load into object's inventory.
     */
    if ( argument[0] == '\0'
    && ( ( to_obj = get_obj_list( ch, arg2, pRoom->contents ) ) != NULL ) )
    {
	pReset		= new_reset_data();
	pReset->command	= 'P';
	pReset->vnum	= pObjIndex->vnum;
	pReset->arg2	= 0;
	pReset->arg3	= to_obj->pIndexData->vnum;
	add_reset( pRoom, pReset, 0/* Last slot*/ );

	newobj = create_object( pObjIndex, number_fuzzy( olevel ) );
	newobj->cost = 0;
	obj_to_obj( newobj, to_obj );

	sprintf( output, "%s (%d) has been loaded into "
	    "%s (%d) and added to resets.\n\r",
	    capitalize( newobj->short_descr ),
	    newobj->pIndexData->vnum,
	    to_obj->short_descr,
	    to_obj->pIndexData->vnum );
	send_to_char( output, ch );
    }
    else
    /*
     * Load into mobile's inventory.
     */
    if ( ( to_mob = get_char_room( ch, arg2 ) ) != NULL )
    {
	int	wear_loc;

	/*
	 * Make sure the location on mobile is valid.
	 */
	if ( (wear_loc = flag_value( wear_loc_flags, argument )) == NO_FLAG )
	{
	    send_to_char( "REdit: Invalid wear_loc.  '? wear-loc'\n\r", ch );
	    return FALSE;
	}

	/*
	 * Disallow loading a sword(WEAR_WIELD) into WEAR_HEAD.
	 */
	if ( !IS_SET( pObjIndex->wear_flags, wear_bit(wear_loc) ) )
	{
	    sprintf( output,
	        "%s (%d) has wear flags: [%s]\n\r",
	        capitalize( pObjIndex->short_descr ),
	        pObjIndex->vnum,
		flag_string( wear_flags, pObjIndex->wear_flags ) );
	    send_to_char( output, ch );
	    return FALSE;
	}

	/*
	 * Can't load into same position.
	 */
	if ( get_eq_char( to_mob, wear_loc ) )
	{
	    send_to_char( "REdit:  Object already equipped.\n\r", ch );
	    return FALSE;
	}

	pReset		= new_reset_data();
	pReset->vnum	= pObjIndex->vnum;
	pReset->arg2	= wear_loc;
	if ( pReset->arg2 == WEAR_NONE )
	    pReset->command = 'G';
	else
	    pReset->command = 'E';
	pReset->arg3	= wear_loc;

	add_reset( pRoom, pReset, 0/* Last slot*/ );

	olevel  = URANGE( 0, to_mob->level - 2, LEVEL_HERO );
        newobj = create_object( pObjIndex, number_fuzzy( olevel ) );

	if ( to_mob->pIndexData->pShop )	/* Shop-keeper? */
	{
	    switch ( pObjIndex->item_type )
	    {
	    default:		olevel = 0;				break;
	    case ITEM_PILL:	olevel = number_range(  0, 10 );	break;
	    case ITEM_POTION:	olevel = number_range(  0, 10 );	break;
	    case ITEM_SCROLL:	olevel = number_range(  5, 15 );	break;
	    case ITEM_WAND:	olevel = number_range( 10, 20 );	break;
	    case ITEM_STAFF:	olevel = number_range( 15, 25 );	break;
	    case ITEM_ARMOR:	olevel = number_range(  5, 15 );	break;
	    case ITEM_WEAPON:	if ( pReset->command == 'G' )
	    			    olevel = number_range( 5, 15 );
				else
				    olevel = number_fuzzy( olevel );
		break;
	    }

	    newobj = create_object( pObjIndex, olevel );
	    if ( pReset->arg2 == WEAR_NONE )
		SET_BIT( newobj->extra_flags, ITEM_INVENTORY );
	}
	else
	    newobj = create_object( pObjIndex, number_fuzzy( olevel ) );

	obj_to_char( newobj, to_mob );
	if ( pReset->command == 'E' )
	    equip_char( to_mob, newobj, pReset->arg3 );

	sprintf( output, "%s (%d) has been loaded "
	    "%s of %s (%d) and added to resets.\n\r",
	    capitalize( pObjIndex->short_descr ),
	    pObjIndex->vnum,
	    flag_string( wear_loc_strings, pReset->arg3 ),
	    to_mob->short_descr,
	    to_mob->pIndexData->vnum );
	send_to_char( output, ch );
    }
    else	/* Display Syntax */
    {
	send_to_char( "REdit:  That mobile isn't here.\n\r", ch );
	return FALSE;
    }

    act( "$n has created $p!", ch, newobj, NULL, TO_ROOM );
    return TRUE;
}



/*
 * Object Editor Functions.
 */
void show_obj_values( CHAR_DATA *ch, OBJ_INDEX_DATA *obj )
{
    switch( obj->item_type )
    {
	default:	/* No values. */
	    break;
            
	case ITEM_LIGHT:
            if ( obj->value[2] == -1 || obj->value[2] == 999 ) /* ROM OLC */
		sprintf( buf, "[v2] Light:  Infinite[-1]\n\r" );
            else
		sprintf( buf, "[v2] Light:  [%d]\n\r", obj->value[2] );
	    send_to_char( buf, ch );
	    break;

	case ITEM_WAND:
	case ITEM_STAFF:
            sprintf( buf,
		"[v0] Level:          [%d]\n\r"
		"[v1] Charges Total:  [%d]\n\r"
		"[v2] Charges Left:   [%d]\n\r"
		"[v3] Spell:          %s\n\r",
		obj->value[0],
		obj->value[1],
		obj->value[2],
		obj->value[3] != -1 ? skill_table[obj->value[3]].name
		                    : "none" );
	    send_to_char( buf, ch );
	    break;

	case ITEM_SCROLL:
	case ITEM_POTION:
	case ITEM_PILL:
            sprintf( buf,
		"[v0] Level:  [%d]\n\r"
		"[v1] Spell:  %s\n\r"
		"[v2] Spell:  %s\n\r"
		"[v3] Spell:  %s\n\r",
		obj->value[0],
		obj->value[1] != -1 ? skill_table[obj->value[1]].name
		                    : "none",
		obj->value[2] != -1 ? skill_table[obj->value[2]].name
                                    : "none",
		obj->value[3] != -1 ? skill_table[obj->value[3]].name
		                    : "none" );
	    send_to_char( buf, ch );
	    break;

/* ARMOR for ROM */

        case ITEM_ARMOR:
	    sprintf( buf,
		"[v0] Ac pierce       [%d]\n\r"
		"[v1] Ac bash         [%d]\n\r"
		"[v2] Ac slash        [%d]\n\r"
		"[v3] Ac exotic       [%d]\n\r",
		obj->value[0],
		obj->value[1],
		obj->value[2],
		obj->value[3] );
	    send_to_char( buf, ch );
	    break;

/* WEAPON changed in ROM: */
/* I had to split the output here, I have no idea why, but it helped -- Hugin */
/* It somehow fixed a bug in showing scroll/pill/potions too ?! */
	case ITEM_WEAPON:
            sprintf( buf, "[v0] Weapon class:   %s\n\r",
		     flag_string( weapon_class, obj->value[0] ) );
	    send_to_char( buf, ch );
	    sprintf( buf, "[v1] Number of dice: [%d]\n\r", obj->value[1] );
	    send_to_char( buf, ch );
	    sprintf( buf, "[v2] Type of dice:   [%d]\n\r", obj->value[2] );
	    send_to_char( buf, ch );
	    sprintf( buf, "[v3] Type:           %s\n\r",
		    flag_string( weapon_flags, obj->value[3] ) );
	    send_to_char( buf, ch );
 	    sprintf( buf, "[v4] Special type:   %s\n\r",
		     flag_string( weapon_type,  obj->value[4] ) );
	    send_to_char( buf, ch );
	    break;

	case ITEM_CONTAINER:
	    sprintf( buf,
		"[v0] Weight: [%d kg]\n\r"
		"[v1] Flags:  [%s]\n\r"
		"[v2] Key:    %s [%d]\n\r",
		obj->value[0],
		flag_string( container_flags, obj->value[1] ),
                get_obj_index(obj->value[2])
                    ? get_obj_index(obj->value[2])->short_descr
                    : "none", obj->value[2]);
	    send_to_char( buf, ch );
	    break;

	case ITEM_DRINK_CON:
	    sprintf( buf,
	        "[v0] Liquid Total: [%d]\n\r"
	        "[v1] Liquid Left:  [%d]\n\r"
	        "[v2] Liquid:       %s\n\r"
	        "[v3] Poisoned:     %s\n\r",
	        obj->value[0],
	        obj->value[1],
	        flag_string( liquid_flags, obj->value[2] ),
	        obj->value[3] != 0 ? "Yes" : "No" );
	    send_to_char( buf, ch );
	    break;

	case ITEM_FOOD:
	    sprintf( buf,
		"[v0] Food hours: [%d]\n\r"
		"[v3] Poisoned:   %s\n\r",
		obj->value[0],
		obj->value[3] != 0 ? "Yes" : "No" );
	    send_to_char( buf, ch );
	    break;

	case ITEM_MONEY:
            sprintf( buf, "[v0] Gold:   [%d]\n\r", obj->value[0] );
	    send_to_char( buf, ch );
	    break;
    }

    return;
}



bool set_obj_values( CHAR_DATA *ch, OBJ_INDEX_DATA *pObj, int value_num, char *argument)
{
    switch( pObj->item_type )
    {
        default:
            break;
            
        case ITEM_LIGHT:
	    switch ( value_num )
	    {
	        default:
		    do_help( ch, "ITEM_LIGHT" );
	            return FALSE;
	        case 2:
	            send_to_char( "HOURS OF LIGHT SET.\n\r\n\r", ch );
	            pObj->value[2] = atoi( argument );
	            break;
	    }
            break;

        case ITEM_WAND:
        case ITEM_STAFF:
	    switch ( value_num )
	    {
	        default:
		    do_help( ch, "ITEM_STAFF_WAND" );
	            return FALSE;
	        case 0:
	            send_to_char( "SPELL LEVEL SET.\n\r\n\r", ch );
	            pObj->value[0] = atoi( argument );
	            break;
	        case 1:
	            send_to_char( "TOTAL NUMBER OF CHARGES SET.\n\r\n\r", ch );
	            pObj->value[1] = atoi( argument );
	            break;
	        case 2:
	            send_to_char( "CURRENT NUMBER OF CHARGES SET.\n\r\n\r", ch );
	            pObj->value[2] = atoi( argument );
	            break;
	        case 3:
	            send_to_char( "SPELL TYPE SET.\n\r", ch );
	            pObj->value[3] = skill_lookup( argument );
	            break;
	    }
            break;

        case ITEM_SCROLL:
        case ITEM_POTION:
        case ITEM_PILL:
	    switch ( value_num )
	    {
	        default:
		    do_help( ch, "ITEM_SCROLL_POTION_PILL" );
	            return FALSE;
	        case 0:
	            send_to_char( "SPELL LEVEL SET.\n\r\n\r", ch );
	            pObj->value[0] = atoi( argument );
	            break;
	        case 1:
	            send_to_char( "SPELL TYPE 1 SET.\n\r\n\r", ch );
	            pObj->value[1] = skill_lookup( argument );
	            break;
	        case 2:
	            send_to_char( "SPELL TYPE 2 SET.\n\r\n\r", ch );
	            pObj->value[2] = skill_lookup( argument );
	            break;
	        case 3:
	            send_to_char( "SPELL TYPE 3 SET.\n\r\n\r", ch );
	            pObj->value[3] = skill_lookup( argument );
	            break;
 	    }
	    break;

/* ARMOR for ROM: */

        case ITEM_ARMOR:
	    switch ( value_num )
	    {
	        default:
		    do_help( ch, "ITEM_ARMOR" );
		    return FALSE;
	        case 0:
		    send_to_char( "AC PIERCE SET.\n\r\n\r", ch );
		    pObj->value[0] = atoi( argument );
		    break;
	        case 1:
		    send_to_char( "AC BASH SET.\n\r\n\r", ch );
		    pObj->value[1] = atoi( argument );
		    break;
	        case 2:
		    send_to_char( "AC SLASH SET.\n\r\n\r", ch );
		    pObj->value[2] = atoi( argument );
		    break;
	        case 3:
		    send_to_char( "AC EXOTIC SET.\n\r\n\r", ch );
		    pObj->value[3] = atoi( argument );
		    break;
	    }
	    break;

/* WEAPONS changed in ROM */

        case ITEM_WEAPON:
	    switch ( value_num )
	    {
	        default:
		    do_help( ch, "ITEM_WEAPON" );
	            return FALSE;
	        case 0:
		    send_to_char( "WEAPON CLASS SET.\n\r\n\r", ch );
		    pObj->value[0] = flag_value( weapon_class, argument );
		    break;
	        case 1:
	            send_to_char( "NUMBER OF DICE SET.\n\r\n\r", ch );
	            pObj->value[1] = atoi( argument );
	            break;
	        case 2:
	            send_to_char( "TYPE OF DICE SET.\n\r\n\r", ch );
	            pObj->value[2] = atoi( argument );
	            break;
	        case 3:
	            send_to_char( "WEAPON TYPE SET.\n\r\n\r", ch );
	            pObj->value[3] = flag_value( weapon_flags, argument );
	            break;
	        case 4:
                    send_to_char( "SPECIAL WEAPON TYPE SET.\n\r\n\r", ch );
		    pObj->value[4] = flag_value( weapon_type, argument );
		    break;
	    }
            break;

        case ITEM_CONTAINER:
	    switch ( value_num )
	    {
		int value;
		
		default:
		    do_help( ch, "ITEM_CONTAINER" );
	            return FALSE;
		case 0:
	            send_to_char( "WEIGHT CAPACITY SET.\n\r\n\r", ch );
	            pObj->value[0] = atoi( argument );
	            break;
		case 1:
	            if ( ( value = flag_value( container_flags, argument ) )
	              != NO_FLAG )
	        	TOGGLE_BIT(pObj->value[1], value);
		    else
		    {
			do_help ( ch, "ITEM_CONTAINER" );
			return FALSE;
		    }
	            send_to_char( "CONTAINER TYPE SET.\n\r\n\r", ch );
	            break;
		case 2:
		    if ( atoi(argument) != 0 )
		    {
			if ( !get_obj_index( atoi( argument ) ) )
			{
			    send_to_char( "THERE IS NO SUCH ITEM.\n\r\n\r", ch );
			    return FALSE;
			}

			if ( get_obj_index( atoi( argument ) )->item_type != ITEM_KEY )
			{
			    send_to_char( "THAT ITEM IS NOT A KEY.\n\r\n\r", ch );
			    return FALSE;
			}
		    }
		    send_to_char( "CONTAINER KEY SET.\n\r\n\r", ch );
		    pObj->value[2] = atoi( argument );
		    break;
	    }
	    break;

	case ITEM_DRINK_CON:
	    switch ( value_num )
	    {
	        default:
		    do_help( ch, "ITEM_DRINK" );
/* OLC		    do_help( ch, "liquids" );    */
	            return FALSE;
	        case 0:
	            send_to_char( "MAXIMUM AMOUT OF LIQUID HOURS SET.\n\r\n\r", ch );
	            pObj->value[0] = atoi( argument );
	            break;
	        case 1:
	            send_to_char( "CURRENT AMOUNT OF LIQUID HOURS SET.\n\r\n\r", ch );
	            pObj->value[1] = atoi( argument );
	            break;
	        case 2:
	            send_to_char( "LIQUID TYPE SET.\n\r\n\r", ch );
	            pObj->value[2] = flag_value( liquid_flags, argument );
	            break;
	        case 3:
	            send_to_char( "POISON VALUE TOGGLED.\n\r\n\r", ch );
	            pObj->value[3] = ( pObj->value[3] == 0 ) ? 1 : 0;
	            break;
	    }
            break;

	case ITEM_FOOD:
	    switch ( value_num )
	    {
	        default:
		    do_help( ch, "ITEM_FOOD" );
	            return FALSE;
	        case 0:
	            send_to_char( "HOURS OF FOOD SET.\n\r\n\r", ch );
	            pObj->value[0] = atoi( argument );
	            break;
	        case 3:
	            send_to_char( "POISON VALUE TOGGLED.\n\r\n\r", ch );
	            pObj->value[3] = ( pObj->value[3] == 0 ) ? 1 : 0;
	            break;
	    }
            break;

	case ITEM_MONEY:
	    switch ( value_num )
	    {
	        default:
		    do_help( ch, "ITEM_MONEY" );
	            return FALSE;
	        case 0:
	            send_to_char( "GOLD AMOUNT SET.\n\r\n\r", ch );
	            pObj->value[0] = atoi( argument );
	            break;
	    }
            break;
    }

    show_obj_values( ch, pObj );

    return TRUE;
}



OEDIT( oedit_show )
{
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *paf;
    int cnt;

    EDIT_OBJ(ch, pObj);

    sprintf( buf, "Name:        [%s]\n\rArea:        [%5d] %s\n\r",
	pObj->name,
	!pObj->area ? -1        : pObj->area->vnum,
	!pObj->area ? "No Area" : pObj->area->name );
    send_to_char( buf, ch );


    sprintf( buf, "Vnum:        [%5d]\n\rType:        [%s]\n\r",
	pObj->vnum,
	flag_string( type_flags, pObj->item_type ) );
    send_to_char( buf, ch );

    sprintf( buf, "Level:       [%5d]\n\r", pObj->level );
    send_to_char( buf, ch );

    sprintf( buf, "Wear flags:  [%s]\n\r",
	flag_string( wear_flags, pObj->wear_flags ) );
    send_to_char( buf, ch );

    sprintf( buf, "Extra flags: [%s]\n\r",
	flag_string( extra_flags, pObj->extra_flags ) );
    send_to_char( buf, ch );

    sprintf( buf, "Material:    [%s]\n\r",                /* ROM */
	flag_string( material_type, pObj->material ) );
    send_to_char( buf, ch );

    sprintf( buf, "Condition:   [%5d]\n\r",               /* ROM */
	pObj->condition );
    send_to_char( buf, ch );

    sprintf( buf, "Weight:      [%5d]\n\rCost:        [%5d]\n\r",
	pObj->weight, pObj->cost );
    send_to_char( buf, ch );

    if ( pObj->extra_descr )
    {
	EXTRA_DESCR_DATA *ed;

	send_to_char( "Ex desc kwd: ", ch );

	for ( ed = pObj->extra_descr; ed; ed = ed->next )
	{
	    send_to_char( "[", ch );
	    send_to_char( ed->keyword, ch );
	    send_to_char( "]", ch );
	}

	send_to_char( "\n\r", ch );
    }

    sprintf( buf, "Short desc:  %s\n\rLong desc:\n\r     %s\n\r",
	pObj->short_descr, pObj->description );
    send_to_char( buf, ch );

    for ( cnt = 0, paf = pObj->affected; paf; paf = paf->next )
    {
	if ( cnt == 0 )
	{
	    send_to_char( "Number Modifier Affects\n\r", ch );
	    send_to_char( "------ -------- -------\n\r", ch );
	}
	sprintf( buf, "[%4d] %-8d %s\n\r", cnt,
	    paf->modifier,
	    flag_string( apply_flags, paf->location ) );
	send_to_char( buf, ch );
	cnt++;
    }

    show_obj_values( ch, pObj );
/* Only IMPs can see an object's clan.
   This is because only IMPs can know the tre number of a clan.
 */
if( get_trust(ch) >= MAX_LEVEL && pObj->clan != 0)
printf_to_char(ch, "Clan: %d\n\r", pObj->clan);

    return FALSE;
}


/*
 * Need to issue warning if flag isn't valid. -- does so now -- Hugin.
 */
OEDIT( oedit_addaffect )
{
    int value;
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *pAf;
    char loc[MAX_STRING_LENGTH];
    char mod[MAX_STRING_LENGTH];

    EDIT_OBJ(ch, pObj);

    argument = one_argument( argument, loc );
    one_argument( argument, mod );

    if ( loc[0] == '\0' || mod[0] == '\0' || !is_number( mod ) )
    {
	send_to_char( "Syntax:  addaffect [location] [#mod]\n\r", ch );
	return FALSE;
    }

    if ( ( value = flag_value( apply_flags, loc ) ) == NO_FLAG ) /* Hugin */
    {
        send_to_char( "Valid affects are:\n\r", ch );
	show_help( ch, "? affect" );
	return FALSE;
    }

    pAf             =   new_affect();
    pAf->location   =   value;
    pAf->modifier   =   atoi( mod );
    pAf->type       =   -1;
    pAf->duration   =   -1;
    pAf->bitvector  =   0;
    pAf->next       =   pObj->affected;
    pObj->affected  =   pAf;

    send_to_char( "Affect added.\n\r", ch);
    return TRUE;
}



/*
 * My thanks to Hans Hvidsten Birkeland and Noam Krendel(Walker)
 * for really teaching me how to manipulate pointers.
 */
OEDIT( oedit_delaffect )
{
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *pAf;
    AFFECT_DATA *pAf_next;
    char affect[MAX_STRING_LENGTH];
    int  value;
    int  cnt = 0;

    EDIT_OBJ(ch, pObj);

    one_argument( argument, affect );

    if ( !is_number( affect ) || affect[0] == '\0' )
    {
	send_to_char( "Syntax:  delaffect [#affect]\n\r", ch );
	return FALSE;
    }

    value = atoi( affect );

    if ( value < 0 )
    {
	send_to_char( "Only non-negative affect-numbers allowed.\n\r", ch );
	return FALSE;
    }

    if ( !( pAf = pObj->affected ) )
    {
	send_to_char( "OEdit:  Non-existant affect.\n\r", ch );
	return FALSE;
    }

    if( value == 0 )	/* First case: Remove first affect */
    {
	pAf = pObj->affected;
	pObj->affected = pAf->next;
	free_affect( pAf );
    }
    else		/* Affect to remove is not the first */
    {
	while ( ( pAf_next = pAf->next ) && ( ++cnt < value ) )
	     pAf = pAf_next;

	if( pAf_next )		/* See if it's the next affect */
	{
	    pAf->next = pAf_next->next;
	    free_affect( pAf_next );
	}
	else                                 /* Doesn't exist */
	{
	     send_to_char( "No such affect.\n\r", ch );
	     return FALSE;
	}
    }

    send_to_char( "Affect removed.\n\r", ch);
    return TRUE;
}



OEDIT( oedit_name )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    if ( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  name [string]\n\r", ch );
	return FALSE;
    }

    free_string( pObj->name );
    pObj->name = str_dup( argument );

    send_to_char( "Name set.\n\r", ch);
    return TRUE;
}



OEDIT( oedit_short )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    if ( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  short [string]\n\r", ch );
	return FALSE;
    }

    free_string( pObj->short_descr );
    pObj->short_descr = str_dup( argument );
    pObj->short_descr[0] = LOWER( pObj->short_descr[0] );

    send_to_char( "Short description set.\n\r", ch);
    return TRUE;
}



OEDIT( oedit_long )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    if ( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  long [string]\n\r", ch );
	return FALSE;
    }
        
    free_string( pObj->description );
    pObj->description = str_dup( argument );
    pObj->description[0] = UPPER( pObj->description[0] );

    send_to_char( "Long description set.\n\r", ch);
    return TRUE;
}



bool set_value( CHAR_DATA *ch, OBJ_INDEX_DATA *pObj, char *argument, int value )
{
    if ( argument[0] == '\0' )
    {
	set_obj_values( ch, pObj, -1, "" );     /* '\0' changed to "" -- Hugin */
	return FALSE;
    }

    if ( set_obj_values( ch, pObj, value, argument ) )
	return TRUE;

    return FALSE;
}



/*****************************************************************************
 Name:		oedit_values
 Purpose:	Finds the object and sets its value.
 Called by:	The four valueX functions below. (now five -- Hugin )
 ****************************************************************************/
bool oedit_values( CHAR_DATA *ch, char *argument, int value )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    if ( set_value( ch, pObj, argument, value ) )
        return TRUE;

    return FALSE;
}


OEDIT( oedit_value0 )
{
    if ( oedit_values( ch, argument, 0 ) )
        return TRUE;

    return FALSE;
}



OEDIT( oedit_value1 )
{
    if ( oedit_values( ch, argument, 1 ) )
        return TRUE;

    return FALSE;
}



OEDIT( oedit_value2 )
{
    if ( oedit_values( ch, argument, 2 ) )
        return TRUE;

    return FALSE;
}



OEDIT( oedit_value3 )
{
    if ( oedit_values( ch, argument, 3 ) )
        return TRUE;

    return FALSE;
}



OEDIT( oedit_value4 )
{
    if ( oedit_values( ch, argument, 4 ) )
        return TRUE;

    return FALSE;
}

OEDIT( oedit_clan )
{
    OBJ_INDEX_DATA *pObj;
    int clan;

    EDIT_OBJ(ch, pObj);

/* We can't have low level gods knowing the actual numbers of the clans */
    if( get_trust(ch) < MAX_LEVEL )
    {
	interpret(ch, "oclan");/* this _should_ produce an error message */
	return FALSE;
    }

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  oclan [number]\n\r", ch );
	return FALSE;
    }

    clan = atoi( argument );
    if( clan > MAX_CLAN || clan < 0 )
    {
	send_to_char( "Syntax:  oclan [number]\n\r", ch );
	return FALSE;
    }
		
    pObj->clan=clan;

    send_to_char( "Clan set.\n\r", ch);
    return TRUE;
}


OEDIT( oedit_weight )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  weight [number]\n\r", ch );
	return FALSE;
    }

    pObj->weight = atoi( argument );

    send_to_char( "Weight set.\n\r", ch);
    return TRUE;
}



OEDIT( oedit_cost )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  cost [number]\n\r", ch );
	return FALSE;
    }

    pObj->cost = atoi( argument );

    send_to_char( "Cost set.\n\r", ch);
    return TRUE;
}



OEDIT( oedit_create )
{
    OBJ_INDEX_DATA *pObj;
    AREA_DATA *pArea;
    int  value;
    int  iHash;

    value = atoi( argument );
    if ( argument[0] == '\0' || value == 0 )
    {
	send_to_char( "Syntax:  oedit create [vnum]\n\r", ch );
	return FALSE;
    }

    pArea = get_vnum_area( value );
    if ( !pArea )
    {
	send_to_char( "OEdit:  That vnum is not assigned an area.\n\r", ch );
	return FALSE;
    }

    if ( !IS_BUILDER( ch, pArea ) )
    {
	send_to_char( "OEdit:  Vnum in an area you cannot build in.\n\r", ch );
	return FALSE;
    }

    if ( get_obj_index( value ) )
    {
	send_to_char( "OEdit:  Object vnum already exists.\n\r", ch );
	return FALSE;
    }
        
    pObj			= new_obj_index();
    pObj->vnum			= value;
    pObj->area			= pArea;
        
    if ( value > top_vnum_obj )
	top_vnum_obj = value;

    iHash			= value % MAX_KEY_HASH;
    pObj->next			= obj_index_hash[iHash];
    obj_index_hash[iHash]	= pObj;
    ch->desc->pEdit		= (void *)pObj;

    send_to_char( "Object Created.\n\r", ch );
    return TRUE;
}



OEDIT( oedit_ed )
{
    OBJ_INDEX_DATA *pObj;
    EXTRA_DESCR_DATA *ed;
    char command[MAX_INPUT_LENGTH];
    char keyword[MAX_INPUT_LENGTH];

    EDIT_OBJ(ch, pObj);

    argument = one_argument( argument, command );
    one_argument( argument, keyword );

    if ( command[0] == '\0' )
    {
	send_to_char( "Syntax:  ed add [keyword]\n\r", ch );
	send_to_char( "         ed delete [keyword]\n\r", ch );
	send_to_char( "         ed edit [keyword]\n\r", ch );
	send_to_char( "         ed format [keyword]\n\r", ch );
	return FALSE;
    }

    if ( !str_cmp( command, "add" ) )
    {
	if ( keyword[0] == '\0' )
	{
	    send_to_char( "Syntax:  ed add [keyword]\n\r", ch );
	    return FALSE;
	}

	ed                  =   new_extra_descr();
	ed->keyword         =   str_dup( keyword );
	ed->next            =   pObj->extra_descr;
	pObj->extra_descr   =   ed;

	string_append( ch, &ed->description );

	return TRUE;
    }

    if ( !str_cmp( command, "edit" ) )
    {
	if ( keyword[0] == '\0' )
	{
	    send_to_char( "Syntax:  ed edit [keyword]\n\r", ch );
	    return FALSE;
	}

	for ( ed = pObj->extra_descr; ed; ed = ed->next )
	{
	    if ( is_name( keyword, ed->keyword ) )
		break;
	}

	if ( !ed )
	{
	    send_to_char( "OEdit:  Extra description keyword not found.\n\r", ch );
	    return FALSE;
	}

	string_append( ch, &ed->description );

	return TRUE;
    }

    if ( !str_cmp( command, "delete" ) )
    {
	EXTRA_DESCR_DATA *ped = NULL;

	if ( keyword[0] == '\0' )
	{
	    send_to_char( "Syntax:  ed delete [keyword]\n\r", ch );
	    return FALSE;
	}

	for ( ed = pObj->extra_descr; ed; ed = ed->next )
	{
	    if ( is_name( keyword, ed->keyword ) )
		break;
	    ped = ed;
	}

	if ( !ed )
	{
	    send_to_char( "OEdit:  Extra description keyword not found.\n\r", ch );
	    return FALSE;
	}

	if ( !ped )
	    pObj->extra_descr = ed->next;
	else
	    ped->next = ed->next;

	free_extra_descr( ed );

	send_to_char( "Extra description deleted.\n\r", ch );
	return TRUE;
    }


    if ( !str_cmp( command, "format" ) )
    {
	EXTRA_DESCR_DATA *ped = NULL;

	if ( keyword[0] == '\0' )
	{
	    send_to_char( "Syntax:  ed format [keyword]\n\r", ch );
	    return FALSE;
	}

	for ( ed = pObj->extra_descr; ed; ed = ed->next )
	{
	    if ( is_name( keyword, ed->keyword ) )
		break;
	    ped = ed;
	}

	if ( !ed )
	{
                send_to_char( "OEdit:  Extra description keyword not found.\n\r", ch );
                return FALSE;
	}

	ed->description = format_string( ed->description );

	send_to_char( "Extra description formatted.\n\r", ch );
	return TRUE;
    }

    oedit_ed( ch, "" );
    return FALSE;
}





/* ROM object functions : */

OEDIT( oedit_extra )      /* Moved out of oedit() due to naming conflicts -- Hugin */
{
    OBJ_INDEX_DATA *pObj;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_OBJ(ch, pObj);

	if ( ( value = flag_value( extra_flags, argument ) ) != NO_FLAG )
	{
	    TOGGLE_BIT(pObj->extra_flags, value);

	    send_to_char( "Extra flag toggled.\n\r", ch);
	    return TRUE;
	}
    }

    send_to_char( "Syntax:  extra [flag]\n\r"
		  "Type '? extra' for a list of flags.\n\r", ch );
    return FALSE;
}


OEDIT( oedit_wear )      /* Moved out of oedit() due to naming conflicts -- Hugin */
{
    OBJ_INDEX_DATA *pObj;
    int value;

     if ( argument[0] != '\0' )
    {
	EDIT_OBJ(ch, pObj);

	if ( ( value = flag_value( wear_flags, argument ) ) != NO_FLAG )
	{
	    TOGGLE_BIT(pObj->wear_flags, value);

	    send_to_char( "Wear flag toggled.\n\r", ch);
	    return TRUE;
	}
    }

    send_to_char( "Syntax:  wear [flag]\n\r"
		  "Type '? wear' for a list of flags.\n\r", ch );
    return FALSE;
}


OEDIT( oedit_type )      /* Moved out of oedit() due to naming conflicts -- Hugin */
{
    OBJ_INDEX_DATA *pObj;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_OBJ(ch, pObj);

	if ( ( value = flag_value( type_flags, argument ) ) != NO_FLAG )
	{
	    pObj->item_type = value;

	    send_to_char( "Type set.\n\r", ch);

	    /*
	     * Clear the values.
	     */
	    pObj->value[0] = 0;
	    pObj->value[1] = 0;
	    pObj->value[2] = 0;
	    pObj->value[3] = 0;
	    pObj->value[4] = 0;     /* ROM */

	    return TRUE;
	}
    }

    send_to_char( "Syntax:  type [flag]\n\r"
		  "Type '? type' for a list of flags.\n\r", ch );
    return FALSE;
}



OEDIT( oedit_material )
{
    OBJ_INDEX_DATA *pObj;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_OBJ(ch, pObj);

	if ( ( value = flag_value( material_type, argument ) ) != NO_FLAG )
	{
	    pObj->material = value;
	    send_to_char( "Material type set.\n\r", ch);
	    return TRUE;
	}
    }

    send_to_char( "Syntax:  material [material-name]\n\r"
		  "Type '? material' for a list of materials.\n\r", ch );
    return FALSE;
}



OEDIT( oedit_level )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  level [number]\n\r", ch );
	return FALSE;
    }

    pObj->level = atoi( argument );

    send_to_char( "Level set.\n\r", ch);
    return TRUE;
}



OEDIT( oedit_condition )
{
    OBJ_INDEX_DATA *pObj;
    int value;

    if ( argument[0] != '\0'
    && ( value = atoi (argument ) ) >= 0
    && ( value <= 100 ) )
    {
	EDIT_OBJ( ch, pObj );

	pObj->condition = value;
	send_to_char( "Condition set.\n\r", ch );

	return TRUE;
    }

    send_to_char( "Syntax:  condition [number]\n\r"
		  "Where number can range from 0 (ruined) to 100 (perfect).\n\r",
		  ch );
    return FALSE;
}





/*
 * Mobile Editor Functions.
 */
MEDIT( medit_show )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

    sprintf( buf, "Name:        [%s]\n\rArea:        [%5d] %s\n\r",
	pMob->player_name,
	!pMob->area ? -1        : pMob->area->vnum,
	!pMob->area ? "No Area" : pMob->area->name );
    send_to_char( buf, ch );

    sprintf( buf, "Act:         [%s]\n\r",
	flag_string( act_flags, pMob->act ) );
    send_to_char( buf, ch );

    sprintf( buf, "Vnum:        [%5d]\n\rSex:         [%s]\n\r",
	pMob->vnum,
	pMob->sex == SEX_MALE    ? "male"   :
	pMob->sex == SEX_FEMALE  ? "female" : 
	pMob->sex == 3           ? "random" : "neutral" );  /* ROM magic number */
    send_to_char( buf, ch );

    sprintf( buf, "Race:        [%s]\n\r",                   /* ROM OLC */
	race_table[pMob->race].name );
    send_to_char( buf, ch );

    sprintf( buf,
	"Level:       [%2d]\n\rAlign:       [%4d]\n\r",
	pMob->level,       pMob->alignment );
    send_to_char( buf, ch );

/* ROM values: */

    sprintf( buf, "Hitroll:     [%d]\n\r",
             pMob->hitroll );
    send_to_char( buf, ch );

    sprintf( buf, "Hit dice:    [%2dd%-3d+%4d]\n\r",
	     pMob->hit[DICE_NUMBER],
	     pMob->hit[DICE_TYPE],
	     pMob->hit[DICE_BONUS] );
    send_to_char( buf, ch );

    sprintf( buf, "Damage dice: [%2dd%-3d+%4d]\n\r",
	     pMob->damage[DICE_NUMBER],
	     pMob->damage[DICE_TYPE],
	     pMob->damage[DICE_BONUS] );
    send_to_char( buf, ch );

    sprintf( buf, "Mana dice:   [%2dd%-3d+%4d]\n\r",
	     pMob->mana[DICE_NUMBER],
	     pMob->mana[DICE_TYPE],
	     pMob->mana[DICE_BONUS] );
    send_to_char( buf, ch );
    
    sprintf( buf, "Damage Type: [%s]\n\r",
    	     attack_table[pMob->dam_type].name);
    send_to_char( buf, ch );

/* ROM values end */

    sprintf( buf, "Affected by: [%s]\n\r",
	flag_string( affect_flags, pMob->affected_by ) );
    send_to_char( buf, ch );

/* ROM values: */

    sprintf( buf, "Armor:       [pierce: %d  bash: %d  slash: %d  magic: %d]\n\r",
	pMob->ac[AC_PIERCE], pMob->ac[AC_BASH],
	pMob->ac[AC_SLASH], pMob->ac[AC_EXOTIC] );
    send_to_char( buf, ch );

    sprintf( buf, "Form:        [%s]\n\r",
	flag_string( form_flags, pMob->form ) );
    send_to_char( buf, ch );

    sprintf( buf, "Parts:       [%s]\n\r",
	flag_string( part_flags, pMob->parts ) );
    send_to_char( buf, ch );

    sprintf( buf, "Imm:         [%s]\n\r",
	flag_string( imm_flags, pMob->imm_flags ) );
    send_to_char( buf, ch );

    sprintf( buf, "Res:         [%s]\n\r",
	flag_string( res_flags, pMob->res_flags ) );
    send_to_char( buf, ch );

    sprintf( buf, "Vuln:        [%s]\n\r",
	flag_string( vuln_flags, pMob->vuln_flags ) );
    send_to_char( buf, ch );

    sprintf( buf, "Off:         [%s]\n\r",
	flag_string( off_flags,  pMob->off_flags ) );
    send_to_char( buf, ch );

    sprintf( buf, "Size:        [%s]\n\r",
	flag_string( size_flags, pMob->size ) );
    send_to_char( buf, ch );

    sprintf( buf, "Start pos.   [%s]\n\r",
	flag_string( position_flags, pMob->start_pos ) );
    send_to_char( buf, ch );

    sprintf( buf, "Default pos  [%s]\n\r",
	flag_string( position_flags, pMob->default_pos ) );
    send_to_char( buf, ch );

    sprintf( buf, "Gold:        [%5ld]\n\r",
	pMob->gold );
    send_to_char( buf, ch );

    sprintf( buf,"Random objects:\n\rChance:      [%4d]\n\r"
                 "Number:      [%4d]\n\r",
       pMob->rnd_obj_percent, pMob->rnd_obj_num);
    send_to_char( buf, ch );

    sprintf( buf, "Types:       [%s]\n\r",
      flag_string( rnd_obj_flags, pMob->rnd_obj_types ) );
    send_to_char( buf, ch );

/* ROM values end */

    sprintf( buf, "Short descr: %s\n\rLong descr:\n\r%s",
	pMob->short_descr,
	pMob->long_descr );
    send_to_char( buf, ch );

    sprintf( buf, "Description:\n\r%s", pMob->description );
    send_to_char( buf, ch );

    if ( pMob->pShop )
    {
	SHOP_DATA *pShop;
	int iTrade;

	pShop = pMob->pShop;

	sprintf( buf,
	  "Shop data for [%5d]:\n\r"
	  "  Markup for purchaser: %d%%\n\r"
	  "  Markdown for seller:  %d%%\n\r",
	    pShop->keeper, pShop->profit_buy, pShop->profit_sell );
	send_to_char( buf, ch );
	sprintf( buf, "  Hours: %d to %d.\n\r",
	    pShop->open_hour, pShop->close_hour );
	send_to_char( buf, ch );

	for ( iTrade = 0; iTrade < MAX_TRADE; iTrade++ )
	{
	    if ( pShop->buy_type[iTrade] != 0 )
	    {
		if ( iTrade == 0 ) {
		    send_to_char( "  Number Trades Type\n\r", ch );
		    send_to_char( "  ------ -----------\n\r", ch );
		}
		sprintf( buf, "  [%4d] %s\n\r", iTrade,
		    flag_string( type_flags, pShop->buy_type[iTrade] ) );
		send_to_char( buf, ch );
	    }
	}
    }

    return FALSE;
}



MEDIT( medit_create )
{
    MOB_INDEX_DATA *pMob;
    AREA_DATA *pArea;
    int  value;
    int  iHash;

    value = atoi( argument );
    if ( argument[0] == '\0' || value == 0 )
    {
	send_to_char( "Syntax:  medit create [vnum]\n\r", ch );
	return FALSE;
    }

    pArea = get_vnum_area( value );

    if ( !pArea )
    {
	send_to_char( "MEdit:  That vnum is not assigned an area.\n\r", ch );
	return FALSE;
    }

    if ( !IS_BUILDER( ch, pArea ) )
    {
	send_to_char( "MEdit:  Vnum in an area you cannot build in.\n\r", ch );
	return FALSE;
    }

    if ( get_mob_index( value ) )
    {
	send_to_char( "MEdit:  Mobile vnum already exists.\n\r", ch );
	return FALSE;
    }

    pMob			= new_mob_index();
    pMob->vnum			= value;
    pMob->area			= pArea;
        
    if ( value > top_vnum_mob )
	top_vnum_mob = value;        

    pMob->act			= ACT_IS_NPC;
    iHash			= value % MAX_KEY_HASH;
    pMob->next			= mob_index_hash[iHash];
    mob_index_hash[iHash]	= pMob;
    ch->desc->pEdit		= (void *)pMob;

    send_to_char( "Mobile Created.\n\r", ch );
    return TRUE;
}



MEDIT( medit_align )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  alignment [number]\n\r", ch );
	return FALSE;
    }

    pMob->alignment = atoi( argument );

    send_to_char( "Alignment set.\n\r", ch);
    return TRUE;
}



MEDIT( medit_level )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  level [number]\n\r", ch );
	return FALSE;
    }

    pMob->level = atoi( argument );

    send_to_char( "Level set.\n\r", ch);
    return TRUE;
}



MEDIT( medit_desc )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

    if ( argument[0] == '\0' )
    {
	string_append( ch, &pMob->description );
	return TRUE;
    }

    send_to_char( "Syntax:  desc    - line edit\n\r", ch );
    return FALSE;
}




MEDIT( medit_long )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

    if ( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  long [string]\n\r", ch );
	return FALSE;
    }

    free_string( pMob->long_descr );
    strcat( argument, "\n\r" );
    pMob->long_descr = str_dup( argument );
    pMob->long_descr[0] = UPPER( pMob->long_descr[0]  );

    send_to_char( "Long description set.\n\r", ch);
    return TRUE;
}



MEDIT( medit_short )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

    if ( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  short [string]\n\r", ch );
	return FALSE;
    }

    free_string( pMob->short_descr );
    pMob->short_descr = str_dup( argument );

    send_to_char( "Short description set.\n\r", ch);
    return TRUE;
}



MEDIT( medit_name )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

    if ( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  name [string]\n\r", ch );
	return FALSE;
    }

    free_string( pMob->player_name );
    pMob->player_name = str_dup( argument );

    send_to_char( "Name set.\n\r", ch);
    return TRUE;
}




MEDIT( medit_shop )
{
    MOB_INDEX_DATA *pMob;
    char command[MAX_INPUT_LENGTH];

    argument = one_argument( argument, command );
    argument = one_argument( argument, arg );

    EDIT_MOB(ch, pMob);

    if ( command[0] == '\0' )
    {
	send_to_char( "Syntax:  shop hours [#opening] [#closing]\n\r", ch );
	send_to_char( "         shop profit [#buying%] [#selling%]\n\r", ch );
	send_to_char( "         shop type [#0-4] [item type]\n\r", ch );
	send_to_char( "         shop delete [#0-4]\n\r", ch );
	return FALSE;
    }


    if ( !str_cmp( command, "hours" ) )
    {
	if ( arg[0] == '\0' || !is_number( arg )
	|| argument[0] == '\0' || !is_number( argument ) )
	{
	    send_to_char( "Syntax:  shop hours [#opening] [#closing]\n\r", ch );
	    return FALSE;
	}

	if ( !pMob->pShop )
	{
	    pMob->pShop         = new_shop();
	    pMob->pShop->keeper = pMob->vnum;
	    shop_last->next     = pMob->pShop;
	}

	pMob->pShop->open_hour = atoi( arg );
	pMob->pShop->close_hour = atoi( argument );

	send_to_char( "Shop hours set.\n\r", ch);
	return TRUE;
    }


    if ( !str_cmp( command, "profit" ) )
    {
	if ( arg[0] == '\0' || !is_number( arg )
	|| argument[0] == '\0' || !is_number( argument ) )
	{
	    send_to_char( "Syntax:  shop profit [#buying%] [#selling%]\n\r", ch );
	    return FALSE;
	}

	if ( !pMob->pShop )
	{
	    pMob->pShop         = new_shop();
	    pMob->pShop->keeper = pMob->vnum;
	    shop_last->next     = pMob->pShop;
	}

	pMob->pShop->profit_buy     = atoi( arg );
	pMob->pShop->profit_sell    = atoi( argument );

	send_to_char( "Shop profit set.\n\r", ch);
	return TRUE;
    }


    if ( !str_cmp( command, "type" ) )
    {
	int value;

	if ( arg[0] == '\0' || !is_number( arg )
	|| argument[0] == '\0' )
	{
	    send_to_char( "Syntax:  shop type [#0-4] [item type]\n\r", ch );
	    return FALSE;
	}

	if ( atoi( arg ) >= MAX_TRADE )
	{
	    sprintf( buf, "REdit:  May sell %d items max.\n\r", MAX_TRADE );
	    send_to_char( buf, ch );
	    return FALSE;
	}

	if ( ( value = flag_value( type_flags, argument ) ) == NO_FLAG )
	{
	    send_to_char( "REdit:  That type of item is not known.\n\r", ch );
	    return FALSE;
	}

	if ( !pMob->pShop )
	{
	    pMob->pShop         = new_shop();
	    pMob->pShop->keeper = pMob->vnum;
	    shop_last->next     = pMob->pShop;
	}

	pMob->pShop->buy_type[atoi( arg )] = value;

	send_to_char( "Shop type set.\n\r", ch);
	return TRUE;
    }


    if ( !str_cmp( command, "delete" ) )
    {
	SHOP_DATA *pShop;
	SHOP_DATA *pShop_next;
	int value;
	int cnt = 0;
	
	if ( arg[0] == '\0' || !is_number( arg ) )
	{
	    send_to_char( "Syntax:  shop delete [#0-4]\n\r", ch );
	    return FALSE;
	}

	value = atoi( argument );
	
	if ( !pMob->pShop )
	{
	    send_to_char( "REdit:  Non-existant shop.\n\r", ch );
	    return FALSE;
	}

	if ( value == 0 )
	{
	    pShop = pMob->pShop;
	    pMob->pShop = pMob->pShop->next;
	    free_shop( pShop );
	}
	else
	for ( pShop = pMob->pShop, cnt = 0; pShop; pShop = pShop_next, cnt++ )
	{
	    pShop_next = pShop->next;
	    if ( cnt+1 == value )
	    {
		pShop->next = pShop_next->next;
		free_shop( pShop_next );
		break;
	    }
	}

	send_to_char( "Shop deleted.\n\r", ch);
	return TRUE;
    }

    medit_shop( ch, "" );
    return FALSE;
}


/* ROM medit functions: */


MEDIT( medit_sex )          /* Moved out of medit() due to naming conflicts -- Hugin */
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( sex_flags, argument ) ) != NO_FLAG )
	{
	    pMob->sex = value;

	    send_to_char( "Sex set.\n\r", ch);
	    return TRUE;
	}
    }

    send_to_char( "Syntax: sex [sex]\n\r"
		  "Type '? sex' for a list of flags.\n\r", ch );
    return FALSE;
}


MEDIT( medit_act )          /* Moved out of medit() due to naming conflicts -- Hugin */
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( act_flags, argument ) ) != NO_FLAG )
	{
	    pMob->act ^= value;
	    SET_BIT( pMob->act, ACT_IS_NPC );

	    send_to_char( "Act flag toggled.\n\r", ch);
	    return TRUE;
	}
    }

    send_to_char( "Syntax: act [flag]\n\r"
		  "Type '? act' for a list of flags.\n\r", ch );
    return FALSE;
}


MEDIT( medit_affect )      /* Moved out of medit() due to naming conflicts -- Hugin */
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( affect_flags, argument ) ) != NO_FLAG )
	{
	    pMob->affected_by ^= value;

	    send_to_char( "Affect flag toggled.\n\r", ch);
	    return TRUE;
	}
    }

    send_to_char( "Syntax: affect [flag]\n\r"
		  "Type '? affect' for a list of flags.\n\r", ch );
    return FALSE;
}



MEDIT( medit_ac )
{
   MOB_INDEX_DATA *pMob;
   int pierce, bash, slash, exotic;

   do   /* So that I can use break and send the syntax in one place */
   {
	   if ( argument[0] == '\0' )  break;

      EDIT_MOB(ch, pMob);
      argument = one_argument( argument, arg );

      if ( !is_number( arg ) )  break;
      pierce = atoi( arg );
      argument = one_argument( argument, arg );

      if ( arg[0] != '\0' )
      {
         if ( !is_number( arg ) )  break;
         bash = atoi( arg );
         argument = one_argument( argument, arg );
      }
      else
         bash = pMob->ac[AC_BASH];

      if ( arg[0] != '\0' )
      {
         if ( !is_number( arg ) )  break;
         slash = atoi( arg );
         argument = one_argument( argument, arg );
      }
      else
         slash = pMob->ac[AC_SLASH];

      if ( arg[0] != '\0' )
      {
         if ( !is_number( arg ) )  break;
         exotic = atoi( arg );
      }
      else
         exotic = pMob->ac[AC_EXOTIC];

      pMob->ac[AC_PIERCE] = pierce;
      pMob->ac[AC_BASH]   = bash;
      pMob->ac[AC_SLASH]  = slash;
      pMob->ac[AC_EXOTIC] = exotic;

      send_to_char( "Ac set.\n\r", ch );
      return TRUE;
   }
   while ( FALSE );    /* Just do it once.. */

   send_to_char( "Syntax:  ac [ac-pierce [ac-bash [ac-slash [ac-exotic]]]]\n\r"
                 "help MOB_AC  gives a list of reasonable ac-values.\n\r", ch );
   return FALSE;
}

MEDIT( medit_form )
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( form_flags, argument ) ) != NO_FLAG )
	{
	    pMob->form ^= value;
	    send_to_char( "Form toggled.\n\r", ch );
	    return TRUE;
	}
    }

    send_to_char( "Syntax: form [flags]\n\r"
		  "Type '? form' for a list of flags.\n\r", ch );
    return FALSE;
}

MEDIT( medit_part )
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( part_flags, argument ) ) != NO_FLAG )
	{
	    pMob->parts ^= value;
	    send_to_char( "Parts toggled.\n\r", ch );
	    return TRUE;
	}
    }

    send_to_char( "Syntax: part [flags]\n\r"
		  "Type '? part' for a list of flags.\n\r", ch );
    return FALSE;
}

MEDIT( medit_imm )
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( imm_flags, argument ) ) != NO_FLAG )
	{
	    pMob->imm_flags ^= value;
	    send_to_char( "Immunity toggled.\n\r", ch );
	    return TRUE;
	}
    }

    send_to_char( "Syntax: imm [flags]\n\r"
		  "Type '? imm' for a list of flags.\n\r", ch );
    return FALSE;
}

MEDIT( medit_res )
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( res_flags, argument ) ) != NO_FLAG )
	{
	    pMob->res_flags ^= value;
	    send_to_char( "Resistance toggled.\n\r", ch );
	    return TRUE;
	}
    }

    send_to_char( "Syntax: res [flags]\n\r"
		  "Type '? res' for a list of flags.\n\r", ch );
    return FALSE;
}

MEDIT( medit_vuln )
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( vuln_flags, argument ) ) != NO_FLAG )
	{
	    pMob->vuln_flags ^= value;
	    send_to_char( "Vulnerability toggled.\n\r", ch );
	    return TRUE;
	}
    }

    send_to_char( "Syntax: vuln [flags]\n\r"
		  "Type '? vuln' for a list of flags.\n\r", ch );
    return FALSE;
}

MEDIT( medit_material )
{
    MOB_INDEX_DATA *pMob;
    int value;

    EDIT_MOB(ch, pMob);

    if ( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  material [material-name]\n\r"
		      "Type '? material' for a list of materials.\n\r", ch );
	return FALSE;
    }

    if ( ( value = flag_value( material_type, argument ) ) != NO_FLAG )
    {
        pMob->material = value;
        send_to_char( "Material type set.\n\r", ch);
        return TRUE;
    }

    send_to_char( "Unknown material type, '? material' for a list.\n\r", ch );
    return FALSE;
}

MEDIT( medit_off )
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( off_flags, argument ) ) != NO_FLAG )
	{
	    pMob->off_flags ^= value;
	    send_to_char( "Offensive behaviour toggled.\n\r", ch );
	    return TRUE;
	}
    }

    send_to_char( "Syntax: off [flags]\n\r"
		  "Type '? off' for a list of flags.\n\r", ch );
    return FALSE;
}

MEDIT( medit_size )
{
    MOB_INDEX_DATA *pMob;
    int value;

    if ( argument[0] != '\0' )
    {
	EDIT_MOB( ch, pMob );

	if ( ( value = flag_value( size_flags, argument ) ) != NO_FLAG )
	{
	    pMob->size = value;
	    send_to_char( "Size set.\n\r", ch );
	    return TRUE;
	}
    }

    send_to_char( "Syntax: size [size]\n\r"
		  "Type '? size' for a list of sizes.\n\r", ch );
    return FALSE;
}

MEDIT( medit_hitdice )
{
    static char syntax[] = "Syntax:  hitdice <number> d <type> + <bonus>\n\r";
    char *num, *type, *bonus, *cp;
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

    if ( argument[0] == '\0' )
    {
	send_to_char( syntax, ch );
	return FALSE;
    }

    num = cp = argument;

    while ( isdigit( *cp ) ) ++cp;
    while ( *cp != '\0' && !isdigit( *cp ) )  *(cp++) = '\0';

    type = cp;

    while ( isdigit( *cp ) ) ++cp;
    while ( *cp != '\0' && !isdigit( *cp ) ) *(cp++) = '\0';

    bonus = cp;

    while ( isdigit( *cp ) ) ++cp;
    if ( *cp != '\0' ) *cp = '\0';

    if ( ( !is_number( num   ) || atoi( num   ) < 1 )
    ||   ( !is_number( type  ) || atoi( type  ) < 1 ) 
    ||   ( !is_number( bonus ) || atoi( bonus ) < 0 ) )
    {
	send_to_char( syntax, ch );
	return FALSE;
    }

    pMob->hit[DICE_NUMBER] = atoi( num   );
    pMob->hit[DICE_TYPE]   = atoi( type  );
    pMob->hit[DICE_BONUS]  = atoi( bonus );

    send_to_char( "Hitdice set.\n\r", ch );
    return TRUE;
}

MEDIT( medit_manadice )
{
    static char syntax[] = "Syntax:  manadice <number> d <type> + <bonus>\n\r";
    char *num, *type, *bonus, *cp;
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

    if ( argument[0] == '\0' )
    {
	send_to_char( syntax, ch );
	return FALSE;
    }

    num = cp = argument;

    while ( isdigit( *cp ) ) ++cp;
    while ( *cp != '\0' && !isdigit( *cp ) )  *(cp++) = '\0';

    type = cp;

    while ( isdigit( *cp ) ) ++cp;
    while ( *cp != '\0' && !isdigit( *cp ) ) *(cp++) = '\0';

    bonus = cp;

    while ( isdigit( *cp ) ) ++cp;
    if ( *cp != '\0' ) *cp = '\0';

    if ( !( is_number( num ) && is_number( type ) && is_number( bonus ) ) )
    {
	send_to_char( syntax, ch );
	return FALSE;
    }

    if ( ( !is_number( num   ) || atoi( num   ) < 1 )
    ||   ( !is_number( type  ) || atoi( type  ) < 1 ) 
    ||   ( !is_number( bonus ) || atoi( bonus ) < 0 ) )
    {
	send_to_char( syntax, ch );
	return FALSE;
    }

    pMob->mana[DICE_NUMBER] = atoi( num   );
    pMob->mana[DICE_TYPE]   = atoi( type  );
    pMob->mana[DICE_BONUS]  = atoi( bonus );

    send_to_char( "Manadice set.\n\r", ch );
    return TRUE;
}

MEDIT( medit_damdice )
{
    static char syntax[] = "Syntax:  damdice <number> d <type> + <bonus>\n\r";
    char *num, *type, *bonus, *cp;
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

    if ( argument[0] == '\0' )
    {
	send_to_char( syntax, ch );
	return FALSE;
    }

    num = cp = argument;

    while ( isdigit( *cp ) ) ++cp;
    while ( *cp != '\0' && !isdigit( *cp ) )  *(cp++) = '\0';

    type = cp;

    while ( isdigit( *cp ) ) ++cp;
    while ( *cp != '\0' && !isdigit( *cp ) ) *(cp++) = '\0';

    bonus = cp;

    while ( isdigit( *cp ) ) ++cp;
    if ( *cp != '\0' ) *cp = '\0';

    if ( !( is_number( num ) && is_number( type ) && is_number( bonus ) ) )
    {
	send_to_char( syntax, ch );
	return FALSE;
    }

    if ( ( !is_number( num   ) || atoi( num   ) < 1 )
    ||   ( !is_number( type  ) || atoi( type  ) < 1 ) 
    ||   ( !is_number( bonus ) || atoi( bonus ) < 0 ) )
    {
	send_to_char( syntax, ch );
	return FALSE;
    }

    pMob->damage[DICE_NUMBER] = atoi( num   );
    pMob->damage[DICE_TYPE]   = atoi( type  );
    pMob->damage[DICE_BONUS]  = atoi( bonus );

    send_to_char( "Damdice set.\n\r", ch );
    return TRUE;
}

MEDIT( medit_damtype )
{
    static char syntax[] = "Syntax:  damtype <damage type>\n\r";
    int x;
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

    if ( argument[0] == '\0' )
    {
	send_to_char( syntax, ch );
	return FALSE;
    }

    for ( x=0; x <= MAX_ATTACK_TYPE+1; x++) {
    	if (x == MAX_ATTACK_TYPE+1) {
    	    send_to_char( "Invalid damage type, do 'help DAMTYPE'.\n\r", ch);
    	    return FALSE;
    	}
    	if (!strcmp(attack_table[x].name, argument)) {
    	    send_to_char( "Damage type set.\n\r", ch);
    	    pMob->dam_type=x;
    	    return TRUE;
    	}
    }
    
    return FALSE;
}


MEDIT( medit_race )
{
    MOB_INDEX_DATA *pMob;
    int race;

    if ( argument[0] != '\0'
    && ( race = race_lookup( argument ) ) != 0 )
    {
	EDIT_MOB( ch, pMob );

	pMob->race = race;
	pMob->off_flags   |= race_table[race].off;
	pMob->imm_flags   |= race_table[race].imm;
	pMob->res_flags   |= race_table[race].res;
	pMob->vuln_flags  |= race_table[race].vuln;
	pMob->form        |= race_table[race].form;
	pMob->parts       |= race_table[race].parts;

	send_to_char( "Race set.\n\r", ch );
	return TRUE;
    }

    if ( argument[0] == '?' )
    {
	send_to_char( "Available races are:", ch );

	for ( race = 0; race_table[race].name != NULL; race++ )
	{
	    if ( ( race % 3 ) == 0 )
		send_to_char( "\n\r", ch );
	    sprintf( buf, " %-15s", race_table[race].name );
	    send_to_char( buf, ch );
	}

	send_to_char( "\n\r", ch );
	return FALSE;
    }

    send_to_char( "Syntax:  race [race]\n\r"
		  "Type 'race ?' for a list of races.\n\r", ch );
    return FALSE;
}


MEDIT( medit_position )
{
    MOB_INDEX_DATA *pMob;
    int value;

    argument = one_argument( argument, arg );

    switch ( arg[0] )
    {
    default:
	break;

    case 'S':
    case 's':
	if ( str_prefix( arg, "start" ) )
	    break;

	if ( ( value = flag_value( position_flags, argument ) ) == NO_FLAG )
	    break;

	EDIT_MOB( ch, pMob );

	pMob->start_pos = value;
	send_to_char( "Start position set.\n\r", ch );
	return TRUE;

    case 'D':
    case 'd':
	if ( str_prefix( arg, "default" ) )
	    break;

	if ( ( value = flag_value( position_flags, argument ) ) == NO_FLAG )
	    break;

	EDIT_MOB( ch, pMob );

	pMob->default_pos = value;
	send_to_char( "Default position set.\n\r", ch );
	return TRUE;
    }

    send_to_char( "Syntax:  position [start/default] [position]\n\r"
		  "Type '? position' for a list of positions.\n\r", ch );
    return FALSE;
}


MEDIT( medit_gold )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  gold [number]\n\r", ch );
	return FALSE;
    }

    pMob->gold = atoi( argument );

    send_to_char( "Gold set.\n\r", ch);
    return TRUE;
}


MEDIT( medit_hitroll )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  hitroll [number]\n\r", ch );
	return FALSE;
    }

    pMob->hitroll = atoi( argument );

    send_to_char( "Hitroll set.\n\r", ch);
    return TRUE;
}

MEDIT( medit_randpct )
{
   MOB_INDEX_DATA *pMob;
   int pctbuf=0;
   EDIT_MOB(ch, pMob);
   
   if(argument[0] == '\0' || !is_number(argument) )
     {
	send_to_char("Syntax: chance [number]\n\r", ch);
	return FALSE;
     }
   pctbuf  = atoi( argument );
   
   if(pctbuf < 0 || pctbuf > 100)
     {
	send_to_char("Number must be from 0 to 100.\n\r", ch);
	return FALSE;
     }
   
   pMob->rnd_obj_percent = pctbuf;
   send_to_char( "Random object loading percent set.\n\r", ch);
   return TRUE;
}

MEDIT( medit_randnum )
{
   MOB_INDEX_DATA *pMob;
   int randbuf;
   EDIT_MOB(ch, pMob);
   
   if ( argument[0] == '\0' || !is_number( argument ) )
     {
	send_to_char( "Syntax:  number [number]\n\r", ch );
	return FALSE;
     }
   
   randbuf = atoi( argument );
   if(randbuf < 0 || randbuf > 10)
     {
	send_to_char("Number must be from 0 to 10.\n\r", ch);
	return FALSE;
     }
   pMob->rnd_obj_num = randbuf;
   
   send_to_char( "Number of random objects possible set.\n\r", ch);
   return TRUE;
}

MEDIT( medit_randtype )
{
   MOB_INDEX_DATA *pMob;    
   int value;
   EDIT_MOB(ch, pMob);
   
   if ( argument[0] != '\0' )
     {
	if ( ( value = flag_value( rnd_obj_flags, argument ) ) != NO_FLAG )
	  {
	     pMob->rnd_obj_types ^= value;
	     send_to_char( "Type set.\n\r", ch);
	     return TRUE;
	  }
	send_to_char( "Syntax:  types [flag]\n\r"
		     "Type '? randobj' for a list of flags.\n\r", ch );
	return FALSE;
     }
   
   
   send_to_char( "Syntax:  types [flag]\n\r"
		"Type '? randobj' for a list of flags.\n\r", ch );
   return FALSE;
}

/*
 * MudProg Editor Functions.
 */

MPEDIT( mpedit_create )
{
	MPROG_DATA *pMudProg;

	if ( ch->desc->pEdit )
	{
		send_to_char("You're already editing a MudProg.\n\r", ch);
		return FALSE;
	}

	if ( *argument != '\0' && !str_prefix(argument, "mobprog") 
	  && !str_prefix(argument, "objprog") && !str_prefix(argument, "roomprog") )
	{
		send_to_char("Syntax:  edit mprog create [mobprog||objprog||roomprog]\n\r", ch);
		return FALSE;
	}

	pMudProg = new_mudprog();

	if ( !str_prefix(argument, "mobprog") )
		pMudProg->prog_type = MOB_PROG;

	if ( !str_prefix(argument, "objprog") )
		pMudProg->prog_type = OBJ_PROG;

	if ( !str_prefix(argument, "roomprog") )
		pMudProg->prog_type = ROOM_PROG;

    ch->desc->pEdit = (void *)pMudProg;

    send_to_char( "MudProg Created.\n\r", ch );
    return TRUE;
}

MPEDIT( mpedit_delete )
{
	MPROG_DATA      *pMudProg;
	MPROG_DATA      *pTempProg;
	MPROG_GROUP     *pMprogGroup;
	MPROG_LIST      *pList;
	OBJ_INDEX_DATA  *pObj;
	MOB_INDEX_DATA  *pMob;
	ROOM_INDEX_DATA *pRoom;
    char arg[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
    int vnum;
	int nMatch;

	argument = one_argument(argument, arg);

	if ( *arg != '\0' )
	{
		if ( ( vnum = atoi( arg ) ) < 1 )
		{
			send_to_char( "Syntax:  Delete [MudProg Vnum]\n\r", ch);
			return FALSE;
		}

		if ( ( pMudProg = get_mprog_by_vnum( vnum ) ) == NULL )
		{
			send_to_char( "Invalid vnum.\n\r", ch );
			return FALSE;
		}
	}
	else
		EDIT_MPROG(ch, pMudProg);

	/*
	 * This mudprog is new and hasn't been added to the list, just free it.
	 */
	if ( pMudProg->vnum == 0 )
	{
		sprintf(buf, "MudProg [%4d] %s - deleted.\n\r", pMudProg->vnum,
		  pMudProg->name);
		free_mudprog(pMudProg);
		send_to_char(buf, ch);
		edit_done(ch);
		return TRUE;
	}

	/*
	 * Check to see if this mudprog is in use or is in a group.  If either is
	 * true then don't allow the deletion.  -Zane
	 */
	switch( pMudProg->prog_type )
	{
	case MOB_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_mob_index; vnum++ )
			if ( ( pMob = get_mob_index( vnum ) ) != NULL )
			{
				if ( IS_SET( pMob->progtypes, pMudProg->trigger_type ) )
					for ( pList = pMob->mudprogs; pList; pList = pList->next )
						if ( pList->mudprog->vnum == pMudProg->vnum )
						{
							send_to_char( "This prog is in use, you cannot delete it.\n\r", ch);
							return FALSE;
						}
				nMatch++;
			}
		break;
	case ROOM_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_room; vnum++ )
			if ( ( pRoom = get_room_index( vnum ) ) != NULL )
			{
				if ( IS_SET( pRoom->progtypes, pMudProg->trigger_type ) )
					for ( pList = pRoom->mudprogs; pList; pList = pList->next )
						if ( pList->mudprog->vnum == pMudProg->vnum )
						{
							send_to_char( "This prog is in use, you cannot delete it.\n\r", ch);
							return FALSE;
						}
				nMatch++;
			}
		break;
	case OBJ_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_obj_index; vnum++ )
			if ( ( pObj = get_obj_index( vnum ) ) != NULL )
			{
				if ( IS_SET( pObj->progtypes, pMudProg->trigger_type ) )
					for ( pList = pObj->mudprogs; pList; pList = pList->next )
						if ( pList->mudprog->vnum == pMudProg->vnum )
						{
							send_to_char( "This prog is in use, you cannot delete it.\n\r", ch);
							return FALSE;
						}
				nMatch++;
			}
		break;
	}

	/* Check groups */
	for ( pMprogGroup = mprog_group_list; pMprogGroup; pMprogGroup = pMprogGroup->next )
		if ( pMprogGroup->prog_type == pMudProg->prog_type )
			for ( pList = pMprogGroup->mudprogs; pList; pList = pList->next )
				if ( pList->mudprog->vnum == pMudProg->vnum )
				{
					send_to_char( "This prog belongs to a group, it cannot be deleted.\n\r", ch);
					return FALSE;
				}

	sprintf(buf, "MudProg [%4d] %s - deleted.\n\r", pMudProg->vnum,
	  pMudProg->name);

	/* Remove mudprog from the list if it's in there */
	if ( mudprog_list == pMudProg )
		mudprog_list = pMudProg->next;
	else
	{
		for ( pTempProg = mudprog_list; pTempProg->next != pMudProg; pTempProg = pTempProg->next )
			;

		pTempProg->next = pMudProg->next;
	}

	free_mudprog(pMudProg);
	send_to_char(buf, ch);
    edit_done( ch );
	return TRUE;
}

MPEDIT( mpedit_description )
{
	MPROG_DATA *pMudProg;
    char colorbuf[MAX_STRING_LENGTH];

	EDIT_MPROG( ch, pMudProg);

	if ( *argument != '\0' )
	{
		if ( *pMudProg->description != '\0' )
			free_string(pMudProg->description);

        do_color(argument, strlen(argument), colorbuf, sizeof(colorbuf), FALSE);
        pMudProg->description = str_dup( colorbuf );
		send_to_char( "MudProg description set.\n\r", ch);
	}
	else
	{
		send_to_char( "Syntax:  Description <new description>\n\r", ch );
		return FALSE;
	}

	return TRUE;
}

MPEDIT( mpedit_edit )
{
    MPROG_DATA* pMudProg;

    EDIT_MPROG(ch, pMudProg);
	
	string_append( ch, &pMudProg->comlist );
	return TRUE;
}

/*
 * List all the groups a MudProg belongs to. - Zane
 */
MPEDIT( mpedit_groups )
{
	MPROG_DATA *pMudProg;
	MPROG_LIST *pList;
	MPROG_GROUP *pMprogGroup;
	char buf[MAX_STRING_LENGTH];
	char buf2[MAX_STRING_LENGTH];

	*buf = '\0';

	EDIT_MPROG( ch, pMudProg);

	/* If it's new then just return */
	if ( pMudProg->vnum == 0 )
	{
		send_to_char("This program does not belong to any groups.\n\r", ch);
		return TRUE;
	}

	for ( pMprogGroup = mprog_group_list; pMprogGroup; pMprogGroup = pMprogGroup->next )
		if ( pMprogGroup->prog_type == pMudProg->prog_type )
			for ( pList = pMprogGroup->mudprogs; pList; pList = pList->next )
				if ( pList->mudprog->vnum == pMudProg->vnum )
				{
					sprintf(buf2, "[%4d] %s\n\r", 
					  pMprogGroup->vnum, pMprogGroup->name);

					if (strlen(buf)+strlen(buf2) >=sizeof(buf))
					{
						page_to_char(buf,ch);
						*buf = '\0';
					}
					strcat(buf,buf2);
				}

	if ( *buf == '\0' )
		send_to_char("This program does not belong to any groups.\n\r", ch);
	else
		page_to_char(buf,ch);

	return TRUE;
}

MPEDIT( mpedit_name )
{
	MPROG_DATA *pMudProg;
    char colorbuf[MAX_STRING_LENGTH];

	EDIT_MPROG( ch, pMudProg);

	if ( str_len(argument) > 20 )
	{
		send_to_char( "MudProg name cannot be longer than 20 characters.\n\r", ch);
		return FALSE;
	}

	if ( *argument != '\0' )
	{
		if ( *pMudProg->name != '\0' )
			free_string(pMudProg->name);

        do_color(argument, strlen(argument), colorbuf, sizeof(colorbuf), FALSE);
		pMudProg->name = str_dup( colorbuf );
		send_to_char( "MudProg name set.\n\r", ch);
	}
	else
		send_to_char( "Syntax:  Name <new name>\n\r", ch );

	return TRUE;
}

MPEDIT( mpedit_progtype )
{
	MPROG_DATA *pMudProg;
	MPROG_LIST *pList;
	MPROG_GROUP *pMprogGroup;
	MOB_INDEX_DATA *pMob;
	ROOM_INDEX_DATA *pRoom;
	OBJ_INDEX_DATA *pObj;
	char arg[MAX_STRING_LENGTH];
	int nMatch;
	int vnum;

    EDIT_MPROG(ch, pMudProg);
	argument = one_argument(argument, arg);

	if ( !str_prefix(arg, "mobprog") || !str_prefix(arg, "roomprog")
	  || !str_prefix(arg, "objprog") )
	{
		/*
		 * Check to see if the prog is in use anywhere (or in any groups).
		 * If it is, don't allow the type to be changed. -Zane
		 */
		if( pMudProg->vnum )
		{
			switch( pMudProg->prog_type )
			{
			case MOB_PROG:
				nMatch = 0;
				for ( vnum = 0; nMatch < top_mob_index; vnum++ )
					if ( ( pMob = get_mob_index( vnum ) ) != NULL )
					{
						if ( IS_SET( pMob->progtypes, pMudProg->trigger_type ) )
							for ( pList = pMob->mudprogs; pList; pList = pList->next )
								if ( pList->mudprog->vnum == pMudProg->vnum )
								{
									send_to_char( "This prog is in use, you cannot change it's prog type.\n\r", ch);
									return FALSE;
								}
						nMatch++;
					}
				break;
			case ROOM_PROG:
				nMatch = 0;
				for ( vnum = 0; nMatch < top_room; vnum++ )
					if ( ( pRoom = get_room_index( vnum ) ) != NULL )
					{
						if ( IS_SET( pRoom->progtypes, pMudProg->trigger_type ) )
							for ( pList = pRoom->mudprogs; pList; pList = pList->next )
								if ( pList->mudprog->vnum == pMudProg->vnum )
								{
									send_to_char( "This prog is in use, you cannot change it's prog type.\n\r", ch);
									return FALSE;
								}
						nMatch++;
					}
				break;
			case OBJ_PROG:
				nMatch = 0;
				for ( vnum = 0; nMatch < top_obj_index; vnum++ )
					if ( ( pObj = get_obj_index( vnum ) ) != NULL )
					{
						if ( IS_SET( pObj->progtypes, pMudProg->trigger_type ) )
							for ( pList = pObj->mudprogs; pList; pList = pList->next )
								if ( pList->mudprog->vnum == pMudProg->vnum )
								{
									send_to_char( "This prog is in use, you cannot change it's prog type.\n\r", ch);
									return FALSE;
								}
						nMatch++;
					}
				break;
			}

			/* Check groups */
			for ( pMprogGroup = mprog_group_list; pMprogGroup; pMprogGroup = pMprogGroup->next )
				if ( pMprogGroup->prog_type == pMudProg->prog_type )
					for ( pList = pMprogGroup->mudprogs; pList; pList = pList->next )
						if ( pList->mudprog->vnum == pMudProg->vnum )
						{
							send_to_char( "This prog belongs to a group, it's type cannot be changed.\n\r", ch);
							return FALSE;
						}
		}

		/* We passed the checks, assign the type */
		if ( !str_prefix(arg, "mobprog") )
			pMudProg->prog_type = MOB_PROG;

		if ( !str_prefix(arg, "objprog") )
			pMudProg->prog_type = OBJ_PROG;

		if ( !str_prefix(arg, "roomprog") )
			pMudProg->prog_type = ROOM_PROG;

		send_to_char( "MudProg type set.\n\r", ch );
		return TRUE;
	}
	else
	{
		send_to_char( "Syntax:  Progtype <mobprog||objprog||roomprog>\n\r", ch);
		return FALSE;
	}

	return TRUE;
}

MPEDIT( mpedit_show )
{
    MPROG_DATA* pMudProg;

    EDIT_MPROG(ch, pMudProg);
	show_mprog(ch, pMudProg);

	return TRUE;
}

MPEDIT( mpedit_trigger )
{
	MPROG_DATA *pMudProg;
	char arg[MAX_STRING_LENGTH];

	argument = one_argument(argument, arg);
	EDIT_MPROG( ch, pMudProg);

	if ( *arg != '\0' )
	{
		if ( *pMudProg->arglist != '\0' )
			free_string(pMudProg->arglist);

		pMudProg->arglist = str_dup(arg);
		send_to_char( "MudProg trigger set.\n\r", ch);
	}
	else
	{
		send_to_char( "Syntax:  Trigger <Trigger value>\n\r", ch );
		return FALSE;
	}

	return TRUE;
}

MPEDIT( mpedit_triggertype )
{
	MPROG_DATA *pMudProg;
	MOB_INDEX_DATA *pMob;
	ROOM_INDEX_DATA *pRoom;
	OBJ_INDEX_DATA *pObj;
	char arg[MAX_STRING_LENGTH];
	int value;
	int vnum;
	int nMatch;

	argument = one_argument(argument, arg);

	if ( *arg == '\0' )
	{
		send_to_char("Syntax:  triggertype <trigger name> [arguments]\n\r", ch);
		return FALSE;
	}

    /* Set mudprog type */
    if( ( value = flag_value( mprog_type_flags, arg ) ) != NO_FLAG )
    {
		EDIT_MPROG( ch, pMudProg);

		/*
		 * If this isn't a new MudProg then search all mobs/objs/rooms to see
		 * if this prog is in use and if it is change their progtypes to reflect
		 * the new prog type.  Clunky but shouldn't happen too often. -Zane
		 */
		if( pMudProg->vnum )
		{
			switch( pMudProg->prog_type )
			{
			case MOB_PROG:
				nMatch = 0;
				for ( vnum = 0; nMatch < top_mob_index; vnum++ )
					if ( ( pMob = get_mob_index( vnum ) ) != NULL )
					{
						if ( IS_SET( pMob->progtypes, pMudProg->trigger_type ) )
						{
							REMOVE_BIT( pMob->progtypes, pMudProg->trigger_type );
							SET_BIT( pMob->progtypes, value );
						}
						nMatch++;
					}
				break;
			case ROOM_PROG:
				nMatch = 0;
				for ( vnum = 0; nMatch < top_room; vnum++ )
					if ( ( pRoom = get_room_index( vnum ) ) != NULL )
					{
						if ( IS_SET( pRoom->progtypes, pMudProg->trigger_type ) )
						{
							REMOVE_BIT( pRoom->progtypes, pMudProg->trigger_type );
							SET_BIT( pRoom->progtypes, value );
						}
						nMatch++;
					}
				break;
			case OBJ_PROG:
				nMatch = 0;
				for ( vnum = 0; nMatch < top_obj_index; vnum++ )
					if ( ( pObj = get_obj_index( vnum ) ) != NULL )
					{
						if ( IS_SET( pObj->progtypes, pMudProg->trigger_type ) )
						{
							REMOVE_BIT( pObj->progtypes, pMudProg->trigger_type );
							SET_BIT( pObj->progtypes, value );
						}
						nMatch++;
					}
				break;
			}
		}
		pMudProg->trigger_type = value;

		argument = one_argument(argument, arg);

		if ( *arg != '\0' )
		{
			if ( *pMudProg->arglist != '\0' )
				free_string(pMudProg->arglist);

			pMudProg->arglist = str_dup(arg);
		}

		send_to_char( "MudProg trigger type set.\n\r", ch);
    }
	else
	{
		send_to_char("Unknown trigger type.\n\r", ch);
		return FALSE;
	}

	return TRUE;
}

MPEDIT( mpedit_assign )
{
	MPROG_DATA *pMudProg;
	MPROG_GROUP *pMprogGroup;
	MOB_INDEX_DATA *pMob;
	OBJ_INDEX_DATA *pObj;
	ROOM_INDEX_DATA *pRoom;
	char arg1[MAX_STRING_LENGTH];
	char arg2[MAX_STRING_LENGTH];
	int targetvnum;
	int progvnum;

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

	if ( *arg1 == '\0' || *arg2 == '\0' || !is_number(arg1) || !is_number(arg2) )
	{
		send_to_char("Syntax:  edit mprog assign <target vnum> <mudprog vnum>\n\r", ch);
		return FALSE;
	}

	targetvnum = atoi(arg1);
	progvnum = atoi(arg2);

	if ( ( pMudProg = get_mprog_by_vnum( progvnum ) ) != NULL )
		switch(pMudProg->prog_type)
		{
		case MOB_PROG:
			if ( ( pMob = get_mob_index( targetvnum ) ) == NULL )
			{
				send_to_char("The MudProg you specified is a MobProg and no mob matches the vnum you supplied.\n\r", ch);
				return FALSE;
			}

			assign_mobprog(pMob, pMudProg, NULL);
			if ( pMob->area )
				SET_BIT(pMob->area->area_flags, AREA_CHANGED);

			break;
		case OBJ_PROG:
			if ( ( pObj = get_obj_index( targetvnum ) ) == NULL )
			{
				send_to_char("The MudProg you specified is a ObjProg and no object matches the vnum you supplied.\n\r", ch);
				return FALSE;
			}

			assign_objprog(pObj, pMudProg, NULL);
			if ( pObj->area )
				SET_BIT(pObj->area->area_flags, AREA_CHANGED);

			break;
		case ROOM_PROG:
			if ( ( pRoom = get_room_index( targetvnum ) ) == NULL )
			{
				send_to_char("The MudProg you specified is a RoomProg and no room matches the vnum you supplied.\n\r", ch);
				return FALSE;
			}

			assign_roomprog(pRoom, pMudProg, NULL);
			if ( pRoom->area )
				SET_BIT(pRoom->area->area_flags, AREA_CHANGED);

			break;
		}
	else if ( ( pMprogGroup = get_mprog_group_by_vnum( progvnum ) ) != NULL )
		switch(pMprogGroup->prog_type)
		{
		case MOB_PROG:
			if ( ( pMob = get_mob_index( targetvnum ) ) == NULL )
			{
				send_to_char("The MudProg you specified is a MobProg and no mob matches the vnum you supplied.\n\r", ch);
				return FALSE;
			}

			assign_mobprog(pMob, NULL, pMprogGroup);
			if ( pMob->area )
				SET_BIT(pMob->area->area_flags, AREA_CHANGED);

			break;
		case OBJ_PROG:
			if ( ( pObj = get_obj_index( targetvnum ) ) == NULL )
			{
				send_to_char("The MudProg you specified is a ObjProg and no object matches the vnum you supplied.\n\r", ch);
				return FALSE;
			}

			assign_objprog(pObj, NULL, pMprogGroup);
			if ( pObj->area )
				SET_BIT(pObj->area->area_flags, AREA_CHANGED);

			break;
		case ROOM_PROG:
			if ( ( pRoom = get_room_index( targetvnum ) ) == NULL )
			{
				send_to_char("The MudProg you specified is a RoomProg and no room matches the vnum you supplied.\n\r", ch);
				return FALSE;
			}

			assign_roomprog(pRoom, NULL, pMprogGroup);
			if ( pRoom->area )
				SET_BIT(pRoom->area->area_flags, AREA_CHANGED);

			break;
		}
	else
	{
		sprintf(arg1, "Invalid MudProg vnum [%4d].\n\r", progvnum);
		send_to_char(arg1, ch);
		return FALSE;
	}

	send_to_char("MudProg assigned.\n\r", ch);
	return TRUE;
}

MPEDIT( mpedit_unassign )
{
	MPROG_DATA *pMudProg;
	MPROG_GROUP *pMprogGroup;
	MOB_INDEX_DATA *pMob;
	OBJ_INDEX_DATA *pObj;
	ROOM_INDEX_DATA *pRoom;
	char arg1[MAX_STRING_LENGTH];
	char arg2[MAX_STRING_LENGTH];
	int targetvnum;
	int progvnum;

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

	if ( *arg1 == '\0' || *arg2 == '\0' || !is_number(arg1) || !is_number(arg2) )
	{
		send_to_char("Syntax:  edit mprog unassign <target vnum> <mudprog vnum>\n\r", ch);
		return FALSE;
	}

	targetvnum = atoi(arg1);
	progvnum = atoi(arg2);

	if ( ( pMudProg = get_mprog_by_vnum( progvnum ) ) != NULL )
		switch(pMudProg->prog_type)
		{
		case MOB_PROG:
			if ( ( pMob = get_mob_index( targetvnum ) ) == NULL )
			{
				send_to_char("No matching MudProg is assigned to this mob.\n\r", ch);
				return FALSE;
			}

			if ( !unassign_mobprog(pMob, pMudProg, NULL) )
			{
				send_to_char("MudProg is part of a group assigned to that mob, please remove the group" \
				  " or remove the Prog from that group.\n\r", ch);
				return FALSE;
			}

			if ( pMob->area )
				SET_BIT(pMob->area->area_flags, AREA_CHANGED);

			break;
		case OBJ_PROG:
			if ( ( pObj = get_obj_index( targetvnum ) ) == NULL )
			{
				send_to_char("No matching MudProg is assigned to this object.\n\r", ch);
				return FALSE;
			}

			if ( !unassign_objprog(pObj, pMudProg, NULL) )
			{
				send_to_char("MudProg is part of a group assigned to that mob, please remove the group" \
				  " or remove the Prog from that group.\n\r", ch);
				return FALSE;
			}

			if ( pObj->area )
				SET_BIT(pObj->area->area_flags, AREA_CHANGED);

			break;
		case ROOM_PROG:
			if ( ( pRoom = get_room_index( targetvnum ) ) == NULL )
			{
				send_to_char("No matching MudProg is assigned to this room.\n\r", ch);
				return FALSE;
			}

			if ( !unassign_roomprog(pRoom, pMudProg, NULL) )
			{
				send_to_char("MudProg is part of a group assigned to that mob, please remove the group" \
				  " or remove the Prog from that group.\n\r", ch);
				return FALSE;
			}

			if ( pRoom->area )
				SET_BIT(pRoom->area->area_flags, AREA_CHANGED);

			break;
		}
	else if ( ( pMprogGroup = get_mprog_group_by_vnum( progvnum ) ) != NULL )
		switch(pMprogGroup->prog_type)
		{
		case MOB_PROG:
			if ( ( pMob = get_mob_index( targetvnum ) ) == NULL )
			{
				send_to_char("No matching MudProg is assigned to this mob.\n\r", ch);
				return FALSE;
			}

			unassign_mobprog(pMob, NULL, pMprogGroup);
			if ( pMob->area )
				SET_BIT(pMob->area->area_flags, AREA_CHANGED);

			break;
		case OBJ_PROG:
			if ( ( pObj = get_obj_index( targetvnum ) ) == NULL )
			{
				send_to_char("No matching MudProg is assigned to this object.\n\r", ch);
				return FALSE;
			}

			unassign_objprog(pObj, NULL, pMprogGroup);
			if ( pObj->area )
				SET_BIT(pObj->area->area_flags, AREA_CHANGED);

			break;
		case ROOM_PROG:
			if ( ( pRoom = get_room_index( targetvnum ) ) == NULL )
			{
				send_to_char("No matching MudProg is assigned to this room.\n\r", ch);
				return FALSE;
			}

			unassign_roomprog(pRoom, NULL, pMprogGroup);
			if ( pRoom->area )
				SET_BIT(pRoom->area->area_flags, AREA_CHANGED);

			break;
		}
	else
	{
		sprintf(arg1, "Invalid MudProg vnum [%4d].\n\r", progvnum);
		send_to_char(arg1, ch);
		return FALSE;
	}

	send_to_char("MudProg unassigned.\n\r", ch);
	return TRUE;
}

void show_mprog( CHAR_DATA* ch, MPROG_DATA* pMudProg )
{
    char buf [MAX_STRING_LENGTH];
    char buf2[MAX_STRING_LENGTH];

	if ( !pMudProg )
		return;

	switch(pMudProg->prog_type)
	{
	case MOB_PROG:
		sprintf(buf2, "MobProg");
		break;
	case OBJ_PROG:
		sprintf(buf2, "ObjProg");
		break;
	case ROOM_PROG:
		sprintf(buf2, "RoomProg");
		break;
	}
    sprintf(buf,"[%4d] %-20s   -   ProgType: %s\n\rDesc: %s\n\r>%s %s~\n\r", 
	  pMudProg->vnum, pMudProg->name, buf2,
	  pMudProg->description, mprog_type_to_name( pMudProg->trigger_type ),
	  pMudProg->arglist ? pMudProg->arglist : "NULL" );
   
    sprintf(buf2,"%s~\n\r", pMudProg->comlist ? pMudProg->comlist : "NULL\n\r");
   
    if (strlen(buf)+strlen(buf2) >=sizeof(buf))
    {
		page_to_char(buf,ch);
		page_to_char(buf2,ch);
		return;
    }
    else
    {
		strcat(buf,buf2);
		page_to_char(buf,ch);
		return;
    }
}

MPGEDIT( mpgedit_add )
{
	MPROG_GROUP *pGroup;
	MPROG_DATA *pProg;
	MPROG_GROUP_LIST *pGroupList;
	MPROG_LIST *pList;
	MOB_INDEX_DATA *pMob;
	OBJ_INDEX_DATA *pObj;
	ROOM_INDEX_DATA *pRoom;
	int progvnum;
	int vnum;
	int nMatch;
	int iFound;
	bool updated;

	EDIT_MPGROUP(ch, pGroup);
	updated = FALSE;
	progvnum = 0;

	if ( *argument == '\0' || ( ( progvnum = atoi(argument) ) == 0 ) )
	{
		send_to_char("Syntax:  add <prog vnum>\n\r", ch);
		return FALSE;
	}

	if ( ( pProg = get_mprog_by_vnum( progvnum ) ) == NULL )
	{
		send_to_char("Invalid vnum.\n\r", ch);
		return FALSE;
	}

	/* Check to make sure it's not already in the group */
	for ( pList = pGroup->mudprogs; pList; pList = pList->next )
		if ( pList->mudprog->vnum == progvnum )
		{
			send_to_char("That MudProg is already in this group.\n\r", ch);
			return FALSE;
		}

	if ( pProg->prog_type != pGroup->prog_type && pGroup->mudprogs )
	{
		send_to_char("Unable to add MudProg, MudProg Group contains Progs of a different type.\n\r", ch);
		return FALSE;
	}
	else
		pGroup->prog_type = pProg->prog_type;

	/*
	 * Add the prog to this group.
	 */
	pList = alloc_perm(sizeof(*pList));
	pList->mudprog = pProg;
	pList->next = pGroup->mudprogs;
	pGroup->mudprogs = pList;

	/*
	 * Search through all mobs/rooms/objs and add this prog to their list if they
	 * have this group.
	 */
	switch( pGroup->prog_type )
	{
	case MOB_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_mob_index; vnum++ )
			if ( ( pMob = get_mob_index( vnum ) ) != NULL )
			{
				iFound = 0;

				for ( pGroupList = pMob->mprog_groups; pGroupList; pGroupList = pGroupList->next )
					if ( pGroupList->mprog_group->vnum == pGroup->vnum )
					{
						iFound = 0;

						for ( pList = pMob->mudprogs; pList; pList = pList->next )
							if ( pList->mudprog->vnum == pProg->vnum )
								iFound = 1;

						if ( !iFound )
						{
							updated = TRUE;
							pList = alloc_perm(sizeof(*pList));
							pList->mudprog = pProg;
							pList->next = pMob->mudprogs;
							pMob->mudprogs = pList;
							SET_BIT(pMob->progtypes, pProg->trigger_type);
						}

						break;
					}

				nMatch++;
			}
		break;
	case ROOM_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_room; vnum++ )
			if ( ( pRoom = get_room_index( vnum ) ) != NULL )
			{
				for ( pGroupList = pRoom->mprog_groups; pGroupList; pGroupList = pGroupList->next )
					if ( pGroupList->mprog_group->vnum == pGroup->vnum )
					{
						iFound = 0;

						for ( pList = pRoom->mudprogs; pList; pList = pList->next )
							if ( pList->mudprog->vnum == pProg->vnum )
								iFound = 1;

						if ( !iFound )
						{
							updated = TRUE;
							pList = alloc_perm(sizeof(*pList));
							pList->mudprog = pProg;
							pList->next = pRoom->mudprogs;
							pRoom->mudprogs = pList;
							SET_BIT(pRoom->progtypes, pProg->trigger_type);
						}

						break;
					}

				nMatch++;
			}
		break;
	case OBJ_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_obj_index; vnum++ )
			if ( ( pObj = get_obj_index( vnum ) ) != NULL )
			{
				for ( pGroupList = pObj->mprog_groups; pGroupList; pGroupList = pGroupList->next )
					if ( pGroupList->mprog_group->vnum == pGroup->vnum )
					{
						iFound = 0;

						for ( pList = pObj->mudprogs; pList; pList = pList->next )
							if ( pList->mudprog->vnum == pProg->vnum )
								iFound = 1;

						if ( !iFound )
						{
							updated = TRUE;
							pList = alloc_perm(sizeof(*pList));
							pList->mudprog = pProg;
							pList->next = pObj->mudprogs;
							pObj->mudprogs = pList;
							SET_BIT(pObj->progtypes, pProg->trigger_type);
						}

						break;
					}

				nMatch++;
			}
		break;
	}

	if ( updated )
		send_to_char("Prog added to group and existing obj/mob/rooms updated.\n\r", ch);
	else
		send_to_char("Prog added to group.\n\r", ch);

	return TRUE;
}

MPGEDIT( mpgedit_create )
{
	MPROG_GROUP *pMprogGroup;

	if ( ch->desc->pEdit )
	{
		send_to_char("You're already editing.\n\r", ch);
		return FALSE;
	}

	if ( *argument == '\0' && !str_prefix(argument, "mobprog") 
	  && !str_prefix(argument, "objprog") && !str_prefix(argument, "roomprog") )
	{
		send_to_char("Syntax:  edit mpgroup create [mobprog||objprog||roomprog]\n\r", ch);
		return FALSE;
	}

	pMprogGroup = new_mudprog_group();

	if ( !str_prefix(argument, "mobprog") )
		pMprogGroup->prog_type = MOB_PROG;

	if ( !str_prefix(argument, "objprog") )
		pMprogGroup->prog_type = OBJ_PROG;

	if ( !str_prefix(argument, "roomprog") )
		pMprogGroup->prog_type = ROOM_PROG;

    ch->desc->pEdit = (void *)pMprogGroup;

    send_to_char( "MudProg Group Created.\n\r", ch );
    return TRUE;
}

MPGEDIT( mpgedit_delete )
{
	MPROG_GROUP		 *pTempGroup;
	MPROG_GROUP      *pMprogGroup;
	MPROG_GROUP_LIST *pList;
	OBJ_INDEX_DATA   *pObj;
	MOB_INDEX_DATA   *pMob;
	ROOM_INDEX_DATA  *pRoom;
    char arg[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];
    int vnum;
	int nMatch;

	argument = one_argument(argument, arg);

	if ( *arg != '\0' )
	{
		if ( ( vnum = atoi( arg ) ) < 1 )
		{
			send_to_char( "Syntax:  Delete [MudProg Group Vnum]\n\r", ch);
			return FALSE;
		}

		if ( ( pMprogGroup = get_mprog_group_by_vnum( vnum ) ) == NULL )
		{
			send_to_char( "Invalid vnum.\n\r", ch );
			return FALSE;
		}
	}
	else
		EDIT_MPGROUP(ch, pMprogGroup);

	/*
	 * This mudprog group is new and hasn't been added to the list, just free it.
	 */
	if ( pMprogGroup->vnum == 0 )
	{
		sprintf(buf, "MudProg Group [%4d] %s - deleted.\n\r", pMprogGroup->vnum,
		  pMprogGroup->name);
		free_mudprog_group(pMprogGroup);
		send_to_char(buf, ch);
		edit_done(ch);
		return TRUE;
	}

	/*
	 * Check to see if this mudprog group is in use.  If it is
	 * then don't allow the deletion.  -Zane
	 */
	switch( pMprogGroup->prog_type )
	{
	case MOB_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_mob_index; vnum++ )
			if ( ( pMob = get_mob_index( vnum ) ) != NULL )
			{
				for ( pList = pMob->mprog_groups; pList; pList = pList->next )
					if ( pList->mprog_group->vnum == pMprogGroup->vnum )
					{
						send_to_char( "This group is in use, you cannot delete it.\n\r", ch);
						return FALSE;
					}
				nMatch++;
			}
		break;
	case ROOM_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_room; vnum++ )
			if ( ( pRoom = get_room_index( vnum ) ) != NULL )
			{
				for ( pList = pRoom->mprog_groups; pList; pList = pList->next )
					if ( pList->mprog_group->vnum == pMprogGroup->vnum )
					{
						send_to_char( "This group is in use, you cannot delete it.\n\r", ch);
						return FALSE;
					}
				nMatch++;
			}
		break;
	case OBJ_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_obj_index; vnum++ )
			if ( ( pObj = get_obj_index( vnum ) ) != NULL )
			{
				for ( pList = pObj->mprog_groups; pList; pList = pList->next )
					if ( pList->mprog_group->vnum == pMprogGroup->vnum )
					{
						send_to_char( "This prog is in use, you cannot delete it.\n\r", ch);
						return FALSE;
					}
				nMatch++;
			}
		break;
	}

	sprintf(buf, "MudProg Group [%4d] %s - deleted.\n\r", pMprogGroup->vnum,
	  pMprogGroup->name);

	/* Remove mudprog from the list if it's in there */
	if ( mprog_group_list == pMprogGroup )
		mprog_group_list = pMprogGroup->next;
	else
	{
		for ( pTempGroup = mprog_group_list; pTempGroup->next != pMprogGroup;
		  pTempGroup = pTempGroup->next )
			;

		pTempGroup->next = pMprogGroup->next;
	}

	free_mudprog_group(pMprogGroup);
	send_to_char(buf, ch);
    edit_done( ch );
	return TRUE;
}

MPGEDIT( mpgedit_description )
{
	MPROG_GROUP *pMprogGroup;
    char colorbuf[MAX_STRING_LENGTH];

	EDIT_MPGROUP( ch, pMprogGroup);

	if ( *argument != '\0' )
	{
		if ( *pMprogGroup->description != '\0' )
			free_string(pMprogGroup->description);

        do_color(argument, strlen(argument), colorbuf, sizeof(colorbuf), FALSE);
		pMprogGroup->description = str_dup( colorbuf );
		send_to_char( "MudProg Group description set.\n\r", ch);
	}
	else
	{
		send_to_char( "Syntax:  Description <new description>\n\r", ch );
		return FALSE;
	}

	return TRUE;
}

MPGEDIT( mpgedit_name )
{
	MPROG_GROUP *pMprogGroup;
    char colorbuf[MAX_STRING_LENGTH];

	EDIT_MPGROUP( ch, pMprogGroup);

	if ( str_len(argument) > 20 )
	{
		send_to_char( "MudProg Group name cannot be longer than 20 characters.\n\r", ch);
		return FALSE;
	}

	if ( *argument != '\0' )
	{
		if ( *pMprogGroup->name != '\0' )
			free_string(pMprogGroup->name);

        do_color(argument, strlen(argument), colorbuf, sizeof(colorbuf), FALSE);
		pMprogGroup->name = str_dup( colorbuf );
		send_to_char( "MudProg Group name set.\n\r", ch);
	}
	else
		send_to_char( "Syntax:  Name <new name>\n\r", ch );

	return TRUE;
}

MPGEDIT( mpgedit_remove )
{
	MPROG_GROUP *pGroup;
	MPROG_GROUP_LIST *pGroupList;
	MPROG_LIST *pList;
	MPROG_LIST *pInnerList;
	MOB_INDEX_DATA *pMob;
	OBJ_INDEX_DATA *pObj;
	ROOM_INDEX_DATA *pRoom;
	int progvnum;
	int vnum;
	int nMatch;
	int iFound;
	bool updated;

	EDIT_MPGROUP(ch, pGroup);
	updated = FALSE;
	progvnum = 0;

	if ( *argument == '\0' || ( ( progvnum = atoi(argument) ) == 0 ) )
	{
		send_to_char("Syntax:  remove <prog vnum>\n\r", ch);
		return FALSE;
	}

	/* Remove the MudProg from the Group if it's in there. */
	for ( pList = pGroup->mudprogs; pList; pList = pList->next )
		if ( pList->mudprog->vnum == progvnum )
		{
			if ( pList == pGroup->mudprogs )
				pGroup->mudprogs = pList->next;
			else
			{
				for ( pInnerList = pGroup->mudprogs; pInnerList->next != pList; 
				  pInnerList = pInnerList->next )
					;

				pInnerList->next = pList->next;
			}

			free_mem(pList, sizeof(*pList));
			updated = TRUE;
			break;
		}

	/* If no matching prog was found throw an error */
	if ( !updated )
	{
		send_to_char("That MudProg does not exist in this group.\n\r", ch);
		return FALSE;
	}
	else
		updated = FALSE;

	/*
	 * Search through all mobs/rooms/objs and remove this prog form their list if they
	 * have this group.
	 */
	switch( pGroup->prog_type )
	{
	case MOB_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_mob_index; vnum++ )
			if ( ( pMob = get_mob_index( vnum ) ) != NULL )
			{
				iFound = 0;

				for ( pGroupList = pMob->mprog_groups; pGroupList; pGroupList = pGroupList->next )
					if ( pGroupList->mprog_group->vnum == pGroup->vnum )
						iFound = 1;

				/*
				 * We found the group, count how many groups use this MudProg.
				 */
				if ( iFound )
				{
					iFound = 0;

					for (pGroupList = pMob->mprog_groups; pGroupList; pGroupList = pGroupList->next )
						for ( pList = pGroupList->mprog_group->mudprogs; pList; pList = pList->next )
							if ( pList->mudprog->vnum == progvnum )
								iFound++;

					/* No references to that prog were found, remove it. */
					if ( iFound < 1 )
					{
						for ( pList = pMob->mudprogs; 
						  pList && pList->mudprog->vnum != progvnum; pList = pList->next )
							  ;

						if ( pList == pMob->mudprogs )
							pMob->mudprogs = pList->next;
						else
						{
							for (pInnerList = pMob->mudprogs; pInnerList->next != pList;
							  pInnerList = pInnerList->next )
								  ;

							pInnerList->next = pList->next;
						}

						free_mem(pList, sizeof(*pList));
						updated = TRUE;
					}
				}

				nMatch++;
			}
		break;
	case ROOM_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_room; vnum++ )
			if ( ( pRoom = get_room_index( vnum ) ) != NULL )
			{
				iFound = 0;

				for ( pGroupList = pRoom->mprog_groups; pGroupList; pGroupList = pGroupList->next )
					if ( pGroupList->mprog_group->vnum == pGroup->vnum )
						iFound = 1;

				/*
				 * We found the group, count how many groups use this MudProg.
				 */
				if ( iFound )
				{
					iFound = 0;

					for (pGroupList = pRoom->mprog_groups; pGroupList; pGroupList = pGroupList->next )
						for ( pList = pGroupList->mprog_group->mudprogs; pList; pList = pList->next )
							if ( pList->mudprog->vnum == progvnum )
								iFound++;

					/* Only one reference to that prog was found, remove it. */
					if ( iFound == 1 )
					{
						for ( pList = pRoom->mudprogs; 
						  pList && pList->mudprog->vnum != progvnum; pList = pList->next )
							  ;

						if ( pList == pRoom->mudprogs )
							pRoom->mudprogs = pList->next;
						else
						{
							for (pInnerList = pRoom->mudprogs; pInnerList->next != pList;
							  pInnerList = pInnerList->next )
								  ;

							pInnerList->next = pList->next;
						}

						free_mem(pList, sizeof(*pList));
						updated = TRUE;
					}
				}

				nMatch++;
			}
		break;
	case OBJ_PROG:
		nMatch = 0;
		for ( vnum = 0; nMatch < top_obj_index; vnum++ )
			if ( ( pObj = get_obj_index( vnum ) ) != NULL )
			{
				iFound = 0;

				for ( pGroupList = pObj->mprog_groups; pGroupList; pGroupList = pGroupList->next )
					if ( pGroupList->mprog_group->vnum == pGroup->vnum )
						iFound = 1;

				/*
				 * We found the group, count how many groups use this MudProg.
				 */
				if ( iFound )
				{
					iFound = 0;

					for (pGroupList = pObj->mprog_groups; pGroupList; pGroupList = pGroupList->next )
						for ( pList = pGroupList->mprog_group->mudprogs; pList; pList = pList->next )
							if ( pList->mudprog->vnum == progvnum )
								iFound++;

					/* Only one reference to that prog was found, remove it. */
					if ( iFound == 1 )
					{
						for ( pList = pObj->mudprogs; 
						  pList && pList->mudprog->vnum != progvnum; pList = pList->next )
							  ;

						if ( pList == pObj->mudprogs )
							pObj->mudprogs = pList->next;
						else
						{
							for (pInnerList = pObj->mudprogs; pInnerList->next != pList;
							  pInnerList = pInnerList->next )
								  ;

							pInnerList->next = pList->next;
						}

						free_mem(pList, sizeof(*pList));
						updated = TRUE;
					}
				}

				nMatch++;
			}
		break;
	}

	if ( updated )
		send_to_char("Prog removed from group and existing obj/mob/rooms updated.\n\r", ch);
	else
		send_to_char("Prog removed from group.\n\r", ch);

	return TRUE;
}

MPGEDIT( mpgedit_show )
{
	MPROG_GROUP *pGroup;

    EDIT_MPGROUP(ch, pGroup);
	show_mpgroup(ch, pGroup);
	
	return TRUE;
}

void show_mpgroup(CHAR_DATA *ch, MPROG_GROUP *pGroup)
{
	MPROG_LIST  *pList;
	char buf[MAX_STRING_LENGTH];

	if ( !pGroup )
		return;

	*buf = '\0';

	sprintf(buf, "** [%4d] Group - %s\n\r** Desc: %s\n\r\n\r", pGroup->vnum,
	  pGroup->name, pGroup->description);
	page_to_char(buf, ch);

	for ( pList = pGroup->mudprogs; pList; pList = pList->next )
		show_mprog(ch, pList->mudprog);

	sprintf(buf, "\n\r** [%4d] End of group.\n\r\n\r", pGroup->vnum);  
	page_to_char(buf,ch);
}