/**
 * This has the controlling code for holding/weilding objects.
 * @author Pinkfish
 */
nosave mixed using, weapons;
int *set_unhold( object ob );
int *set_hold( object ob, int pos );
void create() {
    weapons = ({ });
} /* create() */
/**
 * This method returns the an array of the names of the limbs
 * on the living object.
 * @return an array of limbs
 */
mixed query_limbs() {
    mixed race_ob;
    string *limbs;
    if( !race_ob = TO->query_race_ob() )  {
        using = ({ });
        return ({ });
    }
    limbs = (string *)race_ob->query_limbs();
    if( !using )
        using = allocate( sizeof(limbs) );
    return limbs;
} /* query_limbs() */
/**
 * This method returns the current holding array of the living object.
 * This has one element in the array for each object and a 0 is in the
 * array if that limb is not holding anything.  The positions correspond
 * to the positions returned by the query_limbs() function.
 * @return an array of held objects
 * @see query_holding()
 * @see query_free_limbs()
 * @see query_weapons()
 */
object *query_holding() {
    if( !using )
        query_limbs();
    return copy(using);
} /* query_holding() */
/**
 * This method returns the number of free limbs on the living object.
 * A free limb!  Yes, have a couple of free legs, beat the rush!
 * Buy now!
 * @return the number of free limbs
 * @see query_holding()
 * @see query_limbs()
 */
int query_free_limbs() {
    if( !using )
        query_limbs();
    return sizeof( using ) - sizeof( using - ({ 0 }) );
} /* query_free_limbs() */
/**
 * This method returns the currently held weapons on the living object.
 * This is an array of held items which are weapons and can be used
 * in combat.
 * @return the array of held weapons
 * @see query_holding()
 */
object *query_weapons() {
    weapons -= ({ 0 });
    return weapons + ({ });
} /* query_weapons() */
/**
 * This method sets the object as unheld.  It will attempt to remove
 * the object from a held limb.
 * <p>
 * The return array contains the index of the limbs from which the
 * item was removed, if the array is 0 size then no items were
 * removed.
 * @param ob the object to unhold
 * @return a array of limb numbers
 * @see set_hold()
 * @see query_limbs()
 */
int *set_unhold( object ob ) {
    int *bits, pos, j;
    if( ( pos = member_array( ob, using ) ) == -1 )
        return ({ });
    if( !ob->set_holder(0) )
        return ({ });
    if( ob->query_weapon() )
        weapons = weapons - ({ ob, 0 });
    // Ok, put it down, check to see if it occurs elsewhere in the array.
    bits = ({ pos });
    using[pos] = 0;
    while( ( j = member_array( ob, using ) ) != -1 ) {
        using[j] = 0;
        bits += ({ j });
    }
    if( ob->query_armour() )
        TO->remove_armour(ob);
    call_out("calc_burden", 1 );
    return bits;
} /* set_unhold() */
/**
 * This method sets the object as held.  It will attempt to hold it
 * starting at the given position in the limbs array.
 * <p>
 * The return array contains the index of the limbs from which the
 * item was added, if the array is 0 size then no items were
 * added.
 * @param ob the object to hold
 * @param pos the position in the limb array to start holding at
 * @return a array of limb numbers
 * @see set_unhold()
 * @see query_limbs()
 */
int *set_hold( object ob, int pos ) {
    int j, x, y, off, ret, *bits, ok;
    if( !using )
        query_limbs();
    if( pos == -1 && ( pos = member_array( 0, using ) ) == -1 )
        return ({ });
    if( using[pos] && !sizeof( set_unhold(using[pos]) ) )
        return ({ });
    if( member_array( ob, using ) != -1 && !sizeof( set_unhold(ob) ) )
        return ({ });
    if( ret = ob->query_no_limbs() ) {
        // Wants more than one hand.
        ok = 1;
        for( j = 1; ok ; j++ ) {
            ok = 0;
            if( (pos-j) >= 0 && !using[pos-j] )
                ok = ++y;
            if( (pos+j) < sizeof(using) && !using[pos+j] )
                ok = ++x;
        }
        // We failed.  Tell the object about it.
        if( y+x+1 < ret )
            return ({ });
        if( !ob->set_holder( TO, pos ) )
            return ({ });
        // Try and go up first...
        using[pos] = ob;
        bits = ({ pos });
        for( j = 1; j < ret; j++ ) {
            if( x > 0 ) {
                bits += ({ pos+(++off) });
                using[pos+off] = ob;
                if( !--x )
                    off = 0;
            } else {
                bits += ({ pos-(++off) });
                using[pos-off] = ob;
            }
        }
        if( ob->query_weapon() )
            weapons += ({ ob });
        call_out("calc_burden", 1 );
        return bits;
    }
    return ({ });
} /* set_hold() */