Tapestries/
Tapestries/area/
Tapestries/area/current/
Tapestries/area/helps/
Tapestries/area/tmp/
Tapestries/ideas/
Tapestries/log/
Tapestries/player/
Tapestries/player/b/
Tapestries/player/d/
Tapestries/player/e/
Tapestries/player/h/
Tapestries/player/j/
Tapestries/player/k/
Tapestries/player/l/
Tapestries/player/m/
Tapestries/player/n/
Tapestries/player/r/
Tapestries/player/s/
Tapestries/player/t/
Tapestries/player/u/
Tapestries/player/z/
/***************************************************************************
 *  File: olc_act.c                                                        *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 *                                                                         *
 *  This code was freely distributed with the The Isles 1.1 source code,   *
 *  and has been used here for OLC - OLC would not be what it is without   *
 *  all the previous coders who released their source code.                *
 *                                                                         *
 ***************************************************************************/



#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>	/* OLC 1.1b */
#include "merc.h"
#include "olc.h"



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



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

    return FALSE;
}    

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



/*****************************************************************************
 Name:		show_flag_cmds
 Purpose:	Displays settable flags and stats.
 Called by:	show_help(olc_act.c).
 ****************************************************************************/
void show_flag_cmds( CHAR_DATA *ch, const struct flag_type *flag_table )
{
    char	buf[ MAX_STRING_LENGTH ];
    char	*buf1;
    int		flag;
    int		col;
 
    buf1	= NULL;
    col		= 0;

    for( flag = 0 ; *flag_table[flag].name ; flag++ )
    {
	if( flag_table[flag].settable )
	{
	    sprintf( buf, "%-19.18s", flag_table[flag].name );
	    str_cat( &buf1, buf );
	    if( ++col % 4 == 0 )
		str_cat( &buf1, "\n\r" );
	}
    }
 
    if( col % 4 != 0 )
	str_cat( &buf1, "\n\r" );

    page_to_char( buf1, ch );
    free( buf1 );

    return;
}



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

    for( sn = 0 ; sn < MAX_SKILL ; sn++ )
    {
	if( !skill_table[sn].name )
	    break;

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

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

    page_to_char( buf1, ch );
    free( buf1 );

    return;
}



/*****************************************************************************
 Name:		show_spec_cmds
 Purpose:	Displays settable special functions.
 Called by:	show_help(olc_act.c).
 ****************************************************************************/
void show_spec_cmds( CHAR_DATA *ch )
{
    char	buf[ MAX_STRING_LENGTH ];
    char	*buf1;
    int		spec;
    int		col;
 
    buf1	= NULL;
    col		= 0;

    send_to_char( "Preceed special functions with 'spec_'\n\r\n\r", ch );
    for( spec = 0 ; *spec_table[spec].spec_fun ; spec++ )
    {
	sprintf( buf, "%-19.18s", &spec_table[spec].spec_name[5] );
	str_cat( &buf1, buf );
	if( ++col % 4 == 0 )
	    str_cat( &buf1, "\n\r" );
    }
 
    if( col % 4 != 0 )
	str_cat( &buf1, "\n\r" );

    page_to_char( buf1, ch );
    free( buf1 );

    return;
}



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

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

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

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

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

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

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



bool redit_mlist( CHAR_DATA *ch, char *argument )
{
    MOB_INDEX_DATA	*pMobIndex;
    AREA_DATA		*pArea;
    char		buf  [ MAX_STRING_LENGTH   ];
    char		*buf1;
    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	= NULL;
    fAll	= !str_cmp( arg, "all" );
    found	= FALSE;

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

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

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

    page_to_char( buf1, ch );
    free( buf1 );

    return FALSE;
}



bool redit_olist( CHAR_DATA *ch, char *argument )
{
    OBJ_INDEX_DATA	*pObjIndex;
    AREA_DATA		*pArea;
    char		buf[ MAX_STRING_LENGTH   ];
    char		*buf1;
    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	= NULL;
    fAll	= !str_cmp( arg, "all" );
    found	= FALSE;

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

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

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

    send_to_char( buf1, ch );
    free( buf1 );

    return FALSE;
}



bool redit_mshow( CHAR_DATA *ch, 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 ) )
    {
	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, 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 ) )
    {
	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, char *argument )
{
    AREA_DATA*	pArea;
    char	buf[ MAX_STRING_LENGTH ];
    char	*buf1;

    EDIT_AREA( ch, pArea );

    buf1	= NULL;

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

    sprintf( buf, "Recall:   [%5d] %s\n\r", pArea->recall,
	get_room_index( pArea->recall )
	? get_room_index( pArea->recall )->name : "none" );
    str_cat( &buf1, buf );

    sprintf( buf, "File:     %s\n\r", pArea->filename );
    str_cat( &buf1, buf );

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

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

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

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

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

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

    page_to_char( buf1, ch );
    free( buf1 );

    return FALSE;
}



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

    EDIT_AREA( ch, pArea );

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

    return FALSE;
}



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

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

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

    SET_BIT( pArea->area_flags, AREA_ADDED );
    send_to_char( "Area Created.\n\r", ch );
    return TRUE;	/* OLC 1.1b */
}



bool aedit_name( CHAR_DATA *ch, 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_bw( "Name set.\n\r", ch );
    return TRUE;
}



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

    EDIT_AREA( ch, pArea );

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

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

    /*
     * Simple Syntax Check.
     */
    length = strlen( argument );

    /*
     * Allow only letters and numbers.
     */
    for( i = 0 ; i < length ; i++ )
    {
	if( !isalnum( file[i] ) )
	{
	    send_to_char( "Only letters and numbers are valid.\n\r", ch );
	    return FALSE;
	}
    }    

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

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



bool aedit_age( CHAR_DATA *ch, 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' )
    {
	send_to_char( "Syntax:  age [#age]\n\r", ch );
	return FALSE;
    }

    pArea->age = atoi( age );

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



bool aedit_recall( CHAR_DATA *ch, 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_security( CHAR_DATA *ch, 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 || value < 0 )
    {
	if( ch->pcdata->security != 0 )
	{
	    sprintf( buf, "Security is 0-%d.\n\r", ch->pcdata->security );
	    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, 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( strstr( pArea->builders, name ) != '\0' )
    {
	pArea->builders = string_replace( pArea->builders, name, "\0" );
	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 );
	return TRUE;
    }
    else
    {
	buf[0] = '\0';
	if( strstr( pArea->builders, "None" ) != '\0' )
	{
	    pArea->builders = string_replace( pArea->builders, "None", "\0" );
	    pArea->builders = string_unpad( pArea->builders );
	}

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

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

    return FALSE;
}



bool aedit_vnum( CHAR_DATA *ch, 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, 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, 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, char *argument )
{
    ROOM_INDEX_DATA	*pRoom;
    char		buf[ MAX_STRING_LENGTH ];
    char		*buf1;
    OBJ_DATA		*obj;
    CHAR_DATA		*rch;
    int			door;
    bool		fcnt;
    
    EDIT_ROOM( ch, pRoom );

    buf1	= NULL;
    
    sprintf( buf, "Description:\n\r%s", pRoom->description );
    str_cat( &buf1, buf );

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

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

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

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

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

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

    if( fcnt )
    {
	int end;

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

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

    if( fcnt )
    {
	int end;

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

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

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

	    sprintf( buf, "-%-5s to [%5d] Key: [%5d]",
		capitalize(dir_name[door]),
		pexit->to_room ? pexit->to_room->vnum : 0,
		pexit->key );
	    str_cat( &buf1, buf );

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

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

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

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

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

    page_to_char( buf1, ch );
    free( buf1 );

    return FALSE;
}


/* 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, char *argument, int door )
{
    ROOM_INDEX_DATA	*pRoom;
    char		command[MAX_INPUT_LENGTH];
    char		arg[MAX_INPUT_LENGTH];
    char		total_arg[MAX_STRING_LENGTH];
    int			value = 0;
    int			rev;

    EDIT_ROOM( ch, pRoom );

    /* Often used data. */
    rev = rev_dir[door];
    
    if( !argument )
    {
	do_help( ch, "EXIT" );
	return FALSE;
    }

    /*
     * Now parse the arguments.
     */
    strcpy( total_arg, argument );
    argument = one_argument( argument, command );
    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->exit[rev] )
	{
	    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]->to_room = pLinkRoom;	/* Assign data.		*/
	pRoom->exit[door]->vnum = value;

	pExit			= new_exit();	/* No remote exit.	*/

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

	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]->to_room = pLinkRoom;
	pRoom->exit[door]->vnum = value;

	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( argument, "key" ) )
	{
	    pRoom->exit[door]->key = 0;
            send_to_char( "Exit key removed.\n\r", ch );                        
            return TRUE;
	}

	if( !str_cmp( argument, "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( argument[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" ) )
    {
	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]->key = pObjIndex->vnum;

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

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

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

	free_string( pRoom->exit[door]->keyword );
	pRoom->exit[door]->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();

	    string_append( ch, &pRoom->exit[door]->description );
	    return TRUE;
	}

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

    /*
     * Set the exit flags, needs full argument.
     * ----------------------------------------
     */
    if( ( value = flag_value( exit_flags, total_arg ) ) != NO_FLAG )
    {
	ROOM_INDEX_DATA *pToRoom;

	/*
	 * Create an exit if none exists.
	 */
	if( !pRoom->exit[door] )
	    pRoom->exit[door] = new_exit();

	/*
	 * 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, char *argument )
{
    if( change_exit( ch, argument, DIR_NORTH ) )
	return TRUE;

    return FALSE;
}

bool redit_northeast( CHAR_DATA *ch, char *argument )
{
    if( change_exit( ch, argument, DIR_NORTHEAST ) )
	return TRUE;

    return FALSE;
}

bool redit_northwest( CHAR_DATA *ch, char *argument )
{
    if( change_exit( ch, argument, DIR_NORTHWEST ) )
	return TRUE;

    return FALSE;
}

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

    return FALSE;
}

bool redit_southeast( CHAR_DATA *ch, char *argument )
{
    if( change_exit( ch, argument, DIR_SOUTHEAST ) )
	return TRUE;

    return FALSE;
}

bool redit_southwest( CHAR_DATA *ch, char *argument )
{
    if( change_exit( ch, argument, DIR_SOUTHWEST ) )
	return TRUE;

    return FALSE;
}

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

    return FALSE;
}

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

    return FALSE;
}



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

    return FALSE;
}



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

    return FALSE;
}


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



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

    EDIT_ROOM( ch, pRoom );

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

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

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

	string_append( ch, &ed->description );

	return TRUE;
    }


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

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

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

	string_append( ch, &ed->description );

	return TRUE;
    }


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

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

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

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

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

	free_extra_descr( ed );

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


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

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

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

	/* OLC 1.1b */
	if( strlen( ed->description ) >= ( MAX_STRING_LENGTH - 20 ) )
	{
	    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, char *argument )
{
    ROOM_INDEX_DATA	*pRoom;
    AREA_DATA		*pArea;
    int			value;
    int			iHash;
    
    EDIT_ROOM( ch, pRoom );

    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;

    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, 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_light( CHAR_DATA *ch, char *argument )
{
    ROOM_INDEX_DATA	*pRoom;

    EDIT_ROOM( ch, pRoom );

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

    pRoom->light = atoi( argument );

    send_to_char( "Light Intensity Set.\n\r", ch );
    return TRUE;
}



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

    EDIT_ROOM( ch, pRoom );

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

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




bool redit_format( CHAR_DATA *ch, 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, char *argument )
{
    ROOM_INDEX_DATA	*pRoom;
    MOB_INDEX_DATA	*pMobIndex;
    RESET_DATA		*pReset;
    CHAR_DATA		*newmob;
    char		arg[ MAX_INPUT_LENGTH ];
    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;
    pReset->arg3	= pRoom->vnum;
    add_reset( pRoom, pReset, 0/* Last slot*/ );

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

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

struct wear_type
{
    int	wear_loc;
    int	wear_bit;
};



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



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



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



bool redit_oreset( CHAR_DATA *ch, char *argument )
{
    ROOM_INDEX_DATA	*pRoom;
    OBJ_INDEX_DATA	*pObjIndex;
    RESET_DATA		*pReset;
    CHAR_DATA		*to_mob;
    OBJ_DATA		*newobj;
    OBJ_DATA		*to_obj;
    char		arg1[ MAX_INPUT_LENGTH ];
    char		arg2[ MAX_INPUT_LENGTH ];
    char		output[ MAX_STRING_LENGTH ];
    int			olevel = 0;

    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_args               = into room\n\r", ch );
	send_to_char( "        -<obj_name>            = into obj\n\r", ch );
	send_to_char( "        -<mob_name> <wear_loc> = into mob\n\r", ch );
	return FALSE;
    }

    if( !( pObjIndex = get_obj_index( atoi( 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;
	pReset->arg3	= pRoom->vnum;
	add_reset( pRoom, pReset, 0/* Last slot*/ );

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

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

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

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

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

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

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

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

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

	olevel  = 0;
        newobj = create_object( pObjIndex );

	if( to_mob->pIndexData->pShop )	/* Shop-keeper? */
	{
	    olevel = 0;

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

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

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

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



/*
 * Object Editor Functions.
 * Updated -Ant, Mar '96.
 */
void show_obj_values( CHAR_DATA *ch, OBJ_INDEX_DATA *obj )
{
    char	buf[  MAX_STRING_LENGTH ];
    char	*buf1;
    bool	found;
    int		i;

    found	= FALSE;
    buf1	= NULL;

    if( IS_SET( obj->item_type, ITEM_SCROLL ) )
    {
	sprintf( buf, "Scroll Level %d spells of:", obj->scroll->level );
	str_cat( &buf1, buf );

	for( i = 0 ; i < 4 ; i++ )
	{
	    if( obj->scroll->spell[i] >= 0 && obj->scroll->spell[i] < MAX_SKILL )
	    {
		sprintf( buf, " '%s'",
		    skill_table[obj->scroll->spell[i]].name );
		str_cat( &buf1, buf );
	    }
	}
	str_cat( &buf1, ".\n\r" );
	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_POTION ) )
    {
	sprintf( buf, "Potion Level %d spells of:", obj->potion->level );
	str_cat( &buf1, buf );

	for( i = 0 ; i < 4 ; i++ )
	{
	    if( obj->potion->spell[i] >= 0 && obj->potion->spell[i] < MAX_SKILL )
	    {
		sprintf( buf, " '%s'",
		    skill_table[obj->potion->spell[i]].name );
		str_cat( &buf1, buf );
	    }
	}
	str_cat( &buf1, ".\n\r" );
	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_PILL ) )
    {
	sprintf( buf, "Pill Level %d spells of:", obj->pill->level );
	str_cat( &buf1, buf );

	for( i = 0 ; i < 4 ; i++ )
	{
	    if( obj->pill->spell[i] >= 0 && obj->pill->spell[i] < MAX_SKILL )
	    {
		sprintf( buf, " '%s'",
		    skill_table[obj->pill->spell[i]].name );
		str_cat( &buf1, buf );
	    }
	}
	str_cat( &buf1, ".\n\r" );
	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_WAND ) )
    {
	sprintf( buf, "Wand has %d(%d) charges of level %d",
	    obj->wand->charges, 
	    obj->wand->max, 
	    obj->wand->level );
	str_cat( &buf1, buf );
      
	if( obj->wand->spell >= 0 && obj->wand->spell < MAX_SKILL )
	{
	    	sprintf( buf, " '%s'",
		    skill_table[obj->wand->spell].name );
	    	str_cat( &buf1, buf );
	}
	str_cat( &buf1, ".\n\r" );

	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_STAFF ) )
    {
	sprintf( buf, "Staff has %d(%d) charges of level %d",
	    obj->staff->charges, 
	    obj->staff->max, 
	    obj->staff->level );
	str_cat( &buf1, buf );
      
	if( obj->staff->spell >= 0 && obj->staff->spell < MAX_SKILL )
	{
	    	sprintf( buf, " '%s'",
		    skill_table[obj->staff->spell].name );
	    	str_cat( &buf1, buf );
	}
	str_cat( &buf1, ".\n\r" );

	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_ARMOUR ) )
    {
	sprintf( buf, 
	"Armor class is %d pierce, %d bash, %d slash, and %d vs. magic\n\r", 
	    obj->armour->ac[ 0 ], 
	    obj->armour->ac[ 1 ], 
	    obj->armour->ac[ 2 ], 
	    obj->armour->ac[ 3 ] );
	str_cat( &buf1, buf );

	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_LIGHT ) )
    {
        if( obj->light->duration == -1 )
            sprintf( buf, "Hours of light: Infinite(-1)\n\r" );
        else
            sprintf( buf, "Hours of light: %d\n\r", obj->light->duration );
        str_cat( &buf1, buf );
	sprintf( buf, "Intensity: %d\n\r", obj->light->intensity );
        str_cat( &buf1, buf );

	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_CONTAINER ) )
    {
        sprintf( buf, "Capacity: %d \n\rFlags : %s\n\rKey : %s (%d)\n\r",
	    obj->cont->capacity, 
	    flag_string( container_flags, obj->cont->closed ),
            get_obj_index( obj->cont->key )
                ? get_obj_index( obj->cont->key )->short_descr
                : "none",
            obj->cont->key );
        str_cat( &buf1, buf );

	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_DRINK_CON ) )
    {
	sprintf( buf, "Contains : %d/%d\n\rLiquid : %s\n\rPoisoned? : %s\n\r",
	    obj->drink->volume, 
	    obj->drink->limit, 
	    flag_string( liquid_flags, obj->drink->liquid ),
	    obj->drink->poison != 0 ? "Yes" : "No" );
        str_cat( &buf1, buf );

	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_FOOD ) )
    {
	sprintf( buf, "Hours of food : %d\n\rPoisoned? : %s\n\r",
	    obj->food->bite, 
	    obj->food->poison != 0 ? "Yes" : "No" );
        str_cat( &buf1, buf );

	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_MONEY ) )
    {
	sprintf( buf, "Amount of Gold/Silver/Copper (v0): %d/%d/%d\n\r", 
	    obj->money->gold,
	    obj->money->silver,
	    obj->money->copper );
	str_cat( &buf1, buf );
	found = TRUE;
    }

    if( IS_SET( obj->item_type, ITEM_WEAPON ) )
    {
 	str_cat( &buf1, "Weapon type is " );
	switch( obj->weapon->type )
	{
	    case( WEAPON_EXOTIC  ):
		str_cat( &buf1, "exotic\n\r"      );
		break;
	    case( WEAPON_SWORD   ):
		str_cat( &buf1, "sword\n\r"       );
		break;	
	    case( WEAPON_DAGGER  ):
		str_cat( &buf1, "dagger\n\r"      );
		break;
	    case( WEAPON_SPEAR   ):
		str_cat( &buf1, "spear\n\r"       );
		break;
	    case( WEAPON_MACE    ):
		str_cat( &buf1, "mace/club\n\r"   );
		break;
	    case( WEAPON_AXE     ):
		str_cat( &buf1, "axe\n\r"         );
		break;
	    case( WEAPON_POLEARM ):
		str_cat( &buf1, "polearm\n\r"     );
		break;
	    default:
		str_cat( &buf1, "unknown\n\r"     );
		break;
 	}
	if( obj->weapon->hit )
	{
	    sprintf( buf, "Hit Bonus is %d\n\r",
		obj->weapon->hit );
	    str_cat( &buf1, buf );
	}
	sprintf( buf, "Damage is %dd%d+%d (average %d) '%s'\n\r",
	    obj->weapon->damage[0],
	    obj->weapon->damage[1],
	    obj->weapon->damage[2],
	    ( ( 1 + obj->weapon->damage[1] ) 
		* obj->weapon->damage[0] / 2 ) + obj->weapon->damage[2],
	    flag_string( weapon_flags, obj->weapon->message ) );
	str_cat( &buf1, buf );

	if( obj->weapon->flags )
	{
	    sprintf( buf, "Weapons flags: %s\n\r",
		flag_string( weapon_extra, obj->weapon->flags ) );
        }

	found = TRUE;
    }

    if( !found )
    {
	sprintf( buf, "None Of The Objects Types Require Values\n\r" );
	str_cat( &buf1, buf );
    }
    page_to_char_bw( buf1, ch );

    free( buf1 );

    return;
}



bool set_obj_values( CHAR_DATA *ch, OBJ_INDEX_DATA *pObj, int value_num, char *argument)
{
    show_obj_values( ch, pObj );

    return TRUE;
}



bool oedit_show( CHAR_DATA *ch, char *argument )
{
    OBJ_INDEX_DATA	*pObj;
    AFFECT_DATA		*paf;
    char		buf[MAX_STRING_LENGTH];
    int			cnt;

    EDIT_OBJ( ch, pObj );

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


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

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

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

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

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

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

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

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

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

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

    show_obj_values( ch, pObj );

    return FALSE;
}


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

    EDIT_OBJ(ch, pObj);

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

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

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

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



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

    EDIT_OBJ( ch, pObj );

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

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

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



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

    EDIT_OBJ( ch, pObj );

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

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

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



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

    EDIT_OBJ( ch, pObj );

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

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



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

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

    return FALSE;
}



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

    EDIT_OBJ( ch, pObj );

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

    pObj->weight = atoi( argument );

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

bool oedit_requires( CHAR_DATA *ch, char *argument )
{
    OBJ_INDEX_DATA	*pObj;
    char		stat[ MAX_INPUT_LENGTH ];
    char		buf[ MAX_INPUT_LENGTH ];
    sh_int		value = 0;

    EDIT_OBJ( ch, pObj );

    argument = one_argument( argument, stat );
    one_argument( argument, buf );

    if( stat[ 0 ] == '\0' || buf[ 0 ] == '\0' || !is_number( buf ) )
    {
	send_to_char( "Syntax:  requires <{cstat{x> <{cvalue{x>\n\r", ch );
	return FALSE;
    }

    value = atoi( buf );

    if( !strcmp( stat, "str" ) )
    {
	pObj->requires[ 0 ] = value;
	send_to_char_bw( "Requirement set.\n\r", ch);
	return TRUE;
    }
    else if( !strcmp( stat, "int" ) )
    {
	pObj->requires[ 1 ] = value;
	send_to_char_bw( "Requirement set.\n\r", ch);
	return TRUE;
    }
    else if( !strcmp( stat, "wis" ) )
    {
	pObj->requires[ 2 ] = value;
	send_to_char_bw( "Requirement set.\n\r", ch);
	return TRUE;
    }
    else if( !strcmp( stat, "dex" ) )
    {
	pObj->requires[ 3 ] = value;
	send_to_char_bw( "Requirement set.\n\r", ch);
	return TRUE;
    }
    else if( !strcmp( stat, "con" ) )
    {
	pObj->requires[ 4 ] = value;
	send_to_char_bw( "Requirement set.\n\r", ch);
	return TRUE;
    }

    send_to_char_bw( "Unknown Statistic, choose from: str int wis dex con\n\r", ch );
    send_to_char( "Syntax:  requires <{cstat{x> <{cvalue{x>\n\r", ch );
    
    return FALSE;
}



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

    EDIT_OBJ( ch, pObj );

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

    pObj->cost = atoi( argument );

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



bool oedit_create( CHAR_DATA *ch, 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;
        
    if( value > top_vnum_obj )
	top_vnum_obj = value;

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

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



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

    EDIT_OBJ( ch, pObj );

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

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

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

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

	string_append( ch, &ed->description );

	return TRUE;
    }

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

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

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

	string_append( ch, &ed->description );

	return TRUE;
    }

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

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

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

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

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

	free_extra_descr( ed );

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


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

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

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

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

	/* 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, char *argument )
{
    MOB_INDEX_DATA *pMob;
    char buf[MAX_STRING_LENGTH];

    EDIT_MOB( ch, pMob );

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

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

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

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

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

    if ( pMob->spec_fun )
    {
	sprintf( buf, "Spec fun:    [%s]\n\r",  spec_string( pMob->spec_fun ) );
	send_to_char( buf, ch );
    }

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

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

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

	pShop = pMob->pShop;

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

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

    return FALSE;
}



bool medit_create( CHAR_DATA *ch, 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;
        
    if ( value > top_vnum_mob )
	top_vnum_mob = value;        

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

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



bool medit_spec( CHAR_DATA *ch, 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 = NULL;

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

    if ( spec_lookup( argument ) )
    {
	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_align( CHAR_DATA *ch, char *argument )
{
    MOB_INDEX_DATA *pMob;

    EDIT_MOB(ch, pMob);

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

    pMob->alignment = atoi( argument );

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

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

    EDIT_MOB( ch, pMob );

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

    if( !( pMob->race = race_lookup_olc( argument ) ) );
    {
	send_to_char_bw( "Unknown Race, rejected.\n\r", ch );
	return FALSE;
    }

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



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

    EDIT_MOB( ch, pMob );

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

    pMob->exp = atoi( argument );

    send_to_char_bw( "Experience Value Set.\n\r", ch );

    return TRUE;
}



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

    EDIT_MOB(ch, pMob);

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

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




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

    EDIT_MOB(ch, pMob);

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

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

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



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

    EDIT_MOB(ch, pMob);

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

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

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



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

    EDIT_MOB(ch, pMob);

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

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

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




bool medit_shop( CHAR_DATA *ch, 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();
	    pMob->pShop->keeper = pMob->vnum;
	    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();
	    pMob->pShop->keeper = pMob->vnum;
	    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 ( ( value = flag_value( type_flags, argument ) ) == NO_FLAG )
	{
	    send_to_char( "REdit:  That type of item is not known.\n\r", ch );
	    return FALSE;
	}

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

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

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


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

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

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

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

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