mud_dist/area/
/***************************************************************************
 *  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.                              *
 *                                                                         *
 *  Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David   *
 *  Love, Guilherme 'Willie' Arnold, 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.                                                  *
 ***************************************************************************/

/*$Id: act_obj2.c,v 1.25 2005/04/11 03:24:38 tyrion Exp $*/

#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"

extern char* target_name;

int skill_depoison_weapon( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA *obj;

    if ( target_name[0] == '\0' )                                              
    { send_to_char(AT_DGREEN, "What are you trying to poison?\n\r",    ch ); return SKPELL_BOTCHED; }
    if ( ch->fighting )                                       
    { send_to_char(AT_DGREEN, "While you're fighting?  I think not.\n\r", ch ); return SKPELL_BOTCHED; }
    if ( !( obj = get_obj_carry( ch, target_name ) ) )
    { send_to_char(AT_DGREEN, "You do not have that item.\n\r",      ch ); return SKPELL_BOTCHED; }
    if ( !IS_OBJ_STAT( obj, ITEM_POISONED ) )
    { send_to_char(AT_DGREEN, "That item is not poisoned.\n\r",  ch ); return SKPELL_BOTCHED; }

    /* Now we have a valid weapon...check to see if we have the powder. */

    /* Great, we have the ingredients...but is the thief smart enough? */
    if ( !IS_NPC( ch ) && get_curr_wis( ch ) < 19 )
    {
	send_to_char(AT_DGREEN, "You can't quite remember what to do...\n\r", ch );
	return SKPELL_BOTCHED;
    }
    /* And does the thief have steady enough hands? */
    if ( !IS_NPC( ch )
	&& ( get_curr_dex( ch ) < 20
	    || ch->pcdata->condition[COND_DRUNK] > 0 ) )
    {
	send_to_char(AT_DGREEN,
	"Your hands aren't steady enough to properly remove the poison.\n\r",
								ch );
	return SKPELL_BOTCHED;
    }

    WAIT_STATE( ch, skill_table[sn].beats );

  
    /* Well, I'm tired of waiting.  Are you? */
    act(AT_GREEN, "You remove the deadly poison!",
	ch, NULL, NULL, TO_CHAR );
    act(AT_GREEN, "$n removes the deadly poison!",
	ch, NULL, NULL, TO_ROOM );
    act(AT_GREEN, "You strip the poison from $p, which loses its wicked luster!",
	ch, obj, NULL, TO_CHAR  );
    act(AT_GREEN, "$n strips the poison from $p, which loses its wicked luster!",
	ch, obj, NULL, TO_ROOM  );
    REMOVE_BIT( obj->extra_flags, ITEM_POISONED );


    /* WHAT?  All of that, just for that one bit?  How lame. ;) */
    return SKPELL_NO_DAMAGE;
}

void do_acmorph ( CHAR_DATA *ch, OBJ_DATA *obj, int  vnum )
{
    OBJ_INDEX_DATA *pObjIndex;
    OBJ_DATA       *nObj;
    int             level;
    
    level = 0;
    act( AT_BLUE, "You invoke $p.", ch, obj, NULL, TO_CHAR );
    act( AT_BLUE, "$n invokes $p.", ch, obj, NULL, TO_ROOM ); 
 
    if ( !(pObjIndex = get_obj_index( vnum ) ) )
       {
         act( AT_BLUE, "$p whines and sparks, but nothing happens", ch, obj, NULL, TO_CHAR );
         return;
       }
    level = pObjIndex->level;
    nObj = create_object( pObjIndex, level );
    if ( CAN_WEAR( nObj, ITEM_TAKE ) )
    {
	obj_to_char( nObj, ch );
    }
    else
    {
	obj_to_room( nObj, ch->in_room );
    }

    act(AT_BLUE, "$p's form wavers, then solidifies as $P.", ch, obj, nObj, TO_CHAR );
    act(AT_BLUE, "$n's $p wavers in form. then solidifies as $P.", ch, obj, nObj, TO_ROOM );
    oprog_invoke_trigger( obj, ch, nObj );
    extract_obj( obj );
    return;    
}        
    
void do_acoload( CHAR_DATA *ch, OBJ_DATA *obj, int  vnum )
{
    OBJ_INDEX_DATA *pObjIndex;
    OBJ_DATA       *nObj;
    int             level;
    
    level = 0;
    act( AT_BLUE, "You invoke $p.", ch, obj, NULL, TO_CHAR );
    act( AT_BLUE, "$n invokes $p.", ch, obj, NULL, TO_ROOM ); 
 
    if ( !(pObjIndex = get_obj_index( vnum ) ) )
       {
         act( AT_BLUE, "$p whines and sparks, but nothing happens", ch, obj, NULL, TO_CHAR );
         return;
       }
    level = pObjIndex->level;
    nObj = create_object( pObjIndex, level );
    if ( CAN_WEAR( nObj, ITEM_TAKE ) )
    {
	obj_to_char( nObj, ch );
    }
    else
    {
	obj_to_room( nObj, ch->in_room );
    }
    act(AT_BLUE, "$p spawns $P.", ch, obj, nObj, TO_CHAR );
    act(AT_BLUE, "$n's $p spawns $P.", ch, obj, nObj, TO_ROOM );
    oprog_invoke_trigger( obj, ch, nObj );

    return;    
}        

void do_acmload( CHAR_DATA *ch, OBJ_DATA *obj, int vnum )
{
    CHAR_DATA      *victim;
    MOB_INDEX_DATA *pMobIndex;
    AFFECT_DATA af;
    
    act( AT_BLUE, "You invoke $p.", ch, obj, NULL, TO_CHAR );
    act( AT_BLUE, "$n invokes $p.", ch, obj, NULL, TO_ROOM ); 

    if ( !( pMobIndex = get_mob_index( vnum ) ) )
    {
         act( AT_BLUE, "$p whines and sparks, but nothing happens", ch, obj, NULL, TO_CHAR );
         return;
    }
    victim = create_mobile( pMobIndex );
    char_to_room( victim, ch->in_room );
    
    act(AT_BLUE, "$p spawns $N.", ch, obj, victim, TO_CHAR );
    act(AT_BLUE, "$n's $p spawns $N.", ch, obj, victim, TO_ROOM );
    if ( victim->master )
	stop_follower( victim );
    add_follower( victim, ch );
    af.type      = skill_lookup( "charm person" );
    af.duration  = 50;
    af.location  = APPLY_NONE;
    af.modifier  = 0;
    af.bitvector = AFF_CHARM;
    affect_to_char( victim, &af );
    oprog_invoke_trigger( obj, ch, victim );
    
    return;
}

void do_actrans( CHAR_DATA *ch, OBJ_DATA *obj, int vnum )
{
    ROOM_INDEX_DATA *location;

    act( AT_BLUE, "You invoke $p.", ch, obj, NULL, TO_CHAR );
    act( AT_BLUE, "$n invokes $p.", ch, obj, NULL, TO_ROOM ); 

    if ( !( location = get_room_index( vnum ) ) )
    {
	act(AT_BLUE, "$p whines and sparks, but nothing happens.", ch, obj, NULL, TO_CHAR );
	return;
    }

    if ( room_is_private( location ) )
    {
	send_to_char(AT_BLUE, "That room is private right now.\n\r", ch );
	return;
    }

    if ( ch->fighting )
    {
        act( AT_BLUE, "$p pulses lightly, but fails to function.", ch, obj, NULL, TO_CHAR );
        return;
    }

    if ( IS_SET(location->room_flags, ROOM_SAFE) && ch->pkill && (ch->combat_timer>0))
    {
	send_to_char(AT_BLUE, "Your blood runs to hot to go into that room!\n\r", ch);
        return;
    } 

    act(AT_BLUE, "Everything begins to spin, when it clears you are elsewhere.", ch, obj, NULL, TO_CHAR );
    act(AT_BLUE, "$n invokes $p and vanishes in a swirling red mist.", ch, obj, NULL, TO_ROOM );
    char_from_room( ch );
    char_to_room( ch, location );
    act(AT_BLUE, "$n arrives in a swirling red mist.", ch, obj, NULL, TO_ROOM);
    do_look( ch, "auto" );
    oprog_invoke_trigger( obj, ch, ch );
    return;
}

void do_invoke( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA       *obj;
    CHAR_DATA      *rch;
    CHAR_DATA      *victim;
    char            arg1 [ MAX_INPUT_LENGTH ];
    char            arg2 [ MAX_INPUT_LENGTH ];
    char            spellarg [ MAX_INPUT_LENGTH ];
    
    if ( IS_NPC(ch) )
      return;

    rch = get_char( ch );
    
    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
 
    if ( !(obj = get_obj_carry( ch, arg1 ) ) && ( !(obj = get_obj_wear( ch, arg1 ) ) ) )
    {
	send_to_char( AT_WHITE, "You can't find it.\n\r", ch );
	return;
    }
    
    if ( (ch->level < obj->level) && (ch->multied == ch->class) )
    {
	send_to_char(AT_BLUE, "You have not attained the level of mastery to use this item", ch );
	act(AT_BLUE, "$n tries to use $p, but is too inexperienced.",
	    ch, obj, NULL, TO_ROOM );
	return;
    }
    
    if ( obj->ac_type <= 0 || obj->ac_type >= 6 )
    {
        act( AT_WHITE, "$p cannot be invoked.", ch, obj, NULL, TO_CHAR );
        return;
    }
    if ( obj->ac_type == 5 && !obj->ac_spell )
    {
      sprintf( log_buf, "Obj[%d] AcType Spell with no Spellname",
         obj->pIndexData->vnum );
      bug( log_buf, 0 );
      act( AT_WHITE, "$p cannot be invoked.", ch, obj, NULL, TO_CHAR );
      return;
    }
    
    if ( arg2[0] == '\0' )
       victim = rch;
    else
       if ( !(victim = get_char_world( ch, arg2 ) ) )
          {
           send_to_char( AT_WHITE, "There is no such person in existance.\n\r", ch );
           return;
          }

    if ( !IS_NPC( ch ) ) {
    if (   ( IS_OBJ_STAT( obj, ITEM_ANTI_EVIL     ) && IS_EVIL   ( ch ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_GOOD     ) && IS_GOOD   ( ch ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_NEUTRAL  ) && IS_NEUTRAL( ch ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_MAGE     ) && ( ch->class == CLASS_MAGE || ch->multied == CLASS_MAGE ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_CLERIC   ) && ( ch->class == CLASS_CLERIC || ch->multied == CLASS_CLERIC ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_THIEF    ) && ( ch->class == CLASS_THIEF || ch->multied == CLASS_THIEF ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_WARRIOR  ) && ( ch->class == CLASS_WARRIOR || ch->multied == CLASS_WARRIOR ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_PSI      ) && ( ch->class == CLASS_PSIONICIST || ch->multied == CLASS_PSIONICIST ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_DRUID    ) && ( ch->class == CLASS_DRUID || ch->multied == CLASS_DRUID ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_RANGER   ) && ( ch->class == CLASS_RANGER || ch->multied == CLASS_RANGER ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_PALADIN  ) && ( ch->class == CLASS_PALADIN || ch->multied == CLASS_PALADIN ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_BARD     ) && ( ch->class == CLASS_BARD || ch->multied == CLASS_BARD ) )
	|| ( IS_OBJ_STAT( obj, ITEM_ANTI_VAMP     ) && ( ch->class == CLASS_VAMPIRE || ch->multied == CLASS_VAMPIRE) ) 
	|| ( IS_OBJ_STAT2( obj, ITEM_ANTI_WEREWOLF ) && ( ch->class == CLASS_WEREWOLF || ch->multied == CLASS_WEREWOLF ) ) 
	|| ( IS_OBJ_STAT2( obj, ITEM_ANTI_ANTIPAL  ) && ( ch->class == CLASS_ANTI_PALADIN || ch->multied == CLASS_ANTI_PALADIN ) ) 
	|| ( IS_OBJ_STAT2( obj, ITEM_ANTI_ASSASSIN ) && ( ch->class == CLASS_ASSASSIN || ch->multied == CLASS_ASSASSIN ) )
	|| ( IS_OBJ_STAT2( obj, ITEM_ANTI_MONK     ) && ( ch->class == CLASS_MONK || ch->multied == CLASS_MONK ) )
	|| ( IS_OBJ_STAT2( obj, ITEM_ANTI_BARBARIAN) && ( ch->class == CLASS_BARBARIAN || ch->multied == CLASS_BARBARIAN ) )
	|| ( IS_OBJ_STAT2( obj, ITEM_ANTI_ILLUSIONIST) && ( ch->class == CLASS_ILLUSIONIST || ch->multied == CLASS_ILLUSIONIST ) ) 
      || ( IS_OBJ_STAT2( obj, ITEM_ANTI_NECROMANCER ) && ( ch->class == CLASS_NECROMANCER || ch->multied == CLASS_NECROMANCER ) )
      || ( IS_OBJ_STAT2( obj, ITEM_ANTI_DEMONOLOGIST ) && ( ch->class == CLASS_DEMONOLOGIST || ch->multied == CLASS_DEMONOLOGIST ) )
	|| ( IS_OBJ_STAT2( obj, ITEM_ANTI_SHAMAN ) && ( ch->class == CLASS_SHAMAN || ch->multied == CLASS_SHAMAN ) )
      || ( IS_OBJ_STAT2( obj, ITEM_ANTI_DARKPRIEST ) && ( ch->class == CLASS_DARKPRIEST || ch->multied == CLASS_DARKPRIEST ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_MAGE     ) && ( ch->class != CLASS_MAGE && ch->multied != CLASS_MAGE ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_CLERIC   ) && ( ch->class != CLASS_CLERIC && ch->multied != CLASS_CLERIC ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_THIEF    ) && ( ch->class != CLASS_THIEF && ch->multied != CLASS_THIEF ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_WARRIOR  ) && ( ch->class != CLASS_WARRIOR && ch->multied != CLASS_WARRIOR ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_PSI      ) && ( ch->class != CLASS_PSIONICIST && ch->multied != CLASS_PSIONICIST ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_DRUID    ) && ( ch->class != CLASS_DRUID && ch->multied != CLASS_DRUID ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_RANGER   ) && ( ch->class != CLASS_RANGER && ch->multied != CLASS_RANGER ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_PALADIN  ) && ( ch->class != CLASS_PALADIN && ch->multied != CLASS_PALADIN ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_BARD     ) && ( ch->class != CLASS_BARD && ch->multied != CLASS_BARD ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_VAMP     ) && ( ch->class != CLASS_VAMPIRE && ch->multied != CLASS_VAMPIRE) ) 
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_WEREWOLF ) && ( ch->class != CLASS_WEREWOLF && ch->multied != CLASS_WEREWOLF ) ) 
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_ANTIPAL  ) && ( ch->class != CLASS_ANTI_PALADIN && ch->multied != CLASS_ANTI_PALADIN ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_ASSASSIN ) && ( ch->class != CLASS_ASSASSIN && ch->multied != CLASS_ASSASSIN ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_MONK     ) && ( ch->class != CLASS_MONK && ch->multied != CLASS_MONK ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_BARBARIAN) && ( ch->class != CLASS_BARBARIAN && ch->multied != CLASS_BARBARIAN ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_ILLUSIONIST) && ( ch->class != CLASS_ILLUSIONIST && ch->multied != CLASS_ILLUSIONIST ) ) 
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_NECROMANCER ) && ( ch->class != CLASS_NECROMANCER && ch->multied != CLASS_NECROMANCER ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_DEMONOLOGIST ) && ( ch->class != CLASS_DEMONOLOGIST && ch->multied != CLASS_DEMONOLOGIST ) )
	|| ( IS_OBJ_STAT3( obj, ITEM_PRO_SHAMAN ) && ( ch->class != CLASS_SHAMAN && ch->multied != CLASS_SHAMAN ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_DARKPRIEST ) && ( ch->class != CLASS_DARKPRIEST && ch->multied != CLASS_DARKPRIEST ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_HUMAN )    && ( ch->race != 0 ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_ELF )      && ( ch->race != 1 ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_HALFELF )  && ( ch->race != 2 ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_ORC )      && ( ch->race != 3 ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_DROW )     && ( ch->race != 4 ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_DWARF )    && ( ch->race != 5 ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_HALFDWARF )&& ( ch->race != 6 ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_HOBBIT )   && ( ch->race != 7 ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_GIANT )    && ( ch->race != 8 ) )
      || ( IS_OBJ_STAT3( obj, ITEM_PRO_OGRE )     && ( ch->race != 9 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_ANGEL )    && ( ch->race != 10 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_MINOTAUR ) && ( ch->race != 11 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_FELINE )   && ( ch->race != 12 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_GARGOYLE ) && ( ch->race != 20 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_CANINE )   && ( ch->race != 14 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_DEMON )    && ( ch->race != 15 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_PIXIE )    && ( ch->race != 16 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_ELDER )    && ( ch->race != 17 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_LIZARDMAN )&& ( ch->race != 18 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_PRO_GNOME )    && ( ch->race != 19 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_HUMAN )    && ( ch->race == 0 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_ELF )      && ( ch->race == 1 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_HALFELF )  && ( ch->race == 2 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_ORC )      && ( ch->race == 3 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_DROW )     && ( ch->race == 4 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_DWARF )    && ( ch->race == 5 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_HALFDWARF )&& ( ch->race == 6 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_HOBBIT )   && ( ch->race == 7 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_GIANT )    && ( ch->race == 8 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_OGRE )     && ( ch->race == 9 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_ANGEL )    && ( ch->race == 10 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_MINOTAUR ) && ( ch->race == 11 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_FELINE )   && ( ch->race == 12 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_GARGOYLE ) && ( ch->race == 20 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_CANINE )   && ( ch->race == 14 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_DEMON )    && ( ch->race == 15 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_PIXIE )    && ( ch->race == 16 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_ELDER )    && ( ch->race == 17 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_LIZARDMAN )&& ( ch->race == 18 ) )
      || ( IS_OBJ_STAT4( obj, ITEM_ANTI_GNOME )    && ( ch->race == 19 ) ) )

    {
	act(AT_BLUE, "You are zapped by $p and drop it.", ch, obj, NULL, TO_CHAR );
	act(AT_BLUE, "$n is zapped by $p and drops it.",  ch, obj, NULL, TO_ROOM );
	obj_from_char( obj );
	obj_to_room( obj, ch->in_room );
	return;
    } else if (IS_OBJ_STAT2( obj, ITEM_LEGEND ) && !IS_LEGEND( ch ) )
    {
	act(AT_BLUE, "You somehow don't feel powerful enough for $p and set it on the ground...", ch, obj, NULL, TO_CHAR);
        act(AT_BLUE, "$n attempts to wear $p, thinks better of it and sets it on the ground.",  ch, obj, NULL, TO_ROOM );

        obj_from_char( obj );
        obj_to_room( obj, ch->in_room );
        return;
    }
    }

    switch ( obj->ac_type )
    {
    default:   break;
    case 1:    do_acoload( ch, obj, obj->ac_vnum ); break;
    case 2:    do_acmload( ch, obj, obj->ac_vnum ); break;
    case 3:    do_actrans( ch, obj, obj->ac_vnum ); break;
    case 4:    do_acmorph( ch, obj, obj->ac_vnum ); break;
    case 5:    
        {
         spellarg[0] = '\0';
         sprintf( spellarg, "'%s' %s", obj->ac_spell, arg2 );
         do_acspell( ch, obj, spellarg );
         break;
        }
    }
    if ( obj->ac_charge[1] != -1 )
    if ( -- obj->ac_charge[0] <= 0 )
    {
	act(AT_WHITE, "Your $p sputters and sparks.", ch, obj, NULL, TO_CHAR );
	act(AT_WHITE, "$n's $p sputters and sparks..", ch, obj, NULL, TO_ROOM );
	obj->ac_type = 0;
	obj->ac_spell = " ";
	obj->ac_vnum = 0;
    }

    return;
}      

int skill_voodo ( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA   *obj;
    CHAR_DATA  *victim;
    char        buf [MAX_STRING_LENGTH];
    char       *name;
    

    if( ch->summon_timer > 0 )
    {
	send_to_char(C_DEFAULT, "You try to get it to work, but nothing happens.\n\r", ch );
	return SKPELL_MISSED;
    }

    buf[0] = '\0';
    
    if ( !(victim = get_char_world( ch, target_name ) ) )
       {
        send_to_char( AT_RED, "No such person exists.", ch );
        return SKPELL_MISSED;
       }
    if ( saves_spell( ch->level, victim ) )
     {
      send_to_char( AT_RED, "You failed.\n\r", ch );
      return SKPELL_MISSED;
     } 
    if (IS_NPC(victim))
       name	  = victim->short_descr;
    else
       name       = victim->name;
    obj = create_object ( get_obj_index( OBJ_VNUM_DOLL ), 0 );
    sprintf( buf, obj->short_descr, name );
    free_string( obj->short_descr );
    obj->short_descr = str_dup( buf );
    free_string( obj->name );
    obj->name = str_dup( target_name );
    obj->timer = 10;
    ch->summon_timer = 10;
    obj_to_char(obj, ch);
    act(AT_RED, "You call upon the Gods to create $p.", ch, obj, NULL, TO_CHAR );
    act(AT_RED, "$n calls upon the Gods to create $p.", ch, obj, NULL, TO_ROOM );
    
	return SKPELL_NO_DAMAGE;
}     

void do_repair ( CHAR_DATA *ch, char *argument )
{

  char       arg[MAX_STRING_LENGTH];
  OBJ_DATA  *pObj;
  int        cost;
  char	     buf[MAX_STRING_LENGTH];
  
  if (IS_NPC(ch))
     return;
  if ( !IS_SET( ch->in_room->room_flags, ROOM_SMITHY ) )
  {
    send_to_char(AT_WHITE, "You are not within a smithy.\n\r", ch );
    return;
  }
  one_argument( argument, arg );
  if ( !str_cmp( arg, "all" ) )
    {
      char buf[MAX_STRING_LENGTH];
      for ( pObj = ch->carrying; pObj; pObj = pObj->next_content )
	{
	  if ( pObj->wear_loc == WEAR_NONE )
	    continue;
	  if ( pObj->durability_cur >= pObj->durability_max )
	    continue;
	  if ( pObj->durability_max <= 10 )
	  {
		sprintf( buf, "Your '%s' can no longer be repaired.\n\r", pObj->short_descr );
		send_to_char(AT_WHITE, buf, ch );
		continue;
	  }
	  cost = (pObj->durability_max - pObj->durability_cur) * pObj->weight * ( pObj->level / 4 );
	  switch (pObj->item_type)
	  {
	  case ITEM_WEAPON:
	    break;
	  case ITEM_ARMOR:
	    break;
	  default:
	    bug("Do_repair: Item not weapon or armor.",0);
	    break;
	  }

	  if ( cost <= 0 )
	    cost = 1;

	  if ( cost > ch->gold )
	    {
	      sprintf(buf, "$p will cost %d, you lack the funds.", cost );
	      act(AT_WHITE,buf,ch,pObj,NULL,TO_CHAR);
	      continue;
	    }
	  ch->gold -= cost;
	  pObj->cost = pObj->pIndexData->cost;
	  pObj->durability_max -= 1;
	  pObj->durability_cur = pObj->durability_max;	
	  REMOVE_BIT(pObj->extra_flags, ITEM_PATCHED);
	  sprintf(buf, "You are charged %d for repairing $p.", cost );
	  act(AT_WHITE,buf,ch,pObj,NULL,TO_CHAR);
	  if ( pObj->durability_max <= 10 )
	  {
		sprintf( buf, "Your '%s' can no longer be repaired.\n\r", pObj->short_descr );
		send_to_char(AT_WHITE, buf, ch );
	  }
	}
      return;
    }

  if (!( pObj = get_obj_carry ( ch, arg ) ) )
    {
      send_to_char (AT_WHITE, "You do not see that here.\n\r", ch );
      return;
    }
   
  if ( pObj->durability_max <= 10 )
   {
     sprintf( buf, "Your '%s' can not be repaired.\n\r", pObj->short_descr );
     send_to_char(AT_WHITE, buf, ch );
     return;  
   }

  if ( pObj->durability_max == pObj->durability_cur )
   {
     send_to_char(AT_WHITE, "That item is not damaged.\n\r", ch );
     return;  
   }

  cost = (pObj->pIndexData->cost - pObj->cost);
  switch( pObj->item_type )
  {
  case ITEM_WEAPON:
    cost = cost * pObj->value[1] / pObj->value[2];
    break;
  case ITEM_ARMOR:
    cost = cost * pObj->level / pObj->value[0];
    break;
  default:
    bug("Do_repair: Item not weapon or armor.", 0);
    break;
  }

  if ( cost <= 0 )
    cost = 1;

  if ( ch->gold < cost )
   {
     char    buf[MAX_STRING_LENGTH];
     
     sprintf(buf, "That item will cost %d, you lack the funds.\n\r", cost );
     send_to_char( AT_WHITE, buf, ch );
     return;
   }
  else
   {
     char     buf[MAX_STRING_LENGTH];
     
     sprintf( buf, "You are charged %d for repairing %s.\n\r", cost, pObj->short_descr );
     ch->gold -= cost;
     send_to_char ( AT_WHITE, buf, ch );
     pObj->cost = pObj->pIndexData->cost;
     pObj->durability_max -= 1;
     if ( pObj->durability_max <= 10 )
     {
	sprintf( buf, "Your '%s' can no longer be repaired.\n\r", pObj->short_descr );
	send_to_char(AT_WHITE, buf, ch );
     }
     pObj->durability_cur = pObj->durability_max;	

     REMOVE_BIT(pObj->extra_flags, ITEM_PATCHED);
     return;
   }
  return;

}

void do_account( CHAR_DATA *ch, char *argument )
{
  char arg[MAX_STRING_LENGTH];
  
  if (IS_NPC( ch ) )
    return;
  else
  {
    if ( !IS_SET( ch->in_room->room_flags, ROOM_BANK ) )
    {
      send_to_char(AT_WHITE, "You are not in a bank!\n\r", ch );
      return;
    }
    
    if ( ch->pcdata->bankaccount > 0 )
    {
      sprintf( arg, "You have %d coin%s in your account.\n\r",
               ch->pcdata->bankaccount, 
               ch->pcdata->bankaccount > 1 ? "s" : "" );
      send_to_char(AT_WHITE, arg, ch );
      return;
    }
    else
    {
    int len = 0;
    len = strlen( ch->name );
      send_to_char(AT_WHITE, "You have nothing in your account!\n\r", ch );
      sprintf( arg, "&wFrom the shocked look on $n'%s face, you can tell that they have nothing in their account.",
      		    ch->name[len] == 's' ? "" : "s" );
      act(AT_WHITE, arg, ch, NULL, NULL, TO_ROOM );
      return;
    }
  }
  return;
}         
  
void do_separate( CHAR_DATA *ch, char *argument )
{
  OBJ_DATA *Obj;
  OBJ_DATA *aObj;
  OBJ_DATA *bObj;
  OBJ_INDEX_DATA *pIndex;

  if ( !( Obj = get_obj_carry( ch, argument ) ) )
  {
    send_to_char( AT_WHITE, "You are not carrying that item.\n\r", ch );
    return;
  }

  if ( !get_obj_index( Obj->pIndexData->sep_one ) ||
       !get_obj_index( Obj->pIndexData->sep_two ) )
  {
    send_to_char( AT_WHITE, "It cannot be separated.\n\r", ch );
    return;
  }

  pIndex = get_obj_index( Obj->pIndexData->sep_one );
  aObj = create_object( pIndex, pIndex->level );

  pIndex = get_obj_index( Obj->pIndexData->sep_two );
  bObj = create_object( pIndex, pIndex->level );
  sprintf( log_buf, "$n separates $p into %s and %s.\n\r",
           aObj->name, bObj->name );
  act( AT_WHITE, log_buf, ch, Obj, NULL, TO_ROOM );

  oprog_separate_trigger( Obj, ch );
  obj_from_char( Obj );
  extract_obj( Obj );
  obj_to_char( aObj, ch );
  obj_to_char( bObj, ch );
  send_to_char( AT_WHITE, "The object is now separated.\n\r", ch );
}

void do_join( CHAR_DATA *ch, char *argument )
{
  OBJ_DATA *aObj;
  OBJ_DATA *bObj;
  OBJ_DATA *Obj;
  OBJ_INDEX_DATA *pIndex;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];

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

  if ( !(aObj = get_obj_carry(ch, arg1)) )
  {
    char buf[MAX_STRING_LENGTH];

    sprintf( buf, "You are not carrying any %s.\n\r", arg1 );
    send_to_char( AT_WHITE, buf, ch );
    return;
  }

  if ( !(bObj = get_obj_carry(ch, arg2)) )
  {
    char buf[MAX_STRING_LENGTH];

    if (strlen( arg2 ) > 0 )
    {
    sprintf( buf, "You are not carrying any %s.\n\r", arg2 );
    send_to_char( AT_WHITE, buf, ch );
    return;
    }
    else 
    if (strlen( arg2 ) <= 0 )
    {
    send_to_char( AT_WHITE, "What's that?\n\r", ch );
    return;
    }
  }

  if ( aObj->pIndexData->join != bObj->pIndexData->join ||
       aObj->pIndexData == bObj->pIndexData || 
      !get_obj_index( aObj->pIndexData->join ) )
  {
    char buf[MAX_STRING_LENGTH];

    sprintf( buf, "%s cannot be joined with %s.\n\r",
	    capitalize( aObj->short_descr ), bObj->short_descr );
    send_to_char( AT_WHITE, buf, ch );
    return;
  }
  oprog_join_trigger( aObj, ch, bObj );
  pIndex = get_obj_index( aObj->pIndexData->join );
  Obj = create_object( pIndex, pIndex->level );
  obj_to_char( Obj, ch );
  sprintf( log_buf, "$n joins $p to $P to create %s.\n\r", Obj->short_descr );
  act( AT_WHITE, log_buf, ch, aObj, bObj, TO_ROOM );

  obj_from_char( aObj );
  extract_obj( aObj );
  obj_from_char( bObj );
  extract_obj( bObj );
  send_to_char( AT_WHITE, "Objects joined.\n\r", ch );
}

/*
 * -- Altrag
 */
/*
 * -- Altrag Dalosein
 */
void do_patch( CHAR_DATA *ch, char *argument )
{
  OBJ_DATA *obj;
  int ammount;
  int sn = skill_lookup("patched");

  if ( IS_NPC( ch ) )
    return;

  if ( ch->pcdata->learned[sn] <= 0 )
  {
    send_to_char(C_DEFAULT, "You don't know how to patch equipment.\n\r",ch);
    return;
  }

  if ( !( obj = get_obj_carry( ch, argument ) ) )
  {
    send_to_char(C_DEFAULT, "You do not have that item.\n\r",ch);
    return;
  }

  if ( obj->item_type != ITEM_WEAPON && obj->item_type != ITEM_ARMOR )
  {
    send_to_char(C_DEFAULT, "You may only repair weapons and armor.\n\r",ch);
    return;
  }

  if ( IS_SET(obj->extra_flags, ITEM_PATCHED) )
  {
    send_to_char(C_DEFAULT, "You can't do much more for it.\n\r",ch);
    return;
  }

  if ( obj->cost >= obj->pIndexData->cost )
  {
    send_to_char(C_DEFAULT, "It already looks like new.\n\r",ch);
    return;
  }

  ammount = ch->pcdata->learned[sn] / 20;
  ammount = (ammount * (obj->pIndexData->cost - obj->cost)) / 100;
  obj->cost += ammount;
  SET_BIT(obj->extra_flags, ITEM_PATCHED);

  act(AT_WHITE,"$n repairs his $p a bit.",ch,obj,NULL,TO_ROOM);
  act(AT_WHITE,"You do your best to repair your $p.",ch,obj,NULL,TO_CHAR);
  return;
}

int skill_devour( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA *obj;
    int       amnt;

    if ( target_name[0] == '\0' )
    {
	send_to_char(AT_ORANGE, "Devour what?\n\r", ch );
	return SKPELL_MISSED;
    }

    if ( !( obj = get_obj_carry( ch, target_name ) ) )
    {
	send_to_char(AT_ORANGE, "You do not have that item.\n\r", ch );
	return SKPELL_MISSED;
    }

    if ( !IS_IMMORTAL( ch ) )
    {
	if ( !IS_NPC( ch ) && ch->pcdata->condition[COND_FULL] > 40 )
	{   
	    send_to_char(AT_ORANGE, "You are too full to eat more.\n\r", ch );
	    return SKPELL_BOTCHED;
	}
    }

    act(AT_ORANGE, "You eat $p.", ch, obj, NULL, TO_CHAR );
    act(AT_ORANGE, "$n eats $p.", ch, obj, NULL, TO_ROOM );

    switch ( obj->item_type )
    {

    case ITEM_FOOD:
	if ( !IS_NPC( ch ) )
	{
	    int condition;

	    condition = ch->pcdata->condition[COND_FULL];
	    gain_condition( ch, COND_FULL, obj->value[0] );
	    if ( ch->pcdata->condition[COND_FULL] > 40 )
	        send_to_char(AT_ORANGE, "You are full.\n\r", ch );
	    else if ( condition == 0 && ch->pcdata->condition[COND_FULL] > 0 )
		send_to_char(AT_ORANGE, "You are no longer hungry.\n\r", ch );
	}

	if ( obj->value[3] != 0 )
	{
	    /* The shit was poisoned! */
	    AFFECT_DATA af;

	    act(AT_GREEN, "$n chokes and gags.", ch, 0, 0, TO_ROOM );
	    send_to_char(AT_GREEN, "You choke and gag.\n\r", ch );

	    af.type      = skill_lookup("poison");
	    af.duration  = 2 * obj->value[0];
	    af.location  = APPLY_STR;
	    af.modifier  = -2;
	    af.bitvector = AFF_POISON;
	    affect_join( ch, &af );
	    add_poison( ch, obj->value[0] );
	}
	break;
    case ITEM_BERRY:
       amnt = number_range( obj->value[0], obj->value[1] );
       ch->hit = UMIN( ch->hit + amnt, ch->max_hit );
       update_pos( ch );
       send_to_char(AT_ORANGE, "You feel warm all over.\n\r", ch);
       break;        
    case ITEM_PILL:
	    obj_cast_spell( obj->value[1], obj->value[0], ch, ch, NULL );
	    obj_cast_spell( obj->value[2], obj->value[0], ch, ch, NULL );
	    obj_cast_spell( obj->value[3], obj->value[0], ch, ch, NULL );
	break;
    }

    extract_obj( obj );
    return SKPELL_NO_DAMAGE;
}

/*
 * Hide objects... by Maniac!
 */
int find_door(CHAR_DATA *ch, char *arg);

void do_hide_obj(CHAR_DATA *ch, char *argument)
{
    char        arg[MAX_INPUT_LENGTH];
    int         chance;
    int         door;
    OBJ_DATA    *obj;

    one_argument(argument,arg);
    if ( arg[0] == '\0' )
    {
        send_to_char(AT_WHITE,"What do you want to hide?\n\r", ch);
        return;
    }


    if ( (door = find_door( ch, arg)) >=0 )  /* re-hide hidden exits --Manaux */
    {
      if ( !IS_SET(ch->in_room->exit[door]->exit_info, EX_HIDDEN)
         && IS_SET(ch->in_room->exit[door]->rs_flags, EX_HIDDEN) )
      {
        SET_BIT( ch->in_room->exit[door]->exit_info, EX_HIDDEN);
        send_to_char(AT_WHITE, "You successfully re-hide it.", ch);
        return;
      }
      send_to_char(AT_WHITE, "You can't hide that!", ch);
      return;
    } 

    if ( !( obj = get_obj_carry( ch, arg ) ) )
    {
        send_to_char(AT_WHITE, "You do not have that item.\n\r", ch );
        return;
    }
    if ( !can_drop_obj( ch, obj ) )
    {
//		if ( !IS_SET(obj->extra_flags2, ITEM_QUEST) )
			send_to_char(AT_WHITE, "You can't let go of it.\n\r", ch );
/*		else
			send_to_char(AT_WHITE, "Your precious quest equipment?\n\r", ch); */
        return;
    }

    obj_from_char( obj );
    obj_to_room( obj, ch->in_room );

    if (IS_SET(obj->extra_flags2, ITEM_HIDDEN))  /* no use in hiding it again */
        return;

    chance = number_range(1, 5);
    if (ch->class == 6)      /* Rangers are better */
        chance += 2;
    if (ch->class == 2)       /* Thieves as wel, but not so good */
        chance++;
    if (chance > 5)                     /* Let's not push it... */
        chance = 5;
    if (ch->level > LEVEL_HERO )        /* Immortals will manage */
        chance = 5;
    switch (chance)                     /* Let's see what we've got */
    {
        case 1:
                act(AT_WHITE,"$n is on all fours trying to hide $p.", ch, obj, NULL, TO_ROOM );
                act(AT_WHITE,"You try to hide $p, but fail misarably.", ch, obj, NULL, TO_CHAR );
                break;
        case 2:
                act(AT_WHITE,"$n is on all fours digging in the dirt.", ch, NULL, NULL, TO_ROOM );
                act(AT_WHITE,"You hide $p, but you did it quite obvious.", ch, obj, NULL, TO_CHAR );
                SET_BIT(obj->extra_flags2, ITEM_HIDDEN);
                break;
        case 3:
                act(AT_WHITE, "You fail to hide $p.", ch, obj, NULL, TO_CHAR );
                break;
        case 4:
        case 5:
                act(AT_WHITE, "You hide $p.", ch, obj, NULL, TO_CHAR );
                SET_BIT(obj->extra_flags2, ITEM_HIDDEN);
                break;
    }
}

void do_search(CHAR_DATA *ch, char *argument)
{
    OBJ_DATA *obj;
    char buf[MAX_INPUT_LENGTH];
    char buf2[MAX_INPUT_LENGTH];
    int found = FALSE;
    bool foundExit = FALSE;
    int chance;
    int door;
    int percent;
    int sn = skill_lookup("search");
    EXIT_DATA *pexit;
 
    buf[0] = '\0';
    buf2[0] = '\0';


    WAIT_STATE( ch, skill_table[sn].beats );
    percent  =  number_percent( );

  if ( !IS_NPC( ch ) && percent < ( ch->pcdata->learned[sn] / 10 ) + 35  )
  {
    if (!IS_NPC(ch) && ch->pcdata->learned[sn])
	update_skpell(ch, sn, 0);

    for ( obj = ch->in_room->contents; obj && (!found); obj = obj->next_content )
    {
        if ( IS_SET(obj->extra_flags2, ITEM_HIDDEN) )
        {
                chance = number_range( 1, 5);
                if ((ch->class == 6) || (ch->class == 2))
                        chance++;
                if (chance > 3)
                {
                        sprintf(buf, "You find %s.\n\r", obj->short_descr);
                        strcat(buf2, buf);
                        buf[0] = '\0';
                        REMOVE_BIT(obj->extra_flags2, ITEM_HIDDEN);
                        found = TRUE;
                }
        }
    }
    /*Make search find hidden exits. */

    for ( door = 0; door < 6 ; door++)
    {
      
      if ((pexit = ch->in_room->exit[door])
           &&IS_SET(pexit->exit_info, EX_HIDDEN) )
      {
        REMOVE_BIT( pexit->exit_info , EX_HIDDEN ) ;
        if (!foundExit)
        {
          foundExit = TRUE;
          send_to_char(AT_WHITE, "You revealed a hidden exit.\n\r", ch);
        }
      }  
    }

   }
   if (!found && !foundExit)
        strcat(buf2, "You find nothing.\n\t");
    send_to_char(AT_WHITE,buf2, ch);
    buf2[0] = '\0';
}

int skill_lore( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA *obj;


    if ( target_name[0] == '\0' )
    {
        send_to_char(AT_WHITE,"What do you want to lore?\n\r", ch);
        return SKPELL_BOTCHED;
    }

    obj = get_obj_carry(ch,target_name);
    if ( obj == NULL )
    {
        send_to_char(AT_WHITE,"You aren't carrying that.\n\r", ch);
        return SKPELL_BOTCHED;
    }

    WAIT_STATE(ch, skill_table[sn].beats);

    if ( !IS_NPC(ch) && number_percent( ) > ( ch->pcdata->learned[sn] / 10 ) )
    {
        act(AT_WHITE,"You look at $p, but you can't find out any additional information.",            ch,obj,NULL,TO_CHAR);
        act(AT_WHITE,"$n looks at $p but cannot find out anything.", ch, obj, NULL, TO_ROOM);
        return SKPELL_MISSED;
    }
    else
    {
        act(AT_WHITE,"$n studies $p, discovering all of it's hidden powers.",ch,obj,NULL,TO_ROOM);
        if ( ( number_percent( ) * number_percent( ) ) < 40 )
        {
            obj->cost += (int) ( (ch->pcdata->learned[sn]) * 0.01 * obj->cost);
            send_to_char(AT_WHITE, "Your understanding of the lore behind it increases its worth!\n\r",  ch );
        }

        spell_identify(sn,( 4 * obj->level )/3,ch,obj);
        /* check_improve(ch,gsn_lore,TRUE,4); */
    }

    return SKPELL_NO_DAMAGE;
}

int skill_embalm( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA    *obj = 0;


    return SKPELL_MISSED;

    if ( target_name[0] == '\0' )
    {
        send_to_char(AT_WHITE,"What do you want to embalm?\n\r", ch);
        return SKPELL_BOTCHED;
    }

    if ( obj->item_type != ITEM_CORPSE_PC )
    {
	send_to_char(AT_WHITE, "You can't embalm that!\n\r", ch);
	return SKPELL_BOTCHED;
    }

    if (IS_SET(obj->wear_flags, ITEM_TAKE))  
        return SKPELL_NO_DAMAGE;

    if ( ( obj->item_type = ITEM_CORPSE_PC ) )
	{
	obj->wear_flags = 1;
	send_to_char(AT_WHITE, "You have embalmed the player's corpse successfully!", ch);
	return SKPELL_NO_DAMAGE;
	}

	return SKPELL_MISSED;
}

int skill_gravebind( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA    *obj;
    int         gain = 0;

      if ( !IS_NPC( ch )
        && ( ( ch->level < skill_table[sn].skill_level[ch->class] )   
        && (ch->level < skill_table[sn].skill_level[ch->multied])))    
    {
	send_to_char(C_DEFAULT,
	     "You'd better leave the arts of the dead to the necromancers.\n\r", ch);
	return SKPELL_BOTCHED;
    }

    if ( target_name[0] == '\0' )
    {
        send_to_char(C_DEFAULT, "Gravebind what?\n\r", ch );
        return SKPELL_BOTCHED;
    }

    obj = (OBJ_DATA*) vo;//get_obj_list( ch, target_name, ch->in_room->contents );
    if ( !obj )
    {
        send_to_char(C_DEFAULT, "You can't find it.\n\r", ch );
        return SKPELL_BOTCHED;
    }

    if ( obj->item_type != ITEM_CORPSE_NPC )
    {
        send_to_char(C_DEFAULT, "You can only gravebind corpses of non-players.\n\r", ch );
        return SKPELL_BOTCHED;
    }

    if ( ( obj->item_type = ITEM_CORPSE_NPC ) )
    {
    gain = number_range((int)(ch->max_hit * 0.3), (int)(ch->max_hit * 0.5)) + obj->value[1];

    if (ch->max_hit >= (ch->hit + gain))
	ch->hit = (ch->hit + gain);
    else
	{
	gain = (ch->max_hit - ch->hit);
	ch->hit = (ch->hit + gain);
	}
	
	ch->move -= (int)(gain/12);	/* Added penalty due to new heal range */

    send_to_char(AT_GREY, "You absorb the lasting strength of the corpse.\n\r", ch);
    act(AT_GREY, "$n drains the corpse of its lasting energy.", ch, NULL, NULL, TO_ROOM);

    extract_obj( obj );
    }
return SKPELL_NO_DAMAGE;
}  

int skill_gorge( int sn, int level, CHAR_DATA *ch, void *vo )
{
    OBJ_DATA  * obj;
    int         amount;

    if ( IS_NPC( ch ) )
    {
	return SKPELL_BOTCHED;
    }

    if ( target_name[ 0 ] == '\0' )
    {
        for (obj = ch->in_room->contents; obj; obj = obj->next_content )
        {
            if ( obj->item_type == ITEM_BLOOD )
                break;
        }
        if ( !obj )
        {
            send_to_char ( AT_RED, "Gorge from what?\n\r", ch );
            return SKPELL_MISSED;
        }
    }
    else
    {
        if ( !( obj = get_obj_here ( ch, target_name ) ) )
        {
            send_to_char ( AT_BLUE, "You can't find it.\n\r", ch );
            return SKPELL_MISSED; 
        }
    }

    if ( obj->item_type != ITEM_BLOOD )
    {
	send_to_char ( AT_RED, "You can't gorge yourself from that.\n\r", ch );
        return SKPELL_BOTCHED;
    }

    if ( ( ch->bp + 1 ) > ch->max_bp )
    {
        send_to_char ( AT_RED, "Your thirst for blood has been abated.\n\r", ch );
        return SKPELL_NO_DAMAGE;
    }
/*
    amount = UMIN ( (ch->max_bp - ch->bp ), obj->value[1] );
    amount = UMIN ( amount, 25 );
*/
    if( !IS_NPC( ch ) )
    {
	amount = number_fuzzy( ch->pcdata->learned[sn] / 25 ) + number_fuzzy( ch->level / 10 );
    }
    else
    {
	amount = number_fuzzy( ch->level / 10 );
    }
    ch->bp += amount;
    if ( obj->value[0] != -1 )
        obj->value[1] -= amount;
    if ( obj->value[1] > 0 )
    {
        act ( AT_RED, "You gorge yourself from $p.", ch, obj, NULL, TO_CHAR );
        act ( AT_RED, "$n gorges $mself from $p.", ch, obj, NULL, TO_ROOM );
    }
    else
    {
        act ( AT_RED, "You gorge yourself from $p, which vanishes.", ch, obj, NULL, TO_CHAR );

        act ( AT_RED, "$n gorges $mself from $p, which vanishes.", ch, obj, NULL, TO_ROOM );
        extract_obj ( obj );
    }

	return SKPELL_NO_DAMAGE;
}