From: Ferris@FootPrints.net

void do_push_drag( CHAR_DATA *ch, char *argument, char *verb )
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];
    ROOM_INDEX_DATA *in_room;
    ROOM_INDEX_DATA *to_room;
    CHAR_DATA *victim;
    EXIT_DATA *pexit;
    OBJ_DATA *obj;
    int door;

    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );
    victim = get_char_room(ch,arg1);
    obj = get_obj_list( ch, arg1, ch->in_room->contents );

    if ( arg1[0] == '\0' || arg2[0] == '\0' )
    {
	sprintf( buf, "%s whom or what where?\n\r", capitalize(verb));
	send_to_char( buf, ch );
	return;
    }

    if ( (!victim || !can_see(ch,victim))
    && (!obj || !can_see_obj(ch,obj)) )
    {
	sprintf(buf,"%s whom or what where?\n\r", capitalize(verb));
	send_to_char( buf, ch );
        return;
    }

         if ( !str_cmp( arg2, "n" ) || !str_cmp( arg2, "north" ) ) door = 0;
    else if ( !str_cmp( arg2, "e" ) || !str_cmp( arg2, "east"  ) ) door = 1;
    else if ( !str_cmp( arg2, "s" ) || !str_cmp( arg2, "south" ) ) door = 2;
    else if ( !str_cmp( arg2, "w" ) || !str_cmp( arg2, "west"  ) ) door = 3;
    else if ( !str_cmp( arg2, "u" ) || !str_cmp( arg2, "up"    ) ) door = 4;
    else if ( !str_cmp( arg2, "d" ) || !str_cmp( arg2, "down"  ) ) door = 5;
    else
    {
      sprintf( buf, "Alas, you cannot %s in that direction.\n\r", verb );
      send_to_char( buf, ch );
      return;
    }

  if ( obj )
  {
    in_room = obj->in_room;
    if ( ( pexit   = in_room->exit[door] ) == NULL
    ||   ( to_room = pexit->u1.to_room   ) == NULL 
    ||	 !can_see_room(ch,pexit->u1.to_room))
    {
        sprintf( buf, "Alas, you cannot %s in that direction.\n\r", verb );
        send_to_char( buf, ch );
	return;
    }

    if ( !IS_SET(obj->wear_flags, ITEM_TAKE) || !can_loot(ch,obj) )
    {
	send_to_char( "It won't budge.\n\r", ch );
	return;
    }

    if ( IS_SET(pexit->exit_info, EX_CLOSED)
    || IS_SET(pexit->exit_info,EX_NOPASS) )
    {
	act( "You cannot $t it through the $d.", ch, verb, pexit->keyword, TO_CHAR );
	act( "$n decides to $t $P around!", ch, verb, obj, TO_ROOM );
	return;
    }

    act( "You attempt to $T $p out of the room.", ch, obj, verb, TO_CHAR );
    act( "$n is attempting to $T $p out of the room.", ch, obj, verb, TO_ROOM );

    if ( obj->weight >  (2 * can_carry_w (ch)) )
    {
      act( "$p is too heavy to $T.\n\r", ch, obj, verb, TO_CHAR);
      act( "$n attempts to $T $p, but it is too heavy.\n\r", ch, obj, verb, TO_ROOM);
      return;
    }
    if 	 ( !IS_IMMORTAL(ch)
    ||   IS_SET(ch->in_room->room_flags, ROOM_SAFE)
    ||   IS_SET(ch->in_room->room_flags, ROOM_PRIVATE)
    ||   IS_SET(ch->in_room->room_flags, ROOM_SOLITARY)
    ||   IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
    ||   IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
    || 	 (number_percent() > 75) )
    {
	send_to_char( "It won't budge.\n\r", ch );
	return;
    }

    if ( ch->move > 10 )
    {
	ch->move -= 10;
	send_to_char( "You succeed!\n\r", ch );
	act( "$n succeeds!", ch, NULL, NULL, TO_ROOM );
	obj_from_room( obj );
	obj_to_room( obj, to_room );
	if (!str_cmp( verb, "drag" ))
	  move_char( ch, door, FALSE );
    }
    else
    {
      sprintf( buf, "You are too tired to %s anything around!\n\r", verb );
      send_to_char( buf, ch );
    }
  }
  else
  {
    if ( ch == victim )
    {
	act( "You $t yourself about the room and look very silly.", ch, verb, NULL, TO_CHAR );
	act( "$n decides to be silly and $t $mself about the room.", ch, verb, NULL, TO_ROOM );
	return;
    }

    in_room = victim->in_room;
    if ( ( pexit   = in_room->exit[door] ) == NULL
    ||   ( to_room = pexit->u1.to_room   ) == NULL 
    ||	 !can_see_room(victim,pexit->u1.to_room))
    {
        sprintf( buf, "Alas, you cannot %s them that way.\n\r", verb );
        send_to_char( buf, ch );
	return;
    }

    if (IS_SET(pexit->exit_info, EX_CLOSED)
    &&  (!IS_AFFECTED(victim, AFF_PASS_DOOR) || IS_SET(pexit->exit_info,EX_NOPASS)))
    {
	act( "You try to $t them through the $d.", ch, verb, pexit->keyword, TO_CHAR );
	act( "$n decides to $t you around!", ch, verb, victim, TO_VICT );
	act( "$n decides to $t $N around!", ch, verb, victim, TO_NOTVICT );
	return;
    }

    act( "You attempt to $t $N out of the room.", ch, verb, victim, TO_CHAR );
    act( "$n is attempting to $t you out of the room!", ch, verb, victim, TO_VICT );
    act( "$n is attempting to $t $N out of the room.", ch, verb, victim, TO_NOTVICT );

    if 	 ( !IS_IMMORTAL(ch)
    ||   (IS_NPC(victim) 
    &&	 (IS_SET(victim->act,ACT_TRAIN)
    ||	 IS_SET(victim->act,ACT_PRACTICE)
    ||	 IS_SET(victim->act,ACT_IS_HEALER)
    ||	 IS_SET(victim->act,ACT_IS_CHANGER)
    ||	 IS_SET(victim->imm_flags,IMM_SUMMON)
    ||	 victim->pIndexData->pShop ))
    ||   victim->in_room == NULL
    ||   IS_SET(victim->in_room->room_flags, ROOM_SAFE)
    ||   IS_SET(victim->in_room->room_flags, ROOM_PRIVATE)
    ||   IS_SET(victim->in_room->room_flags, ROOM_SOLITARY)
    ||   IS_SET(victim->in_room->room_flags, ROOM_NO_RECALL)
    ||   IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
    ||	 (!str_cmp( verb, "drag" ) && victim->position >= POS_STANDING)
    ||   (!str_cmp( verb, "push" ) && victim->position != POS_STANDING)
    || 	 is_safe(ch,victim)
    || 	 (number_percent() > 75)
    ||   victim->level >= ch->level + 5
    ||   (!IS_NPC(victim) && victim->level >= LEVEL_HERO) )
    {
	send_to_char( "They won't budge.\n\r", ch );
	return;
    }

    if ( ch->move > 10 )
    {
	ch->move -= 10;
	send_to_char( "You succeed!\n\r", ch );
	act( "$n succeeds!", ch, NULL, NULL, TO_ROOM );
	if (!str_cmp( verb, "drag" ))
	  move_char( ch, door, FALSE );
	move_char( victim, door, FALSE );
    }
    else
    {
      sprintf( buf, "You are too tired to %s anybody around!\n\r", verb );
      send_to_char( buf, ch );
    }
  }

  return;
}
               
void do_push( CHAR_DATA *ch, char *argument )
{
    do_push_drag( ch, argument, "push" );
    return;
}

void do_drag( CHAR_DATA *ch, char *argument )
{
    do_push_drag( ch, argument, "drag" );
    return;
}