dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// oedit.cpp - olc object editor
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with all the licenses *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 ***************************************************************************
 * >> Original Diku Mud copyright (c)1990, 1991 by Sebastian Hammer,       *
 *    Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, & Katja Nyboe.   *
 * >> Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael       *
 *    Chastain, Michael Quan, and Mitchell Tse.                            *
 * >> ROM 2.4 is copyright 1993-1995 Russ Taylor and has been brought to   *
 *    you by the ROM consortium: Russ Taylor(rtaylor@pacinfo.com),         *
 *    Gabrielle Taylor(gtaylor@pacinfo.com) & Brian Moore(rom@rom.efn.org) *
 * >> Oblivion 1.2 is copyright 1996 Wes Wagner                            *
 **************************************************************************/
#include "include.h" // dawn standard includes

#include "olc.h"
#include "security.h"

DECLARE_OLC_FUN( oedit_create );
void do_classlist( char_data *ch, char *);
/**************************************************************************/
extern gameset_value_type gameset_value[];

/**************************************************************************/
void do_material_list( char_data *ch, char *argument)
{
	name_linkedlist_type* materials_list=NULL, *plist;
	OBJ_INDEX_DATA *pObjIndex;
	int vnum,count;
	BUFFER *output;
	char buf[MIL];


	if(IS_NULLSTR(argument)){
		logf("do_material_list(): Sorting materials");
		// add all objects to the linked list, duplicates=false
		for(vnum=0; vnum<MAX_KEY_HASH; vnum ++){
			count=0;
			for ( pObjIndex  = obj_index_hash[vnum];
			  pObjIndex != NULL;
			  pObjIndex  = pObjIndex->next )
			{
				  count++;
				addlist(&materials_list,pObjIndex->material, 0, false, false);
				if(count>20000){
					bugf("Count=%5d, objvnum=%d", count, pObjIndex->vnum);
				}
			}
		}
		logf("do_material_list(): Displaying materials to buffer");
		// go thru displaying all objects
		output = new_buf();  
		count=0;
		for(plist=materials_list;plist; plist=plist->next){
			sprintf(buf, "%3d> %s\n", ++count, plist->name); 
			add_buf( output, buf );
		}
		logf("do_material_list(): Sending buffer to player");
		ch->printlnf( "%d material%s total.",
			count,
			count==1 ? "" : "s" );
		ch->sendpage(buf_string(output));
		free_buf(output);
	}else{
		// do a search for a specified item
		count=0;
		output = new_buf();  
		for(vnum=0; vnum<33000; vnum++){
			pObjIndex =get_obj_index(vnum);
			if(pObjIndex){
				if(is_name(argument,pObjIndex->material)){
					sprintf(buf, "%3d> [%5d] %s   `Smaterial='%s'`x\n", 
						++count, pObjIndex->vnum, 
						pObjIndex->short_descr, pObjIndex->material); 
					add_buf( output, buf );
				}
			}
			if(count>400){
				ch->println( "You can only list up to 400 items at once, be more specific." );
				break;
			}
		}
		// display the list to the character
		ch->printlnf( "Displaying %d material%s total.",
			count,
			count==1 ? "" : "s" );
		ch->sendpage(buf_string(output));
		free_buf(output);
	}
}
/**************************************************************************/
void do_oedit( char_data *ch, char *argument )
{
	OBJ_INDEX_DATA *pObj;
	AREA_DATA *pArea;
	char arg1[MSL];
	int value;

	// do security checks
	if (!HAS_SECURITY(ch, 2))
	{
		ch->println( "You must have an olc security 2 or higher to use this command." );
		return;
	}

	argument = one_argument( argument, arg1 );

	if ( is_number( arg1 ) )
	{
		value = atoi( arg1 );
		if ( !( pObj = get_obj_index( value )))
		{
			ch->println( "OEdit:  That vnum does not exist." );
			return;
		}

		// officially reserved vnum range
		if(value<500){
			ch->println("Warning: all mobs, rooms and objects below vnum 500 are officially reserved for the dawn codebase.");
			if(!HAS_SECURITY(ch,9)){
				ch->println("As a result of this reservation, only those with security 9 can edit in that vnum range.");
				return;
			}			
		}


		if ( !IS_BUILDER( ch, pObj->area, BUILDRESTRICT_OBJECTS) )
		{
			ch->println( "Insufficient security to modify object." );
			return;
		}

		ch->desc->pEdit = (void *)pObj;
		ch->desc->editor = ED_OBJECT;

		ch->wraplnf( "`=rYou are now editing object: '`r%s`=r' vnum: `Y%d`x",
			pObj->short_descr, pObj->vnum);
		ch->println( "`=rType `=Cdone`=r to finish editing." );

		return;
	}
	else
	{
		if ( !str_cmp( arg1, "create" ) )
		{
			value = atoi( argument );
			if ( argument[0] == '\0' || value == 0 )
			{
				ch->println( "Syntax:  oedit create <vnum>" );
				return;
			}

			// officially reserved vnum range
			if(value<500){
				ch->println("Warning: all mobs, rooms and objects below vnum 500 are officially reserved for the dawn codebase.");
				if(!HAS_SECURITY(ch,9)){
					ch->println("As a result of this reservation, only those with security 9 can edit in that vnum range.");
					return;
				}			
			}


			pArea = get_vnum_area( value );

			if ( !pArea )
			{
				ch->println( "OEdit:  That vnum is not assigned an area." );
				return;
			}

			if ( !IS_BUILDER( ch, pArea, BUILDRESTRICT_OBJECTS ))
			{
				ch->println( "Insufficient security to modify object." );
				return;
			}

			if ( oedit_create( ch, argument ) )
			{
				SET_BIT( pArea->olc_flags, OLCAREA_CHANGED );
				ch->desc->editor = ED_OBJECT;
				EDIT_OBJ(ch, pObj);

				ch->wraplnf( "`=rcreated object `r%d  `g(stored in %s)`x",
					pObj->vnum, !pObj->area ? "`RNo Area!!!" : pObj->area->file_name );
				ch->println( "Type `=Cdone`x to finish editing." );
			}
			return;
		}
	}

	ch->wrapln( "OEdit:  Type the vnum of the object you want to edit or 'oedit create <vnum>" );
	return;
}

/**************************************************************************/
// by Kal - June 98
AFFECT_DATA * dup_affects_list(AFFECT_DATA* affect)
{
	AFFECT_DATA * pAffect;
	
	if (affect==NULL)
		return (NULL);

	pAffect= new_affect();
	// use recursion to maintain the order of affects
	pAffect->next = dup_affects_list(affect->next);
	
	pAffect->where		= affect->where;
	pAffect->type		= affect->type;
	pAffect->duration	= affect->duration;
	pAffect->location	= affect->location;
	pAffect->modifier	= affect->modifier;
	pAffect->bitvector	= affect->bitvector;

	return (pAffect);
}
/**************************************************************************/
/*
 * Object Editor Functions.
 */
/**************************************************************************/
void show_obj_values( char_data *ch, OBJ_INDEX_DATA *obj )
{
    switch( obj->item_type )
    {
	default:	// No values. 
	    break;

	case ITEM_LIGHT:
		if ( obj->value[2] == -1)
			ch->println(  "[v2] Light:  Infinite[-1]" );
		else
			ch->printlnf( "[v2] Light:  [%d]", obj->value[2] );
		break;

	case ITEM_INSTRUMENT:
		ch->printlnf(     "[v0] Bardic Spell Mod:      [%d]", obj->value[0] );
		if ( obj->value[1] == -1 )
			ch->println("[v1] Uses before retuning:  Infinite[-1]");
		else
			ch->printlnf( "[v1] Uses before retuning:  [%d]", obj->value[1] );
		break;


	case ITEM_COMPONENT:
		ch->printlnf( "[v0] Charges: [%d]", obj->value[0] );
		ch->printlnf( "[v1] Spell:   %s",
			obj->value[1] != -1 ? skill_table[obj->value[1]].name : "none" );
		break;

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

	
	case ITEM_POULTICE:
		ch->printlnf( "[v0] Level:               [%d]", obj->value[0] );
		ch->printlnf( "[v1] Applications Total:  [%d]", obj->value[1] );
		ch->printlnf( "[v2] Applications Left:   [%d]", obj->value[2] );
		ch->printlnf( "[v3] Spell:                %s",
			obj->value[3] != -1 ? skill_table[obj->value[3]].name : "none" );
	    break;

	case ITEM_PORTAL:
		ch->printlnf( "[v0] Charges:        [%d]", obj->value[0] );
		ch->printlnf( "[v1] Exit Flags:     %s", flag_string( exit_flags, obj->value[1] ));
		ch->printlnf( "[v2] Portal Flags:   %s", flag_string( portal_flags, obj->value[2] ));
		ch->printlnf( "[v3] Goes to (vnum): [%d]", obj->value[3] );
		if(CAN_WEAR(obj, OBJWEAR_TAKE))
		{
			ch->wrapln( "`#`RNOTE:`& Because this portal is takeable, it wont be able "
				"to be used in no recall rooms/areas\r\n");
		}
		break;

	case ITEM_TOKEN:
		ch->printlnf( "[v0] Token:  [%s]",	flag_string( token_flags, obj->value[0] ));
		break;
	    
	case ITEM_FURNITURE:
		ch->printlnf( "[v0] Max people:      [%d]", obj->value[0] );
		ch->printlnf( "[v1] Max weight:      [%d]", obj->value[1] );
		ch->printlnf( "[v2] Furniture Flags: %s", flag_string( furniture_flags, obj->value[2] ));
		ch->printlnf( "[v3] Heal bonus:      [%d]", obj->value[3] );
		ch->printlnf( "[v4] Mana bonus:      [%d]", obj->value[4] );
		break;

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

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

	case ITEM_PARCHMENT:
	    ch->printlnf( "[v0] Unused          [%d]", obj->value[0] );
		ch->printlnf( "[v1] Blank = 0       [%d]", obj->value[1] );
		ch->printlnf( "[v2] Unsealed = 0    [%d]", obj->value[2] );
		ch->printlnf( "[v3] Language        [%s]", 
			language_safe_lookup_by_id(obj->value[3])->name);
		break;

	case ITEM_WEAPON:
		ch->printlnf( "[v0] Weapon class:   %s",
			flag_string( weapon_class_types, obj->value[0] ));
		ch->printlnf( "[v1] Number of dice: [%d]   (avedam %d)",
			obj->value[1], 
			(int) (obj->value[1]+(obj->value[1] * obj->value[2]))/2);
		ch->printlnf( "[v2] Type of dice:   [%d]", obj->value[2] );
		ch->printlnf( "[v3] Attack Type:    %s", attack_table[obj->value[3]].name );
		ch->printlnf( "[v4] Special type:   %s", flag_string( weapon_flags,  obj->value[4] ) );
		ch->printlnf( "Average damage is %d", 
			(int) (obj->value[1]+(obj->value[1] * obj->value[2]))/2);
	    break;

	case ITEM_CAULDRON:
	case ITEM_CONTAINER:
	case ITEM_FLASK:
	case ITEM_MORTAR:
		ch->printlnf( "[v0] Weight:     [%d lbs]", obj->value[0]);
		ch->printlnf( "[v1] Flags:      [%s]", flag_string( container_flags, obj->value[1] ));
		ch->printlnf( "[v2] Key:        [%d] (%s)",
			obj->value[2],
			get_obj_index(obj->value[2]) ? get_obj_index(obj->value[2])->short_descr : "none");
		ch->printlnf( "[v3] Capacity    [%d lbs]", obj->value[3]);
		ch->printlnf( "[v4] Weight Mult [%d]", obj->value[4] );

		ch->wrapln("`YNotes:`x v0 = is the maximum combined weight the container can hold... that is "
			"obtained by adding all objects in the containers true weights together.`1"
			"v3 = is the maximum weight any single object can be to be able to be put inside the container.");			
		break;

	case ITEM_FOUNTAIN:
	case ITEM_DRINK_CON:
		ch->printlnf( "[v0] Liquid Total: [%d] (-1 = infinite)", obj->value[0] );
		ch->printlnf( "[v1] Liquid Left:  [%d] (-1 = infinite)", obj->value[1] );
		ch->printlnf( "[v2] Liquid:       %s", liq_table[obj->value[2]].liq_name );
		ch->printlnf( "[v3] Poisoned:     %s", obj->value[3] != 0 ? "Yes": "No" );
		break;

	case ITEM_FOOD:
		ch->printlnf( "[v0] Food hours: [%d]", obj->value[0] );
		ch->printlnf( "[v1] Full hours: [%d]", obj->value[1] );
		ch->printlnf( "[v3] Poisoned:   %s", obj->value[3] != 0 ? "Yes" : "No" );
		break;

	case ITEM_MONEY:
		ch->printlnf( "[v0] Silver: [%d]", obj->value[0] );
		ch->printlnf( "[v1] Gold:   [%d]", obj->value[1] );
		break;
    }

	return;
}


/**************************************************************************/
bool set_obj_values( char_data *ch, OBJ_INDEX_DATA *pObj, int value_num, char *argument)
{
	int value;
	
    switch( pObj->item_type )
    {
	default:
		break;
		
	case ITEM_LIGHT:
		switch ( value_num )
		{
		default:
			ch->println( "Only valid option is V2, which is the hours of light a light provides (-1 = Infinite)." );
			do_help( ch, "OLC-ITEM-LIGHT" );
			return false;
		case 2:
			ch->println( "HOURS OF LIGHT SET.\r\n" );
			pObj->value[2] = atoi( argument );
			break;
		}
		break;

	case ITEM_WAND:
	case ITEM_STAFF:
		switch ( value_num )
		{
		default:
			do_help( ch, "OLC-ITEM-STAFF-WAND" );
			return false;
        case 0:
			value=atoi( argument );
			if(value==pObj->value[0]){
				ch->println( "Spell level unchanged." );
			}else{
				ch->printlnf( "Spell level changed from %d to %d.\r\n", // Extra lf
					pObj->value[0], value);
				pObj->value[0] = value;
			}
            break;
        case 1:
			ch->println( "TOTAL NUMBER OF CHARGES SET.\r\n" );	// Extra lf
            pObj->value[1] = atoi( argument );
            break;
        case 2:
			ch->println( "CURRENT NUMBER OF CHARGES SET.\r\n" );// Extra lf
			pObj->value[2] = atoi( argument );
			break;
		case 3:
			ch->println( "SPELL TYPE SET.\r\n" );				// Extra lf
			pObj->value[3] = skill_lookup( argument );
			break;
		}
		break;

	case ITEM_POULTICE:
		switch ( value_num )
		{
		default:
			do_help( ch, "OLC-ITEM-POULTICE" );
			return false;
		case 0:
			value=atoi( argument );
			if(value==pObj->value[0]){
				ch->println( "Spell level unchanged." );
			}else{
				ch->printlnf( "Spell level changed from %d to %d.\r\n", // Extra lf
					pObj->value[0], value);
				pObj->value[0] = value;
			}
			break;
		case 1:
			ch->println( "TOTAL NUMBER OF APPLICATIONS SET.\r\n" );
			pObj->value[1] = atoi( argument );
			break;
		case 2:
			ch->println( "CURRENT NUMBER OF APPLICATIONS SET.\r\n" );
			pObj->value[2] = atoi( argument );
			break;
		case 3:
			ch->println( "SPELL TYPE SET.\r\n" );
			pObj->value[3] = skill_lookup( argument );
			break;
		}
		break;

	case ITEM_INSTRUMENT:
		switch ( value_num )
		{
		default:
			do_help( ch, "OLC-ITEM-INSTRUMENT" );
			return false;
		case 0:
			ch->println( "BARDIC SONG MOD SET." );
			pObj->value[0] = atoi( argument );
			break;
		case 1:
			ch->println( "# OF SONGS BEFORE RETUNING SET.  (-1 is infinite)" );
			pObj->value[1] = atoi(argument);
			break;
		}
		break;

	case ITEM_SCROLL:
	case ITEM_POTION:
	case ITEM_PILL:
		switch ( value_num )
	    {
	        default:
		    do_help( ch, "OLC-ITEM-SCROLL-POTION-PILL" );
	            return false;
	        case 0:
				value=atoi( argument );
				if(value==pObj->value[0]){
					ch->println( "Spell level unchanged." );
				}else{
					ch->printlnf( "Spell level changed from %d to %d.\r\n", // Extra lf
						pObj->value[0], value);
					pObj->value[0] = value;
				}
	            break;
	        case 1:
                ch->println( "SPELL TYPE 1 SET.\r\n" );		// Extra lf
	            pObj->value[1] = skill_lookup( argument );
	            break;
	        case 2:
                ch->println( "SPELL TYPE 2 SET.\r\n" );		// Extra lf
	            pObj->value[2] = skill_lookup( argument );
	            break;
	        case 3:
                ch->println( "SPELL TYPE 3 SET.\r\n" );		// Extra lf
	            pObj->value[3] = skill_lookup( argument );
	            break;
	        case 4:
                ch->println( "SPELL TYPE 4 SET.\r\n" );		// Extra lf
	            pObj->value[4] = skill_lookup( argument );
	            break;
 	    }
	    break;


	case ITEM_PARCHMENT:
		switch ( value_num )
		{
		default: return false;
		case 0:  return false;
		case 1:
			ch->println( "Written on field set.  Blank = 0 all else means it can't be written on." );
			pObj->value[1] = atoi( argument );
			break;
		case 2:
			ch->println( "Sealed field set.  Unsealed = 0 all else means it's sealed." );
			pObj->value[2] = atoi( argument );
			break;
		case 3:
			pObj->value[3] = language_safe_lookup(argument)->unique_id;				
			ch->printlnf( "Language set to '%s'.", language_safe_lookup(argument)->name);
			break;
		}
		break;

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

    case ITEM_WEAPON:
		switch ( value_num )
		{
		default:
			ch->println( "Valid v0 weapon class:");
			show_olc_flags_types_value(ch, weapon_class_types,"v0", pObj->value[0]);
			ch->println( "v1 = number of dice to roll.");
			ch->println( "v2 = type of dice to roll.");
			ch->println( "v3 = weapon attack type.");
			ch->println( "v4 = special weapon type.");			
			show_olc_flags_types_value(ch, weapon_flags,"v4", pObj->value[4]);
			ch->println( "");
			ch->println( "SeeAlso: HELP `=_OLC-ITEM-WEAPON");
			return false;
		case 0:
			{
				if ( ( value = flag_value( weapon_class_types, argument ) ) != NO_FLAG ){
					ch->println( "WEAPON CLASS SET.\r\n" );
					pObj->value[0] = flag_value( weapon_class_types, argument );
				}else{
					ch->println( "Valid v0 weapon classes include:");
					show_olc_flags_types_value(ch, weapon_class_types,"v0", pObj->value[0]);
					return false;
				}
			}
			break;
		case 1:
			ch->println( "NUMBER OF DICE SET.\r\n" );
			pObj->value[1] = atoi( argument );
			ch->printlnf( "Average damage is now %d.",
				(int) (pObj->value[1]+(pObj->value[1] * pObj->value[2]))/2);
			break;
		case 2:
			ch->println( "TYPE OF DICE SET.\r\n" );
			pObj->value[2] = atoi( argument );
			ch->printlnf( "Average damage is now %d.",
				(int) (pObj->value[1]+(pObj->value[1] * pObj->value[2]))/2);
			break;
		case 3:
			{
				int att=attack_lookup_with_error( argument );
				if(att<0){
					ch->printlnf("Attack type '%s' not found, must be one of the following:",
						argument);
				    for ( att= 0; attack_table[att].name != NULL; att++)
					{
						ch->printf("   %-12s", attack_table[att].name);
						if(att%4==3){
							ch->print_blank_lines(1);
						}				
					}
				}else{
					ch->println( "WEAPON ATTACK TYPE SET.\r\n" );
					pObj->value[3] = att;
				}
			}
			break;
		case 4:
			ch->println( "SPECIAL WEAPON TYPE TOGGLED.\r\n" );
			pObj->value[4] ^= (flag_value( weapon_flags, argument ) != NO_FLAG
				? flag_value( weapon_flags, argument ) : 0 );
			break;
	}
	break;

	case ITEM_PORTAL:
		switch ( value_num )
		{
		default:
			ch->printlnf( "Valid v1 portal exit flags are: %s", flag_string( exit_flags, -1));
			ch->printlnf( "Valid v2 portal flags are: %s", flag_string( portal_flags, -1));			
			return false;
		case 0:
			ch->println( "CHARGES SET.\r\n" );
			pObj->value[0] = atoi ( argument );
			break;
		case 1:
			if ( ( value = flag_value( exit_flags, argument ) ) != NO_FLAG )
				TOGGLE_BIT(pObj->value[1], value);
			else
			{
				ch->printlnf( "Valid v1 portal exit flags are: %s",
					flag_string( exit_flags, -1));
				do_help ( ch, "OLC-ITEM-PORTAL" );
				return false;
			}
			ch->println( "PORTAL EXIT FLAG SET.\r\n" );
			break;
		case 2:
			if ( ( value = flag_value( portal_flags, argument ) ) != NO_FLAG )
				TOGGLE_BIT(pObj->value[2], value);
			else
			{
				ch->printlnf( "Valid v2 portal flags are: %s",
					flag_string( portal_flags, -1));
				do_help ( ch, "OLC-ITEM-PORTAL" );
				return false;
			}
			ch->println( "PORTAL EXIT FLAG SET.\r\n" );
			break;
		case 3:
			ch->println( "EXIT VNUM SET.\r\n" );
			pObj->value[3] = atoi ( argument );
			break;
		}
		break;

	case ITEM_TOKEN:
		switch ( value_num )
		{
		default:
			do_help(ch, "OLC-ITEM-TOKEN" );
			return false;
		case 0:
			ch->println( "Token Flag Toggled.\r\n" );
			pObj->value[0] = ( flag_value( token_flags, argument ) != NO_FLAG
				? flag_value( token_flags, argument ) : 0 );
			break;
		}
		break;

	case ITEM_COMPONENT:
		switch ( value_num )
		{
			default:
				do_help(ch, "OLC-ITEM-COMPONENT" );
				return false;

			case 0:
				ch->println( "Charges set.\r\n" );
				pObj->value[0] = atoi( argument );
				break;
			case 1:
				ch->println( "Spell set.\r\n" );
				pObj->value[1] = skill_lookup( argument );
				break;
		}
		break;

	case ITEM_FURNITURE:
	    switch ( value_num )
	    {
	        default:
	            do_help( ch, "OLC-ITEM-FURNITURE" );
	            return false;
	            
	        case 0:
                ch->println( "NUMBER OF PEOPLE SET.\r\n" );
	            pObj->value[0] = atoi ( argument );
	            break;
	        case 1:
                ch->println( "MAX WEIGHT SET.\r\n" );
	            pObj->value[1] = atoi ( argument );
	            break;
	        case 2:
				ch->printlnf( "Valid v2 Furniture flags are: %s", flag_string( furniture_flags, -1));
                ch->println( "FURNITURE FLAGS TOGGLED.\r\n" );
	            pObj->value[2] ^= (flag_value( furniture_flags, argument ) != NO_FLAG
	            ? flag_value( furniture_flags, argument ) : 0);
	            break;
	        case 3:
                ch->println( "HEAL BONUS SET.\r\n" );
	            pObj->value[3] = atoi ( argument );
	            break;
	        case 4:
                ch->println( "MANA BONUS SET.\r\n" );
	            pObj->value[4] = atoi ( argument );
	            break;
	    }
	    break;

	case ITEM_CAULDRON:
	case ITEM_CONTAINER:
	case ITEM_FLASK:
	case ITEM_MORTAR:
		switch ( value_num )
		{
			int value;
		default:
			do_help( ch, "OLC-ITEM-CONTAINER" );
			ch->printlnf( "Valid v1 flags include: %s", flag_string( container_flags, -1));
			return false;
		case 0:
			ch->wraplnf( "Maximum combined weight the container can hold changed "
				"from %d lbs to %d lbs.", 
				pObj->value[0], atoi( argument ));
			pObj->value[0] = atoi( argument );
			ch->wrapln("`YNotes:`x v0 = is the maximum combined weight the container can hold... that is "
				"obtained by adding all objects in the containers true weights together.`1"
				"v3 = is the maximum weight any single object can be to be able to be put inside the container.");			
			break;
		case 1:
			if ( ( value = flag_value( container_flags, argument ) ) != NO_FLAG ){
				TOGGLE_BIT(pObj->value[1], value);
			}else{
				ch->printlnf( "Valid v1 container flags are: %s", flag_string( container_flags, -1));
				do_help ( ch, "OLC-ITEM-CONTAINER" );
				return false;
			}
			ch->println( "CONTAINER FLAG SET.\r\n" );
			break;
		case 2:
			if ( atoi(argument) != 0 )
			{
				if ( !get_obj_index( atoi( argument ) ) )
				{
					ch->println( "THERE IS NO SUCH ITEM.\r\n" );
					return false;
				}
				if ( get_obj_index( atoi( argument ) )->item_type != ITEM_KEY )
				{
					ch->println( "THAT ITEM IS NOT A KEY.\r\n" );
					return false;
				}
			}
			ch->println( "CONTAINER KEY SET.\r\n" );
			pObj->value[2] = atoi( argument );
			break;
		case 3:
			ch->wraplnf( "Maximum weight any single object able to be put "
				"into the container changed from %d lbs to %d lbs.", 
				pObj->value[3], atoi( argument ));
			pObj->value[3] = atoi( argument );
			ch->wrapln("`YNotes:`x v0 = is the maximum combined weight the container can hold... that is "
				"obtained by adding all objects in the containers true weights together.`1"
				"v3 = is the maximum weight any single object can be to be able to be put inside the container.");			
			break;
		case 4:
			ch->println( "WEIGHT MULTIPLIER SET.\r\n" );
			pObj->value[4] = atoi ( argument );
			break;
		}
		break;

	case ITEM_DRINK_CON:
		switch ( value_num )
		{
		default:
			do_help( ch, "OLC-ITEM-DRINK" );
			return false;
		case 0:
			ch->println( "MAXIMUM AMOUT OF LIQUID HOURS SET.\r\n" );
			pObj->value[0] = atoi( argument );
			break;
		case 1:
			ch->println( "CURRENT AMOUNT OF LIQUID HOURS SET.\r\n" );
			pObj->value[1] = atoi( argument );
			break;
		case 2:
			ch->println( "LIQUID TYPE SET.\r\n" );
			pObj->value[2] = ( liq_lookup(argument) != -1 ?
				liq_lookup(argument) : 0 );
			break;
		case 3:
			ch->println( "POISON VALUE TOGGLED.\r\n" );
			pObj->value[3] = ( pObj->value[3] == 0 ) ? 1 : 0;
			break;
		}
		break;

	case ITEM_FOUNTAIN:
		switch (value_num)
		{
		default:
			do_help( ch, "OLC-ITEM-FOUNTAIN" );
			return false;
		case 0:
			ch->println( "MAXIMUM AMOUT OF LIQUID HOURS SET.\r\n" );
			pObj->value[0] = atoi( argument );
			break;
		case 1:
			ch->println( "CURRENT AMOUNT OF LIQUID HOURS SET.\r\n" );
			pObj->value[1] = atoi( argument );
			break;
		case 2:
			ch->println( "LIQUID TYPE SET.\r\n" );
			pObj->value[2] = ( liq_lookup( argument ) != -1 ?
				liq_lookup( argument ) : 0 );
			break;
 		case 3:
 			ch->println( "POISON VALUE TOGGLED.\r\n" );
 			pObj->value[3] = ( pObj->value[3] == 0 ) ? 1 : 0;
 			break;
        }
		break;

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

	case ITEM_MONEY:
		{
			int v=atoi(argument);
			switch ( value_num )
			{
			default:
				do_help( ch, "OLC-ITEM-MONEY" );
				return false;
			case 0:
				ch->printlnf( "SILVER AMOUNT CHANGED FROM %d TO %d.", pObj->value[0], v);
				pObj->value[0]=v;
				break;
			case 1:
				ch->printlnf( "GOLD AMOUNT CHANGED FROM %d TO %d.", pObj->value[1], v);
				pObj->value[1]=v;
				break;
			}
		}
		break;
	}

    show_obj_values( ch, pObj );

    return true;
}

/**************************************************************************/
bool oedit_show( char_data *ch, char *)
{
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *paf;
    int cnt;

    EDIT_OBJ(ch, pObj);

  	ch->printlnf( "`=rVnum: `x%-5d   `=rType: `x%-10s `=rLevel: "
        "`x%-3d        `=rArea[%d]: `x%s", 
		pObj->vnum, flag_string( item_types, pObj->item_type ) ,   pObj->level,
		pObj->area ? pObj->area->vnum : 0,
		pObj->area ? pObj->area->file_name : "`RNo Area!!!`x");

	ch->printf(   "`=rCost: `x%-7d ",pObj->cost );
	ch->printf(   "`=rWeight: `x%-3.1f lbs ", ((double)pObj->weight)/10);
	ch->printf(   "`=rCondition: `x%-6d ", pObj->condition );
	ch->printlnf( "`=rMaterial: `x%-14s", pObj->material );

	// sizes
	ch->printf(   "`=rAbsolute size: `x%-6d ", pObj->absolute_size );
	ch->printlnf( "`=rRelative size: `x%-6d", pObj->relative_size );
   
	ch->printlnf( "`=rName: `=x%s", pObj->name);
	ch->printlnf( "`=rShort desc: `=x%s`x", pObj->short_descr);
	if (has_colour(pObj->short_descr))
	{
		ch->print( "`sShort desc: `x" );
		ch->printlnbw(pObj->short_descr);
	}

    ch->printlnf( "`=rLong descr: `=x%s`x", pObj->description);
	if (has_colour(pObj->description))
	{
		ch->print( "`sLong descr: `x" );
		ch->printlnbw(pObj->description);
	}

	// Extended descriptions
	show_char_extended(ch, pObj->extra_descr, false);

	mxp_display_olc_flags(ch, wear_flags, pObj->wear_flags,			"wear",	  "Wear Flags:");
	mxp_display_olc_flags(ch, objextra_flags,  pObj->extra_flags,	"extra",  "Extra Flags:");
	mxp_display_olc_flags(ch, objextra2_flags, pObj->extra2_flags,	"extra2", "Extra2 Flags:");

	if ( IS_SET ( pObj->attune_flags, ATTUNE_NEED_TO_USE ))
	{
		mxp_display_olc_flags(ch, attune_flags, pObj->attune_flags,	"attune", "Attune Flags:");
	}
	if ( pObj->ospec_fun )
	{
		ch->printlnf( "`=rSpecial function: `R%s`x",  ospec_name( pObj->ospec_fun ) );
	}

	if(pObj->item_type!=ITEM_PORTAL){
		if(pObj->class_allowances){
			mxp_display_olc_flags(ch, classnames_flags, pObj->class_allowances,	"classallow", "Class Allowances:");
		}else{
			ch->printlnf( "`=r%s: `xall classes`x", mxp_create_send(ch, "classallow", "Class Allowances"));
		}
	}

    for ( cnt = 0, paf = pObj->affected; paf; paf = paf->next )
    {
		if ( cnt == 0 )	{
            ch->println( "`=rNumber Modifier Affects" );
			ch->println(    "------ -------- -------`x" );
		}

		if ( paf->where == WHERE_SKILLS )
		{
			ch->printf( "[%4d] %-8d Skill - %s",
				cnt, paf->modifier, skill_table[paf->type].name );
		}
		else if ( paf->where == WHERE_OBJECTSPELL )
		{
			ch->printf( "[%4d] ObjectSpell %s - level=%d, duration=%d",
				cnt, skill_table[paf->type].name, paf->level, paf->duration);
		}else{
			if(paf->location==APPLY_NONE){
				ch->printf( "[%4d]     ", cnt);
			}else{
				ch->printf( "[%4d] %8d %s",
					cnt,
					paf->modifier,
					flag_string( apply_types, paf->location ) );
			}
		}
		// say what the 'none' do
		if (paf->bitvector){
			ch->printlnf( "%s", to_affect_string( paf, pObj->level ));
		}else{
			ch->println("");
		}
		cnt++;
    }
 	ch->print( "`x" );

	if(pObj->restrict){
		OBJRESTRICT_LIST_DATA *pr;
		ch->println( "`=r========ClassGroups Object Restrictions========" );
		ch->println( "`=r       ClassGroup       Affect Profile          Prority" );
		ch->println( "--------------------    -----------------------  ---------`x" );

		for ( cnt=0, pr = pObj->restrict; pr; pr = pr->next, cnt++)
		{
	        ch->printlnf( "[%4d] %-20.20s %10s  %3d", 
				cnt,
				pr->classgroup->name,
				pr->affectprofile->name,
				pr->priority);
		}
		ch->println( "note: if multiple classgroup matches, only highest priority is applied.`x" );
    }
 	ch->print( "`x" );

	show_obj_values( ch, pObj );

    return false;
}

/**************************************************************************/
bool oedit_addrestrict( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
	classgroup_type *cg;
	affectprofile_type *ap;
	OBJRESTRICT_LIST_DATA *pr;
    char classgroup[MIL];
    char affectprofile[MIL];
	char strprority[MIL];
	int priority;

    EDIT_OBJ(ch, pObj);
    argument = one_argument( argument, classgroup);
    argument = one_argument( argument, affectprofile);
	one_argument( argument, strprority);
	
    if ( IS_NULLSTR(classgroup) || IS_NULLSTR(affectprofile))
    {
		if(!codehelp(ch,"oedit_addrestrict", CODEHELP_ALL_BUT_PLAYERS)){
			ch->println("Syntax:  addrestrict <classgrouping> <affectprofile> [priority]");
			ch->println("showaffectprofile lists all affect profiles.");
		}
		return false;
    }

	if (pObj->item_type == ITEM_TRASH){
        ch->println("You can't add classgroup restrictions to objects of type trash.");
		return false;
	}

	if(IS_NULLSTR(strprority)){
		priority=-1;
	}else if(!is_number(strprority)){
        ch->println("The priority must be a number between 0 and 100.");
		return false;
	}else{
		priority=atoi(strprority);
	};

	if(priority>100 || priority<-1){
        ch->println("The priority must be a number between 0 and 100.");
		return false;
	}

	// check the parameters
	cg=classgroup_lookup(classgroup);
	if(!cg)
	{
		int index;
		ch->printlnf( "No such classgroup '%s'", classgroup);
		ch->println( "The classgroup must be one of the following:" );
		for(index=0; !IS_NULLSTR(classgroup_table[index].name);index++){
			ch->printlnf( "%-15s - %s",
				classgroup_table[index].name,
				classgroup_table[index].description);
		}
		return false;
	}

	ap=affectprofile_lookup(affectprofile);
	if(!ap)
	{
		int index;
		ch->printlnf( "No such affectprofile %s'", affectprofile);
		ch->println(  "The affectprofile must be one of the following:" );
		for(index=0; !IS_NULLSTR(affectprofile_table[index].name);index++){
			ch->printlnf( "%-15s - %s", 
				affectprofile_table[index].name,
				affectprofile_table[index].description);
		}
		return false;
	}
	pr=new OBJRESTRICT_LIST_DATA;
	pr->affectprofile=ap;
	pr->classgroup=cg;
	pr->priority=priority;
	// add to the linked list
	pr->next=pObj->restrict;
	pObj->restrict=pr;
	// create bit quick lookup
	SET_BIT(pObj->objrestrict,(1<<pObj->restrict->classgroup->bitindex)); 
    ch->printlnf( "Object Classgroup restriction added:\r\n"
		"   classgroup=%s, affectprofile=%s, priority=%d.",
		pr->classgroup->name, pr->affectprofile->name, pr->priority);
    return true;
}
/**************************************************************************/
bool oedit_delrestrict( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
	OBJRESTRICT_LIST_DATA *pr, *pr_next;
    int  value;
    int  cnt = 0;

    EDIT_OBJ(ch, pObj);

	if ( IS_NULLSTR( argument ))
	{
		ch->println( "Syntax:  delrestrict <#affectprofile>" );
		return false;
	}

    if ( !is_number( argument ))
    {
		ch->println( "#affectprofile must be a number." );
		oedit_delrestrict(ch,"");
		return false;
    }

    value = atoi( argument );
    if ( value < 0 )
    {
		ch->println( "Only non-negative restrict-numbers allowed." );
		return false;
    }

	pr=pObj->restrict;
    if ( !pr )
    {
		ch->println( "OEdit: There a no classgroup restrictions on this object." );
		return false;
    }

    if( value == 0 )	// First case: Remove first affect 
    {
		pr = pObj->restrict;
		pObj->restrict = pr->next;
    }
    else		// Affect to remove is not the first 
    {
		while ( ( pr_next = pr->next ) && ( ++cnt < value ) ){
			pr = pr_next;
		}
		
		if( pr_next )		// See if it's the next affect 
		{
			pr->next = pr_next->next;
		}
		else	// Doesn't exist 
		{
			ch->println( "No such restrict." );
			return false;
		}
    }

    ch->printlnf( "Object Classgroup restriction %d removed:\r\n"
		"   classgroup=%s, affectprofile=%s, priority=%d.",
		value, pr->classgroup->name, pr->affectprofile->name, pr->priority);
	delete pr;

	// reset the bitmask
	pObj->objrestrict=0;
	for(pr=pObj->restrict; pr; pr=pr->next){
		SET_BIT(pObj->objrestrict,(1<<pr->classgroup->bitindex));
	}
    return true;
}
/**************************************************************************/
bool oedit_name ( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    if ( IS_NULLSTR(argument) )
    {
		ch->println( "Syntax:  name <string>" );
		return false;
    }

	ch->printlnf( "Object name changed from '%s' to '%s'.", pObj->name, lowercase(argument));
    replace_string( pObj->name, lowercase(argument));
   
    return true;
}
/**************************************************************************/
bool oedit_short( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    // trim the spaces to the right of the short
    while ( !IS_NULLSTR(argument) && is_space(argument[str_len(argument)-1]))
    {
        argument[str_len(argument)-1]='\0';
    }

    if ( IS_NULLSTR(argument) )
    {
        ch->println("Syntax:  short <string>" );
		ch->println("Note: <string> is forced to lowercase unless there are colour codes in it.");
		return false;
    }

	if(has_colour(argument)){
		ch->wraplnf( "Changed object short description from '%s' to '%s' "
			"(lower case not forced due to colour codes).",
			pObj->short_descr, argument);
		replace_string(pObj->short_descr, argument);
	}else{
		ch->printlnf( "Changed object short description from '%s' to '%s'.",
			pObj->short_descr, lowercase(argument));
		replace_string(pObj->short_descr, lowercase(argument));
	}
    return true;
}

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

    EDIT_OBJ(ch, pObj);

    // trim the spaces to the right of the short
    while ( !IS_NULLSTR(argument) && is_space(argument[str_len(argument)-1]))
    {
        argument[str_len(argument)-1]='\0';
    }

    if ( argument[0] == '\0' )
    {
		ch->println( "Syntax: long <string>" );
		ch->println( "  (this is the description of the object seen in the room when you type look.)" );
		ch->println( "  e.g. A large rock is resting here." );
		return false;
	}

	char *ptemp=pObj->description;
	pObj->description = str_dup( argument );
	pObj->description[0] = UPPER( pObj->description[0] );
	ch->printlnf( "Long description from '%s' to '%s'.",
		ptemp, pObj->description);

    free_string( ptemp );

    return true;
}
/**************************************************************************/
bool oedit_nolong( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);   

	if ( IS_NULLSTR(argument) || str_cmp("confirm", argument))
    {
		ch->println( "Syntax:  nolong confirm" );
		ch->println( "  This removes the long descript, allowing for hidden objects in the room" );
		return false;
	}

	// do security checks
	if (!HAS_SECURITY(ch, OEDIT_NOLONG_MINSECURITY))
	{
		ch->printlnf( "You must have an olc security %d or higher to use this command.",
			OEDIT_NOLONG_MINSECURITY);
		return false;
	}

    replace_string(pObj->description,"");
    ch->println( "Long description cleared." );
    return true;
}

/**************************************************************************/
bool set_value( char_data *ch, OBJ_INDEX_DATA *pObj, char *argument, int value )
{
    if (IS_NULLSTR(argument)){
		set_obj_values( ch, pObj, -1, "" );
		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 five valueX functions below.
 ****************************************************************************/
bool oedit_values( char_data *ch, char *argument, int value )
{
    OBJ_INDEX_DATA *pObj;

    EDIT_OBJ(ch, pObj);

    if ( set_value( ch, pObj, argument, value ) ){
        return true;
	}
    return false;
}
/**************************************************************************/
bool oedit_value0( char_data *ch, char *argument )
{
    if ( oedit_values( ch, argument, 0 ) )
        return true;
    return false;
}
/**************************************************************************/
bool oedit_value1( char_data *ch, char *argument )
{
    if ( oedit_values( ch, argument, 1 ) )
        return true;
    return false;
}
/**************************************************************************/
bool oedit_value2( char_data *ch, char *argument )
{
    if ( oedit_values( ch, argument, 2 ) )
        return true;

    return false;
}
/**************************************************************************/
bool oedit_value3( char_data *ch, char *argument )
{
    if ( oedit_values( ch, argument, 3 ) )
        return true;
    return false;
}
/**************************************************************************/
bool oedit_value4( char_data *ch, char *argument )
{
    if ( oedit_values( ch, argument, 4 ) )
        return true;
    return false;
}

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

    EDIT_OBJ(ch, pObj);

	if ( IS_NULLSTR(argument) || !is_number( argument ) )
	{
		ch->println( "Syntax:  weight <number>" );
		ch->println( "Where the number is in 10th of a pound.");
		ch->println( "e.g. 8=0.8lbs, 20=2lbs.");
		return false;
	}

	int value=atoi( argument);
	
	if(value<0){
		ch->println("oedit_weight(): Weight must be 0 or greater.");
		oedit_weight(ch,"");
		return false;
	}

	ch->printlnf( "Weight changed from %0.1f lbs to %0.1f lbs.", 
		((double)pObj->weight/10), ((double)value)/10);
	pObj->weight = value;
	return true;
}

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

	EDIT_OBJ(ch, pObj);

	if ( IS_NULLSTR(argument) || !is_number( argument ) )
	{
		ch->println( "Syntax:  cost <number>" );
		return false;
	}

	int value=atoi( argument);
	
	if(value<0){
		ch->println("oedit_cost(): Cost must be 0 or greater.");
		oedit_cost(ch,"");
		return false;
	}

	ch->printlnf( "Cost changed from %d to %d.", pObj->cost, value);
	pObj->cost = value;
    return true;
}


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

    value = atoi( argument );
    if ( argument[0] == '\0' || value == 0 )
    {
		ch->println( "Syntax:  oedit create <vnum>" );
		return false;
	}

	pArea = get_vnum_area( value );

	if ( !pArea )
	{
		ch->println( "OEdit: That vnum is not assigned an area." );
		return false;
    }

    if ( !IS_BUILDER( ch, pArea, BUILDRESTRICT_OBJECTS) )
    {
		ch->println( "OEdit: Vnum in an area you cannot create objects in." );
		return false;
    }

    if ( get_obj_index( value ) )
    {
		ch->println( "OEdit:  Object vnum already exists." );
		return false;
	}

	pObj					= new_obj_index();
	pObj->vnum				= value;
	pObj->area				= pArea;
	pObj->relative_size		= 50;		// main size so all can wear it
        
	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;

	{ // add vnums to new object default descriptions
		char buf[MIL];
		sprintf(buf, "no name %d", value);  
		replace_string(pObj->name, buf);
		sprintf(buf, "(no short description %d)", value);  
		replace_string(pObj->short_descr, buf);
		sprintf(buf, "(no description %d)", value);  
		replace_string(pObj->description, buf);
	}

    ch->printlnf( "Object %d Created.", value );
    return true;
}

/**************************************************************************/
bool oedit_ed( char_data *ch, char *argument ) 
{
	return( generic_ed (ch, argument) );
}

/**************************************************************************/
bool oedit_extra( char_data *ch, char *argument )
{
	OBJ_INDEX_DATA *pObj;
	EDIT_OBJ(ch, pObj);
	return olc_generic_flag_toggle(ch, argument, "extra", "extra", objextra_flags, &pObj->extra_flags);
}
/**************************************************************************/
bool oedit_extra2( char_data *ch, char *argument )
{
	OBJ_INDEX_DATA *pObj;
	EDIT_OBJ(ch, pObj);
	return olc_generic_flag_toggle(ch, argument, "extra2", "extra2", objextra2_flags, &pObj->extra2_flags);
}

/**************************************************************************/
bool oedit_wear( char_data *ch, char *argument )
{
	OBJ_INDEX_DATA *pObj;
	EDIT_OBJ(ch, pObj);
	return olc_generic_flag_toggle(ch, argument, "wear", "wear", wear_flags, &pObj->wear_flags);
}

/**************************************************************************/
bool oedit_type( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
	EDIT_OBJ(ch, pObj);
    int value;

    if ( !IS_NULLSTR(argument))
    {

		if ( ( value = flag_value( item_types, argument ) ) != NO_FLAG )
		{
			if(pObj->item_type == value){
				ch->printlnf( "Object is already type '%s'",  
					flag_string( item_types, pObj->item_type ));
			
				return false;
			}
	        ch->printlnf( "Type changed from '%s' to '%s'.",  
				flag_string( item_types, pObj->item_type ),
				flag_string( item_types, value ));
		    pObj->item_type = value;

		    // Clear the values.
			switch (pObj->item_type)
			{
			case ITEM_SCROLL:
			case ITEM_POTION:
			case ITEM_PILL:
				pObj->value[0] = -1; // set them to none
				pObj->value[1] = -1;
				pObj->value[2] = -1;
				pObj->value[3] = -1;
				pObj->value[4] = -1;
				break;
			case ITEM_WAND:
			case ITEM_STAFF:
				pObj->value[0] = 0;
				pObj->value[1] = 0;
				pObj->value[2] = 0;
				pObj->value[3] = -1;
				pObj->value[4] = 0;
				break;
			default:
				pObj->value[0] = 0;
				pObj->value[1] = 0;
				pObj->value[2] = 0;
				pObj->value[3] = 0;
				pObj->value[4] = 0;
				break;
			}

			return true;
		}
	}

	show_olc_options(ch, item_types, "type", "type", pObj->item_type);
	return false;
}

/**************************************************************************/
bool oedit_material( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
    EDIT_OBJ(ch, pObj);

    if ( IS_NULLSTR(argument))
    {
		ch->println( "Syntax:  material <string>" );
		return false;
    }

	replace_string( pObj->material, lowercase(argument));

    ch->printlnf( "Material set to '%s'.", pObj->material );
    return true;
}

/**************************************************************************/
bool oedit_level( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
	AFFECT_DATA *paf;
	int value;

    EDIT_OBJ(ch, pObj);

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
		ch->println( "Syntax:  level <number>" );
		return false;
    }

	value=atoi( argument );
    if( pObj->level == value){
		ch->println("Level unchanged.");
	};

    ch->printlnf( "Object level changed from %d to %d.", 
		pObj->level , value);

    for ( paf = pObj->affected; paf; paf = paf->next )
	{
		paf->level=value;
	}
	pObj->level = value;
    return true;
}



/**************************************************************************/
bool oedit_condition( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
    int value;

    if ( !IS_NULLSTR(argument)
    && ( value = atoi (argument ) ) >= 1
    && ( value <= 100 ) )
    {
		EDIT_OBJ( ch, pObj );

		ch->printlnf( "Condition changed from %d to %d.", 
			pObj->condition, value);
		pObj->condition = value;
		return true;
    }

    ch->println("Syntax:  condition <number>");
	ch->println("Where number can range from 1 (ruined) to 100 (perfect).");
    return false;
}

/**************************************************************************/
bool oedit_classallowances( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
	EDIT_OBJ(ch, pObj);
    int value;

    if ( IS_NULLSTR(argument))
    {
		show_olc_options(ch, classnames_flags, "classallow", "classallowance", pObj->class_allowances);
		ch->println( "note: If no class allowances are set, then all classes can use the object." );
		ch->println( "If class allowances are set, then only the classes on the list can use the object." );
		return false;
	}

	if ( ( value = flag_value( classnames_flags, argument ) ) != NO_FLAG )
	{
		TOGGLE_BIT(pObj->class_allowances, value);
		
		ch->println( "Classallowances flag toggled." );
		return true;
	}

	ch->printlnf("Unrecognised classname '%s'", argument);
    return false;
}

/**************************************************************************/
bool oedit_asize( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
	int value;

    EDIT_OBJ(ch, pObj);

    if ( argument[0] == '\0' || !is_number( argument ) )
    {
        ch->println( "Syntax:  asize <number>" );
        ch->println( "(note at this stage absolute size has no effect)" );
		return false;
    }

	value = atoi( argument );
    pObj->absolute_size = value;

	ch->printlnf( "Absolute size set to %d.", value );
    ch->println( "(note at this stage absolute size has no effect)" );
    return true;
}

/**************************************************************************/
bool oedit_rsize( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
	int value, race;

    EDIT_OBJ(ch, pObj);

    if ( IS_NULLSTR(argument) || !is_number( argument ) ){
		ch->println( "Syntax:  rsize <number>" );
		ch->wrapln( "Every object has a relative size value, if this value "
			"is smaller than a races lowsize, the object will be too small for that "
			"race to wear (and the reverse for a races high size).  "
			"The default convention for an object that is wearable by "
			"all races is to set the relative size to 50.");
		return false;
    }

	value = atoi( argument );
	if (value>100 || value<10)
	{
	    ch->println( "Try a value closer to 50." );
		return false;
	}

	{
		char race_wear_list[MSL];
		char race_nowear_list[MSL];
		
		race_wear_list[0]='\0';
		race_nowear_list[0]='\0';
		for ( race = 1; race_table[race]; race++ )
		{
			if (value>=race_table[race]->low_size
				&& value<=race_table[race]->high_size)
			{
				strcat(race_wear_list,race_table[race]->name);
				strcat(race_wear_list,"\r\n");
			}else{
				strcat(race_nowear_list,race_table[race]->name);
				if(value<race_table[race]->low_size){
					strcat(race_nowear_list," - object is too small.\r\n");
				}else{
					strcat(race_nowear_list," - object is too big.\r\n");
				}				
			}
		}

		pObj->relative_size = value;
		ch->printlnf( "Relative size set to %d.", value);

		if (IS_NULLSTR(race_wear_list))
		{
			ch->println( "Warning, no player races can wear it with that relative size value." );
		}	
		else
		{
			ch->printlnf( "`YPlayer races that `Gcan`Y wear it:`x%s", 
				race_wear_list );
			ch->printlnf( "`YPlayer races that `Rcan't`Y wear it:`x%s",
				race_nowear_list );
		}
	}
    return true;
}
/**************************************************************************/
// duplicate the object data from another 
// written by Kalahn - June 98
bool oedit_copy(char_data *ch, char *argument)
{
	OBJ_INDEX_DATA *pObj;
	OBJ_INDEX_DATA *pSrc; // source object
	char arg1[MIL];
	int value;

    argument = one_argument( argument, arg1 );

    if ( !is_number( arg1 ) )
    {
        ch->println( "Syntax: ocopy <source object vnum>" );
        ch->println( "  - copies the source object over the object you are currently editing!" );
        ch->println( "    (warning copies over everything!)" );
        return false;
	}

    value = atoi( arg1 );
    if ( !( pSrc = get_obj_index( value ) ) )
    {
        ch->println( "OEdit_copy:  The source vnum does not exist." );
        return false;
    }
    
    if ( !IS_BUILDER( ch, pSrc->area, BUILDRESTRICT_OBJECTS) && !IS_IMMORTAL(ch) )
    {
        ch->println( "Insufficient security to copy from the area that object\r\n"
            "is stored in and your aren't an immortal." );
        return false;
    }
    
	EDIT_OBJ(ch, pObj);

	// copy the object details
	pObj->name			= str_dup(pSrc->name);
	pObj->short_descr	= str_dup(pSrc->short_descr);
	pObj->description	= str_dup(pSrc->description);
	pObj->material		= str_dup(pSrc->material);

	pObj->item_type		= pSrc->item_type;

	pObj->extra_flags	= pSrc->extra_flags;
        pObj->extra2_flags      = pSrc->extra2_flags;
	pObj->wear_flags	= pSrc->wear_flags;
		
	pObj->level			= pSrc->level;
	pObj->condition		= pSrc->condition;
	pObj->count			= pSrc->count;
	pObj->weight		= pSrc->weight;
	pObj->cost			= pSrc->cost;
	pObj->value[0]		= pSrc->value[0];
	pObj->value[1]		= pSrc->value[1];
	pObj->value[2]		= pSrc->value[2];
	pObj->value[3]		= pSrc->value[3];
	pObj->value[4]		= pSrc->value[4];
	pObj->value[4]		= pSrc->value[4];
	pObj->absolute_size	= pSrc->absolute_size;
	pObj->class_allowances = pSrc->class_allowances;


	// NOTE: we aren't deallocating the existing affects and 
	//	descriptions on the objects... we should, but I can't be
	//	bothered writing the code to do so right now

	// COPY AFFECTS 
	pObj->affected =dup_affects_list(pSrc->affected);

	// COPY THE EXTENDED DESCRIPTIONS 
	pObj->extra_descr	= dup_extdescr_list(pSrc->extra_descr);

//	sh_int         vnum;
//	sh_int         reset_num;
//	AREA_DATA *    area;           

	ch->wraplnf( "`=rCopied object '%s'[%d] to vnum %d", 
				pSrc->short_descr, pSrc->vnum, pObj->vnum);
    return true;
}
/**************************************************************************/
bool oedit_attune( char_data *ch, char *argument )
{
    int value;
    OBJ_INDEX_DATA *pObj;
	EDIT_OBJ(ch, pObj);

	if( !IS_IMMORTAL( ch )) {
		ch->println( "oedit_attune(): Currently only for immortal testing." );
		return false;
	}

    if( !IS_NULLSTR(argument))
    {
		
		if ( ( value = flag_value( attune_flags, argument ) ) != NO_FLAG )
		{
			TOGGLE_BIT(pObj->attune_flags, value);
			ch->println( "Attune flag toggled." );
			return true;
		}
    }
	
	show_olc_options(ch, attune_flags, "attune", "attune", pObj->attune_flags);
    return false;
}
/**************************************************************************/
bool oedit_addskill( char_data *ch, char *argument )
{
    int value;
    OBJ_INDEX_DATA *pObj;
    EDIT_OBJ(ch, pObj);
    AFFECT_DATA *pAf;
    char sn[MSL];
    char mod[MSL];
	int modifier;

	if( !IS_IMMORTAL( ch )) {
		ch->println( "oedit_addskill(): Currently only for immortal testing." );
		return false;
	}


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

    if ( IS_NULLSTR(sn) || IS_NULLSTR(mod) ){
		ch->println( "Syntax:  addskill <skillname> <modifier>" );
		return false;
    }

	if(!is_number( mod ) ){
		ch->println( "Modifier must be a number." );
		oedit_addskill(ch,"");
		return false;
	}

	modifier=atoi(mod);
	if (  modifier< 0 || modifier> 50 )
	{
		ch->println("Value must range from 0 to 50.");
		return false;
	}

	if (pObj->item_type == ITEM_TRASH){
        ch->println( "You can't add a skill modifiers to objects of type trash." );
		return false;
	}

	if (pObj->item_type == ITEM_RP){
        ch->println( "You can't add a skill modifiers to RP objects." );
		return false;
	}

    if (( value = skill_lookup( sn )) == -1 )
    {
        ch->println( "That's not a valid skill." );
		return false;
    }

    pAf             =   new_affect();
    pAf->location   =   APPLY_NONE;
    pAf->modifier   =   modifier;
    pAf->where	    =   WHERE_SKILLS;
    pAf->type       =   value;
    pAf->duration   =   -1;
    pAf->bitvector  =   0;
    pAf->level      =	pObj->level;
    pAf->next       =   pObj->affected;
    pObj->affected  =   pAf;

    ch->printlnf( "Skill modifier '%s' by %d added.", 
		skill_table[value].name, modifier);
    return true;
}

/**************************************************************************/
bool oedit_addspell( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *pAf;

	char name[MIL];
	char level[MIL];
	char duration[MIL];
	char use_spell_for_all_levels[MIL];

    argument = one_argument( argument, name);
    argument = one_argument( argument, level);
    argument = one_argument( argument, duration);
	argument = one_argument( argument, use_spell_for_all_levels);
	
    if ( IS_NULLSTR(name))
    {
		ch->println("Syntax: addspell 'spellname' [level] [duration] [use_spell_for_all_levels]");
		ch->println("Notes: If level is 0, object level is used (default).");
		ch->println("       If duration is 0, spell duration is used.");
		ch->println("       If duration is -1, spell is permanant while object is worn (default).");
		ch->println("       If use_spell_for_all_levels is 1, then the spell will take effect ");
		ch->println("       even if the spell/object is over the players level.");
		return false;
    }

	// check the spell name is valid
	int sn=skill_lookup(name);
	if(sn<FIRST_SPELL || sn>LAST_SPELL){
		ch->printf("oedit_addspell: Couldn't find the spell '%s' to add to object.\r\n",
			name);
		oedit_addspell(ch,"");
		return false;
	}

	// get/check the numeric values
	int ilevel=0;
	int iduration=-1;
	if(!IS_NULLSTR(level)){
		if(is_number(level)){
			ilevel=atoi(level);
		}else{
			ch->println("oedit_addspell: level must be numeric if specified.");
			oedit_addspell(ch,"");
			return false;
		}

		if(!IS_NULLSTR(duration)){
			if(is_number(duration)){
				iduration=atoi(duration);
			}else{
				ch->println("oedit_addspell: duration must be numeric if specified.");
				oedit_addspell(ch,"");
				return false;
			}
		}

	}

    EDIT_OBJ(ch, pObj);
	if (pObj->item_type == ITEM_TRASH)
	{
        ch->println( "You can't add spells to objects of type trash." );
		return false;
	}

	if (pObj->item_type == ITEM_RP)
	{
        ch->println( "You can't add spells to objects of RP items." );
		return false;
	}

    pAf             =   new_affect();
    pAf->location   =   APPLY_NONE;
    pAf->modifier   =   0;
    pAf->where	    =   WHERE_OBJECTSPELL;
    pAf->type       =   sn;
    pAf->duration   =   iduration;
	if(!str_cmp(use_spell_for_all_levels,"1")){
		pAf->bitvector  =   OBJSPELL_IGNORE_LEVEL;
	}else{
		pAf->bitvector  =   0;
	}
    pAf->level      =	ilevel;
    pAf->next       =   pObj->affected;
    pObj->affected  =   pAf;

	ch->printlnf("ObjectSpell '%s' added.", skill_table[sn].name);
    return true;
}

/**************************************************************************/
bool oedit_delaffect( char_data *ch, char *argument )
{
	OBJ_INDEX_DATA *pObj;
	AFFECT_DATA *pAf;
	AFFECT_DATA *pAf_next;
	char affect[MSL];
	int  value;
	int  cnt = 0;

	EDIT_OBJ(ch, pObj);

	one_argument( argument, affect );

	if ( !is_number( affect ) || affect[0] == '\0' )
	{
		ch->println( "Syntax:  delaffect <#xaffect>" );
		ch->println( "Syntax:  delflag <#xaffect>" );
		ch->println( "Syntax:  delmodifier <#xaffect>" );
		return false;
	}

	value = atoi( affect );

	if ( value < 0 )
	{
		ch->println( "Only non-negative affect-numbers allowed." );
		return false;
	}

	if ( !( pAf = pObj->affected ) )
	{
		ch->println( "OEdit:  Non-existant affect." );
		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 
		{
			ch->println( "No such affect." );
			return false;
		}
	}

	ch->println( "Affect removed." );
	return true;
}

/**************************************************************************/
bool oedit_addmodifier( char_data *ch, char *argument )
{
    int value;
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *pAf;
    char location[MSL];
    char amount[MSL];

    EDIT_OBJ(ch, pObj);
    argument = one_argument( argument, location );
    one_argument( argument, amount );

    if ( IS_NULLSTR(location) || IS_NULLSTR(amount))
    {
		ch->println( "Syntax:  addmodifer <location> <amount>" );
		ch->println( "Where <location> is one of:");
		show_olc_flags_types(ch, apply_types);
		ch->println( "(<amount> is a number)");

		if (pObj->item_type == ITEM_TRASH){
			ch->println( "You can't add modifiers to objects of type trash." );
		}
		if (pObj->item_type == ITEM_RP){
			ch->println( "You can't add modifiers to objects of RP items." );
		}
		return false;
    }

	if(!is_number( amount ) ){
		ch->println( "<amount> must be a number." );
		oedit_addmodifier(ch,"");
		return false;
	}

	if (pObj->item_type == ITEM_TRASH){
        ch->println( "You can't add modifiers to objects of type trash." );
		return false;
	}

	if (pObj->item_type == ITEM_RP){
        ch->println( "You can't add modifiers to objects of RP items." );
		return false;
	}

    if ( ( value = flag_value( apply_types, location ) ) == NO_FLAG )
    {
		ch->println("Valid modifiers to apply include:");
		show_olc_flags_types(ch, apply_types);		
		return false;
    }

    pAf             =   new_affect();
    pAf->location   =   (APPLOC)value;
    pAf->modifier   =   atoi( amount);
    pAf->where	    =   WHERE_MODIFIER;
    pAf->type       =   -1;
    pAf->duration   =   -1;
    pAf->bitvector  =   0;
    pAf->level      =	pObj->level;
    pAf->next       =   pObj->affected;
    pObj->affected  =   pAf;

    ch->printlnf( "Modifing affect '%s' added to object... (use delmodifier to remove modifying affects).", 
		to_affect_string(pAf, pObj->level) );
    return true;
}
/**************************************************************************/
// - Kal
bool oedit_addflag( char_data *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
    AFFECT_DATA *pAf;
    char where[MSL];
    char flag[MSL];
	int wherevalue, flagvalue;

    EDIT_OBJ(ch, pObj);
	
    argument = one_argument( argument, where );
    argument = one_argument( argument, flag);

	if(IS_NULLSTR(where)){
		ch->println( "Syntax: addflag <where> <flag>" ); // flag sets the bitvector
		ch->println( "e.g. addflag affects swim" );
    	
		ch->println( "Valid <where> places to apply to include:" );
		show_olc_flags_types(ch, to_types);        
		ch->println( "The <flag>'s available depend on <where> the flag is being applied." );

		if (pObj->item_type == ITEM_TRASH){
			ch->println( "You can't add applies to objects of type trash." );
		}
		if (pObj->item_type == ITEM_RP){
			ch->println( "You can't add applies to RP objects." );
		}
		return false;
	}

	if (pObj->item_type == ITEM_TRASH){
        ch->println( "You can't add applies to objects of type trash." );
		return false;
	}

	if (pObj->item_type == ITEM_RP){
        ch->println( "You can't add applies to RP objects." );
		return false;
	}

    if ( (wherevalue= flag_value( to_types, where)) == NO_FLAG ){
    	ch->println( "Invalid <where> location to apply a flag to... valid places <where> you can apply a flag include:" );
		show_olc_flags_types(ch, to_types);
    	return false;
    }
	const flag_type *bv_flags=affect_get_bitvector_table_for_where(wherevalue);

	if ( !bv_flags ){
		ch->wraplnf( "oedit_addflag(): coding bug - please report: For some reason "
			"affect_get_bitvector_table_for_where() returned NULL for a wherevalue of %d, "
			"The most likely cause of this is a new character affect location has been "
			"added but not added to affect_get_bitvector_table_for_where() or an affect "
			"of another type has been added to to_types[], and should be flagged as false. "
			"Until this is fixed, you cant add flags with a <where> of '%s'"
			, wherevalue, where);
		return false;
	}

    if ( IS_NULLSTR(flag) ){
		oedit_addflag(ch,"");
        ch->printlnf( "Valid flags when applying '%s' include:", where);
		show_olc_flags_types(ch, bv_flags);		
		return false;
    }

	flagvalue=flag_value( bv_flags, flag);
    if ( flagvalue== NO_FLAG )
    {
		ch->printlnf( "Invalid flag type '%s'.", flag);
        ch->printlnf( "Valid flags when applying '%s' include:", where);
		show_olc_flags_types(ch, bv_flags);		
		return false;
	}

    pAf             =   new_affect();
    pAf->location   =   APPLY_NONE;
    pAf->modifier   =   0;
	pAf->where      =   wherevalue;
    pAf->type	    =	-1;
    pAf->duration   =   -1;
    pAf->bitvector  =   flagvalue;
    pAf->level      =	pObj->level;
    pAf->next       =   pObj->affected;
    pObj->affected  =   pAf;

    ch->printlnf( "Flag '%s' added... (use delflag to remove flagged affects)", 
		to_affect_string(pAf, pObj->level));
    return true;
}
/**************************************************************************/
bool oedit_delete( char_data *ch, char *)
{
	ch->println("If you want to delete an object, use the 'odelete' command");
	return false;
}
/**************************************************************************/
// Kal, Feb 2001
bool oedit_odelete(char_data *ch, char *argument)
{
    OBJ_INDEX_DATA *pObj;
    EDIT_OBJ(ch, pObj);

    if (IS_NULLSTR(argument))
    {
		ch->titlebar("ODELETE SYNTAX");
        ch->println("Syntax: odelete confirm - delete the current object");
        ch->println("Syntax: odelete <number> confirm - delete object vnum <number>");
		ch->println("Any object that you delete must meet the following conditions:");
		ch->println("* Must not be used by any reset in any room.");
		ch->println("* Must not be currently loaded in the game.");
		ch->println("* Gameedit can't be making use of the object.");
		ch->println("* You must have sufficient security to edit that object.");
		ch->println("* Noone else can currently be editing the object.");
        ch->wrapln("NOTE: It is strongly recommended that no mobprogs attempt to load the object "
			"you are considering deleting... the easiest method to do this is 'textsearch mobprog <objvnum>'.");
		return false;
    }

	// support specifying the object by vnum
	char arg1[MIL];
	OBJ_INDEX_DATA *pDeleteObj;
	argument=one_argument(argument, arg1);
	if(is_number(arg1)){
		pDeleteObj=get_obj_index(atoi(arg1));
		if(!pDeleteObj){
			ch->printlnf("oedit_odelete(): There is no object number %s to delete.", arg1);
			return false;
		}
		argument=one_argument(argument, arg1); // put the word 'confirm' into arg1
	}else{
		pDeleteObj=pObj; // deleting the object we are currently editing
	}

	// security check
	if ( !IS_BUILDER( ch, pDeleteObj->area, BUILDRESTRICT_OBJECTS ) )
    {
        ch->printlnf("OEdit: Insufficient security to delete object %d.", pDeleteObj->vnum);
        return false;
    }

	// confirm they are using 'confirm'
	if(str_cmp(arg1, "confirm")){
		ch->println("You must confirm your intention to delete an object.");
		oedit_odelete(ch,"");
		return false;
	}

	if(!IS_NULLSTR(ltrim_string(argument))){
		ch->println("Incorrect syntax - too many arguments, or arguments in wrong order.");
		oedit_odelete(ch, "");
		return false;
	}

	int v=pDeleteObj->vnum;
	// We have the object they are wanting to delete and they have 
	// confirmed they want to delete it, check if it isn't in use
	{
		int in_use=0;
		// objects in game
		for ( obj_data *inuse_obj= object_list; inuse_obj; inuse_obj= inuse_obj->next ){
			if(inuse_obj->pIndexData==pDeleteObj){
				ch->printlnf("`=rOne or more objects based on object template %d are currently in the game... use owhere <vnum> to find them.`x", v);
				in_use++;
				break;
			}
		}

		// resets using this object
		for( int iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
		{
			for( ROOM_INDEX_DATA *pRoom= room_index_hash[iHash]; pRoom; pRoom = pRoom->next )
			{
				for ( RESET_DATA *pReset = pRoom->reset_first; pReset; pReset = pReset->next )
				{
					if( pReset->arg1==v  && 
						(pReset->command=='P' 
						|| pReset->command=='O' 
						|| pReset->command=='G' 
						|| pReset->command=='E' 
						) )
					{
						ch->printlnf("object %d reset in room %d (%s).", 
							v, pRoom->vnum, pRoom->name);
						in_use++;
					}
				}
			}
		}

		for(int i=0; !IS_NULLSTR(gameset_value[i].name); i++){
			if(gameset_value[i].category!=GSVC_OBJECT){
				continue;
			}
			// get our numeric value
			int value=GSINT(gameset_value[i].offset);

			if(value==v){
				ch->printlnf("Game setting value '%s (%s)' makes use of object %d.", 
					gameset_value[i].name, gameset_value[i].description, value);
				in_use++;
			}

		}

		// someone else currently editing the mob
		for(connection_data *c=connection_list; c; c=c->next){
			if(c!=ch->desc && c->pEdit==(void *)pDeleteObj){
				ch->println("Someone else is currently editing it, so it can't currently be deleted.");
				in_use++;
			}
		}

		if(in_use){
			ch->println("You can't delete this object, it is currently in use.");
			oedit_odelete(ch, "");
			return false;
		}
	}

	if(pObj==pDeleteObj){
		edit_done(ch);
	}
	ch->printlnf("Deleting object %d.", v);
	
	// remove object from hash table
	{
		int i=v% MAX_KEY_HASH;
		// check if we are the first entry in the hash table
		if(pDeleteObj== obj_index_hash[i]){
			obj_index_hash[i]=obj_index_hash[i]->next;
		}else{
			OBJ_INDEX_DATA *prev=obj_index_hash[i];
			if(!prev){
				bugf("oedit_odelete(): Trying to free object vnum %d, but not found in obj_index_hash[%d]!", 
					v, i);
			}else{
				for( ; prev->next; prev=prev->next )
				{
					if(prev->next==pDeleteObj){
						prev->next=pDeleteObj->next; // remove the object from the link
						break;
					}
				}
			}
		}
	}
	free_obj_index(pDeleteObj);
	top_obj_index--;

	ch->printlnf("Object %d Deleted.",v);
	
	return true;
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/