/* ************************************************************************
*   File: act.obj1.c                                    Part of CircleMUD *
*  Usage: object handling routines -- get/drop and container handling     *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Copyright (C) 1993 by the Trustees of the Johns Hopkins University     *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"

/* extern variables */
extern struct str_app_type str_app[];
extern struct room_data *world;


void perform_put(struct char_data *ch, struct obj_data *obj,
		 struct obj_data *container)
{
   if (GET_OBJ_WEIGHT(container) + GET_OBJ_WEIGHT(obj) > container->obj_flags.value[0])
      act("$p won't fit in $P.", FALSE, ch, obj, container, TO_CHAR);
   else {
      obj_from_char(obj);
      obj_to_obj(obj, container);
      act("You put $p in $P.", FALSE, ch, obj, container, TO_CHAR);
      act("$n puts $p in $P.", TRUE, ch, obj, container, TO_ROOM);
   }
}

   
/* The following put modes are supported by the code below:

	1) put <object> <container>
	2) put all.<object> <container>
	3) put all <container>

	<container> must be in inventory or on ground.
	all objects to be put into container must be in inventory.
*/

ACMD(do_put)
{
   char	arg1[MAX_INPUT_LENGTH];
   char	arg2[MAX_INPUT_LENGTH];
   struct obj_data *obj;
   struct obj_data *next_obj;
   struct obj_data *container;
   struct char_data *tmp_char;
   int	obj_dotmode, cont_dotmode;

   argument_interpreter(argument, arg1, arg2);
   obj_dotmode = find_all_dots(arg1);
   cont_dotmode = find_all_dots(arg2);

   if (cont_dotmode != FIND_INDIV)
      send_to_char("You can only put things into one container at a time.\n\r", ch);
   else if (!*arg1)
      send_to_char("Put what in what?\n\r", ch);
   else if (!*arg2) {
      sprintf(buf, "What do you want to put %s in?\n\r",
	      ((obj_dotmode != FIND_INDIV) ? "them" : "it"));
      send_to_char(buf, ch);
   } else {
      generic_find(arg2, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &tmp_char, &container);
      if (!container) {
	 sprintf(buf, "You don't see a %s here.\n\r", arg2);
	 send_to_char(buf, ch);
      } else if (GET_ITEM_TYPE(container) != ITEM_CONTAINER) {
	 act("$p is not a container.", FALSE, ch, container, 0, TO_CHAR);
      } else if (IS_SET(container->obj_flags.value[1], CONT_CLOSED)) {
	 send_to_char("You'd better open it first!\n\r", ch);
      } else {
	 if (obj_dotmode == FIND_ALL) {	    /* "put all <container>" case */
	    /* check and make sure the guy has something first */
	    if (container == ch->carrying && !ch->carrying->next_content)
	       send_to_char("You don't seem to have anything to put in it.\n\r", ch);
	    else for (obj = ch->carrying; obj; obj = next_obj) {
	       next_obj = obj->next_content;
	       if (obj != container)
		  perform_put(ch, obj, container);
	    }
	 } else if (obj_dotmode == FIND_ALLDOT) {  /* "put all.x <cont>" case */
	    if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
	       sprintf(buf, "You don't seem to have any %ss.\n\r", arg1);
	       send_to_char(buf, ch);
	    } else while (obj) {
	       next_obj = get_obj_in_list_vis(ch, arg1, obj->next_content);
	       if (obj != container)
		  perform_put(ch, obj, container);
	       obj = next_obj;
	    }
	 } else {		    /* "put <thing> <container>" case */
	    if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying))) {
	       sprintf(buf, "You aren't carrying %s %s.\n\r", AN(arg1), arg1);
	       send_to_char(buf, ch);
	    } else if (obj == container)
	       send_to_char("You attempt to fold it into itself, but fail.\n\r", ch);
	    else
	       perform_put(ch, obj, container);
	 }
      }
   }
}



int	can_take_obj(struct char_data *ch, struct obj_data *obj)
{
   if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) {
      sprintf(buf, "%s: You can't carry that many items.\n\r", OBJS(obj, ch));
      send_to_char(buf, ch);
      return 0;
   } else if ((IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(ch)) {
      sprintf(buf , "%s: You can't carry that much weight.\n\r", OBJS(obj, ch));
      send_to_char(buf, ch);
      return 0;
   } else if (!(CAN_WEAR(obj, ITEM_TAKE))) {
      sprintf(buf, "%s: You can't take that!\n\r", OBJS(obj, ch));
      send_to_char(buf, ch);
      return 0;
   }

   return 1;
}


void	get_check_money(struct char_data *ch, struct obj_data *obj)
{
   if ((GET_ITEM_TYPE(obj) == ITEM_MONEY) && (obj->obj_flags.value[0] > 0)) {
      obj_from_char(obj);
      if (obj->obj_flags.value[0] > 1) {
	 sprintf(buf, "There were %d coins.\n\r", obj->obj_flags.value[0]);
	 send_to_char(buf, ch);
      }
      GET_GOLD(ch) += obj->obj_flags.value[0];
      extract_obj(obj);
   }
}


void	perform_get_from_container(struct char_data *ch, struct obj_data *obj,
				   struct obj_data *cont, int mode)
{
   if (mode == FIND_OBJ_INV || can_take_obj(ch, obj)) {
      if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch))
	 sprintf("%s: You can't hold any more items.\n\r", OBJS(obj, ch));
      else {
         obj_from_obj(obj);
         obj_to_char(obj, ch);
	 act("You get $p from $P.", FALSE, ch, obj, cont, TO_CHAR);
	 act("$n gets $p from $P.", TRUE, ch, obj, cont, TO_ROOM);
	 get_check_money(ch, obj);
      }
   }
}


void	get_from_container(struct char_data *ch, struct obj_data *cont,
			   char *arg, int mode)
{
   struct obj_data *obj, *next_obj;
   int obj_dotmode, found = 0;

   obj_dotmode = find_all_dots(arg);

   if (IS_SET(cont->obj_flags.value[1], CONT_CLOSED))
      act("The $p is closed.", FALSE, ch, cont, 0, TO_CHAR);
   else if (obj_dotmode == FIND_ALL) {
      for (obj = cont->contains; obj; obj = next_obj) {
	 next_obj = obj->next_content;
	 if (CAN_SEE_OBJ(ch, obj)) {
	    found = 1;
	    perform_get_from_container(ch, obj, cont, mode);
	 }
      }
      if (!found)
	 act("$p seems to be empty.", FALSE, ch, cont, 0, TO_CHAR);
   } else if (obj_dotmode == FIND_ALLDOT) {
      if (!*arg) {
	 send_to_char("Get all of what?\n\r", ch);
	 return;
      }
      obj = get_obj_in_list_vis(ch, arg, cont->contains);
      while (obj) {
         next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
	 if (CAN_SEE_OBJ(ch, obj)) {
	    found = 1;
	    perform_get_from_container(ch, obj, cont, mode);
	 }
	 obj = next_obj;
      }
      if (!found) {
	 sprintf(buf, "You can't find any %ss in $p.", arg);
	 act(buf, FALSE, ch, cont, 0, TO_CHAR);
      }
   } else {
      if (!(obj = get_obj_in_list_vis(ch, arg, cont->contains))) {
	 sprintf(buf, "There doesn't seem to be %s %s in $p.", AN(arg), arg);
	 act(buf, FALSE, ch, cont, 0, TO_CHAR);
      } else
	 perform_get_from_container(ch, obj, cont, mode);
   }
}


int	perform_get_from_room(struct char_data *ch, struct obj_data *obj)
{
   if (can_take_obj(ch, obj)) {
      obj_from_room(obj);
      obj_to_char(obj, ch);
      act("You get $p.", FALSE, ch, obj, 0, TO_CHAR);
      act("$n gets $p.", TRUE, ch, obj, 0, TO_ROOM);
      get_check_money(ch, obj);
      return 1;
   }

   return 0;
}


void get_from_room(struct char_data *ch, char *arg)
{
   struct obj_data *obj, *next_obj;
   int	dotmode, found = 0;

   dotmode = find_all_dots(arg);

   if (dotmode == FIND_ALL) {
      for (obj = world[ch->in_room].contents; obj; obj = next_obj) {
	 next_obj = obj->next_content;
	 if (CAN_SEE_OBJ(ch, obj)) {
	    found = 1;
	    perform_get_from_room(ch, obj);
	 }
      }
      if (!found)
	 send_to_char("There doesn't seem to be anything here.\n\r", ch);
   } else if (dotmode == FIND_ALLDOT) {
      if (!*arg) {
	 send_to_char("Get all of what?\n\r", ch);
	 return;
      }
      if (!(obj = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents))) {
	 sprintf(buf, "You don't see any %ss here.\n\r", arg);
	 send_to_char(buf, ch);
      } else while (obj) {
	 next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
	 perform_get_from_room(ch, obj);
	 obj = next_obj;
      }
   } else {
      if (!(obj = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents))) {
	 sprintf(buf, "You don't see %s %s here.\n\r", AN(arg), arg);
	 send_to_char(buf, ch);
      } else
	 perform_get_from_room(ch, obj);
   }
}



ACMD(do_get)
{
   char	arg1[MAX_INPUT_LENGTH];
   char	arg2[MAX_INPUT_LENGTH];

   int	cont_dotmode, found = 0, mode;
   struct obj_data *cont, *next_cont;
   struct char_data *tmp_char;

   if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) 
      send_to_char("Your arms are already full!\n\r", ch);
   else {
      argument_interpreter(argument, arg1, arg2);
      if (!*arg1)
         send_to_char("Get what?\n\r", ch);
      else {
         if (!*arg2)
            get_from_room(ch, arg1);
         else {
	    cont_dotmode = find_all_dots(arg2);
	    if (cont_dotmode == FIND_ALL) { /* use all in inv. and on ground */
	       for(cont = ch->carrying; cont; cont = cont->next_content)
		  if (GET_ITEM_TYPE(cont) == ITEM_CONTAINER) {
		     found = 1;
		     get_from_container(ch, cont, arg1, FIND_OBJ_INV);
		  }
	       for(cont = world[ch->in_room].contents; cont; cont = cont->next_content)
		  if (CAN_SEE_OBJ(ch, cont) && GET_ITEM_TYPE(cont) == ITEM_CONTAINER) {
		     found = 1;
		     get_from_container(ch, cont, arg1, FIND_OBJ_ROOM);
		  }
	       if (!found)
		  send_to_char("You can't seem to find any containers.\n\r", ch);
	    } else if (cont_dotmode == FIND_ALLDOT) {
	       if (!*arg2) {
		  send_to_char("Get from all of what?\n\r", ch);
		  return;
	       }
	       cont = get_obj_in_list_vis(ch, arg2, ch->carrying);
	       while (cont) {
		  found = 1;
		  next_cont = get_obj_in_list_vis(ch, arg2, cont->next_content);
		  if (GET_ITEM_TYPE(cont) != ITEM_CONTAINER)
		     act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
		  else
		     get_from_container(ch, cont, arg1, FIND_OBJ_INV);
		  cont = next_cont;
	       }
	       cont = get_obj_in_list_vis(ch, arg2, world[ch->in_room].contents);
	       while (cont) {
		  found = 1;
		  next_cont = get_obj_in_list_vis(ch, arg2, cont->next_content);
		  if (GET_ITEM_TYPE(cont) != ITEM_CONTAINER)
		     act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
		  else
		      get_from_container(ch, cont, arg1, FIND_OBJ_ROOM);
		  cont = next_cont;
	       }
	       if (!found) {
		  sprintf(buf, "You can't seem to find any %ss here.\n\r", arg2);
		  send_to_char(buf, ch);
	       }
	    } else { /* get <items> <container> (no all or all.x) */
	       mode = generic_find(arg2, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &tmp_char, &cont);
	       if (!cont) {
		  sprintf(buf, "You don't have %s %s.\n\r", AN(arg2), arg2);
		  send_to_char(buf, ch);
	       } else if (GET_ITEM_TYPE(cont) != ITEM_CONTAINER)
	          act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
	       else
		  get_from_container(ch, cont, arg1, mode);
	    }
	 }
      }
   }
}


void	perform_drop_gold(struct char_data *ch, int amount,
			  byte mode, sh_int RDR)
{
   struct obj_data *obj;

   if (amount <= 0)
      send_to_char("Heh heh heh.. we are jolly funny today, eh?\n\r", ch);
   else if (GET_GOLD(ch) < amount)
      send_to_char("You don't have that many coins!\n\r", ch);
   else {
      if (mode != SCMD_JUNK) {
	 obj = create_money(amount);
	 if (mode == SCMD_DONATE) {
	    send_to_char("You throw some gold into the air where it disappears in a puff of smoke!\n\r", ch);
	    act("$n throws some gold into the air where it disappears in a puff of smoke!", FALSE, ch, 0, 0, TO_ROOM);
	    send_to_room("Some gold suddenly appears in mid-air, then drops to the ground!\n\r", RDR);
	    obj_to_room(obj, RDR);
	 } else {
	    send_to_char("You drop some gold.\n\r", ch);
	    act("$n drops some gold.", FALSE, ch, 0, 0, TO_ROOM);
	    obj_to_room(obj, ch->in_room);
	 }
      } else {
	 act("$n drops some gold which disappears in a puff of smoke!", FALSE, ch, 0, 0, TO_ROOM);
	 send_to_char("You drop some gold which disappears in a puff of smoke!\n\r", ch);
      }
      GET_GOLD(ch) -= amount;
   }
}


#define VANISH(mode) ((mode == SCMD_DONATE || mode == SCMD_JUNK) ? \
		      "  It vanishes in a puff of smoke!" : "")

int	perform_drop(struct char_data *ch, struct obj_data *obj,
		     byte mode, char *sname, sh_int RDR)
{
   int	value;

   if (IS_SET(obj->obj_flags.extra_flags, ITEM_NODROP)) {
      sprintf(buf, "You can't %s %s, it must be CURSED!\n\r", sname, OBJS(obj, ch));
      send_to_char(buf, ch);
      return 0;
   }

   if ((mode == SCMD_DONATE) && IS_SET(obj->obj_flags.extra_flags, ITEM_NODONATE)) {
      sprintf(buf, "You can't donate %s.\n\r", OBJS(obj, ch));
      send_to_char(buf, ch);
      return 0;
   }

   sprintf(buf, "You %s %s.%s\n\r", sname, OBJS(obj, ch), VANISH(mode));
   send_to_char(buf, ch);
   sprintf(buf, "$n %ss $p.%s", sname, VANISH(mode));
   act(buf, TRUE, ch, obj, 0, TO_ROOM);

   obj_from_char(obj);

   switch(mode) {
   case SCMD_DROP:
      obj_to_room(obj, ch->in_room);
      return 0;
      break;
   case SCMD_DONATE:
      obj_to_room(obj, RDR);
      send_to_room("Something suddenly appears in a puff a smoke!\n\r", RDR);
      return 0;
      break;
   case SCMD_JUNK:
      value = MAX(1, MIN(200, obj->obj_flags.cost >> 4));
      extract_obj(obj);
      return value;
      break;
   default:
      log("SYSERR: Incorrect argument passed to perform_drop");
      break;
   }

   return 0;
}



ACMD(do_drop)
{
   extern sh_int donation_room_1, donation_room_2, donation_room_3; 
   struct obj_data *obj, *next_obj;
   sh_int RDR = 0;
   byte	mode = SCMD_DROP;
   int	dotmode, amount = 0;
   char	*sname;

   switch (subcmd) {
   case SCMD_JUNK:
      sname = "junk";
      mode = SCMD_JUNK;
      break;
   case SCMD_DONATE:
      sname = "donate";
      mode = SCMD_DONATE;
      switch (number(0, 2)) {
      case 0:
	 mode = SCMD_JUNK;
	 break;
      case 1:
      case 2: RDR = real_room(donation_room_1); break;
/*    case 3: RDR = real_room(donation_room_2); break;
      case 4: RDR = real_room(donation_room_3); break;
*/
      }
      if (RDR == NOWHERE) {
	 send_to_char("Sorry, you can't donate anything right now.\n\r", ch);
	 return;
      }
      break;
   default:
      sname = "drop";
      break;
   }

   argument = one_argument(argument, arg);

   if (!*arg) {
      sprintf(buf, "What do you want to %s?\n\r", sname);
      send_to_char(buf, ch);
      return;
   } else if (is_number(arg)) {
      amount = atoi(arg);
      argument = one_argument(argument, arg);
      if (!str_cmp("coins", arg) || !str_cmp("coin", arg))
         perform_drop_gold(ch, amount, mode, RDR);
      else {
	 /* code to drop multiple items.  anyone want to write it? -je */
	 send_to_char("Sorry, you can't do that (yet)...\n\r", ch);
	 return;
      }
   } else {
      dotmode = find_all_dots(arg);

      /* Can't junk or donate all */
      if ((dotmode == FIND_ALL) && (subcmd == SCMD_JUNK || subcmd == SCMD_DONATE)) {
         if (subcmd == SCMD_JUNK) 
	    send_to_char("Go to the dump if you want to junk EVERYTHING!\n\r", ch);
         else 
	    send_to_char("Go do the donation room if you want to donate EVERYTHING!\n\r", ch);
         return;
      }

      if (dotmode == FIND_ALL) {
         if (!ch->carrying)
	    send_to_char("You don't seem to be carrying anything.\n\r", ch);
	 else
            for (obj = ch->carrying; obj; obj = next_obj) {
               next_obj = obj->next_content;
	       amount += perform_drop(ch, obj, mode, sname, RDR);
	    }
      } else if (dotmode == FIND_ALLDOT) {
	 if (!*arg) {
	    sprintf(buf, "What do you want to %s all of?\n\r", sname);
	    send_to_char(buf, ch);
	    return;
	 }
         if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
            sprintf(buf, "You don't seem to have any %ss.\n\r", arg);
	    send_to_char(buf, ch);
	 }
         while (obj) {
	    next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
	    amount += perform_drop(ch, obj, mode, sname, RDR);
	    obj = next_obj;
	 }
      } else {
         if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) {
	    sprintf(buf, "You don't seem to have %s %s.\n\r", AN(arg), arg);
	    send_to_char(buf, ch);
	 } else
	    amount += perform_drop(ch, obj, mode, sname, RDR);
      }
   }

   if (amount && (subcmd == SCMD_JUNK)) {
      send_to_char("You have been rewarded by the gods!\n\r", ch);
      act("$n has been rewarded by the gods!", TRUE, ch, 0, 0, TO_ROOM);
      GET_GOLD(ch) += amount;
   }
}


void	perform_give(struct char_data *ch, struct char_data *vict,
		     struct obj_data *obj)
{
   if (IS_SET(obj->obj_flags.extra_flags, ITEM_NODROP)) {
      act("You can't let go of $p!!  Yeech!", FALSE, ch, obj, 0, TO_CHAR);
      return;
   }

   if (IS_CARRYING_N(vict) >= CAN_CARRY_N(vict)) {
      act("$N seems to have $S hands full.", FALSE, ch, 0, vict, TO_CHAR);
      return;
   }

   if (GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(vict) > CAN_CARRY_W(vict)) {
      act("$E can't carry that much weight.", FALSE, ch, 0, vict, TO_CHAR);
      return;
   }

   obj_from_char(obj);
   obj_to_char(obj, vict);
   act("You give $p to $N.", FALSE, ch, obj, vict, TO_CHAR);
   act("$n gives you $p.", FALSE, ch, obj, vict, TO_VICT);
   act("$n gives $p to $N.", TRUE, ch, obj, vict, TO_NOTVICT);
}

/* utility function for give */
struct char_data *give_find_vict(struct char_data *ch, char *arg1)
{
   struct char_data *vict;
   char arg2[MAX_INPUT_LENGTH];

   strcpy(buf, arg1);
   argument_interpreter(buf, arg1, arg2);
   if (!*arg1) {
      send_to_char("Give what to who?\n\r", ch);
      return 0;
   } else if (!*arg2) {
      send_to_char("To who?\n\r", ch);
      return 0;
   } else if (!(vict = get_char_room_vis(ch, arg2))) {
      send_to_char("No-one by that name here.\n\r", ch);
      return 0;
   } else if (vict == ch) {
      send_to_char("What's the point of that?\n\r", ch);
      return 0;
   } else
      return vict;
}


void	perform_give_gold(struct char_data *ch, struct char_data *vict,
			  int amount)
{
   if (amount <= 0) {
      send_to_char("Heh heh heh ... we are jolly funny today, eh?\n\r", ch);
      return;
   }

   if ((GET_GOLD(ch) < amount) && (IS_NPC(ch) || (GET_LEVEL(ch) < LEVEL_GOD))) {
      send_to_char("You haven't got that many coins!\n\r", ch);
      return;
   }

   send_to_char("Ok.\n\r", ch);
   sprintf(buf, "%s gives you %d gold coins.\n\r", PERS(ch, vict), amount);
   send_to_char(buf, vict);
   act("$n gives some gold to $N.", TRUE, ch, 0, vict, TO_NOTVICT);
   if (IS_NPC(ch) || (GET_LEVEL(ch) < LEVEL_GOD))
      GET_GOLD(ch) -= amount;
   GET_GOLD(vict) += amount;
}


ACMD(do_give)
{
   char arg1[MAX_INPUT_LENGTH];
   char arg2[MAX_INPUT_LENGTH];
   int	amount, dotmode;
   struct char_data *vict;
   struct obj_data *obj, *next_obj;

   half_chop(argument, arg1, arg2);

   if (!*arg1)
      send_to_char("Give what to who?\n\r", ch);
   else if (is_number(arg1)) {
      amount = atoi(arg1);
      if (!(vict = give_find_vict(ch, arg2)))
         return;
      if (!str_cmp("coins", arg2) || !str_cmp("coin", arg2))
         perform_give_gold(ch, vict, amount);
      else {
	 /* code to give multiple items.  anyone want to write it? -je */
	 send_to_char("Sorry, you can't do that (yet)...\n\r", ch);
	 return;
      }
   } else {
      if (!(vict = give_find_vict(ch, argument)))
	 return;
      dotmode = find_all_dots(argument);
      if (dotmode == FIND_ALL) {
	 if (!ch->carrying)
	    send_to_char("You don't seem to be holding anything.\n\r", ch);
	 else for (obj = ch->carrying; obj; obj = next_obj) {
	    next_obj = obj->next_content;
	    perform_give(ch, vict, obj);
	 }
      } else if (dotmode == FIND_ALLDOT) {
	 if (!*argument) {
	    send_to_char("All of what?\n\r", ch);
	    return;
	 }
	 if (!(obj = get_obj_in_list_vis(ch, argument, ch->carrying))) {
	    sprintf(buf, "You don't seem to have any %ss.\n\r", argument);
	    send_to_char(buf, ch);
	 } else while (obj) {
	    next_obj = get_obj_in_list_vis(ch, argument, obj->next_content);
	    perform_give(ch, vict, obj);
	    obj = next_obj;
	 }
      } else {
	 if (!(obj = get_obj_in_list_vis(ch, argument, ch->carrying))) {
	    sprintf(buf, "You don't seem to have %s %s.\n\r", AN(argument), argument);
	    send_to_char(buf, ch);
	 } else
	    perform_give(ch, vict, obj);
      }
   }
}

