/
mudtem/
mudtem/area/scripts/
mudtem/bin/
mudtem/log/
mudtem/player/
mudtem/slang/autoconf/
mudtem/slang/doc/
mudtem/slang/doc/OLD/help/
mudtem/slang/doc/internal/
mudtem/slang/doc/text/
mudtem/slang/doc/tm/tools/
mudtem/slang/examples/
mudtem/slang/modules/
mudtem/slang/slsh/
mudtem/slang/slsh/lib/
mudtem/slang/slsh/scripts/
mudtem/slang/src/mkfiles/
mudtem/slang/src/util/
mudtem/src/CVS/
mudtem/src/include/
mudtem/src/include/CVS/
mudtem/src/var/CVS/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

/***************************************************************************
*	ROM 2.4 is copyright 1993-1996 Russ Taylor			   *
*	ROM has been brought to you by the ROM consortium		   *
*	    Russ Taylor (rtaylor@efn.org)				   *
*	    Gabrielle Taylor						   *
*	    Brian Moore (zump@rom.org)					   *
*	By using this code, you have agreed to follow the terms of the	   *
*	ROM license, in the file Rom24/doc/rom.license			   *
***************************************************************************/

#if defined(macintosh)
#include <types.h>
#include <time.h>
#else
#include <sys/types.h>
#if !defined(WIN32)
#include <sys/time.h>
#endif
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>	// para unlink()
#include "merc.h"
#include "events.h"
#include "recycle.h"
#include "lookup.h"
#include "tables.h"
#include "auction.h"

/* command procedures needed */
DECLARE_DO_FUN(do_split		);
DECLARE_DO_FUN(do_yell		);
DECLARE_DO_FUN(do_say		);
DECLARE_DO_FUN(do_wake		);
DECLARE_SPELL_FUN(spell_imprint		);
DECLARE_SPELL_FUN(spell_acid_blast	);
DECLARE_SPELL_FUN(spell_fireball	);
DECLARE_SPELL_FUN(spell_identify	);
DECLARE_SPELL_FUN(spell_null		);
DECLARE_SPEC_FUN(spec_taxidermist	);

extern	AFFECT_DATA *new_affect(void);

void fwrite_room(ROOM_INDEX_DATA *room);

/*
 * Local functions.
 */
#define CD CHAR_DATA
#define OD OBJ_DATA
bool	remove_obj	args( (CHAR_DATA *ch, int iWear, bool fReplace ) );
void	wear_obj	args( (CHAR_DATA *ch, OBJ_DATA *obj, bool fReplace ) );
CD *	find_keeper	args( (CHAR_DATA *ch ) );
CD *	find_reparador	args( (CHAR_DATA *ch ) );
int	get_cost	args( (CHAR_DATA *keeper, OBJ_DATA *obj, bool fBuy ) );
void 	obj_to_keeper	args( (OBJ_DATA *obj, CHAR_DATA *ch ) );
OD *	get_obj_keeper	args( (CHAR_DATA *ch,CHAR_DATA *keeper,char *argument));

#undef OD
#undef	CD

/* RT part of the corpse looting code */

bool can_loot(CHAR_DATA *ch, OBJ_DATA *obj)
{
/*  CHAR_DATA *owner, *wch; */

    if (IS_IMMORTAL(ch))
	return TRUE;

    if ( IS_NULLSTR(obj->owner) )
	return TRUE;

    if ( !str_cmp( obj->owner, ch->name ) )
    	return TRUE;

/*  owner = NULL;
    for ( wch = char_list; wch != NULL ; wch = wch->next )
        if (!str_cmp(wch->name,obj->owner))
            owner = wch;

    if (owner == NULL)
	return TRUE;

    if (!str_cmp(ch->name,owner->name))
	return TRUE;

    if (!IS_NPC(owner) && IS_SET(owner->act,PLR_CANLOOT))
	return TRUE;

    if (is_same_group(ch,owner))
	return TRUE; */

    return FALSE;
}

void get_obj( CHAR_DATA *ch, OBJ_DATA *obj, OBJ_DATA *container )
{
    /* variables for AUTOSPLIT */
    CHAR_DATA *gch;
    int members;
    char buffer[100];

    if ( !CAN_WEAR(obj, ITEM_TAKE) )
    {
	send_to_char( "No puedes tomar eso.\n\r", ch );
	return;
    }

    if (checkgetput(ch, obj) )
        return;

    if (!IS_IMMORTAL(ch) && IS_SET(obj->extra_flags, ITEM_PROTOTIPO))
    {
        send_to_char( "No puedes tomar prototipos.\n\r", ch);
        return;
    }

    if ( ch->carry_number + get_obj_number( obj ) > can_carry_n( ch ) )
    {
	act( "$d: no puedes acarrear tantos items.",
	    ch, NULL, strToEnt(obj->name,ch->in_room), TO_CHAR );
	return;
    }

    if ((!obj->in_obj || obj->in_obj->carried_by != ch)
    &&  (get_carry_weight(ch) + get_obj_weight(obj) > can_carry_w(ch)))
    {
	act( "$d: no puedes acarrear tanto peso.",
	    ch, NULL, strToEnt(obj->name,ch->in_room), TO_CHAR );
	return;
    }

    if (!can_loot(ch,obj))
    {
	if (obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC )
		act("Ese cadaver no es tuyo.",ch,NULL,NULL,TO_CHAR );
	else
		act("Eso no te pertenece.", ch, NULL, NULL, TO_CHAR );
	return;
    }

    if ( obj->in_obj )
    {
	OBJ_DATA *contenedor;

	for ( contenedor = obj; contenedor->in_obj; contenedor = contenedor->in_obj )
		;

	if ( ES_CORPSE(contenedor) && !can_loot(ch,contenedor) )
	{
		send_to_char( "Saqueo de cuerpos no esta permitido.\n\r", ch );
		return;
	}
    }

    if ( !IS_IMMORTAL(ch)
    &&    obj->clan
    &&    obj->clan != ch->clan )
    {
    	send_to_char( "No es de tu clan.\n\r", ch );
    	return;
    }

    if (obj->in_room != NULL)
    {
	for (gch = obj->in_room->people; gch != NULL; gch = gch->next_in_room)
	    if (gch->on == obj)
	    {
		act("$N parece estar usando $p.",
		    ch,objToEnt(obj),chToEnt(gch),TO_CHAR);
		return;
	    }
    }

    if ( container != NULL )
    {
    	if (container->pIndexData->vnum == OBJ_VNUM_PIT
	&&  get_trust(ch) < obj->level)
	{
	    send_to_char("No eres lo suficientemente poderoso para poder usarlo.\n\r",ch);
	    return;
	}

    	if (container->pIndexData->vnum == OBJ_VNUM_PIT
	&&  !CAN_WEAR(container, ITEM_TAKE)
	&&  !IS_OBJ_STAT(obj,ITEM_HAD_TIMER))
	    obj->timer = 0;	
	act( "Sacas $p desde $P.", ch, objToEnt(obj), objToEnt(container), TO_CHAR );
	act( "$n saca $p desde $P.", ch, objToEnt(obj), objToEnt(container), TO_ROOM );
	REMOVE_BIT(obj->extra_flags,ITEM_HAD_TIMER);
	obj_from_obj( obj );
    }
    else
    {
	act( "Tomas $p.", ch, objToEnt(obj), objToEnt(container), TO_CHAR );
	act( "$n toma $p.", ch, objToEnt(obj), objToEnt(container), TO_ROOM );
	obj_from_room( obj );
	if (IS_SET( obj->extra_flags, ITEM_HIDDEN ))
		REMOVE_BIT( obj->extra_flags, ITEM_HIDDEN );
    }

    if ( obj->item_type == ITEM_MONEY)
    {
	ch->silver += obj->value[0];
	ch->gold += obj->value[1];
        if (IS_SET(ch->act,PLR_AUTOSPLIT))
        { /* AUTOSPLIT code */
    	  members = 0;
    	  for (gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room )
    	  {
            if (!IS_AFFECTED(gch,AFF_CHARM) && is_same_group( gch, ch ) )
              members++;
    	  }

	  if ( members > 1 && (obj->value[0] > 1 || obj->value[1]))
	  {
	    sprintf(buffer,"%d %d",obj->value[0],obj->value[1]);
	    do_split(ch,buffer);
	  }
        }

	extract_obj( obj, TRUE );
    }
    else
    {
	obj_to_char( obj, ch );
    }

    if ( HAS_TRIGGER( obj, TRIG_GET ) )
    	mp_percent_trigger( objToEnt(obj), chToEnt(ch), NULL, NULL, TRIG_GET );

    return;
}



void do_get( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    OBJ_DATA *container;
    bool found;

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

    if (!str_cmp(arg2,"from"))
	argument = one_argument(argument,arg2);

    /* Get type. */
    if ( arg1[0] == '\0' )
    {
	send_to_char( "Tomar que?\n\r", ch );
	return;
    }

    if ( arg2[0] == '\0' )
    {
	if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
	{
	    /* 'get obj' */
	    obj = get_obj_list( ch, arg1, ch->in_room->contents );
	    if ( obj == NULL )
	    {
		act( "No veo ningun $T aqui.", ch, NULL, strToEnt(arg1,ch->in_room), TO_CHAR );
		return;
	    }

	    get_obj( ch, obj, NULL );
	    if ( IS_SET(ch->in_room->room_flags, ROOM_GRABADO) )
	    {
		fwrite_room(ch->in_room);
		save_char_obj( ch );
	    }
	}
	else
	{
	    /* 'get all' or 'get all.obj' */
	    found = FALSE;

	    for ( obj = ch->in_room->contents; obj != NULL; obj = obj_next )
	    {
		obj_next = obj->next_content;
		if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) )
		&&   can_see_obj( ch, obj ) )
		{
		    found = TRUE;
		    get_obj( ch, obj, NULL );
		}
	    }

	    if ( !found ) 
	    {
		if ( arg1[3] == '\0' )
		    send_to_char( "No veo nada aqui.\n\r", ch );
		else
		    act( "No veo ningun $T aqui.", ch, NULL, strToEnt(&arg1[4],ch->in_room), TO_CHAR );
	    }
	    else
	    if ( IS_SET(ch->in_room->room_flags, ROOM_GRABADO) )
	    {
		fwrite_room(ch->in_room);
		save_char_obj( ch );
	    }
	}
    }
    else
    {
	/* 'get ... container' */
	if ( !str_cmp( arg2, "all" ) || !str_prefix( "all.", arg2 ) )
	{
	    send_to_char( "No puedes hacer eso.\n\r", ch );
	    return;
	}

	if ( ( container = get_obj_here( ch, arg2 ) ) == NULL )
	{
	    act( "No veo ningun $T aqui.", ch, NULL, strToEnt(arg2,ch->in_room), TO_CHAR );
	    return;
	}

	switch ( container->item_type )
	{
	default:
	    send_to_char( "Eso no es un contenedor.\n\r", ch );
	    return;

	case ITEM_CONTAINER:
	case ITEM_CORPSE_NPC:
	    break;

	case ITEM_CORPSE_PC:
	    {
		if (!can_loot(ch,container))
		{
		    send_to_char( "No puedes hacer eso.\n\r", ch );
		    return;
		}
	    }
	}

	if ( !ES_CORPSE(container) && IS_SET(container->value[1], CONT_CLOSED) )
	{
	    act( "El $d esta cerrado.", ch, NULL, strToEnt(container->name,ch->in_room), TO_CHAR );
	    return;
	}

	if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
	{
	    /* 'get obj container' */
	    obj = get_obj_list( ch, arg1, container->contains );
	    if ( obj == NULL )
	    {
		act( "No veo nada de eso en el $T.",
		    ch, NULL, strToEnt(arg2,ch->in_room), TO_CHAR );
		return;
	    }
	    get_obj( ch, obj, container );
	    if ( IS_SET(ch->in_room->room_flags, ROOM_GRABADO) )
	    {
		fwrite_room(ch->in_room);
		save_char_obj( ch );
	    }
	}
	else
	{
	    /* 'get all container' or 'get all.obj container' */
	    found = FALSE;
	    for ( obj = container->contains; obj != NULL; obj = obj_next )
	    {
		obj_next = obj->next_content;
		if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) )
		&&   can_see_obj( ch, obj ) )
		{
		    found = TRUE;
		    if (container->pIndexData->vnum == OBJ_VNUM_PIT
		    &&  !IS_IMMORTAL(ch))
		    {
			send_to_char("No seas tan ambicioso!\n\r",ch);
			return;
		    }
		    get_obj( ch, obj, container );
		}
	    }

	    if ( !found )
	    {
		if ( arg1[3] == '\0' )
		    act( "No veo nada en el $T.",
			ch, NULL, strToEnt(arg2,ch->in_room), TO_CHAR );
		else
		    act( "No veo nada de eso en el $T.",
			ch, NULL, strToEnt(arg2,ch->in_room), TO_CHAR );
	    }
	    else
	    if ( IS_SET(ch->in_room->room_flags, ROOM_GRABADO) )
	    {
		fwrite_room(ch->in_room);
		save_char_obj( ch );
	    }
	}
    }

    return;
}



void do_put( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    OBJ_DATA *container;
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;

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

    if (!str_cmp(arg2,"in") || !str_cmp(arg2,"on"))
	argument = one_argument(argument,arg2);

    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "Poner que donde?\n\r", ch );
	return;
    }

    if ( !str_cmp( arg2, "all" ) || !str_prefix( "all.", arg2 ) )
    {
	send_to_char( "No puedes hacer eso.\n\r", ch );
	return;
    }

    if ( ( container = get_obj_here( ch, arg2 ) ) == NULL )
    {
	act( "No veo ningun $T aqui.", ch, NULL, strToEnt(arg2,ch->in_room), TO_CHAR );
	return;
    }

    if ( container->item_type != ITEM_CONTAINER )
    {
	send_to_char( "Eso no es un contenedor.\n\r", ch );
	return;
    }

    if ( IS_SET(container->value[1], CONT_CLOSED) )
    {
	act( "El $d esta cerrado.", ch, NULL, strToEnt(container->name,ch->in_room), TO_CHAR );
	return;
    }

    if (checkgetput( ch, container) )
       return;

    if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
    {
	/* 'put obj container' */
	if ( ( obj = get_obj_carry( ch, arg1, ch ) ) == NULL )
	{
	    send_to_char( "No tienes ese item.\n\r", ch );
	    return;
	}

	if ( obj == container )
	{
	    send_to_char( "No lo puedes poner dentro de si mismo.\n\r", ch );
	    return;
	}

	if ( !can_drop_obj( ch, obj ) )
	{
	    send_to_char( "No lo puedes soltar.\n\r", ch );
	    SET_BIT(obj->detected, DETECTED_CURSE);
	    return;
	}

    	if (WEIGHT_MULT(obj) != 100)
    	{
           send_to_char("Sientes como que fuera una mala idea.\n\r",ch);
            return;
        }

	if (get_obj_weight( obj ) + get_true_weight( container )
	     > (container->value[0] * 10) 
	||  get_obj_weight(obj) > (container->value[3] * 10))
	{
	    send_to_char( "No cabe.\n\r", ch );
	    return;
	}
	
	if (container->pIndexData->vnum == OBJ_VNUM_PIT 
	&& !CAN_WEAR(container,ITEM_TAKE))
	{
		if (obj->timer)
			SET_BIT(obj->extra_flags,ITEM_HAD_TIMER);
		else
			obj->timer = number_range(100,200);
	}

	obj_from_char( obj );
	obj_to_obj( obj, container );

	if (IS_SET(container->value[1],CONT_PUT_ON))
	{
	    act("$n pone $p sobre $P.",ch,objToEnt(obj),objToEnt(container), TO_ROOM);
	    act("Pones $p sobre $P.",ch,objToEnt(obj),objToEnt(container), TO_CHAR);
	}
	else
	{
	    act( "$n pone $p dentro de $P.", ch, objToEnt(obj), objToEnt(container), TO_ROOM );
	    act( "Pones $p dentro de $P.", ch, objToEnt(obj), objToEnt(container), TO_CHAR );
	}

	if ( HAS_TRIGGER( obj, TRIG_PUT ) )
		mp_percent_trigger( objToEnt(obj), chToEnt(ch), NULL, NULL, TRIG_PUT );
    }
    else
    {
	/* 'put all container' or 'put all.obj container' */
	for ( obj = ch->carrying; obj != NULL; obj = obj_next )
	{
	    obj_next = obj->next_content;

	    if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) )
	    &&   can_see_obj( ch, obj )
	    &&   WEIGHT_MULT(obj) == 100
	    &&   obj->wear_loc == WEAR_NONE
	    &&   obj != container
	    &&   can_drop_obj( ch, obj )
	    &&   get_obj_weight( obj ) + get_true_weight( container )
		 <= (container->value[0] * 10) 
	    &&   get_obj_weight(obj) < (container->value[3] * 10))
	    {
	    	if (container->pIndexData->vnum == OBJ_VNUM_PIT
		&& !CAN_WEAR(obj, ITEM_TAKE) )
		{
			if (obj->timer)
				SET_BIT(obj->extra_flags,ITEM_HAD_TIMER);
			else
				obj->timer = number_range(100,200);
		}

		obj_from_char( obj );
		obj_to_obj( obj, container );

        	if (IS_SET(container->value[1],CONT_PUT_ON))
        	{
            	    act("$n pone $p sobre $P.",ch,objToEnt(obj),objToEnt(container), TO_ROOM);
            	    act("Pones $p sobre $P.",ch,objToEnt(obj),objToEnt(container), TO_CHAR);
        	}
		else
		{
		    act( "$n pone $p dentro de $P.", ch, objToEnt(obj), objToEnt(container), TO_ROOM );
		    act( "Pones $p dentro de $P.", ch, objToEnt(obj), objToEnt(container), TO_CHAR );
		}

		if ( HAS_TRIGGER( obj, TRIG_PUT ) )
			mp_percent_trigger( objToEnt(obj), chToEnt(ch), NULL, NULL, TRIG_PUT );
	    }
	}
    }

    return;
}



void do_drop( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    char buf[MIL];
    char shd[MIL];
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    OBJ_DATA *repobj;
    OBJ_DATA *repobj_next;
    bool found;
    int cnt;

    argument = one_argument( argument, arg );

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

    if ( is_number( arg ) )
    {
	/* 'drop NNNN coins' */
	int amount, gold = 0, silver = 0;

	amount   = atoi(arg);
	argument = one_argument( argument, arg );
	if ( amount <= 0
	|| ( str_cmp( arg, "coins" ) && str_cmp( arg, "coin" ) && 
	     str_cmp( arg, "gold"  ) && str_cmp( arg, "silver") ) )
	{
	    send_to_char( "Lamentablemente, no puedes hacer eso.\n\r", ch );
	    return;
	}

	if ( !str_cmp( arg, "coins") || !str_cmp(arg,"coin") 
	||   !str_cmp( arg, "silver"))
	{
	    if (ch->silver < amount)
	    {
		send_to_char("No tienes tantas monedas de plata.\n\r",ch);
		return;
	    }

	    ch->silver -= amount;
	    silver = amount;
	}

	else
	{
	    if (ch->gold < amount)
	    {
		send_to_char("No tienes tantas monedas de oro.\n\r",ch);
		return;
	    }

	    ch->gold -= amount;
  	    gold = amount;
	}

	for ( obj = ch->in_room->contents; obj != NULL; obj = obj_next )
	{
	    obj_next = obj->next_content;

	    switch ( obj->pIndexData->vnum )
	    {
	    case OBJ_VNUM_SILVER_ONE:
		silver += 1;
		extract_obj(obj, TRUE);
		break;

	    case OBJ_VNUM_GOLD_ONE:
		gold += 1;
		extract_obj( obj, TRUE );
		break;

	    case OBJ_VNUM_SILVER_SOME:
		silver += obj->value[0];
		extract_obj(obj, TRUE);
		break;

	    case OBJ_VNUM_GOLD_SOME:
		gold += obj->value[1];
		extract_obj( obj, TRUE );
		break;

	    case OBJ_VNUM_COINS:
		silver += obj->value[0];
		gold += obj->value[1];
		extract_obj(obj, TRUE);
		break;
	    }
	}

	obj_to_room( create_money( gold, silver ), ch->in_room );
	act( "$n bota unas cuantas monedas.", ch, NULL, NULL, TO_ROOM );
	send_to_char( "OK.\n\r", ch );
	if ( IS_SET(ch->in_room->room_flags, ROOM_GRABADO) )
	{
		fwrite_room(ch->in_room);
		save_char_obj( ch );
	}
	return;
    }

    if ( str_cmp( arg, "all" ) && str_prefix( "all.", arg ) )
    {
	/* 'drop obj' */
	if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
	{
	    send_to_char( "No tienes ese item.\n\r", ch );
	    return;
	}

	if ( !can_drop_obj( ch, obj ) )
	{
	    send_to_char( "No puedes soltarlo.\n\r", ch );
	    SET_BIT(obj->detected, DETECTED_CURSE);
	    return;
	}

	obj_from_char( obj );
	obj_to_room( obj, ch->in_room );
	act( "$n bota $p.", ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Tu botas $p.", ch, objToEnt(obj), NULL, TO_CHAR );
	if (!IS_OBJ_STAT(obj,ITEM_MELT_DROP))
	{
		if ( IS_SET(ch->in_room->room_flags, ROOM_GRABADO) )
		{
			fwrite_room(ch->in_room);
			save_char_obj( ch );
		}
	}
	else
	{
	    act("$p se disuelve en una nube de humo.",ch,objToEnt(obj),NULL,TO_ROOM);
	    act("$p se disuelve en una nube de humo.",ch,objToEnt(obj),NULL,TO_CHAR);
	    extract_obj(obj, TRUE);
	}
    }
    else
    {
	found = FALSE;
	/* 'drop all' or 'drop all.obj' */
	for ( obj = ch->carrying; obj != NULL; obj = obj_next )
	{
		obj_next = obj->next_content;

		cnt = 0;

		if ( ( arg[3] == '\0' || is_name( &arg[4], obj->name ) )
		&&   can_see_obj( ch, obj )
		&&   obj->wear_loc == WEAR_NONE
		&&   can_drop_obj( ch, obj ) )
		{
			found = TRUE;
			strcpy(shd,obj->short_descr);
			for ( repobj = obj; repobj; repobj = repobj_next )
			{
				repobj_next = repobj->next_content;

				if ( !can_see_obj( ch, repobj )
				||    repobj->wear_loc != WEAR_NONE
				||   !can_drop_obj( ch, repobj )
				||    obj->pIndexData != repobj->pIndexData )
					continue;

				if ( repobj == obj_next )
					obj_next = repobj_next;

				obj_from_char( repobj );
				cnt++;
				obj_to_room( repobj, ch->in_room );
		        	if (IS_OBJ_STAT(repobj,ITEM_MELT_DROP))
		        	{
					act("$p se disuelve en una nube de humo.",ch,objToEnt(repobj),NULL,TO_ROOM);
					act("$p se disuelve en una nube de humo.",ch,objToEnt(repobj),NULL,TO_CHAR);
					extract_obj(repobj, TRUE);
				}
			}

			if ( cnt > 1 )
				sprintf( buf, "$n bota %d*%s.", cnt, shd );
			else
				sprintf( buf, "$n bota %s.", shd );
			act( buf, ch, NULL, NULL, TO_ROOM );
			if ( cnt > 1 )
				sprintf( buf, "Botas %d*%s.", cnt, shd );
			else
				sprintf( buf, "Botas %s.", shd );
			act( buf, ch, NULL, NULL, TO_CHAR );
			if ( IS_SET(ch->in_room->room_flags, ROOM_GRABADO) )
			{
				fwrite_room(ch->in_room);
				save_char_obj( ch );
			}
		}
	}
	if ( !found )
	{
		if ( arg[3] == '\0' )
			act( "No estas llevando nada.",
				ch, NULL, strToEnt(arg,ch->in_room), TO_CHAR );
		else
			act( "No estas llevando ningun $T.",
				ch, NULL, strToEnt(&arg[4],ch->in_room), TO_CHAR );
	}
    }

    return;
}



void do_give( CHAR_DATA *ch, char *argument )
{
    char arg1 [MAX_INPUT_LENGTH];
    char arg2 [MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];
    CHAR_DATA *victim;
    OBJ_DATA  *obj;

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

    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "Darle que a quien?\n\r", ch );
	return;
    }

    if ( is_number( arg1 ) )
    {
	/* 'give NNNN coins victim' */
	int amount;
	bool silver;

	amount   = atoi(arg1);
	if ( amount <= 0
	|| ( str_cmp( arg2, "coins" ) && str_cmp( arg2, "coin" ) && 
	     str_cmp( arg2, "gold"  ) && str_cmp( arg2, "silver")) )
	{
	    send_to_char( "Lamentablemente, no puedes hacer eso.\n\r", ch );
	    return;
	}

	silver = str_cmp(arg2,"gold");

	argument = one_argument( argument, arg2 );
	if ( arg2[0] == '\0' )
	{
	    send_to_char( "Darle que a quien?\n\r", ch );
	    return;
	}

	if ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
	{
	    send_to_char( "No esta aqui.\n\r", ch );
	    return;
	}

	if ( ch == victim )
	{
		send_to_char( "Muy gracioso.\n\r", ch );
		return;
	}

	if ( (!silver && ch->gold < amount) || (silver && ch->silver < amount) )
	{
	    send_to_char( "No tienes esa cantidad.\n\r", ch );
	    return;
	}

	if ( !IS_NPC(victim)
	&& get_carry_weight(victim) + (silver ? silver_weight(amount) : gold_weight(amount)) > can_carry_w(victim) )
	{
	    act( "$N no puede llevar tanto peso.", ch, NULL, chToEnt(victim), TO_CHAR );
	    return;
	}

	if ( IS_NPC(victim)
	&&   IS_SET(victim->act, ACT_IS_CHANGER))
	{
	    if ( get_carry_weight(ch) + (silver ? silver_weight(amount) : gold_weight(amount)) > can_carry_w(ch) )
	    {
	    	act( "$n te dice 'Lo lamento, estas llevando demasiado peso.'", ch, NULL, chToEnt(victim), TO_VICT );
	    	return;
	    }

	    if ( !can_see(victim, ch) )
	    {
		act( "$N no puede verte.", ch, NULL, chToEnt(victim), TO_CHAR );
		return;
	    }
	}

	if (silver)
	{
	    ch->silver		-= amount;
	    victim->silver 	+= amount;
	}
	else
	{
	    ch->gold		-= amount;
	    victim->gold	+= amount;
	}

	sprintf(buf,"$n te da %d monedas de %s.",amount, silver ? "plata" : "oro");
	act( buf, ch, NULL, chToEnt(victim), TO_VICT    );
	act( "$n le da a $N unas monedas.",  ch, NULL, chToEnt(victim), TO_NOTVICT );
	sprintf(buf,"Le das a $N %d monedas de %s.",amount, silver ? "plata" : "oro");
	act( buf, ch, NULL, chToEnt(victim), TO_CHAR    );

 	/*
 	 * Bribe trigger
 	 */
 	if ( IS_NPC(victim) && HAS_TRIGGER( victim, TRIG_BRIBE ) )
 	    mp_bribe_trigger( victim, ch, silver ? amount : amount * 100 );
 
	if (IS_NPC(victim) && IS_SET(victim->act,ACT_IS_CHANGER))
	{
	    int change;

	    change = (silver ? 95 * amount / 100 / 100 
		 	     : 95 * amount);

	    if (!silver && change > victim->silver)
	    	victim->silver += change;

	    if (silver && change > victim->gold)
		victim->gold += change;

	    if (change < 1)
	    {
		act( "$n te dice 'Lo lamento, no me diste demasiadas monedas para poder cambiartelas.'",victim,NULL,chToEnt(ch),TO_VICT);
		ch->reply = victim;
		sprintf(buf,"%d %s %s", 
			amount, silver ? "silver" : "gold",ch->name);
		do_give(victim,buf);
	    }
	    else
	    {
		sprintf(buf,"%d %s %s", 
			change, silver ? "gold" : "silver",ch->name);
		do_give(victim,buf);
		if (silver)
		{
		    sprintf(buf,"%d silver %s", 
			(95 * amount / 100 - change * 100),ch->name);
		    do_give(victim,buf);
		}
		act("$n te dice 'Gracias, vuelve cuando quieras.'",
		    victim,NULL,chToEnt(ch),TO_VICT);
		ch->reply = victim;
	    }
	}
	return;
    }

    if ( ( obj = get_obj_carry( ch, arg1, ch ) ) == NULL )
    {
	send_to_char( "No tienes ese item.\n\r", ch );
	return;
    }

    if ( obj->wear_loc != WEAR_NONE )
    {
	send_to_char( "Debes dejar de usarlo primero.\n\r", ch );
	return;
    }

    if ( IS_SET(obj->extra_flags, ITEM_PROTOTIPO) )
    {
    	send_to_char( "No puedes dar prototipos.\n\r", ch );
    	return;
    }

    if ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
    {
	send_to_char( "No esta aqui.\n\r", ch );
	return;
    }

    if ( ch == victim )
    {
	send_to_char( "Muy gracioso.\n\r", ch );
	return;
    }

    if (IS_NPC(victim)
    && victim->pIndexData->pShop != NULL
    && victim->pIndexData->spec_fun != spec_taxidermist )
    {
	act("$N te dice 'Lo lamento, deberas vender eso.'",
	    ch,NULL,chToEnt(victim),TO_CHAR);
	ch->reply = victim;
	return;
    }

    if ( !can_drop_obj( ch, obj ) )
    {
	send_to_char( "No puedes soltarlo.\n\r", ch );
	SET_BIT(obj->detected, DETECTED_CURSE);
	return;
    }

    if ( IS_OBJ_STAT( obj, ITEM_ANTI_EVIL ) && victim->race == RACE_VAMPIRE )
    {
	act( "$N rechaza $p.", ch, objToEnt(obj), chToEnt(victim), TO_CHAR );
	act( "$n intenta darle $p a $N pero $E lo rechaza.",
	    ch, objToEnt(obj), chToEnt(victim), TO_ROOM );
	act( "Rechazas $p que $n queria darte.",
	    ch, objToEnt(obj), chToEnt(victim), TO_VICT );
	return;
    }

    if ( victim->carry_number + get_obj_number( obj ) > can_carry_n( victim ) )
    {
	act( "$N tiene $S manos llenas.", ch, NULL, chToEnt(victim), TO_CHAR );
	return;
    }

    if (get_carry_weight(victim) + get_obj_weight(obj) > can_carry_w( victim ))
    {
	act( "$N no puede llevar tanto peso.", ch, NULL, chToEnt(victim), TO_CHAR );
	return;
    }

    if ( !can_see_obj( victim, obj ) )
    {
	act( "$N no puede verlo.", ch, NULL, chToEnt(victim), TO_CHAR );
	return;
    }

    if ( obj->clan && victim->clan != obj->clan )
    {
    	act( "$N no puede tener ese objeto.", ch, NULL, chToEnt(victim), TO_CHAR );
    	return;
    }

    obj_from_char( obj );
    obj_to_char( obj, victim );
    MOBtrigger = FALSE;
    act( "$n le da $p a $N.", ch, objToEnt(obj), chToEnt(victim), TO_NOTVICT );
    act( "$n te da $p.",   ch, objToEnt(obj), chToEnt(victim), TO_VICT    );
    act( "Le das $p a $N.", ch, objToEnt(obj), chToEnt(victim), TO_CHAR    );
    MOBtrigger = TRUE;

    /*
     * Give trigger
     */
    if ( IS_NPC(victim) && HAS_TRIGGER( victim, TRIG_GIVE ) )
	mp_give_trigger( victim, ch, obj );

    return;
}


/* for poisoning weapons and food/drink */
void do_envenom(CHAR_DATA *ch, char *argument)
{
    OBJ_DATA *obj;
    AFFECT_DATA af;
    int percent,skill;

    /* find out what */
    if (argument == '\0')
    {
	send_to_char("Envenenar que item?\n\r",ch);
	return;
    }

    obj =  get_obj_list(ch,argument,ch->carrying);

    if (obj== NULL)
    {
	send_to_char("No tienes ese item.\n\r",ch);
	return;
    }

    if ((skill = get_skill(ch,gsn_envenom)) < 1)
    {
	send_to_char("Estas loco? Podrias envenenarte!\n\r",ch);
	return;
    }

    if (obj->item_type == ITEM_FOOD || obj->item_type == ITEM_DRINK_CON)
    {
	if (IS_OBJ_STAT(obj,ITEM_BLESS) || IS_OBJ_STAT(obj,ITEM_BURN_PROOF))
	{
	    act("Fallas en envenenar $p.",ch,objToEnt(obj),NULL,TO_CHAR);
	    return;
	}

	if (number_percent() < skill)  /* success! */
	{
	    act("$n mezcla $p con un veneno mortal.",ch,objToEnt(obj),NULL,TO_ROOM);
	    act("Mezclas $p con un veneno mortal.",ch,objToEnt(obj),NULL,TO_CHAR);

	    if ( !IS_SET(obj->value[3], FOOD_POISON) )
	    {
	    	SET_BIT(obj->value[3], FOOD_POISON);
		check_improve(ch,gsn_envenom,TRUE,4);
	    }

	    WAIT_STATE(ch,skill_table[gsn_envenom].beats);
	    return;
	}

	act("Fallas en envenenar $p.",ch,objToEnt(obj),NULL,TO_CHAR);
	if (!IS_SET(obj->value[3], FOOD_POISON))
	    check_improve(ch,gsn_envenom,FALSE,4);
	WAIT_STATE(ch,skill_table[gsn_envenom].beats);
	return;
     }

    if (obj->item_type == ITEM_WEAPON)
    {
        if (IS_WEAPON_STAT(obj,WEAPON_FLAMING)
        ||  IS_WEAPON_STAT(obj,WEAPON_FROST)
        ||  IS_WEAPON_STAT(obj,WEAPON_VAMPIRIC)
        ||  IS_WEAPON_STAT(obj,WEAPON_SHARP)
        ||  IS_WEAPON_STAT(obj,WEAPON_VORPAL)
        ||  IS_WEAPON_STAT(obj,WEAPON_SHOCKING)
        ||  IS_OBJ_STAT(obj,ITEM_BLESS) || IS_OBJ_STAT(obj,ITEM_BURN_PROOF))
        {
            act("Pareciera que no puedes envenenar $p.",ch,objToEnt(obj),NULL,TO_CHAR);
            return;
        }

	if (obj->value[3] < 0 
	||  attack_table[obj->value[3]].damage == DAM_BASH)
	{
	    send_to_char("Solo puedes envenenar armas con filo.\n\r",ch);
	    return;
	}

        if (IS_WEAPON_STAT(obj,WEAPON_POISON))
        {
            act("$p ya fue envenenada.",ch,objToEnt(obj),NULL,TO_CHAR);
            return;
        }

	percent = number_percent();
	if (percent < skill)
	{
 
            af.where     = TO_WEAPON;
            af.type      = gsn_poison;
            af.level     = getNivelPr(ch) * percent / 100;
            af.duration  = getNivelPr(ch)/2 * percent / 100;
            af.location  = 0;
            af.modifier  = 0;
            af.bitvector = WEAPON_POISON;
            affect_to_obj(obj,&af);
 
            act("$n cubre $p con un veneno mortal.",ch,objToEnt(obj),NULL,TO_ROOM);
	    act("Cubres $p con un veneno mortal.",ch,objToEnt(obj),NULL,TO_CHAR);
	    check_improve(ch,gsn_envenom,TRUE,3);
	    WAIT_STATE(ch,skill_table[gsn_envenom].beats);
            return;
        }
	else
	{
	    act("Fallas en envenenar $p.",ch,objToEnt(obj),NULL,TO_CHAR);
	    check_improve(ch,gsn_envenom,FALSE,3);
	    WAIT_STATE(ch,skill_table[gsn_envenom].beats);
	    return;
	}
    }
 
    act("No puedes envenenar $p.",ch,objToEnt(obj),NULL,TO_CHAR);
    return;
}

void do_fill( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];
    OBJ_DATA *obj;
    OBJ_DATA *fountain;
    bool found;

    one_argument( argument, arg );

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

    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
    {
	send_to_char( "No tienes ese item.\n\r", ch );
	return;
    }

    found = FALSE;
    for ( fountain = ch->in_room->contents; fountain != NULL;
	fountain = fountain->next_content )
    {
	if ( fountain->item_type == ITEM_FOUNTAIN )
	{
	    found = TRUE;
	    break;
	}
    }

    if ( !found )
    {
	send_to_char( "No hay ninguna fuente aqui!\n\r", ch );
	return;
    }

    if ( obj->item_type != ITEM_DRINK_CON )
    {
	send_to_char( "No puedes llenar eso.\n\r", ch );
	return;
    }

    if ( obj->value[1] != 0 && obj->value[2] != fountain->value[2] )
    {
	send_to_char( "Ya hay otro liquido en eso.\n\r", ch );
	return;
    }

    if ( obj->value[1] >= obj->value[0] )
    {
	send_to_char( "Tu contenedor esta lleno.\n\r", ch );
	return;
    }

    sprintf(buf,"Llenas $p con %s de $P.",
	liq_table[fountain->value[2]].liq_name);
    act( buf, ch, objToEnt(obj), objToEnt(fountain), TO_CHAR );
    sprintf(buf,"$n llena $p con %s de $P.",
	liq_table[fountain->value[2]].liq_name);
    act(buf,ch,objToEnt(obj),objToEnt(fountain),TO_ROOM);
    obj->value[2] = fountain->value[2];
    obj->value[1] = obj->value[0];
    return;
}

void do_pour (CHAR_DATA *ch, char *argument)
{
    char arg[MAX_STRING_LENGTH],buf[MAX_STRING_LENGTH];
    OBJ_DATA *out, *in;
    CHAR_DATA *vch = NULL;
    int amount;

    argument = one_argument(argument,arg);
    
    if (arg[0] == '\0' || argument[0] == '\0')
    {
	send_to_char("Verter que en que?\n\r",ch);
	return;
    }
    

    if ((out = get_obj_carry(ch,arg, ch)) == NULL)
    {
	send_to_char("No tienes ese item.\n\r",ch);
	return;
    }

    if (out->item_type != ITEM_DRINK_CON)
    {
	send_to_char("Ese no es un contenedor para liquidos.\n\r",ch);
	return;
    }

    if (!str_cmp(argument,"out"))
    {
	if (out->value[1] == 0)
	{
	    send_to_char("Esta vacio.\n\r",ch);
	    return;
	}

	out->value[1] = 0;
	out->value[3] = 0;
	sprintf(buf,"Inviertes $p, derramando %s por todo el suelo.",
		liq_table[out->value[2]].liq_name);
	act(buf,ch,objToEnt(out),NULL,TO_CHAR);
	
	sprintf(buf,"$n invierte $p, derramando %s por todo el suelo.",
		liq_table[out->value[2]].liq_name);
	act(buf,ch,objToEnt(out),NULL,TO_ROOM);
	return;
    }

    if ((in = get_obj_here(ch,argument)) == NULL)
    {
	vch = get_char_room(ch,argument);

	if (vch == NULL)
	{
	    send_to_char("Verter a quien?\n\r",ch);
	    return;
	}

	in = get_eq_char(vch,WEAR_HOLD);

	if (in == NULL)
	{
	    send_to_char("No esta sosteniendo nada.",ch);
 	    return;
	}
    }

    if (in->item_type != ITEM_DRINK_CON)
    {
	send_to_char("Solo puedes vertir en otros contenedores de liquidos.\n\r",ch);
	return;
    }
    
    if (in == out)
    {
	send_to_char("No puedes cambiar las leyes de la fisica!\n\r",ch);
	return;
    }

    if (in->value[1] != 0 && in->value[2] != out->value[2])
    {
	send_to_char("No tienen el mismo liquido.\n\r",ch);
	return;
    }

    if (out->value[1] == 0)
    {
	act("No hay nada en $p para verter.",ch,objToEnt(out),NULL,TO_CHAR);
	return;
    }

    if (in->value[1] >= in->value[0])
    {
	act("$p esta lleno hasta el tope.",ch,objToEnt(in),NULL,TO_CHAR);
	return;
    }

    amount = UMIN(out->value[1],in->value[0] - in->value[1]);

    in->value[1] += amount;
    out->value[1] -= amount;
    in->value[2] = out->value[2];
    
    if (vch == NULL)
    {
    	sprintf(buf,"Viertes %s de $p en $P.",
	    liq_table[out->value[2]].liq_name);
    	act(buf,ch,objToEnt(out),objToEnt(in),TO_CHAR);
    	sprintf(buf,"$n vierte %s de $p en $P.",
	    liq_table[out->value[2]].liq_name);
    	act(buf,ch,objToEnt(out),objToEnt(in),TO_ROOM);
    }
    else
    {
        sprintf(buf,"Viertes un poco de %s para $N.",
            liq_table[out->value[2]].liq_name);
        act(buf,ch,NULL,chToEnt(vch),TO_CHAR);
	sprintf(buf,"$n vierte en tu contenedor un poco de %s.",
	    liq_table[out->value[2]].liq_name);
	act(buf,ch,NULL,chToEnt(vch),TO_VICT);
        sprintf(buf,"$n vierte %s en el contenedor de $N.",
            liq_table[out->value[2]].liq_name);
        act(buf,ch,NULL,chToEnt(vch),TO_NOTVICT);
	
    }
}

void do_drink( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    int amount;
    int liquid;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	for ( obj = ch->in_room->contents; obj; obj = obj->next_content )
	{
	    if ( obj->item_type == ITEM_FOUNTAIN )
		break;
	}

	if ( obj == NULL )
	{
	    send_to_char( "Tomar que?\n\r", ch );
	    return;
	}
    }
    else
    {
	if ( ( obj = get_obj_here( ch, arg ) ) == NULL )
	{
	    send_to_char( "No puedes encontrarlo.\n\r", ch );
	    return;
	}
    }

    if ( !IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK] > 10 )
    {
	send_to_char( "Fallas en alcanzar tu boca.  *Hic*\n\r", ch );
	return;
    }

    switch ( obj->item_type )
    {
    default:
	send_to_char( "No puedes tomar de eso.\n\r", ch );
	return;

    case ITEM_FOUNTAIN:
	liquid = obj->value[2];

	if ( (ch->race == RACE_VAMPIRE) && (liquid != liq_lookup( "blood" )) )
	{
	    send_to_char( "No puedes tomar de eso.\n\r", ch );
	    return;
	}

	if ( (obj->pIndexData->vnum == OBJ_VNUM_CHARCO) && !IS_NPC(ch) && (ch->pcdata->condition[COND_THIRST] > 10) )
	{
	    send_to_char( "No estas TAN desesperado como para pasarle la lengua al suelo!\n\r", ch );
	    return;
	}

        if ( liquid < 0 )
        {
            bug( "Do_drink: bad liquid number %d.", liquid );
            liquid = obj->value[2] = 0;
        }

	amount = liq_table[liquid].liq_affect[4] * 3;
	break;

    case ITEM_DRINK_CON:
	if ( obj->value[1] <= 0 )
	{
	    send_to_char( "Esta vacio.\n\r", ch );
	    return;
	}

	if ( ( liquid = obj->value[2] )  < 0 )
	{
	    bug( "Do_drink: bad liquid number %d.", liquid );
	    liquid = obj->value[2] = 0;
	}

        amount = liq_table[liquid].liq_affect[4];
        amount = UMIN(amount, obj->value[1]);
	break;
    }

    if (!IS_NPC(ch) && !IS_IMMORTAL(ch) && ch->pcdata->condition[COND_FULL] > 45)
    {
	send_to_char("Estas demasiado lleno para poder tomar mas.\n\r",ch);
	return;
    }

    if ( obj->pIndexData->vnum == OBJ_VNUM_CHARCO )
    {
	act( "$n se agacha y toma $T de $p.", ch, objToEnt(obj), strToEnt(liq_table[liquid].liq_name,ch->in_room), TO_ROOM );
	act( "Tomas $T de $p.", ch, objToEnt(obj), strToEnt(liq_table[liquid].liq_name,ch->in_room), TO_CHAR );
    }
    else
    {
	act( "$n toma $T de $p.",
		ch, objToEnt(obj), strToEnt(liq_table[liquid].liq_name,ch->in_room), TO_ROOM );
	act( "Tomas $T de $p.",
		ch, objToEnt(obj), strToEnt(liq_table[liquid].liq_name,ch->in_room), TO_CHAR );
    }

    gain_condition( ch, COND_DRUNK,
		amount * liq_table[liquid].liq_affect[COND_DRUNK] / 36 );

    if ( ch->race != RACE_VAMPIRE )
    {
	gain_condition( ch, COND_FULL,
		amount * liq_table[liquid].liq_affect[COND_FULL] / 4 );
	if ( gain_condition(ch, COND_THIRST, amount * liq_table[liquid].liq_affect[COND_THIRST] / 10 ) == victdead )
		return;
	if ( gain_condition(ch, COND_HUNGER, amount * liq_table[liquid].liq_affect[COND_HUNGER] / 2 ) == victdead )
		return;
    }
    else
    /* If blood */
    if ( liquid == liq_lookup("blood") )
    {
	gain_condition( ch, COND_FULL, amount * 2 );
	if ( gain_condition( ch, COND_THIRST, amount ) == victdead )
		return;
	if ( gain_condition( ch, COND_HUNGER, amount ) == victdead )
		return;
    }

    if ( !IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK]  > 10 )
	send_to_char( "Te sientes ebrio.\n\r", ch );
    if ( !IS_NPC(ch) && ch->pcdata->condition[COND_FULL]   > 40 )
	send_to_char( "Estas lleno.\n\r", ch );
    if ( !IS_NPC(ch) && ch->pcdata->condition[COND_THIRST] > 40 )
	send_to_char( "Tu sed fue saciada.\n\r", ch );

    if ( obj->value[3] != 0 && !IS_FORM(ch, FORM_UNDEAD) )
    {
	/* The drink was poisoned ! */
	AFFECT_DATA af;

	act( "$n se ahoga y empieza a toser.", ch, NULL, NULL, TO_ROOM );
	send_to_char( "Te ahogas y toses.\n\r", ch );
	af.where     = TO_AFFECTS;
	af.type      = gsn_poison;
	af.level     = number_fuzzy(amount);
	af.duration  = 3 * amount;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_POISON;
	affect_join( ch, &af );
    }
	
    if (obj->value[0] > 0)
    {
        obj->value[1] -= amount;
        if (obj->item_type == ITEM_DRINK_CON
        &&  obj->value[1] == 0 )
		act( "$p quedo vacio.", ch, objToEnt(obj), NULL, TO_CHAR );
    }
        	
    return;
}

void eat_msg( EVENT *ev )
{
	switch((int) ev->param)
	{
		case 0:
		send_to_char( "Tu hambre fue saciada.\n\r", ev->item.ch );
		break;
		case 1:
		send_to_char( "Estas lleno.\n\r", ev->item.ch );
		break;
		case 2:
		act( "$n se ahoga y empieza a toser.", ev->item.ch, NULL, NULL, TO_ROOM );
		act( "Te ahogas y toses.", ev->item.ch, NULL, NULL, TO_CHAR );
		break;
		case 3:
		act( "$n termina de comer.", ev->item.ch, NULL, NULL, TO_ROOM );
		act( "Terminas de comer.", ev->item.ch, NULL, NULL, TO_CHAR );
		break;
		case 4:
		send_to_char( "Hmmm...sientes un sabor raro.\n\r", ev->item.ch );
	}
}

void do_eat( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;

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

    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
    {
	send_to_char( "No tienes ese item.\n\r", ch );
	return;
    }

    if ( !IS_IMMORTAL(ch) )
    {
	if ( obj->item_type != ITEM_FOOD && obj->item_type != ITEM_PILL )
	{
	    send_to_char( "No es comestible.\n\r", ch );
	    return;
	}

	if ( !IS_NPC(ch) && ch->pcdata->condition[COND_FULL] > 40 )
	{   
	    send_to_char( "Estas demasiado lleno para poder comer mas.\n\r", ch );
	    return;
	}
    }

    act( "$n empieza a comer $p.", ch, objToEnt(obj), NULL, TO_ROOM );
    act( "Empiezas a comer $p.", ch, objToEnt(obj), NULL, TO_CHAR );

    WAIT_STATE( ch, 3*PULSE_PER_SECOND );

    switch ( obj->item_type )
    {
    case ITEM_FOOD:
	if ( !IS_NPC(ch) )
	{
	    int condition;

	    condition = ch->pcdata->condition[COND_HUNGER];
	    gain_condition( ch, COND_FULL, obj->value[0] / 2 );
	    if ( gain_condition( ch, COND_HUNGER, obj->value[1]) == victdead )
	    	return;
	    if ( condition == 0 && ch->pcdata->condition[COND_HUNGER] > 0 )
		char_event_add( ch, PULSE_PER_SECOND, 0, eat_msg );
	    else if ( ch->pcdata->condition[COND_FULL] > 40 )
		char_event_add( ch, PULSE_PER_SECOND, (void *) 1, eat_msg );
	}

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

	    if (CHANCE(50))
	    	char_event_add( ch, PULSE_PER_SECOND, (void *) 4, eat_msg );

	    char_event_add( ch, 2*PULSE_PER_SECOND, (void *) 2, eat_msg );

	    if ( IS_SET(obj->value[3], FOOD_POISON) )
	    {
		af.where     = TO_AFFECTS;
		af.type      = gsn_poison;
		af.level     = number_fuzzy(obj->value[0]);
		af.duration  = 2 * obj->value[0];
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bitvector = AFF_POISON;
		affect_join( ch, &af );
	    }

	    if ( IS_SET(obj->value[3], FOOD_PLAGUE) )
	    {
		af.where     = TO_AFFECTS;
		af.type      = gsn_plague;
		af.level     = number_fuzzy(obj->value[0]);
		af.duration  = 2 * obj->value[0];
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bitvector = AFF_PLAGUE;
		affect_join( ch, &af );
	    }
	}
	break;

    case ITEM_PILL:
	obj_cast_spell( obj->value[1], obj->value[0], objToEnt(obj), ch, chToEnt(ch) );
	obj_cast_spell( obj->value[2], obj->value[0], objToEnt(obj), ch, chToEnt(ch) );
	obj_cast_spell( obj->value[3], obj->value[0], objToEnt(obj), ch, chToEnt(ch) );
	obj_cast_spell( obj->value[4], obj->value[0], objToEnt(obj), ch, chToEnt(ch) );

	gain_condition( ch, COND_FULL, 8 );
	if ( gain_condition( ch, COND_HUNGER, 4 ) == victdead )
		return;
	break;
    }

    char_event_add( ch, 3*PULSE_PER_SECOND, (void *) 3, eat_msg );

    extract_obj( obj, TRUE );

    return;
}



/*
 * Remove an object.
 */
bool remove_obj( CHAR_DATA *ch, int iWear, bool fReplace )
{
    OBJ_DATA *obj, *tObj;

    if ( ( obj = get_eq_char( ch, iWear ) ) == NULL )
	return TRUE;

    if ( !fReplace )
	return FALSE;

    if ( IS_SET(obj->extra_flags, ITEM_NOREMOVE) )
    {
	act( "No puedes remover $p.", ch, objToEnt(obj), NULL, TO_CHAR );
	SET_BIT(obj->detected, DETECTED_CURSE);
	return FALSE;
    }

    if (obj->wear_loc == WEAR_WIELD && (tObj = get_eq_char(ch, WEAR_SECONDARY)))
    	remove_obj( ch, WEAR_SECONDARY, TRUE );

    unequip_char( ch, obj );
    act( "$n deja de usar $p.", ch, objToEnt(obj), NULL, TO_ROOM );
    act( "Dejas de usar $p.", ch, objToEnt(obj), NULL, TO_CHAR );
    return TRUE;
}



/*
 * Wear one object.
 * Optional replacement of existing objects.
 * Big repetitive code, ick.
 */
void wear_obj( CHAR_DATA *ch, OBJ_DATA *obj, bool fReplace )
{
    if ( getNivelPr(ch) < obj->level )
    {
	printf_to_char( ch, "Debes ser de nivel %d para poder usar %s.\n\r",
		obj->level, obj->short_descr );
	act( "$n intenta usar $p, pero es demasiado inexperto.",
	    ch, objToEnt(obj), NULL, TO_ROOM );
	return;
    }

    if ( obj->clan && obj->clan != ch->clan )
    {
    	send_to_char( "Ese objeto no es de tu clan.\n\r", ch );
    	return;
    }

    if ( obj->item_type == ITEM_LIGHT )
    {
	if ( !remove_obj( ch, WEAR_LIGHT, fReplace ) )
	    return;
	act( "$n enciende $p y lo sostiene.", ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Enciendes $p y lo sostienes.",  ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_LIGHT );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_FINGER ) )
    {
	if ( get_eq_char( ch, WEAR_FINGER_L ) != NULL
	&&   get_eq_char( ch, WEAR_FINGER_R ) != NULL
	&&   !remove_obj( ch, WEAR_FINGER_L, fReplace )
	&&   !remove_obj( ch, WEAR_FINGER_R, fReplace ) )
	    return;

	if ( !IS_SET(ch->parts, PART_FINGERS) && !IS_SET(ch->parts, PART_CLAWS) )
	{
		extern bool fBootDb;

		send_to_char( "Necesitas dedos para poder usar anillos.\n\r", ch );

		if (fBootDb)
			bugf("wear_obj : mob %d no pudo ponerse anillo vnum %d",
				CHARVNUM(ch), obj->pIndexData->vnum );

		return;
	}

	if ( get_eq_char( ch, WEAR_FINGER_L ) == NULL )
	{
	    act( "$n se pone $p en su dedo izquierdo.",    ch, objToEnt(obj), NULL, TO_ROOM );
	    act( "Te pones $p en tu dedo izquierdo.",  ch, objToEnt(obj), NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_FINGER_L );
	    return;
	}

	if ( get_eq_char( ch, WEAR_FINGER_R ) == NULL )
	{
	    act( "$n se pone $p en su dedo derecho.",   ch, objToEnt(obj), NULL, TO_ROOM );
	    act( "Te pones $p en tu dedo derecho.", ch, objToEnt(obj), NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_FINGER_R );
	    return;
	}

	bug( "Wear_obj: no free finger.", 0 );
	send_to_char( "Ya tienes tus dedos ocupados.\n\r", ch );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_NECK ) )
    {
	if ( get_eq_char( ch, WEAR_NECK_1 ) != NULL
	&&   get_eq_char( ch, WEAR_NECK_2 ) != NULL
	&&   !remove_obj( ch, WEAR_NECK_1, fReplace )
	&&   !remove_obj( ch, WEAR_NECK_2, fReplace ) )
	    return;

	if ( get_eq_char( ch, WEAR_NECK_1 ) == NULL )
	{
	    act( "$n se pone $p alrededor del cuello.",   ch, objToEnt(obj), NULL, TO_ROOM );
	    act( "Te pones $p alrededor del cuello.", ch, objToEnt(obj), NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_NECK_1 );
	    return;
	}

	if ( get_eq_char( ch, WEAR_NECK_2 ) == NULL )
	{
	    act( "$n se pone $p alrededor del cuello.",   ch, objToEnt(obj), NULL, TO_ROOM );
	    act( "Te pones $p alrededor del cuello.", ch, objToEnt(obj), NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_NECK_2 );
	    return;
	}

	bug( "Wear_obj: no free neck.", 0 );
	send_to_char( "Ya estas usando dos objetos en el cuello.\n\r", ch );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_BODY ) )
    {
	if ( !remove_obj( ch, WEAR_BODY, fReplace ) )
	    return;
	act( "$n se pone $p en el torso.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Te pones $p en el torso.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_BODY );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_HEAD ) )
    {
	if ( !remove_obj( ch, WEAR_HEAD, fReplace ) )
	    return;

	if ( !IS_SET(ch->parts, PART_HEAD) )
	{
		send_to_char( "Necesitas tener cabeza para poder hacer eso.\n\r", ch );
		return;
	}

	act( "$n se pone $p en su cabeza.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Te pones $p en tu cabeza.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_HEAD );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_LEGS ) )
    {
	if ( !remove_obj( ch, WEAR_LEGS, fReplace ) )
	    return;

	if ( !IS_SET(ch->parts, PART_LEGS) )
	{
		send_to_char( "Necesitas tener piernas para poder hacer eso.\n\r", ch );
		return;
	}

	act( "$n se pone $p en sus piernas.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Te pones $p en tus piernas.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_LEGS );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_FEET ) )
    {
	if ( !remove_obj( ch, WEAR_FEET, fReplace ) )
	    return;

	if ( !IS_SET(ch->parts, PART_FEET) )
	{
		send_to_char( "Necesitas pies para poder hacer eso.\n\r", ch );
		return;
	}

	act( "$n se pone $p en sus pies.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Te pones $p en tus pies.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_FEET );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_HANDS ) )
    {
	if ( !remove_obj( ch, WEAR_HANDS, fReplace ) )
	    return;

	if ( !IS_SET(ch->parts, PART_HANDS) )
	{
		send_to_char( "Necesitas manos para poder hacer eso.\n\r", ch );
		return;
	}

	act( "$n se pone $p en las manos.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Te pones $p en las manos.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_HANDS );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_ARMS ) )
    {
	if ( !remove_obj( ch, WEAR_ARMS, fReplace ) )
	    return;

	if ( !IS_SET(ch->parts, PART_ARMS) )
	{
		send_to_char( "Necesitas brazos para poder hacer eso.\n\r", ch );
		return;
	}

	act( "$n se pone $p en los brazos.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Te pones $p en los brazos.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_ARMS );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_ABOUT ) )
    {
	if ( !remove_obj( ch, WEAR_ABOUT, fReplace ) )
	    return;
	act( "$n se pone $p alrededor del torso.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Te pones $p alrededor del torso.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_ABOUT );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_WAIST ) )
    {
	if ( !remove_obj( ch, WEAR_WAIST, fReplace ) )
	    return;
	act( "$n se pone $p alrededor de la cintura.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Te pones $p alrededor de la cintura.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_WAIST );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_WRIST ) )
    {
	if ( get_eq_char( ch, WEAR_WRIST_L ) != NULL
	&&   get_eq_char( ch, WEAR_WRIST_R ) != NULL
	&&   !remove_obj( ch, WEAR_WRIST_L, fReplace )
	&&   !remove_obj( ch, WEAR_WRIST_R, fReplace ) )
	    return;

	if ( get_eq_char( ch, WEAR_WRIST_L ) == NULL )
	{
	    act( "$n se pone $p en su muneca izquierda.",
		ch, objToEnt(obj), NULL, TO_ROOM );
	    act( "Te pones $p en tu muneca izquierda.",
		ch, objToEnt(obj), NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_WRIST_L );
	    return;
	}

	if ( get_eq_char( ch, WEAR_WRIST_R ) == NULL )
	{
	    act( "$n se pone $p en su muneca derecha.",
		ch, objToEnt(obj), NULL, TO_ROOM );
	    act( "Te pones $p en tu muneca derecha.",
		ch, objToEnt(obj), NULL, TO_CHAR );
	    equip_char( ch, obj, WEAR_WRIST_R );
	    return;
	}

	bug( "Wear_obj: no free wrist.", 0 );
	send_to_char( "Ya estas usando dos munequeras.\n\r", ch );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_SHIELD ) )
    {
	OBJ_DATA *weapon;

	if ( !remove_obj( ch, WEAR_SHIELD, fReplace ) )
	    return;

	weapon = get_eq_char(ch,WEAR_WIELD);

	if (weapon != NULL
	&&  ch->size < SIZE_LARGE 
	&&  IS_WEAPON_STAT(weapon,WEAPON_TWO_HANDS))
	{
	    send_to_char("Tus manos estan atadas con tu arma!\n\r",ch);
	    return;
	}

        if (get_eq_char (ch, WEAR_SECONDARY) != NULL)
        {
            send_to_char ("No puedes usar un escudo mientras usas 2 armas.\n\r",ch);
            return;
        }

	act( "$n usa $p como escudo.", ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Usas $p como escudo.", ch, objToEnt(obj), NULL, TO_CHAR );

	equip_char( ch, obj, WEAR_SHIELD );

	return;
    }

    if ( CAN_WEAR( obj, ITEM_WIELD ) )
    {
	int sn,skill = 0;
	int wear_pos;

	if ( !IS_NPC(ch)
	&&    get_eq_char(ch, WEAR_WIELD) != NULL
	&&    get_eq_char(ch, WEAR_SHIELD) == NULL
	&&    get_eq_char(ch, WEAR_HOLD) == NULL
	&&   !IS_WEAPON_STAT(obj, WEAPON_TWO_HANDS)
	&&   (skill = get_skill(ch, gsn_ambidiestro)) > 0 )
		wear_pos = WEAR_SECONDARY;
	else
		wear_pos = WEAR_WIELD;

	if ( !remove_obj( ch, wear_pos, fReplace ) )
	    return;

	if ( !IS_NPC(ch) 
	&&    get_obj_weight(obj) > (str_app[get_curr_stat(ch,STAT_STR)].wield * 10))
	{
	    send_to_char( "Es demasiado pesado como para esgrimirlo.\n\r", ch );
	    return;
	}

	if (!IS_NPC(ch)
	&&   ch->size < SIZE_LARGE 
	&&   IS_WEAPON_STAT(obj,WEAPON_TWO_HANDS)
 	&&  (get_eq_char(ch,WEAR_SHIELD)
	  || get_eq_char(ch,WEAR_WIELD)
	  || get_eq_char(ch,WEAR_SECONDARY)) )
	{
		send_to_char("Necesitas dos manos libres para esa arma.\n\r",ch);
		return;
	}

	if ( wear_pos == WEAR_SECONDARY
	&&   number_percent() > skill )
	{
		act( "Whoops! Intentas esgrimir $p pero se te cae!", ch, objToEnt(obj), NULL, TO_CHAR );
 		act( "$n intenta esgrimir $p, pero se le cae, torpemente.", ch, objToEnt(obj), NULL, TO_ROOM );
 		obj_from_char( obj );
		obj_to_room( obj, ch->in_room );
		return;
    	}

	act( "$n esgrime $p.", ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Esgrimes $p.", ch, objToEnt(obj), NULL, TO_CHAR );

	equip_char( ch, obj, wear_pos );

        sn = get_weapon_sn(ch,FALSE);

	if (sn == gsn_hand_to_hand)
	   return;

        skill = get_weapon_skill(ch,sn);
 
        if (skill >= 100)
            act("$p se siente como una parte de ti!",ch,objToEnt(obj),NULL,TO_CHAR);
        else if (skill > 85)
            act("Te sientes seguro con $p.",ch,objToEnt(obj),NULL,TO_CHAR);
        else if (skill > 70)
            act("Eres habil con $p.",ch,objToEnt(obj),NULL,TO_CHAR);
        else if (skill > 50)
            act("Tu pericia con $p es adecuada.",ch,objToEnt(obj),NULL,TO_CHAR);
        else if (skill > 25)
            act("$p se siente un poco aparatosa en tus manos.",ch,objToEnt(obj),NULL,TO_CHAR);
        else if (skill > 1)
            act("Te enredas y casi se te cae $p.",ch,objToEnt(obj),NULL,TO_CHAR);
        else
            act("No sabes siquiera cual es la punta de $p.",
                ch,objToEnt(obj),NULL,TO_CHAR);

	return;
    }

    if ( CAN_WEAR( obj, ITEM_HOLD ) )
    {
	if ( !remove_obj( ch, WEAR_HOLD, fReplace ) )
	    return;

        if (get_eq_char (ch, WEAR_SECONDARY) != NULL)
        {
            send_to_char ("No puedes sostener un item mientras usas 2 armas.\n\r",ch);
            return;
        }

	act( "$n sostiene $p en su mano.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Sostienes $p en tu mano.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_HOLD );
	return;
    }

    if ( CAN_WEAR(obj,ITEM_WEAR_FLOAT) )
    {
	if (!remove_obj(ch,WEAR_FLOAT, fReplace) )
	    return;
	act("$n suelta $p para que flote junto a $m.",ch,objToEnt(obj),NULL,TO_ROOM);
	act("Sueltas $p y empieza a flotar a tu lado.",ch,objToEnt(obj),NULL,TO_CHAR);
	equip_char(ch,obj,WEAR_FLOAT);
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_LENTES ) )
    {
	if ( !remove_obj( ch, WEAR_LENTES, fReplace ) )
	    return;

	if ( !IS_SET(ch->parts, PART_EYE) )
	{
		send_to_char( "Tu no tienes ojos.\n\r", ch );
		return;
	}

	act( "$n usa $p en sus ojos.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Usas $p para proteger tus ojos.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_LENTES );
	return;
    }

    if ( CAN_WEAR( obj, ITEM_WEAR_OREJAS ) )
    {
	if ( !remove_obj( ch, WEAR_OREJAS, fReplace ) )
	    return;

	if ( !IS_SET(ch->parts, PART_EAR) )
	{
		send_to_char( "Tu no tienes ojos.\n\r", ch );
		return;
	}

	act( "$n se pone $p en los oidos.",   ch, objToEnt(obj), NULL, TO_ROOM );
	act( "Usas $p en tus orejas.", ch, objToEnt(obj), NULL, TO_CHAR );
	equip_char( ch, obj, WEAR_OREJAS );
	return;
    }

    if ( fReplace )
	send_to_char( "No puedes esgrimir, ponerte, o sostener eso.\n\r", ch );

    return;
}

void do_wear( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;

    if ( !IS_NPC( ch ) && IS_AFFECTED2( ch, AFF_GHOUL ) )
    {
	send_to_char(
	   "No puedes ponerte, esgrimir o sostener nada mientras seas un ghoul.\n\r",
		     ch );
	return;
    }

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	send_to_char( "Ponerte, esgrimir o sostener que?\n\r", ch );
	return;
    }

    if ( !str_cmp( arg, "all" ) )
    {
	OBJ_DATA *obj_next;

	for ( obj = ch->carrying; obj != NULL; obj = obj_next )
	{
	    obj_next = obj->next_content;
	    if ( obj->wear_loc == WEAR_NONE && can_see_obj( ch, obj ) )
		wear_obj( ch, obj, FALSE );
	}
	return;
    }
    else
    {
	if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
	{
	    send_to_char( "No tienes ese item.\n\r", ch );
	    return;
	}

	wear_obj( ch, obj, TRUE );
    }

    return;
}

void do_remove( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;

    one_argument( argument, arg );

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

     if ( !str_cmp( arg, "all" ) )
    {
	OBJ_DATA *obj_next;

	for ( obj = ch->carrying; obj != NULL; obj = obj_next )
	{
	    obj_next = obj->next_content;
            if ( obj->wear_loc != WEAR_NONE ) remove_obj( ch, obj->wear_loc, TRUE );
	}
     	return;
       }
    else
        if ( ( obj = get_obj_wear( ch, arg ) ) == NULL )
    {
	send_to_char( "No tienes ese item.\n\r", ch );
	return;
    }

    remove_obj( ch, obj->wear_loc, TRUE );
    return;
}



void do_sacrifice( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];
    OBJ_DATA *obj;
    int silver;
    
    /* variables for AUTOSPLIT */
    CHAR_DATA *gch;
    int members;
    char buffer[100];

    one_argument( argument, arg );

    if ( arg[0] == '\0' || !str_cmp( arg, ch->name ) )
    {
	act( "$n se ofrece a si mismo a $t, que graciosamente declina.",
	    ch, strToEnt(ch->clan ? get_clan_table(ch->clan)->god : "Mota", ch->in_room), NULL, TO_ROOM );
	sprintf( buf, "%s aprecia tu ofrecimiento y quizas lo acepte despues.\n\r",
		(ch->clan ? get_clan_table(ch->clan)->god : "Mota") );
	send_to_char(buf,ch);
	return;
    }

    obj = get_obj_list( ch, arg, ch->in_room->contents );
    if ( obj == NULL )
    {
	send_to_char( "No puedes encontrarlo.\n\r", ch );
	return;
    }

    if ( obj->item_type == ITEM_CORPSE_PC )
    {
	if (obj->contains)
        {
	   sprintf(buf,"A %s no le gustaria eso.\n\r",(ch->clan ? get_clan_table(ch->clan)->god : "Mota") );
	   send_to_char(buf,ch);
	   return;
        }
    }

    if ( !CAN_WEAR(obj, ITEM_TAKE) || CAN_WEAR(obj, ITEM_NO_SAC))
    {
	act( "$p no es un sacrificio aceptable.", ch, objToEnt(obj), NULL, TO_CHAR );
	return;
    }

    if (obj->in_room != NULL)
    {
	for (gch = obj->in_room->people; gch != NULL; gch = gch->next_in_room)
	    if (gch->on == obj)
	    {
		act("$N parece estar usando $p.",
		    ch,objToEnt(obj),chToEnt(gch),TO_CHAR);
		return;
	    }
    }
		
    silver = UMAX(1,obj->level * 3);

    if (obj->item_type != ITEM_CORPSE_NPC && obj->item_type != ITEM_CORPSE_PC)
    	silver = UMIN(silver,obj->cost);

    if (silver == 1) {
	sprintf(buf,"%s te da una moneda de plata por tu sacrificio.\n\r",
			(ch->clan ? get_clan_table(ch->clan)->god : "Mota") );
	send_to_char(buf,ch);
	}
    else
    {
	sprintf(buf,"%s te da %d monedas de plata por tu sacrificio.\n\r",
		(ch->clan ? get_clan_table(ch->clan)->god : "Mota"),silver);
	send_to_char(buf,ch);
    }
    
    ch->silver += silver;
    
    if (IS_SET(ch->act,PLR_AUTOSPLIT) )
    { /* AUTOSPLIT code */
    	members = 0;
	for (gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room )
    	{
    	    if ( is_same_group( gch, ch ) )
            members++;
    	}

	if ( members > 1 && silver > 1)
	{
	    sprintf(buffer,"%d",silver);
	    do_split(ch,buffer);	
	}
    }

    if ( HAS_TRIGGER( obj, TRIG_SAC ) )
    	mp_percent_trigger( objToEnt(obj), chToEnt(ch), NULL, NULL, TRIG_SAC );

    act( "$n sacrifica $p a $T.", ch, objToEnt(obj),strToEnt(ch->clan ? get_clan_table(ch->clan)->god : "Mota",ch->in_room) , TO_ROOM );
    wiznet("$N envia $p como un ofrecimiento consumido por el fuego.",
	   ch,obj,WIZ_SACCING,0,0);
    extract_obj( obj, TRUE );

    return;
}

void do_quaff( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;

    one_argument( argument, arg );

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

    if ( EN_ARENA(ch) )
    {
    	send_to_char( "No puedes beber pociones en la Arena.\n\r", ch );
    	return;
    }

    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
    {
	send_to_char( "No tienes esa pocion.\n\r", ch );
	return;
    }

    if ( obj->item_type != ITEM_POTION )
    {
	send_to_char( "Solo puedes beber pociones.\n\r", ch );
	return;
    }

    if (getNivelPr(ch) < obj->level)
    {
	send_to_char("Ese liquido es demasiado poderoso para que lo puedas beber.\n\r",ch);
	return;
    }

    act( "$n bebe $p.", ch, objToEnt(obj), NULL, TO_ROOM );
    act( "Bebes $p.", ch, objToEnt(obj), NULL ,TO_CHAR );

    if ( IS_AFFECTED2(ch, AFF_DOLOR_GUATA) )
    {
    	act( "Tomas un sorbo de $p...pero...", ch, objToEnt(obj), NULL, TO_CHAR );
    	act( "$n empieza a vomitar.", ch, NULL, NULL, TO_ROOM );
	ch->move = UMAX( 0, ch->move - 50 );
	ch->hit = UMAX( 1, ch->hit - 50 );
    	return;
    }

    if ( ch->position == POS_FIGHTING
    &&   ( get_eq_char( ch, WEAR_HOLD )
	|| get_eq_char( ch, WEAR_SECONDARY ) ) )
	WAIT_STATE(ch, 2*PULSE_PER_SECOND);
    else
	WAIT_STATE(ch, PULSE_PER_SECOND);

    DAZE_STATE(ch, PULSE_VIOLENCE);

    obj_cast_spell( obj->value[1], obj->value[0], objToEnt(obj), ch, chToEnt(ch) );
    obj_cast_spell( obj->value[2], obj->value[0], objToEnt(obj), ch, chToEnt(ch) );
    obj_cast_spell( obj->value[3], obj->value[0], objToEnt(obj), ch, chToEnt(ch) );
    obj_cast_spell( obj->value[4], obj->value[0], objToEnt(obj), ch, chToEnt(ch) );

    extract_obj( obj, TRUE );

    return;
}

void do_recite( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    CHAR_DATA *victim;
    OBJ_DATA *scroll;
    OBJ_DATA *obj;

    if ( EN_ARENA(ch) )
    {
    	send_to_char( "No puedes recitar mientras estes en la Arena.\n\r", ch );
    	return;
    }

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

    if ( ( scroll = get_obj_carry( ch, arg1, ch ) ) == NULL )
    {
	send_to_char( "No tienes ese scroll.\n\r", ch );
	return;
    }

    if ( scroll->item_type != ITEM_SCROLL )
    {
	send_to_char( "Puedes recitar scrolls solamente.\n\r", ch );
	return;
    }

    if ( getNivelPr(ch) < scroll->level)
    {
	send_to_char(
		"Este scroll es demasiado complejo como para que lo puedas comprender.\n\r",ch);
	return;
    }

	if ( IS_AFFECTED2( ch, AFF_MUTE )
	     || IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
	{
        	send_to_char( "Parece que no puedes romper el silencio.\n\r", ch );
	        return;
	}

    obj = NULL;
    if ( arg2[0] == '\0' )
    {
	victim = ch;
    }
    else
    {
	if ( ( victim = get_char_room ( ch, arg2 ) ) == NULL
	&&   ( obj    = get_obj_here  ( ch, arg2 ) ) == NULL )
	{
	    send_to_char( "No puedes encontrarlo.\n\r", ch );
	    return;
	}
    }

    act( "$n recita $p.", ch, objToEnt(scroll), NULL, TO_ROOM );
    act( "Recitas $p.", ch, objToEnt(scroll), NULL, TO_CHAR );

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

    if (number_percent() >= 20 + get_skill(ch,gsn_scrolls) * 4/5)
    {
	send_to_char("Pronuncias mal una silaba.\n\r",ch);
	check_improve(ch,gsn_scrolls,FALSE,2);
    }

    else
    {
    	obj_cast_spell( scroll->value[1], scroll->value[0], objToEnt(scroll), ch, obj ? objToEnt(obj) : chToEnt(victim) );
    	obj_cast_spell( scroll->value[2], scroll->value[0], objToEnt(scroll), ch, obj ? objToEnt(obj) : chToEnt(victim) );
    	obj_cast_spell( scroll->value[3], scroll->value[0], objToEnt(scroll), ch, obj ? objToEnt(obj) : chToEnt(victim) );
    	obj_cast_spell( scroll->value[4], scroll->value[0], objToEnt(scroll), ch, obj ? objToEnt(obj) : chToEnt(victim) );

	check_improve(ch,gsn_scrolls,TRUE,2);
    }

    extract_obj( scroll, TRUE );
    return;
}

void do_brandish( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;
    OBJ_DATA *staff;
    char buf[MIL];
    int sn;

    if ( EN_ARENA(ch) )
    {
    	send_to_char( "No puedes hacerlo mientras estes en la Arena.\n\r", ch );
    	return;
    }

    if ( ( staff = get_eq_char( ch, WEAR_HOLD ) ) == NULL )
    {
	send_to_char( "No estas sosteniendo nada.\n\r", ch );
	return;
    }

    if ( staff->item_type != ITEM_STAFF )
    {
	send_to_char( "Solo puedes blandir una vara.\n\r", ch );
	return;
    }

    if ( ( sn = staff->value[3] ) < 0
    ||   sn >= MAX_SKILL
    ||   skill_table[sn].spell_fun == 0 )
    {
	sprintf( buf, "Do_brandish: bad sn %d, vnum %d, jugador %s.",
		sn, staff->pIndexData->vnum, ch->name );
	bug( buf, 0 );
	return;
    }

    WAIT_STATE( ch, 2 * PULSE_VIOLENCE );

    if ( staff->value[2] > 0 )
    {
	act( "$n blande $p.", ch, objToEnt(staff), NULL, TO_ROOM );
	act( "Blandes $p.",  ch, objToEnt(staff), NULL, TO_CHAR );
	if ( getNivelPr(ch) < staff->level 
	||   number_percent() >= 20 + get_skill(ch,gsn_staves) * 4/5)
 	{
	    act ("Fallas al invocar $p.",ch,objToEnt(staff),NULL,TO_CHAR);
	    act ("...y no paso nada.",ch,NULL,NULL,TO_ROOM);
	    check_improve(ch,gsn_staves,FALSE,2);
	}
	
	else for ( vch = ch->in_room->people; vch; vch = vch_next )
	{
	    vch_next	= vch->next_in_room;

	    switch ( skill_table[sn].target )
	    {
	    default:
		sprintf( buf, "Do_brandish: bad target for sn %d, vnum %d, jugador %s.",
		sn, staff->pIndexData->vnum, ch->name );
		bug( buf, 0 );
		return;

	    case TAR_IGNORE:
		if ( vch != ch )
		    continue;
		break;

	    case TAR_CHAR_OFFENSIVE:
		if ( IS_NPC(ch) ? IS_NPC(vch) : !IS_NPC(vch) )
		    continue;
		break;
		
	    case TAR_CHAR_DEFENSIVE:
		if ( IS_NPC(ch) ? !IS_NPC(vch) : IS_NPC(vch) )
		    continue;
		break;

	    case TAR_CHAR_SELF:
		if ( vch != ch )
		    continue;
		break;
	    }

	    obj_cast_spell( staff->value[3], staff->value[0], objToEnt(staff), ch, chToEnt(vch) );
	    check_improve(ch,gsn_staves,TRUE,2);
	}
    }

    if ( --staff->value[2] <= 0 )
    {
	act( "$p de $n brilla fuertemente y desaparece.", ch, objToEnt(staff), NULL, TO_ROOM );
	act( "Tu $p brilla fuertemente y desaparece.", ch, objToEnt(staff), NULL, TO_CHAR );
	extract_obj( staff, TRUE );
    }

    return;
}



void do_zap( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *victim;
    OBJ_DATA *wand;
    OBJ_DATA *obj;

    if ( EN_ARENA(ch) )
    {
	send_to_char( "No puedes hacerlo mientras estes en la Arena.\n\r", ch );
	return;
    }

    one_argument( argument, arg );
    if ( arg[0] == '\0' && ch->fighting == NULL )
    {
	send_to_char( "Zap que o quien?\n\r", ch );
	return;
    }

    if ( ( wand = get_eq_char( ch, WEAR_HOLD ) ) == NULL )
    {
	send_to_char( "No estas sosteniendo nada.\n\r", ch );
	return;
    }

    if ( wand->item_type != ITEM_WAND )
    {
	send_to_char( "Solo puedes zap con una varita.\n\r", ch );
	return;
    }

    obj = NULL;
    if ( arg[0] == '\0' )
    {
	if ( ch->fighting != NULL )
	{
	    victim = ch->fighting;
	}
	else
	{
	    send_to_char( "Zap que o quien?\n\r", ch );
	    return;
	}
    }
    else
    {
	if ( ( victim = get_char_room ( ch, arg ) ) == NULL
	&&   ( obj    = get_obj_here  ( ch, arg ) ) == NULL )
	{
	    send_to_char( "No puedes encontrarlo.\n\r", ch );
	    return;
	}
    }

    WAIT_STATE( ch, 2*PULSE_VIOLENCE );

    if ( wand->value[2] > 0 )
    {
	if ( victim != NULL )
	{
	    act( "$n zaps $N con $p.", ch, objToEnt(wand), chToEnt(victim), TO_NOTVICT );
	    act( "Tu zap $N con $p.", ch, objToEnt(wand), chToEnt(victim), TO_CHAR );
	    act( "$n zaps you con $p.",ch, objToEnt(wand), chToEnt(victim), TO_VICT );
	}
	else
	{
	    act( "$n zaps $P con $p.", ch, objToEnt(wand), objToEnt(obj), TO_ROOM );
	    act( "Tu zap $P con $p.", ch, objToEnt(wand), objToEnt(obj), TO_CHAR );
	}

 	if (getNivelPr(ch) < wand->level 
	||  number_percent() >= 20 + get_skill(ch,gsn_wands) * 4/5) 
	{
	    act( "Tus esfuerzos con $p solo produjeron chispas y humo.",
		 ch,objToEnt(wand),NULL,TO_CHAR);
	    act( "Los esfuerzos de $n con $p solo produjeron chispas y humo.",
		 ch,objToEnt(wand),NULL,TO_ROOM);
	    check_improve(ch,gsn_wands,FALSE,2);
	}
	else
	{
	    obj_cast_spell( wand->value[3], wand->value[0], objToEnt(wand), ch, obj ? objToEnt(obj) : chToEnt(victim) );
	    check_improve(ch,gsn_wands,TRUE,2);
	}
    }

    if ( --wand->value[2] <= 0 )
    {
	act( "$p de $n explota en mil pedazos.", ch, objToEnt(wand), NULL, TO_ROOM );
	act( "$p explota en mil pedazos.", ch, objToEnt(wand), NULL, TO_CHAR );
	extract_obj( wand, TRUE );
    }

    return;
}



void do_steal( CHAR_DATA *ch, char *argument )
{
    char buf  [MAX_STRING_LENGTH];
    char arg1 [MAX_INPUT_LENGTH];
    char arg2 [MAX_INPUT_LENGTH];
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    int percent;

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

    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	send_to_char( "Robar que de quien?\n\r", ch );
	return;
    }

    if ( ( victim = get_char_room( ch, arg2 ) ) == NULL )
    {
	send_to_char( "No esta aqui.\n\r", ch );
	return;
    }

    if ( victim == ch )
    {
	send_to_char( "Eso es estupido.\n\r", ch );
	return;
    }

    if (is_safe(ch,victim))
	return;

    if ( IS_NPC(victim) 
	  && victim->position == POS_FIGHTING)
    {
	send_to_char(  "Kill stealing no esta permitido.\n\r"
		       "Mejor no lo hagas -- podrias salir herido.\n\r",ch);
	return;
    }

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

    /* porcentaje de ser descubierto */
    percent  = number_percent();

    if (!IS_AWAKE(victim))
    	percent -= 20;
    else if (!can_see(victim,ch))
    	percent -= 25;

    percent -= get_skill(ch, gsn_steal) / 4;
    percent -= get_curr_stat(ch, STAT_DEX) / 2;
    percent += get_curr_stat(victim, STAT_DEX) / 2;
    percent += (getNivelPr(victim) - getNivelPr(ch)) * 10;

/*  if ( ((getNivelPr(ch) + 7 < getNivelPr(victim) || getNivelPr(ch) -7 > getNivelPr(victim)) 
    && !IS_NPC(victim) && !IS_NPC(ch) )
    || ( !IS_NPC(ch) && percent > get_skill(ch,gsn_steal))
    || ( !IS_NPC(ch) && !is_clan(ch)) ) */

    if ( (is_clan(ch) && (!is_clan(victim) || is_same_clan(ch, victim)))
    ||    CHANCE(percent)
    ||   !ENTRE_I( getNivelPr(victim) - 7, getNivelPr(ch), getNivelPr(victim) + 7 ) )
    {
	/*
	 * Failure.
	 */
	send_to_char( "Oops.\n\r", ch );
	affect_strip(ch,gsn_sneak);
	REMOVE_BIT(ch->affected_by,AFF_SNEAK);

	act( "$n intento robarte.", ch, NULL, chToEnt(victim), TO_VICT    );
	act( "$n intento robarle a $N.",  ch, NULL, chToEnt(victim), TO_NOTVICT );

	switch(number_range(0,3))
	{
	case 0 :
	   sprintf( buf, "%s es un maldito ladron!", PERS(ch, victim) );
	   break;
        case 1 :
	   sprintf( buf, "%s no podria robarle un dulce a un bebe!",
		    PERS(ch, victim) );
	   break;
	case 2 :
	    sprintf( buf,"%s intento robarme!", PERS(ch, victim) );
	    break;
	case 3 :
	    sprintf(buf,"Quita tus manos de ahi, %s!", PERS(ch, victim) );
	    break;
        }
	if ( IS_NPC(victim) )
		REMOVE_BIT(victim->comm, COMM_NOSHOUT);
        if (!IS_AWAKE(victim))
            do_wake(victim,"");
	if (IS_AWAKE(victim))
	    do_yell( victim, buf );
	if ( !IS_NPC(ch) )
	{
	    if ( IS_NPC(victim) )
	    {
	        check_improve(ch,gsn_steal,FALSE,2);
		multi_hit( victim, ch, TYPE_UNDEFINED );
	    }
	    else
	    {
		sprintf(buf,"$N intento robarle a %s.",victim->name);
		wiznet(buf,ch,NULL,WIZ_FLAGS,0,0);
		if ( !IS_SET(ch->act, PLR_THIEF) )
		{
		    SET_BIT(ch->act, PLR_THIEF);
		    send_to_char( "*** #BEres ahora un #FLADRON!!#f#b ***\n\r", ch );
		    save_char_obj( ch );
		}
	    }
	}
	else
		multi_hit( victim, ch, TYPE_UNDEFINED );

	return;
    }

    if ( !str_cmp( arg1, "coin"  )
    ||   !str_cmp( arg1, "coins" )
    ||   !str_cmp( arg1, "gold"  ) 
    ||	 !str_cmp( arg1, "silver"))
    {
	int gold, silver;

	gold = victim->gold * number_range(1, getNivelPr(ch)) / 60;
	silver = victim->silver * number_range(1,getNivelPr(ch)) / 60;
	if ( gold <= 0 && silver <= 0 )
	{
	    send_to_char( "No pudiste sacar ninguna moneda.\n\r", ch );
	    return;
	}

	ch->gold     	+= gold;
	ch->silver   	+= silver;
	victim->silver 	-= silver;
	victim->gold 	-= gold;
	if (silver <= 0)
	    sprintf( buf, "Bingo!  Obtuviste %d monedas de oro.\n\r", gold );
	else if (gold <= 0)
	    sprintf( buf, "Bingo!  Obtuviste %d monedas de plata.\n\r",silver);
	else
	    sprintf(buf, "Bingo!  Obtuviste %d monedas de plata y %d de oro.\n\r",
		    silver,gold);

	send_to_char( buf, ch );
	check_improve(ch,gsn_steal,TRUE,2);
	return;
    }

    if ( ( obj = get_obj_carry( victim, arg1, ch ) ) == NULL )
    {
	send_to_char( "No puedes encontrarlo.\n\r", ch );
	return;
    }
	
    if ( !can_drop_obj( ch, obj )
    ||   IS_SET(obj->extra_flags, ITEM_INVENTORY)
    ||   obj->level > getNivelPr(ch) )
    {
	send_to_char( "No pudiste sacarselo.\n\r", ch );
	return;
    }

    if ( ch->carry_number + get_obj_number( obj ) > can_carry_n( ch ) )
    {
	send_to_char( "Tienes tus manos llenas.\n\r", ch );
	return;
    }

    if ( ch->carry_weight + get_obj_weight( obj ) > can_carry_w( ch ) )
    {
	send_to_char( "No puedes llevar tanto peso.\n\r", ch );
	return;
    }

    obj_from_char( obj );
    obj_to_char( obj, ch );
    act("Robas $p.",ch,objToEnt(obj),NULL,TO_CHAR);
    check_improve(ch,gsn_steal,TRUE,2);
    send_to_char( "Lo tienes!\n\r", ch );
    return;
}



/*
 * Shopping commands.
 */
CHAR_DATA *find_keeper( CHAR_DATA *ch )
{
    /*char buf[MAX_STRING_LENGTH];*/
    CHAR_DATA *keeper;
    SHOP_DATA *pShop;

    pShop = NULL;
    for ( keeper = ch->in_room->people; keeper; keeper = keeper->next_in_room )
    {
	if ( IS_NPC(keeper) && (pShop = keeper->pIndexData->pShop) != NULL )
	    break;
    }

    if ( pShop == NULL )
    {
	send_to_char( "No puedes hacer eso aqui.\n\r", ch );
	return NULL;
    }

    REMOVE_BIT(keeper->comm, COMM_NOCHANNELS);

    /*
     * Undesirables.
     *
    if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_KILLER) )
    {
	do_say( keeper, "Asesinos no son bienvenidos!" );
	sprintf( buf, "%s el #BASESINO#b esta aqui!\n\r", ch->name );
	do_yell( keeper, buf );
	return NULL;
    }

    if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_THIEF) )
    {
	do_say( keeper, "Ladrones no son bienvenidos!" );
	sprintf( buf, "%s el #BTHIEF#b esta aqui!\n\r", ch->name );
	do_yell( keeper, buf );
	return NULL;
    }
	*/
    /*
     * Shop hours.
     */
    if ( time_info.hour < pShop->open_hour )
    {
	do_say( keeper, "Lo lamento, esta cerrado. Vuelve mas tarde." );
	return NULL;
    }
    
    if ( time_info.hour > pShop->close_hour )
    {
	do_say( keeper, "Lo lamento, esta cerrado. Vuelve manana." );
	return NULL;
    }

    /*
     * Invisible or hidden people.
     */
    if ( !can_see( keeper, ch ) )
    {
	do_say( keeper, "No trato con gente que no puedo ver." );
	return NULL;
    }

    return keeper;
}

/* insert an object at the right spot for the keeper */
void obj_to_keeper( OBJ_DATA *obj, CHAR_DATA *ch )
{
    OBJ_DATA *t_obj, *t_obj_next;

    /* see if any duplicates are found */
    for (t_obj = ch->carrying; t_obj != NULL; t_obj = t_obj_next)
    {
	t_obj_next = t_obj->next_content;

	if (obj->pIndexData == t_obj->pIndexData 
	&&  !str_cmp(obj->short_descr,t_obj->short_descr))
	{
	    /* if this is an unlimited item, destroy the new one */
	    if (IS_OBJ_STAT(t_obj,ITEM_INVENTORY))
	    {
		extract_obj(obj, TRUE);
		return;
	    }
	    obj->cost = t_obj->cost; /* keep it standard */
	    break;
	}
    }

    if (t_obj == NULL)
    {
	obj->next_content = ch->carrying;
	ch->carrying = obj;
    }
    else
    {
	obj->next_content = t_obj->next_content;
	t_obj->next_content = obj;
    }

    obj->carried_by      = ch;
    obj->in_room         = NULL;
    obj->in_obj          = NULL;
    ch->carry_number    += get_obj_number( obj );
    ch->carry_weight    += get_obj_weight( obj );
}

/* get an object from a shopkeeper's list */
OBJ_DATA *get_obj_keeper( CHAR_DATA *ch, CHAR_DATA *keeper, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    int number;
    int count;
 
    number = number_argument( argument, arg );
    count  = 0;
    for ( obj = keeper->carrying; obj != NULL; obj = obj->next_content )
    {
        if (obj->wear_loc == WEAR_NONE
        &&  can_see_obj( keeper, obj )
	&&  can_see_obj(ch,obj)
        &&  is_name( arg, obj->name ) )
        {
            if ( ++count == number )
                return obj;
	
	    /* skip other objects of the same name */
	    while (obj->next_content != NULL
	    && obj->pIndexData == obj->next_content->pIndexData
	    && !str_cmp(obj->short_descr,obj->next_content->short_descr))
		obj = obj->next_content;
        }
    }
 
    return NULL;
}

int get_cost( CHAR_DATA *keeper, OBJ_DATA *obj, bool fBuy )
{
    SHOP_DATA *pShop;
    int cost;

    if ( obj == NULL || ( pShop = keeper->pIndexData->pShop ) == NULL )
	return 0;

    if ( fBuy )
    {
	cost = obj->cost * pShop->profit_buy  / 100;
    }
    else
    {
	OBJ_DATA *obj2;
	int itype;

	cost = 0;
	for ( itype = 0; itype < MAX_TRADE; itype++ )
	{
	    if ( obj->item_type == pShop->buy_type[itype] )
	    {
		cost = obj->cost * pShop->profit_sell / 100;
		break;
	    }
	}

	if (!IS_OBJ_STAT(obj,ITEM_SELL_EXTRACT))
	    for ( obj2 = keeper->carrying; obj2; obj2 = obj2->next_content )
	    {
	    	if ( obj->pIndexData == obj2->pIndexData
		&&  !str_cmp(obj->short_descr,obj2->short_descr) )
		{
			if (IS_OBJ_STAT(obj2,ITEM_INVENTORY))
				cost /= 2;
			else
				cost = cost * 3 / 4;
		}
	    }
    }

    if ( obj->item_type == ITEM_STAFF || obj->item_type == ITEM_WAND )
    {
	if (obj->value[1] == 0)
	    cost /= 4;
	else
	    cost = cost * obj->value[2] / obj->value[1];
    }

    return cost;
}



void do_buy( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];
    int cost,roll;

    if ( argument[0] == '\0' )
    {
	send_to_char( "Comprar que?\n\r", ch );
	return;
    }

    if ( IS_SET(ch->in_room->room_flags, ROOM_PET_SHOP) )
    {
	char arg[MAX_INPUT_LENGTH];
	char buf2[MAX_STRING_LENGTH];
	CHAR_DATA *pet;
	ROOM_INDEX_DATA *pRoomIndexNext;

	if ( IS_NPC(ch) )
	    return;

	argument = one_argument(argument,arg);

	/* hack to make new thalos pets work */
	if (ch->in_room->vnum == 9621)
	    pRoomIndexNext = get_room_index(9706);
	else
	    pRoomIndexNext = get_room_index( ch->in_room->vnum + 1 );

	if ( pRoomIndexNext == NULL )
	{
	    bug( "Do_buy: bad pet shop at vnum %d.", ch->in_room->vnum );
	    send_to_char( "Lo lamento, no puedes comprar eso aqui.\n\r", ch );
	    return;
	}

	pet         = alt_get_char_room( pRoomIndexNext, arg );

	if ( pet == NULL || !IS_SET(pet->act, ACT_PET) )
	{
	    send_to_char( "Lo lamento, no vendo de ese tipo de mascotas.\n\r", ch );
	    return;
	}

	if ( ch->pet != NULL )
	{
	    send_to_char("Ya tienes una mascota.\n\r",ch);
	    return;
	}

 	cost = 10 * getNivelPr(pet) * getNivelPr(pet);

	if ( (ch->silver + 100 * ch->gold) < cost )
	{
	    send_to_char( "No te alcanza el dinero.\n\r", ch );
	    return;
	}

	if ( getNivelPr(ch) < getNivelPr(pet) )
	{
	    send_to_char(
		"No eres lo suficientemente poderoso para poder dominar esta mascota.\n\r", ch );
	    return;
	}

	/* haggle */
	roll = number_percent();
	if (roll < get_skill(ch,gsn_haggle))
	{
	    cost -= cost / 2 * roll / 100;
	    sprintf(buf2,"Regateas, y logras que el precio baje a %d monedas.\n\r",cost);
	    send_to_char(buf2,ch);
	    check_improve(ch,gsn_haggle,TRUE,4);
	}

	deduct_cost(ch,cost);
	pet			= create_mobile( pet->pIndexData );
	SET_BIT(pet->act, ACT_PET);
	SET_BIT(pet->affected_by, AFF_CHARM);
	pet->comm = COMM_NOTELL|COMM_NOSHOUT|COMM_NOCHANNELS;

	argument = one_argument( argument, arg );
	if ( arg[0] != '\0' )
	{
	    sprintf( buf2, "%s %s", pet->name, arg );
	    free_string( pet->name );
	    pet->name = str_dup( buf2 );
	}

	sprintf( buf2, "%sUna etiqueta en el cuello dice 'Pertenezco a %s'.\n\r",
	    pet->description, ch->name );
	free_string( pet->description );
	pet->description = str_dup( buf2 );

	char_to_room( pet, ch->in_room );
	add_follower( pet, ch );
	pet->leader = ch;
	ch->pet = pet;
	send_to_char( "Disfruta tu mascota.\n\r", ch );
	act( "$n compro $N como mascota.", ch, NULL, chToEnt(pet), TO_ROOM );
	return;
    }
    else
    {
	CHAR_DATA *keeper;
	OBJ_DATA *obj,*t_obj;
	char arg[MAX_INPUT_LENGTH];
	int number, count = 1;

	if ( ( keeper = find_keeper( ch ) ) == NULL )
	    return;

	number = mult_argument(argument,arg);
	obj  = get_obj_keeper( ch,keeper, arg );
	cost = get_cost( keeper, obj, TRUE );

	if (number < 1 || number > 99)
	{
	    act("$n te dice 'Se realista!'",keeper,NULL,chToEnt(ch),TO_VICT);
	    return;
	}

	if ( obj != NULL && IS_SET( obj->extra_flags, ITEM_PROTOTIPO ) )
	{
	    act("$n te dice 'Ese es un objeto prototipo.'", keeper, NULL, chToEnt(ch),
	    	TO_VICT );
	    return;
	}

	if ( cost <= 0 || !can_see_obj( ch, obj ) )
	{
	    act( "$n te dice 'No vendo eso -- intenta 'list''.",
		keeper, NULL, chToEnt(ch), TO_VICT );
	    ch->reply = keeper;
	    return;
	}

	if (!IS_OBJ_STAT(obj,ITEM_INVENTORY))
	{
	    for (t_obj = obj->next_content;
	     	 count < number && t_obj != NULL; 
	     	 t_obj = t_obj->next_content) 
	    {
	    	if (t_obj->pIndexData == obj->pIndexData
	    	&&  !str_cmp(t_obj->short_descr,obj->short_descr))
		    count++;
	    	else
		    break;
	    }

	    if (count < number)
	    {
	    	act("$n te dice 'No tengo tantos en stock.",
		    keeper,NULL,chToEnt(ch),TO_VICT);
	    	ch->reply = keeper;
	    	return;
	    }
	}

	if ( (ch->silver + ch->gold * 100) < cost * number )
	{
	    if (number > 1)
		act("$n te dice 'No tienes tanto dinero como para comprar esa cantidad.",
		    keeper,objToEnt(obj),chToEnt(ch),TO_VICT);
	    else
	    	act( "$n te dice 'No tienes suficiente dinero para poder comprar $p'.",
		    keeper, objToEnt(obj), chToEnt(ch), TO_VICT );
	    ch->reply = keeper;
	    return;
	}
	
	if ( obj->level > getNivelPr(ch) )
	{
	    act( "$n te dice 'No puedes usar $p todavia'.",
		keeper, objToEnt(obj), chToEnt(ch), TO_VICT );
	    ch->reply = keeper;
	    return;
	}

	if (ch->carry_number +  number * get_obj_number(obj) > can_carry_n(ch))
	{
	    send_to_char( "No puedes acarrear tantos items.\n\r", ch );
	    return;
	}

	if ( ch->carry_weight + number * get_obj_weight(obj) > can_carry_w(ch))
	{
	    send_to_char( "No puedes llevar tanto peso.\n\r", ch );
	    return;
	}

	/* haggle */
	roll = number_percent();
	if (!IS_OBJ_STAT(obj,ITEM_SELL_EXTRACT) 
	&& roll < get_skill(ch,gsn_haggle))
	{
	    cost -= obj->cost / 2 * roll / 100;
	    act("Regateas con $N.",ch,NULL,chToEnt(keeper),TO_CHAR);
	    check_improve(ch,gsn_haggle,TRUE,4);
	}

	if (number > 1)
	{
	    sprintf(buf,"$n compra $p[%d].",number);
	    act(buf,ch,objToEnt(obj),NULL,TO_ROOM);
	    sprintf(buf,"Compras $p[%d] por %d monedas de plata.",number,cost * number);
	    act(buf,ch,objToEnt(obj),NULL,TO_CHAR);
	}
	else
	{
	    act( "$n compra $p.", ch, objToEnt(obj), NULL, TO_ROOM );
	    sprintf(buf,"Compras $p por %d monedas de plata.",cost);
	    act( buf, ch, objToEnt(obj), NULL, TO_CHAR );
	}
	deduct_cost(ch,cost * number);
	keeper->gold += cost * number/100;
	keeper->silver += cost * number - (cost * number/100) * 100;

	for (count = 0; count < number; count++)
	{
	    if ( IS_SET( obj->extra_flags, ITEM_INVENTORY ) )
	    	t_obj = create_object( obj->pIndexData, obj->level );
	    else
	    {
		t_obj = obj;
		obj = obj->next_content;
	    	obj_from_char( t_obj );
	    }

	    if (t_obj->timer > 0 && !IS_OBJ_STAT(t_obj,ITEM_HAD_TIMER))
	    	t_obj->timer = 0;
	    REMOVE_BIT(t_obj->extra_flags,ITEM_HAD_TIMER);
	    obj_to_char( t_obj, ch );
	    if (cost < t_obj->cost)
	    	t_obj->cost = cost;
	}
    }
}

void do_list( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];

    if ( IS_SET(ch->in_room->room_flags, ROOM_PET_SHOP) )
    {
	ROOM_INDEX_DATA *pRoomIndexNext;
	CHAR_DATA *pet;
	bool found;

        /* hack to make new thalos pets work */
        if (ch->in_room->vnum == 9621)
            pRoomIndexNext = get_room_index(9706);
        else
            pRoomIndexNext = get_room_index( ch->in_room->vnum + 1 );

	if ( pRoomIndexNext == NULL )
	{
	    bug( "Do_list: bad pet shop at vnum %d.", ch->in_room->vnum );
	    send_to_char( "No puedes hacer eso aqui.\n\r", ch );
	    return;
	}

	found = FALSE;
	for ( pet = pRoomIndexNext->people; pet; pet = pet->next_in_room )
	{
	    if ( IS_SET(pet->act, ACT_PET) )
	    {
		if ( !found )
		{
		    found = TRUE;
		    send_to_char( "Mascotas en venta:\n\r", ch );
		}
		sprintf( buf, "[%2d] %8d - %s\n\r",
		    getNivelPr(pet),
		    10 * getNivelPr(pet) * getNivelPr(pet),
		    pet->short_descr );
		send_to_char( buf, ch );
	    }
	}
	if ( !found )
	    send_to_char( "Lo lamento, se nos acabaron las mascotas.\n\r", ch );
	return;
    }
    else
    {
	CHAR_DATA *keeper;
	OBJ_DATA *obj;
	int cost,count;
	bool found;
	char arg[MAX_INPUT_LENGTH];

	if ( ( keeper = find_keeper( ch ) ) == NULL )
	    return;
        one_argument(argument,arg);

	found = FALSE;
	for ( obj = keeper->carrying; obj; obj = obj->next_content )
	{
	    if ( obj->wear_loc == WEAR_NONE
	    &&   can_see_obj( ch, obj )
	    &&   ( cost = get_cost( keeper, obj, TRUE ) ) > 0 
	    &&   ( arg[0] == '\0'  
 	       ||  is_name(arg,obj->name) ))
	    {
		if ( !found )
		{
		    found = TRUE;
		    send_to_char( "[Ni Preci Can] Item\n\r", ch );
		}

		if (IS_OBJ_STAT(obj,ITEM_INVENTORY))
		    sprintf(buf,"[%2d %5d -- ] %s\n\r",
			obj->level,cost,obj->short_descr);
		else
		{
		    count = 1;

		    while (obj->next_content != NULL 
		    && obj->pIndexData == obj->next_content->pIndexData
		    && !str_cmp(obj->short_descr,
			        obj->next_content->short_descr))
		    {
			obj = obj->next_content;
			count++;
		    }
		    sprintf(buf,"[%2d %5d %2d ] %s\n\r",
			obj->level,cost,count,obj->short_descr);
		}
		send_to_char( buf, ch );
	    }
	}

	if ( !found )
	    send_to_char( "No puedes comprar nada aqui.\n\r", ch );
	return;
    }
}



void do_sell( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *keeper;
    OBJ_DATA *obj;
    int cost,roll;

    one_argument( argument, arg );

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

    if ( ( keeper = find_keeper( ch ) ) == NULL )
	return;

    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
    {
	act( "$n te dice 'No tienes ese item'.",
	    keeper, NULL, chToEnt(ch), TO_VICT );
	ch->reply = keeper;
	return;
    }

    if ( !can_drop_obj( ch, obj ) )
    {
	send_to_char( "No puedes soltarlo.\n\r", ch );
	SET_BIT(obj->detected, DETECTED_CURSE);
	return;
    }

    if ( IS_OBJ_STAT(obj, ITEM_FLAMING) )
    {
    	send_to_char( "No puedes vender eso.\n\r", ch );
    	return;
    }

    if (!can_see_obj(keeper,obj))
    {
	act("$n no ve lo que le estas ofreciendo.",keeper,NULL,chToEnt(ch),TO_VICT);
	return;
    }

    if ( ( cost = get_cost( keeper, obj, FALSE ) ) <= 0 )
    {
	act( "$n no se ve interesado en $p.", keeper, objToEnt(obj), chToEnt(ch), TO_VICT );
	return;
    }
    if ( cost > (keeper-> silver + 100 * keeper->gold) )
    {
	act("$n te dice 'Lo lamento, pero no tengo suficiente dinero para comprarte $p'.",
	    keeper,objToEnt(obj),chToEnt(ch),TO_VICT);
	return;
    }

    act( "$n vende $p.", ch, objToEnt(obj), NULL, TO_ROOM );
    /* haggle */
    roll = number_percent();
    if (!IS_OBJ_STAT(obj,ITEM_SELL_EXTRACT) && roll < get_skill(ch,gsn_haggle))
    {
        send_to_char("Regateas con el vendedor.\n\r",ch);
        cost += obj->cost / 2 * roll / 100;
        cost = UMIN(cost,95 * get_cost(keeper,obj,TRUE) / 100);
	cost = UMIN(cost,(keeper->silver + 100 * keeper->gold));
        check_improve(ch,gsn_haggle,TRUE,4);
    }
    sprintf( buf, "Vendes $p por %d moneda%s de plata y %d moneda%s de oro.",
	cost - (cost/100) * 100, ( ( cost - (cost/100) * 100 ) == 1 ) ? "" : "s",
        cost/100, cost == 1 ? "" : "s" );
    act( buf, ch, objToEnt(obj), NULL, TO_CHAR );
    ch->gold     += cost/100;
    ch->silver 	 += cost - (cost/100) * 100;
    deduct_cost(keeper,cost);
    if ( keeper->gold < 0 )
	keeper->gold = 0;
    if ( keeper->silver< 0)
	keeper->silver = 0;

    if ( obj->item_type == ITEM_TRASH || IS_OBJ_STAT(obj,ITEM_SELL_EXTRACT))
    {
	extract_obj( obj, TRUE );
    }
    else
    {
	obj_from_char( obj );
	if (obj->timer)
	    SET_BIT(obj->extra_flags,ITEM_HAD_TIMER);
	else
	    obj->timer = number_range(50,100);
	obj_to_keeper( obj, keeper );
    }

    return;
}



void do_value( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *keeper;
    OBJ_DATA *obj;
    int cost;

    one_argument( argument, arg );

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

    if ( ( keeper = find_keeper( ch ) ) == NULL )
	return;

    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
    {
	act( "$n te dice 'No tienes ese item'.",
	    keeper, NULL, chToEnt(ch), TO_VICT );
	ch->reply = keeper;
	return;
    }

    if (!can_see_obj(keeper,obj))
    {
        act("$n no ve lo que le estas ofreciendo.",keeper,NULL,chToEnt(ch),TO_VICT);
        return;
    }

    if ( !can_drop_obj( ch, obj ) )
    {
	send_to_char( "No puedes soltarlo.\n\r", ch );
	SET_BIT(obj->detected, DETECTED_CURSE);
	return;
    }

    if ( ( cost = get_cost( keeper, obj, FALSE ) ) <= 0 )
    {
	act( "$n no se ve interesado en $p.", keeper, objToEnt(obj), chToEnt(ch), TO_VICT );
	return;
    }

    sprintf( buf, 
	"$n te dice 'Te daria %d monedas de plata y %d monedas de oro por $p'.", 
	cost - (cost/100) * 100, cost/100 );
    act( buf, keeper, objToEnt(obj), chToEnt(ch), TO_VICT );
    ch->reply = keeper;

    return;
}

/*
 * Hide objects... by Maniac!
 */
void do_hide_obj(CHAR_DATA *ch, char *argument)
{
    char	arg[MAX_INPUT_LENGTH];
    int		chance;
    OBJ_DATA	*obj;

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

    obj = get_obj_carry(ch, arg, ch);
    if ( obj == NULL )
    {
        send_to_char("No puedes encontrarlo.\n\r", ch);
        return;
    }

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

    chance = number_range(1, 5);

    if (es_clase(ch, CLASS_RANGER))
	chance += 2;
    else
    if (es_clase(ch, CLASS_THIEF))
	chance++;

    if (chance > 5)			/* Let's not push it... */
	chance = 5;
    if ( IS_IMMORTAL(ch) )
	chance = 5;
    switch (chance)			/* Let's see what we've got */
    {
	case 1:
		act("$n esta a cuatro patas tratando de esconder $p.", ch, objToEnt(obj), NULL, TO_ROOM );
		act("Intentas esconder $p, pero fallas miserablemente.", ch, objToEnt(obj), NULL, TO_CHAR );
		break;
	case 2:
		act("$n esta a cuatro patas cavando en el suelo.", ch, NULL, NULL, TO_ROOM );
		act("Escondes $p, pero lo hiciste en forma obvia.", ch, objToEnt(obj), NULL, TO_CHAR );
		obj_from_char(obj);
		obj_to_room(obj, ch->in_room);
		SET_BIT(obj->extra_flags, ITEM_HIDDEN);
		break;
	case 3:
		act( "Fallas en esconder $p.", ch, objToEnt(obj), NULL, TO_CHAR );
		break;
	case 4:
	case 5:
		act( "Escondes $p.", ch, objToEnt(obj), NULL, TO_CHAR );
		obj_from_char(obj);
		obj_to_room(obj, ch->in_room);
		SET_BIT(obj->extra_flags, 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;
    int	chance;

    buf[0] = buf2[0] = '\0';

    for ( obj = ch->in_room->contents;obj && (!found); obj = obj->next_content )
    {
        if ( IS_SET(obj->extra_flags, ITEM_HIDDEN) )
        {
		chance = number_range( 1, 5);
		if (es_clase(ch, CLASS_THIEF)
		||  es_clase(ch, CLASS_RANGER))
			chance++; 
		if (IS_IMMORTAL(ch))
		    chance = 5;
		if (chance > 3)
		{
			sprintf(buf, "Encuentras %s.\n\r", obj->short_descr);
			strcat(buf2, buf);
			REMOVE_BIT(obj->extra_flags, ITEM_HIDDEN);
			found = TRUE;
		}
        }
    }
    if (!found)
	sprintf(buf2, "No encontraste nada.\n\t");

    send_to_char(buf2, ch);
    buf2[0] = '\0';
}

/* Original Code by Todd Lair.                                        */
/* Improvements and Modification by Jason Huang (huangjac@netcom.com).*/
/* Permission to use this code is granted provided this header is     */
/* retained and unaltered.                                            */

void do_brew ( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    int sn, skill;

    skill = get_skill(ch, gsn_brew);

    if ( skill < 1 )
    {                                          
	send_to_char( "No sabes como preparar pociones.\n\r", ch );
	return;
    }

    argument = one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	send_to_char( "Hacer una pocion de que spell?\n\r", ch );
	return;
    }

    obj = get_eq_char( ch, WEAR_HOLD );

    /* Interesting ... Most scrolls/potions in the mud have no hold
       flag; so, the problem with players running around making scrolls 
       with 3 heals or 3 gas breath from pre-existing scrolls has been 
       severely reduced. Still, I like the idea of 80% success rate for  
       first spell imprint, 25% for 2nd, and 10% for 3rd. I don't like the
       idea of a scroll with 3 ultrablast spells; although, I have limited
       its applicability when I reduced the spell->level to 1/3 and 1/4 of 
       getNivelPr(ch) for scrolls and potions respectively. --- JH */

    /* I will just then make two items, an empty vial and a parchment available
       in midgaard shops with holdable flags and -1 for each of the 3 spell
       slots. Need to update the midgaard.are files --- JH */

    if ( !obj || obj->item_type != ITEM_POTION )
    {
	send_to_char( "No estas sosteniendo un vial.\n\r", ch );
	return;
    }

    if ( ( sn = skill_lookup(arg) )  < 0)
    {
	send_to_char( "No conoces ningun spell que se llame asi.\n\r", ch );
	return;
    }

    /* preventing potions of gas breath, acid blast, etc.; doesn't make sense
       when you quaff a gas breath potion, and then the mobs in the room are
       hurt. Those TAR_IGNORE spells are a mixed blessing. - JH */
  
    if ( (skill_table[sn].target != TAR_CHAR_DEFENSIVE) && 
         (skill_table[sn].target != TAR_CHAR_SELF)              ) 
    {
	send_to_char( "No puedes preparar ese spell.\n\r", ch );
	return;
    }

    act( "$n empieza a preparar una pocion.", ch, objToEnt(obj), NULL, TO_ROOM );
    WAIT_STATE( ch, skill_table[gsn_brew].beats );

    /* Check the skill percentage, fcn(wis,int,skill) */
    if ( !CHANCE(skill)
    ||   !CHANCE((get_curr_stat(ch, STAT_WIS)+get_curr_stat(ch, STAT_INT))*2) )
    {
	act( "$p explota violentamente!", ch, objToEnt(obj), NULL, TO_ALL );

        spell_acid_blast(gsn_acid_blast, LEVEL_HERO - 1, chToEnt(ch), chToEnt(ch), TARGET_CHAR );

	extract_obj( obj, TRUE );
	return;
    }

    /* took this outside of imprint codes, so I can make do_brew differs from
       do_scribe; basically, setting potion level and spell level --- JH */

    obj->level		= getNivelPr(ch)/2;
    obj->value[0]	= getNivelPr(ch)/4;

    spell_imprint(sn, getNivelPr(ch), chToEnt(ch), objToEnt(obj), TARGET_OBJ ); 
}

void do_scribe ( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    int sn, skill;

    skill = get_skill(ch, gsn_scribe);

    if ( skill < 1 )
    {                                          
	send_to_char( "No sabes escribir scrolls.\n\r", ch );
	return;
    }

    argument = one_argument( argument, arg );

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

    /* Do we have a parchment to scribe spells? */
    obj = get_eq_char( ch, WEAR_HOLD );

    if ( !obj || obj->item_type != ITEM_SCROLL )
    {
	send_to_char( "No estas sosteniendo un papel.\n\r", ch );
	return;
    }

    if ( ( sn = skill_lookup(arg) )  < 0)
    {
	send_to_char( "No conoces ningun spell con ese nombre.\n\r", ch );
	return;
    }
    
    act( "$n empieza a escribir un scroll.", ch, objToEnt(obj), NULL, TO_ROOM );
    WAIT_STATE( ch, skill_table[gsn_scribe].beats );

    /* Check the skill percentage, fcn(int,wis,skill) */
    if ( !CHANCE(skill)
    ||   !CHANCE((get_curr_stat(ch, STAT_WIS)+get_curr_stat(ch, STAT_INT))*2) )
    {
	act( "$p se convierte en fuego!", ch, objToEnt(obj), NULL, TO_ALL );
        spell_fireball(gsn_fireball, LEVEL_HERO - 1, chToEnt(ch), chToEnt(ch), TARGET_CHAR ); 
	extract_obj( obj, TRUE );
	return;
    }

    /* basically, making scrolls more potent than potions; also, scrolls
       are not limited in the choice of spells, i.e. scroll of enchant weapon
       has no analogs in potion forms --- JH */

    obj->level		= getNivelPr(ch)*2/3;
    obj->value[0]	= getNivelPr(ch)/3;

    spell_imprint(sn, getNivelPr(ch), chToEnt(ch), objToEnt(obj), TARGET_OBJ ); 
}

/* Contributed by BoneCrusher of EnvyMud. */
void do_donate( CHAR_DATA *ch, char *arg )
{
    OBJ_DATA *container;
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    OBJ_DATA *repobj;
    OBJ_DATA *repobj_next;
    ROOM_INDEX_DATA *antes, *pit;
    int	roomvnum;
    char      arg1[MAX_INPUT_LENGTH];
    char      buf[MSL];

    arg = one_argument( arg, arg1 );

    if ( arg1[0] == '\0' )
    {
	send_to_char( "Donar que?\n\r", ch );
	return;
    }

    if ( IS_NPC(ch) || !is_clan(ch) )
    	roomvnum = ROOM_VNUM_ALTAR;
    else
	roomvnum = get_clan_table(ch->clan)->pit;

    pit		= get_room_index( roomvnum );
    antes	= ch->in_room; /* donde estaba antes */

    if ( !pit || !antes )
    {
    	send_to_char( "Algo salio mal.\n\r", ch );
    	return;
    }

    char_from_room( ch );
    char_to_room( ch, pit );

    if ( ( container = get_obj_here( ch, "donation pit" ) ) == NULL )
    {
	send_to_char( "El donation pit no esta en esta realidad.\n\r", ch );
	char_from_room( ch );
	char_to_room( ch, antes );
	return;
    }

    char_from_room( ch );
    char_to_room( ch, antes );

    if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
    {
	if ( ( obj = get_obj_carry( ch, arg1 , ch ) ) == NULL )
	{
	    send_to_char( "No tienes ese item.\n\r", ch );
	    return;
	}

	if ( !can_drop_obj( ch, obj ) )
	{
	    send_to_char( "No puedes soltarlo.\n\r", ch );
	    SET_BIT(obj->detected, DETECTED_CURSE);
	    return;
	}
	
	if ( obj->item_type == ITEM_TRASH
	    || obj->item_type == ITEM_FOOD
	    || obj->item_type == ITEM_KEY
	    || obj->item_type == ITEM_PILL )
	{
	    act( "Envias $p volando hacia $P.", ch, objToEnt(obj), objToEnt(container),
		TO_CHAR );
	    extract_obj( obj, TRUE );
	    return;
	}

	obj_from_char( obj );
	obj_to_obj( obj, container );
	act( "$n envia $p volando hacia $P.", ch, objToEnt(obj), objToEnt(container), TO_ROOM );
	act( "Envias $p volando hacia $P.", ch, objToEnt(obj), objToEnt(container), TO_CHAR );
	send_to_room( "Un ruido metalico se escucha desde el pit!",
		     container->in_room );
    }
    else
    {
	int count = 0, glcount = 0;
	char shd[MSL];

	for ( obj = ch->carrying; obj; obj = obj_next )
	{
		obj_next = obj->next_content;

		if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) )
		&& can_see_obj( ch, obj )
		&& obj->wear_loc == WEAR_NONE
		&& obj != container
		&& can_drop_obj( ch, obj ) )
		{
			count	= 0;
			strcpy(shd,obj->short_descr);
			for ( repobj = obj; repobj; repobj = repobj_next )
			{
				repobj_next = repobj->next_content;

				if ( !can_see_obj( ch, repobj )
				||   repobj->wear_loc != WEAR_NONE
				||   obj->pIndexData != repobj->pIndexData
				||   !can_drop_obj( ch, repobj ) )
					continue;

				if ( repobj == obj_next )
					obj_next = repobj_next;

				count++;

				if ( repobj->item_type == ITEM_TRASH
				|| repobj->item_type == ITEM_FOOD
				|| repobj->item_type == ITEM_KEY
				|| repobj->item_type == ITEM_PILL )
				{
					extract_obj( repobj, TRUE );
					continue;
				}

				obj_from_char(repobj);
				obj_to_obj( repobj, container );
			}
			if ( count > 1 )
				sprintf( buf, "$n envia %d*%s volando hacia $P.", count, shd );
			else
				sprintf( buf, "$n envia %s volando hacia $P.", shd );
			act( buf, ch, NULL, objToEnt(container), TO_ROOM );
			if ( count > 1 )
				sprintf( buf, "Envias %d*%s volando hacia $P.", count, shd );
			else
				sprintf( buf, "Envias %s volando hacia $P.", shd );
			act( buf, ch, NULL, objToEnt(container), TO_CHAR );
			glcount += count;
		}
	}
	if (glcount > 0)
	{
		sprintf(buf, "%d ruido%s metalico%s se escucha%s desde el pit!",
		glcount, glcount == 1 ? "" : "s", glcount == 1 ? "" : "s",
		glcount == 1 ? "" : "n" );
		send_to_room( buf, container->in_room );
	}
    }

    return;
}

/* Poison weapon by Thelonius for EnvyMud */
/* Blade thirst code is a changed version of poison weapon */
/* Written by The Maniac. This skill came from the internet book */
/* The Tome of Mighty Magic */
void do_bladethirst( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj;
    OBJ_DATA *pobj;
    OBJ_DATA *wobj;
    AFFECT_DATA *paf;
    char      arg [ MAX_INPUT_LENGTH ];

    if ( get_skill(ch, gsn_bladethirst) < 1 )
    {                                          
	send_to_char( "Que crees que eres, un necromancer?\n\r", ch );
	return;
    }

    one_argument( argument, arg );

    if ( arg[0] == '\0' )                                              
    { send_to_char( "Que tratas de hacer...?\n\r",    ch ); return; }
    if ( ch->fighting )                                       
    { send_to_char( "Mientras peleas?  Buen intento.\n\r", ch ); return; }
    if ( !( obj = get_obj_carry( ch, arg , ch ) ) )
    { send_to_char( "No tienes esa arma.\n\r",      ch ); return; }
    if ( obj->item_type != ITEM_WEAPON )
    { send_to_char( "Eso no es un arma.\n\r",        ch ); return; }
    if ( IS_OBJ_STAT( obj, ITEM_BLADE_THIRST ) )
    { send_to_char( "Esa arma ya esta sedienta.\n\r",  ch ); return; }

 /* Now we have a valid weapon...check to see if we have the bar of mithril. */
    for ( pobj = ch->carrying; pobj; pobj = pobj->next_content )
    {
	if ( pobj->pIndexData->vnum == OBJ_VNUM_MITHRIL )
	    break;
    }
    if ( !pobj )
    {
	send_to_char( "No tienes el mithril.\n\r", ch );
	return;
    }

    /* Okay, we have the mithril...do we have blood? */
    for ( wobj = ch->carrying; wobj; wobj = wobj->next_content )
    {
	if ( wobj->item_type == ITEM_DRINK_CON
	    && wobj->value[1]  >  0
	    && wobj->value[2]  == liq_lookup( "blood" ) )
	    break;
    }
    if ( !wobj )
    {
	send_to_char( "Necesitas un poco de sangre para este skill.\n\r", ch );
	return;
    }

    /* Great, we have the ingredients...but is the ch smart enough? */
    if ( !IS_NPC( ch ) && get_curr_stat( ch , STAT_WIS ) < 17 )
    {
	send_to_char( "No recuerdas como hacerlo...\n\r", ch );
	return;
    }
    /* And does he have steady enough hands? */
    if ( !IS_NPC( ch )
	&& ( get_curr_stat( ch , STAT_DEX ) < 17
	    || ch->pcdata->condition[COND_DRUNK] > 0 ) )
    {
	send_to_char(
	"Tus manos son muy torpes como para poder mezclar los ingredientes.\n\r",
								ch );
	return;
    }

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

    /* Check the skill percentage */
    if ( !IS_NPC( ch )
	&& number_percent( ) > ch->pcdata->learned[gsn_bladethirst] )
    {
	send_to_char( "Fallas y derramas un poco sobre ti.  Ouch!\n\r",
		     ch );
	damage_old( ch, ch, getNivelPr(ch) * 2, gsn_bladethirst, DAM_ACID, TRUE );
	act( "$n derrama la mezcla en el suelo!", ch, NULL, NULL, TO_ROOM );
	extract_obj( pobj, TRUE );
	extract_obj( wobj, TRUE );
	return;
    }

    /* Well, I'm tired of waiting.  Are you? */
    act( "Mezclas $p en $P, creando una pocion maldita!",
	ch, objToEnt(pobj), objToEnt(wobj), TO_CHAR );
    act( "$n mezcla $p en $P, creando una pocion maldita!",
	ch, objToEnt(pobj), objToEnt(wobj), TO_ROOM );
    act( "Derramas la pocion sobre $p, que brilla malignamente!",
	ch, objToEnt(obj), NULL, TO_CHAR  );
    act( "$n derrama la pocion sobre $p, que brilla malignamente!",
	ch, objToEnt(obj), NULL, TO_ROOM  );
    SET_BIT( obj->extra_flags, ITEM_BLADE_THIRST );
    obj->cost *= getNivelPr(ch);

    /* Set an object timer.  Dont want proliferation of thirsty weapons */
    obj->timer = 10 + getNivelPr(ch);

    if ( IS_OBJ_STAT( obj, ITEM_BLESS ) )
	obj->timer *= 2;

    if ( IS_OBJ_STAT( obj, ITEM_MAGIC ) )
	obj->timer *= 2;

    /* WHAT?  All of that, just for that one bit?  How lame. ;) */
    act( "El resto de la pocion corroe $p, que se desvanece.",
	ch, objToEnt(wobj), NULL, TO_CHAR );
    act( "El resto de la pocion corroe $p, que se desvanece.",
	ch, objToEnt(wobj), NULL, TO_ROOM );
    extract_obj( pobj, TRUE );
    extract_obj( wobj, TRUE );

    paf			= new_affect();
    paf->type           = -1;
    paf->duration       = -1;
    paf->location       = APPLY_HITROLL;
    paf->modifier       = 3;
    paf->bitvector      = 0;
    paf->next           = obj->affected;
    obj->affected       = paf;

    return;
}

/* Study skill... converted from Rom by Maniac */
void do_study( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    OBJ_DATA *scroll;

    argument = one_argument(argument, arg1);

    if (( scroll = get_obj_carry(ch,arg1,ch)) == NULL)
    {
        send_to_char("No tienes ese scroll.\n\r",ch);
        return;
    }

    if ( scroll->item_type != ITEM_SCROLL )
    {
        send_to_char("Solo puedes estudiar scrolls.\n\r",ch);
        return;
    }

    if ( getNivelPr(ch) < scroll->level )
    {
        send_to_char("No eres de nivel lo suficientemente alto para poder estudiar este scroll.\n\r", ch );
        return;
    }

    if ( get_skill(ch, scroll->value[1]) < 1 )
    {
        send_to_char("Tu clase no puede aprender este spell.\n\r",ch);
        return;
    }

    if ( ch->pcdata->learned[scroll->value[1]] > 0 )
    {
        send_to_char("Tu ya conoces ese spell!\n\r",ch);
        return;
    }

    act("$n estudia $p.",ch,objToEnt(scroll),NULL,TO_ROOM);
    act("Estudias $p.",ch,objToEnt(scroll),NULL,TO_CHAR);

    if (number_percent() >= (20 + ch->pcdata->learned[gsn_scrolls]) * 4/5)
    {
        send_to_char("Te equivocas y el scroll se desvanece!\n\r",ch);
        act("$n lanza un grito de furia.",ch,NULL,NULL,TO_ROOM);
        check_improve(ch,gsn_scrolls,FALSE,2);
    }

    else
    {
        act("Aprendiste el spell!",ch,NULL,NULL,TO_CHAR);
        act("$n aprendio el spell!",ch,NULL,NULL,TO_ROOM);
        ch->pcdata->learned[scroll->value[1]] = 5;
        ch->pcdata->points += 3; 
        check_improve(ch,gsn_scrolls,TRUE,2);
    }
    extract_obj(scroll, TRUE);
    return;
}

/* put an item on auction, or see the stats on the current item or bet */
void do_auction (CHAR_DATA *ch, char *argument)
{
    OBJ_DATA *obj;
    char arg1[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];

    argument = one_argument (argument, arg1);

    if (IS_NPC(ch)) /* NPC can be extracted at any time and thus can't auction! */
	return;

    if (arg1[0] == '\0')
    {
	if (auction->item != NULL)
        {
            /* show item data here */
            if (auction->bet > 0)
                sprintf (buf, "La apuesta actual en este item es de #B%d#b MP.\n\r",auction->bet);
            else
                sprintf (buf, "No se han recibido apuestas para este item.\n\r");
            send_to_char (buf,ch);
            spell_identify (0, LEVEL_HERO - 1, chToEnt(ch), objToEnt(auction->item), TARGET_OBJ ); /* uuuh! */
            return;
        }
        else
        {
            send_to_char ("Rematar que?\n\r",ch);
            return;
        }
    }

    if (IS_IMMORTAL(ch) && !str_cmp(arg1,"stop"))
    {
	if (auction->item == NULL)
	{
		send_to_char ("No hay remate para detener.\n\r",ch);
		return;
	}
	else /* stop the auction */
	{
		sprintf (buf,"La venta de %s ha sido detenida por Dios. Item confiscado.",
                        auction->item->short_descr);
		talk_auction (buf);
		obj_to_char (auction->item, ch);
		auction->item = NULL;
		if (auction->buyer != NULL) /* return money to the buyer */
		{
			auction->buyer->silver += auction->bet;
			send_to_char ("Tu dinero ha sido devuelto.\n\r",auction->buyer);
		}
		return;
	}
    }

    if (!str_cmp(arg1,"bet") )
    {
        if (auction->item != NULL)
        {
            int newbet;

            /* make - perhaps - a bet now */
            if (argument[0] == '\0')
            {
                send_to_char ("Apostar cuanto?\n\r",ch);
                return;
            }

            if ( ch == auction->seller )
            {
                send_to_char ("No puedes apostar en este remate.\n\r", ch);
                return;
            }

            newbet = parsebet (auction->bet, argument);
/*	    sprintf( buf, "Bet: %d", newbet);
            log_string (buf); */

            if (newbet < (auction->bet + 100))
            {
                send_to_char ("Debes subir la apuesta en al menos 100 MP.\n\r",ch);
                return;
            }

            if (newbet > DINERO(ch))
            {
                send_to_char ("No tienes esa cantidad de dinero!\n\r",ch);
                return;
            }

            /* the actual bet is OK! */

            /* return the silver to the last buyer, if one exists */
            if (auction->buyer != NULL)
                auction->buyer->silver += auction->bet;

            deduct_cost( ch, newbet ); /* substract the silver - important :) */
            auction->buyer = ch;
            auction->bet   = newbet;
            auction->going = 0;
            auction->pulse = PULSE_AUCTION; /* start the auction over again */

            sprintf (buf,"Una apuesta de %d MP ha sido puesta en %s.",newbet,auction->item->short_descr);
            talk_auction (buf);
            return;
        }
        else
        {
            send_to_char ("No hay ningun objeto en remate.\n\r",ch);
            return;
        }
    }

/* finally... */

    if ( !str_cmp(arg1, "on") )
    {
    	send_to_char( "Canal de remates ahora esta #BON#b.\n\r", ch );
    	REMOVE_BIT(ch->comm, COMM_NOAUCTION);
    	return;
    }
    
    if ( !str_cmp(arg1, "off") )
    {
    	send_to_char( "Canal de remates ahora esta #BOFF#b.\n\r", ch );
    	SET_BIT(ch->comm, COMM_NOAUCTION);
    	return;
    }

/*    obj = get_obj_list (ch, arg1, ch->carrying); */ /* does char have the item ? */

    if ( IS_SET(ch->act, PLR_NOAUCTION) )
    {
    	send_to_char( "No puedes rematar objetos todavia. Espera unos minutos.\n\r", ch );
    	return;
    }

    obj = get_obj_carry( ch, arg1, ch );

    if (obj == NULL)
    {
        send_to_char ("No estas llevando eso.\n\r",ch);
        return;
    }

    if (obj->clan)
    {
    	send_to_char ("No puedes rematar un objeto de clan.\n\r", ch );
    	return;
    }

    if (auction->item == NULL)
    switch (obj->item_type)
    {

    default:
        act ("No puedes rematar $Ts.",ch, NULL, strToEnt(item_name (obj->item_type),ch->in_room), TO_CHAR);
        return;

    case ITEM_WEAPON:
    case ITEM_ARMOR:
    case ITEM_STAFF:
    case ITEM_WAND:
    case ITEM_SCROLL:
        obj_from_char (obj);
        auction->item = obj;
        auction->bet = 0;
        auction->buyer = NULL;
        auction->seller = ch;
        auction->pulse = PULSE_AUCTION;
        auction->going = 0;

        sprintf (buf, "Un nuevo item ha sido recibido: %s.", obj->short_descr);
        talk_auction (buf);

	SET_BIT(ch->act, PLR_NOAUCTION);

	char_event_add(ch,MINUTOS(10)*PULSE_PER_SECOND,(void *) PLR_NOAUCTION,
		actremove );

        return;
    } /* switch */
    else
    {
        act ("Intentalo despues - $p esta siendo rematado justo ahora!",ch,objToEnt(auction->item),NULL,TO_CHAR);
        return;
    }
}

/*
 * Reparador.
 */
CHAR_DATA *find_reparador( CHAR_DATA *ch )
{
    /*char buf[MAX_STRING_LENGTH];*/
    CHAR_DATA *reparador;
    REPAIR_DATA *pRepair;

    pRepair = NULL;
    for ( reparador = ch->in_room->people; reparador; reparador = reparador->next_in_room )
    {
	if ( IS_NPC(reparador) && (pRepair = reparador->pIndexData->pRepair) != NULL )
	    break;
    }

    if ( pRepair == NULL )
    {
	send_to_char( "No puedes hacer eso aqui.\n\r", ch );
	return NULL;
    }

    REMOVE_BIT(reparador->comm, COMM_NOCHANNELS);

    /*
     * Undesirables.
     *
    if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_KILLER) )
    {
	do_say( reparador, "Asesinos no son bienvenidos!" );
	sprintf( buf, "%s el #BASESINO#b esta aqui!\n\r", ch->name );
	do_yell( reparador, buf );
	return NULL;
    }

    if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_THIEF) )
    {
	do_say( reparador, "Ladrones no son bienvenidos!" );
	sprintf( buf, "%s el #BLADRON#b esta aqui!\n\r", ch->name );
	do_yell( reparador, buf );
	return NULL;
    }
	*/
    /*
     * Repair hours.
     */
    if ( time_info.hour < pRepair->open_hour )
    {
	do_say( reparador, "Lo lamento, esta cerrado. Vuelve mas tarde." );
	return NULL;
    }
    
    if ( time_info.hour > pRepair->close_hour )
    {
	do_say( reparador, "Lo lamento, esta cerrado. Vuelve manana." );
	return NULL;
    }

    /*
     * Invisible or hidden people.
     */
    if ( !can_see( reparador, ch ) )
    {
	do_say( reparador, "No trato con gente que no puedo ver." );
	return NULL;
    }

    return reparador;
}

void reparar_obj(CHAR_DATA *ch, CHAR_DATA *reparador, OBJ_DATA *obj, bool fAll)
{
	int i;

	if ( !obj )
		return;

	if ( fAll )
	{
		if ( obj->contains )
			reparar_obj(ch, reparador, obj->contains, TRUE);
		if ( obj->next_content )
			reparar_obj(ch, reparador, obj->next_content, TRUE);
	}

	if ( obj->condition > 89 )
	{
		if ( !fAll )
			send_to_char( "Ese objeto esta en excelente condicion!\n\r", ch );
		return;
	}

	for ( i = 0; i < MAX_TRADE; ++i )
		if (reparador->pIndexData->pRepair->repair_type[i] == obj->item_type)
			break;

	if ( i == MAX_TRADE )
	{
		if ( !fAll )
			send_to_char( "Lo siento, no se como reparar eso.\n\r", ch );
		return;
	}

	i = (obj->cost * ( 100 - obj->condition ) / 100) * 1.2;

	if ( i < 50 )
		i = obj->level * 25;

	if ( i > DINERO(ch))
	{
		if ( !fAll )
			send_to_char( "Lo lamento, no tienes suficiente dinero.\n\r", ch );
		return;
	}

	deduct_cost( ch, i );

	obj->condition = UMIN( 90 + (int) ( ( getNivelPr(reparador) / 60.0 ) * 10 )
		+ number_range(0, 3), 100 );

	act( "$n repara $p y te lo entrega.", reparador, objToEnt(obj), chToEnt(ch), TO_VICT );
	act( "$n repara $p y se lo entrega a $N.", reparador, objToEnt(obj), chToEnt(ch), TO_NOTVICT );
}

void do_reparar( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *reparador;
	OBJ_DATA *obj;
	
	if ( ch->in_room == NULL )
		return;
	
	if ( !argument || (argument && argument[0] == '\0') )
	{
		send_to_char( "Que objeto quieres reparar?\n\r", ch );
		return;
	}

	if ( (reparador = find_reparador(ch)) == NULL )
		return;

	if ( !ch->carrying )
	{
		act( "$n te dice 'No tienes nada para reparar.", reparador, NULL, chToEnt(ch), TO_VICT );
		return;
	}

	if ( str_cmp(argument, "all") && str_cmp(argument, "todo") )
	{
		if ( (obj = get_obj_carry( ch, argument, ch )) == NULL )
		{
			send_to_char( "No estas llevando eso!\n\r", ch );
			return;
		}

		reparar_obj(ch, reparador, obj, FALSE);
	}
	else
		reparar_obj(ch, reparador, ch->carrying, TRUE);
}

void do_cotizar( CHAR_DATA *ch, char *argument )
{
	OBJ_DATA *obj;
	char buf[MSL];
	CHAR_DATA *reparador;
	REPAIR_DATA *pRepair;
	int i;
	
	if ( !ch->in_room )
		return;
	
	if ( !argument || (argument && argument[0] == '\0') )
	{
		send_to_char( "Que objeto quieres cotizar?\n\r", ch );
		return;
	}

	if ( ( reparador = find_reparador( ch ) ) == NULL )
		return;
	
	pRepair = reparador->pIndexData->pRepair;
	
	if ( (obj = get_obj_carry( ch, argument, ch )) == NULL )
	{
		send_to_char( "No estas llevando eso!\n\r", ch );
		return;
	}
	
	for ( i = 0; i < MAX_TRADE; ++i )
	{
		if (pRepair->repair_type[i] == obj->item_type)
			break;
	}
	
	if ( i == MAX_TRADE )
	{
		act( "$n te dice 'Lo siento, no se como reparar eso'.", reparador, NULL, chToEnt(ch), TO_VICT );
		return;
	}
	
	if ( obj->condition > 89 )
	{
		act( "$n te dice 'Ese objeto esta en excelente condicion!'.", reparador, NULL, chToEnt(ch), TO_VICT );
		return;
	}

	i = (obj->cost * ( 100 - obj->condition ) / 100) * 1.2;

	if ( i < 50 )
		i = obj->level * 25;

	sprintf( buf, "$n te dice 'Reparar $p te costara %d monedas de plata'.", i );
	act( buf, reparador, objToEnt(obj), chToEnt(ch), TO_VICT );

	return;
}

void afilar_arma( EVENT *ev )
{
	OBJ_DATA *arma = ev->item.obj;
	CHAR_DATA *ch;
	AFFECT_DATA af;
	
	switch( (int) ev->param )
	{
		case 0:
		if ( (ch = arma->carried_by) )
		{
			act( "Terminas de afilar $p.", ch, objToEnt(arma), NULL, TO_CHAR );
			act( "$n termina de afilar $p.", ch, objToEnt(arma), NULL, TO_ROOM );
		}
		af.where	= TO_WEAPON;
		af.type		= gsn_afilar;
		af.duration	= 6 + (getNivelPr(ch) / 6);
		af.location	= APPLY_NONE;
		af.modifier	= 0;
		af.bitvector	= WEAPON_SHARP;
		af.level	= getNivelPr(ch);
		affect_to_obj( arma, &af );
		break;

		case 1:
		if ( (ch = arma->carried_by) )
		{
			act( "Terminas de afilar $p, pero no notas ningun cambio.", ch, objToEnt(arma), NULL, TO_CHAR );
			act( "$n termina de afilar $p.", ch, objToEnt(arma), NULL, TO_ROOM );
		}
		arma->condition = UMAX(1, arma->condition - 5);
		break;
		
		case 2:
		if ( (ch = arma->carried_by) )
		{
			act( "Whoops! al estar afilando $p, se rompio!", ch, objToEnt(arma), NULL, TO_CHAR );
			act( "Whoops! $p se quebro mientras $p estaba afilando.", ch, objToEnt(arma), NULL, TO_ROOM );
		}
		extract_obj( arma, TRUE );
		break;
	}
	return;
}

void do_afilar( CHAR_DATA *ch, char *argument )
{
	int chance;
	OBJ_DATA *obj, *arma;

	if ( IS_NULLSTR(argument) )
	{
		send_to_char( "Que quieres afilar?\n\r", ch );
		return;
	}
	
	if ( (chance = get_skill(ch,gsn_afilar)) < 1 )
	{
		send_to_char( "No sabes como afilar.\n\r", ch );
		return;
	}
	
	if ( (arma = get_obj_carry(ch, argument, ch)) == NULL )
	{
		send_to_char( "No estas llevando eso.\n\r", ch );
		return;
	}
	
	if ( arma->item_type != ITEM_WEAPON )
	{
		send_to_char( "Eso no es un arma!\n\r", ch );
		return;
	}

	if ( IS_WEAPON_STAT(arma, WEAPON_SHARP) )
	{
		send_to_char( "Esa arma ya esta afilada.\n\r", ch );
		return;
	}

	for ( obj = ch->carrying; obj; obj = obj->next_content )
		if ( obj->item_type == ITEM_PEDERNAL )
			break;
	
	if ( !obj )
	{
		send_to_char( "Necesitas un pedernal para poder afilar.\n\r", ch );
		return;
	}
	
	WAIT_STATE(ch,skill_table[gsn_afilar].beats);
	act( "Empiezas a afilar $p con $P.", ch, objToEnt(arma), objToEnt(obj), TO_CHAR );
	act( "$n empieza a afilar $p con $P.", ch, objToEnt(arma), objToEnt(obj), TO_ROOM );
	extract_obj( obj, TRUE );

	if ( chance > number_percent() ) /* exito */
	{
		SET_BIT(obj->detected, DETECTED_SHARP);
		obj_event_add( arma, skill_table[gsn_afilar].beats, 0, afilar_arma );
		check_improve( ch, gsn_afilar, TRUE, 1 );
	}
	else /* fracaso */
	{
		if ( CHANCE(chance*2) ) /* no pasa nada */
			obj_event_add( arma, skill_table[gsn_afilar].beats, (int *)1, afilar_arma );
		else /* se pierde el arma */
			obj_event_add( arma, skill_table[gsn_afilar].beats, (int *)2, afilar_arma );
		check_improve( ch, gsn_afilar, FALSE, 1 );
	}

	return;
}

void do_identify( CHAR_DATA *ch, char *argument )
{
	OBJ_DATA *obj;
	CHAR_DATA *rch;
	int costo;

	if ( ( obj = get_obj_carry( ch, argument, ch ) ) == NULL )
	{
		send_to_char( "No estas llevando eso.\n\r", ch );
		return;
	}

	for ( rch = ch->in_room->people; rch != NULL; rch = rch->next_in_room )
		if ( IS_NPC(rch)
		&&   IS_MOB_MAGIC(rch)
		&&   rch->position == POS_STANDING
		&&   IS_FORM(rch, FORM_SENTIENT)
		&&  !HATES(rch, ch)
		&&   getNivelPr(rch) >= obj->level )
			break;

	if (!rch)
	{
		send_to_char("Parece que nadie sabe mucho acerca de eso.\n\r", ch);
		return;
	}

	if ( getNivelPr(rch) < obj->level )
	{
		act( "$n te dice 'Mis poderes son insuficientes para poder identificar $p'.",
			rch, objToEnt(obj), chToEnt(ch), TO_VICT );
		return;
	}

	costo = getNivelPr(ch) * getNivelPr(ch) * 10 + obj->level * 100 + 50;

	if (IS_IMMORTAL(ch))
		act( "$n te mira y sus ojos brillan!", rch, objToEnt(obj), chToEnt(ch), TO_VICT );
	else if (DINERO(ch) < costo)
	{
		act( "$n sigue su camino sin mirar a $p.",
			rch, objToEnt(obj), 0, TO_ROOM );
		return;
	}
	else
	{
		deduct_cost(ch, costo);
		send_to_char("Tu bolsillo se siente mas liviano.\n\r", ch);
	}

	act( "$n toma $p y bota algunos huesos al suelo.",
		rch, objToEnt(obj), 0, TO_ALL );
	act( "En el humo, alcanzas a leer:", ch, NULL, NULL, TO_CHAR );
	spell_identify( 0, LEVEL_HERO - 1, chToEnt(ch), objToEnt(obj), TARGET_OBJ );
}

void do_rezar( CHAR_DATA *ch, char *argument )
{
	ROOM_INDEX_DATA *lugar;
	OBJ_DATA *obj;

	if ( IS_NPC(ch) || !is_clan(ch) )
	{
		send_to_char( "Debes estar en un clan para poder rezar a tu dios.\n\r", ch );
		return;
	}

	if ( ES_INDEP(ch->clan) )
	{
		send_to_char( "No crees en Dios, como piensas rezarle?\n\r", ch );
		return;
	}

	if ( (IS_GOOD(ch)    && IS_CLAN_NOGOOD(ch->clan))
	||   (IS_EVIL(ch)    && IS_CLAN_NOEVIL(ch->clan))
	||   (IS_NEUTRAL(ch) && IS_CLAN_NONEUTRAL(ch->clan)) )
	{
		act( "$T te ignora.", ch, NULL, strToEnt(CLAN_GOD(ch),ch->in_room), TO_CHAR );
		return;
	}

	if ( !IS_SET(ch->in_room->room_flags, ROOM_SANTUARIO ) )
	{
		send_to_char( "Este lugar no es lo suficientemente puro.\n\r", ch );
		return;
	}

	if ( (obj = ch->pcdata->corpse) == NULL )
	{
		send_to_char( "No tienes porque rezar.\n\r", ch );
		return;
	}

	act( "$n empieza a rezarle a su dios $T.", ch, NULL, strToEnt(CLAN_GOD(ch),ch->in_room), TO_ROOM );
	act( "Empiezas a rezarle a tu dios $T.", ch, NULL, strToEnt(CLAN_GOD(ch),ch->in_room), TO_CHAR );

	WAIT_STATE(ch,12);

	if (obj->carried_by)
		obj_from_char( obj );
	else
	if ( obj->in_obj )
		obj_from_obj( obj );
	else
	if ( obj->in_room )
		obj_from_room( obj );

	obj_to_room( obj, (lugar = get_room_index(MORGUE(ch))) );

	if ( lugar->people )
		act( "$p aparece en el cuarto.", lugar->people, objToEnt(obj), NULL, TO_ALL );

	return;
}

void do_trozar( CHAR_DATA *ch, char *argument )
{
	int cnt = 0, chance;
	OBJ_DATA *corpse, *obj;
	char cnts[MIL];

	if ( (chance = get_skill(ch, gsn_trozar)) < 1 )
	{
		send_to_char( "Trozar? Que es eso?\n\r", ch );
		return;
	}

	if ( IS_NULLSTR(argument) )
	{
		send_to_char( "Que quieres trozar?\n\r", ch );
		return;
	}

	corpse = get_obj_here( ch, argument );

	if ( corpse == NULL )
	{
		act( "No encuentras ningun $T por aqui.", ch, NULL, strToEnt(argument,ch->in_room), TO_CHAR );
		return;
	}

	if ( corpse->item_type != ITEM_CORPSE_NPC )
	{
		act( "No puedes trozar $T.", ch, NULL, strToEnt(argument,ch->in_room), TO_CHAR );
		return;
	}

	if ( corpse->contains )
	{
		act( "No creo que quieras comer bistecs con trozos de $P!",
			ch, NULL, objToEnt(corpse->contains), TO_CHAR );
		return;
	}

	if ( !CHANCE(chance) )
	{
		act( "$n intenta trozar $P, pero hace mal el corte, destrozando el cuerpo.", ch, NULL, objToEnt(corpse), TO_ROOM );
		act( "Whoops! Haces mal un corte y $P se despedaza.", ch, NULL, objToEnt(corpse), TO_CHAR );
		extract_obj( corpse, TRUE );
		return;
	}

	if ( IS_SET(corpse->value[2], PART_HEAD) )
		cnt++;
	if ( IS_SET(corpse->value[2], PART_ARMS) )
		cnt += 2;
	if ( IS_SET(corpse->value[2], PART_LEGS) )
		cnt += 2;
	if ( IS_SET(corpse->value[2], PART_HEART) )
		cnt++;
	if ( IS_SET(corpse->value[2], PART_WINGS) )
		cnt++;
	if ( IS_SET(corpse->value[2], PART_TAIL) )
		cnt++;

	if ( !CHANCE(chance) )
		cnt /= number_fuzzy(2);

	cnt = UMAX(1,cnt);

	sprintf( cnts, "%d", cnt );
	act( "$n troza $P, obteniendo $t bistecs.", ch, strToEnt(cnts,ch->in_room), objToEnt(corpse), TO_ROOM );
	act( "Trozas $P, obteniendo $t bistecs.", ch, strToEnt(cnts,ch->in_room), objToEnt(corpse), TO_CHAR );

	while (cnt-- > 0)
	{
		obj		= create_object( get_obj_index(OBJ_VNUM_BISTEC), 0 );
		obj->timer	= 10;
		obj->cost	= 0;
		if (IS_SET(corpse->value[1], CONT_CUERPO_POISON))
			SET_BIT(obj->value[3], FOOD_POISON);
		obj_to_char( obj, ch );
	}

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

	extract_obj( corpse, TRUE );

	return;
}

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

	if ( IS_NULLSTR(argument) )
	{
		send_to_char( "Que quieres beber?\n\r", ch );
		return;
	}

	if ( (obj = get_obj_carry( ch, argument, ch )) == NULL
	&&   (obj = get_obj_type_list(ITEM_FOUNTAIN, ch->in_room->contents)) == NULL )
	{
		act( "No estas llevando ningun $t.", ch, strToEnt(argument,ch->in_room), NULL, TO_CHAR );
		return;
	}

	if ( obj->item_type == ITEM_POTION )
		do_quaff( ch, argument );
	else
	if ( obj->item_type == ITEM_DRINK_CON
	||   obj->item_type == ITEM_FOUNTAIN )
		do_drink( ch, argument );
	else
		act( "No puedes beber $t.", ch, strToEnt(argument,ch->in_room), NULL, TO_CHAR );

	return;
}

void nuke_corpse( char * name, bool bak )
{
	FILE *fp;
	char buf[MIL];

	sprintf( buf, "%s%s", CORPSE_DIR, name );

	if ( (fp = fopen(buf,"r")) )
	{
		fclose(fp);
		unlink(buf);
	}

	if ( !bak )
		return;

	sprintf( buf, "%s%s", CORPSE_BAK_DIR, name );

	if ( (fp = fopen( buf, "r")) )
	{
		fclose(fp);
		unlink(buf);
	}
}