/**
 * This file contains all the code need to handle the types of carrying
 * which npcs tend to involve themselves in.
 * @author Pinkfish
 * @changed Changed query_wearing_hidden() to deal better with items
 * with multiple types - Sandoz, Dec. 2003.
 */
#include <money.h>
object* query_wearing();
/**
 * This method returns the list of types of things which are passed into
 * the array.
 * <p>
 * Two elements in an array is returned, the first element is the list of
 * all of the different types which are worn and the second is the list
 * of types corresponding to each of the inputs.
 * @param things the things to check
 * @return a two element array
 * @see armour_list()
 */
protected varargs mixed query_types_worn( object *things ) {
    int i;
    string *types;
    mixed stuff;
    types = ({ });
    if( !things )
        things = (object *)TO->query_wearing();
    i = sizeof( stuff = (mixed *)things->query_type() );
    while( i-- ) {
        if( stringp( stuff[ i ] ) )
            stuff[ i ] = ({ stuff[ i ] });
        if( !pointerp( stuff[ i ] ) ) {
            printf("%O (%s) has an invalid type.  Please bug report it.\n",
                things[ i ], (string)things[ i ]->query_short() );
            stuff[ i ] = ({"broken"});
        }
        types += stuff[ i ];
    }
    return ({ types, stuff });
} /* query_types_worn() */
/**
 * This method returns the items that are hidden by something on top of
 * them.
 * @param looker the person looking at the items
 * @param things an optional set of things
 * @return the hidden worn types
 */
object* query_wearing_hidden( object looker, object *things ) {
    string *types, *under, under_type;
    object *worn, *ret;
    mixed obj_types;
    int i, j;
    worn = ( !things ? query_wearing() : things );
    obj_types = query_types_worn( worn );
    types = obj_types[0];
    obj_types = obj_types[1];
    ret = ({ });
    i = sizeof(worn);
    while( i-- ) {
        if( worn[i]->query_visible(looker) ) {
            j = sizeof( obj_types[i] );
            // We cycle through each type, and are only hidden if every
            // type is covered. This way jumpers won't cover whole dresses,
            // because the skirt part is still visible. - Sandoz, 2003.
            while( j-- ) {
                under = CLOTHING_H->query_clothing_hiding( obj_types[i][j] );
                if( sizeof(under) ) {
                    foreach( under_type in under ) {
                        if( member_array( under_type, types ) != -1 )
                            obj_types[i] = delete( obj_types[i], j, 1 );
                    }
                }
                // No more visible types left.
                if( !sizeof( obj_types[i] ) ) {
                    ret += ({ worn[i] });
                    break;
                }
            }
        } else {
            ret += ({ worn[i] });
        }
    }
    return ret;
} /* query_wearing_hidden() */
/**
 * This method returns a string list of the armours which the player
 * is wearing.  It will show also modify the list to show only hidden
 * items (items under other items are considered hidden).
 * @param things the things to get the list of armours from
 * @param hidden_only only show the list of hidden objects
 * @see query_types_worn()
 * @see query_living_contents()
 */
protected string armour_list( object *things, int hidden_only, int self ) {
    object* hidden;
    hidden = query_wearing_hidden( TP, things );
    if( hidden_only )
        things = filter( hidden, (: $1->query_visible( TP ) :) );
    else
        things = things - hidden;
    if( !sizeof( things ) )
        return 0;
    // Order them in a reasonable way.
    if( !self )
        things = sort_array( things, (:
            CLOTHING_H->query_clothing_depth($2->query_type())  -
            CLOTHING_H->query_clothing_depth($1->query_type()) :) );
    return query_multiple_short( things );
} /* armour_list() */
/**
 * This method does the inventory of the living objects we all know and
 * love.  It is used in the long description and the inventory commands.
 * @param self are we showing our own inventory
 * @see armour_list()
 * @index inventory
 */
string query_living_contents( int self ) {
    string s;
    string *limbs, *bits, *strs;
    object *carry, *conts, *holding, *arms;
    object money, ob;
    int i, coins, pos;
    mixed fish;
    s = "";
    strs = ({ });
    if( !limbs = TO->query_limbs() )
        limbs = ( TO->query_race_ob() )->query_limbs();
    conts = filter( INV(TO), (: $1->short(0) :) );
    money = present( MONEY_ALIAS, TO );
    i = sizeof( holding = (object *)TO->query_holding() + ({ }) );
    if( !arms = (object *)TO->query_armours() - holding )
        arms = ({ });
    carry = conts - arms - holding - ({ money });
    while( i-- ) {
        if( holding[i] ) {
            bits = ({ limbs[i] });
            ob = holding[i];
            holding[i] = 0;
            while( ( pos = member_array( ob, holding ) ) != -1 ) {
                bits += ({ limbs[pos] });
                holding[pos] = 0;
            }
            strs += ({ ob->a_short()+" ("+
                query_multiple_short( bits, "a", 1 )+")" });
        }
    }
    if( sizeof(strs) )
        s += "$I$+10,+0=%^RED%^Holding%^RESET%^ : "+
             query_multiple_short( strs )+".\n$I$-10,-0=";
    if( sizeof( arms ) ) {
        if( fish = armour_list( arms, 0, self ) )
            s += "$I$+10,+0=%^YELLOW%^Wearing%^RESET%^ : "+fish+
                 ".\n$I$-10,-0=";
        if( self && ( fish = armour_list( arms, 1, self ) ) )
            s += "$I$+10,+0=%^YELLOW%^(under)%^RESET%^ : "+fish+
                 ".\n$I$-10,-0=";
    }
    if( sizeof( carry ) ) {
        if( fish = TO->query_contents( 0, carry, 1 ) ) {
            if( pointerp(fish) )
                s += "$I$+10,+0=%^GREEN%^"+fish[1]+"%^RESET%^: "+
                     fish[0]+"$I$-10,-0=";
            else
                s += "$I$+10,+0=%^GREEN%^Carrying%^RESET%^: "+fish+
                     "$I$-10,-0=";
        }
    }
    if( self && s == "")
        s = "You are empty handed.\n";
    if( self && !TO->check_dark( ENV(TO)->query_light() ) ) {
        s += "Your purse contains "+( money ?
             query_multiple_short( (string *)money->half_short( 1 ) ) :
             "only moths" )+".\n";
    } else {
       if( money )
           coins = (int)money->query_number_coins();
       if( coins ) {
           s += ( self ? "Your" : CAP( (string)TO->HIS ) ) + " purse is ";
           switch( coins ) {
             case 0..10:
               s += "home to only moths!";
             break;
             case 11..100:
               s += "tinkling with coins.";
             break;
             case 101..300:
               s += "bulging with coins.";
             break;
             default:
               s += "fit to burst!";
           }
           s += "\n";
       }
    }
    return s;
} /* query_living_contents() */