FlCodebase3.1/
FlCodebase3.1/bounty/
FlCodebase3.1/challenge/
FlCodebase3.1/clans/
FlCodebase3.1/gods/
FlCodebase3.1/mobprogs/
FlCodebase3.1/player/
FlCodebase3.1/savemud/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  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.                                                  * 
 *                                                                         *
 *      ROM 2.4 is copyright 1993-1998 Russ Taylor                         *
 *      ROM has been brought to you by the ROM consortium                  *
 *          Russ Taylor (rtaylor@hypercube.org)                            *
 *          Gabrielle Taylor (gtaylor@hypercube.org)                       *
 *          Brian Moore (zump@rom.org)                                     *
 *      By using this code, you have agreed to follow the terms of the     *
 *      ROM license, in the file Rom24/doc/rom.license                     *
 *                                                                         *
 * Code Adapted and Improved by Abandoned Realms Mud                       *
 * and Aabahran: The Forsaken Lands Mud by Virigoth                        *
 *                                                                         *
 * Continued Production of this code is available at www.flcodebase.com    *
 ***************************************************************************/

#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 "merc.h"
#include "olc.h"
#include "cabal.h"
#include "recycle.h"
#include "tome.h"
#include "clan.h"

#define DIF(a,b) (~((~a)|(b)))

AREA_DATA *get_area_data	args( ( int vnum ) );


extern          int                     top_reset;
extern          int                     top_area;
extern          int                     top_exit;
extern          int                     top_ed;
extern          int                     top_room;
extern		int                     top_mprog_index;
extern		int                     top_oprog_index;
extern		int                     top_rprog_index; 
extern		char			*string_space;
extern		char			*top_string;
PROG_CODE              *       mpcode_free;
PROG_CODE	       *       opcode_free;
PROG_CODE	       *       rpcode_free;

AREA_DATA		*	area_free;
EXTRA_DESCR_DATA	*	extra_descr_free;
EXIT_DATA		*	exit_free;
ROOM_INDEX_DATA		*	room_index_free;
OBJ_INDEX_DATA		*	obj_index_free;
SHOP_DATA		*	shop_free;
MOB_INDEX_DATA		*	mob_index_free;
RESET_DATA		*	reset_free;
HELP_DATA		*	help_free;
HELP_DATA		*	help_last;

void free_extra_descr( EXTRA_DESCR_DATA *pExtra );
void free_affect( AFFECT_DATA *af );


/* Executed from comm.c.  Minimizes compiling when changes are made. */
bool run_olc_editor( DESCRIPTOR_DATA *d )
{
    switch ( d->editor )
    {
    case ED_AREA:   aedit( d->character, d->incomm ); break;
    case ED_ROOM:   redit( d->character, d->incomm ); break;
    case ED_OBJECT: oedit( d->character, d->incomm ); break;
    case ED_MOBILE: medit( d->character, d->incomm ); break;
    case ED_ARMY:   armedit(d->character, d->incomm ); break;
    case ED_TRAP:   tedit( d->character, d->incomm ); break;
    case ED_HELP:   hedit( d->character, d->incomm ); break;
    case ED_CABAL:  cedit( d->character, d->incomm ); break;
    case ED_MPCODE: mpedit( d->character, d->incomm );break;
    case ED_OPCODE: opedit( d->character, d->incomm );break;
    case ED_RPCODE: rpedit( d->character, d->incomm );break;
    default:        return FALSE;
    }
    return TRUE;
}

char *olc_ed_name( CHAR_DATA *ch )
{
    static char buf[10];
    buf[0] = '\0';
    switch (ch->desc->editor)
    {
    case ED_AREA:   sprintf( buf, "AEdit" ); break;
    case ED_ROOM:   sprintf( buf, "REdit" ); break;
    case ED_TRAP:   sprintf( buf, "TEdit" ); break;
    case ED_HELP:   sprintf( buf, "HEdit" ); break;
    case ED_CABAL:  sprintf( buf, "CEdit" ); break;
    case ED_OBJECT: sprintf( buf, "OEdit" ); break;
    case ED_MOBILE: sprintf( buf, "MEdit" ); break;
    case ED_MPCODE:
    	sprintf( buf, "MPEdit" );
	break;
    case ED_OPCODE:
	sprintf( buf, "OPEdit" );
	break;
    case ED_RPCODE:
	sprintf( buf, "RPEdit" );
	break;
    default:        sprintf( buf, " " ); break;
    }
    return buf;
}

char *olc_ed_vnum( CHAR_DATA *ch )
{
    AREA_DATA *pArea;
    ROOM_INDEX_DATA *pRoom;
    OBJ_INDEX_DATA *pObj;
    MOB_INDEX_DATA *pMob;
    CABAL_INDEX_DATA *pCab;
    HELP_DATA *pHelp;
    PROG_CODE *pMprog;
    PROG_CODE *pOprog;
    PROG_CODE *pRprog;

    static char buf[10];
    buf[0] = '\0';
    switch ( ch->desc->editor )
    {
    case ED_AREA:   pArea = (AREA_DATA *)ch->desc->pEdit; sprintf( buf, "%d", pArea ? pArea->vnum : 0 ); break;
    case ED_ROOM:   pRoom = ch->in_room; sprintf( buf, "%d", pRoom ? pRoom->vnum : 0 ); break;
    case ED_OBJECT: pObj = (OBJ_INDEX_DATA *)ch->desc->pEdit; sprintf( buf, "%d", pObj ? pObj->vnum : 0 ); break;
    case ED_MOBILE: 
      pMob = (MOB_INDEX_DATA *)ch->desc->pEdit; 
      sprintf( buf, "%d", pMob ? pMob->vnum : 0 ); 
      break;
    case ED_CABAL: 
      pCab = (CABAL_INDEX_DATA *)ch->desc->pEdit; 
      sprintf( buf, "%d", pCab ? pCab->vnum : 0 ); 
      break;
    case ED_HELP: 
      pHelp = (HELP_DATA *)ch->desc->pEdit; 
      sprintf( buf, "%d", pHelp ? pHelp->vnum : 0 ); 
      break;
    case ED_MPCODE:
    	pMprog = (PROG_CODE *)ch->desc->pEdit;
    	sprintf( buf, "%d", pMprog ? pMprog->vnum : 0 );
	break;
    case ED_OPCODE:
	pOprog = (PROG_CODE *)ch->desc->pEdit;
	sprintf( buf, "%d", pOprog ? pOprog->vnum : 0 );
	break;
    case ED_RPCODE:
	pRprog = (PROG_CODE *)ch->desc->pEdit;
	sprintf( buf, "%d", pRprog ? pRprog->vnum : 0 );
	break;
    default:        sprintf( buf, " " ); break;
    }
    return buf;
}

/* Format up the commands from given table. *
 * Called by show_commands(olc_act.c).      */
void show_olc_cmds( CHAR_DATA *ch, const struct olc_cmd_type *olc_table )
{
    char buf  [ MSL ];
    char buf1 [ MSL ];
    int  cmd;
    int  col;
    buf1[0] = '\0';
    col = 0;
    for (cmd = 0; olc_table[cmd].name != NULL; cmd++)
    {
	sprintf( buf, "%-15.15s", olc_table[cmd].name );
	strcat( buf1, buf );
	if ( ++col % 5 == 0 )
	    strcat( buf1, "\n\r" );
    }
    if ( col % 5 != 0 )
	strcat( buf1, "\n\r" );
    send_to_char( buf1, ch );
    return;
}

/* Display all olc commands.   *
 * Called by olc interpreters. */
bool show_commands( CHAR_DATA *ch, char *argument )
{
    switch (ch->desc->editor)
    {
    case ED_AREA:   show_olc_cmds( ch, aedit_table ); break;
    case ED_ROOM:   show_olc_cmds( ch, redit_table ); break;
    case ED_TRAP:   show_olc_cmds( ch, tedit_table ); break;
    case ED_HELP:   show_olc_cmds( ch, hedit_table ); break;
    case ED_CABAL:  show_olc_cmds( ch, cedit_table ); break;
    case ED_OBJECT: show_olc_cmds( ch, oedit_table ); break;
    case ED_MOBILE: show_olc_cmds( ch, medit_table ); break;
    case ED_MPCODE:
      show_olc_cmds( ch, mpedit_table );
      break;
    case ED_OPCODE:
      show_olc_cmds( ch, opedit_table );
      break;
    case ED_RPCODE:
      show_olc_cmds( ch, rpedit_table );
      break;
    }
    return FALSE;
}

/* Interpreter Table */
const struct olc_cmd_type aedit_table[] =
{
/*  {   command		function	}, */
    {   "age",		aedit_age	},
    {   "bastion",      aedit_bastion	},
    {   "builder",      aedit_builder   },
    {   "commands",	show_commands	},
    {   "create",	aedit_create	},
    {   "filename",	aedit_file	},
    {   "name",		aedit_name	},
    {   "prefix",	aedit_prefix	},
    {	"reset",	aedit_reset	},
    {   "security",	aedit_security	},
    {	"show",		aedit_show	},
    {   "vnum",		aedit_vnum	},
    {   "lvnum",	aedit_lvnum	},
    {   "uvnum",	aedit_uvnum	},
    {   "credits",	aedit_credits	},
    {   "?",		show_help	},
    {   "version",	show_version	},
    {   "aflag",	aedit_flags	},
    {   "crime",	aedit_crime	},
    {   "startroom",	aedit_startroom	},
    {	NULL,		0,		}
};

const struct olc_cmd_type redit_table[] =
{
/*  {   command		function	}, */
    {   "commands",	show_commands	},
    {   "create",	redit_create	},
    {   "desc",		redit_desc	},
    {   "ndesc",	redit_ndesc	},
    {   "ed",		redit_ed	},
    {   "format",	redit_format	},
    {   "name",		redit_name	},
    {	"show",		redit_show	},
    {   "heal",		redit_heal	},
    {	"mana",		redit_mana	},
    {	"watch",	redit_watch	},
    {	"temp",		redit_temp	},
    {   "cabal",        redit_cabal     },
    {   "north",	redit_north	},
    {   "south",	redit_south	},
    {   "east",		redit_east	},
    {   "west",		redit_west	},
    {   "up",		redit_up	},
    {   "down",		redit_down	},
    {   "sector",	redit_sector	},
    {   "room",		redit_room	},
    /* New reset commands. */
    {	"mreset",	redit_mreset	},
    {	"oreset",	redit_oreset	},
    {	"treset",	redit_treset	},
    {	"mlist",	redit_mlist	},
    {	"rlist",	redit_rlist	},
    {	"olist",	redit_olist	},
    {	"mshow",	redit_mshow	},
    {	"oshow",	redit_oshow	},
    {   "?",		show_help	},
    {   "version",	show_version	},
    {   "copy",		redit_copy	},
    /* New prog commands */
    {	"addprog",	redit_addrprog	},
    {	"delprog",	redit_delrprog	},
    {	NULL,		0,		}
};

const struct olc_cmd_type oedit_table[] =
{
/*  {   command		function	}, */
    {   "addaffect",	oedit_addaffect	},
    {   "addapply",	oedit_addapply	},
    {   "commands",	show_commands	},
    {   "cost",		oedit_cost	},
    {   "create",	oedit_create	},
    {   "delaffect",	oedit_delaffect	},
    {   "ed",		oedit_ed	},
    {   "long",		oedit_long	},
    {   "name",		oedit_name	},
    {   "short",	oedit_short	},
    {	"show",		oedit_show	},
    {   "v0",		oedit_value0	},
    {   "v1",		oedit_value1	},
    {   "v2",		oedit_value2	},
    {   "v3",		oedit_value3	},
    {   "v4",           oedit_value4    },  
    {   "weight",	oedit_weight	},
    {   "condition",	oedit_condition	},
    {   "shots",	oedit_condition	},
    {   "material",     oedit_material  },
    {   "extra",        oedit_extra     },  
    {   "wear",         oedit_wear      },  
    {   "type",         oedit_type      },  
    {   "level",        oedit_level     },  
    {   "?",		show_help	},
    {   "version",	show_version	},
    {   "copy",		oedit_copy	},
    {   "cabal",	oedit_cabal	},
    {   "race",		oedit_race	},
    {   "class",	oedit_class	},
    {   "message",	oedit_message	},
    /* new prog commands */
    {	"addprog",	oedit_addoprog	},
    {	"delprog",	oedit_deloprog	},

    {	NULL,		0,		}
};

const struct olc_cmd_type medit_table[] =
{
/*  {   command		function	}, */
    {   "alignment",	medit_align	},
    {   "cabal",        medit_cabal     },  
    {   "commands",	show_commands	},
    {   "create",	medit_create	},
    {   "desc",		medit_desc	},
    {   "level",	medit_level	},
    {   "long",		medit_long	},
    {   "name",		medit_name	},
    {   "shop",		medit_shop	},
    {   "short",	medit_short	},
    {	"show",		medit_show	},
    {   "spec",		medit_spec	},
    {   "sex",          medit_sex       },  
    {   "act",          medit_act       },  
    {   "act2",         medit_act2      },  
    {   "affect2",      medit_affect2   },  
    {   "affect1",      medit_affect    },  
    {   "armor",        medit_ac        },  
    {   "imm",          medit_imm       },  
    {   "res",          medit_res       },  
    {   "vuln",         medit_vuln      },  
    {   "off",          medit_off       },  
    {   "size",         medit_size      },  
    {   "hitdice",      medit_hitdice   },  
    {   "manadice",     medit_manadice  },  
    {   "damdice",      medit_damdice   },  
    {   "race",         medit_race      },  
    {   "position",     medit_position  },  
    {   "gold",         medit_gold      },  
    {   "hitroll",      medit_hitroll   },  
    {	"damtype",	medit_damtype	},
    {	"group",	medit_group	},
    {   "?",		show_help	},
    {   "version",	show_version	},
    {   "copy",		medit_copy	},
    /* New prog commands */
    {	"addprog",	medit_addmprog	},
    {	"delprog",	medit_delmprog	},

    {	NULL,		0,		}
};

const struct olc_cmd_type armedit_table[] =
{
/*{   command		function	}, */
  {   "?",		show_help	},
  {   "create",		armedit_create	},
  {   "show",		armedit_show	},
  {   "type",		armedit_type	},
  {   "cost",		armedit_cost	},
  {   "support",	armedit_support	},
  {   "flags",		armedit_flags	},
  {   "offense",	armedit_offense	},
  {   "hitpoints",	armedit_hitpoint},
  {   "armor",		armedit_armor	},
  {   "noun",		armedit_noun	},
  {   "short",		armedit_short	},
  {   "long",		armedit_long	},
  {   "description",	armedit_descr	},
  {   "copy",		armedit_copy	},
  {	NULL,		0,		}
};

/* trap table */
const struct olc_cmd_type tedit_table[] ={
/*{	command		function	}, */
  {	"?",		show_help	},
  {	"create",	tedit_create	},
  {	"show",		tedit_show	},
  {	"name",		tedit_name	},
  {	"echo",		tedit_echo	},
  {	"oecho",	tedit_oecho	},
  {	"level",	tedit_level	},
  {	"type",		tedit_type	},
  {	"flag",		tedit_flag	},
  {	"v0",		tedit_v0	},
  {	"v1",		tedit_v1	},
  {	"v2",		tedit_v2	},
  {	"v3",		tedit_v3	},
  {	"v4",		tedit_v4	},
  {	NULL,		0,		}
};

/* help table */
const struct olc_cmd_type hedit_table[] ={
/*{	command		function	}, */
  {	"?",		show_help	},
  {	"create",	hedit_create	},
  {	"show",		hedit_show	},
  {	"keyword",	hedit_key	},
  {	"level",	hedit_level	},
  {	"type",		hedit_type	},
  {	"text",		hedit_text	},
  {	NULL,		0,		}
};

/* help table */
const struct olc_cmd_type cedit_table[] ={
/*{	command		function	}, */
  {	"?",		show_help	},
  {	"create",	cedit_create	},
  {	"show",		cedit_show	},
  {	"name",		cedit_name	},
  {	"filename",	cedit_file_name	},
  {	"msggate",	cedit_msggate	},
  {	"ongate",	cedit_ongate	},
  {	"offgate",	cedit_offgate	},
  {	"city",		cedit_city	},
  {	"enemy",	cedit_enemy	},
  {	"anchor",	cedit_anchor	},
  {	"guard",	cedit_guard	},
  {	"pit",		cedit_pit	},
  {	"whoname",	cedit_whoname	},
  {	"immortal",	cedit_imm	},
  {	"currency",	cedit_currency	},
  {	"clan",		cedit_clan	},
  {	"members",	cedit_members	},
  {	"maxrooms",	cedit_max_room	},
  {	"levels",	cedit_levels	},
  {	"rank",		cedit_rank	},
  {	"franks",	cedit_frank	},
  {	"mranks",	cedit_mrank	},
  {	"flag",		cedit_flag	},
  {	"progress",	cedit_progress	},
  {	"align",	cedit_align	},
  {	"ethos",	cedit_ethos	},
  {	"race",		cedit_race	},
  {	"class",	cedit_class	},
  {	"skill",	cedit_skill	},
  {	"vote",		cedit_vote	},
  {	"room",		cedit_room	},
  {	"avatar",	cedit_avatar	},
  {	"parent",	cedit_parent	},
  {	"army",		cedit_army	},
  {	"tower",	cedit_tower	},
  {	"prefix",	cedit_prefix	},
  {	"tax",		cedit_tax	},
  {	NULL,		0,		}
};

/* Returns pointer to area with given vnum. *
 * Called by do_aedit(olc.c).               */
AREA_DATA *get_area_data( int vnum )
{
    AREA_DATA *pArea;
    for (pArea = area_first; pArea; pArea = pArea->next )
        if (pArea->vnum == vnum)
            return pArea;
    return 0;
}
/* retusn area data by name */
AREA_DATA *get_area_data_str( char* name ){
  AREA_DATA *pArea;
  for (pArea = area_first; pArea; pArea = pArea->next )
    if (!str_cmp(pArea->name, name))
      return pArea;
  return 0;
}

/* Resets builder information on completion.   *
 * Called by aedit, redit, oedit, medit(olc.c) */
bool edit_done( CHAR_DATA *ch )
{
    ch->desc->pEdit = NULL;
    ch->desc->editor = 0;
    return FALSE;
}

/* Area Interpreter.   *
 * Called by do_aedit. */
void aedit( CHAR_DATA *ch, char *argument )
{
    AREA_DATA *pArea;
    char command[MIL];
    char arg[MIL];
    int  cmd;
    int  value;
    EDIT_AREA(ch, pArea);
    smash_tilde( argument );
    strcpy( arg, argument );
    argument = one_argument( argument, command );
    if ( !IS_BUILDER( ch, pArea ) )
    {
        send_to_char( "AEdit:  Insufficient security to modify area.\n\r", ch );
	edit_done( ch );
	return;
    }
    if ( !str_cmp(command, "done") )
    {
	edit_done( ch );
	return;
    }
    if ( !IS_BUILDER( ch, pArea ) )
    {
	interpret( ch, arg );
	return;
    }
    if ( command[0] == '\0' )
    {
	aedit_show( ch, argument );
	return;
    }
    if ( ( value = flag_value( area_flags, command ) ) != NO_FLAG )
    {
	TOGGLE_BIT(pArea->area_flags, value);
	send_to_char( "Flag toggled.\n\r", ch );
	SET_BIT( pArea->area_flags, AREA_CHANGED );
	return;
    }
    for ( cmd = 0; aedit_table[cmd].name != NULL; cmd++ )
	if ( !str_prefix( command, aedit_table[cmd].name ) )
	{
	    if ( (*aedit_table[cmd].olc_fun) ( ch, argument ) )
	    {
		SET_BIT( pArea->area_flags, AREA_CHANGED );
		return;
	    }
	    else
		return;
	}
    interpret( ch, arg );
    return;
}

/* Room Interpreter    *
 * Called by do_redit. */
void redit( CHAR_DATA *ch, char *argument )
{
    ROOM_INDEX_DATA *pRoom;
    AREA_DATA *pArea;
    char arg[MSL];
    char command[MIL];
    int  cmd;
    int  value;
    EDIT_ROOM(ch, pRoom);
    pArea = pRoom->area;
    smash_tilde( argument );
    strcpy( arg, argument );
    argument = one_argument( argument, command );
    if ( !IS_BUILDER( ch, pArea ) )
    {
        send_to_char( "REdit:  Insufficient security to modify room.\n\r", ch );
	edit_done( ch );
	return;
    }
    if ( !str_cmp(command, "done") )
    {
	edit_done( ch );
	return;
    }
    if ( !IS_BUILDER( ch, pArea ) )
    {
        interpret( ch, arg );
        return;
    }
    if ( command[0] == '\0' )
    {
	redit_show( ch, argument );
	return;
    }
    if ( ( value = flag_value( room_flags, command ) ) != NO_FLAG )
    {
        TOGGLE_BIT(pRoom->room_flags, value);
        SET_BIT( pArea->area_flags, AREA_CHANGED );
        send_to_char( "Room flag toggled.\n\r", ch );
        return;
    }
    if ( ( value = flag_value( room_flags2, command ) ) != NO_FLAG )
    {
        TOGGLE_BIT(pRoom->room_flags2, value);
        SET_BIT( pArea->area_flags, AREA_CHANGED );
        send_to_char( "Room flag toggled.\n\r", ch );
        return;
    }
    if ( ( value = flag_value( sector_flags, command ) ) != NO_FLAG )
    {
        pRoom->sector_type  = value;
        SET_BIT( pArea->area_flags, AREA_CHANGED );
        send_to_char( "Sector type set.\n\r", ch );
        return;
    }
    for ( cmd = 0; redit_table[cmd].name != NULL; cmd++ )
	if ( !str_prefix( command, redit_table[cmd].name ) )
	{
	    if ( (*redit_table[cmd].olc_fun) ( ch, argument ) )
	    {
		SET_BIT( pArea->area_flags, AREA_CHANGED );
		return;
	    }
	    else
		return;
	}
    interpret( ch, arg );
    return;
}

/* Object Interpreter *
 * Called by do_oedit. */
void oedit( CHAR_DATA *ch, char *argument )
{
    AREA_DATA *pArea;
    OBJ_INDEX_DATA *pObj;
    char arg[MSL];
    char command[MIL];
    int  cmd;
    smash_tilde( argument );
    strcpy( arg, argument );
    argument = one_argument( argument, command );
    EDIT_OBJ(ch, pObj);
    pArea = pObj->area;
    if ( !IS_BUILDER( ch, pArea ) )
    {
	send_to_char( "OEdit: Insufficient security to modify area.\n\r", ch );
	edit_done( ch );
	return;
    }
    if ( !str_cmp(command, "done") )
    {
	edit_done( ch );
	return;
    }
    if ( !IS_BUILDER( ch, pArea ) )
    {
	interpret( ch, arg );
	return;
    }
    if ( command[0] == '\0' )
    {
	oedit_show( ch, argument );
	return;
    }
    for ( cmd = 0; oedit_table[cmd].name != NULL; cmd++ )
	if ( !str_prefix( command, oedit_table[cmd].name ) )
	{
	    if ( (*oedit_table[cmd].olc_fun) ( ch, argument ) )
	    {
		SET_BIT( pArea->area_flags, AREA_CHANGED );
		return;
	    }
	    else
		return;
	}
    interpret( ch, arg );
    return;
}

/* Mobile Interpreter. *
 * called by do_medit. */
void medit( CHAR_DATA *ch, char *argument )
{
    AREA_DATA *pArea;
    MOB_INDEX_DATA *pMob;
    char command[MIL];
    char arg[MSL];
    int  cmd;
    smash_tilde( argument );
    strcpy( arg, argument );
    argument = one_argument( argument, command );
    EDIT_MOB(ch, pMob);
    pArea = pMob->area;
    if ( !IS_BUILDER( ch, pArea ) )
    {
	send_to_char( "MEdit: Insufficient security to modify area.\n\r", ch );
	edit_done( ch );
	return;
    }
    if ( !str_cmp(command, "done") )
    {
	edit_done( ch );
	return;
    }
    if ( !IS_BUILDER( ch, pArea ) )
    {
	interpret( ch, arg );
	return;
    }
    if ( command[0] == '\0' )
    {
        medit_show( ch, argument );
        return;
    }
    for ( cmd = 0; medit_table[cmd].name != NULL; cmd++ )
	if ( !str_prefix( command, medit_table[cmd].name ) )
	{
	    if ( (*medit_table[cmd].olc_fun) ( ch, argument ) )
	    {
		SET_BIT( pArea->area_flags, AREA_CHANGED );
		return;
	    }
	    else
		return;
	}
    interpret( ch, arg );
    return;
}

/* Amry Interpreter. *
 * called by do_armedit. */
void armedit( CHAR_DATA *ch, char *argument )
{
    AREA_DATA *pArea;
    ARMY_INDEX_DATA *pai;
    char command[MIL];
    char arg[MSL];
    int  cmd;
    smash_tilde( argument );
    strcpy( arg, argument );
    argument = one_argument( argument, command );

    EDIT_ARMY(ch, pai);
    pArea = pai->area;

    if ( !IS_BUILDER( ch, pArea ) )
    {
	send_to_char( "MEdit: Insufficient security to modify area.\n\r", ch );
	edit_done( ch );
	return;
    }
    if ( !str_cmp(command, "done") )
    {
	edit_done( ch );
	return;
    }
    if ( !IS_BUILDER( ch, pArea ) )
    {
	interpret( ch, arg );
	return;
    }
    if ( command[0] == '\0' )
    {
        armedit_show( ch, argument );
        return;
    }
    for ( cmd = 0; armedit_table[cmd].name != NULL; cmd++ )
      if ( !str_prefix( command, armedit_table[cmd].name ) ){
	if ( (*armedit_table[cmd].olc_fun) ( ch, argument ) ){
	  SET_BIT( pArea->area_flags, AREA_CHANGED );
	  return;
	}
	else
	  return;
      }
    interpret( ch, arg );
    return;
}

const struct editor_cmd_type editor_table[] =
{
/*  {   command		function	}, */
    {   "area",		do_aedit	},
    {   "room",		do_redit	},
    {   "object",	do_oedit	},
    {   "mobile",	do_medit	},
    {   "army",		do_armedit	},
    {   "trap",		do_tedit	},
    {   "help",		do_hedit	},
    {   "cabal",	do_cedit	},
    {   "mprog",	do_mpedit	},
    {   "rprog",	do_rpedit	},
    {   "oprog",	do_opedit	},
    {	NULL,		0,		}
};

/* Entry point for all editors. */
void do_olc( CHAR_DATA *ch, char *argument )
{
    char command[MIL];
    int  cmd;
    argument = one_argument( argument, command );
    if ( command[0] == '\0' )
    {
        do_help( ch, "olc" );
        return;
    }
    if ((mud_data.mudport == 6666) && (get_trust(ch) < 60)){
      send_to_char("Main port access limited to Implementor trust.\n\r", ch);
      return;
    }
    for ( cmd = 0; editor_table[cmd].name != NULL; cmd++ )
	if ( !str_prefix( command, editor_table[cmd].name ) )
	{
	    (*editor_table[cmd].do_fun) ( ch, argument );
	    return;
	}
    do_help( ch, "olc" );
    return;
}

/* Entry point for editing area_data. */
void do_aedit( CHAR_DATA *ch, char *argument )
{
    AREA_DATA *pArea;
    int value;
    char value2[MSL];
    char arg[MSL];
    pArea = ch->in_room->area;
    argument = one_argument(argument,arg);
    if ( is_number( arg ) )
    {
	value = atoi( arg );
	if ( !( pArea = get_area_data( value ) ) )
	{
	    send_to_char( "That area vnum does not exist.\n\r", ch );
	    return;
	}
    }
    else if ( !str_cmp( arg, "create" ) )
    {
        if (!IS_NPC(ch) && (ch->pcdata->security < 9) )
        {
            send_to_char("Insufficient security to modify area.\n\r",ch);
            return;
        }
        argument            =   one_argument(argument,value2);
        value = atoi (value2);
        if (get_area_data(value) != NULL)
        {
            send_to_char("Esa area ya existe!",ch);
            return;
        }
        pArea               =   new_area();
        area_last->next     =   pArea;
        area_last           =   pArea;      
        SET_BIT( pArea->area_flags, AREA_ADDED );
        send_to_char("Area created.\n\r",ch);
    }
    if (!IS_BUILDER(ch,pArea))
    {
        send_to_char("Insufficient security to modify area.\n\r",ch);
    	return;
    }
    ch->desc->pEdit = (void *)pArea;
    ch->desc->editor = ED_AREA;
    return;
}

/* Entry point for editing room_index_data. */
void do_redit( CHAR_DATA *ch, char *argument )
{
    ROOM_INDEX_DATA *pRoom, *pRoom2;
    char arg1[MSL];
    argument = one_argument( argument, arg1 );
    pRoom = ch->in_room;
    if ( !str_cmp( arg1, "reset" ) )
    {
	if ( !IS_BUILDER( ch, pRoom->area ) )
	{
            send_to_char("Insufficient security to modify room.\n\r",ch);
            return;
	}
	reset_room( pRoom );
	send_to_char( "Room reset.\n\r", ch );
	return;
    }
    else if ( !str_cmp( arg1, "create" ) )
    {
	if ( argument[0] == '\0' || atoi( argument ) == 0 )
	{
	    send_to_char( "Syntax:  edit room create [vnum]\n\r", ch );
	    return;
	}
	if ( redit_create( ch, argument ) )
	{
	    char_from_room( ch );
	    char_to_room( ch, ch->desc->pEdit );
	    SET_BIT( pRoom->area->area_flags, AREA_CHANGED );
	    pRoom = ch->in_room;
	}
    }
    else
    {
        pRoom2 = get_room_index(atoi(arg1));
        if ( (pRoom2 != NULL) && IS_BUILDER(ch,pRoom2->area) )
        {
            char_from_room( ch );
            char_to_room( ch, pRoom2 );
            pRoom = ch->in_room;
        }
        else if (atoi(arg1) != 0)
        {
            send_to_char("Insufficient security to modify room.\n\r",ch);
            return;
        }   
    }
    if ( !IS_BUILDER( ch, pRoom->area ) )
    {
        send_to_char("Insufficient security to modify area.\n\r",ch);
       	return;
    }
    ch->desc->pEdit = (void *)pRoom;
    ch->desc->editor = ED_ROOM;
    return;
}

/* Entry point for editing obj_index_data. */
void do_oedit( CHAR_DATA *ch, char *argument )
{
    OBJ_INDEX_DATA *pObj;
    AREA_DATA *pArea;
    char arg1[MSL];
    int value;
    if ( IS_NPC(ch) )
	return;
    argument = one_argument( argument, arg1 );
    if ( is_number( arg1 ) )
    {
	value = atoi( arg1 );
	if ( !( pObj = get_obj_index( value ) ) )
	{
	    send_to_char( "OEdit:  That vnum does not exist.\n\r", ch );
	    return;
	}
	if ( !IS_BUILDER( ch, pObj->area ) )
        {
            send_to_char("Insufficient security to modify objects.\n\r",ch);
            return;
        }
	ch->desc->pEdit = (void *)pObj;
	ch->desc->editor = ED_OBJECT;
	return;
    }
    else if ( !str_cmp( arg1, "create" ) )
    {
        value = atoi( argument );
        if ( argument[0] == '\0' || value == 0 )
        {
            send_to_char( "Syntax:  edit object create [vnum]\n\r", ch );
            return;
        }
        pArea = get_vnum_area( value );
        if ( !pArea )
        {
            send_to_char( "OEdit:  That vnum is not assigned an area.\n\r", ch );
            return;
        }
        if ( !IS_BUILDER( ch, pArea ) )
        {
            send_to_char("Insufficient security to modify objects.\n\r",ch);
            return;
        }
        if ( oedit_create( ch, argument ) )
        {
            SET_BIT( pArea->area_flags, AREA_CHANGED );
            ch->desc->editor = ED_OBJECT;
        }
        return;
    }
    send_to_char( "OEdit:  There is no default object to edit.\n\r", ch );
    return;
}

/* Entry point for editing mob_index_data. */
void do_medit( CHAR_DATA *ch, char *argument )
{
    MOB_INDEX_DATA *pMob;
    AREA_DATA *pArea;
    int value;
    char arg1[MSL];
    argument = one_argument( argument, arg1 );
    if ( is_number( arg1 ) )
    {
	value = atoi( arg1 );
	if ( !( pMob = get_mob_index( value ) ))
	{
	    send_to_char( "MEdit:  That vnum does not exist.\n\r", ch );
	    return;
	}
	if ( !IS_BUILDER( ch, pMob->area ) )
	{
            send_to_char("Insufficient security to modify mobs.\n\r",ch);
            return;
	}
	ch->desc->pEdit = (void *)pMob;
	ch->desc->editor = ED_MOBILE;
	return;
    }
    else if ( !str_cmp( arg1, "create" ) )
    {
        value = atoi( argument );
        if ( arg1[0] == '\0' || value == 0 )
        {
            send_to_char( "Syntax:  edit mobile create [vnum]\n\r", ch );
            return;
        }
        pArea = get_vnum_area( value );
        if ( !pArea )
        {
            send_to_char( "OEdit:  That vnum is not assigned an area.\n\r", ch );
            return;
        }
        if ( !IS_BUILDER( ch, pArea ) )
        {
            send_to_char( "Insufficient security to edit mobs.\n\r" , ch );
            return;
        }
        if ( medit_create( ch, argument ) )
        {
            SET_BIT( pArea->area_flags, AREA_CHANGED );
            ch->desc->editor = ED_MOBILE;
        }
        return;
    }
    send_to_char( "MEdit:  There is no default mobile to edit.\n\r", ch );
    return;
}

/* Entry point for editing army_index_data. */
void do_armedit( CHAR_DATA *ch, char *argument )
{
    ARMY_INDEX_DATA *pai;
    AREA_DATA *pArea;
    int value;
    char arg1[MSL];
    argument = one_argument( argument, arg1 );
    if ( is_number( arg1 ) )
    {
	value = atoi( arg1 );
	if ( !( pai = get_army_index( value ) ))
	{
	    send_to_char( "ArmEdit:  That vnum does not exist.\n\r", ch );
	    return;
	}
	if ( !IS_BUILDER( ch, pai->area ) )
	{
            send_to_char("Insufficient security to modify armies.\n\r",ch);
            return;
	}
	ch->desc->pEdit = (void *)pai;
	ch->desc->editor = ED_ARMY;
	return;
    }
    else if ( !str_cmp( arg1, "create" ) )
    {
        value = atoi( argument );
        if ( arg1[0] == '\0' || value == 0 )
        {
            send_to_char( "Syntax:  edit area create [vnum]\n\r", ch );
            return;
        }
        pArea = get_vnum_area( value );
        if ( !pArea )
        {
            send_to_char( "OEdit:  That vnum is not assigned an area.\n\r", ch );
            return;
        }
        if ( !IS_BUILDER( ch, pArea ) )
        {
            send_to_char( "Insufficient security to edit mobs.\n\r" , ch );
            return;
        }
        if ( armedit_create( ch, argument ) )
        {
            SET_BIT( pArea->area_flags, AREA_CHANGED );
            ch->desc->editor = ED_ARMY;
        }
        return;
    }
    send_to_char( "ArmEdit:  There is no default mobile to edit.\n\r", ch );
    return;
}

void do_tedit(CHAR_DATA *ch, char *argument){
  TRAP_INDEX_DATA* pTrap;
  char command[MIL];

  argument = one_argument(argument, command);

  if( is_number(command) ){
    int vnum = atoi(command);
    AREA_DATA *ad;

    if ( (pTrap = get_trap_index(vnum)) == NULL ){
      send_to_char("TEdit : That vnum does not exist.\n\r", ch);
      return;
    }
    ad = get_vnum_area(vnum);

    if ( ad == NULL ){
      send_to_char( "TEdit : Vnum is not assigned an area.\n\r", ch );
      return;
    }

    if ( !IS_BUILDER(ch, ad) ){
      send_to_char("TEdit : Insufficient security to modify area.\n\r", ch );
      return;
    }

    ch->desc->pEdit		= (void *)pTrap;
    ch->desc->editor		= ED_TRAP;
    return;
  }

  if ( !str_cmp(command, "create") ){
    if (argument[0] == '\0'){
      send_to_char( "Syntax : tedit create [vnum]\n\r", ch );
      return;
    }
    tedit_create(ch, argument);
    return;
  }

  send_to_char( "Syntax : tedit [vnum]\n\r", ch );
  send_to_char( "         tedit create [vnum]\n\r", ch );

  return;
}


void do_hedit(CHAR_DATA *ch, char *argument){
  HELP_DATA* pHelp;
  char command[MIL];

  argument = one_argument(argument, command);

  if( is_number(command) ){
    int vnum = atoi(command);
    
    if ( (pHelp = get_help_index(vnum)) == NULL ){
      send_to_char("HEdit : That vnum does not exist.\n\r", ch);
      return;
    }
    
    ch->desc->pEdit		= (void *)pHelp;
    ch->desc->editor		= ED_HELP;
    return;
  }
  
  if ( !str_cmp(command, "create") ){
    hedit_create(ch, argument);
    return;
  }

  send_to_char( "Syntax : hedit [vnum]\n\r", ch );
  send_to_char( "         hedit create\n\r", ch );
  return;
}

void do_cedit(CHAR_DATA *ch, char *argument){
  CABAL_INDEX_DATA* pCab;
  char command[MIL];

  argument = one_argument(argument, command);

  if( is_number(command) ){
    int vnum = atoi(command);
    
    if ( (pCab = get_cabal_index(vnum)) == NULL ){
      send_to_char("CEdit : That vnum does not exist.\n\r", ch);
      return;
    }
    
    ch->desc->pEdit		= (void *)pCab;
    ch->desc->editor		= ED_CABAL;
    return;
  }
  
  if ( !str_cmp(command, "create") ){
    if (get_trust(ch) < IMPLEMENTOR){
      sendf(ch, "Requires level %d trust.\n\r", IMPLEMENTOR);
      return;
    }
    cedit_create(ch, argument);
    return;
  }

  send_to_char( "Syntax : cedit [vnum]\n\r", ch );
  send_to_char( "         cedit create\n\r", ch );
  return;
}




void display_resets( CHAR_DATA *ch )
{
    ROOM_INDEX_DATA	*pRoom;
    RESET_DATA		*pReset;
    MOB_INDEX_DATA	*pMob = NULL;
    char 		buf   [ MSL ];
    char 		final [ MSL ];
    int 		iReset = 0;
    EDIT_ROOM(ch, pRoom);
    final[0]  = '\0';
    send_to_char ( 
      " No.  Loads    Description       Location         Vnum   Wo Ar Description\n\r"
      "==== ======== ============= =================== ======== ===== ===========\n\r", ch );
    for ( pReset = pRoom->reset_first; pReset; pReset = pReset->next )
    {
	OBJ_INDEX_DATA  *pObj;
	MOB_INDEX_DATA  *pMobIndex;
	OBJ_INDEX_DATA  *pObjIndex;
	OBJ_INDEX_DATA  *pObjToIndex;
	ROOM_INDEX_DATA *pRoomIndex;
	TRAP_INDEX_DATA *pTrap;
	final[0] = '\0';
	sprintf( final, "[%2d] ", ++iReset );
	switch ( pReset->command )
	{
	default:
	    sprintf( buf, "Bad reset command: %c.", pReset->command );
	    strcat( final, buf );
            break;
	case 'M':
	    if ( !( pMobIndex = get_mob_index( pReset->arg1 ) ) )
	    {
                sprintf( buf, "Load Mobile - Bad Mob %d\n\r", pReset->arg1 );
                strcat( final, buf );
                continue;
	    }
	    if ( !( pRoomIndex = get_room_index( pReset->arg3 ) ) )
	    {
                sprintf( buf, "Load Mobile - Bad Room %d\n\r", pReset->arg3 );
                strcat( final, buf );
                continue;
	    }
            pMob = pMobIndex;
            sprintf( buf, "M[%5d] %-13.13s in room             R[%5d] %2d-%2d %-15.15s\n\r",
              pReset->arg1, pMob->short_descr, pReset->arg3,
              pReset->arg2, pReset->arg4, pRoomIndex->name );
            strcat( final, buf );
	    {
		ROOM_INDEX_DATA *pRoomIndexPrev;
		pRoomIndexPrev = get_room_index( pRoomIndex->vnum - 1 );
                if ( pRoomIndexPrev && IS_SET( pRoomIndexPrev->room_flags, ROOM_PET_SHOP ) )
                    final[5] = 'P';
	    }
	    break;
	case 'O':
	    if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) )
	    {
                sprintf( buf, "Load Object - Bad Object %d\n\r", pReset->arg1 );
                strcat( final, buf );
                continue;
	    }
            pObj       = pObjIndex;
	    if ( !( pRoomIndex = get_room_index( pReset->arg3 ) ) )
	    {
                sprintf( buf, "Load Object - Bad Room %d\n\r", pReset->arg3 );
                strcat( final, buf );
                continue;
	    }
            sprintf( buf, "O[%5d] %-13.13s in room             R[%5d]       %-15.15s\n\r",
              pReset->arg1, pObj->short_descr, pReset->arg3, pRoomIndex->name );
            strcat( final, buf );
	    break;
	case 'P':
	    if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) )
	    {
                sprintf( buf, "Put Object - Bad Object %d\n\r", pReset->arg1 );
                strcat( final, buf );
                continue;
            }
            pObj       = pObjIndex;
	    if ( !( pObjToIndex = get_obj_index( pReset->arg3 ) ) )
	    {
                sprintf( buf, "Put Object - Bad To Object %d\n\r", pReset->arg3 );
                strcat( final, buf );
                continue;
	    }
            sprintf( buf, "O[%5d] %-13.13s inside              O[%5d] %2d    %-15.15s\n\r",
              pReset->arg1, pObj->short_descr, pReset->arg3, pReset->arg4, pObjToIndex->short_descr );
            strcat( final, buf );
	    break;
	case 'G':
	case 'E':
	    if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) )
	    {
                sprintf( buf, "Give/Equip Object - Bad Object %d\n\r", pReset->arg1 );
                strcat( final, buf );
                continue;
            }
            pObj       = pObjIndex;
	    if ( !pMob )
	    {
                sprintf( buf, "Give/Equip Object - No Previous Mobile\n\r" );
                strcat( final, buf );
                break;
	    }
            sprintf( buf, "O[%5d] %-13.13s %-19.19s M[%5d]       %-15.15s\n\r",
		     pReset->arg1, pObj->short_descr,
		     (pReset->command == 'G') ? flag_string( wear_loc_strings, WEAR_NONE ) : flag_string( wear_loc_strings, pReset->arg3 ),
		     pMob->vnum, pMob->short_descr );
	    strcat( final, buf );
	    break;
	case 'D':
	    pRoomIndex = get_room_index( pReset->arg1 );
	    sprintf( buf, "R[%5d] %s door of %-19.19s reset to %s\n\r",
              pReset->arg1, capitalize( dir_name[ pReset->arg2 ] ),
              pRoomIndex->name, flag_string( door_resets, pReset->arg3 ) );
	    strcat( final, buf );
	    break;
	case 'R':
	    if ( !( pRoomIndex = get_room_index( pReset->arg1 ) ) )
	    {
                sprintf( buf, "Randomize Exits - Bad Room %d\n\r", pReset->arg1 );
		strcat( final, buf );
		continue;
	    }
            sprintf( buf, "R[%5d] Exits are randomized in %s\n\r", pReset->arg1, pRoomIndex->name );
	    strcat( final, buf );
	    break;
	case 'T':
	  if ( (pTrap = get_trap_index( pReset->arg1 )) == NULL){
	    sprintf( buf, "Load Trap - Bad Trap %d\n\r", pReset->arg1 );
	    strcat( final, buf );
	    continue;
	  }
	  if ( (pRoomIndex = get_room_index( pReset->arg3 )) == NULL ){
	    sprintf( buf, "Load Trap - Bad Room %d\n\r", pReset->arg3 );
	    strcat( final, buf );
	    continue;
	  }
	  sprintf( buf, "T[%5d] %-13.13s ",
		   pReset->arg1, pTrap->name);
	  strcat( final, buf );
	  if (pReset->arg2 == TRAP_ON_EXIT){
	    sprintf( buf, "on %s exit        R[%5d] lv[%2d]  %s\n\r",
		     dir_name[pReset->arg4], pReset->arg3, 
		     pTrap->level,
		     trap_table[pTrap->type].name);
	    strcat( final, buf );
	  }
	  else if (pReset->arg2 == TRAP_ON_OBJ){
	    sprintf( buf, "on previous obj     R[%5d] lv[%2d]  %s\n\r",
		     pReset->arg3, 
		     pTrap->level,
		     trap_table[pTrap->type].name);
	    strcat( final, buf );
	  }
	  else{
	    sprintf(buf, "TRAP TYPE ERROR \n\r");
	    strcat( final, buf );
	  }
	}
	send_to_char( final, ch );
    }
    return;
}

/* Inserts a new reset in the given index slot. *
 * Called by do_resets(olc.c).                  */
void add_reset( ROOM_INDEX_DATA *room, RESET_DATA *pReset, int index )
{
    RESET_DATA *reset;
    int iReset = 0;
    if ( !room->reset_first )
    {
	room->reset_first	= pReset;
	room->reset_last	= pReset;
	pReset->next		= NULL;
	return;
    }
    index--;
    if ( index == 0 )
    {
	pReset->next = room->reset_first;
	room->reset_first = pReset;
	return;
    }
    for ( reset = room->reset_first; reset->next; reset = reset->next )
	if ( ++iReset == index )
	    break;
    pReset->next	= reset->next;
    reset->next		= pReset;
    if ( !pReset->next )
	room->reset_last = pReset;
    SET_BIT( room->area->area_flags, AREA_CHANGED );
    return;
}

void do_resets( CHAR_DATA *ch, char *argument )
{
    char arg1[MIL];
    char arg2[MIL];
    char arg3[MIL];
    char arg4[MIL];
    char arg5[MIL];
    char arg6[MIL];
    char arg7[MIL];
    RESET_DATA *pReset = NULL;
    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    argument = one_argument( argument, arg3 );
    argument = one_argument( argument, arg4 );
    argument = one_argument( argument, arg5 );
    argument = one_argument( argument, arg6 );
    argument = one_argument( argument, arg7 );
    if ( !IS_BUILDER( ch, ch->in_room->area ) )
    {
        send_to_char( "Resets: Invalid security for editing this area.\n\r", ch );
	return;
    }
    if (mud_data.mudport != TEST_PORT && get_trust(ch) < MASTER){
      send_to_char("This command avaliable on test port only.\n\r", ch);
      return;
    }
    if ( arg1[0] == '\0' )
    {
	if ( ch->in_room->reset_first )
	{
            send_to_char("Resets: M = mobile, R = room, O = object, P = pet, S= shopkeeper T = trap\n\r", ch );
	    display_resets( ch );
	}
	else
	    send_to_char( "No resets in this room.\n\r", ch );
    }
    if ( is_number( arg1 ) )
    {
	ROOM_INDEX_DATA *pRoom = ch->in_room;
	if ( !str_cmp( arg2, "delete" ) )
	{
	    int insert_loc = atoi( arg1 );
	    if ( !ch->in_room->reset_first )
	    {
		send_to_char( "No resets in this area.\n\r", ch );
		return;
	    }
	    if ( insert_loc-1 <= 0 )
	    {
		pReset = pRoom->reset_first;
		pRoom->reset_first = pRoom->reset_first->next;
		if ( !pRoom->reset_first )
		    pRoom->reset_last = NULL;
	    }
	    else
	    {
		int iReset = 0;
		RESET_DATA *prev = NULL;
                for ( pReset = pRoom->reset_first; pReset; pReset = pReset->next )
		{
		    if ( ++iReset == insert_loc )
			break;
		    prev = pReset;
		}
		if ( !pReset )
		{
		    send_to_char( "Reset not found.\n\r", ch );
		    return;
		}
		if ( prev )
		    prev->next = prev->next->next;
		else
		    pRoom->reset_first = pRoom->reset_first->next;
                for ( pRoom->reset_last = pRoom->reset_first; pRoom->reset_last->next; pRoom->reset_last = pRoom->reset_last->next );
	    }
	    free_reset_data( pReset );
	    send_to_char( "Reset deleted.\n\r", ch );
	    SET_BIT( ch->in_room->area->area_flags, AREA_CHANGED );
	}
        else if ( (!str_cmp( arg2, "mob" ) && is_number( arg3 ))
		  || (!str_cmp( arg2, "obj" ) && is_number( arg3 )) 
		  || (!str_cmp( arg2, "trap" ) && is_number( arg3 )) )
	  {
	    if ( !str_cmp( arg2, "trap" ) ){
	      int type = 0;
	      int exit = 0;
	      if (get_trap_index( is_number(arg3) ? atoi( arg3 ) : 1 ) == NULL){
		send_to_char("Trap doesn't exist.\n\r",ch);
		return;
	      }
	      if (IS_NULLSTR(arg4)){
		send_to_char("OBJ or EXIT trap?\n\r", ch);
		return;
	      }
	      if (!str_cmp("obj", arg4))
		type  = TRAP_ON_OBJ;
	      else if (!str_cmp("exit", arg4)){
		type  = TRAP_ON_EXIT;
		if ( (exit = dir_lookup(arg5)) < 0 || exit >= MAX_DOOR){
		  send_to_char("Invalid exit.\n\r", ch);
		  return;
		}
	      }
	      else{
		send_to_char("OBJ or EXIT trap?\n\r", ch);
		return;
	      }

	      pReset		= new_reset_data();
	      pReset->command	= 'T';
	      pReset->arg1	= atoi( arg3 );
	      pReset->arg2	= type;
	      pReset->arg3	= ch->in_room->vnum;
	      pReset->arg4	= exit;
	    }
	    else if ( !str_cmp( arg2, "mob" ) )
	      {
		if (get_mob_index( is_number(arg3) ? atoi( arg3 ) : 1 ) == NULL)
		  {
                    send_to_char("Mob doesn't exist.\n\r",ch);
		    return;
		  }
                pReset = new_reset_data();
                pReset->command = 'M';
		pReset->arg1    = atoi( arg3 );
                pReset->arg2    = is_number( arg4 ) ? atoi( arg4 ) : 1; 
		pReset->arg3    = ch->in_room->vnum;
                pReset->arg4    = is_number( arg5 ) ? atoi( arg5 ) : 1; 
	      }
	    else
	      if ( !str_cmp( arg2, "obj" ) )
		{
		  pReset = new_reset_data();
		  pReset->arg1    = atoi( arg3 );
		  if ( !str_prefix( arg4, "inside" ) )
		    {
		      OBJ_INDEX_DATA *temp;
		      temp = get_obj_index(is_number(arg5) ? atoi(arg5) : 1);
		      if ( ( temp->item_type != ITEM_CONTAINER ) && ( temp->item_type != ITEM_CORPSE_NPC ) )
			{
			  send_to_char( "Object 2 is not a container\n\r.", ch);
			  return;
			}
		      pReset->command = 'P';
		      pReset->arg2    = is_number( arg6 ) ? atoi( arg6 ) : 1;
		      pReset->arg3    = is_number( arg5 ) ? atoi( arg5 ) : 1;
		      pReset->arg4    = is_number( arg7 ) ? atoi( arg7 ) : 1;
		    }
		  else if ( !str_cmp( arg4, "room" ) )
		    {
		      if (get_obj_index(atoi(arg3)) == NULL)
			{
			  send_to_char( "Vnum doesn't exist.\n\r",ch);
			  return;
			}
		      pReset->command  = 'O';
		      pReset->arg2     = 0;
		      pReset->arg3     = ch->in_room->vnum;
		      pReset->arg4     = 0;
		    }
		  else
		    {
		      if ( flag_value( wear_loc_flags, arg4 ) == NO_FLAG )
			{
			  send_to_char( "Resets: '? wear-loc'\n\r", ch );
			  return;
		    }
		    if (get_obj_index(atoi(arg3)) == NULL)
		      {
                        send_to_char( "Vnum no existe.\n\r",ch);
                        return;
		      }
		    pReset->arg1 = atoi(arg3);
		    pReset->arg3 = flag_value( wear_loc_flags, arg4 );
		    if ( pReset->arg3 == WEAR_NONE )
		      pReset->command = 'G';
		    else
		      pReset->command = 'E';
		    }
		}
	    add_reset( ch->in_room, pReset, atoi( arg1 ) );
            SET_BIT( ch->in_room->area->area_flags, AREA_CHANGED );
            send_to_char( "Reset added.\n\r", ch );
	  }
        else if (!str_cmp( arg2, "random") && is_number(arg3))
        {
                if (atoi(arg3) < 1 || atoi(arg3) > 6)
                        {
                                send_to_char("Invalid argument.\n\r", ch);
                                return;
                        }
                pReset = new_reset_data ();
                pReset->command = 'R';
                pReset->arg1 = ch->in_room->vnum;
                pReset->arg2 = atoi(arg3);
                add_reset( ch->in_room, pReset, atoi( arg1 ) );
                SET_BIT( ch->in_room->area->area_flags, AREA_CHANGED );
                send_to_char( "Random exits reset added.\n\r", ch);

        }
	else
	{
	send_to_char( "Syntax: RESET <number> OBJ <vnum> <wear_loc>\n\r", ch );
        send_to_char( "        RESET <number> OBJ <vnum> inside <vnum> [limit] [count]\n\r", ch );
	send_to_char( "        RESET <number> OBJ <vnum> room\n\r", ch );
        send_to_char( "        RESET <number> MOB <vnum> [max # area] [max # room]\n\r", ch );
        send_to_char( "        RESET <number> TRAP <vnum> OBJ\n\r", ch );
        send_to_char( "        RESET <number> TRAP <vnum> EXIT <dir>\n\r", ch );
	send_to_char( "        RESET <number> DELETE\n\r", ch );
        send_to_char( "        RESET <number> RANDOM [# exits]\n\r", ch );
	}
    
    }
    else
    {
	send_to_char( "Syntax: RESET <number> OBJ <vnum> <wear_loc>\n\r", ch );
        send_to_char( "        RESET <number> OBJ <vnum> inside <vnum> [limit] [count]\n\r", ch );
	send_to_char( "        RESET <number> OBJ <vnum> room\n\r", ch );
        send_to_char( "        RESET <number> MOB <vnum> [max # area] [max # room]\n\r", ch );
        send_to_char( "        RESET <number> TRAP <vnum> OBJ\n\r", ch );
        send_to_char( "        RESET <number> TRAP <vnum> EXIT <dir>\n\r", ch );
	send_to_char( "        RESET <number> DELETE\n\r", ch );
        send_to_char( "        RESET <number> RANDOM [# exits]\n\r", ch );
    }
    return;
}


/* Normal command to list areas and display area information. *
 * Called by interpreter(interp.c)                            */
void do_alist( CHAR_DATA *ch, char *argument )
{
  BUFFER* buffer;
  char buf    [ MSL ];
  AREA_DATA *pArea;
  buffer = new_buf();

  sprintf( buf, "[%3s] [%4s] [%-20s] (%-5s-%5s) [%-10s] %3s [%-10s]\n\r",
	   "Num", "Idle", "Area Name", "lvnum", "uvnum", "Filename", "Sec", "Builders" );
  add_buf(buffer, buf);

  for ( pArea = area_first; pArea; pArea = pArea->next ){
    sprintf( buf, "[%3d] [%4d] %-22.22s (%-5d-%5d) %-12.12s [%d] [%-10.10s]\n\r",
	     pArea->vnum, pArea->idle, pArea->name, pArea->min_vnum, pArea->max_vnum,
	     pArea->file_name, pArea->security, pArea->builders );
    add_buf(buffer, buf);
    }
  page_to_char(buf_string(buffer),ch);
  free_buf(buffer);
  return;
}

/* OLC_SAVE.C
 * This takes care of saving all the .are information.
 * Notes:
 * -If a good syntax checker is used for setting vnum ranges of areas
 *  then it would become possible to just cycle through vnums instead
 *  of using the iHash stuff and checking that the room or reset or
 *  mob etc is part of that area. */

/*  Verbose writes reset data in plain english into the comments
 *  section of the resets.  It makes areas considerably larger but
 *  may aid in debugging. */
/* #define VERBOSE */

/* Returns a string without \r and ~. */
char *fix_string( const char *str )
{
    static char strfix[MSL*2];
    int i;
    int o;
    if ( str == NULL )
        return '\0';
    for ( o = i = 0; str[i+o] != '\0'; i++ )
    {
        if (str[i+o] == '\r' || str[i+o] == '~')
            o++;
        strfix[i] = str[i+o];
    }
    strfix[i] = '\0';
    return strfix;
}

/* Saves the listing of files to be loaded at startup. *
 * Called by do_asave(olc_save.c).                     */
void save_area_list()
{
    FILE *fp;
    AREA_DATA *pArea;
    if ( ( fp = fopen( "area.lst", "w" ) ) == NULL )
    {
	bug( "Save_area_list: fopen", 0 );
	fp = fopen( NULL_FILE, "r" );
	fclose (fp);
	perror( "area.lst" );
    }
    else
    {
        /* Add any help files that need to be loaded at *
         * startup to this section.                     */
        fprintf( fp, "social.are\n" );
	for( pArea = area_first; pArea; pArea = pArea->next ){
	  fprintf( fp, "%s\n", pArea->file_name );
	}
	fprintf( fp, "$\n" );
	fclose( fp );
    }
    return;
}

/* Used in save_mobile and save_object below.  Writes *
 * flags on the form fread_flag reads.                *
 * buf[] must hold at least 32+1 characters.          */
char *fwrite_flag( long flags, char buf[] )
{
    char offset;
    char *cp;
    buf[0] = '\0';
    if ( flags == 0 )
    {
	strcpy( buf, "0" );
	return buf;
    }
    for ( offset = 0, cp = buf; offset < 32; offset++ )
        if ( flags & ( (long)1 << offset ) )
	{
	    if ( offset <= 'Z' - 'A' )
		*(cp++) = 'A' + offset;
	    else
		*(cp++) = 'a' + offset - ( 'Z' - 'A' + 1 );
	}
    *cp = '\0';
    return buf;
}

/* save all the helps to the file */
void save_helps(){
  FILE *fp;
  HELP_DATA *pHelp;
  CABAL_INDEX_DATA* pCab;

  int vnum = 0;
  fclose( fpReserve );
  if ( ( fp = fopen( HELP_FILE, "w" ) ) == NULL ){
    fp = fopen( NULL_FILE, "r" );
    fclose (fp);
    perror( HELP_FILE );
  }
  else{
    for ( pHelp = help_first; pHelp != NULL; pHelp = pHelp->next ){
      /* vnum */
      fprintf( fp, "#%d\n", ++vnum);
      /* level/type */
      fprintf( fp, "%d ", pHelp->level);
      /* decide if we print anything special for race etc.*/
      switch (pHelp->level){
      case HELP_RACE:
	/* special races helps */
	if (pHelp->type < 0){
	  if (pHelp->type == -1){
	    fprintf( fp, "%s~ ", "avatar" );
	    break;
	  }
	}
	else 
	  fprintf( fp, "%s~ ", race_table[pHelp->type].name );
	break;
      case HELP_CLASS:
	fprintf( fp, "%s~ ", class_table[pHelp->type].name );
	break;
      case HELP_CABAL:
	pCab = get_cabal_index( pHelp->type );
	fprintf( fp, "%s~ ", pCab ? pCab->name : "cabal" );
	break;
      case HELP_PSALM:
	fprintf( fp, "%s~ ", psalm_table[pHelp->type].name );
	break;
      case HELP_ALL:
      default:
	break;
      }
      /* print the keywords */
      fprintf( fp, "%s~\n", pHelp->keyword );
      /* print text */
      fprintf( fp, "%s~\n\n", pHelp->text );
    }
  }
  fprintf( fp, "#0" );

  fclose( fp );
  fpReserve = fopen( NULL_FILE, "r" );
}



/* Save one mobile to file, new format *
 * Called by save_mobiles (below).     */
void save_mobile( FILE *fp, MOB_INDEX_DATA *pMobIndex )
{
    PROG_LIST *pMprog;
    sh_int race = pMobIndex->race;
    char buf[MSL];
    long temp;
    fprintf( fp, "#%d\n",         pMobIndex->vnum );
    fprintf( fp, "%s~\n",         pMobIndex->player_name );
    fprintf( fp, "%s~\n",         pMobIndex->short_descr );
    fprintf( fp, "%s~\n",         fix_string( pMobIndex->long_descr ) );
    fprintf( fp, "%s~\n",         fix_string( pMobIndex->description) );
    fprintf( fp, "%s~\n",         race_table[race].name );
    fprintf( fp, "%s ",	          fwrite_flag( pMobIndex->act,         buf ) );
    fprintf( fp, "%s ",	          fwrite_flag( pMobIndex->act2,        buf ) );
    fprintf( fp, "%s ",	          fwrite_flag( pMobIndex->affected_by, buf ) );
    fprintf( fp, "%s ",	          fwrite_flag( pMobIndex->affected2_by, buf ) );
    fprintf( fp, "%d %d\n",        pMobIndex->alignment , pMobIndex->group);
    fprintf( fp, "%d ",	          pMobIndex->level );
    fprintf( fp, "%d ",	          pMobIndex->hitroll );
    fprintf( fp, "%dd%d+%d ",     pMobIndex->hit[DICE_NUMBER], 
	     	     	          pMobIndex->hit[DICE_TYPE], 
	     	     	          pMobIndex->hit[DICE_BONUS] );

    fprintf( fp, "%dd%d+%d ",     pMobIndex->mana[DICE_NUMBER], 
	     	     	          pMobIndex->mana[DICE_TYPE], 
	     	     	          pMobIndex->mana[DICE_BONUS] );

    fprintf( fp, "%dd%d+%d ",     pMobIndex->damage[DICE_NUMBER], 
	     	     	          pMobIndex->damage[DICE_TYPE], 
	     	     	          pMobIndex->damage[DICE_BONUS] );
    fprintf( fp, "%s\n",          attack_table[pMobIndex->dam_type].name );
    fprintf( fp, "%d %d %d %d\n", pMobIndex->ac[AC_PIERCE] / 10, 
	     	     	          pMobIndex->ac[AC_BASH]   / 10, 
	     	     	          pMobIndex->ac[AC_SLASH]  / 10, 
	     	     	          pMobIndex->ac[AC_EXOTIC] / 10 );
    fprintf( fp, "%s ",           fwrite_flag( pMobIndex->off_flags,  buf ) );
    fprintf( fp, "%s ",	          fwrite_flag( pMobIndex->imm_flags,  buf ) );
    fprintf( fp, "%s ",           fwrite_flag( pMobIndex->res_flags,  buf ) );
    fprintf( fp, "%s\n",          fwrite_flag( pMobIndex->vuln_flags, buf ) );
    fprintf( fp, "%s %s ",        position_table[pMobIndex->start_pos].short_name,
	         	     	  position_table[pMobIndex->default_pos].short_name);
    fprintf( fp, "%s ",    	  sex_table[pMobIndex->sex].name);

    fprintf( fp, "%s~\n",    	  pMobIndex->pCabal ? pMobIndex->pCabal->name : "none");

    fprintf( fp, "%ld\n",          pMobIndex->gold );
    fprintf( fp, "%s ",           fwrite_flag( pMobIndex->form,  buf ) );
    fprintf( fp, "%s ",      	  fwrite_flag( pMobIndex->parts, buf ) );
    fprintf( fp, "%s ",           size_table[pMobIndex->size].name );
    fprintf( fp, "0\n");
    if ((temp = DIF(race_table[race].act,pMobIndex->act)))
        fprintf( fp, "F act %s\n", fwrite_flag(temp, buf) );
    if ((temp = DIF(race_table[race].act2,pMobIndex->act2)))
        fprintf( fp, "F act2 %s\n", fwrite_flag(temp, buf) );
    if ((temp = DIF(race_table[race].aff,pMobIndex->affected_by)))
        fprintf( fp, "F aff %s\n", fwrite_flag(temp, buf) );
    if ((temp = DIF(race_table[race].off,pMobIndex->off_flags)))
        fprintf( fp, "F off %s\n", fwrite_flag(temp, buf) );
    if ((temp = DIF(race_table[race].imm,pMobIndex->imm_flags)))
        fprintf( fp, "F imm %s\n", fwrite_flag(temp, buf) );
    if ((temp = DIF(race_table[race].res,pMobIndex->res_flags)))
        fprintf( fp, "F res %s\n", fwrite_flag(temp, buf) );
    if ((temp = DIF(race_table[race].vuln,pMobIndex->vuln_flags)))
        fprintf( fp, "F vul %s\n", fwrite_flag(temp, buf) );
/*    if ((temp = DIF(race_table[race].form,pMobIndex->form)))
        fprintf( fp, "F for %s\n", fwrite_flag(temp, buf) );
    if ((temp = DIF(race_table[race].parts,pMobIndex->parts)))
        fprintf( fp, "F par %s\n", fwrite_flag(temp, buf) );*/

    for (pMprog = pMobIndex->mprogs; pMprog; pMprog = pMprog->next)
    {
        fprintf(fp, "P %s %d %s~\n",
        prog_type_to_name(pMprog->trig_type), pMprog->vnum,
                pMprog->trig_phrase);
    }
    return;
}

/* Save #MOBILES secion of an area file. *
 * Called by:     save_area(olc_save.c). */

/* This function is for new mobprogs only, Will MERGE them later. */
void save_new_mobprogs( FILE *fp, AREA_DATA *pArea )
{
	PROG_CODE *pMprog;
        int i;

	//old save_mobprog below prints this.        fprintf(fp, "#MOBPROGS\n");

	for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
        {
          if ( (pMprog = get_prog_index(i, PRG_MPROG) ) != NULL)
		{
		          fprintf(fp, "#%d\n", i);
		          fprintf(fp, "%s~\n", fix_string(pMprog->code));
		}
        }
        fprintf(fp,"#0\n\n");
        return;
}

void save_mobprogs( FILE *fp, AREA_DATA *pArea )
{
    int iHash;
    TRIGFILE_DATA *ptrigfile;
    MOB_INDEX_DATA *pMobIndex;

    fprintf( fp, "#MOBPROGS\n" );

    /* Write new progs */
    save_new_mobprogs( fp, pArea);

    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
        for( pMobIndex = mob_index_hash[iHash]; pMobIndex; pMobIndex = pMobIndex->next )
            if ( pMobIndex && pMobIndex->area == pArea && pMobIndex->progtypes )
		for ( ptrigfile = pMobIndex->trigfile; ptrigfile; ptrigfile = ptrigfile->next )
                    fprintf( fp, "M %d %d %s NL\n", pMobIndex->vnum, ptrigfile->dowhen, ptrigfile->name );
    fprintf( fp, "S\n\n\n\n\n" );
    return;
}



void save_objprogs( FILE *fp, AREA_DATA *pArea )
{
	PROG_CODE *pOprog;
        int i;

        fprintf(fp, "#OBJPROGS\n");

	for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
        {
          if ( (pOprog = get_prog_index(i, PRG_OPROG) ) != NULL)
		{
		          fprintf(fp, "#%d\n", i);
		          fprintf(fp, "%s~\n", fix_string(pOprog->code));
		}
        }

        fprintf(fp,"#0\n\n");
        return;
}

void save_roomprogs( FILE *fp, AREA_DATA *pArea )
{
	PROG_CODE *pRprog;
        int i;

        fprintf(fp, "#ROOMPROGS\n");

	for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
        {
          if ( (pRprog = get_prog_index(i,PRG_RPROG) ) != NULL)
		{
		          fprintf(fp, "#%d\n", i);
		          fprintf(fp, "%s~\n", fix_string(pRprog->code));
		}
        }

        fprintf(fp,"#0\n\n");
        return;
}

void save_mobiles( FILE *fp, AREA_DATA *pArea )
{
    int i;
    MOB_INDEX_DATA *pMob;
    fprintf( fp, "#MOBILES\n" );
    for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
      if ( (pMob = get_mob_index( i )) ){
	save_mobile( fp, pMob );
      }
    fprintf( fp, "#0\n\n\n\n" );
    return;
}

/* Save one object to file.             *
 * Called by:     save_objects (below). */
void save_object( FILE *fp, OBJ_INDEX_DATA *pObjIndex )
{
    char letter;
    AFFECT_DATA *pAf;
    EXTRA_DESCR_DATA *pEd;
    OBJ_SPELL_DATA *pOs;
    char buf[MSL];
    PROG_LIST *pOprog;

    if (pObjIndex->item_type == ITEM_PROJECTILE)
      SET_BIT( pObjIndex->wear_flags, ITEM_WEAR_QUIVER);

    fprintf( fp, "#%d\n",    pObjIndex->vnum );
    fprintf( fp, "%s~\n",    pObjIndex->name );
    fprintf( fp, "%s~\n",    pObjIndex->short_descr );
    fprintf( fp, "%s~\n",    fix_string( pObjIndex->description ) );
    fprintf( fp, "%s~\n",    pObjIndex->material );
    fprintf( fp, "%s ",      item_name(pObjIndex->item_type));
    fprintf( fp, "%s ",      fwrite_flag( pObjIndex->extra_flags, buf ) );
    fprintf( fp, "%s\n",     fwrite_flag( pObjIndex->wear_flags,  buf ) );
/*  Using fwrite_flag to write most values gives a strange *
 *  looking area file, consider making a case for each     *
 *  item type later.                                       */
    switch ( pObjIndex->item_type )
    {
        default:
            fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[0], buf ) );
            fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[1], buf ) );
            fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[2], buf ) );
            fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[3], buf ) );
            fprintf( fp, "%s\n", fwrite_flag( pObjIndex->value[4], buf ) );
	    break;
        case ITEM_LIGHT:
            fprintf( fp, "0 0 %d 0 0\n", pObjIndex->value[2] < 1 ? 999 : pObjIndex->value[2] );
	    break;
        case ITEM_MONEY:
            fprintf( fp, "%d %d 0 0 0\n", pObjIndex->value[0], pObjIndex->value[1]);
            break;
        case ITEM_DRINK_CON:
            fprintf( fp, "%d %d '%s' %d 0\n",
              pObjIndex->value[0], pObjIndex->value[1],
              liq_table[pObjIndex->value[2]].liq_name,
              pObjIndex->value[3]);
            break;
	case ITEM_FOUNTAIN:
	    fprintf( fp, "%d %d '%s' 0 0\n",
              pObjIndex->value[0], pObjIndex->value[1],
              liq_table[pObjIndex->value[2]].liq_name);
	    break;
        case ITEM_CONTAINER:
            fprintf( fp, "%d %s %d %d %d\n",
              pObjIndex->value[0], fwrite_flag( pObjIndex->value[1], buf ),
              pObjIndex->value[2], pObjIndex->value[3], pObjIndex->value[4]);
            break;
        case ITEM_FOOD:
            fprintf( fp, "%d %d 0 %s %d\n",
              pObjIndex->value[0], pObjIndex->value[1], fwrite_flag( pObjIndex->value[3], buf ), pObjIndex->value[4] );
            break;
        case ITEM_WEAPON:
            fprintf( fp, "%s %d %d %s %s\n",
              weapon_name(pObjIndex->value[0]), pObjIndex->value[1], pObjIndex->value[2],
              attack_table[pObjIndex->value[3]].name, fwrite_flag( pObjIndex->value[4], buf ) );
            break;
	case ITEM_THROW:
            fprintf( fp, "%d %d %d %s %s\n",
              pObjIndex->value[0], pObjIndex->value[1], pObjIndex->value[2],
              attack_table[pObjIndex->value[3]].name, fwrite_flag( pObjIndex->value[4], buf ) );
            break;
        case ITEM_ARMOR:
            fprintf( fp, "%d %d %d %d %d\n",
              pObjIndex->value[0], pObjIndex->value[1], pObjIndex->value[2],
              pObjIndex->value[3], pObjIndex->value[4]);
            break;
        case ITEM_PILL:
        case ITEM_POTION:
        case ITEM_SCROLL:
	case ITEM_RELIC:
	case ITEM_ARTIFACT:
	case ITEM_HERB:
		/* Timer, Eaten, Herb, Brew, None */
	    fprintf( fp, "%d '%s' '%s' '%s' '%s'\n",
              pObjIndex->value[0] > 0 ? pObjIndex->value[0] : 0,
              pObjIndex->value[1] != -1 ? skill_table[pObjIndex->value[1]].name : "",
              pObjIndex->value[2] != -1 ? skill_table[pObjIndex->value[2]].name : "",
              pObjIndex->value[3] != -1 ? skill_table[pObjIndex->value[3]].name : "",
              pObjIndex->value[4] != -1 ? skill_table[pObjIndex->value[4]].name : "");
	    break;
        case ITEM_STAFF:
        case ITEM_WAND:
	    fprintf( fp, "%d ", pObjIndex->value[0] );
	    fprintf( fp, "%d ", pObjIndex->value[1] );
	    fprintf( fp, "%d '%s' 0\n",
              pObjIndex->value[2], pObjIndex->value[3] != -1 ? skill_table[pObjIndex->value[3]].name : "(null)" );
	    break;
    case ITEM_INSTRUMENT:
      fprintf( fp, "0 0 0 0 %s\n", fwrite_flag( pObjIndex->value[4], buf ) );
      break;
    case ITEM_SOCKET:
      fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[0], buf ) );
      fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[1], buf ) );
      fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[2], buf ) );
      fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[3], buf ) );
      fprintf( fp, "%s\n", 
	       fwrite_flag( IS_SOC_STAT(pObjIndex, SOCKET_WEAPON) ?
			    pObjIndex->value[4] : 0, buf ) );
      break;
    case ITEM_RANGED:
      fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[0], buf ) );
      fprintf( fp, "%d ",  pObjIndex->value[1]);
      fprintf( fp, "%d ",  pObjIndex->value[2]);
      fprintf( fp, "%d ",  pObjIndex->value[3]);
      fprintf( fp, "%s\n",  fwrite_flag( pObjIndex->value[4], buf ) );
      break;
    case ITEM_PROJECTILE:
      fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[0], buf ) );
      fprintf( fp, "%d ",  pObjIndex->value[1]);
      fprintf( fp, "%d ",  pObjIndex->value[2]);
      fprintf( fp, "%s ",  attack_table[pObjIndex->value[3]].name);
      fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[4], buf ) 
);
      break;   
    }
    fprintf( fp, "%d ", pObjIndex->level );
    fprintf( fp, "%d ", pObjIndex->weight );
    fprintf( fp, "%d ", pObjIndex->cost );
    if      ( pObjIndex->condition >  90 ) letter = 'P';
    else if ( pObjIndex->condition >  75 ) letter = 'G';
    else if ( pObjIndex->condition >  50 ) letter = 'A';
    else if ( pObjIndex->condition >  25 ) letter = 'W';
    else if ( pObjIndex->condition >  10 ) letter = 'D';
    else if ( pObjIndex->condition >   0 ) letter = 'B';
    else                                   letter = 'R';
    fprintf( fp, "%c\n", letter );
    if (pObjIndex->pCabal)
      fprintf( fp, "C\n%s~\n", pObjIndex->pCabal->name );
    if (pObjIndex->race)
      fprintf( fp, "R\n%d\n", pObjIndex->race );
    if (pObjIndex->class >= 0)
      fprintf( fp, "L\n%d\n", pObjIndex->class );
    for( pEd = pObjIndex->extra_descr; pEd; pEd = pEd->next )
        fprintf( fp, "E\n%s~\n%s~\n", pEd->keyword, fix_string( pEd->description ) );
    for ( pOs = pObjIndex->spell; pOs; pOs = pOs->next )
        fprintf( fp, "T\n%d %d %d\n%s~\n%s~\n", pOs->spell, pOs->target, pOs->percent,
	pOs->message, pOs->message2 );
    if (pObjIndex->message)
	fprintf( fp, "M\n%s~\n%s~\n%s~\n%s~\n", pObjIndex->message->onself, pObjIndex->message->onother,
	pObjIndex->message->offself, pObjIndex->message->offother );
    for( pAf = pObjIndex->affected; pAf; pAf = pAf->next )
        fprintf( fp, "F\n%s %d %d %s\n",
		 pAf->where == TO_IMMUNE ? "I" : 
		 pAf->where==TO_RESIST ? "R"   :
		 pAf->where == TO_VULN ? "V"   :
		 pAf->where == TO_SKILL ? "S"  : "A",
		 pAf->location, pAf->modifier, fwrite_flag(pAf->bitvector, buf) );

    for (pOprog = pObjIndex->oprogs; pOprog; pOprog = pOprog->next)
    {
        fprintf(fp, "P %s %d %s~\n",
        prog_type_to_name(pOprog->trig_type), pOprog->vnum,
                pOprog->trig_phrase);
    }
    return;
}

/* Save #OBJECTS section of an area file. *
 * Called by save_area(olc_save.c).       */
void save_objects( FILE *fp, AREA_DATA *pArea )
{
    int i;
    OBJ_INDEX_DATA *pObj;
    fprintf( fp, "#OBJECTS\n" );
    for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
	if ( (pObj = get_obj_index( i )) )
	    save_object( fp, pObj );
    fprintf( fp, "#0\n\n\n\n" );
    return;
}
 
/* SAVE #TRAPS section of an area file	*/
/* called save_area			*/
/* This function is for new mobprogs only, Will MERGE them later. */
void save_traps( FILE *fp, AREA_DATA *pArea ){
  char buf[MIL];
  TRAP_INDEX_DATA *pTrap;
  int i;
  
  fprintf(fp, "#TRAPS\n");
  
  for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ ){
    if ( (pTrap = get_trap_index(i)) != NULL){
      fprintf(fp, "#%d\n", i);
      /* common things */
      fprintf( fp, "%s~\n%s~\n%s~\n%s %d %s\n", 
	       pTrap->name,
	       pTrap->echo,
	       pTrap->oEcho,
	       trap_table[pTrap->type].name, 
	       pTrap->level,
	       fwrite_flag(pTrap->flags, buf));
      
      /* based on type */
      switch (pTrap->type){
      default:
      case TTYPE_DUMMY:
	fprintf( fp, "%d %d %d %d %d\n",
		 pTrap->value[0],
		 pTrap->value[1],
		 pTrap->value[2],
		 pTrap->value[3],
		 pTrap->value[4]);
	break;
      case TTYPE_DAMAGE:
	fprintf( fp, "%s %d %d %d %d\n",
		 attack_table[pTrap->value[0]].name,
		 pTrap->value[1],
		 pTrap->value[2],
		 pTrap->value[3],
		 pTrap->value[4]);
	break;
      case TTYPE_XDAMAGE:
	fprintf( fp, "%s~ %d %d %d %d\n",
		 IS_GEN(pTrap->value[0]) ? effect_table[pTrap->value[0]].name :
		 skill_table[pTrap->value[0]].name,
		 pTrap->value[1],
		 pTrap->value[2],
		 pTrap->value[3],
		 pTrap->value[4]);
	break;
      case TTYPE_SPELL:
	fprintf( fp, "%s~ %d %s~ %d %d\n",
		 skill_table[pTrap->value[0]].name,
		 pTrap->value[1],
		 skill_table[pTrap->value[2]].name,
		 pTrap->value[3],
		 pTrap->value[4]);
	break;
      case TTYPE_MOB:
	fprintf( fp, "%d %d %d %d %d\n",
		 pTrap->value[0],
		 pTrap->value[1],
		 pTrap->value[2],
		 pTrap->value[3],
		 pTrap->value[4]);
	break;
      }
    }
  }
  fprintf(fp,"#0\n\n");
  return;
}

/* writes a singel room */
void write_room( FILE* fp, ROOM_INDEX_DATA* pRoomIndex ){
  EXTRA_DESCR_DATA *pEd;
  EXIT_DATA *pExit;
  PROG_LIST *pRprog;
  int door;  
  Double_List *tmp_list;
  char buf[MIL];

  fprintf( fp, "%s~\n",		pRoomIndex->name );
  fprintf( fp, "%s~\n",		fix_string( pRoomIndex->description ) );
  if (pRoomIndex->description2 != NULL)
    fprintf( fp, "%s~\n",		fix_string( pRoomIndex->description2 ) );
  else
    fprintf( fp, "~\n" );
  fprintf( fp, "0 " );
  fprintf( fp, "%d ",		pRoomIndex->room_flags );
  fprintf( fp, "%d ",		pRoomIndex->room_flags2 );
  fprintf( fp, "%d\n",		pRoomIndex->sector_type );
  for ( pEd = pRoomIndex->extra_descr; pEd; pEd = pEd->next )
    fprintf( fp, "E\n%s~\n%s~\n", pEd->keyword, fix_string( pEd->description ) );

  for( door = 0; door < MAX_DIR; door++ ) {
    if ( ( pExit = pRoomIndex->exit[door] ) && pExit->to_room ){
      /* we check if this is a non virtual room leading to virtual */
      if (pRoomIndex->vnum > 0 && !IS_VIRROOM(pRoomIndex) && IS_VIRROOM(pExit->to_room))
	continue;
      fprintf( fp, "D%d\n",      pExit->orig_door );
      fprintf( fp, "%s~\n",      fix_string( pExit->description ) );
      fprintf( fp, "%s~\n",      pExit->keyword );
      fprintf( fp, "%s %d %d\n", fwrite_flag(pExit->rs_flags, buf),  pExit->key, pExit->to_room->vnum );
    }
  }

  if (pRoomIndex->mana_rate != 100 || pRoomIndex->heal_rate != 100)
    fprintf ( fp, "M %d H %d\n",pRoomIndex->mana_rate, pRoomIndex->heal_rate);
  if (pRoomIndex->pCabal)
    fprintf ( fp, "C %s~\n" , pRoomIndex->pCabal->name );
  if (pRoomIndex->temp != 72)
    fprintf ( fp, "T %d\n" , pRoomIndex->temp );
  tmp_list = pRoomIndex->watch_vnums;
  while (tmp_list != NULL) {
    fprintf ( fp, "W %d\n" , (int) tmp_list->cur_entry );
    tmp_list = tmp_list->next_node;
  }
  for (pRprog = pRoomIndex->rprogs; pRprog; pRprog = pRprog->next){
    fprintf(fp, "P %s %d %s~\n",
	    prog_type_to_name(pRprog->trig_type), pRprog->vnum,
	    pRprog->trig_phrase);
  }
  fprintf( fp, "S\n" );
}

/* Save #ROOMS section of an area file. *
 * Called by save_area(olc_save.c).     */
void save_rooms( FILE *fp, AREA_DATA *pArea )
{
    ROOM_INDEX_DATA *pRoomIndex;
    int iHash;

    fprintf( fp, "#ROOMS\n" );
    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ){
      for( pRoomIndex = room_index_hash[iHash]; pRoomIndex; pRoomIndex = pRoomIndex->next )
	if ( pRoomIndex->area == pArea && !IS_VIRROOM( pRoomIndex) ){
	  fprintf( fp, "#%d\n",		pRoomIndex->vnum );
	  write_room( fp, pRoomIndex );
	}
    }
    fprintf( fp, "#0\n\n\n\n" );
    return;
}

/* Save #SPECIALS section of area file. *
 * Called by save_area(olc_save.c).     */
void save_specials( FILE *fp, AREA_DATA *pArea )
{
    int iHash;
    MOB_INDEX_DATA *pMobIndex;
    fprintf( fp, "#SPECIALS\n" );
    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
        for( pMobIndex = mob_index_hash[iHash]; pMobIndex; pMobIndex = pMobIndex->next )
            if ( pMobIndex && pMobIndex->area == pArea && pMobIndex->spec_fun )
#if defined( VERBOSE )
                fprintf( fp, "M %d %s Load to: %s\n", pMobIndex->vnum, spec_name( pMobIndex->spec_fun ), pMobIndex->short_descr );
#else
                fprintf( fp, "M %d %s\n", pMobIndex->vnum, spec_name( pMobIndex->spec_fun ) );
#endif
    fprintf( fp, "S\n\n\n\n" );
    return;
}

/* writes a single room's resets */
void write_resets( FILE* fp, ROOM_INDEX_DATA* pRoom ){
  RESET_DATA *pReset;
  MOB_INDEX_DATA *pLastMob = NULL;
  OBJ_INDEX_DATA *pLastObj;
  TRAP_INDEX_DATA *pTrap;
  char buf[MIL];
  
  for ( pReset = pRoom->reset_first; pReset; pReset = pReset->next ){
    switch ( pReset->command ){
    default:
      bug( "Save_resets: bad command %c.", pReset->command );
      break;
#if defined( VERBOSE )
    case 'M':
      pLastMob = get_mob_index( pReset->arg1 );
      fprintf( fp, "M 0 %d %d %d %d Load %s\n", 
	       pReset->arg1, pReset->arg2, pReset->arg3,
	       pReset->arg4, pLastMob->short_descr );
      break;
    case 'O':
      pLastObj = get_obj_index( pReset->arg1 );
      pRoom = get_room_index( pReset->arg3 );
      fprintf( fp, "O 0 %d 0 %d %s loaded to %s\n", 
	       pReset->arg1, pReset->arg3,
	       capitalize(pLastObj->short_descr), pRoom->name );
      break;
    case 'P':
      pLastObj = get_obj_index( pReset->arg1 );
      fprintf( fp, "P 0 %d %d %d %d %s put inside %s\n", 
	       pReset->arg1, pReset->arg2, pReset->arg3, pReset->arg4,
	       capitalize(get_obj_index( pReset->arg1 )->short_descr),
	       pLastObj->short_descr );
      break;
    case 'G':
      fprintf( fp, "G 0 %d 0 %s is given to %s\n",
	       pReset->arg1,
	       capitalize(get_obj_index( pReset->arg1 )->short_descr),
	       pLastMob ? pLastMob->short_descr : "!NO_MOB!" );
      if ( !pLastMob )
	{
	  sprintf( buf, "Save_resets: !NO_MOB! in [%s]", pArea->file_name );
	  bug( buf, 0 );
	}
      break;
    case 'E':
      fprintf( fp, "E 0 %d 0 %d %s is loaded %s of %s\n",
	       pReset->arg1, pReset->arg3,
	       capitalize(get_obj_index( pReset->arg1 )->short_descr),
	       flag_string( wear_loc_strings, pReset->arg3 ),
	       pLastMob ? pLastMob->short_descr : "!NO_MOB!" );
      if ( !pLastMob )
	{
	  sprintf( buf, "Save_resets: !NO_MOB! in [%s]", pArea->file_name );
	  bug( buf, 0 );
	}
      break;
    case 'D':
      break;
    case 'R':
      pRoom = get_room_index( pReset->arg1 );
      fprintf( fp, "R 0 %d %d Randomize %s\n", 
	       pReset->arg1, pReset->arg2, pRoom->name );
      break;
#endif
#if !defined( VERBOSE )
  case 'M':
    pLastMob = get_mob_index( pReset->arg1 );
    fprintf( fp, "M 0 %d %d %d %d\n",
	     pReset->arg1, pReset->arg2, pReset->arg3, pReset->arg4 );
    break;
  case 'O':
    pLastObj = get_obj_index( pReset->arg1 );
    pRoom = get_room_index( pReset->arg3 );
    fprintf( fp, "O 0 %d 0 %d\n", pReset->arg1, pReset->arg3 );
    break;
  case 'P':
    pLastObj = get_obj_index( pReset->arg1 );
    fprintf( fp, "P 0 %d %d %d %d\n", pReset->arg1, pReset->arg2, pReset->arg3, pReset->arg4 );
    break;
  case 'T':
    pTrap = get_trap_index( pReset->arg1 );
    fprintf( fp, "T 0 %d %d %d %d\n",
	     pReset->arg1, pReset->arg2, pReset->arg3, pReset->arg4 );
    break;
  case 'G':
    fprintf( fp, "G 0 %d 0\n", pReset->arg1 );
    if ( !pLastMob )
      {
	sprintf( buf, "Save_resets: !NO_MOB! in [%d]", pReset->arg1 );
	bug( buf, 0 );
      }
    break;
  case 'E':
    fprintf( fp, "E 0 %d 0 %d\n", pReset->arg1, pReset->arg3 );
    if ( !pLastMob )
      {
	sprintf( buf, "Save_resets: !NO_MOB! in [%d]", pReset->arg1 );
	bug( buf, 0 );
      }
    break;
  case 'D':
    break;
  case 'R':
    pRoom = get_room_index( pReset->arg1 );
    fprintf( fp, "R 0 %d %d\n", pReset->arg1, pReset->arg2 );
    break;
#endif
    }
  }
}

/* Saves the #RESETS section of an area file. *
 * Called by save_area(olc_save.c)            */
void save_resets( FILE *fp, AREA_DATA *pArea )
{
  ROOM_INDEX_DATA *pRoom;
  int iHash;
  
  fprintf( fp, "#RESETS\n" );
  for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ){
    for( pRoom = room_index_hash[iHash]; pRoom; pRoom = pRoom->next ){
      if ( pRoom->area == pArea && !IS_VIRROOM( pRoom ) ){
	write_resets( fp, pRoom );
      }
    }//end for room in hash cell
  }//end for each hash cell
  fprintf( fp, "S\n\n\n\n" );
  return;
}

/* Saves the #SHOPS section of an area file. *
 * Called by save_area(olc_save.c)           */
void save_shops( FILE *fp, AREA_DATA *pArea )
{
    SHOP_DATA *pShopIndex;
    MOB_INDEX_DATA *pMobIndex;
    int iHash;
    int iTrade;
    fprintf( fp, "#SHOPS\n" );
    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
        for( pMobIndex = mob_index_hash[iHash]; pMobIndex; pMobIndex = pMobIndex->next )
	  if ( pMobIndex && pMobIndex->area == pArea && pMobIndex->pShop)
            {
                pShopIndex = pMobIndex->pShop;
                fprintf( fp, "%d ", pShopIndex->keeper );
                for ( iTrade = 0; iTrade < MAX_TRADE; iTrade++ )
                {
                    if ( pShopIndex->buy_type[iTrade] != 0 )
                       fprintf( fp, "%d ", pShopIndex->buy_type[iTrade] );
                    else
                       fprintf( fp, "0 ");
                }
                fprintf( fp, "%d %d ", pShopIndex->profit_buy, pShopIndex->profit_sell );
                fprintf( fp, "%d %d\n", pShopIndex->open_hour, pShopIndex->close_hour );
            }
    fprintf( fp, "0\n\n\n\n" );
    return;
}

/* Save an area, note that this format is new. *
 * Called by do_asave(olc_save.c).             */
void save_area( AREA_DATA *pArea )
{
    FILE *fp;
    int i = 0, flag;
    fclose( fpReserve );
    if ( !( fp = fopen( pArea->file_name, "w" ) ) )
    {
	bug( "Open_area: fopen", 0 );
	fp = fopen( NULL_FILE, "r" );
	fclose (fp);
	perror( pArea->file_name );
    }
    /* clear off the flags which should not be saved */
    flag = pArea->area_flags;
    for (i = 0; area_flags[i].name; i ++){
      if (area_flags[i].settable == FALSE)
	flag &= ~area_flags[i].bit;
    }    
    fprintf( fp, "#AREADATA\n" );
    fprintf( fp, "Name %s~\n",        pArea->name );
    fprintf( fp, "Pref %s~\n",        pArea->prefix );
    fprintf( fp, "Builders %s~\n",    fix_string( pArea->builders ) );
    fprintf( fp, "VNUMs %d %d\n",     pArea->min_vnum, pArea->max_vnum );
    fprintf( fp, "Max_Bastions %d\n", pArea->bastion_max);
    fprintf( fp, "Credits %s~\n",	 pArea->credits );
    fprintf( fp, "Security %d\n",         pArea->security );
    fprintf( fp, "Startroom %d\n",         pArea->startroom );
    fprintf( fp, "Flags %d\n",         flag );
    fprintf( fp, "Crimes %d ",         MAX_CRIME );

    /* print crimes */
    for (i = 0; i < MAX_CRIME; i++){
      fprintf( fp, "%d ", pArea->crimes[i] );
    }
    fprintf( fp, "\n" );
    fprintf( fp, "End\n\n\n\n" );
    save_cabal_indexes( fp, pArea );
    save_mobiles( fp, pArea );
    save_objects( fp, pArea );
    save_rooms( fp, pArea );
    save_army_indexes( fp, pArea );
    save_specials( fp, pArea );
    save_traps( fp, pArea );
    save_resets( fp, pArea );
    save_shops( fp, pArea );
    save_mobprogs( fp, pArea );
    save_objprogs( fp, pArea );
    save_roomprogs( fp, pArea );

    fprintf( fp, "#$\n" );
    fclose( fp );
    fpReserve = fopen( NULL_FILE, "r" );
    return;
}

/* Entry point for saving area data. *
 * Called by interpreter(interp.c)   */
void do_asave( CHAR_DATA *ch, char *argument )
{
    char arg1 [MIL];
    AREA_DATA *pArea;
    FILE *fp;
    int value;
    fp = NULL;
    if ( !ch )
    {
	save_area_list();
	for( pArea = area_first; pArea; pArea = pArea->next )
	{
	    REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	    save_area( pArea );
	}
	return;
    }
    smash_tilde( argument );
    strcpy( arg1, argument );
    if ( arg1[0] == '\0' )
    {
        send_to_char( "Syntax:\n\r", ch );
        send_to_char( "  asave <vnum>   - saves a particular area\n\r",     ch );
        send_to_char( "  asave list     - saves the area.lst file\n\r",     ch );
        send_to_char( "  asave help     - saves the help files\n\r",     ch );
        send_to_char( "  asave cabal    - saves the cabal file\n\r",     ch );
        send_to_char( "  asave area     - saves the area being edited\n\r", ch );
        send_to_char( "  asave tomes    - saves the library tomes\n\r", ch );
        send_to_char( "  asave changed  - saves all changed zones\n\r",     ch );
        send_to_char( "  asave armies   - saves all armies\n\r",     ch );
        send_to_char( "  asave world    - saves the world! (db dump)\n\r",  ch );
        send_to_char( "\n\r", ch );
        return;
    }
    value = atoi( arg1 );
    if ( !( pArea = get_area_data( value ) ) && is_number( arg1 ) )
    {
	send_to_char( "That area does not exist.\n\r", ch );
	return;
    }
    if ( is_number( arg1 ) )
    {
	if ( !IS_BUILDER( ch, pArea ) )
	{
	    send_to_char( "You are not a builder for this area.\n\r", ch );
	    return;
	}
	save_area_list();
	save_area( pArea );
	return;
    }
    if ( !str_cmp( "world", arg1 ) )
    {
	save_area_list();
	save_helps();
	send_to_char("Helps saved.\n\r", ch);
	save_armies();
	save_cabals(FALSE, ch);
	for( pArea = area_first; pArea; pArea = pArea->next )
	{
	    if ( !IS_BUILDER( ch, pArea ) )
		continue;	  
	    REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	    save_area( pArea );
	}
	send_to_char( "You saved the world.\n\r", ch );
	return;
    }
    if ( !str_cmp( "changed", arg1 ) )
    {
	char buf[MIL];
	save_area_list();
	save_helps();
	save_cabals(TRUE, ch);
	send_to_char( "Saved zones:\n\r", ch );
	sprintf( buf, "None.\n\r" );
	for( pArea = area_first; pArea; pArea = pArea->next )
	{
	    if ( !IS_BUILDER( ch, pArea ) )
		continue;
	    if ( IS_SET(pArea->area_flags, AREA_CHANGED) )
	    {
		REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
		save_area( pArea );
		sprintf( buf, "%24s - '%s'\n\r", pArea->name, pArea->file_name );
		send_to_char( buf, ch );
	    }
        }
	if ( !str_cmp( buf, "None.\n\r" ) )
	    send_to_char( buf, ch );
        return;
    }
    if ( !str_cmp( arg1, "armies" ) ){
      save_armies();
      return;
    }
    if ( !str_cmp( arg1, "list" ) )
    {
	save_area_list();
	return;
    }
    if ( !str_cmp( arg1, "tomes" ) )
    {
	SaveTomes();
	return;
    }
    if ( !str_cmp( arg1, "cabal" ) || !str_cmp( arg1, "cabals" ) )
    {
	save_cabals(FALSE, ch);
	return;
    }
    if ( !str_cmp( arg1, "clan" ) || !str_cmp( arg1, "clans" ) )
    {
	SaveClans();
	return;
    }
    if ( !str_cmp( arg1, "help" ) )
    {
      save_helps();
      send_to_char("Helps saved.\n\r", ch);
      return;
    }
    if ( !str_cmp( arg1, "area" ) )
    {
	if ( ch->desc->editor == 0 )
	{
            send_to_char( "You are not editing an area, therefore an area vnum is required.\n\r", ch );
	    return;
	}
	switch (ch->desc->editor)
	{
        case ED_AREA:   pArea = (AREA_DATA *)ch->desc->pEdit; break;
        case ED_ROOM:   pArea = ch->in_room->area; break;
        case ED_OBJECT: pArea = ( (OBJ_INDEX_DATA *)ch->desc->pEdit )->area; break;
        case ED_MOBILE: pArea = ( (MOB_INDEX_DATA *)ch->desc->pEdit )->area; break;
        default:        pArea = ch->in_room->area; break;
	}
	if ( !IS_BUILDER( ch, pArea ) )
	{
	    send_to_char( "You are not a builder for this area.\n\r", ch );
	    return;
	}
	save_area_list();
	REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	save_area( pArea );
	send_to_char( "Area saved.\n\r", ch );
	return;
    }
    do_asave( ch, "" );
    return;
}

/* The code below uses a table lookup system that is based on suggestions     *
 * from Russ Taylor.  There are many routines in handler.c that would benefit *
 * with the use of tables.  You may consider simplifying your code base by    *
 * implementing a system like below with such functions.                      */

struct flag_stat_type
{
    const struct flag_type *structure;
    bool stat;
};

/* This table catagorizes the tables following the lookup      *
 * functions below into stats and flags.  Flags can be toggled *
 * but stats can only be assigned.  Update this table when a   *
 * new set of flags is installed.                              */
const struct flag_stat_type flag_stat_table[] =
{
/*  {	structure		stat	}, */

/* OLC FLAGS */
    {	area_flags,		FALSE	},
    {   sex_flags,		TRUE	},
    {   exit_flags,		FALSE	},
    {   door_resets,		TRUE	},
    {   room_flags,		FALSE	},
    {   sector_flags,		TRUE	},
    {   type_flags,		TRUE	},
    {   extra_flags,		FALSE	},
    {   socket_flags,		FALSE	},
    {   wear_flags,		FALSE	},
    {   act_flags,		FALSE	},
    {   affect_flags,		FALSE	},
    {   affect2_flags,		FALSE	},
    {   apply_flags,		TRUE	},
    {   wear_loc_flags,		TRUE	},
    {   wear_loc_strings,	TRUE	},
    {   container_flags,	FALSE	},
    {   cabal_flags,		FALSE	},
    {   cabal_progress_flags,	FALSE	},
    {   croom_flags,		FALSE	},
    {   army_types,		TRUE	},
    {   army_flags,		FALSE	},

    /* ROM specific flags: */
    {	crime_table,		FALSE	},
    {	punish_table,		FALSE	},
    {	pact_flags,		FALSE	},
    {   form_flags,             FALSE   },
    {   part_flags,             FALSE   },
    {   ac_type,                TRUE    },
    {   size_flags,             TRUE    },
    {   position_flags,         TRUE    },
    {   off_flags,              FALSE   },
    {   imm_flags,              FALSE   },
    {   res_flags,              FALSE   },
    {   vuln_flags,             FALSE   },
    {   weapon_class,           TRUE    },
    {   weapon_type2,           FALSE   },
    {   apply_types,            TRUE    },
    {   room_flags2,		FALSE	},
    {   special_flags,		FALSE	},
    {   0,			0	}
};

/* Returns TRUE if the table is a stat table and FALSE if flag. *
 * Called by flag_value and flag_string.                        *
 * This function is local and used only in bit.c.               */
bool is_stat( const struct flag_type *flag_table )
{
    int flag;
    for (flag = 0; flag_stat_table[flag].structure; flag++)
        if ( flag_stat_table[flag].structure == flag_table && flag_stat_table[flag].stat )
	    return TRUE;
    return FALSE;
}

/* returns flag value regarldess of settable bit */
int flag_lookup_abs (const char *name, const struct flag_type *flag_table)
{
    int flag;
    for (flag = 0; flag_table[flag].name != NULL; flag++)
      if ( !str_cmp( name, flag_table[flag].name))
	return flag_table[flag].bit;
    return NO_FLAG;
}
/* This function is Russ Taylor's creation.  Thanks Russ!                  8
 * All code copyright (C) Russ Taylor, permission to use and/or distribute *
 * has NOT been granted.  Use only in this OLC package has been granted.   */

/* Returns the value of a single, settable flag from the table. *
 * Called by flag_value and flag_string.                        *
 * This function is local and used only in bit.c.               */
int flag_lookup2 (const char *name, const struct flag_type *flag_table)
{
    int flag;
    for (flag = 0; flag_table[flag].name != NULL; flag++)
        if ( !str_cmp( name, flag_table[flag].name ) && flag_table[flag].settable )
            return flag_table[flag].bit;
    return NO_FLAG;
}

/* Returns the value of the flags entered.  Multi-flags accepted. *
 * Called by olc.c and olc_act.c.                                 */
int flag_value( const struct flag_type *flag_table, char *argument)
{
    char word[MIL];
    int  bit;
    int  marked = 0;
    bool found = FALSE;
    if ( is_stat( flag_table ) )
    {
	one_argument( argument, word );
	if ( ( bit = flag_lookup2( word, flag_table ) ) != NO_FLAG )
	    return bit;
	else
	    return NO_FLAG;
    }
    for (; ;)
    {
        argument = one_argument( argument, word );
        if ( word[0] == '\0' )
            break;
        if ( ( bit = flag_lookup2( word, flag_table ) ) != NO_FLAG )
        {
            SET_BIT( marked, bit );
            found = TRUE;
        }
    }
    if ( found )
	return marked;
    else
	return NO_FLAG;
}

/* Returns string with name(s) of the flags or stat entered. *
 * Called by act_olc.c, olc.c, and olc_save.c.               */
char *flag_string( const struct flag_type *flag_table, int bits )
{
    static char buf[512];
    int  flag;
    buf[0] = '\0';
    for (flag = 0; flag_table[flag].name != NULL; flag++)
    {
	if ( !is_stat( flag_table ) && IS_SET(bits, flag_table[flag].bit) )
	{
	    strcat( buf, " " );
	    strcat( buf, flag_table[flag].name );
	}
        else if ( flag_table[flag].bit == bits )
	{
	    strcat( buf, " " );
	    strcat( buf, flag_table[flag].name );
	    break;
	}
    }
    return (buf[0] != '\0') ? buf+1 : "none";
}

RESET_DATA *new_reset_data( void )
{
    RESET_DATA *pReset;
    if ( !reset_free )
    {
        pReset          =   alloc_perm( sizeof(*pReset) );
        top_reset++;
    }
    else
    {
        pReset          =   reset_free;
        reset_free      =   reset_free->next;
    }
    pReset->next        =   NULL;
    pReset->command     =   'X';
    pReset->arg1        =   0;
    pReset->arg2        =   0;
    pReset->arg3        =   0;
    pReset->arg4        =   0;
    return pReset;
}

void free_reset_data( RESET_DATA *pReset )
{
    pReset->next            = reset_free;
    reset_free              = pReset;
    return;
}

AREA_DATA *new_area( void )
{
    AREA_DATA *pArea;
    char buf[MIL];
    int count;

    if ( !area_free )
    {
        pArea   =   alloc_perm( sizeof(*pArea) );
        top_area++;
    }
    else
    {
        pArea       =   area_free;
        area_free   =   area_free->next;
    }
    memset(pArea, 0, sizeof(*pArea ));

    pArea->next             =   NULL;
    pArea->name             =   str_dup( "New area" );
    pArea->pCabal	    = NULL;
    pArea->towers	    = NULL;
    pArea->exits	    = NULL;
    pArea->raid		    = NULL;
    pArea->last_raid	    = 0;
    pArea->area_flags       =   0;
    pArea->security         =   1;
    pArea->prefix	    =  str_empty;
    pArea->builders         =   str_dup( "None" );
    pArea->min_vnum            =   0;
    pArea->max_vnum            =   0;
    pArea->age              =   0;
    pArea->bastion_max      =   0;
    pArea->bastion_current  =   0;
    for (count = 0; count < MAX_CRIME; count++) {
      pArea->crimes[count] = 0;
    }
    pArea->idle             =   0;
    pArea->nplayer          =   0;
    pArea->empty            =   TRUE;       
    sprintf( buf, "area%d.are", pArea->vnum );
    pArea->file_name        =   str_dup( buf );
    pArea->vnum             =   top_area-1;
    pArea->credits 	    = str_dup( "{ All }" );
    return pArea;
}

void free_area( AREA_DATA *pArea )
{
    free_string( pArea->name );
    free_string( pArea->file_name );
    free_string( pArea->builders );
    free_string( pArea->credits );
    pArea->next         =   area_free->next;
    area_free           =   pArea;
    return;
}

EXIT_DATA *new_exit( void )
{
    EXIT_DATA *pExit;
    if ( !exit_free )
    {
        pExit           =   alloc_perm( sizeof(*pExit) );
        top_exit++;
    }
    else
    {
        pExit           =   exit_free;
        exit_free       =   exit_free->next;
    }
    pExit->to_room   =   NULL;                
    pExit->vnum	=   0;                
    pExit->next         =   NULL;
    pExit->next_in_area =   NULL;
    pExit->traps	=   NULL;
    pExit->exit_info    =   0;
    pExit->key          =   0;
    pExit->orig_door	=   0;
    pExit->keyword      =   &str_empty[0];
    pExit->description  =   &str_empty[0];
    pExit->rs_flags     =   0;
    return pExit;
}

void free_exit( EXIT_DATA *pExit )
{
    free_string( pExit->keyword );
    free_string( pExit->description );
    pExit->next         =   exit_free;
    exit_free           =   pExit;
    return;
}

ROOM_INDEX_DATA *new_room_index( void )
{
    ROOM_INDEX_DATA *pRoom;
    int door;
    if ( !room_index_free )
    {
        pRoom           =   alloc_perm( sizeof(*pRoom) );
        top_room++;
    }
    else
    {
        pRoom           =   room_index_free;
        room_index_free =   room_index_free->next;
    }

    pRoom->next             =   NULL;
    pRoom->area             =   NULL;
    pRoom->vnum             =   0;
    pRoom->pCabal           =   NULL;

    pRoom->people           =   NULL;
    pRoom->contents         =   NULL;

    pRoom->name             =   &str_empty[0];
    pRoom->description      =   &str_empty[0];
    pRoom->description2     =   &str_empty[0];
    pRoom->extra_descr      =   NULL;
    pRoom->watch_vnums =	NULL;
    pRoom->rprogs	    =	NULL;

    pRoom->room_flags       =   0;
    pRoom->room_flags2      =   0;
    pRoom->sector_type      =   0;

    pRoom->light            =   0;
    pRoom->heal_rate	    =   100;
    pRoom->mana_rate	    =   100;
    pRoom->temp             =   72;

    for ( door=0; door < MAX_DIR; door++ )
        pRoom->exit[door]   =   NULL;

    memset(&pRoom->room_armies, 0, sizeof( ARMY_ROOM_DATA ));

    return pRoom;
}

void free_room_index( ROOM_INDEX_DATA *pRoom )
{
    int door;
    EXTRA_DESCR_DATA *pExtra;
    RESET_DATA *pReset;

    if (pRoom == NULL)
      return;
/* in order to free this we have to check if its a string in shared space,
or perm-allocated
*/
    if (pRoom->name > string_space && pRoom->name < top_string ){
      free_string( pRoom->name );
    }
    if (pRoom->description > string_space && pRoom->description < top_string ){
      free_string( pRoom->description );
    }
    if (pRoom->description2 > string_space && pRoom->description2 < top_string ){
    free_string( pRoom->description2 );
    }

    while (pRoom->rprogs ){
      PROG_LIST* pr = pRoom->rprogs;
      pRoom->rprogs = pr->next;
      free_rprog( pr );
    }

    for ( door = 0; door < MAX_DIR; door++ ){
      if ( pRoom->exit[door] )
	free_exit( pRoom->exit[door] );
    }
    while ( (pExtra = pRoom->extra_descr)){
      pRoom->extra_descr = pExtra->next;
      free_extra_descr( pExtra );
    }

    while ( (pReset = pRoom->reset_first)){
      pRoom->reset_first = pReset->next;
      free_reset_data( pReset );
    }

    while ( pRoom->watch_vnums ){
      Double_List * tmp_list = pRoom->watch_vnums;
      pRoom->watch_vnums = tmp_list->next_node;
      free (tmp_list);
    }

    pRoom->next     =   room_index_free;
    room_index_free =   pRoom;
    return;
}

extern AFFECT_DATA *affect_free;
extern AFFECT_DATA *skill_free;

SHOP_DATA *new_shop( void )
{
    SHOP_DATA *pShop;
    int buy;
    if ( !shop_free )
    {
        pShop           =   alloc_perm( sizeof(*pShop) );
        top_shop++;
    }
    else
    {
        pShop           =   shop_free;
        shop_free       =   shop_free->next;
    }
    if ( shop_first == NULL )
        shop_first = pShop;
    if ( shop_last  != NULL )
        shop_last->next = pShop;
    shop_last       = pShop;
    pShop->next         =   NULL;
    pShop->keeper       =   0;
    for ( buy=0; buy<MAX_TRADE; buy++ )
        pShop->buy_type[buy]    =   0;
    pShop->profit_buy   =   100;
    pShop->profit_sell  =   100;
    pShop->open_hour    =   0;
    pShop->close_hour   =   23;
    return pShop;
}

void free_shop( SHOP_DATA *pShop )
{
    pShop->next = shop_free;
    shop_free   = pShop;
    return;
}

OBJ_INDEX_DATA *new_obj_index( void )
{
    OBJ_INDEX_DATA *pObj;
    int value;
    if ( !obj_index_free )
    {
        pObj           =   alloc_perm( sizeof(*pObj) );
        top_obj_index++;
    }
    else
    {
        pObj            =   obj_index_free;
        obj_index_free  =   obj_index_free->next;
    }
    pObj->next          =   NULL;
    pObj->extra_descr   =   NULL;
    pObj->affected      =   NULL;
    pObj->area          =   NULL;
    pObj->name          =   str_dup( "no name" );
    pObj->short_descr   =   str_dup( "(no short description)" );
    pObj->description   =   str_dup( "(no description)" );
    pObj->vnum          =   0;
    pObj->item_type     =   ITEM_TRASH;
    pObj->extra_flags   =   0;
    pObj->wear_flags    =   0;
    pObj->count         =   0;
    pObj->class         =   -1;
    pObj->race          =    0;
    pObj->weight        =   0;
    pObj->cost          =   0;
    pObj->material      =   str_dup( "unknown" );      
    pObj->condition     =   100;                        
    for ( value = 0; value < 5; value++ )            
        pObj->value[value]  =   0;
    pObj->new_format    = TRUE;
    return pObj;
}

void free_obj_index( OBJ_INDEX_DATA *pObj )
{
    EXTRA_DESCR_DATA *pExtra;
    AFFECT_DATA *pAf;
    OBJ_SPELL_DATA *os, *os_next;
    int num_times = 0;

    for (os = pObj->spell; os != NULL; os = os_next)
    {
        os_next = os->next;
        free_string(os->message);
        free_string(os->message2);

/* break out of loop if stupid number of times through */
	if (num_times++ > STUPID_NUMBER_OF_SPELLS) {
	  break;
	}
    }
    if (pObj->message)
    {
        free_string(pObj->message->onself);
        free_string(pObj->message->onother);
        free_string(pObj->message->offself);
        free_string(pObj->message->offother);
    }
    free_string( pObj->name );
    free_string( pObj->short_descr );
    free_string( pObj->description );
    free_oprog( pObj->oprogs );
    free_string( pObj->material );
    for ( pAf = pObj->affected; pAf; pAf = pAf->next )
        free_affect( pAf );
    for ( pExtra = pObj->extra_descr; pExtra; pExtra = pExtra->next )
        free_extra_descr( pExtra );
    pObj->next              = obj_index_free;
    obj_index_free          = pObj;
    return;
}

MOB_INDEX_DATA *new_mob_index( void )
{
    MOB_INDEX_DATA *pMob;
    if ( !mob_index_free )
    {
        pMob           =   alloc_perm( sizeof(*pMob) );
        top_mob_index++;
    }
    else
    {
        pMob            =   mob_index_free;
        mob_index_free  =   mob_index_free->next;
    }
    pMob->next          =   NULL;
    pMob->spec_fun      =   NULL;
    pMob->pShop         =   NULL;
    pMob->area          =   NULL;
    pMob->player_name   =   str_dup( "no name" );
    pMob->short_descr   =   str_dup( "(no short description)" );
    pMob->long_descr    =   str_dup( "(no long description)\n\r" );
    pMob->description   =   &str_empty[0];
    pMob->vnum          =   0;
    pMob->count         =   0;
    pMob->killed        =   0;
    pMob->sex           =   0;
    pMob->pCabal        =   NULL;
    pMob->level         =   0;
    pMob->act           =   ACT_IS_NPC;
    pMob->act2          =   0;
    pMob->affected_by   =   0;
    pMob->alignment     =   0;
    pMob->hitroll	=   0;
    pMob->race          =   race_lookup( "human" ); 
    pMob->form          =   0;           
    pMob->parts         =   0;           
    pMob->imm_flags     =   0;           
    pMob->res_flags     =   0;           
    pMob->vuln_flags    =   0;           
    pMob->off_flags     =   0;           
    pMob->size          =   SIZE_MEDIUM; 
    pMob->ac[AC_PIERCE] =   0;           
    pMob->ac[AC_BASH]   =   0;           
    pMob->ac[AC_SLASH]  =   0;           
    pMob->ac[AC_EXOTIC] =   0;           
    pMob->hit[DICE_NUMBER]      =   0;   
    pMob->hit[DICE_TYPE]        =   0;   
    pMob->hit[DICE_BONUS]       =   0;   
    pMob->mana[DICE_NUMBER]     =   0;   
    pMob->mana[DICE_TYPE]       =   0;   
    pMob->mana[DICE_BONUS]      =   0;   
    pMob->damage[DICE_NUMBER]   =   0;   
    pMob->damage[DICE_TYPE]     =   0;   
    pMob->damage[DICE_NUMBER]   =   0;   
    pMob->start_pos             =   POS_STANDING; 
    pMob->default_pos           =   POS_STANDING; 
    pMob->gold                  =   0;
    pMob->new_format            = TRUE;  
    return pMob;
}

void free_mob_index( MOB_INDEX_DATA *pMob )
{
    TRIGFILE_DATA *tf, *tf_next;
    MPROG_DATA *mp, *mp_next;
    for (tf = pMob->trigfile; tf != NULL; tf = tf_next)
    {
        tf_next = tf->next;
	free_string(tf->name);
    }
    for (mp = pMob->mobprogs; mp != NULL; mp = mp_next)
    {
        mp_next = mp->next;
        free_string(mp->arglist);
        free_string(mp->comlist);
    }
    free_string( pMob->player_name );
    free_string( pMob->short_descr );
    free_string( pMob->long_descr );
    free_string( pMob->description );
    free_shop( pMob->pShop );
    pMob->next              = mob_index_free;
    mob_index_free          = pMob;
    return;
}

/* Clears string and puts player into editing mode. */
void string_edit( CHAR_DATA *ch, char **pString )
{
    send_to_char( "-========- Entering EDIT Mode -=========-\n\r", ch );
    send_to_char( "    Type .h on a new line for help\n\r", ch );
    send_to_char( " Terminate with a ~ or @ on a blank line.\n\r", ch );
    send_to_char( "-=======================================-\n\r", ch );
    if ( *pString == NULL )
        *pString = str_dup( "" );
    else
        **pString = '\0';
    ch->desc->pString = pString;
    return;
}

/* Puts player into append mode for given string. *
 * Called by (many)olc_act.c                      */
void string_append( CHAR_DATA *ch, char **pString )
{
    send_to_char( "-=======- Entering APPEND Mode -========-\n\r", ch );
    send_to_char( "    Type .h on a new line for help\n\r", ch );
    send_to_char( " Terminate with a ~ or @ on a blank line.\n\r", ch );
    send_to_char( "-=======================================-\n\r", ch );
    if ( *pString == NULL )
        *pString = str_dup( "" );
    send_to_char( *pString, ch );
    if ( *(*pString + strlen( *pString ) - 1) != '\r' )
    send_to_char( "\n\r", ch );
    ch->desc->pString = pString;
    return;
}

/* Substitutes one string for another.                      *
 * Called by string_add(string.c) (aedit_builder)olc_act.c. */
char * string_replace( char * orig, char * old, char * new )
{
    char xbuf[MSL];
    int i;
    xbuf[0] = '\0';
    strcpy( xbuf, orig );
    if ( strstr( orig, old ) != NULL )
    {
        i = strlen( orig ) - strlen( strstr( orig, old ) );
        xbuf[i] = '\0';
        strcat( xbuf, new );
        strcat( xbuf, &orig[i+strlen( old )] );
        free_string( orig );
    }
    return str_dup( xbuf );
}

/* Interpreter for string editing.   *
 * Called by game_loop_xxxx(comm.c). */
void string_add( CHAR_DATA *ch, char *argument )
{
    char buf[MSL];
    smash_tilde( argument );
    if ( *argument == '.' )
    {
        char arg1 [MIL];
        char arg2 [MIL];
        char arg3 [MIL];
        argument = one_argument( argument, arg1 );
        argument = first_arg( argument, arg2, FALSE );
        argument = first_arg( argument, arg3, FALSE );
        if ( !str_cmp( arg1, ".c" ) )
        {
            send_to_char( "String cleared.\n\r", ch );
	    free_string( *ch->desc->pString );
	    *ch->desc->pString = str_dup( "" );
            return;
        }
        if ( !str_cmp( arg1, ".s" ) )
        {
            send_to_char( "String so far:\n\r", ch );
            send_to_char( *ch->desc->pString, ch );
            return;
        }
        if ( !str_cmp( arg1, ".r" ) )
        {
            if ( arg2[0] == '\0' )
            {
                send_to_char(
                    "usage:  .r \"old string\" \"new string\"\n\r", ch );
                return;
            }
            smash_tilde( arg3 );
            *ch->desc->pString = string_replace( *ch->desc->pString, arg2, arg3 );
            sprintf( buf, "'%s' replaced with '%s'.\n\r", arg2, arg3 );
            send_to_char( buf, ch );
            return;
        }
        if ( !str_cmp( arg1, ".f" ) )
        {
            *ch->desc->pString = format_string( *ch->desc->pString );
            send_to_char( "String formatted.\n\r", ch );
            return;
        }
        if ( !str_cmp( arg1, ".h" ) )
        {
            send_to_char( "Sedit help (commands on blank line):   \n\r", ch );
            send_to_char( ".r 'old' 'new'   - replace a substring \n\r", ch );
            send_to_char( "                   (requires '', \"\") \n\r", ch );
            send_to_char( ".h               - get help (this info)\n\r", ch );
            send_to_char( ".s               - show string so far  \n\r", ch );
            send_to_char( ".f               - (word wrap) string  \n\r", ch );
            send_to_char( ".c               - clear string so far \n\r", ch );
            send_to_char( "@                - end string          \n\r", ch );
            return;
        }
        send_to_char( "SEdit:  Invalid dot command.\n\r", ch );
        return;
    }
    if ( *argument == '~' || *argument == '@' )
    {
      if ( ch->desc->editor == ED_MPCODE ) /* for the mobprogs */
	{
	  MOB_INDEX_DATA *mob;
	  int hash;
	  PROG_LIST *mpl;
	  PROG_CODE *mpc;
	  
	  EDIT_MPCODE(ch, mpc);
	  
	  if ( mpc != NULL )
	    for ( hash = 0; hash < MAX_KEY_HASH; hash++ )
	      for ( mob = mob_index_hash[hash]; mob; mob = mob->next )
		for ( mpl = mob->mprogs; mpl; mpl = mpl->next )
		  if ( mpl->vnum == mpc->vnum )
		    {
		      sprintf( buf, "Fixing mob %d.\n\r", mob->vnum );
		      send_to_char( buf, ch );
		      mpl->code = mpc->code;
		    }
	}
      if ( ch->desc->editor == ED_OPCODE ) /* for the objprogs */
	{
	  OBJ_INDEX_DATA *obj;
	  int hash;
	  PROG_LIST *opl;
	  PROG_CODE *opc;
	  
	  EDIT_OPCODE(ch, opc);
	  
	  if ( opc != NULL )
	    for ( hash = 0; hash < MAX_KEY_HASH; hash++ )
	      for ( obj = obj_index_hash[hash]; obj; obj = obj->next )
		for ( opl = obj->oprogs; opl; opl = opl->next )
		  if ( opl->vnum == opc->vnum )
		    {
		      sprintf( buf, "Fixing object %d.\n\r", obj->vnum );
		      send_to_char( buf, ch );
		      opl->code = opc->code;
		    }
	}
      
      if ( ch->desc->editor == ED_RPCODE ) /* for the roomprogs */
	{
	  ROOM_INDEX_DATA *room;
	  int hash;
	  PROG_LIST *rpl;
	  PROG_CODE *rpc;
	  
	  EDIT_RPCODE(ch, rpc);
	  
	  if ( rpc != NULL )
	    for ( hash = 0; hash < MAX_KEY_HASH; hash++ )
	      for ( room = room_index_hash[hash]; room; room = room->next )
		for ( rpl = room->rprogs; rpl; rpl = rpl->next )
		  if ( rpl->vnum == rpc->vnum )
		    {
		      sprintf( buf, "Fixing room %d.\n\r", room->vnum );
		      send_to_char( buf, ch );
		      rpl->code = rpc->code;
		    }
	}
      
      
      ch->desc->pString = NULL;
      return;
    }
    strcpy( buf, *ch->desc->pString );
    if ( strlen( buf ) + strlen( argument ) >= ( MSL - 4 ) )
      {
        send_to_char( "String too long, last line skipped.\n\r", ch );
        ch->desc->pString = NULL;
        return;
      }
    smash_tilde( argument );
    strcat( buf, argument );
    strcat( buf, "\n\r" );
    free_string( *ch->desc->pString );
    *ch->desc->pString = str_dup( buf );
    return;
}

/* Special string formating and word-wrapping.    *
 * Called by string_add(string.c) (many)olc_act.c */
char *format_string( char *oldstring )
{
    char xbuf[MSL];
    char xbuf2[MSL];
    char *rdesc;
    int i=0;
    bool cap=TRUE;
    xbuf[0]=xbuf2[0]=0;
    i=0;

    for (rdesc = oldstring; *rdesc; rdesc++){
    /* New Line */
      if (*rdesc=='\n'){
	/* check for empty seperator lines */
	if (*(rdesc + 1) && *(rdesc + 2) && *(rdesc + 3) 
	    && *(rdesc + 2) == ' ' && *(rdesc + 3) == '\n'){
	  xbuf[i++]= '\n';
	  xbuf[i++]= '\r';
	  xbuf[i++]= '\n';
	  xbuf[i++]= '\r';
	  rdesc += 4;
	}
	else if (xbuf[i-1] != ' '){
	  xbuf[i]=' ';
	  i++;
	}
      }
      /* return */

      else if (*rdesc=='\r'){
	if (xbuf[i-1] != ' '){
	  xbuf[i]=' ';
	  i++;
	}
      }
    /* Space */
      else if (*rdesc==' '){
	if (xbuf[i-1] != ' '){
	  xbuf[i]=' ';
	  i++;
        }
      }
    /* bracket */
      else if (*rdesc==')'){
	if (xbuf[i-1]==' ' && xbuf[i-2]==' ' 
	    && (xbuf[i-3]=='.' || xbuf[i-3]=='?' || xbuf[i-3]=='!')){
	  xbuf[i-2]=*rdesc;
	  xbuf[i-1]=' ';
	  xbuf[i]=' ';
	  i++;
	}
	else{
	  xbuf[i]=*rdesc;
	  i++;
	}
      }
      else if (*rdesc=='.' || *rdesc=='?' || *rdesc=='!'){
	if (xbuf[i-1]==' ' && xbuf[i-2]==' ' 
	    && (xbuf[i-3]=='.' || xbuf[i-3]=='?' || xbuf[i-3]=='!')) {
	  xbuf[i-2]=*rdesc;
	  if (*(rdesc+1) != '\"'){
	    xbuf[i-1]=' ';
	    xbuf[i]=' ';
	    i++;
	  }
	  else{
	    xbuf[i-1]='\"';
	    xbuf[i]=' ';
	    xbuf[i+1]=' ';
	    i+=2;
	    rdesc++;
	  }
        }
        else{
	  xbuf[i]=*rdesc;
	  if (*(rdesc+1) != '\"'){
	    xbuf[i+1]=' ';
	    xbuf[i+2]=' ';
	    i += 3;
	  }
	  else{
	    xbuf[i+1]='\"';
	    xbuf[i+2]=' ';
	    xbuf[i+3]=' ';
	    i += 4;
	    rdesc++;
	  }
        }
        cap = TRUE;
      }
      else{
	xbuf[i]=*rdesc;
	if ( cap ){
	  cap = FALSE;
	  xbuf[i] = UPPER( xbuf[i] );
	}
	i++;
      }
    }
    xbuf[i]=0;
    strcpy(xbuf2,xbuf);
    rdesc=xbuf2;
    xbuf[0]=0;

    for ( ; ; )
    {
      bool fSkip = FALSE;
        for (i=0; i<77; i++)
            if (!*(rdesc+i)) break;

        if (i<77)
            break;

	/* check for already existing returns first */
        for (i=(xbuf[0]?76:73) ; i ; i--){
	  if (*(rdesc+i)=='\r'){
            *(rdesc+i)=0;
            strcat(xbuf,rdesc);
            strcat(xbuf,"\r");
            rdesc += i+1;
            while (*rdesc == ' ') rdesc++;
	    fSkip = TRUE;
	    break;
	  }
	}
	if (fSkip)
	  continue;

	/* check for spaces now */
        for (i=(xbuf[0]?76:73) ; i ; i--)
            if (*(rdesc+i)==' ')  break;
        if (i)
        {
            *(rdesc+i)=0;
            strcat(xbuf,rdesc);
            strcat(xbuf,"\n\r");
            rdesc += i+1;
            while (*rdesc == ' ') rdesc++;
        }
        else
        {
	  //bug ("No spaces", 0);
            *(rdesc+75)=0;
            strcat(xbuf,rdesc);
            strcat(xbuf,"-\n\r");
            rdesc += 76;
        }
    }

    while (*(rdesc+i) && (*(rdesc+i)==' ' ))
      //			  || *(rdesc+i)=='\n' || *(rdesc+i)=='\r'))
      i--;
    *(rdesc+i+1)=0;
    strcat(xbuf,rdesc);
    if (xbuf[strlen(xbuf)-2] != '\n')
        strcat(xbuf,"\n\r");
    free_string(oldstring);
    return(str_dup(xbuf));
}

/* Used above in string_add.  Because this function does not *
 * modify case if fCase is FALSE and because it understands  *
 * parenthesis, it would probably make a nice replacement    *
 * for one_argument.                                         */
/* Pick off one argument from a string and return the rest.         *
 * Understands quates, parenthesis (barring ) ('s) and percentages. *
 * Called by string_add(string.c)                                   */
char *first_arg( char *argument, char *arg_first, bool fCase )
{
    char cEnd;
    while ( *argument == ' ' )
	argument++;
    cEnd = ' ';
    if ( *argument == '\'' || *argument == '"' || *argument == '%'  || *argument == '(' )
    {
        if ( *argument == '(' )
        {
            cEnd = ')';
            argument++;
        }
        else cEnd = *argument++;
    }
    while ( *argument != '\0' )
    {
	if ( *argument == cEnd )
	{
	    argument++;
	    break;
	}
        if ( fCase )
            *arg_first = LOWER(*argument);
        else
            *arg_first = *argument;
	arg_first++;
	argument++;
    }
    *arg_first = '\0';
    while ( *argument == ' ' )
	argument++;
    return argument;
}

/* Used in olc_act.c for aedit_builders. */
char * string_unpad( char * argument )
{
    char buf[MSL];
    char *s;
    s = argument;
    while ( *s == ' ' )
        s++;
    strcpy( buf, s );
    s = buf;
    if ( *s != '\0' )
    {
        while ( *s != '\0' )
            s++;
        s--;
        while( *s == ' ' )
            s--;
        s++;
        *s = '\0';
    }
    free_string( argument );
    return str_dup( buf );
}

/* Same as capitalize but changes the pointer's data. *
 * Used in olc_act.c in aedit_builder.                */
char * string_proper( char * argument )
{
    char *s;
    s = argument;
    while ( *s != '\0' )
    {
        if ( *s != ' ' )
        {
            *s = UPPER(*s);
            while ( *s != ' ' && *s != '\0' )
                s++;
        }
        else
            s++;
    }
    return argument;
}


PROG_CODE *new_mpcode(void)
{
     PROG_CODE *NewCode;

     if (!mpcode_free)
     {
         NewCode = alloc_perm(sizeof(*NewCode) );
         top_mprog_index++;
     }
     else
     {
         NewCode     = mpcode_free;
         mpcode_free = mpcode_free->next;
     }

     NewCode->vnum    = 0;
     NewCode->code    = str_dup("");
     NewCode->next    = NULL;

     return NewCode;
}

PROG_CODE *new_opcode(void)
{
     PROG_CODE *NewCode;

     if (!opcode_free)
     {
         NewCode = alloc_perm(sizeof(*NewCode) );
         top_oprog_index++;
     }
     else
     {
         NewCode     = opcode_free;
         opcode_free = opcode_free->next;
     }

     NewCode->vnum    = 0;
     NewCode->code    = str_dup("");
     NewCode->next    = NULL;

     return NewCode;
}

PROG_CODE *new_rpcode(void)
{
     PROG_CODE *NewCode;

     if (!rpcode_free)
     {
         NewCode = alloc_perm(sizeof(*NewCode) );
         top_rprog_index++;
     }
     else
     {
         NewCode     = rpcode_free;
         rpcode_free = rpcode_free->next;
     }

     NewCode->vnum    = 0;
     NewCode->code    = str_dup("");
     NewCode->next    = NULL;

     return NewCode;
}

void free_opcode(PROG_CODE *pOcode)
{
    free_string(pOcode->code);
    pOcode->next = opcode_free;
    opcode_free  = pOcode;
    return;
}

void free_rpcode(PROG_CODE *pRcode)
{
    free_string(pRcode->code);
    pRcode->next = rpcode_free;
    rpcode_free  = pRcode;
    return;
}


void free_mpcode(PROG_CODE *pMcode)
{
    free_string(pMcode->code);
    pMcode->next = mpcode_free;
    mpcode_free  = pMcode;
    return;
}