swrots/.slog/
swrots/doc/mudprogs/
swrots/gods/
swrots/html/profiles/
swrots/log/
swrots/planets/
swrots/player/
swrots/player/u/
#include <math.h>
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"

char * const spell_flag[] =
{ "water", "earth", "air", "astral", "area", "distant", "reverse",
"save_half_dam", "save_negates", "accumulative", "recastable", "noscribe",
"nobrew", "group", "object", "character", "secretskill", "pksensitive" };

char * const spell_saves[] =
{ "none", "poison_death", "wands", "para_petri", "breath", "spell_staff" };

char * const spell_damage[] =
{ "none", "fire", "cold", "electricity", "energy", "acid", "poison", "drain" };

char * const spell_action[] =
{ "none", "create", "destroy", "resist", "suscept", "divinate", "obscure",
"change" };

char * const spell_power[] =
{ "none", "minor", "greater", "major" };

char * const spell_class[] =
{ "none", "lunar", "solar", "travel", "summon", "life", "death", "illusion" };

char * const target_type[] =
{ "ignore", "offensive", "defensive", "self", "objinv"};


void show_char_to_char( CHAR_DATA *list, CHAR_DATA *ch );
void show_list_to_char( OBJ_DATA *list, CHAR_DATA *ch, bool fShort, 
	bool fShowN );

int ris_save( CHAR_DATA *ch, int chance, int ris );
bool check_illegal_psteal( CHAR_DATA *ch, CHAR_DATA *victim );

/* from magic.c */
void failed_casting( struct skill_type *skill, CHAR_DATA *ch,
		     CHAR_DATA *victim, OBJ_DATA *obj );

int     xp_compute      args( ( CHAR_DATA *gch, CHAR_DATA *victim ) );

ROOM_INDEX_DATA *generate_exit( ROOM_INDEX_DATA *in_room, EXIT_DATA **pexit );

/*
 * Dummy function
 */
void skill_notfound( CHAR_DATA *ch, char *argument )
{
    send_to_char( "Huh?\n\r", ch );
    return;
}


int get_ssave( char *name )
{
    int x;

    for ( x = 0; x < sizeof(spell_saves) / sizeof(spell_saves[0]); x++ )
      if ( !str_cmp( name, spell_saves[x] ) )
        return x;
    return -1;
}

int get_starget( char *name )
{
    int x;

    for ( x = 0; x < sizeof(target_type) / sizeof(target_type[0]); x++ )
      if ( !str_cmp( name, target_type[x] ) )
        return x;
    return -1;
}

int get_sflag( char *name )
{
    int x;

    for ( x = 0; x < sizeof(spell_flag) / sizeof(spell_flag[0]); x++ )
      if ( !str_cmp( name, spell_flag[x] ) )
        return x;
    return -1;
}

int get_sdamage( char *name )
{
    int x;

    for ( x = 0; x < sizeof(spell_damage) / sizeof(spell_damage[0]); x++ )
      if ( !str_cmp( name, spell_damage[x] ) )
        return x;
    return -1;
}

int get_saction( char *name )
{
    int x;

    for ( x = 0; x < sizeof(spell_action) / sizeof(spell_action[0]); x++ )
      if ( !str_cmp( name, spell_action[x] ) )
        return x;
    return -1;
}

int get_spower( char *name )
{
    int x;

    for ( x = 0; x < sizeof(spell_power) / sizeof(spell_power[0]); x++ )
      if ( !str_cmp( name, spell_power[x] ) )
        return x;
    return -1;
}

int get_sclass( char *name )
{
    int x;

    for ( x = 0; x < sizeof(spell_class) / sizeof(spell_class[0]); x++ )
      if ( !str_cmp( name, spell_class[x] ) )
        return x;
    return -1;
}

bool is_legal_kill(CHAR_DATA *ch, CHAR_DATA *vch)
{
  if ( IS_NPC(ch) || IS_NPC(vch) )
    return TRUE;
  if ( is_safe(ch,vch) )
    return FALSE;
  return TRUE;
}


extern char *target_name;	/* from magic.c */

/*
 * Perform a binary search on a section of the skill table
 * Each different section of the skill table is sorted alphabetically
 * Only match skills player knows				-Thoric
 */
bool check_skill( CHAR_DATA *ch, char *command, char *argument )
{
    int sn;
    int first = gsn_first_skill;
    int top   = gsn_first_weapon-1;
    struct timeval time_used;
    int mana;
    
    /* bsearch for the skill */
    for (;;)
    {
	sn = (first + top) >> 1;

	if ( LOWER(command[0]) == LOWER(skill_table[sn]->name[0])
	&&  !str_prefix(command, skill_table[sn]->name)
	&&  (skill_table[sn]->skill_fun || skill_table[sn]->spell_fun != spell_null)
	&&  (IS_NPC(ch)
	||  ( ch->pcdata->learned[sn] > 0 )) )
		break;
	if (first >= top)
	    return FALSE;
    	if (strcmp( command, skill_table[sn]->name) < 1)
	    top = sn - 1;
    	else
	    first = sn + 1;
    }

    if ( !check_pos( ch, skill_table[sn]->minimum_position ) )
	return TRUE;

    if ( IS_NPC(ch)
    &&  (IS_AFFECTED( ch, AFF_CHARM ) || IS_AFFECTED( ch, AFF_POSSESS )) )
    {
	send_to_char( "For some reason, you seem unable to perform that...\n\r", ch );
	act( AT_GREY,"$n looks around.", ch, NULL, NULL, TO_ROOM );
	return TRUE;
    }

    /* check if mana is required */
    if ( skill_table[sn]->min_mana )
    {
	mana = IS_NPC(ch) ? 0 : skill_table[sn]->min_mana;

	if ( !IS_NPC(ch) && ch->mana < mana )
	{
	    send_to_char( "You need to rest before using the Force any more.\n\r", ch );
	    return TRUE;
	}
    }
    else
    {
	mana = 0;
    }
    
    /*
     * Is this a real do-fun, or a really a spell?
     */
    if ( !skill_table[sn]->skill_fun )
    {
	ch_ret retcode = rNONE;
	void *vo = NULL;
	CHAR_DATA *victim = NULL;
	OBJ_DATA *obj = NULL;

	target_name = "";

	switch ( skill_table[sn]->target )
	{
	default:
	    bug( "Check_skill: bad target for sn %d.", sn );
	    send_to_char( "Something went wrong...\n\r", ch );
	    return TRUE;

	case TAR_IGNORE:
	    vo = NULL;
	    if ( argument[0] == '\0' )
	    {
		if ( (victim=who_fighting(ch)) != NULL )
		    target_name = victim->name;
	    }
	    else
		target_name = argument;
	    break;

	case TAR_CHAR_OFFENSIVE:
	    if ( argument[0] == '\0'
	    &&  (victim=who_fighting(ch)) == NULL )
	    {
		ch_printf( ch, "%s who?\n\r", capitalize( skill_table[sn]->name ) );
		return TRUE;
	    }
	    else
	    if ( argument[0] != '\0'
	    &&  (victim=get_char_room(ch, argument)) == NULL )
	    {
		send_to_char( "They aren't here.\n\r", ch );
		return TRUE;
	    }
	    if ( is_safe( ch, victim ) )
		return TRUE;
	    vo = (void *) victim;
	    break;

	case TAR_CHAR_DEFENSIVE:
	    if ( argument[0] != '\0'
	    &&  (victim=get_char_room(ch, argument)) == NULL )
	    {
		send_to_char( "They aren't here.\n\r", ch );
		return TRUE;
	    }
	    if ( !victim )
		victim = ch;
	    vo = (void *) victim;
	    break;

	case TAR_CHAR_SELF:
	    vo = (void *) ch;
	    break;

	case TAR_OBJ_INV:
	    if ( (obj=get_obj_carry(ch, argument)) == NULL )
	    {
		send_to_char( "You can't find that.\n\r", ch );
		return TRUE;
	    }
	    vo = (void *) obj;
	    break;
	}

	/* waitstate */
	WAIT_STATE( ch, skill_table[sn]->beats );
	/* check for failure */
	if ( (number_percent( ) + skill_table[sn]->difficulty * 5)
	   > (IS_NPC(ch) ? 75 : ch->pcdata->learned[sn]) )
	{
	    failed_casting( skill_table[sn], ch, vo, obj );
	    learn_from_failure( ch, sn );
	    if ( mana )
	    {
		  ch->mana -= mana/2;
	    }
	    return TRUE;
	}
	if ( mana )
	{
		ch->mana -= mana;
	}
	start_timer(&time_used);
	retcode = (*skill_table[sn]->spell_fun) ( sn, ch->top_level, ch, vo );
	end_timer(&time_used);
	update_userec(&time_used, &skill_table[sn]->userec);
	
	if ( retcode == rCHAR_DIED || retcode == rERROR )
	    return TRUE;

	if ( char_died(ch) )
	    return TRUE;

	if ( retcode == rSPELL_FAILED )
	{
	    learn_from_failure( ch, sn );
	    retcode = rNONE;
	}
	else
	    learn_from_success( ch, sn );

	if ( skill_table[sn]->target == TAR_CHAR_OFFENSIVE
	&&   victim != ch
	&&  !char_died(victim) )
	{
	    CHAR_DATA *vch;
	    CHAR_DATA *vch_next;

	    for ( vch = ch->in_room->first_person; vch; vch = vch_next )
	    {
		vch_next = vch->next_in_room;
		if ( victim == vch && !victim->fighting && victim->master != ch )
		{
		    retcode = multi_hit( victim, ch, TYPE_UNDEFINED );
		    break;
		}
	    }
	}
	return TRUE;
    }

    if ( mana )
    {
	  ch->mana -= mana;
    }
    ch->prev_cmd = ch->last_cmd;    /* haus, for automapping */
    ch->last_cmd = skill_table[sn]->skill_fun;
    start_timer(&time_used);
    (*skill_table[sn]->skill_fun) ( ch, argument );
    end_timer(&time_used);
    update_userec(&time_used, &skill_table[sn]->userec);

    tail_chain( );
    return TRUE;
}

/*
 * Lookup a skills information
 * High god command
 */
void do_slookup( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];
    char arg[MAX_INPUT_LENGTH];
    int sn;
    SKILLTYPE *skill = NULL;

    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Slookup what?\n\r", ch );
	return;
    }

    if ( !str_cmp( arg, "all" ) )
    {
	for ( sn = 0; sn < top_sn && skill_table[sn] && skill_table[sn]->name; sn++ )
	    pager_printf( ch, "Sn: %4d Slot: %4d Skill/spell: '%-20s' Damtype: %s\n\r",
		sn, skill_table[sn]->slot, skill_table[sn]->name,
		spell_damage[SPELL_DAMAGE( skill_table[sn] )] );
    }
    else
    if ( !str_cmp( arg, "herbs" ) )
    {
	for ( sn = 0; sn < top_herb && herb_table[sn] && herb_table[sn]->name; sn++ )
	   pager_printf( ch, "%d) %s\n\r", sn, herb_table[sn]->name );
    }
    else
    {
	SMAUG_AFF *aff;
	int cnt = 0;

	if ( arg[0] == 'h' && is_number(arg+1) )
	{
	    sn = atoi(arg+1);
	    if ( !IS_VALID_HERB(sn) )
	    {
		send_to_char( "Invalid herb.\n\r", ch );
		return;
	    }
	    skill = herb_table[sn];
	}
	else
	if ( is_number(arg) )
	{
	    sn = atoi(arg);
	    if ( (skill=get_skilltype(sn)) == NULL )
	    {
		send_to_char( "Invalid sn.\n\r", ch );
		return;
	    }
	    sn %= 1000;
	}
	else
	if ( ( sn = skill_lookup( arg ) ) >= 0 )
	    skill = skill_table[sn];
	else
	if ( ( sn = herb_lookup( arg ) ) >= 0 )
	    skill = herb_table[sn];
	else
	{
	    send_to_char( "No such skill, spell, proficiency or tongue.\n\r", ch );
	    return;
	}
	if ( !skill )
	{
	    send_to_char( "Not created yet.\n\r", ch );
	    return;
	}

	ch_printf( ch, "Sn: %4d Slot: %4d %s: '%-20s'\n\r",
	    sn, skill->slot, skill_tname[skill->type], skill->name );
	if ( skill->flags )
	{
	    int x;

	    ch_printf( ch, "Damtype: %s  Acttype: %s   Classtype: %s   Powertype: %s\n\r",
		spell_damage[SPELL_DAMAGE( skill )],
		spell_action[SPELL_ACTION( skill )],
		spell_class[SPELL_CLASS( skill )],
		spell_power[SPELL_POWER( skill )] );
	    strcpy( buf, "Flags:" );
	    for ( x = 11; x < 32; x++ )
	      if ( SPELL_FLAG( skill, 1 << x ) )
	      {
		strcat( buf, " " );
		strcat( buf, spell_flag[x-11] );
	      }
	    strcat( buf, "\n\r" );
	    send_to_char( buf, ch );
	}
	ch_printf( ch, "Saves: %s\n\r", spell_saves[(int) skill->saves] );

	if ( skill->difficulty != '\0' )
	    ch_printf( ch, "Difficulty: %d\n\r", (int) skill->difficulty );

	ch_printf( ch, "Type: %s  Target: %s  Minpos: %d  Mana: %d  Beats: %d\n\r",
		skill_tname[skill->type],
		target_type[URANGE(TAR_IGNORE, skill->target, TAR_OBJ_INV)],
		skill->minimum_position,
		skill->min_mana,
		skill->beats );
	ch_printf( ch, "Flags: %d  Guild: %d  Code: %s\n\r",
		skill->flags,
		skill->guild,
		skill->skill_fun ? skill_name(skill->skill_fun)
					   : spell_name(skill->spell_fun));
	ch_printf( ch, "Dammsg: %s\n\rWearoff: %s\n",
		skill->noun_damage,
		skill->msg_off ? skill->msg_off : "(none set)" );
	if ( skill->dice && skill->dice[0] != '\0' )
	    ch_printf( ch, "Dice: %s\n\r", skill->dice );
	if ( skill->teachers && skill->teachers[0] != '\0' )
	    ch_printf( ch, "Teachers: %s\n\r", skill->teachers );
	if ( skill->components && skill->components[0] != '\0' )
	    ch_printf( ch, "Components: %s\n\r", skill->components );
	if ( skill->participants )
	    ch_printf( ch, "Participants: %d\n\r", (int) skill->participants );
	if ( skill->userec.num_uses )
	    send_timer(&skill->userec, ch);
	for ( aff = skill->affects; aff; aff = aff->next )
	{
	    if ( aff == skill->affects )
	      send_to_char( "\n\r", ch );
	    sprintf( buf, "Affect %d", ++cnt );
	    if ( aff->location )
	    {
		strcat( buf, " modifies " );
		strcat( buf, a_types[aff->location % REVERSE_APPLY] );
		strcat( buf, " by '" );
		strcat( buf, aff->modifier );
		if ( aff->bitvector )
		  strcat( buf, "' and" );
		else
		  strcat( buf, "'" );
	    }
	    if ( aff->bitvector )
	    {
		int x;

		strcat( buf, " applies" );
		for ( x = 0; x < 32; x++ )
		  if ( IS_SET(aff->bitvector, 1 << x) )
		  {
		      strcat( buf, " " );
		      strcat( buf, a_flags[x] );
		  }
	    }
	    if ( aff->duration[0] != '\0' && aff->duration[0] != '0' )
	    {
		strcat( buf, " for '" );
		strcat( buf, aff->duration );
		strcat( buf, "' rounds" );
	    }
	    if ( aff->location >= REVERSE_APPLY )
		strcat( buf, " (affects caster only)" );
	    strcat( buf, "\n\r" );
	    send_to_char( buf, ch );
	    if ( !aff->next )
	      send_to_char( "\n\r", ch );
	}
	if ( skill->hit_char && skill->hit_char[0] != '\0' )
	    ch_printf( ch, "Hitchar   : %s\n\r", skill->hit_char );
	if ( skill->hit_vict && skill->hit_vict[0] != '\0' )
	    ch_printf( ch, "Hitvict   : %s\n\r", skill->hit_vict );
	if ( skill->hit_room && skill->hit_room[0] != '\0' )
	    ch_printf( ch, "Hitroom   : %s\n\r", skill->hit_room );
	if ( skill->miss_char && skill->miss_char[0] != '\0' )
	    ch_printf( ch, "Misschar  : %s\n\r", skill->miss_char );
	if ( skill->miss_vict && skill->miss_vict[0] != '\0' )
	    ch_printf( ch, "Missvict  : %s\n\r", skill->miss_vict );
	if ( skill->miss_room && skill->miss_room[0] != '\0' )
	    ch_printf( ch, "Missroom  : %s\n\r", skill->miss_room );
	if ( skill->die_char && skill->die_char[0] != '\0' )
	    ch_printf( ch, "Diechar   : %s\n\r", skill->die_char );
	if ( skill->die_vict && skill->die_vict[0] != '\0' )
	    ch_printf( ch, "Dievict   : %s\n\r", skill->die_vict );
	if ( skill->die_room && skill->die_room[0] != '\0' )
	    ch_printf( ch, "Dieroom   : %s\n\r", skill->die_room );
	if ( skill->imm_char && skill->imm_char[0] != '\0' )
	    ch_printf( ch, "Immchar   : %s\n\r", skill->imm_char );
	if ( skill->imm_vict && skill->imm_vict[0] != '\0' )
	    ch_printf( ch, "Immvict   : %s\n\r", skill->imm_vict );
	if ( skill->imm_room && skill->imm_room[0] != '\0' )
	    ch_printf( ch, "Immroom   : %s\n\r", skill->imm_room );
	if ( skill->type != SKILL_HERB && skill->guild >= 0 && skill->guild < MAX_ABILITY)
	{
		sprintf(buf, "guild: %s   Align: %4d   lvl: %3d\n\r",
				ability_name[skill->guild], skill->alignment,    skill->min_level );
            send_to_char( buf, ch );
	}
	send_to_char( "\n\r", ch );
    }

    return;
}


/*
 * Set a skill's attributes or what skills a player has.
 * High god command, with support for creating skills/spells/herbs/etc
 */
void do_sset( CHAR_DATA *ch, char *argument )
{
    char arg1 [MAX_INPUT_LENGTH];
    char arg2 [MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];
    CHAR_DATA *victim;
    int value;
    int sn;
    bool fAll;

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

    if ( arg1[0] == '\0' || arg2[0] == '\0' || (argument[0] == '\0' && strcmp(arg2,"delete")))   
    {
	send_to_char( "Syntax: sset <victim> <skill> <value>\n\r",	ch );
	send_to_char( "or:     sset <victim> all     <value>\n\r",	ch );
	if ( get_trust(ch) > LEVEL_SUB_IMPLEM )
	{
	  send_to_char( "or:     sset save skill table\n\r",		ch );
	  send_to_char( "or:     sset save herb table\n\r",		ch );
	  send_to_char( "or:     sset create skill 'new skill'\n\r",	ch );
	  send_to_char( "or:     sset create herb 'new herb'\n\r",	ch );
	}
	if ( get_trust(ch) > LEVEL_GREATER )
	{
	  send_to_char( "or:     sset <sn>     <field> <value>\n\r",	ch );
	  send_to_char( "\n\rField being one of:\n\r",			ch );
	  send_to_char( "  name code target minpos slot mana beats dammsg wearoff guild minlevel\n\r", ch );
	  send_to_char( "  type damtype acttype classtype powertype flag dice value difficulty affect\n\r", ch );
	  send_to_char( "  rmaffect level adept hit miss die imm (char/vict/room)\n\r", ch );
	  send_to_char( "  components teachers\n\r",			ch );
	  send_to_char( "Affect having the fields: <location> <modfifier> [duration] [bitvector]\n\r", ch );
	  send_to_char( "(See AFFECTTYPES for location, and AFFECTED_BY for bitvector)\n\r", ch );
	}
	send_to_char( "Skill being any skill or spell.\n\r",		ch );
	return;
    }

    if ( get_trust(ch) > LEVEL_SUB_IMPLEM
    &&  !str_cmp( arg1, "save" )
    &&	!str_cmp( argument, "table" ) )
    {
	if ( !str_cmp( arg2, "skill" ) )
	{
	    send_to_char( "Saving skill table...\n\r", ch );
	    save_skill_table(-1);
	    return;
	}
	if ( !str_cmp( arg2, "herb" ) )
	{
	    send_to_char( "Saving herb table...\n\r", ch );
	    save_herb_table();
	    return;
	}
    }
    if ( get_trust(ch) > LEVEL_SUB_IMPLEM
    &&  !str_cmp( arg1, "create" )
    && (!str_cmp( arg2, "skill" ) || !str_cmp( arg2, "herb" )) )
    {
	struct skill_type *skill;
	sh_int type = SKILL_UNKNOWN;

	if ( !str_cmp( arg2, "herb" ) )
	{
	    type = SKILL_HERB;
	    if ( top_herb >= MAX_HERB )
	    {
		ch_printf( ch, "The current top herb is %d, which is the maximum.  "
			   "To add more herbs,\n\rMAX_HERB will have to be "
			   "raised in mud.h, and the mud recompiled.\n\r",
			   top_sn );
		return;
	    }
	}
	else
	if ( top_sn >= MAX_SKILL )
	{
	    ch_printf( ch, "The current top sn is %d, which is the maximum.  "
			   "To add more skills,\n\rMAX_SKILL will have to be "
			   "raised in mud.h, and the mud recompiled.\n\r",
			   top_sn );
	    return;
	}
	CREATE( skill, struct skill_type, 1 );
	if ( type == SKILL_HERB )
	{
	    int max, x;

	    herb_table[top_herb++] = skill;
	    for ( max = x = 0; x < top_herb-1; x++ )
		if ( herb_table[x] && herb_table[x]->slot > max )
		    max = herb_table[x]->slot;
	    skill->slot = max+1;
	}
	else
	    skill_table[top_sn++] = skill;
	skill->name = str_dup( argument );
	skill->noun_damage = str_dup( "" );
	skill->msg_off = str_dup( "" );
	skill->spell_fun = spell_smaug;
	skill->type = type;
	send_to_char( "Done.\n\r", ch );
	return;
    }

    if ( arg1[0] == 'h' )
	sn = atoi( arg1+1 );
    else
	sn = atoi( arg1 );
    if ( get_trust(ch) > LEVEL_GREATER
    && ((arg1[0] == 'h' && is_number(arg1+1) && (sn=atoi(arg1+1))>=0)
    ||  (is_number(arg1) && (sn=atoi(arg1)) >= 0)) )
    {
	struct skill_type *skill;

	if ( arg1[0] == 'h' )
	{
	    if ( sn >= top_herb )
	    {
		send_to_char( "Herb number out of range.\n\r", ch );
		return;
	    }
	    skill = herb_table[sn];
	}
	else
	{
	    if ( (skill=get_skilltype(sn)) == NULL )
	    {
		send_to_char( "Skill number out of range.\n\r", ch );
		return;
	    }
	    sn %= 1000;
	}

	if ( !str_cmp( arg2, "difficulty" ) )
	{
	    skill->difficulty = atoi( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "participants" ) )
	{
	    skill->participants = atoi( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "alignment" ) )
	{
	    skill->alignment = atoi( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "damtype" ) )
	{
	    int x = get_sdamage( argument );

	    if ( x == -1 )
		send_to_char( "Not a spell damage type.\n\r", ch );
	    else
	    {
		SET_SDAM( skill, x );
		send_to_char( "Ok.\n\r", ch );
	    }
	    return;
	}
	if ( !str_cmp( arg2, "acttype" ) )
	{
	    int x = get_saction( argument );

	    if ( x == -1 )
		send_to_char( "Not a spell action type.\n\r", ch );
	    else
	    {
		SET_SACT( skill, x );
		send_to_char( "Ok.\n\r", ch );
	    }
	    return;
	}
	if ( !str_cmp( arg2, "classtype" ) )
	{
	    int x = get_sclass( argument );

	    if ( x == -1 )
		send_to_char( "Not a spell class type.\n\r", ch );
	    else
	    {
		SET_SCLA( skill, x );
		send_to_char( "Ok.\n\r", ch );
	    }
	    return;
	}
	if ( !str_cmp( arg2, "powertype" ) )
	{
	    int x = get_spower( argument );

	    if ( x == -1 )
		send_to_char( "Not a spell power type.\n\r", ch );
	    else
	    {
		SET_SPOW( skill, x );
		send_to_char( "Ok.\n\r", ch );
	    }
	    return;
	}
	if ( !str_cmp( arg2, "flag" ) )
	{
	    int x = get_sflag( argument );

	    if ( x == -1 )
		send_to_char( "Not a spell flag.\n\r", ch );
	    else
	    {
		TOGGLE_BIT( skill->flags, 1 << (x+11) );
		send_to_char( "Ok.\n\r", ch );
	    }
	    return;
	}
	if ( !str_cmp( arg2, "saves" ) )
	{
	    int x = get_ssave( argument );

	    if ( x == -1 )
		send_to_char( "Not a saving type.\n\r", ch );
	    else
	    {
		skill->saves = x;
		send_to_char( "Ok.\n\r", ch );
	    }
	    return;
	}

	if ( !str_cmp( arg2, "code" ) )
	{
	    SPELL_FUN *spellfun;
	    DO_FUN    *dofun;
		
	    if ( (spellfun=spell_function(argument)) != spell_notfound )
	    {
		skill->spell_fun = spellfun;
		skill->skill_fun = NULL;
	    }
	    else
	    if ( (dofun=skill_function(argument)) != skill_notfound )
	    {
		skill->skill_fun = dofun;
		skill->spell_fun = NULL;
	    }
	    else
	    {
		send_to_char( "Not a spell or skill.\n\r", ch );
		return;
	    }
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}

	if ( !str_cmp( arg2, "target" ) )
	{
	    int x = get_starget( argument );

	    if ( x == -1 )
		send_to_char( "Not a valid target type.\n\r", ch );
	    else
	    {
		skill->target = x;
		send_to_char( "Ok.\n\r", ch );
	    }
	    return;
	}
	if ( !str_cmp( arg2, "minpos" ) )
	{
	    skill->minimum_position = URANGE( POS_DEAD, atoi( argument ), POS_DRAG );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "minlevel" ) )
	{
	    skill->min_level = URANGE( 1, atoi( argument ), MAX_LEVEL );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "slot" ) )
	{
	    skill->slot = URANGE( 0, atoi( argument ), 30000 );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "mana" ) )
	{
	    skill->min_mana = URANGE( 0, atoi( argument ), 2000 );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "beats" ) )
	{
	    skill->beats = URANGE( 0, atoi( argument ), 120 );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "guild" ) )
	{
	    skill->guild = atoi( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "value" ) )
	{
	    skill->value = atoi( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "type" ) )
	{
	    skill->type = get_skill( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "rmaffect" ) )
	{
	    SMAUG_AFF *aff = skill->affects;
	    SMAUG_AFF *aff_next;
	    int num = atoi( argument );
	    int cnt = 1;

	    if ( !aff )
	    {
		send_to_char( "This spell has no special affects to remove.\n\r", ch );
		return;
	    }
	    if ( num == 1 )
	    {
		skill->affects = aff->next;
		DISPOSE( aff->duration );
		DISPOSE( aff->modifier );
		DISPOSE( aff );
		send_to_char( "Removed.\n\r", ch );
		return;
	    }
	    for ( ; aff; aff = aff->next )
	    {
		if ( ++cnt == num && (aff_next=aff->next) != NULL )
		{
		    aff->next = aff_next->next;
		    DISPOSE( aff_next->duration );
		    DISPOSE( aff_next->modifier );
		    DISPOSE( aff_next );
		    send_to_char( "Removed.\n\r", ch );
		    return;
		}
	    }
	    send_to_char( "Not found.\n\r", ch );
	    return;
	}
	/*
	 * affect <location> <modifier> <duration> <bitvector>
	 */
	if ( !str_cmp( arg2, "affect" ) )
	{
	    char location[MAX_INPUT_LENGTH];
	    char modifier[MAX_INPUT_LENGTH];
	    char duration[MAX_INPUT_LENGTH];
	    char bitvector[MAX_INPUT_LENGTH];
	    int loc, bit, tmpbit;
	    SMAUG_AFF *aff;

	    argument = one_argument( argument, location );
	    argument = one_argument( argument, modifier );
	    argument = one_argument( argument, duration );
	    
	    if ( location[0] == '!' )
		loc = get_atype( location+1 ) + REVERSE_APPLY;
	    else
		loc = get_atype( location );
	    if ( (loc % REVERSE_APPLY) < 0
	    ||   (loc % REVERSE_APPLY) >= MAX_APPLY_TYPE )
	    {
		send_to_char( "Unknown affect location.  See AFFECTTYPES.\n\r", ch );
		return;
	    }
	    bit = 0;
	    while ( argument[0] != 0 )
	    {
		argument = one_argument( argument, bitvector );
		if ( (tmpbit=get_aflag( bitvector )) == -1 )
		  ch_printf( ch, "Unknown bitvector: %s.  See AFFECTED_BY\n\r", bitvector );
		else
		  bit |= (1 << tmpbit);
	    }
	    CREATE( aff, SMAUG_AFF, 1 );
	    if ( !str_cmp( duration, "0" ) )
	      duration[0] = '\0';
	    if ( !str_cmp( modifier, "0" ) )
	      modifier[0] = '\0';
	    aff->duration = str_dup( duration );
	    aff->location = loc;
	    aff->modifier = str_dup( modifier );
	    aff->bitvector = bit;
	    aff->next = skill->affects;
	    skill->affects = aff;
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "level" ) )
	{
	    skill->min_level = URANGE( 1, atoi( argument ), 100 );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "adept" ) )
	{
	    return;
	}
	if ( !str_cmp( arg2, "name" ) )
	{
	    DISPOSE(skill->name);
	    skill->name = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "dammsg" ) )
	{
	    DISPOSE(skill->noun_damage);
	    if ( !str_cmp( argument, "clear" ) )
	      skill->noun_damage = str_dup( "" );
	    else
	      skill->noun_damage = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "wearoff" ) )
	{
	    DISPOSE(skill->msg_off);
	    if ( str_cmp( argument, "clear" ) )
	      skill->msg_off = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "hitchar" ) )
	{
	    if ( skill->hit_char )
	      DISPOSE(skill->hit_char);
	    if ( str_cmp( argument, "clear" ) )
	      skill->hit_char = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "hitvict" ) )
	{
	    if ( skill->hit_vict )
	      DISPOSE(skill->hit_vict);
	    if ( str_cmp( argument, "clear" ) )
	      skill->hit_vict = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "hitroom" ) )
	{
	    if ( skill->hit_room )
	      DISPOSE(skill->hit_room);
	    if ( str_cmp( argument, "clear" ) )
	      skill->hit_room = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "misschar" ) )
	{
	    if ( skill->miss_char )
	      DISPOSE(skill->miss_char);
	    if ( str_cmp( argument, "clear" ) )
	      skill->miss_char = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "missvict" ) )
	{
	    if ( skill->miss_vict )
	      DISPOSE(skill->miss_vict);
	    if ( str_cmp( argument, "clear" ) )
	      skill->miss_vict = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "missroom" ) )
	{
	    if ( skill->miss_room )
	      DISPOSE(skill->miss_room);
	    if ( str_cmp( argument, "clear" ) )
	      skill->miss_room = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "diechar" ) )
	{
	    if ( skill->die_char )
	      DISPOSE(skill->die_char);
	    if ( str_cmp( argument, "clear" ) )
	      skill->die_char = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "dievict" ) )
	{
	    if ( skill->die_vict )
	      DISPOSE(skill->die_vict);
	    if ( str_cmp( argument, "clear" ) )
	      skill->die_vict = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "dieroom" ) )
	{
	    if ( skill->die_room )
	      DISPOSE(skill->die_room);
	    if ( str_cmp( argument, "clear" ) )
	      skill->die_room = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "immchar" ) )
	{
	    if ( skill->imm_char )
	      DISPOSE(skill->imm_char);
	    if ( str_cmp( argument, "clear" ) )
	      skill->imm_char = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "immvict" ) )
	{
	    if ( skill->imm_vict )
	      DISPOSE(skill->imm_vict);
	    if ( str_cmp( argument, "clear" ) )
	      skill->imm_vict = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "immroom" ) )
	{
	    if ( skill->imm_room )
	      DISPOSE(skill->imm_room);
	    if ( str_cmp( argument, "clear" ) )
	      skill->imm_room = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "dice" ) )
	{
	    if ( skill->dice )
	      DISPOSE(skill->dice);
	    if ( str_cmp( argument, "clear" ) )
	      skill->dice = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "components" ) )
	{
	    if ( skill->components )
	      DISPOSE(skill->components);
	    if ( str_cmp( argument, "clear" ) )
	      skill->components = str_dup( argument );
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	if ( !str_cmp( arg2, "teachers" ) )
	{
	    //if ( skill->teachers )
	      //DISPOSE(skill->teachers);

	    if ( !str_cmp( argument, "clear" ) )
	      skill->teachers = str_dup( "" );
	    else {
	      //strcat(skill->teachers, " ");  
	      //strcat(skill->teachers, argument);
	    if(skill->teachers)
	    {
	      sprintf(buf, "%s %s", skill->teachers, argument);
	      skill->teachers = str_dup(buf);
	    }
	    else
	      skill->teachers = str_dup(argument);
	    }
	    send_to_char( "Ok.\n\r", ch );
	    return;
	}
	do_sset( ch, "" );
	return;
    }

    if ( ( victim = get_char_world( ch, arg1 ) ) == NULL )
    {
	if ( (sn = skill_lookup(arg1)) >= 0 )
	{
	    sprintf(arg1, "%d %s %s", sn, arg2, argument);
	    do_sset(ch, arg1);
	}
	else
	    send_to_char( "They aren't here.\n\r", ch );
	return;
    }

    if ( IS_NPC(victim) )
    {
	send_to_char( "Not on NPC's.\n\r", ch );
	return;
    }

    fAll = !str_cmp( arg2, "all" );
    sn   = 0;
    if ( !fAll && ( sn = skill_lookup( arg2 ) ) < 0 )
    {
	send_to_char( "No such skill or spell.\n\r", ch );
	return;
    }

    /*
     * Snarf the value.
     */
    if ( !is_number( argument ) )
    {
	send_to_char( "Value must be numeric.\n\r", ch );
	return;
    }

    value = atoi( argument );
    if ( value < 0 || value > 100 )
    {
	send_to_char( "Value range is 0 to 100.\n\r", ch );
	return;
    }

    if ( fAll )
    {
	for ( sn = 0; sn < top_sn; sn++ )
	{
            /* Fix by Narn to prevent ssetting skills the player shouldn't have. */ 
	      if (skill_table[sn]->guild < 0 || skill_table[sn]->guild >= MAX_ABILITY )
               continue;
            if ( skill_table[sn]->name 
            && ( victim->skill_level[skill_table[sn]->guild] >= skill_table[sn]->min_level 
                      || value == 0 ) )
              victim->pcdata->learned[sn] = value;
	}
    }
    else
	victim->pcdata->learned[sn] = value;

    return;
}


void learn_from_success( CHAR_DATA *ch, int sn )
{
  send_to_char( "Notify the Imms of this.\n\r", ch );
  return;
}

void learn_from_failure( CHAR_DATA *ch, int sn )
{
  send_to_char( "Notify the Imms of this.\n\r", ch );
  return;
}

void do_detrap( CHAR_DATA *ch, char *argument )
{
    char arg  [MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    OBJ_DATA *trap;
    OBJ_DATA *toolkit;
    int chance;
    bool has_toolkit = FALSE;
    bool found = FALSE;

    switch( ch->substate )
    {
	default:
	    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
	    {
		send_to_char( "You can't concentrate enough for that.\n\r", ch );
		return;
	    }
	    argument = one_argument( argument, arg );
	    if ( IS_NPC(ch) )
	    {
		send_to_char("You do not yet know of this skill.\n\r", ch );
		return;
	    }
	    if ( arg[0] == '\0' )
	    {
		send_to_char( "Detrap what?\n\r", ch );
		return;
	    }
	    if ( ms_find_obj(ch) )
		return;
	    found = FALSE;
	    if ( ch->mount )
	    {
		send_to_char( "You can't do that while mounted.\n\r", ch );
		return;
	    }
	    if ( !ch->in_room->first_content )
	    {
	       send_to_char( "You can't find that here.\n\r", ch );
	       return;
	    }
	    for ( toolkit = ch->last_carrying; obj; obj = obj->prev_content )
	    {
	       if ( toolkit->item_type == ITEM_TOOLKIT )
		{
		  has_toolkit = TRUE;
		  break;
	   	}
	    }
	    if( !has_toolkit )
	    {
		send_to_char( "You can't do that without a toolkit.\n\r", ch );
		return;
	    }
	    for ( obj = ch->in_room->first_content; obj; obj = obj->next_content )
	    {
	       if ( can_see_obj( ch, obj ) && nifty_is_name( arg, obj->name ) )
	       {
		  found = TRUE;
		  break;
	       }
	    }
	    if ( !found )
	    {
	       send_to_char( "You can't find that here.\n\r", ch );
	       return;
	    }
	    act( AT_ACTION, "You begin your attempt to detrap $p.", ch, obj, NULL, TO_CHAR );
	    act( AT_ACTION, "$n nervously attempts to disable a trap.", ch, obj, NULL, TO_ROOM );
	    ch->dest_buf = str_dup( obj->name );
	    add_timer( ch, TIMER_DO_FUN, number_range(2,8), do_detrap, 1 );
	    return;
	case 1:
	    if ( !ch->dest_buf )
	    {
		send_to_char( "You were interupted before you could remove the trap!\n\r", ch );
		bug( "do_detrap: ch->dest_buf NULL!", 0 );
		return;
	    }
	    strcpy( arg, ch->dest_buf );
	    DISPOSE( ch->dest_buf );
	    ch->dest_buf = NULL;
	    ch->substate = SUB_NONE;
	    break;
	case SUB_TIMER_DO_ABORT:
	    DISPOSE(ch->dest_buf);
	    ch->substate = SUB_NONE;
	    send_to_char( "You carefully stop in your attempt to remove the trap.\n\r", ch );
	    return;
    }

    if ( !ch->in_room->first_content )
    {
       send_to_char( "You can't find that here.\n\r", ch );
       return;
    }
    for ( toolkit = ch->last_carrying; obj; obj = obj->prev_content )
    {
	if( toolkit->item_type == ITEM_TOOLKIT )
	 {
	   has_toolkit = TRUE;
	   break;
	 }
    }
    if( !has_toolkit )
    {
	send_to_char( "You cannot complete your work without a toolkit.\n\r", ch );
	return;
    }
    for ( obj = ch->in_room->first_content; obj; obj = obj->next_content )
    {
       if ( can_see_obj( ch, obj ) && nifty_is_name( arg, obj->name ) )
       {
	  found = TRUE;
	  break;
       }
    }
    if ( !found )
    {
       send_to_char( "You can't find that here.\n\r", ch );
       return;
    }
    if ( (trap = get_trap( obj )) == NULL )
    {
       send_to_char( "You find no trap on that.\n\r", ch );
       return;
    }

    chance = skill_roll( ch, DISABLE_DEVICE );

    separate_obj(obj);
    if ( chance < 20 )
    {
       send_to_char( "You made a fatal error and sprung the trap!\n\r", ch );
       spring_trap( ch, trap );
       return;
    }

    extract_obj( trap );

    send_to_char( "You have successfully removed the trap.\n\r", ch );
    return;
}

void do_dig( CHAR_DATA *ch, char *argument )
{
    char arg [MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    OBJ_DATA *startobj;
    bool found;
    bool shovel=FALSE;
    EXIT_DATA *pexit;
    int chance;
   
    switch( ch->substate )
    {
	default:
	  if ( IS_NPC(ch)  && IS_AFFECTED( ch, AFF_CHARM ) )
	  {
	    send_to_char( "You can't concentrate enough for that.\n\r", ch );
	    return;
	  }
          if ( ch->mount )
	  {
	    send_to_char( "You can't do that while mounted.\n\r", ch );
	    return;
	  }
	  one_argument( argument, arg );
	  if ( arg[0] != '\0' )
	  {
	      if ( ( pexit = find_door( ch, arg, TRUE ) ) == NULL && get_dir(arg) == -1 )
	      {
		  send_to_char( "What direction is that?\n\r", ch );
		  return;
	      }
	      if ( pexit )
	      {
		  if ( !IS_SET(pexit->exit_info, EX_DIG) && !IS_SET(pexit->exit_info, EX_CLOSED) )
		  {
		      send_to_char( "There is no need to dig out that exit.\n\r", ch );
		      return;
		  }
	      }
	  }
	  else
	  {
	      switch( ch->in_room->sector_type )
	      {
		  case SECT_CITY:
		  case SECT_INSIDE:
		    send_to_char( "You will never be able to penetrate the floor.\n\r", ch );
		    return;
		  case SECT_WATER_SWIM:
		  case SECT_WATER_NOSWIM:
		  case SECT_UNDERWATER:
		    send_to_char( "You cannot dig here.\n\r", ch );
		    return;
		  case SECT_AIR:
		    send_to_char( "What?  In the air?!\n\r", ch );
		    return;
	      }
	  }
          for( obj = ch->last_carrying; obj; obj = obj->prev_content )
	  {
	    if( obj->item_type == ITEM_SHOVEL )
	     {
		shovel = TRUE;
		break;
	     }
	  }
	  if( !shovel )
	  {
		send_to_char( "That would be awfully difficult without a shovel.\n\r", ch );
		return;
	  }
	  add_timer( ch, TIMER_DO_FUN, 3, do_dig, 1);
	  ch->dest_buf = str_dup( arg );
	  send_to_char( "You begin digging into the ground.\n\r", ch );
 	  act( AT_PLAIN, "$n begins digging into the ground.", ch, NULL, NULL, TO_ROOM );
	  return;

	case 1:
	  if ( !ch->dest_buf )
	  {
	      send_to_char( "Your digging was interrupted!\n\r", ch );
	      act( AT_PLAIN, "$n's digging was interrupted!", ch, NULL, NULL, TO_ROOM );
	      bug( "do_dig: dest_buf NULL", 0 );
	      return;
	  }
	  strcpy( arg, ch->dest_buf );  
	  DISPOSE( ch->dest_buf );	
	  break;

	case SUB_TIMER_DO_ABORT:
	  DISPOSE( ch->dest_buf );
	  ch->substate = SUB_NONE;
	  send_to_char( "You stop digging.\n\r", ch );
	  act( AT_PLAIN, "$n stops digging.", ch, NULL, NULL, TO_ROOM );
	  return;
    }

    ch->substate = SUB_NONE;

    for ( obj = ch->first_carrying; obj; obj = obj->next_content )
      if ( obj->item_type == ITEM_SHOVEL )
      {
	  shovel = TRUE;
	  break;
      }
    if( !shovel )
      {
	send_to_char( "You cannot complete your dig without a shovel.\n\r", ch );
	return;
      }

    chance = skill_roll( ch, SPOT_SKILL );

    if ( arg[0] != '\0' )
    {
	if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL
	&&     IS_SET( pexit->exit_info, EX_DIG )
	&&     IS_SET( pexit->exit_info, EX_CLOSED ) )
	{
	    if ( chance >= 15 )
	    {
		REMOVE_BIT( pexit->exit_info, EX_CLOSED );
		send_to_char( "You discover a passageway!\n\r", ch );
		act( AT_PLAIN, "$n discovers a passageway!", ch, NULL, NULL, TO_ROOM );
		return;
	    }
	}
	send_to_char( "Your dig did not discover any passageways.\n\r", ch );
	act( AT_PLAIN, "$n's dig did not discover any passageways.", ch, NULL, NULL, TO_ROOM );
	return;
    }

    startobj = ch->in_room->first_content;
    found = FALSE;
    
    for ( obj = startobj; obj; obj = obj->next_content )
    {
	if ( IS_OBJ_STAT( obj, ITEM_BURRIED ) && chance >= 10 )
	{
	  found = TRUE;
	  break;
	}
    }

    if ( !found )
    {
	send_to_char( "You did not discover anything on your dig.\n\r", ch );
	act( AT_PLAIN, "$n discovers nothing on $s dig.", ch, NULL, NULL, TO_ROOM );
	return;
    }

    separate_obj(obj);
    REMOVE_BIT( obj->extra_flags, ITEM_BURRIED );
    act( AT_SKILL, "You find $p in the ground!", ch, obj, NULL, TO_CHAR );
    act( AT_SKILL, "$n discovers $p in the ground!", ch, obj, NULL, TO_ROOM );
    return;
} 

void do_search( CHAR_DATA *ch, char *argument )
{
    char arg  [MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    OBJ_DATA *container;
    OBJ_DATA *startobj;
    int chance, door;
    bool found, room;

    door = -1;
    switch( ch->substate )
    {
	default:
	    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
	    {
		send_to_char( "You can't concentrate enough for that.\n\r", ch );
		return;
	    }
	    if ( ch->mount )
	    {
		send_to_char( "You can't do that while mounted.\n\r", ch );
		return;
	    }
	    argument = one_argument( argument, arg );
	    if ( arg[0] != '\0' && (door = get_door( arg )) == -1 )
	    {
		container = get_obj_here( ch, arg );
		if ( !container )
		{
		  send_to_char( "You can't find that here.\n\r", ch );
		  return;
		}
		if ( container->item_type != ITEM_CONTAINER )
		{
		  send_to_char( "You can't search in that!\n\r", ch );
		  return;
		}
		if ( IS_SET(container->value[1], CONT_CLOSED) )
		{
		  send_to_char( "It is closed.\n\r", ch );
		  return;
		}
	    }
	    add_timer( ch, TIMER_DO_FUN, 3, do_search, 1 );
	    send_to_char( "You begin to search.\n\r", ch );
	    ch->dest_buf = str_dup( arg );
	    return;

	case 1:
	    if ( !ch->dest_buf )
	    {
		send_to_char( "Your search was interrupted!\n\r", ch );
		bug( "do_search: dest_buf NULL", 0 );
		return;
	    }
	    strcpy( arg, ch->dest_buf );
	    DISPOSE( ch->dest_buf );
	    break;
	case SUB_TIMER_DO_ABORT:
	    DISPOSE( ch->dest_buf );
	    ch->substate = SUB_NONE;
	    send_to_char( "You stop searching.\n\r", ch );
	    return;
    }
    ch->substate = SUB_NONE;
    if ( arg[0] == '\0' )
    {
	room = TRUE;
	startobj = ch->in_room->first_content;
    }
    else
    {
	if ( (door = get_door( arg )) != -1 )
	  startobj = NULL;
	else
	{
	    container = get_obj_here( ch, arg );
	    if ( !container )
	    {
		send_to_char( "You can't find that here.\n\r", ch );
		return;
	    }
	    startobj = container->first_content;
	}
    }

    found = FALSE;

    if ( (!startobj && door == -1) || IS_NPC(ch) )
    {
	send_to_char( "You find nothing.\n\r", ch );
	return;
    }

    chance = skill_roll( ch, SEARCH_SKILL );

    if ( door != -1 )
    {
	EXIT_DATA *pexit;
	
	if ( (pexit = get_exit( ch->in_room, door )) != NULL
	&&   IS_SET( pexit->exit_info, EX_SECRET )
	&&   IS_SET( pexit->exit_info, EX_xSEARCHABLE )
	&&   chance >= 20 )
	{
	    act( AT_SKILL, "After your search, you discover the $d!", ch, NULL, pexit->keyword, TO_CHAR );
	    act( AT_SKILL, "After searching, $n finds the $d!", ch, NULL, pexit->keyword, TO_ROOM );
	    REMOVE_BIT( pexit->exit_info, EX_SECRET );
	    return;
	}
    }
    else
    for ( obj = startobj; obj; obj = obj->next_content )
    {
       if ( IS_OBJ_STAT( obj, ITEM_HIDDEN ) && chance > 10 )
       {
	  found = TRUE;
	  break;
       }
    }

    if ( !found )
    {
       send_to_char( "You find nothing.\n\r", ch );
       return;
    }

    separate_obj(obj);
    REMOVE_BIT( obj->extra_flags, ITEM_HIDDEN );
    act( AT_SKILL, "After your search, you reveal $p!", ch, obj, NULL, TO_CHAR );
    act( AT_SKILL, "$n discovers $p!", ch, obj, NULL, TO_ROOM );
    return;
}

void do_steal( CHAR_DATA *ch, char *argument )
{
    char logbuf  [MAX_STRING_LENGTH];
    char arg1 [MAX_INPUT_LENGTH];
    char arg2 [MAX_INPUT_LENGTH];
    CHAR_DATA *victim, *rch;
    OBJ_DATA *obj , *obj_next;
    int chance, spot, iSpot;

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

    if ( ch->mount )
    {
	send_to_char( "You can't do that while mounted.\n\r", ch );
	return;
    }
    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "Steal what from whom?\n\r", ch );
	return;
    }
    if ( ms_find_obj(ch) )
	return;
    if ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }
    if ( victim == ch )
    {
	send_to_char( "That's pointless.\n\r", ch );
	return;
    }
    if ( IS_SET( ch->in_room->room_flags, ROOM_SAFE ) )
    {
	set_char_color( AT_MAGIC, ch );
	send_to_char( "This isn't a good place to do that.\n\r", ch );
	return;
    }
    if ( IS_IMMORTAL(victim) )
    {
	send_to_char( "You can't steal from an immortal!\n\r", ch );
	return;
    }
    WAIT_STATE( ch, PULSE_PER_SECOND*3 );
    chance = skill_roll( ch, SLEIGHT_OF_HAND );
    spot = skill_roll( victim, SPOT_SKILL );

    if ( !IS_AWAKE(victim) || victim->position == POS_FIGHTING )
	spot -= number_range(2, 8);

    if ( chance < 20 ) 
    {
        if( chance > spot )
	 {
	   act( AT_ACTION, "You fail to steal from $N, but $E doesn't seem to notice!\n\r", ch, NULL, victim, TO_CHAR );
   	   for( rch = ch->in_room->first_person; rch; rch = rch->next )
    	    {
		if( rch == ch || rch == victim )
	   	   continue;
		iSpot = 0;
		iSpot = skill_roll( rch, SPOT_SKILL );
		if( iSpot >= chance )
		 ch_printf( rch, "&BYou see %s fail to steal anything from the oblivious %s", ch->name, victim->name );
	    }
	   return;
	 }
	act( AT_ACTION, "You fail to steal from $N and $E has caught you!\n\r", ch, NULL, victim, TO_CHAR );
	act( AT_ACTION, "You catch $n tring to steal from you!\n\r", ch, NULL, victim, TO_VICT    );
   	for( rch = ch->in_room->first_person; rch; rch = rch->next )
    	 {
		if( rch == ch || rch == victim )
	   	   continue;
		iSpot = 0;
		iSpot = skill_roll( rch, SPOT_SKILL );
		if( iSpot >= chance )
		 ch_printf( rch, "&BYou see %s fail to steal anything from the observant %s", ch->name, victim->name );
	 }
	if(IS_NPC(victim))
	  global_retcode = multi_hit( victim, ch, TYPE_UNDEFINED );
	return;
    }

    for( rch = ch->in_room->first_person; rch; rch = rch->next )
     {
		if( rch == ch || rch == victim )
	   	   continue;
		iSpot = 0;
		iSpot = skill_roll( rch, SPOT_SKILL );
		if( iSpot >= chance )
		 ch_printf( rch, "&BYou see %s steal from the oblivious %s", ch->name, victim->name );
     }
    
    if ( !str_cmp( arg1, "credits"  ) || !str_cmp( arg1, "credit" ) || !str_cmp( arg1, "money"  ) )
    {
	int amount;

	amount = (int) (victim->gold * number_range(1, 10) / 100);
	if ( amount <= 0 )
	{
	    send_to_char( "You couldn't get any credits.\n\r", ch );
	    return;
	}

	ch->gold     += amount;
	victim->gold -= amount;
	ch_printf( ch, "&w&WYou managed to steal &G%d&w&W credits!\n\r", amount );
        sprintf(logbuf, "%s stole %d credits from %s.\n\r", ch->name, amount, IS_NPC(victim) ? victim->short_descr : victim->name);
        log_string(logbuf);
	return;
    }

    if ( ( obj = get_obj_carry( victim, arg1 ) ) == NULL )
    {
        if ( victim->position <= POS_SLEEPING )
        {   
           if ( ( obj = get_obj_wear( victim, arg1 ) ) != NULL ) 
           {
             if ( (obj_next=get_eq_char(victim, obj->wear_loc)) != obj )
             {
	       ch_printf( ch, "They are wearing %s on top of %s.\n\r", obj_next->short_descr, obj->short_descr);
	       send_to_char( "You'll have to steal that first.\n\r", ch );	
	       return;
             }
             else
               unequip_char( victim, obj );
           }
        }
           
	send_to_char( "You can't seem to find it.\n\r", ch );
	return;
    }

    if ( !can_drop_obj( ch, obj ) || IS_OBJ_STAT(obj, ITEM_INVENTORY) || IS_OBJ_STAT(obj, ITEM_PROTOTYPE))
    {
	send_to_char( "You can't manage to pry it away.\n\r", ch );
	return;
    }

    if ( ch->carry_number + (get_obj_number(obj)/obj->count) > can_carry_n( ch ) )
    {
	send_to_char( "You have your hands full.\n\r", ch );
	return;
    }

    if ( ch->carry_weight + (get_obj_weight(obj)/obj->count) > can_carry_w( ch ) )
    {
	send_to_char( "You can't carry that much weight.\n\r", ch );
	return;
    }

    ch_printf( ch, "&w&WYou stole &G%s&w&W from &G%s&w&W!\n\r", obj->name, victim->name );
    sprintf(logbuf, "%s stole %s from %s.\n\r", ch->name, obj->name, IS_NPC(victim) ? victim->short_descr : victim->name );
    log_string(logbuf);
    separate_obj( obj );
    obj_from_char( obj );
    obj_to_char( obj, ch );
    return;
}

void do_rescue( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *victim;
    CHAR_DATA *fch;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }
    if ( ch->class_level[PROTECTOR_ABILITY] < 2 )
    {
	send_to_char( "Huh?\n\r", ch );
	return;
    }
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Rescue whom?\n\r", ch );
	return;
    }
    if ( ( victim = get_char_room( ch, arg ) ) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }
    if ( victim == ch )
    {
	send_to_char( "Rescue yourself, wouldn't that be lovily?\n\r", ch );
	return;
    }
    if ( ch->mount )
    {
	send_to_char( "You can't do that while mounted.\n\r", ch );
	return;
    }
    if ( !IS_NPC(ch) && IS_NPC(victim) )
    {
	send_to_char( "Doesn't need your help!\n\r", ch );
	return;
    }
    if ( ( fch = who_fighting( victim) ) == NULL )
    {
	send_to_char( "They are not fighting right now.\n\r", ch );
	return;
    }
    if ( fch == ch )
    {
	send_to_char("You cannot rescue them from yourself.\n\r", ch);
	return;
    }

    WAIT_STATE( ch, PULSE_VIOLENCE*2 );
    act( AT_SKILL, "You succeed in rescueing $N!",  ch, NULL, victim, TO_CHAR    );
    act( AT_SKILL, "$n rescues you!", ch, NULL, victim, TO_VICT    );
    act( AT_SKILL, "$n moves in front of $N!",  ch, NULL, victim, TO_NOTVICT );
       
    stop_fighting( fch, FALSE );
    stop_fighting( victim, FALSE );
    if ( ch->fighting )
      stop_fighting( ch, FALSE );

    set_fighting( ch, fch );
    set_fighting( fch, ch );
    return;
}

void disarm( CHAR_DATA *ch, CHAR_DATA *victim )
{
    OBJ_DATA *obj, *tmpobj, *ch_wield;
    int chance, resist;

    

    if ( ( obj = get_eq_char( victim, WEAR_WIELD ) ) == NULL )
	return;

    if ( ( tmpobj = get_eq_char( victim, WEAR_DUAL_WIELD ) ) != NULL )
	obj = tmpobj;

    if ( ( ch_wield = get_eq_char( ch, WEAR_WIELD ) ) != NULL )
       if( ch_wield->item_type == ITEM_WEAPON && (ch_wield->value[3] == WEAPON_BLASTER_RIFLE || ch_wield->value[3] == WEAPON_BLASTER
  	|| ch_wield->value[3] == WEAPON_BOWCASTER || ch_wield->value[3] == WEAPON_HEAVY ) )
	return;

    if ( IS_NPC( ch ) && !can_see_obj( ch, obj ) )
	return;

    chance = ( number_range(1,20) + ch->hitroll );
    resist = ( number_range(1,20) + ch->hitroll );

    if ( chance > resist )
     {
       act( AT_SKILL, "$n DISARMS you!", ch, NULL, victim, TO_VICT    );
       act( AT_SKILL, "You disarm $N!",  ch, NULL, victim, TO_CHAR    );
       act( AT_SKILL, "$n disarms $N!",  ch, NULL, victim, TO_NOTVICT );
     }
    else
     {
       act( AT_SKILL, "$n fails to disarm you!", ch, NULL, victim, TO_VICT );
       act( AT_SKILL, "You fail to disarm $N!", ch, NULL, victim, TO_CHAR );
       act( AT_SKILL, "$n fails to disarm $N!", ch, NULL, victim, TO_NOTVICT );
       return;
     }

    if ( obj == get_eq_char( victim, WEAR_WIELD )
    &&  (tmpobj = get_eq_char( victim, WEAR_DUAL_WIELD)) != NULL )
       tmpobj->wear_loc = WEAR_WIELD;

    obj_from_char( obj );

    if ( ( ch_wield = get_eq_char( ch, WEAR_WIELD ) ) == NULL )
     {
        obj_to_char( obj, ch );
	return;
     }
    obj_to_room( obj, victim->in_room );
    return;
}

void do_disarm( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    OBJ_DATA *obj;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }
    if ( get_eq_char( ch, WEAR_WIELD ) == NULL )
    {
	send_to_char( "You must wield a weapon to disarm.\n\r", ch );
	return;
    }
    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }
    if ( ( obj = get_eq_char( victim, WEAR_WIELD ) ) == NULL )
    {
	send_to_char( "Your opponent is not wielding a weapon.\n\r", ch );
	return;
    }
    WAIT_STATE( ch, PULSE_VIOLENCE );
    disarm( ch, victim );
    return;
}

void trip( CHAR_DATA *ch, CHAR_DATA *victim )
{
    OBJ_DATA *armor;
    int chance, resist, touch, trip;

    touch = GET_AC(victim);
    if( ( armor = get_eq_char( victim, WEAR_BODY ) ) != NULL )
	touch -= armor->value[0];

    chance = ( number_range(1,20) + ch->hitroll );

    if( chance < touch )
     {
	act( AT_SKILL, "$n fails to trip you!", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "You fail to trip $N!", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n fails to trip $N!", ch, NULL, victim, TO_NOTVICT );
	return;
     }    

    trip = ( number_range( 1, 20 ) + stat_table[get_curr_str(ch)].mod );
    resist = number_range(1,20);
    if( get_curr_str(victim) > get_curr_dex(victim) )
	resist += stat_table[get_curr_str(victim)].mod;
    else
	resist += stat_table[get_curr_dex(victim)].mod;

    if( trip < resist )
     {
	act( AT_SKILL, "$n fails to trip you!", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "You fail to trip $N!", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n fails to trip $N!", ch, NULL, victim, TO_NOTVICT );
	return;
     }
    if ( victim->mount )
    {
	act( AT_SKILL, "$n trips your mount and you fall off!", ch, NULL, victim, TO_VICT    );
	act( AT_SKILL, "You trip $N's mount and $N falls off!", ch, NULL, victim, TO_CHAR    );
	act( AT_SKILL, "$n trips $N's mount and $N falls off!", ch, NULL, victim, TO_NOTVICT );
	REMOVE_BIT( victim->mount->act, ACT_MOUNTED );
	victim->mount = NULL;
	victim->hit -= number_range(1, 5);
	update_pos(victim);
	WAIT_STATE( ch,     2 * PULSE_VIOLENCE );
	WAIT_STATE( victim, 2 * PULSE_VIOLENCE );
	victim->position = POS_RESTING;
	return;		
    }
    if ( victim->wait == 0 )
    {
	act( AT_SKILL, "$n trips you and you go down!", ch, NULL, victim, TO_VICT    );
	act( AT_SKILL, "You trip $N and $N goes down!", ch, NULL, victim, TO_CHAR    );
	act( AT_SKILL, "$n trips $N and $N goes down!", ch, NULL, victim, TO_NOTVICT );
	WAIT_STATE( ch,     2 * PULSE_VIOLENCE );
	WAIT_STATE( victim, 2 * PULSE_VIOLENCE );
	victim->position = POS_RESTING;
    }
    return;
}

void do_pick( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    int x, y;
    CHAR_DATA *victim;
    CHAR_DATA *gch;
    OBJ_DATA *obj;
    OBJ_DATA *iObj;
    EXIT_DATA *pexit;
    SHIP_DATA *ship;
    bool toolkit = FALSE;
    
    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	send_to_char( "Pick what?\n\r", ch );
	return;
    }

    if ( ms_find_obj(ch) )
	return;

    if ( ch->mount )
    {
	send_to_char( "You can't do that while mounted.\n\r", ch );
	return;
    }
    for( iObj = ch->first_carrying; iObj; iObj = iObj->next_content )
    {
	if( iObj->item_type == ITEM_TOOLKIT )
	 {
		toolkit = TRUE;
		break;
	 }
    }
    if( !toolkit )
    {
	send_to_char( "How are you going to do that without tools?\n\r", ch );
	return;
    }
    WAIT_STATE( ch, PULSE_PER_SECOND*2 );
    for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
    {
	if ( IS_NPC(gch) && IS_AWAKE(gch) && ch->top_level < gch->top_level )
	{
	    act( AT_PLAIN, "$N is standing too close to the lock.", ch, NULL, gch, TO_CHAR );
	    return;
	}
    }
    
    if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL )
    {
	EXIT_DATA *pexit_rev;

	if ( !IS_SET(pexit->exit_info, EX_CLOSED) )
	    { send_to_char( "It's not closed.\n\r",        ch ); return; }
	if ( pexit->key < 0 )
	    { send_to_char( "It can't be picked.\n\r",     ch ); return; }
	if ( !IS_SET(pexit->exit_info, EX_LOCKED) )
	    { send_to_char( "It's already unlocked.\n\r",  ch ); return; }
	if ( IS_SET(pexit->exit_info, EX_PICKPROOF) )
	{
	   send_to_char( "You failed.\n\r", ch );
	   check_room_for_traps( ch, TRAP_PICK | trap_door[pexit->vdir] );
	   return;
	}
        x = skill_roll( ch, DISABLE_DEVICE );
        
        if ( x < 20 )
        {
	  send_to_char( "You failed to disable the lock.\n\r", ch);
	  return;
        }

	REMOVE_BIT(pexit->exit_info, EX_LOCKED);
	send_to_char( "You override the locking mechanism!\n\r", ch );
	act( AT_ACTION, "$n overrides the lock of the $d.", ch, NULL, pexit->keyword, TO_ROOM );
	/* pick the other side */
	if ( ( pexit_rev = pexit->rexit ) != NULL && pexit_rev->to_room == ch->in_room )
	{
	    REMOVE_BIT( pexit_rev->exit_info, EX_LOCKED );
	}
	check_room_for_traps( ch, TRAP_PICK | trap_door[pexit->vdir] );
        return;
    }

    if ( ( obj = get_obj_here( ch, arg ) ) != NULL )
    {
	if ( obj->item_type != ITEM_CONTAINER )
	    { send_to_char( "You can't pick that.\n\r", ch ); return; }
	if ( !IS_SET(obj->value[1], CONT_CLOSED) )
	    { send_to_char( "It's not closed.\n\r",        ch ); return; }
	if ( obj->value[2] < 0 )
	    { send_to_char( "It can't be unlocked.\n\r",   ch ); return; }
	if ( !IS_SET(obj->value[1], CONT_LOCKED) )
	    { send_to_char( "It's already unlocked.\n\r",  ch ); return; }
	if ( IS_SET(obj->value[1], CONT_PICKPROOF) )
	{
	   send_to_char( "You failed.\n\r", ch );
	   check_for_trap( ch, obj, TRAP_PICK );
	   return;
	}
        x = skill_roll( ch, DISABLE_DEVICE );          
        if ( x < 15 )
        {
	  send_to_char( "You failed to disable the locking mechanism.\n\r", ch);
	  return;
        }

	separate_obj( obj );
	REMOVE_BIT(obj->value[1], CONT_LOCKED);
	send_to_char( "You disable the locking mechanism!\n\r", ch );
	act( AT_ACTION, "$n disables the lock of the $p.", ch, obj, NULL, TO_ROOM );
	check_for_trap( ch, obj, TRAP_PICK );
	return;
    }  
    if ( ( ship = ship_in_room(ch->in_room, arg ) ) != NULL )
    {        
             if ( check_pilot( ch , ship ) )
    	     {
    	            send_to_char("&RWhat would be the point of that!\n\r",ch);
    	            return;
    	     }    	        
	     if ( ship->shipstate != SHIP_DOCKED && ship->shipstate != SHIP_DISABLED )
   	     {
        	send_to_char( "&RThat ship has already started to launch",ch);
        	return;
   	     }   
   	     WAIT_STATE( ch, PULSE_PER_SECOND*2 );
             y = skill_roll( ch, DISABLE_DEVICE );
   	     if ( y < 25 )
             {
		send_to_char( "You failed to override the ships locking mechanism.\n\r", ch);	
                if (ship->alarm >= 1)                 
                   if((victim = get_char_world_ooc(ch, ship->owner)) != NULL)
                     ch_printf(victim, "&RYou have received a signal from the alarm module installed in %s.&W", ship->name);                                
		return;
             }	     
   	     if ( !ship->hatchopen)
             {
   		ship->hatchopen = TRUE;
   		act( AT_PLAIN, "You pick the lock and open the hatch on $T.", ch, NULL, ship->name, TO_CHAR );
   		act( AT_PLAIN, "$n picks open the hatch on $T.", ch, NULL, ship->name, TO_ROOM );
   		echo_to_room( AT_YELLOW , get_room_index(ship->entrance) , "The hatch opens from the outside." );
	     }
       	     return;
    }
    ch_printf( ch, "You see no %s here.\n\r", arg );
    return;
}

void do_sneak( CHAR_DATA *ch, char *argument )
{
    AFFECT_DATA af;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }

    if ( ch->mount )
    {
	send_to_char( "You can't do that while mounted.\n\r", ch );
	return;
    }

    send_to_char( "You attempt to move silently.\n\r", ch );
    affect_strip( ch, gsn_sneak );

    af.type      = gsn_sneak;
    af.duration  = ch->top_level  * DUR_CONV;
    af.location  = APPLY_NONE;
    af.modifier  = 0;
    af.bitvector = AFF_SNEAK;
    affect_to_char( ch, &af );
    return;
}

void do_hide( CHAR_DATA *ch, char *argument )
{
    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }

    if ( ch->mount )
    {
	send_to_char( "You can't do that while mounted.\n\r", ch );
	return;
    }

    send_to_char( "You attempt to hide.\n\r", ch );
    
    if ( IS_NPC(ch) || number_percent( ) < 0 )
	SET_BIT(ch->affected_by, AFF_HIDE);
    return;
}

void do_visible( CHAR_DATA *ch, char *argument )
{
    affect_strip ( ch, gsn_sneak			);
    REMOVE_BIT   ( ch->affected_by, AFF_HIDE		);
    REMOVE_BIT   ( ch->affected_by, AFF_INVISIBLE	);
    REMOVE_BIT   ( ch->affected_by, AFF_SNEAK		);
    send_to_char( "You become more visible.\n\r", ch );
    return;
}

void do_recall( CHAR_DATA *ch, char *argument )
{
    ROOM_INDEX_DATA *location;
    CHAR_DATA *opponent;

    location = NULL;

    location = get_room_index( wherehome(ch) ); 
    
    if ( get_trust( ch ) < LEVEL_IMMORTAL )
    {
        AREA_DATA * pArea;
    
        if ( !ch->pcdata || !(pArea=ch->pcdata->area) )
        {
	   send_to_char( "Only builders can recall.\n\r", ch );
	   return;
        }   
        
        if  ( ch->in_room->vnum < pArea->low_r_vnum
        || ch->in_room->vnum > pArea->hi_r_vnum )
        {
	   send_to_char( "You can only recall from your assigned area.\n\r", ch );
	   return;
        }   
    }
    
    if ( !location )
    {
	send_to_char( "You are completely lost.\n\r", ch );
	return;
    }

    if ( ch->in_room == location )
	return;

    if ( IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL) )
    {
	send_to_char( "For some strange reason... nothing happens.\n\r", ch );
	return;
    }

    if ( ( opponent = who_fighting( ch ) ) != NULL )
    {

	if ( number_bits( 1 ) == 0 || ( !IS_NPC( opponent ) && number_bits( 3 ) > 1 ) )
	{
	    WAIT_STATE( ch, 4 );
	    ch_printf( ch, "You failed!\n\r" );
	    return;
	}

	ch_printf( ch, "You recall from combat!\n\r" );
	stop_fighting( ch, TRUE );
    }

    act( AT_ACTION, "$n disappears in a swirl of the Force.", ch, NULL, NULL, TO_ROOM );
    char_from_room( ch );
    char_to_room( ch, location );
    if ( ch->mount )
    {
	char_from_room( ch->mount );
	char_to_room( ch->mount, location );
    }
    act( AT_ACTION, "$n appears in a swirl of the Force.", ch, NULL, NULL, TO_ROOM );
    do_look( ch, "auto" );

    return;
}

void do_aid( CHAR_DATA *ch, char *argument )
{
  CHAR_DATA *victim;
  OBJ_DATA *obj;
  int chance, heal;
  bool has_toolkit = FALSE;
  bool has_medpac = FALSE;

  if( !IS_AWAKE(ch) || ch->position == POS_FIGHTING )
   {
	send_to_char( "Not in this current position.\n\r", ch );
	return;
   }
  if( ch->mount )
   {
	send_to_char( "Not while mounted.\n\r", ch );
	return;
   }
  if( argument[0] == '\0' )
   {
	send_to_char( "Offer aid to whom?\n\r", ch );
	return;
   }
  if( ( victim = get_char_room( ch, argument ) ) == NULL )
   {
	send_to_char( "I don't see them here.\n\r", ch );
	return;
   }
  if( victim->hit >= victim->max_hit )
   {
	send_to_char( "They don't need your assistance.\n\r", ch );
	return;
   }
  if( IS_DROID(victim) )
   {
	for( obj = ch->first_carrying; obj; obj = obj->next_content )
         {
	    if( obj->item_type == ITEM_TOOLKIT )
	     {
		has_toolkit = TRUE;
		break;
	     }
	 }
	if( !has_toolkit )
	 {
	    send_to_char( "How are you going to repair a droid without a toolkit?\n\r", ch );
	    return;
	 }
	chance = skill_roll( ch, REPAIR_SKILL );
	WAIT_STATE( ch, PULSE_VIOLENCE );
	if( chance < 15 )
	 {
	    act( AT_ACTION, "You fail to repair $N.\n\r", ch, NULL, victim, TO_CHAR );
	    act( AT_ACTION, "$n fails to repair you.\n\r", ch, NULL, victim, TO_VICT );
	    act( AT_ACTION, "$n fails to repair $N.\n\r", ch, NULL, victim, TO_NOTVICT );
	    return;
	 }
	heal = number_range(2, 9); 
	if( chance >= 15 && chance < 20 )
	    heal += 2;
	else if( chance >= 20 )
	    heal += 5;
	victim->hit = URANGE( victim->hit, victim->hit + heal, victim->max_hit );
	update_pos(victim);
	act( AT_ACTION, "You repair $N.\n\r", ch, NULL, victim, TO_CHAR );
	act( AT_ACTION, "$n repairs you.\n\r", ch, NULL, victim, TO_VICT );
	act( AT_ACTION, "$n repairs $N.\n\r", ch, NULL, victim, TO_NOTVICT );
	return;
   }

  for( obj = ch->first_carrying; obj; obj = obj->next_content )
   {
	if( obj->item_type == ITEM_MEDPAC )
	 {
		has_medpac = TRUE;
		break;
	 }
   }
  if( !has_medpac )
   {
	send_to_char( "How are you going to be of any use without a medpac.\n\r", ch );
	return;
   }
  separate_obj( obj );
  obj_from_char( obj );
  chance = skill_roll( ch, TREAT_INJURY );
  WAIT_STATE( ch, PULSE_VIOLENCE );
  if( chance < 15 )
   {
      if( ch != victim )
       {
	act( AT_ACTION, "You fail to aid $N.\n\r", ch, NULL, victim, TO_CHAR );
	act( AT_ACTION, "$n fails to aid you.\n\r", ch, NULL, victim, TO_VICT );
	act( AT_ACTION, "$n fails to aid $N.\n\r", ch, NULL, victim, TO_NOTVICT );
	return;
       }
      act( AT_ACTION, "You fail to aid yourself.\n\r", ch, NULL, victim, TO_CHAR );
      act( AT_ACTION, "$n fails to aid $mself.\n\r", ch, NULL, victim, TO_NOTVICT );
      return;
   }
  heal = ( number_range(1, 10) + (4 * obj->value[0]) );
  victim->hit = URANGE( victim->hit, victim->hit + heal, victim->max_hit );
  update_pos(victim);
  if( ch != victim )
   {
	act( AT_ACTION, "You aid $N.\n\r", ch, NULL, victim, TO_CHAR );
	act( AT_ACTION, "$n aids you slightly.\n\r", ch, NULL, victim, TO_VICT );
	act( AT_ACTION, "$n aids $N slightly.\n\r", ch, NULL, victim, TO_NOTVICT );
	return;
   }
  act( AT_ACTION, "You aid yourself.\n\r", ch, NULL, victim, TO_CHAR );
  act( AT_ACTION, "$n aids $mself.\n\r", ch, NULL, victim, TO_NOTVICT );
  return;
}

void do_mount( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    int chance;

    if ( ch->mount )
    {
	send_to_char( "You're already mounted!\n\r", ch );
	return;
    }

    if ( ( victim = get_char_room( ch, argument ) ) == NULL )
    {
	send_to_char( "You can't find that here.\n\r", ch );
	return;
    }

    if ( !IS_NPC(victim) || !IS_SET(victim->act, ACT_MOUNTABLE ) )
    {
	send_to_char( "You can't mount that!\n\r", ch );
	return;
    }

    if ( IS_SET(victim->act, ACT_MOUNTED ) )
    {
	send_to_char( "That mount already has a rider.\n\r", ch );
	return;
    }

    if ( victim->position < POS_STANDING )
    {
	send_to_char( "Your mount must be standing.\n\r", ch );
	return;
    }

    if ( victim->position == POS_FIGHTING || victim->fighting )
    {
	send_to_char( "Your mount is moving around too much.\n\r", ch );
	return;
    }
    chance = skill_roll( ch, RIDE_SKILL );
    WAIT_STATE( ch, PULSE_PER_SECOND*2 );
    if ( chance >= 10 )
    {
	SET_BIT( victim->act, ACT_MOUNTED );
	ch->mount = victim;
	act( AT_SKILL, "You mount $N.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n skillfully mounts $N.", ch, NULL, victim, TO_NOTVICT );
	act( AT_SKILL, "$n mounts you.", ch, NULL, victim, TO_VICT );
	ch->position = POS_MOUNTED;
    }
    else
    {
	act( AT_SKILL, "You unsuccessfully try to mount $N.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n unsuccessfully attempts to mount $N.", ch, NULL, victim, TO_NOTVICT );
	act( AT_SKILL, "$n tries to mount you.", ch, NULL, victim, TO_VICT );
    }
    return;
}

void do_dismount( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    int chance;

    if ( (victim = ch->mount) == NULL )
    {
	send_to_char( "You're not mounted.\n\r", ch );
	return;	
    }
    chance = skill_roll( ch, RIDE_SKILL );
    WAIT_STATE( ch, PULSE_PER_SECOND*2 );
    if ( chance >= 10 )
    {
	act( AT_SKILL, "You dismount $N.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n skillfully dismounts $N.", ch, NULL, victim, TO_NOTVICT );
	act( AT_SKILL, "$n dismounts you.  Whew!", ch, NULL, victim, TO_VICT );
	REMOVE_BIT( victim->act, ACT_MOUNTED );
	ch->mount = NULL;
	ch->position = POS_STANDING;
    }
    else
    {
	act( AT_SKILL, "You fall off while dismounting $N.  Ouch!", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n falls off of $N while dismounting.", ch, NULL, victim, TO_NOTVICT );
	act( AT_SKILL, "$n falls off your back.", ch, NULL, victim, TO_VICT );
	REMOVE_BIT( victim->act, ACT_MOUNTED );
	ch->mount = NULL;
	ch->position = POS_SITTING;
	global_retcode = damage( ch, ch, 1, TYPE_UNDEFINED, FALSE );
    }
    return;
}

bool check_parry( CHAR_DATA *ch, CHAR_DATA *victim )
{
  return FALSE;
}

void do_rage( CHAR_DATA *ch, char *argument )
{
  AFFECT_DATA af;
  
  if ( !IS_NPC(ch) && !HAS_FFEAT( ch, RAGE_FEAT ) )
  {
	send_to_char( "Huh?\n\r", ch );
	return;
  }
  if ( !ch->fighting )
  {
    send_to_char( "But you aren't fighting!\n\r", ch );
    return;
  }
  if ( IS_AFFECTED(ch, AFF_RAGE ) )
  {
    send_to_char( "Your rage is already at its peak!\n\r", ch );
    return;
  }
  gain_darkpoint( ch );
  WAIT_STATE(ch, PULSE_PER_SECOND*3 );

  af.type = gsn_rage;
  af.duration = (20 * stat_table[get_curr_con(ch)].mod);
  af.location = APPLY_STR;
  af.modifier = 4;
  af.bitvector = AFF_RAGE;
  affect_to_char(ch, &af);
  af.type = gsn_rage;
  af.duration = (20 * stat_table[get_curr_con(ch)].mod);
  af.location = APPLY_FORT;
  af.modifier = 2;
  af.bitvector = AFF_RAGE;
  affect_to_char(ch, &af);
  af.type = gsn_rage;
  af.duration = (20 * stat_table[get_curr_con(ch)].mod);
  af.location = APPLY_WILL;
  af.modifier = 2;
  af.bitvector = AFF_RAGE;
  affect_to_char(ch, &af);
  af.type = gsn_rage;
  af.duration = (20 * stat_table[get_curr_con(ch)].mod);
  af.location = APPLY_AC;
  af.modifier = -2;
  af.bitvector = AFF_RAGE;
  affect_to_char(ch, &af);
  af.type = gsn_rage;
  af.duration = (20 * stat_table[get_curr_con(ch)].mod);
  af.location = APPLY_HIT;
  af.modifier = (2 * ch->top_level);
  af.bitvector = AFF_RAGE;
  affect_to_char(ch, &af);
  send_to_char( "You start to lose control..\n\r", ch );
  return;
}

bool check_illegal_psteal( CHAR_DATA *ch, CHAR_DATA *victim )
{
    return FALSE;
}

void do_scan( CHAR_DATA *ch, char *argument )
{
  ROOM_INDEX_DATA *was_in_room;
  ROOM_INDEX_DATA *to_room;
  EXIT_DATA *pexit;
  OBJ_DATA *goggles;
  sh_int dir = -1;
  sh_int dist;
  sh_int max_dist = 3;

  if ( argument[0] == '\0' )
  {
    send_to_char( "Scan in a direction...\n\r", ch );
    return;
  }

  if ( ( dir = get_door( argument ) ) == -1 )
  {
    send_to_char( "Scan in WHAT direction?\n\r", ch );
    return;
  }

  was_in_room = ch->in_room;
  act( AT_GREY, "Scanning $t...", ch, dir_name[dir], NULL, TO_CHAR );
  act( AT_GREY, "$n scans $t.", ch, dir_name[dir], NULL, TO_ROOM );
  
  if ( ( pexit = get_exit( ch->in_room, dir ) ) == NULL )
  {
    act( AT_GREY, "You can't see $t.", ch, dir_name[dir], NULL, TO_CHAR );
    return;
  }


  goggles = get_eq_char(ch, WEAR_EYES);
  if( goggles != NULL && goggles->item_type == ITEM_GOGGLES)
  {
    if(goggles->value[4] != 0)
	  max_dist = goggles->value[4]; 
  }
  for ( dist = 1; dist <= max_dist; )
  {
    if ( IS_SET( pexit->exit_info, EX_CLOSED ) )
    {
      if ( IS_SET( pexit->exit_info, EX_SECRET ) )
	act( AT_GREY, "Your view $t is blocked by a wall.", ch,
	  dir_name[dir], NULL, TO_CHAR );
       else
        act( AT_GREY, "Your view $t is blocked by a door.", ch, 
	  dir_name[dir], NULL, TO_CHAR );
      break;
    }
    
    to_room = NULL;
    if ( pexit->distance > 1 )
       to_room = generate_exit( ch->in_room , &pexit );
    
    if ( to_room == NULL )
       to_room = pexit->to_room;
    
    if ( room_is_private( ch, to_room )
	&& get_trust(ch) < LEVEL_GREATER )
    {
      act( AT_GREY, "Your view $t is blocked by a private room.", ch, 
	dir_name[dir], NULL, TO_CHAR );
      break;
    }
    char_from_room( ch );
    char_to_room( ch, to_room );    
    set_char_color( AT_RMNAME, ch );
    send_to_char( ch->in_room->name, ch );
    send_to_char( "\n\r", ch );
    show_list_to_char( ch->in_room->first_content, ch, FALSE, FALSE );
    show_char_to_char( ch->in_room->first_person, ch );

    dist++;

    if ( dist >= max_dist )
    {
      act( AT_GREY, "Your vision blurs with distance and you see no "
	"farther $t.", ch, dir_name[dir], NULL, TO_CHAR );
      break;
    }
    if ( ( pexit = get_exit( ch->in_room, dir ) ) == NULL )
    {
      act( AT_GREY, "Your view $t is blocked by a wall.", ch, 
	dir_name[dir], NULL, TO_CHAR );
      break;
    }
  }
  
  char_from_room( ch );
  char_to_room( ch, was_in_room );

  return;
}

void do_plantcamera( CHAR_DATA *ch, char *argument )
{
  OBJ_DATA *obj;
  ROOM_INDEX_DATA *room;
  CHAR_DATA *gch;
  AREA_DATA *area;
  char arg[MAX_INPUT_LENGTH];
  bool has_camera;
  bool has_toolkit;
  bool not_alone;
  bool not_linked;
  int chance;

  strcpy( arg , argument );
    
  switch( ch->substate )
   { 
    	default:

	  if ( IS_NPC(ch) )
   		return;
	  has_camera = FALSE;
	  has_toolkit = FALSE;
          for ( obj = ch->last_carrying; obj; obj = obj->prev_content )     
           {
		if( obj->item_type == ITEM_TOOLKIT )
		  has_toolkit = TRUE;
		if( obj->item_type == ITEM_CAMERA )
		  has_camera = TRUE;
	   }
	  if ( !has_toolkit )
	   {
		send_to_char( "&RYou must possess a toolkit in order to do this.&w\n\r", ch );
		return;
	   }
	  if ( !has_camera )
	   {
		send_to_char( "&RYou lack a camera.&w\n\r", ch );
		return;
	   }
  	  if ( ( room = get_room_index( ch->in_room->vnum ) ) == NULL )
   	   {
		send_to_char( "You aren't in a valid room. Notify an IMM.\n\r", ch );
		return;
   	   }
	  not_alone = FALSE;
	  for ( gch = ch->in_room->first_person; gch; gch = gch->next )
	   {
		if( IS_IMMORTAL(ch) )
			break;
		if( gch == ch )
			continue;
		if( IS_NPC(gch) || !is_same_group( ch, gch ) )
			not_alone = TRUE;
	   }
	  if ( not_alone )
	   {
		send_to_char( "&RYou require more privacy for this.&w\n\r", ch );
		return;
	   }
	  chance = 0;
	  chance = IS_NPC(ch) ? ch->top_level
	                 : ( ch->skill_level[SLEIGHT_OF_HAND] + stat_table[get_curr_dex(ch)].mod + number_range(1,20) );
	  if ( chance >= 20 )
	   {
        	send_to_char( "&GYou begin to install a camera.\n\r", ch);
    		act( AT_PLAIN, "$N takes $S tools and starts to install a camera.", NULL,
		        NULL, ch, TO_NOTVICT );
		add_timer ( ch , TIMER_DO_FUN , 25 , do_plantcamera, 1 );
    		ch->dest_buf = str_dup(arg);
    		return;
	   }
	  send_to_char( "&RYou can't figure out how to plant this camera.&w\n\r", ch );
	  return;

    	case 1: 
    		if ( !ch->dest_buf )
    		     return;
    		strcpy(arg, ch->dest_buf);
    		DISPOSE( ch->dest_buf);
    		break;
    		
    	case SUB_TIMER_DO_ABORT:
    		DISPOSE( ch->dest_buf );
    		ch->substate = SUB_NONE;    		                                   
    	        send_to_char("&RYou are interupted and fail to finish your work.\n\r", ch);
    	        return;
   }

 ch->substate = SUB_NONE;
 has_toolkit = FALSE;
 has_camera = FALSE;
 not_alone = FALSE;
 not_linked = FALSE;

 for ( obj = ch->last_carrying; obj; obj = obj->prev_content )     
  {
	if ( obj->item_type == ITEM_TOOLKIT )
		has_toolkit = TRUE;
	if ( obj->item_type == ITEM_CAMERA && has_camera == FALSE )
	 {
	    if( obj->value[0] == 0 )
	     {
		not_linked = TRUE;
		continue;
	     }
	        separate_obj( obj );
          	obj_from_char( obj );
          	extract_obj( obj );
		has_camera = TRUE;
	 }
  }
 if ( !has_camera && not_linked )
  {
	send_to_char( "&GYou must first link the camera to a monitor.&w\n\r", ch );
	return;
  }
 room = get_room_index( ch->in_room->vnum );
 if ( !room )
  {
	send_to_char( "&RNotify an IMM.&w\n\r", ch );	
	return;
  }
 for ( gch = ch->in_room->first_person; gch; gch = gch->next )
  {
	if( IS_IMMORTAL(ch) )
		break;
	if( ch == gch )
		continue;
	if( IS_NPC(gch) || !is_same_group( ch, gch ) )
		not_alone = TRUE;
  }
 if ( not_alone )
  {
	send_to_char( "&RSome has come and disturbed your work.&w\n\r", ch );
	return;
  }
 chance = 0;
 chance = IS_NPC(ch) ? ch->top_level
                : ( ch->skill_level[SLEIGHT_OF_HAND] + stat_table[get_curr_dex(ch)].mod + number_range(1,20) );
                
 if( !has_camera || !has_toolkit || ( 15 > chance ) )
  {
	send_to_char( "&GYou finish installing a new camera, only to realize you've destroyed it.&w\n\r", ch );
	return;
  }
 area = ch->in_room->area;
 if( !area )
  {
	send_to_char( "&GCould not add reset. Inform an IMM.&w\n\r", ch );
	return;
  }
 add_obj_reset( area, 'O', obj, 1, ch->in_room->vnum );
 SET_BIT( obj->extra_flags, ITEM_INSTALLED );
 obj_to_room( obj, room );
 send_to_char( "&GYou successfully installed a camera.&w\n\r", ch );
 act( AT_GREEN, "$N has finished $S work.&w\n\r", NULL, NULL, ch, TO_NOTVICT );
 return;
}

void do_plantmonitor( CHAR_DATA *ch, char *argument )
{
  OBJ_DATA *obj;
  ROOM_INDEX_DATA *room;
  CHAR_DATA *gch;
  AREA_DATA *area;
  char arg[MAX_INPUT_LENGTH];
  bool has_monitor;
  bool has_toolkit;
  bool not_alone;
  bool not_linked;
  int chance;

  strcpy( arg , argument );
    
  switch( ch->substate )
   { 
    	default:

	  if ( IS_NPC(ch) )
   		return;
	  has_monitor = FALSE;
	  has_toolkit = FALSE;
          for ( obj = ch->last_carrying; obj; obj = obj->prev_content )     
           {
		if( obj->item_type == ITEM_TOOLKIT )
		  has_toolkit = TRUE;
		if( obj->item_type == ITEM_MONITOR )
		  has_monitor = TRUE;
	   }
	  if ( !has_toolkit )
	   {
		send_to_char( "&RYou must possess a toolkit in order to do this.&w\n\r", ch );
		return;
	   }
	  if ( !has_monitor )
	   {
		send_to_char( "&RYou lack a monitor.&w\n\r", ch );
		return;
	   }
  	  if ( ( room = get_room_index( ch->in_room->vnum ) ) == NULL )
   	   {
		send_to_char( "You aren't in a valid room. Notify an IMM.\n\r", ch );
		return;
   	   }
	  not_alone = FALSE;
	  for ( gch = ch->in_room->first_person; gch; gch = gch->next )
	   {
		if( IS_IMMORTAL(ch) )
			break;
		if( gch == ch )
			continue;
		if( IS_NPC(gch) || !is_same_group( ch, gch ) )
			not_alone = TRUE;
	   }
	  if ( not_alone )
	   {
		send_to_char( "&RYou require more privacy for this.&w\n\r", ch );
		return;
	   }
	  chance = 0;
	  chance = IS_NPC(ch) ? ch->top_level
	                 : ( ch->skill_level[SLEIGHT_OF_HAND] + stat_table[get_curr_dex(ch)].mod + number_range(1,20) );
	  if ( chance >= 20 )
	   {
        	send_to_char( "&GYou begin to install a monitor.\n\r", ch);
    		act( AT_PLAIN, "$N takes $S tools and starts to install a monitor.", NULL,
		        NULL, ch, TO_NOTVICT );
		add_timer ( ch , TIMER_DO_FUN , 25 , do_plantmonitor, 1 );
    		ch->dest_buf = str_dup(arg);
    		return;
	   }
	  send_to_char( "&RYou can't figure out how to plant this monitor.&w\n\r", ch );
	  return;

    	case 1: 
    		if ( !ch->dest_buf )
    		     return;
    		strcpy(arg, ch->dest_buf);
    		DISPOSE( ch->dest_buf);
    		break;
    		
    	case SUB_TIMER_DO_ABORT:
    		DISPOSE( ch->dest_buf );
    		ch->substate = SUB_NONE;
    	        send_to_char("&RYou are interupted and fail to finish your work.\n\r", ch);
    	        return;
   }

 ch->substate = SUB_NONE;
 has_toolkit = FALSE;
 has_monitor = FALSE;
 not_alone = FALSE;
 not_linked = FALSE;

 for ( obj = ch->last_carrying; obj; obj = obj->prev_content )     
  {
	if ( obj->item_type == ITEM_TOOLKIT )
		has_toolkit = TRUE;
	if ( obj->item_type == ITEM_MONITOR && has_monitor == FALSE )
	 {
	        separate_obj( obj );
          	obj_from_char( obj );
          	extract_obj( obj );
		has_monitor = TRUE;
	 }
  }
 room = get_room_index( ch->in_room->vnum );
 if ( !room )
  {
	send_to_char( "&RNotify an IMM.&w\n\r", ch );	
	return;
  }
 for ( gch = ch->in_room->first_person; gch; gch = gch->next )
  {
	if( IS_IMMORTAL(ch) )
		break;
	if( ch == gch )
		continue;
	if( IS_NPC(gch) || !is_same_group( ch, gch ) )
		not_alone = TRUE;
  }
 if ( not_alone )
  {
	send_to_char( "&RSome has come and disturbed your work.&w\n\r", ch );
	return;
  }
 chance = 0;
 chance = IS_NPC(ch) ? ch->top_level
                : ( ch->skill_level[SLEIGHT_OF_HAND] + stat_table[get_curr_dex(ch)].mod + number_range(1,20) );
                
 if( !has_monitor || !has_toolkit || ( 15 > chance ) )
  {
	send_to_char( "&GYou finish installing a new monitor, only to realize you've destroyed it.&w\n\r", ch );
	return;
  }
 area = ch->in_room->area;
 if( !area )
  {
	send_to_char( "&GCould not add reset. Inform an IMM.&w\n\r", ch );
	return;
  }
 add_obj_reset( area, 'O', obj, 1, room->vnum );
 SET_BIT( obj->extra_flags, ITEM_INSTALLED );
 obj_to_room( obj, room );
 send_to_char( "&GYou successfully installed a monitor.&w\n\r", ch );
 act( AT_GREEN, "$N has finished $S work.&w\n\r", NULL, NULL, ch, TO_NOTVICT );
 return;
}

void do_linkcamera( CHAR_DATA *ch, char *argument )
{
  OBJ_DATA *camera;
  OBJ_DATA *monitor;
  OBJ_DATA *obj;

  if( IS_NPC(ch) || argument[0] == '\0' )
   {
	send_to_char( "&GSyntax: &w&WLinkcamera <camera>&w\n\r", ch );
	return;
   }
  if( ( camera = get_obj_carry( ch, argument ) ) == NULL )
   {
        send_to_char( "You do not have that camera.\n\r", ch );
        return;
   }
  for ( obj = ch->in_room->first_content; obj; obj = obj->next )
   {
	if( obj->item_type == ITEM_MONITOR )
	 {
		monitor = obj;
		break;
	 }
   }
  if( !monitor )
   {
	send_to_char( "&RThere is no monitor here to link to.&w\n\r", ch );
	return;
   }
  camera->value[0] = ch->in_room->vnum;
  act( AT_GREEN, "You link a camera to $p.\n\r", ch, monitor, NULL, TO_CHAR );
  act( AT_GREEN, "$n links a camera to $p.\n\r", ch, monitor, NULL, TO_NOTVICT );
  return;
}

void do_tunemonitor( CHAR_DATA *ch, char *argument )
{
  AREA_DATA *area;
  ROOM_INDEX_DATA *in_room;
  ROOM_INDEX_DATA *iRoom;
  OBJ_DATA *monitor;
  OBJ_DATA *camera;
  char buf[MAX_STRING_LENGTH];
  bool has_monitor=FALSE;
  bool has_camera=FALSE;
  int room;
  int chance=0;

  if( IS_NPC(ch) )
     return;
  in_room = get_room_index( ch->in_room->vnum );
  if( !in_room )
   {
     send_to_char( "&RYou are not in a room. Inform an IMM.&w\n\r", ch );
     return;
   }
  area = in_room->area;
  if( !area )
   {
     send_to_char( "&RYour room is not linked to an Area. Inform an IMM.&w\n\r", ch );
     return;
   }
  for( monitor = in_room->first_content; monitor; monitor = monitor->next )
   {
     if( monitor->item_type == ITEM_MONITOR && IS_SET(monitor->extra_flags, ITEM_INSTALLED) )
      {
 	has_monitor = TRUE;
	break;
      }
   }
  if( !has_monitor )
   {
     send_to_char( "&RThere is no monitor here to tune.&w\n\r", ch );
     return;
   }
  chance = ( number_range(1,20) + ch->skill_level[COMPUTER_SKILL] + stat_table[get_curr_int(ch)].mod );
  if( chance < 17 )
   {
     sprintf( buf, "%s beeps in error.", monitor->name );
     act( AT_GREEN, buf, ch, NULL, NULL, TO_CHAR );
     act( AT_GREEN, buf, ch, NULL, NULL, TO_ROOM );
     return;
   }
  for( room = area->low_r_vnum; room < area->hi_r_vnum; room++ )
   {
     if( ( iRoom = get_room_index( room ) ) == NULL )
	continue;
     if( iRoom->vnum <= in_room->vnum )
	continue;
     for( camera = iRoom->first_content; camera; camera = camera->next )
       if( camera->item_type == ITEM_CAMERA && camera->value[0] == in_room->vnum )
        {
	  has_camera = TRUE;
	  break;
	}
   }
  if( !has_camera )
   {
     for( room = area->low_r_vnum; room < area->hi_r_vnum; room++ )
      {
	if( ( iRoom = get_room_index( room ) ) == NULL )
	  continue;
	if( iRoom->vnum == in_room->vnum )
	  continue;
	for( camera = iRoom->first_content; camera; camera = camera->next )
	 {
	   if( camera->item_type == ITEM_CAMERA && camera->value[0] == in_room->vnum )
	    {
	      has_camera = TRUE;
	      break;
	    }
    	 }
       }
   }
  if( !has_camera )
   {
     send_to_char( "&RThere are no cameras linked to this monitor.&w\n\r", ch );
     return;
   }
  monitor->pIndexData->value[0] = iRoom->vnum;
  sprintf( buf, "%s beeps as it locks into a cameras signal.", monitor->name );
  act( AT_GREEN, buf, ch, monitor, NULL, TO_CHAR );
  act( AT_GREEN, buf, ch, monitor, NULL, TO_ROOM );
  WAIT_STATE(ch, PULSE_VIOLENCE);
  return;
}

void do_checkmonitor( CHAR_DATA *ch, char *argument )
{
  ROOM_INDEX_DATA *iRoom;
  OBJ_DATA *monitor;
  OBJ_DATA *camera;
  char buf[MAX_STRING_LENGTH];
  bool has_monitor=FALSE;
  bool has_camera=FALSE;
  int chance;

  if( IS_NPC(ch) )
    return;
  if( ch->position <= POS_SLEEPING )
   {
     send_to_char( "&RYou can't do that while in your current position.&w\n\r", ch );
     return;
   }
  for( monitor = ch->in_room->first_content; monitor; monitor = monitor->next )
   {
     if( monitor->item_type == ITEM_MONITOR && IS_SET(monitor->extra_flags, ITEM_INSTALLED) )
      {
	has_monitor = TRUE;
	break;
      }
   }
  if( !has_monitor )
   {
     send_to_char( "&RI don't see a monitor here.&w\n\r", ch );
     return;
   }
  iRoom = get_room_index( monitor->value[0] );
  if( !iRoom )
   {
     send_to_char( "&RThis monitor isn't linked to any cameras.&w\n\r", ch );
     return;
   }
  for( camera = iRoom->first_content; camera; camera = camera->next )
   {
     if( camera->item_type == ITEM_CAMERA && camera->value[0] == ch->in_room->vnum )
      {
	has_camera = TRUE;
	break;
      }
   }
  if( !has_camera )
   {
     send_to_char( "&RThis monitor isn't connected to any cameras.&w\n\r", ch );
     return;
   }
  chance = ( number_range(1,20) + ch->skill_level[COMPUTER_SKILL] + stat_table[get_curr_int(ch)].mod );
  if( chance < 17 )
   {
     sprintf( buf, "%s beeps in error.", monitor->name );
     act( AT_GREEN, buf, ch, monitor, NULL, TO_ROOM );
     act( AT_GREEN, buf, ch, monitor, NULL, TO_CHAR );
     WAIT_STATE( ch, PULSE_VIOLENCE );
     return;
   }
  ch_printf(ch, "&R-=&r( &G&W%s &G&r)&R=-&C&w ", iRoom->name);
  if ( ! ch->desc->original )
   {
    if ((get_trust(ch) >= LEVEL_IMMORTAL) && (IS_SET(ch->pcdata->flags, PCFLAG_ROOM)))
     {
      set_char_color(AT_BLUE, ch);
      send_to_char("{", ch);
      ch_printf(ch, "&G&W%d", iRoom->vnum);
      set_char_color(AT_BLUE, ch);
      send_to_char("}", ch);
      set_char_color(AT_CYAN, ch);	 
      send_to_char("[", ch); 
      send_to_char(" ", ch);
      set_char_color(AT_WHITE, ch);
      send_to_char(flag_string(iRoom->room_flags, r_flags), ch);
      send_to_char(" ", ch);
      if( iRoom->room_flags2 != 0)
       {
         set_char_color(AT_DGREEN, ch);
         send_to_char(flag_string(iRoom->room_flags2, r_flags2), ch);
         send_to_char(" ", ch);
       }
      set_char_color(AT_CYAN, ch);
      send_to_char("]", ch);
     }
         
   }
  send_to_char( "\n\r", ch );
  set_char_color( AT_RMDESC, ch ); 	
	
  if ( !IS_NPC(ch) && !IS_SET(ch->act, PLR_BRIEF) )
    send_to_char( iRoom->description, ch );
	
  if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_AUTOEXIT) )
    do_exits( ch, "" );

  show_ships_to_char( iRoom->first_ship, ch );
  show_list_to_char( iRoom->first_content, ch, FALSE, FALSE );
  show_char_to_char( iRoom->first_person,  ch );
  return;
}