daleken/
daleken/data/notes/
daleken/data/player/
daleken/data/system/poses/
daleken/doc/Homepage/images/
daleken/log/
/*___________________________________________________________________________*
   )()(			  DalekenMUD 1.12 (C) 2000			)()(
   `]['		       by Martin Thomson, Lee Brooks,			`]['
    ||		       Ken Herbert and David Jacques			 ||
    || ----------------------------------------------------------------- ||
    || Envy Diku Mud improvements copyright (C) 1994 by Michael Quan,	 ||
    || David Love, Guilherme 'Willie' Arnold, and Mitchell Tse.		 ||
    || Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael	 ||
    || Chastain, Michael Quan, and Mitchell Tse.			 ||
    || Original Diku Mud copyright (C) 1990, 1991			 ||
    || by Sebastian Hammer, Michael Seifert, Hans Henrik St{rfeldt,	 ||
    || Tom Madsen, and Katja Nyboe.					 ||
    || ----------------------------------------------------------------- ||
    || Any use of this software must follow the licenses of the		 ||
    || creators.  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.					 ||
    || ----------------------------------------------------------------- ||
    ||                             olc_act.c                             ||
    || Code for editing areas, rooms and mobile and object indexes.      ||
 *_/<>\_________________________________________________________________/<>\_*/


#include <limits.h>		/* OLC 1.1b */
#include "mud.h"
#include "olc.h"
#include "event.h"

#if defined( unix )
#include <unistd.h>
#endif

#ifndef INT_MAX
#define INT_MAX 65536
#endif


extern const int rev_dir[];
void junk_old_religion		args( ( AREA_DATA *pArea ) );
int edit_mpadd			args( ( CHAR_DATA *ch, MPROG_DATA **top,
					const char *argument, int *allowed ) );
bool edit_mpdelete		args( ( CHAR_DATA *ch, MPROG_DATA **top,
					const char *argument ) );
bool edit_mpedit		args( ( CHAR_DATA *ch, MPROG_DATA *mprg,
					const char *argument ) );
void edit_mpshow		args( ( CHAR_DATA *ch, MPROG_DATA *mprg,
					const char *argument ) );


void edit_mpshow( CHAR_DATA *ch, MPROG_DATA *mprg, const char *argument )
{
    BUFFER *buf = buffer_new( MAX_STRING_LENGTH );
    int num = 0;
    int argnum = -1;
    bool sh = FALSE;

    if( argument[0] != '\0' )
    {
	if( is_number( argument ) )
	{
	    argnum = atoi( argument );
	}
	else if( !str_cmp( argument, "short" ) )
	{
	    sh = TRUE;
	}
	else
	{
	    send_to_char( "Syntax:  mpshow [number/'short']\n\r", ch );
	    return;
	}
    }
    if( !mprg )
    {
	send_to_char( "Edit: There are no MudProgs here.\n\r", ch );
	return;
    }
    for( ; mprg; mprg = mprg->next, num++ )
    {
	if( argnum >= 0 && num != argnum )
	    continue;

	bprintf( buf, "&c<%3d> &y%-20s", num,
		flag_string( mud_prog_flags, &mprg->type ) );
	bprintf( buf, "&garg-&b[&y%s&b]&n\n\r", mprg->arglist );

	if( sh )
	    continue;

	bprintf( buf, "&w%s&n\n\r", mprg->comlist );
	if( argnum >= 0 )
	    break;
    }
    if( argnum >= 0 && !mprg )
	send_to_char( "Edit: MudProg not found.\n\r", ch );
    else
	send_to_char( buf->data, ch );
    buffer_free( buf );
    return;
}


int edit_mpadd( CHAR_DATA *ch, MPROG_DATA **top, const char *argument,
		int *allowed )
{
    MPROG_DATA *mprg, *mprg2;
    MPROG_GLOBAL *glob;
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    int num;
    int type, realtype;
    int i;

    if( !ch->pcdata || ch->pcdata->security < 6 )
    {
	send_to_char( "You aren't authorised to use mudprogs.\n\r", ch );
	return PROG_ERROR;
    }

    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    if( arg1[0] == '\0' || !is_number( arg1 )
	|| arg2[0] == '\0' || argument[0] == '\0' )
    {
	send_to_char( "Syntax:	mpadd <#num> <event> <args>.\n\r", ch );
	return PROG_ERROR;
    }
    num = atoi( arg1 );

    if( flag_value( &type, mud_prog_flags, arg2 ) == NO_FLAG )
    {
	send_to_char( "Edit: invalid mudprog event '? MPROG'\n\r", ch );
	return PROG_ERROR;
    }

    /*
     * Some extensive checking is required for a global style program.
     */
    if( type == GLOBAL_PROG )
    {
	if( !is_number( argument ) )
	{
	    send_to_char( "For a global prog, please specify a vnum.\n\r",
			  ch );
	    return PROG_ERROR;
	}
	if( !( glob = get_global_mudprog_index( atoi( argument ) ) ) )
	{
	    send_to_char( "That global prog doesn't exist.\n\r",
			  ch );
	    return PROG_ERROR;
	}

	if( !ch->desc )
	    return PROG_ERROR;

	if( !str_cmp( ch->desc->interpreter->name, "OEdit" )
	    && !IS_SET( glob->allowed, MPROG_GLOBAL_OBJ ) )
	{
	    send_to_char( "That prog isn't designed for objects.\n\r", ch );
	    return PROG_ERROR;
	}
	else if( !str_cmp( ch->desc->interpreter->name, "MEdit" )
		 && !IS_SET( glob->allowed, MPROG_GLOBAL_MOB ) )
	{
	    send_to_char( "That prog isn't designed for mobs.\n\r", ch );
	    return PROG_ERROR;
	}
	else if( !str_cmp( ch->desc->interpreter->name, "REdit" )
	    && !IS_SET( glob->allowed, MPROG_GLOBAL_ROOM ) )
	{
	    send_to_char( "That prog isn't designed for rooms.\n\r", ch );
	    return PROG_ERROR;
	}

	realtype = glob->type;
    }
    else
	realtype = type;

    /*
     * Check that the type of prog is allowed.
     */
    for( i = 0; allowed[i] != -1; ++i )
	if( allowed[i] == realtype )
	    break;
    if( allowed[i] == -1 )
    {
	send_to_char( "Edit: that MudProg is used in a different context.\n\r",
		      ch );
	send_to_char( "You can use:", ch );
	for( i = 0; allowed[i] != -1; ++i )
	    charprintf( ch, " %s", flag_string( mud_prog_flags, &allowed[i] ) );
	send_to_char( ".\n\r", ch );
	return PROG_ERROR;
    }

    /*
     * Create a new prog.
     */
    mprg = new_mprog( );
    mprg->type = type;
    mprg->arglist = str_dup( argument );
    if( num <= 0 || !*top )
    {
	mprg->next = *top;
	*top = mprg;
    }
    else
    {
	i = 0;
	for( mprg2 = *top; mprg2->next; mprg2 = mprg2->next )
	{
	    if( ++i == num )
		break;
	}
	mprg->next = mprg2->next;
	mprg2->next = mprg;
    }
    if( mprg->type == GLOBAL_PROG )
	send_to_char( "Global programs don't require any code, but feel\n\r"
		      "free to add any comments if you want.\n\r", ch );

    string_edit( ch, &mprg->comlist );
    return realtype;
}


bool edit_mpdelete( CHAR_DATA *ch, MPROG_DATA **top, const char *argument )
{
    MPROG_DATA *mprg;
    MPROG_DATA *mprg_next;
    char mpstr[MAX_STRING_LENGTH];
    int value;
    int cnt = 0;

    one_argument( argument, mpstr );

    if( !ch->pcdata || ch->pcdata->security < 6 )
    {
	send_to_char( "You aren't authorised to use mudprogs.\n\r", ch );
	return FALSE;
    }

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

    value = atoi( mpstr );

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

    if( !( mprg = *top ) )
    {
	send_to_char( "Edit:  Non-existant MudProg.\n\r", ch );
	return FALSE;
    }

    if( value == 0 )		/* First case: Remove first affect */
    {
	mprg = *top;
	*top = mprg->next;
	mprg->next = NULL;
	free_mprog( mprg );
    }
    else	/* Affect to remove is not the first */
    {
	while( ( mprg_next = mprg->next ) && ( ++cnt < value ) )
	    mprg = mprg_next;

	if( mprg_next )		/* See if it's the next affect */
	{
	    mprg->next = mprg_next->next;
	    mprg_next->next = NULL;
	    free_mprog( mprg_next );
	}
	else	    /* Doesn't exist */
	{
	    send_to_char( "Edit: No such MudProg.\n\r", ch );
	    return FALSE;
	}
    }

    send_to_char( "Edit: MudProg removed.\n\r", ch );
    return TRUE;
}


bool edit_mpedit( CHAR_DATA *ch, MPROG_DATA *mprg, const char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    int num;

    if( !ch->pcdata || ch->pcdata->security < 6 )
    {
	send_to_char( "You aren't authorised to use mudprogs.\n\r", ch );
	return FALSE;
    }

    argument = one_argument( argument, arg );
    if( arg[0] == '\0' || !is_number( arg ) )
    {
	send_to_char( "Syntax:	mprog <number>		- edit body\n\r", ch );
	send_to_char( "Syntax:	mprog <number> [arguments]   - args\n\r", ch );
	return FALSE;
    }
    num = atoi( arg );
    for( ; num && mprg; mprg = mprg->next )
	num--;
    if( num || !mprg )
    {
	send_to_char( "That one doesn't exist.\n\r", ch );
	return FALSE;
    }
    if( argument[0] == '\0' )
	string_edit( ch, &mprg->comlist );
    else
    {
	free_string( mprg->arglist );
	mprg->arglist = str_dup( argument );
	send_to_char( "Argument to MudProg changed.\n\r", ch );
    }
    return TRUE;
}


bool edit_gmplist( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    int mor = MPROG_GLOBAL_MOB|MPROG_GLOBAL_OBJ|MPROG_GLOBAL_ROOM;
    int i;
    BUFFER *buf = buffer_new( MAX_INPUT_LENGTH );
    MPROG_GLOBAL *mprg;

    pArea = get_editing_area( ch );

    if( argument[0] != '\0' )
	mor = flag_value( NULL, mor_type_flags, argument );

    for( i = 0; i < MPROG_GLOBAL_HASH; ++i )
	for( mprg = global_progs[i]; mprg; mprg = mprg->next )
	{
	    if( mprg->area == pArea && IS_SET( mprg->allowed, mor ) )
	    {
		bprintf( buf, "&b[&r%5d&b]&g %s: %s\n\r", mprg->vnum,
			 flag_string( mud_prog_flags, &mprg->allowed ),
			 mprg->arglist );
	    }
	}
    send_to_char( buf->data, ch );
    buffer_free( buf );
    return FALSE;
}


bool redit_mlist( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMobIndex;
    AREA_DATA *pArea;
    char buf[MAX_STRING_LENGTH];
    char buf1[MAX_STRING_LENGTH * 2];
    char arg[MAX_INPUT_LENGTH];
    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 ) )
	    && pMobIndex->area == pArea )
	{
	    if( fAll || is_name( arg, pMobIndex->name ) )
	    {
		char tmp[MAX_INPUT_LENGTH];

		found = TRUE;
		sprintf( buf, "&b[&r%5d&b] &g%s ",
			pMobIndex->vnum,
			colour_strpad( tmp, capitalize( pMobIndex->short_descr ), 16 ) );
		strcat( buf1, buf );
		if( ++col % 3 == 0 )
		    strcat( buf1, "&n\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;
}


bool redit_olist( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObjIndex;
    AREA_DATA *pArea;
    char buf[MAX_STRING_LENGTH];
    char buf1[MAX_STRING_LENGTH * 2];
    char arg[MAX_INPUT_LENGTH];
    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 ) )
	    && pObjIndex->area == pArea )
	{
	    if( fAll || is_name( arg, pObjIndex->name )
		|| flag_value( NULL, type_flags, arg ) == pObjIndex->item_type )
	    {
		char tmp[MAX_INPUT_LENGTH];

		found = TRUE;
		sprintf( buf, "&b[&r%5d&b]&g %s ",
			pObjIndex->vnum,
			colour_strpad( tmp, capitalize( pObjIndex->short_descr ), 16 ) );
		strcat( buf1, buf );
		if( ++col % 3 == 0 )
		    strcat( buf1, "&n\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;
}


bool redit_mshow( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    int value;

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

    if( !is_number( argument ) )
    {
	send_to_char( "REdit:  Please specify an mobile vnum.\n\r", ch );
	return FALSE;
    }
    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;
}


bool redit_oshow( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    int value;

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

    if( !is_number( argument ) )
    {
	send_to_char( "REdit:  Please specify an object vnum.\n\r", ch );
	return FALSE;
    }
    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 && upper >= pArea->lvnum )
	    || ( upper >= pArea->uvnum && lower <= pArea->uvnum ) )
	    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.
 */
bool aedit_show( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    BUFFER *buf = buffer_new( MAX_STRING_LENGTH );

    EDIT_AREA( ch, pArea );

    bprintf( buf, "&gDescription:\n\r&w%s", pArea->description );

    bprintf( buf, "&b[&r%5d&b]&g Name: &b[&c%s&b]&n\n\r",
	     pArea->vnum, pArea->name );
    bprintf( buf, "&gPlane:        &b[&c%s&b]&n\n\r",
	     pArea->plane ? pArea->plane->name : "none" );
    bprintf( buf, "&gFile:         &b[&c%s&b]&N\n\r", pArea->filename );
    bprintf( buf, "&gVnums:        &b[&c%d&b-&c%d&b]&n\n\r",
	     pArea->lvnum, pArea->uvnum );
    bprintf( buf, "&gRecall:       &b[&c%5d&b] &y%s&n\n\r", pArea->recall,
	     get_room_index( pArea->recall )
	     ? get_room_index( pArea->recall )->name : "none" );
    bprintf( buf, "&gLevels:       &b[&c%d&b-&c%d &b(&c%d&b)]&n\n\r",
	     pArea->min, pArea->max, pArea->ave );
    bprintf( buf, "&gAve Temp:     &b[&c%5d&b]"
	     "&g     Age:          &b[&c%d&b]&n\n\r",
	     pArea->ave_temp, pArea->age );
    bprintf( buf, "&gPlayers:      &b[&c%5d&b]"
	     "&g     Mobiles:      &b[&c%d&b]&n\n\r",
	     pArea->nplayer, pArea->nmobile );
    bprintf( buf, "&gSecurity:     &b[&c%5d&b]"
	     "&g     Builders:     &b[&c%s&b]&n\n\r",
	     pArea->security, pArea->builders );
    bprintf( buf, "&gEconomy:      &b[&y%8d gold&b]&n\n\r",
	     pArea->economy );
    if( pArea->order )
    {
	bprintf( buf, "&gOrder:        &b[&c%s&b]&n %s&n\n\r",
		 pArea->order->name, pArea->order->display_name );
	bprintf( buf, "&g  Religion:   &b[&c%s&b]&n %s&n\n\r",
		 pArea->order->religion->name,
		 pArea->order->religion->display_name );
	bprintf( buf, "&g  Token Room: &b[&c%5d&b] &y%s&n\n\r",
		 pArea->token_room,
		 get_room_index( pArea->token_room )
		 ? get_room_index( pArea->token_room )->name : "None" );
    }
    if( pArea->repop && pArea->repop[0] != '\0' )
	bprintf( buf, "&gRepop:&n        %s", pArea->repop );
    bprintf( buf, "&gFlags:        &b[&c%s&b]&n\n\r",
	     flag_string( area_flags, &pArea->area_flags ) );

    send_to_char( buf->data, ch );
    buffer_free( buf );
    return FALSE;
}


bool aedit_reset( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    int save_player;

    EDIT_AREA( ch, pArea );

    save_player = pArea->nplayer;
    pArea->nplayer = 0;
    reset_area( pArea );
    pArea->nplayer = save_player;
    send_to_char( "Area reset.\n\r", ch );

    return FALSE;
}


void clear_room( ROOM_INDEX_DATA * room )
{
    OBJ_DATA *obj, *obj_next;
    CHAR_DATA *victim, *vnext;

    for( victim = room->people; victim; victim = vnext )
    {
	vnext = victim->next_in_room;
	if( victim->deleted )
	    continue;

	if( IS_NPC( victim ) )
	    extract_char( victim, TRUE );
    }

    for( obj = room->contents; obj; obj = obj_next )
    {
	obj_next = obj->next_content;
	if( obj->deleted )
	    continue;

	if( obj->item_type != ITEM_CORPSE_PC )
	    extract_obj( obj );
    }

    return;
}


bool aedit_clear( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    ROOM_INDEX_DATA *pRoom;
    int vnum;

    EDIT_AREA( ch, pArea );

    for( vnum = pArea->lvnum; vnum <= pArea->uvnum; vnum++ )
    {
	if( ( pRoom = get_room_index( vnum ) ) )
	    clear_room( pRoom );
    }

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


bool aedit_create( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;

    if( !ch->pcdata || ch->pcdata->security < 5 )
    {
	send_to_char( "You aren't authorised to create areas.\n\r", ch );
	return FALSE;
    }

    if( top_area >= INT_MAX )	/* OLC 1.1b */
    {
	send_to_char( "We're out of vnums for new areas.\n\r", ch );
	return FALSE;
    }

    if( IS_NPC( ch ) || ch->pcdata->security < 3 )
    {
	send_to_char( "You aren't allowed to create new areas, we don't trust you :p\n\r", ch );
	return FALSE;
    }

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

    wiznetf( ch, WIZ_CREATE, get_trust( ch ), "%s has just created a new area!",
	     ch->name );
    SET_BIT( pArea->area_flags, AREA_ADDED );
    send_to_char( "Area Created.\n\r", ch );
    return TRUE;		/* OLC 1.1b */
}


bool aedit_name( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;

    EDIT_AREA( ch, pArea );

    if( argument[0] == '\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;
}


bool aedit_plane( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;

    EDIT_AREA( ch, pArea );

    if( ch->pcdata->security <= 5 )
    {
	send_to_char( "You have insufficient security.\n\r", ch );
	return FALSE;
    }

    if( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  plane <$plane>\n\r", ch );
	return FALSE;
    }
    if( !plane_lookup( argument ) )
    {
	send_to_char( "AEdit: No such plane.\n\r", ch );
	return FALSE;
    }

    pArea->plane = plane_lookup( argument );

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


bool aedit_file( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char file[MAX_STRING_LENGTH];
    int i, length;
    FILE *fp;

    EDIT_AREA( ch, pArea );

    first_arg( argument, file, TRUE );	/* Forces Lowercase */

    if( argument[0] == '\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;
	}
    }

    strcat( file, ".are" );

    if( !( fp = open_file( file, "a+", TRUE ) ) )
    {
	send_to_char( "Sorry, that file cannot exist.\n\r", ch );
	return FALSE;
    }
    close_file( fp );

    log_string( "%s changing file name from %s to %s.",
	       ch->name, pArea->filename, file );
#if defined( unix )
    wiznetf( ch, WIZ_DEBUG, L_MAS, "Unlinking file %s.", pArea->filename );
    unlink( pArea->filename );
#else
    wiznetf( ch, WIZ_DEBUG, L_MAS, "Please delete old file (%s).",
	    pArea->filename );
#endif
    free_string( pArea->filename );
    pArea->filename = str_dup( file );
    save_area( pArea );

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


void junk_old_religion( AREA_DATA *pArea )
{
    RELIGION_DATA *pReligion;
    OBJ_INDEX_DATA *pObj;
    OBJ_DATA *obj;
    ROOM_INDEX_DATA *pRoom;

    if( !( pReligion = pArea->order->religion ) )
	return;
    pRoom = get_room_index( pArea->token_room );
    pObj = get_obj_index( pReligion->token );
    if( pRoom && pObj )
	for( obj = pRoom->contents; obj; obj = obj->next_content )
	    if( !obj->deleted && obj->pIndexData == pObj )
		extract_obj( obj );
    pArea->order = NULL;
    pArea->token_room = -1;
    return;
}


/*
 * Nifty little formatting function.
 */
void show_range( CHAR_DATA *ch, int low, int high, int *pos )
{
    char buf[MAX_INPUT_LENGTH];
    char buf1[MAX_INPUT_LENGTH];

    buf1[0] = '\0';

    if( high > low )
	sprintf( buf, "%d-%d", low, high );
    else
	sprintf( buf, "%d", low );
    if( *pos < 0 )				/* initial position */
    {
	*pos = strlen( buf ) + 4;
    }
    else if( *pos + strlen( buf ) > 73 )	/* end of line */
    {
	strcat( buf1, ",&n\n\r    &y" );
	*pos = strlen( buf ) + 4;
    }
    else					/* normal increment */
    {
	strcat( buf1, ", " );
	*pos += strlen( buf ) + 2;
    }
    strcat( buf1, buf );
    send_to_char( buf1, ch );
}


bool aedit_count( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    ROOM_INDEX_DATA *pRoom;
    OBJ_INDEX_DATA *pObj;
    MOB_INDEX_DATA *pMob;
    bool unused = FALSE;
    int start, i, pos;

    EDIT_AREA( ch, pArea );

    if( UPPER( argument[0] ) == 'U' )
	unused = TRUE;

    charprintf(
	ch, "&gVnums %sused so far in this area from &b[&c%d&b-&c%d&b]&n\n\r",
	( unused ) ? "un" : "", pArea->lvnum, pArea->uvnum );

    send_to_char( "&mRooms:\n\r    &y", ch );
    start = -1;
    pos = -1;
    for( i = pArea->lvnum; i <= pArea->uvnum; ++i )
    {
	pRoom = get_room_index( i );
	if( ( unused && !pRoom )
	    || ( !unused && pRoom && pRoom->area == pArea ) )
	{
	    if( start < 0 )
		start = i;
	}
	else
	{
	    if( start > 0 )
		show_range( ch, start, i - 1, &pos );
	    start = -1;
	}
    }
    if( start > 0 )
	show_range( ch, start, i - 1, &pos );
    send_to_char( "&n\n\r&mMobiles:\n\r    &y", ch );
    start = -1;
    pos = -1;
    for( i = pArea->lvnum; i <= pArea->uvnum; ++i )
    {
	pMob = get_mob_index( i );
	if( ( unused && !pMob )
	    || ( !unused && pMob && pMob->area == pArea ) )
	{
	    if( start < 0 )
		start = i;
	}
	else
	{
	    if( start > 0 )
		show_range( ch, start, i - 1, &pos );
	    start = -1;
	}
    }
    if( start > 0 )
	show_range( ch, start, i - 1, &pos );
    send_to_char( "&n\n\r&mObjects:\n\r    &y", ch );
    start = -1;
    pos = -1;
    for( i = pArea->lvnum; i <= pArea->uvnum; ++i )
    {
	pObj = get_obj_index( i );
	if( ( unused && !pObj )
	    || ( !unused && pObj && pObj->area == pArea ) )
	{
	    if( start < 0 )
		start = i;
	}
	else
	{
	    if( start > 0 )
		show_range( ch, start, i - 1, &pos );
	    start = -1;
	}
    }
    if( start > 0 )
	show_range( ch, start, i - 1, &pos );
    send_to_char( "&n\n\r", ch );
    return FALSE;
}


bool aedit_order( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    CLAN_DATA *pClan;
    char room[MAX_INPUT_LENGTH];
    ROOM_INDEX_DATA *pRoom;
    int value;
    OBJ_INDEX_DATA *pObj;
    OBJ_DATA *obj;

    if( get_trust( ch ) < L_MAS )
    {
	send_to_char( "You aren't allowed to do this.\n\r", ch );
	return FALSE;
    }

    EDIT_AREA( ch, pArea );

    if( !str_cmp( argument, "none" ) )
    {
	junk_old_religion( pArea );
	send_to_char( "Ok.\n\r", ch );
	return TRUE;
    }

    argument = one_argument( argument, room );

    if( !is_number( room ) || room[0] == '\0' )
    {
	send_to_char( "Syntax:  order <#tokenrm> <$order>\n\r", ch );
	send_to_char( "Syntax:  order none\n\r", ch );
	return FALSE;
    }

    value = atoi( room );

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

    if( !( pClan = clan_lookup( argument ) )
	|| pClan->clan_type != CLAN_ORDER )
    {
	send_to_char( "AEdit:  Religious order not found.\n\r", ch );
	return FALSE;
    }
    if( !( pObj = get_obj_index( pClan->religion->token ) ) )
    {
	send_to_char( "AEdit:  Their religion has no token.\n\r", ch );
	return FALSE;
    }

    junk_old_religion( pArea );
    obj = create_object( pObj, 0 );
    obj_to_room( obj, pRoom );
    REMOVE_BIT( obj->extra_flags, ITEM_TAKE );
    obj->item_type = ITEM_CORPSE_NPC;	/* prevent accidental purge */
    strip_events( &obj->events, evn_obj_decay );
    strip_events( &obj->events, evn_imp_grab );
    pArea->order = pClan;
    pArea->token_room = value;

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


bool aedit_age( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char age[MAX_STRING_LENGTH];

    EDIT_AREA( ch, pArea );

    one_argument( argument, age );

    if( !is_number( age ) || age[0] == '\0' || atoi( age ) < 3 )
    {
	send_to_char( "Syntax:  age <#age>\n\r", ch );
	send_to_char( "Note: age must be at least 3 minutes.\n\r", ch );
	return FALSE;
    }

    pArea->age = atoi( age );

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


bool aedit_economy( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char economy[MAX_STRING_LENGTH];

    EDIT_AREA( ch, pArea );

    one_argument( argument, economy );

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

    pArea->economy = atoi( economy );

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


bool aedit_recall( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char room[MAX_STRING_LENGTH];
    int value;

    EDIT_AREA( ch, pArea );

    one_argument( argument, room );

    if( !is_number( argument ) || argument[0] == '\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;
}


bool aedit_repop( CHAR_DATA *ch, const char *argument )
{
    char buf[MAX_STRING_LENGTH];
    AREA_DATA *pArea;

    EDIT_AREA( ch, pArea );

    if( argument[0] == '\0' )
    {
	free_string( pArea->repop );
	pArea->repop = str_dup( "" );
	send_to_char( "AEdit:  Area repop message cleared.\n\r", ch );
	return TRUE;
    }

    sprintf( buf, "%s&n\n\r", argument );

    free_string( pArea->repop );
    pArea->repop = str_dup( buf );
    pArea->repop[0] = UPPER( pArea->repop[0] );

    send_to_char( "AEdit:  Area Repop message set.\n\r", ch );
    return TRUE;
}


bool aedit_temp( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char room[MAX_STRING_LENGTH];
    int value;

    EDIT_AREA( ch, pArea );

    one_argument( argument, room );

    if( !is_number( argument ) || argument[0] == '\0' )
    {
	send_to_char( "Syntax:  temp <#temperature>\n\r", ch );
	return FALSE;
    }

    value = URANGE( -250, atoi( room ), 250 );

    pArea->ave_temp = value;

    send_to_char( "Average area temperature set.\n\r", ch );
    return TRUE;
}


bool aedit_security( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char sec[MAX_STRING_LENGTH];
    char buf[MAX_STRING_LENGTH];
    int value;

    EDIT_AREA( ch, pArea );

    one_argument( argument, sec );

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

    value = atoi( sec );

    if( value > ch->pcdata->security + 1 || value < 0 )
    {
	if( ch->pcdata->security != 0 )
	{
	    sprintf( buf, "Security is 0-%d.\n\r", ch->pcdata->security + 1 );
	    send_to_char( buf, ch );
	}
	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;
}


bool aedit_builder( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char name[MAX_STRING_LENGTH];
    char buf[MAX_STRING_LENGTH];

    EDIT_AREA( ch, pArea );

    one_argument( argument, name );

    if( name[0] == '\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( str_str( pArea->builders, name ) != '\0' )
    {
	string_replace( &pArea->builders, name, "\0", FALSE );
	pArea->builders = string_unpad( pArea->builders );

	if( pArea->builders[0] == '\0' )
	{
	    free_string( pArea->builders );
	    pArea->builders = str_dup( "None" );
	}
	send_to_char( "Builder removed.\n\r", ch );
    }
    else
    {
	buf[0] = '\0';
	if( str_str( pArea->builders, "None" ) != '\0' )
	{
	    string_replace( &pArea->builders, "None", "\0", FALSE );
	    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;
}


bool aedit_desc( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;

    EDIT_AREA( ch, pArea );

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

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


bool aedit_vnum( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char lower[MAX_STRING_LENGTH];
    char upper[MAX_STRING_LENGTH];
    int ilower;
    int iupper;

    EDIT_AREA( ch, pArea );

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

    if( !is_number( lower ) || lower[0] == '\0'
	|| !is_number( upper ) || upper[0] == '\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;
    }

    /* OLC 1.1b */
    if( ilower <= 0 || ilower >= INT_MAX || iupper <= 0 || iupper >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "AEdit:  vnum must be between 0 and %d.\n\r", INT_MAX );
	send_to_char( output, 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 );

    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;
}


bool aedit_lvnum( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char lower[MAX_STRING_LENGTH];
    int ilower;
    int iupper;

    EDIT_AREA( ch, pArea );

    one_argument( argument, lower );

    if( !is_number( lower ) || lower[0] == '\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;
    }

    /* OLC 1.1b */
    if( ilower <= 0 || ilower >= INT_MAX || iupper <= 0 || iupper >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "AEdit:  vnum must be between 0 and %d.\n\r", INT_MAX );
	send_to_char( output, 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;
}


bool aedit_uvnum( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    char upper[MAX_STRING_LENGTH];
    int ilower;
    int iupper;

    EDIT_AREA( ch, pArea );

    one_argument( argument, upper );

    if( !is_number( upper ) || upper[0] == '\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;
    }

    /* OLC 1.1b */
    if( ilower <= 0 || ilower >= INT_MAX || iupper <= 0 || iupper >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "AEdit:  vnum must be between 0 and %d.\n\r", INT_MAX );
	send_to_char( output, 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.
 */
bool redit_show( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;

    EDIT_ROOM( ch, pRoom );

    show_room( ch, pRoom );
    return FALSE;
}


void show_room( CHAR_DATA *ch, ROOM_INDEX_DATA *pRoom )
{
    char word[MAX_INPUT_LENGTH];
    BUFFER *buf = buffer_new( MAX_STRING_LENGTH );
    OBJ_DATA *obj;
    CHAR_DATA *rch;
    int door;
    bool fcnt;

    bprintf( buf, "&gDescription:\n\r&w%s", pRoom->description );

    bprintf( buf, "&b[&r%5d&b]&g Name: &b[&c%s&b]&n\n\r"
	     "&gArea:         &b[&c%5d&b] &m%s&n\n\r",
	     pRoom->vnum, pRoom->name,
	     pRoom->area->vnum, pRoom->area->name );

    bprintf( buf, "&gSector:       &b[&c%s&b]&n\n\r"
	     "&gLight:        &b[&c%5d&b]&n\n\r",
	    flag_string( sector_flags, &pRoom->sector_type ),
	    get_room_light( pRoom ) );

    bprintf( buf, "&gRoom flags:   &b[&c%s&b]&n\n\r",
	    flag_string( room_flags, &pRoom->room_flags ) );

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

	buffer_strcat( buf, "&gDesc Kwds:    &b[&c" );
	for( ed = pRoom->extra_descr; ed; ed = ed->next )
	{
	    buffer_strcat( buf, ed->keyword );
	    if( ed->next )
		buffer_strcat( buf, " " );
	}
	buffer_strcat( buf, "&b]&n\n\r" );
    }

    buffer_strcat( buf, "&gCharacters:   &b[&c" );
    fcnt = FALSE;
    for( rch = pRoom->people; rch; rch = rch->next_in_room )
    {
	/*
	 * Security as from rstat
	 */
	if( can_see( ch, rch ) )
	{
	    one_argument( rch->name, word );
	    buffer_strcat( buf, word );
	    buffer_strcat( buf, " " );
	    fcnt = TRUE;
	}
    }

    if( fcnt )
    {
	buf->data[--buf->len] = '\0';
	buffer_strcat( buf, "&b]&n\n\r" );
    }
    else
	buffer_strcat( buf, "none&b]&n\n\r" );

    buffer_strcat( buf, "&gObjects:      &b[&c" );
    fcnt = FALSE;
    for( obj = pRoom->contents; obj; obj = obj->next_content )
    {
	one_argument( obj->name, word );
	buffer_strcat( buf, word );
	buffer_strcat( buf, " " );
	fcnt = TRUE;
    }

    if( fcnt )
    {
	buf->data[--buf->len] = '\0';
	buffer_strcat( buf, "&b]&n\n\r" );
    }
    else
	buffer_strcat( buf, "none&b]&n\n\r" );

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

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

	    bprintf( buf, "&b-&w%-5s&g to &b[&r%5d&b]&g Key: &b[&r%5d&b]",
		    capitalize( dir_name[door] ),
		    pexit->to_room ? pexit->to_room->vnum : 0,
		    pexit->key );

	    /*
	     * 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 );
	    buffer_strcat( buf, " &gExit flags: &b[&c" );
	    for( ;; )
	    {
		state = one_argument( state, word );

		if( word[0] == '\0' )
		{
		    buf->data[--buf->len] = '\0';
		    buffer_strcat( buf, "&b]&n\n\r" );
		    break;
		}

		if( str_infix( word, reset_state ) )
		{
		    length = strlen( word );
		    for( i = 0; i < length; i++ )
			word[i] = toupper( word[i] );
		}
		buffer_strcat( buf, word );
		buffer_strcat( buf, " " );
	    }

	    if( pexit->keyword && pexit->keyword[0] != '\0' )
		bprintf( buf, "&gKwds: &b[&c%s&b]&n\n\r", pexit->keyword );
	    if( pexit->description && pexit->description[0] != '\0' )
		bprintf( buf, "&w%s&n", pexit->description );
	}
    }

    send_to_char( buf->data, ch );
    buffer_free( buf );
    return;
}


/* OLC 1.1b */
/*****************************************************************************
  Name:		change_exit
  Purpose:	Command interpreter for changing exits.
  Called by:	redit_<dir>.  This is a local function.
  ****************************************************************************/
bool change_exit( CHAR_DATA *ch, const char *argument, int door )
{
    ROOM_INDEX_DATA *pRoom;
    ROOM_INDEX_DATA *pToRoom;
    char command[MAX_INPUT_LENGTH];
    char arg[MAX_INPUT_LENGTH];
    char total_arg[MAX_STRING_LENGTH];
    int rev;
    int value = 0;

    EDIT_ROOM( ch, pRoom );

    /* Often used data. */
    rev = rev_dir[door];

    if( argument[0] == '\0' )
    {
	do_help( ch, "OLCEXIT" );
	return FALSE;
    }

    /*
     * Now parse the arguments.
     */
    strcpy( total_arg, argument );
    argument = one_argument( argument, command );
    if( str_cmp( command, "name" ) && strcmp( command, "namerev" ) )
	argument = one_argument( argument, arg );

    if( !str_cmp( command, "delete" ) )
    {
	if( !pRoom->exit[door] )
	{
	    send_to_char( "REdit:  Exit does not exist.\n\r", ch );
	    return FALSE;
	}

	/*
	 * Remove To Room Exit.
	 */
	if( pRoom->exit[door]->to_room && pRoom->exit[door]->to_room->exit[rev]
	    && pRoom->exit[door]->to_room->exit[rev]->to_room == pRoom )
	{
	    free_exit( pRoom->exit[door]->to_room->exit[rev] );
	    pRoom->exit[door]->to_room->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;
    }

    /*
     * Create a two-way exit.
     */
    if( !str_cmp( command, "link" ) )
    {
	EXIT_DATA *pExit;
	ROOM_INDEX_DATA *pLinkRoom;

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

	if( !( pLinkRoom = get_room_index( atoi( arg ) ) ) )
	{
	    send_to_char( "REdit:  Non-existant room.\n\r", ch );
	    return FALSE;
	}

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

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

	if( !pRoom->exit[door] )		/* No exit.		*/
	{
	    pRoom->exit[door] = new_exit( );
	    pRoom->exit[door]->in_room = pRoom;
	}

	pRoom->exit[door]->to_room = pLinkRoom;	/* Assign data.		*/

	pExit = new_exit( );			/* No remote exit.	*/
	pExit->in_room = pLinkRoom;

	pExit->to_room = ch->in_room;		/* Assign data.		*/

	pLinkRoom->exit[rev] = pExit;		/* Link exit to room.	*/

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

    /*
     * Create room and make two-way exit.
     */
    if( !str_cmp( command, "dig" ) )
    {
	char buf[MAX_INPUT_LENGTH];

	if( arg[0] == '\0' || !is_number( arg ) )
	{
	    send_to_char( "Syntax:  <direction> dig <vnum>\n\r", ch );
	    return FALSE;
	}

	redit_create( ch, arg );	/* Create the room.	*/
	sprintf( buf, "link %s", arg );
	change_exit( ch, buf, door );	/* Create the exits.	*/
	return TRUE;
    }

    /*
     * Create one-way exit.
     */
    if( !str_cmp( command, "room" ) )
    {
	ROOM_INDEX_DATA *pLinkRoom;

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

	if( !( pLinkRoom = get_room_index( atoi( arg ) ) ) )
	{
	    send_to_char( "REdit:  Non-existant room.\n\r", ch );
	    return FALSE;
	}

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

	pRoom->exit[door]->to_room = pLinkRoom;

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

    if( !str_cmp( command, "remove" ) )
    {
	if( arg[0] == '\0' )
	{
	    send_to_char(
		"Syntax:  <direction> remove <key/name/desc>\n\r", ch );
	    return FALSE;
	}

	if( !pRoom->exit[door] )
	{
	    send_to_char( "REdit:  Exit does not exist.\n\r", ch );
	    return FALSE;
	}

	if( !str_cmp( arg, "key" ) )
	{
	    pRoom->exit[door]->key = -1;
	    send_to_char( "Exit key removed.\n\r", ch );
	    return TRUE;
	}

	if( !str_cmp( arg, "name" ) )
	{
	    free_string( pRoom->exit[door]->keyword );
	    pRoom->exit[door]->keyword = &str_empty[0];
	    send_to_char( "Exit name removed.\n\r", ch );
	    return TRUE;
	}

	if( arg[0] == 'd' && !str_prefix( argument, "description" ) )
	{
	    free_string( pRoom->exit[door]->description );
	    pRoom->exit[door]->description = &str_empty[0];
	    send_to_char( "Exit description removed.\n\r", ch );
	    return TRUE;
	}

	send_to_char( "Syntax:  <direction> remove <key/name/desc>\n\r", ch );
	return FALSE;
    }

    if( !str_cmp( command, "key" ) || !str_cmp( command, "keyrev" ) )
    {
	OBJ_INDEX_DATA *pObjIndex;

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

	if( !( pObjIndex = get_obj_index( atoi( arg ) ) ) )
	{
	    send_to_char( "REdit:  Item does not exist.\n\r", ch );
	    return FALSE;
	}

	if( pObjIndex->item_type != ITEM_KEY )
	{
	    send_to_char( "REdit:  Item is not a key.\n\r", ch );
	    return FALSE;
	}

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

	pRoom->exit[door]->key = pObjIndex->vnum;
	/*
	 * Set key of connected room.
	 * Skip one-way exits and non-existant rooms.
	 */
	if( !str_cmp( command, "keyrev" ) &&
	    ( pToRoom = pRoom->exit[door]->to_room ) && pToRoom->exit[rev] )
	{
	    pToRoom->exit[rev]->key = pObjIndex->vnum;
	}

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

    if( !str_cmp( command, "name" ) || !str_cmp( command, "namerev" ) )
    {
	if( argument[0] == '\0' )
	{
	    send_to_char( "Syntax:  <direction> name <string>\n\r", ch );
	    return FALSE;
	}

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

	free_string( pRoom->exit[door]->keyword );
	pRoom->exit[door]->keyword = str_dup( argument );
	/*
	 * Set name of connected room.
	 * Skip one-way exits and non-existant rooms.
	 */
	if( !str_cmp( command, "namerev" ) &&
	    ( pToRoom = pRoom->exit[door]->to_room ) && pToRoom->exit[rev] )
	{
	    free_string( pToRoom->exit[rev]->keyword );
	    pToRoom->exit[rev]->keyword = str_dup( argument );
	}

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

    if( command[0] == 'd' && !str_prefix( command, "description" ) )
    {
	if( arg[0] == '\0' )
	{
	    if( !pRoom->exit[door] )
	    {
		pRoom->exit[door] = new_exit( );
		pRoom->exit[door]->in_room = pRoom;
	    }

	    string_edit( 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( flag_value( &value, exit_flags, total_arg ) != NO_FLAG )
    {
	/*
	 * Create an exit if none exists.
	 */
	if( !pRoom->exit[door] )
	{
	    pRoom->exit[door] = new_exit( );
	    pRoom->exit[door]->in_room = pRoom;
	}

	/*
	 * Set door bits for this room.
	 */
	TOGGLE_BIT( pRoom->exit[door]->rs_flags, value );
	pRoom->exit[door]->exit_info = pRoom->exit[door]->rs_flags;

	/*
	 * Set door bits of connected room.
	 * Skip one-way exits and non-existant rooms.
	 */
	if( ( pToRoom = pRoom->exit[door]->to_room ) && pToRoom->exit[rev] )
	{
	    TOGGLE_BIT( pToRoom->exit[rev]->rs_flags, value );
	    pToRoom->exit[rev]->exit_info = pToRoom->exit[rev]->rs_flags;
	}

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

    return FALSE;
}


bool redit_north( CHAR_DATA *ch, const char *argument )
{
    if( change_exit( ch, argument, DIR_NORTH ) )
	return TRUE;

    return FALSE;
}


bool redit_south( CHAR_DATA *ch, const char *argument )
{
    if( change_exit( ch, argument, DIR_SOUTH ) )
	return TRUE;

    return FALSE;
}


bool redit_east( CHAR_DATA *ch, const char *argument )
{
    if( change_exit( ch, argument, DIR_EAST ) )
	return TRUE;

    return FALSE;
}


bool redit_west( CHAR_DATA *ch, const char *argument )
{
    if( change_exit( ch, argument, DIR_WEST ) )
	return TRUE;

    return FALSE;
}


bool redit_up( CHAR_DATA *ch, const char *argument )
{
    if( change_exit( ch, argument, DIR_UP ) )
	return TRUE;

    return FALSE;
}


bool redit_down( CHAR_DATA *ch, const char *argument )
{
    if( change_exit( ch, argument, DIR_DOWN ) )
	return TRUE;

    return FALSE;
}


/* OLC 1.1b */
bool redit_move( CHAR_DATA *ch, const char *argument )
{
    interpret( ch, argument );
    return FALSE;
}


bool redit_mpadd( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;
    int type;
    int allowed[] = { GLOBAL_PROG, ACT_PROG, SPEECH_PROG, RAND_PROG,
		      GREET_PROG, ALL_GREET_PROG, LEAVE_PROG, TIME_PROG,
		      REPOP_PROG, COMMAND_PROG, LOOK_PROG, SLEEP_PROG,
		      REST_PROG, DROP_PROG, -1 };

    EDIT_ROOM( ch, pRoom );

    if( ( type = edit_mpadd( ch, &pRoom->mudprogs, argument, allowed ) ) == PROG_ERROR )
	return FALSE;
    xSET_BIT( pRoom->progtypes, type );

    return TRUE;
}


bool redit_mpdelete( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;
    EDIT_ROOM( ch, pRoom );

    return edit_mpdelete( ch, &pRoom->mudprogs, argument );
}


bool redit_mpedit( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;

    EDIT_ROOM( ch, pRoom );

    return edit_mpedit( ch, pRoom->mudprogs, argument );
}


bool redit_mpshow( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;

    EDIT_ROOM( ch, pRoom );

    edit_mpshow( ch, pRoom->mudprogs, argument );
    return FALSE;
}


bool redit_ed( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;
    EXTRA_DESCR_DATA *ed;
    char command[MAX_INPUT_LENGTH];

    EDIT_ROOM( ch, pRoom );

    argument = one_argument( argument, command );

    if( command[0] == '\0' || argument[0] == '\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( argument[0] == '\0' )
	{
	    send_to_char( "Syntax:  ed add <keyword>\n\r", ch );
	    return FALSE;
	}

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

	string_edit( ch, &ed->description );

	return TRUE;
    }


    if( !str_cmp( command, "edit" ) )
    {
	if( argument[0] == '\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( argument, ed->keyword ) )
		break;
	}

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

	string_edit( ch, &ed->description );

	return TRUE;
    }


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

	if( argument[0] == '\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( argument, 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( argument[0] == '\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( argument, ed->keyword ) )
		break;
	}

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

	/* OLC 1.1b */
	if( strlen( ed->description ) >= ( MAX_STRING_LENGTH - 4 ) )
	{
	    send_to_char( "String too long to be formatted.\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;
}


bool redit_create( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    ROOM_INDEX_DATA *pRoom;
    int value;
    int iHash;

    value = atoi( argument );

    /* OLC 1.1b */
    if( argument[0] == '\0' || value <= 0 || value >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "Syntax:  create <0 < #vnum < %d>\n\r", INT_MAX );
	send_to_char( output, ch );
	return FALSE;
    }

    if( argument[0] == '\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;
    pRoom->name = str_dup( "A Room" );
    pRoom->description = str_dup( "" );

    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;

    wiznetf( ch, WIZ_CREATE, get_trust( ch ), "%s has created a new room %d.",
	     ch->name, value );
    send_to_char( "Room created.\n\r", ch );
    return TRUE;
}


bool redit_clone( CHAR_DATA *ch, const char *argument )
{
    AREA_DATA *pArea;
    ROOM_INDEX_DATA *curr;
    ROOM_INDEX_DATA *pRoom;
    int value;
    int iHash;

    EDIT_ROOM( ch, curr );

    value = atoi( argument );

    /* OLC 1.1b */
    if( argument[0] == '\0' || value <= 0 || value >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "Syntax:  create <0 < #vnum < %d>\n\r", INT_MAX );
	send_to_char( output, ch );
	return FALSE;
    }

    if( argument[0] == '\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;
    pRoom->name = str_dup( curr->name );
    pRoom->description = str_dup( curr->description );
    pRoom->room_flags = curr->room_flags;
    pRoom->sector_type = curr->sector_type;

    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;
}


bool redit_name( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;

    EDIT_ROOM( ch, pRoom );

    if( argument[0] == '\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;
}


bool redit_desc( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;

    EDIT_ROOM( ch, pRoom );

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

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


bool redit_format( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;

    EDIT_ROOM( ch, pRoom );

    /* OLC 1.1b */
    if( strlen( pRoom->description ) >= ( MAX_STRING_LENGTH - 4 ) )
    {
	send_to_char( "String too long to be formatted.\n\r", ch );
	return FALSE;
    }

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

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


bool redit_mreset( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;
    MOB_INDEX_DATA *pMobIndex;
    CHAR_DATA *newmob;
    char arg[MAX_INPUT_LENGTH];

    RESET_DATA *pReset;
    char output[MAX_STRING_LENGTH];

    EDIT_ROOM( ch, pRoom );

    argument = one_argument( argument, arg );

    if( arg[0] == '\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->arg1 = pMobIndex->vnum;
    pReset->arg2 = is_number( argument ) ? atoi( argument ) : MAX_MOB;
    add_reset( pRoom, pReset, 0 /* Last slot */ );

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

    sprintf(
	output, "&g%s &b[&r%d&b]&w has been loaded and added to resets.&n\n\r"
	"&wThere will be a maximum of &c%d&w loaded to this room.&n\n\r",
	capitalize( pMobIndex->short_descr ),
	pMobIndex->vnum, pReset->arg2 );
    send_to_char( output, ch );
    act( "&g$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_olc[] =
{
    { WEAR_NONE,		ITEM_TAKE		},
    { WEAR_HEAD,		ITEM_WEAR_HEAD		},
    { WEAR_HORNS,		ITEM_WEAR_HORNS		},
    { WEAR_EAR_L,		ITEM_WEAR_EAR		},
    { WEAR_EAR_R,		ITEM_WEAR_EAR		},
    { WEAR_FACE,		ITEM_WEAR_FACE		},
    { WEAR_NOSE,		ITEM_WEAR_NOSE		},
    { WEAR_NECK_1,		ITEM_WEAR_NECK		},
    { WEAR_NECK_2,		ITEM_WEAR_NECK		},
    { WEAR_SHOULDERS,		ITEM_WEAR_SHOULDERS	},
    { WEAR_WINGS,		ITEM_WEAR_WINGS		},
    { WEAR_FLOAT_L,		ITEM_FLOAT		},
    { WEAR_FLOAT_R,		ITEM_FLOAT		},
    { WEAR_ARMS,		ITEM_WEAR_ARMS		},
    { WEAR_WRIST_L,		ITEM_WEAR_WRIST		},
    { WEAR_WRIST_R,		ITEM_WEAR_WRIST		},
    { WEAR_HANDS,		ITEM_WEAR_HANDS		},
    { WEAR_FINGER_L,		ITEM_WEAR_FINGER	},
    { WEAR_FINGER_R,		ITEM_WEAR_FINGER	},
    { WEAR_WIELD_R,		ITEM_WIELD		},
    { WEAR_WIELD_L,		ITEM_WIELD		},
    { WEAR_WIELD_DOUBLE,	ITEM_WIELD_DOUBLE	},
    { WEAR_HOLD_L,		ITEM_HOLD		},
    { WEAR_HOLD_R,		ITEM_HOLD		},
    { WEAR_SHIELD,		ITEM_WEAR_SHIELD	},
    { WEAR_BODY,		ITEM_WEAR_BODY		},
    { WEAR_LEGS,		ITEM_WEAR_LEGS		},
    { WEAR_WAIST,		ITEM_WEAR_WAIST		},
    { WEAR_ANKLE_L,		ITEM_WEAR_ANKLE		},
    { WEAR_ANKLE_R,		ITEM_WEAR_ANKLE		},
    { WEAR_FEET,		ITEM_WEAR_FEET		},
    { WEAR_JUGGLED,		0			},
    { 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_olc[flag].wear_bit != NO_FLAG; flag++ )
    {
	if( IS_SET( bits, wear_table_olc[flag].wear_bit ) && --count < 1 )
	    return wear_table_olc[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_olc[flag].wear_loc != NO_FLAG; flag++ )
    {
	if( loc == wear_table_olc[flag].wear_loc )
	    return wear_table_olc[flag].wear_bit;
    }

    return 0;
}


bool redit_oreset( CHAR_DATA *ch, const char *argument )
{
    ROOM_INDEX_DATA *pRoom;
    OBJ_INDEX_DATA *pObjIndex;
    OBJ_DATA *newobj;
    OBJ_DATA *to_obj;
    CHAR_DATA *to_mob;
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];

    RESET_DATA *pReset;
    char output[MAX_STRING_LENGTH];

    EDIT_ROOM( ch, pRoom );

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

    if( arg1[0] == '\0' || !is_number( arg1 ) )
    {
	send_to_char( "Syntax:  oreset <#vnum> <args>\n\r", ch );
	send_to_char( "	     -no arg                = 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( arg1 ) ) ) )
    {
	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->arg1 = pObjIndex->vnum;
	pReset->arg2 = 0;
	add_reset( pRoom, pReset, 0 /* Last slot */ );

	newobj = create_object( pObjIndex, 0 );
	obj_to_room( newobj, pRoom );

	sprintf(
	    output, "&g%s&n [%d]&w has been loaded and added to resets.&n\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 ) ) )
    {
	pReset = new_reset_data( );
	pReset->command = 'P';
	pReset->arg1 = pObjIndex->vnum;
	pReset->arg2 = to_obj->pIndexData->vnum;
	add_reset( pRoom, pReset, 0 /* Last slot */ );

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

	sprintf( output, "&g%s&n &b[&r%d&b]&w has been loaded into "
		"&g%s &b[&r%d&b]&w and added to resets.&n\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(  flag_value( &wear_loc, 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,
		    "&g%s&n &b[&r%d&b]&w has wear flags: &b[&c%s&b]&n\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( wear_loc != WEAR_NONE && get_eq_char( to_mob, wear_loc ) )
	{
	    send_to_char( "REdit:  Object already equipped.\n\r", ch );
	    return FALSE;
	}

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

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

	if( to_mob->pIndexData->pShop )	/* Shop-keeper? */
	{
	    newobj = create_object( pObjIndex, 0 );
	    if( pReset->arg2 == WEAR_NONE )
		SET_BIT( newobj->extra_flags, ITEM_INVENTORY );
	}
	else
	    newobj = create_object( pObjIndex, to_mob->level - 2 );

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

	sprintf( output, "&g%s&n &b[&r%d&b]&w has been loaded "
		 "%s of &g%s&n &b[&r%d&b]&w and added to resets.&n\n\r",
		 capitalize( pObjIndex->short_descr ),
		 pObjIndex->vnum,
		 flag_string( wear_loc_strings, &pReset->arg2 ),
		 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( "&g$n has created $p!", ch, newobj, NULL, TO_ROOM );
    return TRUE;
}


/*
 * Object Editor Functions.
 */
void show_obj_values( int type, int value[], BUFFER *buf )
{
    ROOM_INDEX_DATA *room;

    switch( type )
    {
    default:			/* No values. */
	break;

    case ITEM_CORPSE_PC:
    case ITEM_CORPSE_NPC:
	bprintf( buf, "&b[&cv0&b]&g Corpse Race: &b[&c%s&b]&n\n\r",
		 ( value[0] < 0 || value[0] >= MAX_RACE ) ? "none"
		 : race_table[value[0]].name );
	break;

    case ITEM_ARMOUR:
	if( value[1] < 0 )
	    bprintf( buf, "&b[&cv0&b]&g Armour Class: &b[&c%d&b]&n\n\r"
		     "&b[&cv1&b]&g Armour Size:  &b[&cfits all&b]&n\n\r",
		     value[0] );
	else
	    bprintf( buf, "&b[&cv0&b]&g Armour Class: &b[&c%d&b]&n\n\r"
		     "&b[&cv1&b]&g Armour Size:  &b[&c%d&b]&n\n\r",
		     value[0], value[1] );
	break;

    case ITEM_PORTAL:
	room = get_room_index( value[0] );
	bprintf( buf, "&b[&cv0&b]&g Destination:  &b[&r%d&b]&y %s&n\n\r",
		 value[0], ( room ) ? room->name : "none" );
	break;

    case ITEM_EXPLOSIVE:
	bprintf( buf, "&b[&cv0&b]&g Explosive Level: &b[&c%d&b]&n\n\r",
		 value[0] );
	break;

    case ITEM_LIGHT:
	if( value[2] == -1 )
	    bprintf( buf, "&b[&cv2&b]&g Light:	&wInfinite&b[&c-1&b]&n\n\r" );
	else
	    bprintf( buf, "&b[&cv2&b]&g Light:	&b[&c%d&b]&n\n\r", value[2] );
	break;

    case ITEM_WAND:
    case ITEM_STAFF:
	bprintf( buf,
		 "&b[&cv0&b]&g Level:          &b[&c%d&b]&n\n\r"
		 "&b[&cv1&b]&g Charges Total:  &b[&c%d&b]&n\n\r"
		 "&b[&cv2&b]&g Charges Left:   &b[&c%d&b]&n\n\r"
		 "&b[&cv3&b]&g Spell:          &y%s&n\n\r",
		 value[0], value[1], value[2],
		 value[3] != -1 ? skill_table[value[3]].name : "none" );
	break;

    case ITEM_PLANT:
    case ITEM_SCROLL:
    case ITEM_POTION:
    case ITEM_PILL:
	bprintf( buf,
		 "&b[&cv0&b]&g Level:  &b[&c%d&b]&n\n\r"
		 "&b[&cv1&b]&g Spell:  &y%s\n\r"
		 "&b[&cv2&b]&g Spell:  &y%s\n\r"
		 "&b[&cv3&b]&g Spell:  &y%s\n\r",
		 value[0],
		 value[1] != -1 ? skill_table[value[1]].name : "none",
		 value[2] != -1 ? skill_table[value[2]].name : "none",
		 value[3] != -1 ? skill_table[value[3]].name : "none" );
	break;

    case ITEM_WEAPON:
	bprintf( buf,
		 "&b[&cv0&b]&g Offensive spell:&y%s&n\n\r"
		 "&b[&cv1&b]&g Damage minimum: &b[&c%d&b]&n\n\r"
		 "&b[&cv2&b]&g Damage maximum: &b[&c%d&b]&n\n\r"
		 "&b[&cv3&b]&g Type:           &y%s&n\n\r",
		 ( value[0] >= 0 && value[0] < MAX_SKILL )
		 ? skill_table[value[0]].name : "none",
		 value[1], value[2],
		 flag_string( weapon_flags, &value[3] ) );
	break;

    case ITEM_CONTAINER:
	bprintf( buf,
		 "&b[&cv0&b]&g Weight:      &b[&c%d &bkg]&n\n\r"
		 "&b[&cv1&b]&g Flags:       &b[&c%s&b]&n\n\r"
		 "&b[&cv2&b]&g Key:         &y%s &b[&r%d&b]&n\n\r",
		 value[0],
		 flag_string( container_flags, &value[1] ),
		 get_obj_index( value[2] )
		 ? get_obj_index( value[2] )->short_descr
		 : "none", value[2] );
	break;

    case ITEM_DRINK_CON:
	bprintf( buf,
		 "&b[&cv0&b]&g Liquid Total: &b[&c%d&b]&n\n\r"
		 "&b[&cv1&b]&g Liquid Left:  &b[&c%d&b]&n\n\r"
		 "&b[&cv2&b]&g Liquid:       &y%s&n\n\r"
		 "&b[&cv3&b]&g Poisoned:     &y%s&n\n\r",
		 value[0], value[1],
		 flag_string( liquid_flags, &value[2] ),
		 value[3] != 0 ? "Yes" : "No" );
	break;

    case ITEM_FOUNTAIN:
	bprintf( buf,
		 "&b[&cv2&b]&g Liquid:       &y%s&n\n\r",
		 flag_string( liquid_flags, &value[2] ) );
	break;

    case ITEM_FOOD:
	bprintf( buf,
		 "&b[&cv0&b]&g Food hours: &b[&c%d&b]&n\n\r"
		 "&b[&cv3&b]&g Poisoned:   &y%s&n\n\r",
		 value[0],
		 value[3] != 0 ? "Yes" : "No" );
	break;

    case ITEM_LIMB:
	bprintf( buf,
		 "&b[&cv0&b]&g Limbs:      &b[&c%s&b]&n\n\r"
		 "&b[&cv3&b]&g Poisoned:   &y%s&n\n\r",
		 flag_string( body_part_flags, &value[0] ),
		 value[3] != 0 ? "Yes" : "No" );
	break;

    case ITEM_MONEY:
	bprintf( buf, "&b[&cv0&b]&g Gold:   &b[&c%d&b]&n\n\r", value[0] );
	break;

    case ITEM_TREASURE:
	bprintf( buf, "&b[&cv0&b]&g Value:  &b[&c%d&b]&n\n\r", value[0] );
	break;

    case ITEM_BOOK:
	bprintf( buf,
		 "&b[&cv0&b]&g Spell:         &y%s&n\n\r"
		 "&b[&cv1&b]&g %%age per study &b[&c%d%%&b]&n\n\r"
		 "&b[&cv2&b]&g Maximum %%age 1 &b[&c%d%%&b]&n\n\r"
		 "&b[&cv3&b]&g Maximum %%age 2 &b[&c%d%%&b]&n\n\r"
		 "&c*1 &b- Relative to the characters normal adept level.&n\n\r"
		 "&c*2 &b- An absolute maximum.&n\n\r",
		 value[0] > 0 ? skill_table[value[0]].name : "none",
		 value[1], value[2], value[3] );
	break;

    case ITEM_GEM:
	bprintf( buf,
		 "&b[&cv0&b]&g Magic Sphere:   &b[&c%s&b]&n\n\r"
		 "&b[&cv1&b]&g Capacity:       &b[&c%d&b]&n\n\r"
		 "&b[&cv2&b]&g Current Amount: &b[&c%d&b]&n\n\r",
		 flag_string( magic_flags, &value[0] ),
		 value[1], value[2] );
	break;

    case ITEM_FURNITURE:
	bprintf( buf,
		 "&b[&cv0&b]&g Flags:        &b[&c%s&b]&n\n\r"
		 "&b[&cv1&b]&g Max People:   &b[&c%d&b]&n\n\r"
		 "&b[&cv2&b]&g Health Bonus: &b[&c%d%%&b]&n\n\r"
		 "&b[&cv3&b]&g Mana Bonus:   &b[&c%d%%&b]&n\n\r",
		 flag_string( furniture_flags, &value[0] ),
		 value[1], value[2], value[3] );
	break;
    }
    return;
}


bool set_obj_values( CHAR_DATA *ch, OBJ_INDEX_DATA * pObj, int value_num,
		     const char *argument )
{
    BUFFER *buf = buffer_new( MAX_INPUT_LENGTH );


    switch( pObj->item_type )
    {
    default:
	break;

    case ITEM_GEM:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_GEM" );
	    buffer_free( buf );
	    return FALSE;
	case 0:
	    buffer_strcat( buf, "Gem type: " );
	    if( flag_value( NULL, magic_flags, argument ) == NO_FLAG )
	    {
		buffer_strcat( buf, "Bad magic type '? magic'.\n\r" );
		send_to_char( buf->data, ch );
		buffer_free( buf );
		return FALSE;
	    }
	    else
	    {
		pObj->value[0] = flag_value( NULL, magic_flags, argument );
		buffer_strcat( buf, "Sphere set.\n\r" );
	    }
	    break;
	case 1: case 2:
	    pObj->value[value_num] = atoi( argument );
	    buffer_strcat( buf, "Gem value set.\n\r\n\r" );
	    break;
	}
	break;

    case ITEM_FURNITURE:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_FURNITURE" );
	    buffer_free( buf );
	    return FALSE;
	case 0:
	    buffer_strcat( buf, "Furniture type: " );
	    if( flag_value( NULL, furniture_flags, argument ) == NO_FLAG )
	    {
		buffer_strcat( buf, "Bad furniture type '? furniture'.\n\r" );
		send_to_char( buf->data, ch );
		buffer_free( buf );
		return FALSE;
	    }
	    else
	    {
		TOGGLE_BIT( pObj->value[0],
			    flag_value( NULL, furniture_flags, argument ) );
		buffer_strcat( buf, "Flags set.\n\r" );
	    }
	    break;
	case 1: case 2: case 3:
	    pObj->value[value_num] = atoi( argument );
	    buffer_strcat( buf, "Furniture value set.\n\r\n\r" );
	    break;
	}
	break;

    case ITEM_PORTAL:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_PORTAL" );
	    buffer_free( buf );
	    return FALSE;
	case 0:
	    buffer_strcat( buf, "Portal Destination: " );
	    pObj->value[0] = atoi( argument );
	    if( !get_room_index( pObj->value[0] ) )
	    {
		pObj->value[0] = ROOM_VNUM_TEMPLE;
		send_to_char( "That room couldn't be found.\n\r", ch );
		buffer_free( buf );
		return FALSE;
	    }
	    else
	    {
		buffer_strcat( buf, "Successful change.\n\r\n\r" );
	    }
	    break;
	}
	break;

    case ITEM_EXPLOSIVE:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_EXPLOSIVE" );
	    buffer_free( buf );
	    return FALSE;
	case 0:
	    buffer_strcat( buf, "EXPLOSIVE LEVEL SET.\n\r\n\r" );
	    pObj->value[0] = atoi( argument );
	    break;
	}
	break;

    case ITEM_LIGHT:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_LIGHT" );
	    buffer_free( buf );
	    return FALSE;
	case 2:
	    buffer_strcat( buf, "HOURS OF LIGHT SET.\n\r\n\r" );
	    pObj->value[2] = atoi_special( argument );
	    break;
	}
	break;

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

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

    case ITEM_WEAPON:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_WEAPON" );
	    buffer_free( buf );
	    return FALSE;
	case 0:
	    buffer_strcat( buf, "WEAPON SPELL SET.\n\r\n\r" );
	    pObj->value[0] = skill_lookup( argument );
	    break;
	case 1:
	    buffer_strcat( buf, "MINIMUM DAMAGE SET.\n\r\n\r" );
	    pObj->value[1] = atoi( argument );
	    break;
	case 2:
	    buffer_strcat( buf, "MAXIMUM DAMAGE SET.\n\r\n\r" );
	    pObj->value[2] = atoi( argument );
	    break;
	case 3:
	    buffer_strcat( buf, "WEAPON TYPE SET.\n\r\n\r" );
	    pObj->value[3] = flag_value( NULL, weapon_flags, argument );
	    break;
	}
	break;

    case ITEM_ARMOUR:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_ARMOUR" );
	    buffer_free( buf );
	    return FALSE;
	case 1:
	    buffer_strcat( buf, "ARMOUR SIZE SET.\n\r\n\r" );
	    pObj->value[1] = atoi( argument );
	    break;
	}
	break;

    case ITEM_CORPSE_PC:
    case ITEM_CORPSE_NPC:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_CORPSE" );
	    buffer_free( buf );
	    return FALSE;
	case 0:
	    buffer_strcat( buf, "CORPSE RACE SET.\n\r\n\r" );
	    pObj->value[0] = race_lookup( argument );
	    break;
	}
	break;

    case ITEM_CONTAINER:
	switch( value_num )
	{
	    int value;

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

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

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

    case ITEM_FOUNTAIN:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_FOUNTAIN" );
	    buffer_free( buf );
	    return FALSE;
	case 2:
	    buffer_strcat( buf, "LIQUID TYPE SET.\n\r\n\r" );
	    pObj->value[2] = flag_value( NULL, liquid_flags, argument );
	    break;
	}
	break;

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

    case ITEM_LIMB:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_LIMB" );
	    buffer_free( buf );
	    return FALSE;
	case 0:
	    if( flag_value( NULL, body_part_flags, argument ) == NO_FLAG )
	    {
		send_to_char( "Invalid Limb.\n\r", ch );
		buffer_free( buf );
		return FALSE;
	    }
	    buffer_strcat( buf, "LIMB VALUE SET.\n\r\n\r" );
	    TOGGLE_BIT( pObj->value[0],
			flag_value( NULL, body_part_flags, argument ) );
	    break;
	case 3:
	    buffer_strcat( buf, "POISON VALUE TOGGLED.\n\r\n\r" );
	    pObj->value[3] = ( pObj->value[3] == 0 ) ? 1 : 0;
	    break;
	}
	break;


    case ITEM_MONEY:
    case ITEM_TREASURE:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_MONEY" );
	    buffer_free( buf );
	    return FALSE;
	case 0:
	    buffer_strcat( buf, "GOLD VALUE SET.\n\r\n\r" );
	    pObj->value[0] = atoi_special( argument );
	    break;
	}
	break;

    case ITEM_BOOK:
	switch( value_num )
	{
	default:
	    do_help( ch, "ITEM_BOOK" );
	    buffer_free( buf );
	    return FALSE;
	case 0:
	    buffer_strcat( buf, "SPELL/SKILL SET.\n\r" );
	    pObj->value[0] = skill_lookup( argument );
	    break;
	case 1:
	    buffer_strcat( buf, "PERCENTAGE GAIN PER STUDY SET.\n\r" );
	    pObj->value[1] = URANGE( 0, atoi( argument ), 100 );
	    break;
	case 2:
	    buffer_strcat( buf, "RELATIVE MAXIMUM SKILL LEVEL FROM STUDYING SET.\n\r" );
	    pObj->value[2] = URANGE( -100, atoi( argument ), 200 );
	    break;
	case 3:
	    buffer_strcat( buf, "ABSOLUTE MAXIMUM SKILL LEVEL FROM STUDYING SET.\n\r" );
	    pObj->value[2] = URANGE( 0, atoi( argument ), 200 );
	    break;
	}
	break;
    }

    show_obj_values( pObj->item_type, pObj->value, buf );
    send_to_char( buf->data, ch );
    buffer_free( buf );

    return TRUE;
}


bool oedit_show( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    BUFFER *buf = buffer_new( MAX_STRING_LENGTH );
    char *p;
    AFFECT_DATA *paf;
    int cnt;

    EDIT_OBJ( ch, pObj );

    bprintf( buf, "&b[&r%5d&b]&g Name: &b[&c%s&b]&n\n\r",
	     pObj->vnum, pObj->name );
    bprintf( buf, "&gArea:         &b[&c%5d&b]&m %s&n\n\r",
	     !pObj->area ? -1 : pObj->area->vnum,
	     !pObj->area ? "No Area" : pObj->area->name );
    bprintf( buf, "&gLevel:        &b[&c%5d&b]"
	     "&g       Repop:       &b[&c%d&b/&c1000&b]&n\n\r",
	     pObj->level, pObj->reset_chance );
    bprintf( buf, "&gWeight:       &b[&c%5d&b]"
	     "&g       Cost:        &b[&c%5s&b]&n\n\r",
	     pObj->weight, int_to_str_special( pObj->cost ) );
    bprintf( buf, "&gType:         &b[&c%s&b]&n\n\r",
	     flag_string( type_flags, &pObj->item_type ) );
    bprintf( buf, "&gWear flags:   &b[&c%s&b]&n\n\r",
	     flag_string( wear_flags, &pObj->wear_flags ) );
    bprintf( buf, "&gExtra flags:  &b[&c%s&b]&n\n\r",
	     flag_string( extra_flags, &pObj->extra_flags ) );
    bprintf( buf, "&gRequired:     &b[&c%s&b]&n\n\r",
	     ( pObj->required_skill > 0 )
	     ? skill_table[pObj->required_skill].name : "none" );
    bprintf( buf, "&gMaterial:     &b[&c%s&b]&n\n\r"
	     "&gCondition:    &b[&c%3d.%d%%&b]&n\n\r",
	     flag_string( material_flags, &pObj->material ),
	     pObj->condition / 10, pObj->condition % 10 );

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

	buffer_strcat( buf, "&gEx desc kwd:  " );

	for( ed = pObj->extra_descr; ed; ed = ed->next )
	{
	    buffer_strcat( buf, "&b[&c" );
	    buffer_strcat( buf, ed->keyword );
	    buffer_strcat( buf, "&b]" );
	}

	buffer_strcat( buf, "&n\n\r" );
    }

    bprintf( buf, "&gShort desc:   &w%s&n\n\r&gLong desc:\n\r     &w%s&n\n\r",
	     pObj->short_descr, pObj->description );
    if( pObj->action && pObj->action[0] != '\0' )
	bprintf( buf, "&gAction:&n\n\r%s&n", pObj->action );

    for( cnt = 0, paf = pObj->affected; paf; paf = paf->next )
    {
	char temp[MAX_STRING_LENGTH];

	if( cnt == 0 )
	{
	    buffer_strcat( buf, "&gNum   Name          Affects    Mod Bits&n\n\r" );
	    buffer_strcat( buf, "&B----- ------------- ---------- --- --------&n\n\r" );
	}
	if( paf->type == gsn_delayed_effect
	    || paf->type == gsn_continuous_effect )
	    strcpy( temp, skill_table[paf->location].name );
	else
	    strcpy( temp, flag_string( apply_flags, &paf->location ) );
	if( paf->type != gsn_perm_spell )
	    bprintf( buf, "&b[&r%3d&b]&y %-13.13s %-10.10s &c%3d&y %s&n\n\r",
		     cnt, paf->type > 0 ? skill_table[paf->type].name : "none",
		     temp, paf->modifier,
		     flag_string( affect_flags, paf->bitvector ) );
	else
	    bprintf( buf, "&b[&r%3d&b]&y %-13.13s permanent spell.&n\n\r",
		     cnt, paf->location > 0
		     ? skill_table[paf->location].name
		     : "ERROR - delete this!" );
	cnt++;
    }

    show_obj_values( pObj->item_type, pObj->value, buf );
    while( ( p = strstr( buf->data, "&x" ) ) )
	*( p + 1 ) = 'w';
    send_to_char( buf->data, ch );
    buffer_free( buf );

    return FALSE;
}


/*
 * Need to issue warning if flag isn't valid.
 */
bool oedit_addaffect( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *pAf;
    char loc[MAX_STRING_LENGTH];
    char mod[MAX_STRING_LENGTH];
    int value;

    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( flag_value( &value, apply_flags, loc ) == NO_FLAG )
    {
	send_to_char( "OEdit:  Invalid value.  '? apply'\n\r", ch );
	return FALSE;
    }

    pAf = new_affect( );
    pAf->location = flag_value( NULL, apply_flags, loc );
    pAf->modifier = atoi( mod );
    pAf->type = -1;
    pAf->duration = -1;
    vzero( pAf->bitvector );
    pAf->next = pObj->affected;
    pObj->affected = pAf;

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


/*
 * Need to issue warning if flag isn't valid.
 * Just like addaffect but with extras
 */
bool oedit_addspell( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *pAf;
    char type[MAX_INPUT_LENGTH];
    char loc[MAX_INPUT_LENGTH];
    char mod[MAX_INPUT_LENGTH];
    int value;
    int vect[MAX_VECTOR];

    EDIT_OBJ( ch, pObj );

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

    if( type[0] == '\0' || loc[0] == '\0' || mod[0] == '\0'
	|| ( !is_number( mod )
	    && flag_value( NULL, body_part_flags, mod ) == NO_FLAG ) )
    {
	send_to_char(
	    "Syntax:  addspell <type> <location> <#mod> [bits]\n\r", ch );
	return FALSE;
    }

    if( skill_lookup( type ) < 0 )
    {
	send_to_char( "OEdit:  Invalid spell name.\n\r", ch );
	return FALSE;
    }

    if( !is_number( loc ) &&
	flag_value( &value, apply_flags, loc ) == NO_FLAG )
    {
	send_to_char( "OEdit:  Invalid value.  '? apply'\n\r", ch );
	return FALSE;
    }

    if( argument[0] != '\0' && str_cmp( argument, "none" ) &&
	flag_value( vect, affect_flags, argument ) == NO_FLAG )
    {
	send_to_char( "OEdit:  Invalid value.  '? affect'\n\r", ch );
	return FALSE;
    }

    pAf = new_affect( );
    pAf->location = is_number( loc )
	? atoi( loc )
	: flag_value( NULL, apply_flags, loc );
    pAf->modifier = is_number( mod )
	? atoi( mod )
	: flag_value( NULL, body_part_flags, mod );
    pAf->type = skill_lookup( type );
    pAf->duration = -1;
    if( !strcmp( argument, "none" ) || argument[0] == '\0' )
	vzero( pAf->bitvector );
    else
	flag_value( pAf->bitvector, affect_flags, argument );
    pAf->next = pObj->affected;
    pObj->affected = pAf;

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


bool oedit_addperm( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *pAf;
    int sn;

    EDIT_OBJ( ch, pObj );

    if( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  addperm <type>\n\r", ch );
	return FALSE;
    }

    if( ( sn = skill_lookup( argument ) ) < 0 )
    {
	send_to_char( "OEdit:  Invalid spell name.\n\r", ch );
	return FALSE;
    }
    if( ( skill_table[sn].target != TAR_CHAR_DEFENSIVE
	  && skill_table[sn].target != TAR_CHAR_SELF
	  && skill_table[sn].target != TAR_CHAR_OFFENSIVE )
	|| !skill_table[sn].spell_fun )
    {
	send_to_char( "OEdit:  Please use a character targeted spell.\n\r",
		      ch );
	return FALSE;
    }

    pAf = new_affect( );
    pAf->type = gsn_perm_spell;
    pAf->location = skill_lookup( argument );
    pAf->modifier = 0;
    pAf->duration = -1;
    vzero( pAf->bitvector );
    pAf->next = pObj->affected;
    pObj->affected = pAf;

    send_to_char( "Permanent spell effect added.\n\r", ch );
    return TRUE;
}


/*
 * My thanks to Hans Hvidsten Birkeland and Noam Krendel (Walker)
 * for really teaching me how to manipulate pointers.
 */
bool oedit_delaffect( CHAR_DATA *ch, const char *argument )
{
    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;
}


bool oedit_name( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ( ch, pObj );

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

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

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


bool oedit_short( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ( ch, pObj );

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

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

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


bool oedit_level( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ( ch, pObj );

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

    pObj->level = atoi( argument );

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


bool oedit_long( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ( ch, pObj );

    if( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  long <$long>\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 oedit_action( CHAR_DATA *ch, const char *argument )
{
    char buf[MAX_STRING_LENGTH];
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ( ch, pObj );

    if( argument[0] == '\0' )
    {
	free_string( pObj->action );
	pObj->action = str_dup( "" );
	send_to_char( "Action description cleared.\n\r", ch );
	return TRUE;
    }

    sprintf( buf, "%s&n\n\r", argument );

    free_string( pObj->action );
    pObj->action = str_dup( buf );
    pObj->action[0] = UPPER( pObj->action[0] );

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


bool set_value( CHAR_DATA *ch, OBJ_INDEX_DATA * pObj, const char *argument,
		int value )
{
    if( argument[0] == '\0' )
    {
	set_obj_values( ch, pObj, -1, '\0' );
	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.
 ****************************************************************************/
bool oedit_values( CHAR_DATA *ch, const char *argument, int value )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ( ch, pObj );

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

    return FALSE;
}


bool oedit_value0( CHAR_DATA *ch, const char *argument )
{
    if( oedit_values( ch, argument, 0 ) )
	return TRUE;

    return FALSE;
}


bool oedit_value1( CHAR_DATA *ch, const char *argument )
{
    if( oedit_values( ch, argument, 1 ) )
	return TRUE;

    return FALSE;
}


bool oedit_value2( CHAR_DATA *ch, const char *argument )
{
    if( oedit_values( ch, argument, 2 ) )
	return TRUE;

    return FALSE;
}


bool oedit_value3( CHAR_DATA *ch, const char *argument )
{
    if( oedit_values( ch, argument, 3 ) )
	return TRUE;

    return FALSE;
}


bool oedit_mpadd( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    int type;
    int allowed[] = { GLOBAL_PROG, ACT_PROG, SPEECH_PROG, RAND_PROG,
		      GREET_PROG, ALL_GREET_PROG, LEAVE_PROG, TIME_PROG,
		      REPOP_PROG, COMMAND_PROG, WEAR_PROG, REMOVE_PROG,
		      SAC_PROG, LOOK_PROG, EXAMINE_PROG, USE_PROG, GET_PROG,
		      DROP_PROG, GIVE_PROG, DAMAGE_PROG, REPAIR_PROG,
		      OPEN_PROG, CLOSE_PROG, LOOT_PROG, -1 };

    EDIT_OBJ( ch, pObj );

    if( ( type = edit_mpadd( ch, &pObj->mudprogs, argument, allowed ) ) == PROG_ERROR )
	return FALSE;
    xSET_BIT( pObj->progtypes, type );

    return TRUE;
}


bool oedit_mpdelete( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    EDIT_OBJ( ch, pObj );

    return edit_mpdelete( ch, &pObj->mudprogs, argument );
}


bool oedit_mpedit( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ( ch, pObj );

    return edit_mpedit( ch, pObj->mudprogs, argument );
}


bool oedit_mpshow( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ( ch, pObj );

    edit_mpshow( ch, pObj->mudprogs, argument );
    return FALSE;
}


bool oedit_weight( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    int weight;

    EDIT_OBJ( ch, pObj );

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

    weight = atoi_special( argument );

    if( weight < 0 )
    {
	send_to_char( "You may not set negative weight.\n\r", ch );
	return FALSE;
    }

    pObj->weight = weight;

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


bool oedit_repop( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    int repop;

    EDIT_OBJ( ch, pObj );

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

    repop = atoi_special( argument );

    if( repop < 0 || repop > 1000 )
    {
	send_to_char( "Range is 0 to 1000.\n\r", ch );
	return FALSE;
    }

    pObj->reset_chance = repop;

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


bool oedit_required( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    int sn;

    EDIT_OBJ( ch, pObj );

    if( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  required <skill>\n\r", ch );
	return FALSE;
    }

    sn = skill_lookup( argument );

    if( sn < 0 )
    {
	send_to_char( "Skill not found.\n\r", ch );
	return FALSE;
    }

    pObj->required_skill = sn;

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


bool oedit_rsfind( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    OBJ_INDEX_DATA *pObjToIndex;
    MOB_INDEX_DATA *pMob = NULL;
    ROOM_INDEX_DATA *pRoom;
    int rvnum;
    RESET_DATA *pReset;
    BUFFER *buf = buffer_new( MAX_STRING_LENGTH );
    char tmp[MAX_INPUT_LENGTH];

    EDIT_OBJ( ch, pObj );
    for( rvnum = pObj->area->lvnum; rvnum <= pObj->area->uvnum; rvnum++ )
    {
	if( ( pRoom = get_room_index( rvnum ) ) && pRoom->area == pObj->area )
	{
	    for( pReset = pRoom->reset_first; pReset; pReset = pReset->next )
	    {
		if( pReset->command == 'M' )
		{
		    pMob = get_mob_index( pReset->arg1 );
		    continue;
		}
		if( pReset->arg1 != pObj->vnum )
		    continue;
		switch( pReset->command )
		{
		case 'O':
		    bprintf( buf, "&m[%5d]&y%s &ginto room.&n\n\r", rvnum,
			     colour_strpad( tmp, pRoom->name, 20 ) );
		    break;
		case 'P':
		    if( !( pObjToIndex = get_obj_index( pReset->arg2 ) ) )
		    {
			bprintf( buf, "Put Object - Bad To Object %d.\n\r",
				 pReset->arg2 );
			break;
		    }

		    bprintf( buf, "&m[%5d]&y%s ", rvnum,
			     colour_strpad( tmp, pRoom->name, 20 ) );
		    bprintf( buf, "&ginside &mO[%5d] &y%s&n\n\r", pReset->arg2,
			     colour_strpad( tmp, pObjToIndex->short_descr, 20 ) );
		    break;
		case 'E':
		case 'G':
		    if( !pMob )
		    {
			bprintf( buf, "No last mobile - Room %d.\n\r", rvnum );
			break;
		    }
		    bprintf( buf, "&m[%5d]&y%s ", rvnum,
			     colour_strpad( tmp, pRoom->name, 20 ) );
		    bprintf( buf, "&g%-20.20s &mM[%5d] &y%s&n\n\r",
			     ( pReset->command == 'G' ) ?
			     wear_loc_strings[0].name
			     : flag_string( wear_loc_strings, &pReset->arg2 ),
			     pMob->vnum, colour_strpad( tmp, pMob->short_descr, 20 ) );
		    break;
		}
	    }
	}
    }
    if( buf->data[0] != '\0' )
	send_to_char( buf->data, ch );
    else
	send_to_char( "This object has no resets in this area.\n\r", ch );
    buffer_free( buf );
    return FALSE;
}


bool oedit_cost( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    int cost;

    EDIT_OBJ( ch, pObj );

    if( argument[0] == '\0' || !is_number_special( argument ) )
    {
	send_to_char( "Syntax:  cost <number with k/m/t suffix>\n\r", ch );
	return FALSE;
    }

    cost = atoi_special( argument );

    if( cost < 0 )
    {
	send_to_char( "You may not set negative cost.\n\r", ch );
	return FALSE;
    }

    pObj->cost = cost;

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


bool oedit_condition( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    int cond;

    EDIT_OBJ( ch, pObj );

    if( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  condition <#condition/100>\n\r", ch );
	return FALSE;
    }

    cond = atoi( argument );

    if( cond < 0 )
    {
	send_to_char( "You may not set negative condition.\n\r", ch );
	return FALSE;
    }
    else if( cond > 100 )
	send_to_char( "OEdit:  [WARNING] setting condition higher than 100 "
		      "isn't a good idea.\n\r", ch );
    pObj->condition = cond * 10;

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


bool oedit_create( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    AREA_DATA *pArea;
    int value;
    int iHash;

    value = atoi( argument );

    /* OLC 1.1b */
    if( argument[0] == '\0' || value <= 0 || value >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "Syntax:  create <0 < #vnum < %d>\n\r", INT_MAX );
	send_to_char( output, 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;
    pObj->action = str_dup( "" );

    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;

    wiznetf( ch, WIZ_CREATE, get_trust( ch ), "%s has created a new object %d.",
	     ch->name, value );
    send_to_char( "Object Created.\n\r", ch );
    return TRUE;
}


bool oedit_clone( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    OBJ_INDEX_DATA *curr;
    AREA_DATA *pArea;
    int value;
    int iHash;

    EDIT_OBJ( ch, curr );

    value = atoi( argument );

    /* OLC 1.1b */
    if( argument[0] == '\0' || value <= 0 || value >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "Syntax:  clone <0 < #vnum < %d>\n\r", INT_MAX );
	send_to_char( output, 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;

    free_string( pObj->name );
    pObj->name = str_dup( curr->name );
    free_string( pObj->short_descr );
    pObj->short_descr = str_dup( curr->short_descr );
    free_string( pObj->description );
    pObj->description = str_dup( curr->description );
    free_string( pObj->action );
    pObj->action = str_dup( curr->action );
    pObj->level = curr->level;
    pObj->value[0] = curr->value[0];
    pObj->value[1] = curr->value[1];
    pObj->value[2] = curr->value[2];
    pObj->value[3] = curr->value[3];
    pObj->item_type = curr->item_type;
    pObj->extra_flags = curr->extra_flags;
    pObj->wear_flags = curr->wear_flags;
    pObj->weight = curr->weight;
    pObj->required_skill = curr->required_skill;
    pObj->material = curr->material;
    pObj->cost = curr->cost;

    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 Cloned.\n\r", ch );
    return TRUE;
}


bool oedit_ed( CHAR_DATA *ch, const char *argument )
{
    OBJ_INDEX_DATA *pObj;
    EXTRA_DESCR_DATA *ed;
    char command[MAX_INPUT_LENGTH];

    EDIT_OBJ( ch, pObj );

    argument = one_argument( argument, command );

    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( argument[0] == '\0' )
	{
	    send_to_char( "Syntax:  ed add <keyword>\n\r", ch );
	    return FALSE;
	}

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

	string_edit( ch, &ed->description );

	return TRUE;
    }

    if( !str_cmp( command, "edit" ) )
    {
	if( argument[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( argument, ed->keyword ) )
		break;
	}

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

	string_edit( ch, &ed->description );

	return TRUE;
    }

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

	if( argument[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( argument, 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" ) )
    {
	if( argument[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( argument, ed->keyword ) )
		break;

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

	/* OLC 1.1b */
	if( strlen( ed->description ) >= ( MAX_STRING_LENGTH - 4 ) )
	{
	    send_to_char( "String too long to be formatted.\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;
}


/*
 * Mobile Editor Functions.
 */
bool medit_show( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    BUFFER *buf = buffer_new( MAX_STRING_LENGTH );
    char tmp[MAX_STRING_LENGTH];
    char tmp2[MAX_STRING_LENGTH];
    char *p;

    EDIT_MOB( ch, pMob );

    bprintf( buf, "&b[&r%5d&b]&g Name: &b[&c%s&b]&n\n\r"
	     "&gArea:         &b[&c%5d&b]&m %s&n\n\r",
	     pMob->vnum, pMob->name,
	     !pMob->area ? -1 : pMob->area->vnum,
	     !pMob->area ? "No Area" : pMob->area->name );

    bprintf( buf, "&gLevel:        &b[&c%5d&b]"
	     "&g            Race:        &b[&c%s&b]&n\n\r",
	     pMob->level, race_table[pMob->race].name );

    bprintf( buf, "&gRepop:        &b[&c%4d&b/&c1000&b]"
	     "&g        Class:       &b[&c%s&b]&n\n\r",
	     pMob->reset_chance,
	     pMob->class < 0 ? "none" : class_table[pMob->class].name );

    bprintf( buf, "&gAlign:        &b[&c%5d&b]"
	     "&g            Sex:         &b[&c%s&b]&n\n\r",
	     pMob->alignment,
	     pMob->sex == SEX_MALE ? "male" :
	     pMob->sex == SEX_FEMALE ? "female" : "neutral" );

    bprintf( buf, "&gAct:          &b[&c%s&b]&n\n\r",
	     flag_string( act_flags, pMob->act ) );

    sprintf( tmp, "&gAffected by:  &b[&c%s&b]&n\n\r",
	     flag_string( affect_flags, pMob->affected_by ) );
    buffer_strcat( buf, multi_line( tmp2, tmp, 79, 15 ) );

    sprintf( tmp, "&gBody Parts:   &b[&c%s&b]&n\n\r",
	     flag_string( body_part_flags, &pMob->body_parts ) );
    buffer_strcat( buf, multi_line( tmp2, tmp, 79, 15 ) );

    if( pMob->spec_fun )
	bprintf( buf, "&gSpec fun:     &b[&c%s&b]&n\n\r",
		 spec_table[pMob->spec_fun].spec_name );

    bprintf( buf, "&gShort descr:  &w%s\n\r&gLong descr:\n\r&w%s&n",
	     pMob->short_descr, pMob->long_descr );

    buffer_strcat( buf, "&gDescription:\n\r&w" );
    buffer_strcat( buf, pMob->description );
    buffer_strcat( buf, "&n" );

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

	pShop = pMob->pShop;

	bprintf( buf,
		 "&gShop data for &b[&r%5d&b]&g:&n\n\r"
		 "\t&gMarkup for purchaser: &b[&c%d%%&b]&n\n\r"
		 "\t&gMarkdown for seller:  &b[&c%d%%&b]&n\n\r",
		 pMob->vnum, pShop->profit_buy, pShop->profit_sell );
	bprintf( buf, "\t&gHours: &c%d&g to &c%d&g.&n\n\r",
		 pShop->open_hour, pShop->close_hour );

	for( iTrade = 0; iTrade < MAX_TRADE; iTrade++ )
	{
	    if( pShop->buy_type[iTrade] > 0 )
	    {
		if( iTrade == 0 )
		{
		    buffer_strcat( buf, "\t&gNumber Trades Type&n\n\r" );
		    buffer_strcat( buf, "\t&B------ -----------&n\n\r" );
		}
		bprintf( buf, "\t&b[&c%4d&b]&n &y%s&n\n\r", iTrade,
			 flag_string( type_flags, &pShop->buy_type[iTrade] ) );
	    }
	}
    }
    while( ( p = strstr( buf->data, "&x" ) ) )
	*( p + 1 ) = 'w';
    send_to_char( buf->data, ch );
    buffer_free( buf );

    return FALSE;
}


bool medit_create( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    AREA_DATA *pArea;
    int value;
    int iHash;

    value = atoi( argument );

    /* OLC 1.1b */
    if( argument[0] == '\0' || value <= 0 || value >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "Syntax:  create <0 < #vnum < %d>\n\r", INT_MAX );
	send_to_char( output, 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;
    pMob->body_parts = race_table[0].body_parts;
    pMob->class = CLASS_NONE;

    if( value > top_vnum_mob )
	top_vnum_mob = value;

    vset( 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;

    wiznetf( ch, WIZ_CREATE, get_trust( ch ), "%s has created a new mobile (%d).",
	    ch->name, value );
    send_to_char( "Mobile Created.\n\r", ch );
    return TRUE;
}


bool medit_clone( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    MOB_INDEX_DATA *curr;
    AREA_DATA *pArea;
    int value;
    int iHash;

    EDIT_MOB( ch, curr );

    value = atoi( argument );

    /* OLC 1.1b */
    if( argument[0] == '\0' || value <= 0 || value >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "Syntax:  create <0 < #vnum < %d>\n\r", INT_MAX );
	send_to_char( output, 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;

    free_string( pMob->name );
    pMob->name = str_dup( curr->name );
    free_string( pMob->short_descr );
    pMob->short_descr = str_dup( curr->short_descr );
    free_string( pMob->long_descr );
    pMob->long_descr = str_dup( curr->long_descr );
    free_string( pMob->description );
    pMob->description = str_dup( curr->description );
    pMob->spec_fun = curr->spec_fun;
    pMob->level = curr->level;
    vcopy( pMob->act, curr->act );
    vcopy( pMob->affected_by, curr->affected_by );
    pMob->race = curr->race;
    pMob->sex = curr->sex;
    pMob->body_parts = curr->body_parts;
    pMob->alignment = curr->alignment;
    pMob->class = curr->class;

    if( value > top_vnum_mob )
	top_vnum_mob = value;

    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 Cloned.\n\r", ch );
    return TRUE;
}


bool medit_spec( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

    if( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  spec <special function>\n\r", ch );
	return FALSE;
    }


    if( !str_cmp( argument, "none" ) )
    {
	pMob->spec_fun = 0;

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

    if( spec_lookup( argument ) >= 0 )
    {
	pMob->spec_fun = spec_lookup( argument );
	send_to_char( "Spec set.\n\r", ch );
	return TRUE;
    }

    send_to_char( "MEdit:  No such special function.\n\r", ch );
    return FALSE;
}


bool medit_class( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

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

    if( flag_value( NULL, class_flags, argument ) != NO_FLAG )
    {
	pMob->class = flag_value( NULL, class_flags, argument );
	send_to_char( "Class set.\n\r", ch );
	return TRUE;
    }

    send_to_char( "MEdit:  No such class.\n\r", ch );
    return FALSE;
}


bool medit_mpadd( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    int type;
    int allowed[] = { GLOBAL_PROG, SUB_PROG, ACT_PROG, SPEECH_PROG,
		      RAND_PROG, GREET_PROG, ALL_GREET_PROG, LEAVE_PROG,
		      TIME_PROG, REPOP_PROG, COMMAND_PROG, LOOK_PROG,
		      FIGHT_PROG, DEATH_PROG, HITPRCNT_PROG, ENTRY_PROG,
		      GIVE_PROG, BRIBE_PROG, ATTACK_PROG, DELAY_PROG,
		      CAST_PROG, -1 };

    EDIT_MOB( ch, pMob );

    if( ( type = edit_mpadd( ch, &pMob->mudprogs, argument, allowed ) ) == PROG_ERROR )
	return FALSE;
    xSET_BIT( pMob->progtypes, type );

    return TRUE;
}


bool medit_mpdelete( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    EDIT_MOB( ch, pMob );

    return edit_mpdelete( ch, &pMob->mudprogs, argument );
}


bool medit_mpedit( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

    return edit_mpedit( ch, pMob->mudprogs, argument );
}


bool medit_mpshow( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

    edit_mpshow( ch, pMob->mudprogs, argument );
    return FALSE;
}


bool medit_align( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

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

    pMob->alignment = atoi( argument );

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


bool medit_repop( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    int repop;

    EDIT_MOB( ch, pMob );

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

    repop = atoi_special( argument );

    if( repop < 0 || repop > 1000 )
    {
	send_to_char( "Range is 0 to 1000.\n\r", ch );
	return FALSE;
    }

    pMob->reset_chance = repop;

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


bool medit_rsfind( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    ROOM_INDEX_DATA *pRoom;
    int rvnum, col = 0;
    RESET_DATA *pReset;
    BUFFER *buf = buffer_new( MAX_STRING_LENGTH );

    EDIT_MOB( ch, pMob );
    for( rvnum = pMob->area->lvnum; rvnum <= pMob->area->uvnum; rvnum++ )
    {
	if( ( pRoom = get_room_index( rvnum ) ) && pRoom->area == pMob->area )
	{
	    for( pReset = pRoom->reset_first; pReset; pReset = pReset->next )
	    {
		if( pReset->command == 'M' && pReset->arg1 == pMob->vnum )
		{
		    char tmp[MAX_INPUT_LENGTH];

		    bprintf( buf, "&m[%5d]&y%s &gnumber: %3d", rvnum,
			     colour_strpad( tmp, pRoom->name, 19 ), pReset->arg2 );
		    if( ++col % 2 == 0 )
			buffer_strcat( buf, ".&n\n\r" );
		    else
			buffer_strcat( buf, ", " );
		}
	    }
	}
    }
    if( col % 2 != 0 )
	buffer_strcat( buf, "&n\n\r" );
    if( buf->data[0] != '\0' )
	send_to_char( buf->data, ch );
    else
	send_to_char( "This mobile has no resets in this area.\n\r", ch );
    buffer_free( buf );
    return FALSE;
}


bool medit_level( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

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

    pMob->level = atoi( argument );

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


bool medit_desc( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

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

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


bool medit_long( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    char buf[MAX_INPUT_LENGTH];

    EDIT_MOB( ch, pMob );

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

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

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


bool medit_short( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

    if( argument[0] == '\0' )
    {
	send_to_char( "Syntax:  short <#short>\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;
}


bool medit_name( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB( ch, pMob );

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

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

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


bool medit_shop( CHAR_DATA *ch, const char *argument )
{
    MOB_INDEX_DATA *pMob;
    char command[MAX_INPUT_LENGTH];
    char arg1[MAX_INPUT_LENGTH];

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

    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( arg1[0] == '\0' || !is_number( arg1 )
	    || 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( );
	    shop_last->next = pMob->pShop;
	}

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

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


    if( !str_cmp( command, "profit" ) )
    {
	if( arg1[0] == '\0' || !is_number( arg1 )
	    || 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( );
	    shop_last->next = pMob->pShop;
	}

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

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


    if( !str_cmp( command, "type" ) )
    {
	char buf[MAX_INPUT_LENGTH];
	int value;

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

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

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

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

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

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


    if( !str_cmp( command, "delete" ) )
    {
	SHOP_DATA *pShop;

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

	pShop = pMob->pShop;
	free_shop( pShop );
	pMob->pShop = NULL;

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

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


bool gmpedit_create( CHAR_DATA *ch, const char *argument )
{
    MPROG_GLOBAL *mprg;
    AREA_DATA *pArea;
    int value, iHash;

    value = atoi( argument );

    /* OLC 1.1b */
    if( argument[0] == '\0' || value <= 0 || value >= INT_MAX )
    {
	char output[MAX_STRING_LENGTH];

	sprintf( output, "Syntax:  create <0 < #vnum < %d>\n\r", INT_MAX );
	send_to_char( output, ch );
	return FALSE;
    }

    pArea = get_vnum_area( value );

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

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

    if( get_global_mudprog_index( value ) )
    {
	send_to_char( "GMPEdit:  MudProg vnum already exists.\n\r", ch );
	return FALSE;
    }

    mprg = new_mprog_global( );
    mprg->area = pArea;
    mprg->vnum = value;
    mprg->type = GLOBAL_PROG;

    iHash = value % MPROG_GLOBAL_HASH;
    mprg->next = global_progs[iHash];
    global_progs[iHash] = mprg;
    ch->desc->pEdit = (void *)mprg;
    ch->desc->interpreter = get_interpreter( "GMPEdit" );

    wiznetf( ch, WIZ_CREATE, get_trust( ch ),
	     "%s has created a new mud program (%d).",
	     ch->name, value );
    send_to_char( "Mud Program Created.\n\r", ch );
    return TRUE;
}


bool gmpedit_show( CHAR_DATA *ch, const char *argument )
{
    MPROG_GLOBAL *mprg;
    BUFFER *buf = buffer_new( MAX_STRING_LENGTH );

    EDIT_GMPROG( ch, mprg );

    bprintf( buf, "&b[&r%5d&b]&g Type: &b[&c%s&b]&n\n\r",
	     mprg->vnum, flag_string( mud_prog_flags, &mprg->type ) );
    bprintf( buf, "&gArea:         &b[&c%4d&b]&m %s&n\n\r",
	     !mprg->area ? -1 : mprg->area->vnum,
	     !mprg->area ? "No Area" : mprg->area->name );
    bprintf( buf, "&gAllowed:      &b[&c%s&b]&n\n\r",
	      flag_string( mor_type_flags, &mprg->allowed ) );
    bprintf( buf, "&gArguments(s): &w%s&n\n\r"
	     "&gScript:\n\r&w", mprg->arglist );
    buffer_strcat( buf, mprg->comlist );

    send_to_char( buf->data, ch );
    send_to_char( "&n", ch );
    buffer_free( buf );

    return FALSE;
}


bool gmpedit_area( CHAR_DATA *ch, const char *argument )
{
    MPROG_GLOBAL *mprg;
    AREA_DATA *pArea;

    EDIT_GMPROG( ch, mprg );

    if( argument[0] == '\0' || !is_number( argument ) )
    {
	send_to_char( "Syntax:  area <#areavnum>\n\r", ch );
	return FALSE;
    }

    pArea = get_area_data( atoi( argument ) );
    if( !pArea )
    {
	send_to_char( "No area there.\n\r", ch );
	return FALSE;
    }
    if( !IS_BUILDER( ch, pArea ) )
    {
	send_to_char( "You can build that area.\n\r", ch );
	return FALSE;
    }

    mprg->area = pArea;
    SET_BIT( pArea->area_flags, AREA_CHANGED );

    send_to_char( "GMPEdit:  Mud Program area set.\n\r", ch );
    return TRUE;
}


bool gmpedit_arglist( CHAR_DATA *ch, const char *argument )
{
    MPROG_GLOBAL *mprg;

    EDIT_GMPROG( ch, mprg );

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

    free_string( mprg->arglist );
    mprg->arglist = str_dup( argument );

    send_to_char( "Arguments to program set.\n\r", ch );
    return TRUE;
}


bool gmpedit_comlist( CHAR_DATA *ch, const char *argument )
{
    MPROG_GLOBAL *mprg;

    EDIT_GMPROG( ch, mprg );

    if( argument[0] == '\0' )
    {
	string_edit( ch, &mprg->comlist );
	return TRUE;
    }

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