skylib_fluffos_v3/
skylib_fluffos_v3/bin/
skylib_fluffos_v3/bin/db/
skylib_fluffos_v3/fluffos-2.9-ds2.04/
skylib_fluffos_v3/fluffos-2.9-ds2.04/ChangeLog.old/
skylib_fluffos_v3/fluffos-2.9-ds2.04/Win32/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/simuls/
skylib_fluffos_v3/fluffos-2.9-ds2.04/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/clone/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/command/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/data/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/etc/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/master/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/log/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/compiler/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/efuns/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/operators/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/u/
skylib_fluffos_v3/fluffos-2.9-ds2.04/tmp/
skylib_fluffos_v3/fluffos-2.9-ds2.04/windows/
skylib_fluffos_v3/mudlib/
skylib_fluffos_v3/mudlib/cmds/
skylib_fluffos_v3/mudlib/cmds/admin/
skylib_fluffos_v3/mudlib/cmds/guild-race/
skylib_fluffos_v3/mudlib/cmds/living/broken/
skylib_fluffos_v3/mudlib/cmds/player/group_cmds/
skylib_fluffos_v3/mudlib/cmds/playtester/
skylib_fluffos_v3/mudlib/d/admin/
skylib_fluffos_v3/mudlib/d/admin/room/
skylib_fluffos_v3/mudlib/d/admin/room/we_care/
skylib_fluffos_v3/mudlib/d/admin/save/
skylib_fluffos_v3/mudlib/d/admin/text/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/buildings/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/map/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/roads/
skylib_fluffos_v3/mudlib/d/learning/chars/
skylib_fluffos_v3/mudlib/d/learning/functions/
skylib_fluffos_v3/mudlib/d/learning/handlers/
skylib_fluffos_v3/mudlib/d/learning/help_topics/
skylib_fluffos_v3/mudlib/d/learning/help_topics/npcs/
skylib_fluffos_v3/mudlib/d/learning/help_topics/objects/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/crowd/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/situations/
skylib_fluffos_v3/mudlib/d/learning/save/
skylib_fluffos_v3/mudlib/d/learning/school/
skylib_fluffos_v3/mudlib/d/learning/school/add_sc/
skylib_fluffos_v3/mudlib/d/learning/school/characters/
skylib_fluffos_v3/mudlib/d/learning/school/general/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/basic_commands/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/edtutor/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_fluffos_v3/mudlib/d/learning/school/items/
skylib_fluffos_v3/mudlib/d/learning/school/npc_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/room_basic/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/situations/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_fluffos_v3/mudlib/d/learning/text/
skylib_fluffos_v3/mudlib/d/liaison/
skylib_fluffos_v3/mudlib/d/mudlib/
skylib_fluffos_v3/mudlib/d/mudlib/changes/
skylib_fluffos_v3/mudlib/d/playtesters/
skylib_fluffos_v3/mudlib/d/playtesters/effects/
skylib_fluffos_v3/mudlib/d/playtesters/handlers/
skylib_fluffos_v3/mudlib/d/playtesters/items/
skylib_fluffos_v3/mudlib/d/sage/
skylib_fluffos_v3/mudlib/doc/
skylib_fluffos_v3/mudlib/doc/creator/
skylib_fluffos_v3/mudlib/doc/driver/
skylib_fluffos_v3/mudlib/doc/driver/efuns/arrays/
skylib_fluffos_v3/mudlib/doc/driver/efuns/buffers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/calls/
skylib_fluffos_v3/mudlib/doc/driver/efuns/compile/
skylib_fluffos_v3/mudlib/doc/driver/efuns/filesystem/
skylib_fluffos_v3/mudlib/doc/driver/efuns/floats/
skylib_fluffos_v3/mudlib/doc/driver/efuns/functions/
skylib_fluffos_v3/mudlib/doc/driver/efuns/general/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mappings/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mixed/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mudlib/
skylib_fluffos_v3/mudlib/doc/driver/efuns/numbers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/parsing/
skylib_fluffos_v3/mudlib/doc/login/
skylib_fluffos_v3/mudlib/doc/lpc/basic_manual/
skylib_fluffos_v3/mudlib/doc/lpc/intermediate/
skylib_fluffos_v3/mudlib/doc/new/add_command/
skylib_fluffos_v3/mudlib/doc/new/events/
skylib_fluffos_v3/mudlib/doc/new/handlers/
skylib_fluffos_v3/mudlib/doc/new/living/race/
skylib_fluffos_v3/mudlib/doc/new/living/spells/
skylib_fluffos_v3/mudlib/doc/new/object/
skylib_fluffos_v3/mudlib/doc/new/player/
skylib_fluffos_v3/mudlib/doc/new/room/guild/
skylib_fluffos_v3/mudlib/doc/new/room/outside/
skylib_fluffos_v3/mudlib/doc/new/room/storeroom/
skylib_fluffos_v3/mudlib/doc/object/
skylib_fluffos_v3/mudlib/doc/playtesters/
skylib_fluffos_v3/mudlib/doc/policy/
skylib_fluffos_v3/mudlib/doc/weapons/
skylib_fluffos_v3/mudlib/global/
skylib_fluffos_v3/mudlib/global/creator/
skylib_fluffos_v3/mudlib/handlers/
skylib_fluffos_v3/mudlib/include/casino/
skylib_fluffos_v3/mudlib/include/cmds/
skylib_fluffos_v3/mudlib/include/effects/
skylib_fluffos_v3/mudlib/include/npc/
skylib_fluffos_v3/mudlib/include/room/
skylib_fluffos_v3/mudlib/include/shops/
skylib_fluffos_v3/mudlib/net/daemon/
skylib_fluffos_v3/mudlib/net/daemon/chars/
skylib_fluffos_v3/mudlib/net/inherit/
skylib_fluffos_v3/mudlib/net/obj/
skylib_fluffos_v3/mudlib/net/obj/BACKUPS/
skylib_fluffos_v3/mudlib/obj/amulets/
skylib_fluffos_v3/mudlib/obj/armours/plate/
skylib_fluffos_v3/mudlib/obj/b_day/
skylib_fluffos_v3/mudlib/obj/clothes/transport/horse/
skylib_fluffos_v3/mudlib/obj/faith/symbols/
skylib_fluffos_v3/mudlib/obj/fungi/
skylib_fluffos_v3/mudlib/obj/gatherables/
skylib_fluffos_v3/mudlib/obj/instruments/
skylib_fluffos_v3/mudlib/obj/media/
skylib_fluffos_v3/mudlib/obj/misc/player_shop/
skylib_fluffos_v3/mudlib/obj/monster/godmother/
skylib_fluffos_v3/mudlib/obj/monster/transport/
skylib_fluffos_v3/mudlib/obj/rings/
skylib_fluffos_v3/mudlib/obj/scabbards/
skylib_fluffos_v3/mudlib/obj/spells/
skylib_fluffos_v3/mudlib/obj/stationery/
skylib_fluffos_v3/mudlib/obj/stationery/envelopes/
skylib_fluffos_v3/mudlib/obj/toys/
skylib_fluffos_v3/mudlib/obj/vessels/
skylib_fluffos_v3/mudlib/obj/weapons/axes/
skylib_fluffos_v3/mudlib/obj/weapons/chains/
skylib_fluffos_v3/mudlib/obj/weapons/maces/BACKUPS/
skylib_fluffos_v3/mudlib/save/autodoc/
skylib_fluffos_v3/mudlib/save/book_handler/
skylib_fluffos_v3/mudlib/save/books/history/calarien/
skylib_fluffos_v3/mudlib/save/mail/
skylib_fluffos_v3/mudlib/save/new_soul/data/
skylib_fluffos_v3/mudlib/save/parcels/
skylib_fluffos_v3/mudlib/save/playerinfo/
skylib_fluffos_v3/mudlib/save/players/d/
skylib_fluffos_v3/mudlib/save/players/s/
skylib_fluffos_v3/mudlib/save/random_names/
skylib_fluffos_v3/mudlib/save/random_names/data/
skylib_fluffos_v3/mudlib/save/terrains/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_desert/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_grassy_field/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_mountain/
skylib_fluffos_v3/mudlib/save/todo_lists/
skylib_fluffos_v3/mudlib/secure/
skylib_fluffos_v3/mudlib/secure/cmds/admin/
skylib_fluffos_v3/mudlib/secure/cmds/lord/
skylib_fluffos_v3/mudlib/secure/config/
skylib_fluffos_v3/mudlib/secure/handlers/autodoc/
skylib_fluffos_v3/mudlib/secure/handlers/intermud/
skylib_fluffos_v3/mudlib/secure/include/global/
skylib_fluffos_v3/mudlib/secure/save/
skylib_fluffos_v3/mudlib/secure/save/handlers/
skylib_fluffos_v3/mudlib/secure/std/
skylib_fluffos_v3/mudlib/secure/std/classes/
skylib_fluffos_v3/mudlib/secure/std/modules/
skylib_fluffos_v3/mudlib/std/creator/
skylib_fluffos_v3/mudlib/std/dom/
skylib_fluffos_v3/mudlib/std/effects/
skylib_fluffos_v3/mudlib/std/effects/external/
skylib_fluffos_v3/mudlib/std/effects/fighting/
skylib_fluffos_v3/mudlib/std/effects/magic/
skylib_fluffos_v3/mudlib/std/effects/magic/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/other/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/priest/
skylib_fluffos_v3/mudlib/std/effects/room/
skylib_fluffos_v3/mudlib/std/environ/
skylib_fluffos_v3/mudlib/std/guilds/
skylib_fluffos_v3/mudlib/std/guilds/old/
skylib_fluffos_v3/mudlib/std/languages/
skylib_fluffos_v3/mudlib/std/liquids/
skylib_fluffos_v3/mudlib/std/npc/
skylib_fluffos_v3/mudlib/std/npc/goals/
skylib_fluffos_v3/mudlib/std/npc/goals/basic/
skylib_fluffos_v3/mudlib/std/npc/goals/misc/
skylib_fluffos_v3/mudlib/std/npc/plans/
skylib_fluffos_v3/mudlib/std/npc/plans/basic/
skylib_fluffos_v3/mudlib/std/npc/types/
skylib_fluffos_v3/mudlib/std/npc/types/helper/
skylib_fluffos_v3/mudlib/std/npcs/
skylib_fluffos_v3/mudlib/std/outsides/
skylib_fluffos_v3/mudlib/std/races/shadows/
skylib_fluffos_v3/mudlib/std/room/basic/BACKUPS/
skylib_fluffos_v3/mudlib/std/room/basic/topography/
skylib_fluffos_v3/mudlib/std/room/controller/
skylib_fluffos_v3/mudlib/std/room/inherit/topography/
skylib_fluffos_v3/mudlib/std/room/topography/area/
skylib_fluffos_v3/mudlib/std/room/topography/iroom/
skylib_fluffos_v3/mudlib/std/room/topography/milestone/
skylib_fluffos_v3/mudlib/std/shadows/curses/
skylib_fluffos_v3/mudlib/std/shadows/disease/
skylib_fluffos_v3/mudlib/std/shadows/fighting/
skylib_fluffos_v3/mudlib/std/shadows/healing/
skylib_fluffos_v3/mudlib/std/shadows/magic/
skylib_fluffos_v3/mudlib/std/shadows/poison/
skylib_fluffos_v3/mudlib/std/shadows/room/
skylib_fluffos_v3/mudlib/std/shops/controllers/
skylib_fluffos_v3/mudlib/std/shops/objs/
skylib_fluffos_v3/mudlib/std/shops/player_shop/
skylib_fluffos_v3/mudlib/std/socket/
skylib_fluffos_v3/mudlib/std/soul/d/
skylib_fluffos_v3/mudlib/std/soul/e/
skylib_fluffos_v3/mudlib/std/soul/i/
skylib_fluffos_v3/mudlib/std/soul/j/
skylib_fluffos_v3/mudlib/std/soul/k/
skylib_fluffos_v3/mudlib/std/soul/l/
skylib_fluffos_v3/mudlib/std/soul/n/
skylib_fluffos_v3/mudlib/std/soul/o/
skylib_fluffos_v3/mudlib/std/soul/q/
skylib_fluffos_v3/mudlib/std/soul/r/
skylib_fluffos_v3/mudlib/std/soul/u/
skylib_fluffos_v3/mudlib/std/soul/v/
skylib_fluffos_v3/mudlib/std/soul/y/
skylib_fluffos_v3/mudlib/std/soul/z/
skylib_fluffos_v3/mudlib/std/stationery/
skylib_fluffos_v3/mudlib/w/
skylib_fluffos_v3/mudlib/w/default/
skylib_fluffos_v3/mudlib/w/default/armour/
skylib_fluffos_v3/mudlib/w/default/clothes/
skylib_fluffos_v3/mudlib/w/default/item/
skylib_fluffos_v3/mudlib/w/default/npc/
skylib_fluffos_v3/mudlib/w/default/room/
skylib_fluffos_v3/mudlib/w/default/weapon/
skylib_fluffos_v3/mudlib/www/
skylib_fluffos_v3/mudlib/www/java/
skylib_fluffos_v3/mudlib/www/secure/
skylib_fluffos_v3/mudlib/www/secure/lpc/advanced/
skylib_fluffos_v3/mudlib/www/secure/lpc/intermediate/
skylib_fluffos_v3/win32/
/**
 * Keeps track of all the standard armours, weapons and clothing.
 * @index armour
 * @index weapon
 * @index scabard
 * @index clothing
 * @index clothes
 * @index jewellery
 * @index stationery
 * @index instruments
 * @author Furball
 * @changed Many many, by many people
 * @changed 4/1/97 Ceres
 * The discworld armoury was rewritten by Ceres on 4/1/97 to handle
 * subdirectories within the standard dirs.
 * @changed 20/06/01 Shaydz
 * Rewritten to remove a few annoying bugs, including not being able to
 * request items that had more than one word.
 * @changed 26/06/02 Sandoz
 * Removed all the recycling code, because it will never be reliable,
 * because of properties, effects and whatnot.
 * @changed 06/09/02 Sandoz
 * Added stationery and instrument lists, and new recycling code which
 * will hopefully work ( gotta love reload_object() :) ).
 * @changed 26/09/02 Sandoz
 * Changed to only recycle items that have been requested before with
 * request_item(), and to only accept an item for recycling if its
 * miss count is higher than the number of currently recycled items.
 */

#define CONTAINER    "/std/objects/armoury_container"

#define ITEM_LOG

#ifdef ITEM_LOG
#define SAVE_FILE    HANDLER_SAVE_DIR "/armoury_log.o"
#endif

// The maximum number of items of the same time we recycle.
#define MAX_RECYCLE  10

#define O_WEAPON     1
#define O_ARMOUR     2
#define O_CLOTHING   4
#define O_SCABBARD   8
#define O_JEWELLERY  16
#define O_STATIONERY 32
#define O_INSTRUMENT 64
#define O_ACCEPT     128
#define O_ORES       256

inherit ROOM_OBJ;

/**
 * This class stores all the data for a specific armoury item.
 * @member file the file name of the item
 * @member recycled the recycled objects
 * @member hits recycle hits
 * @member misses recycle misses
 */
class item_data {
    string file;
    object *recycled;
    int hits;
    int misses;
    int flags;
}

#ifdef ITEM_LOG
private int call_id;
#endif

// This mapping contains all our items, for faster access.
private nosave mapping item_list;

// This stores our container object, where we keep all out recycled stuff.
private object cont;

// This stores all the items that can be searched up from rooms.
private object *guttered;

#ifdef ITEM_LOG
private void do_logging();
#endif

void rehash();

/** @ignore yes */
int query_keep_room_loaded() { return 1; }

protected void setup() {
    set_short("Armoury" );
    add_property("determinate", "the ");
    set_light(50);

    set_long("You are in the Armoury.  Here you can list all of the "
        "\"weapons\", \"armour\", \"clothing\", \"jewellery\", "
        "\"scabbards\", \"stationery\" items, \"ores\" and "
        "musical \"instruments\" "
        "that are available, or \"request\" one of them.  The armoury "
        "stores its list of items a mapping, which can be updated with "
        "\"rehash\".\n");

    rehash();

    guttered = ({ });

#ifdef ITEM_LOG
    call_id = call_out( (: do_logging :), 1200 );
    if( file_exists(SAVE_FILE) )
        unguarded( (: rm, SAVE_FILE :) );
#endif

} /* setup() */

/** @ignore yes */
private string convert_fname( string file ) {
    return replace_string( explode( file, ".")[0], "_", " ");
} /* convert_fname() */

/**
 * This method recycles a suitable object.
 * It will call reload_object() on it, and make it available for
 * requesting from the armoury.
 * @param ob the object to try to recycle
 * @return 1 if recycled successfully, 0 if not
 */
int recycle_object( object ob ) {
    class item_data data;
    string base, name;
    int i;

    name = convert_fname( explode( base = base_name(ob), "/")[<1] );

    if( classp( data = item_list[name] ) && ( data->flags & O_ACCEPT ) &&
        data->file == base && ( i = sizeof(data->recycled) ) < data->misses &&
        i < MAX_RECYCLE ) {
        object *inv;

        if( sizeof( inv = INV(ob) ) ) {
            inv->move("/room/rubbish");
            if( sizeof( INV(ob) ) )
                return 0;
        }

        if( !cont && !( cont = clone_object(CONTAINER) ) || ob->move(cont) )
            return 0;

        reload_object(ob);
        data->recycled += ({ ob });

        if( ob->query_weight() < roll_MdN( 4, 20 ) &&
            !sizeof( ob->query_value_info() ) )
            guttered += ({ ob });

        return 1;

    }

    return 0;

} /* recycle_object() */

/**
 * General item retreival function.  It returns a new item
 * it handles any sort of item.  The percentage is the
 * percentage condition in which it is returned.
 * The "word" parameter is the name of the requested item, essentially
 * the filename without directory and with "_"'s changed to " "'s. The
 * "percent" parameter is used as measure of how good it
 * is compared to a fully functional one. So a 50% dagger is only 50% as
 * good as a 100% one.
 * <p>
 * The file armoury.h defines the ARMOURY variable.  You need to include
 * this into your file to use it.  You should include this file and
 * uyse ythis define rather than the full path to the armoury, as
 * otherwise your code could stuff up :)
 * @param word the name of the item to retreive
 * @param percent the percentage condition to be in
 * @see /include/armoury.h
 * @return the requested object, or 0 on failure
 * @example
 * // get a slightly worn long sword and give it to the npc.
 * ARMOURY->request_item("long sword", 85)->move(npc);
 * @example
 * // Get a random condition armour.
 * armour = ARMOURY->request_item("leather jacket", random(100));
 */
object request_item( string word, int percent ) {
    class item_data data;
    object thing, *obs;
    int i;
    if( !word )
        error("No item name specified in request_item().\n");

    if( percent < 1 )
        error("Zero or negative item condition in request_item().\n");

    if( !classp( data = item_list[word] ) )
        return 0;

    if( cont && ( i = sizeof( obs = data->recycled ) ) ) {
        while( i-- ) {
            if( ( thing = obs[i] ) && ENV(thing) == cont ) {
                data->recycled = obs[0..i-1];
                data->hits++;
                thing->set_percentage( percent );
                guttered -= ({ 0, thing });

                return thing;
            }
        }
        // We found nothing of use.
        data->recycled = ({ });
    }

    if( !thing = clone_object( data->file ) ) {
        printf("The armoury failed to clone %O.\n", word );
        log_file("ARMOURY", "%s - failed to clone %O (%s).\n",
            ctime(time()), word, file_name(PO) );

        return 0;
    }

    data->misses++;

    if( !( data->flags & O_ACCEPT ) &&
        !thing->query_property(NO_RECYCLE) )
        data->flags |= O_ACCEPT;

    thing->set_percentage( percent );

    return thing;

} /* request_item() */

/** @ignore yes */
void dest_me() {
    if( cont )
        cont->dest_me();
    ::dest_me();
} /* dest_me() */

/**
 * Returns the current list of all items.
 * @return the items mapping
 */
mapping query_item_list() { return copy(item_list); }

/**
 * This method returns the recycle hits count for a specific file.
 * @param word the name of the object to get the hits count for
 * @return the hits count
 */
int query_hits( string word ) {
    if( item_list[ word ] ||
        item_list[ word = convert_fname( explode( word, "/")[<1] ) ] )
        return item_list[word]->hits;
    return 0;
} /* query_hits() */

/**
 * This method returns the recycle miss count for a specific file.
 * @param word the name of the object to get the misses count for
 * @return the misses count
 */
int query_misses( string word ) {
    if( item_list[ word ] ||
        item_list[ word = convert_fname( explode( word, "/")[<1] ) ] )
        return item_list[word]->misses;
    return 0;
} /* query_misses() */

/**
 * This method returns the recycled items for a specific file.
 * @param word the name of the object to get the recycled objects for
 * @return the recycled objects
 */
object *query_recycled( string word ) {
    if( word && ( item_list[ word ] ||
        item_list[ word = convert_fname( explode( word, "/")[<1] ) ] ) )
        return item_list[word]->recycled;
    return 0;
} /* query_recycled() */

/**
 * This method returns whether or not the armoury is currently accepting
 * the specified item for recycling.
 * @param word the name of the object to check
 * @return 1 if we are currently accepting the item, 0 if not
 */
int query_accepting( string word ) {
    if( item_list[ word ] ||
        item_list[ word = convert_fname( explode( word, "/")[<1] ) ] )
        return ( item_list[word]->flags & O_ACCEPT ) > 0;
    return 0;
} /* query_accepting() */

/**
 * This method returns the absolute filename of an item.
 * @param name the name of the item
 * @return the absolute filename of the item
 */
string query_item_filename( string item ) {
    class item_data data;

    if( classp( data = item_list[item] ) )
        return data->file;

    return 0;

} /* query_item_filename() */

/** @ignore yes */
string *item_list_filter( int type ) {
    return keys( filter( item_list, (: $2->flags & $3 :), type ) );
} /* item_list_filter() */

/**
 * Returns the current list of known weapons.
 * @return the weapons array
 */
string *query_weapons() { return item_list_filter( O_WEAPON ); }

/**
 * Returns the current list of known armours.
 * @return the armours array
 */
string *query_armour() { return item_list_filter( O_ARMOUR ); }

/**
 * Returns the current list of known clothing.
 * @return the clothing array
 */
string *query_clothing() { return item_list_filter( O_CLOTHING ); }

/**
 * Returns the current list of known jewelley.
 * @return the jewellery array
 */
string *query_jewellery() { return item_list_filter( O_JEWELLERY ); }

/**
 * Returns the current list of known scabbards.
 * @return the scabbards array
 */
string *query_scabbards() { return item_list_filter( O_SCABBARD ); }

/**
 * Returns the current list of known stationery items.
 * @return the stationery items array
 */
string *query_stationery() { return item_list_filter( O_STATIONERY ); }

/**
 * Returns the current list of known musical instruments.
 * @return the musical instruments array
 */
string *query_instruments() { return item_list_filter( O_INSTRUMENT ); }

/**
 * Returns the current list of known ores.
 * @return the ores instruments array
 */
string *query_ores() { return item_list_filter( O_ORES ); }

/** @ignore yes */
private void make_list( string base_dir, int type ) {
    string *dirs, dir, fname, tmp;
    mixed file;

    dirs = ({ });

    foreach( file in get_dir( base_dir, -1 ) )
        if( file[1] == -2 )
            dirs += ({ base_dir+file[0]+"/" });

    dirs += ({ base_dir });

    foreach( dir in dirs ) {
        foreach( fname in get_dir( dir+"*.c") ) {
            if( undefinedp( item_list[ tmp = convert_fname(fname) ] ) ) {
                item_list[tmp] = new( class item_data );
                item_list[tmp]->file = dir+fname[0..<3];
                item_list[tmp]->recycled = ({ });
                item_list[tmp]->flags = type;
            } else {
                printf("Failed to add %s (%s) - %s already exists in the "
                    "mapping.\n", tmp, dir+fname[0..<3],
                    item_list[tmp]->file );
                log_file("ARMOURY", "Failed to add %s (%s) - %s already "
                    "exists in the mapping.\n", tmp, dir+fname[0..<3],
                    item_list[tmp]->file );
            }
        }
    }

} /* make_list() */

/** @ignore yes */
int clean_up( int parent ) { return 0; }

/**
 * This method returns the list of items that could be
 * searched up from gutters.
 * @return the guttered items list
 */
object *query_guttered() {
    if( cont )
        guttered = filter( guttered, (: $1 && ENV($1) == $2 :), cont );
    else
        guttered = ({ });

    return guttered;

} /* query_guttered() */

/**
 * This method gets a guttered item from the armoury.
 * This is used by the search function in city rooms,
 * and returns a random smaller item from the armoury's
 * recycled items list.  The condition percentage should
 * not be set too high for guttered items, and has been
 * capped at 50% for that very reason.
 * @param percent the percentage condition the item should be in
 * @return a guttered object or 0 if there are none
 */
object get_guttered( int percent ) {
    int i;

    if( percent < 1 )
        error("Zero or negative item condition in get_guttered().\n");

    if( percent > 10 )
        percent = 10;

    if( cont && ( i = sizeof( query_guttered() ) ) ) {
        object ob;

        ob = guttered[ i = random( i ) ];
        ob->set_percentage( percent );
        guttered = delete( guttered, i, 1 );
        return ob;
    }

    return 0;

} /* get_guttered() */

/** @ignore yes */
void rehash() {
    mapping tmp;
    string file;
    class item_data data;

    if( sizeof(item_list) )
        tmp = item_list;

    item_list = ([ ]);

    //make_list("/obj/dwweapons/", O_WEAPON );
    make_list("/obj/weapons/", O_WEAPON );

    //make_list("/obj/dwarmours/", O_ARMOUR );
    make_list("/obj/armours/", O_ARMOUR );

    //make_list("/obj/dwclothes/", O_CLOTHING );
    make_list("/obj/clothes/", O_CLOTHING );

    //make_list("/obj/dwjewellery/", O_JEWELLERY );
    make_list("/obj/jewellery/", O_JEWELLERY );

    //make_list("/obj/dwscabbards/", O_SCABBARD );
    make_list("/obj/scabbards/", O_SCABBARD );

    make_list("/obj/stationery/", O_STATIONERY );

    make_list("/obj/instruments/", O_INSTRUMENT );
    
    make_list("/obj/ores/", O_ORES);

    if( sizeof(tmp) ) {
        string *keys;

        // Transfer the accept flag, recycled objects and hits/misses
        // from the old mapping.
        foreach( file, data in item_list ) {
            if( classp( tmp[file] ) ) {
                data->hits = tmp[file]->hits;
                data->misses = tmp[file]->misses;

                if( data->file == tmp[file]->file )
                    data->recycled = tmp[file]->recycled - ({ 0 });
                else if( cont && sizeof( tmp[file]->recycled -= ({ 0 }) ) )
                    map( filter( tmp[file]->recycled, (: ENV($1) == $2 :),
                        cont ), (: $1->dest_me() :) );

                if( tmp[file]->flags & O_ACCEPT )
                    data->flags |= O_ACCEPT;
            }
        }

        // Clean up recycled items that are no longer needed.
        if( cont && sizeof( keys = keys(tmp) - keys(item_list) ) )
            foreach( file in keys )
                if( sizeof( tmp[file]->recycled -= ({ 0 }) ) )
                    map( filter( tmp[file]->recycled, (: ENV($1) == $2 :),
                        cont ), (: $1->dest_me() :) );
    }

} /* rehash() */

/** @ignore yes */
private int print_list( string str, string *arr ) {
    printf( str, TP->query_cols(), implode( sort_array( arr, 1 ), "\n") );
    return 1;
} /* print_list() */

/** @ignore yes */
int weapons() {
    return print_list("Weapons:\n%-*#s\n", query_weapons() );
} /* weapons() */

/** @ignore yes */
int armour() {
    return print_list("Armour:\n%-*#s\n", query_armour() );
} /* armour() */

/** @ignore yes */
int clothing() {
    return print_list("Clothes:\n%-*#s\n", query_clothing() );
} /* clothing() */

/** @ignore yes */
int jewellery() {
    return print_list("Jewellery:\n%-*#s\n", query_jewellery() );
} /* jewellery() */

/** @ignore yes */
int scabbards() {
    return print_list("Scabbards:\n%-*#s\n", query_scabbards() );
} /* scabbards() */

/** @ignore yes */
int stationery() {
    return print_list("Stationery items:\n%-*#s\n", query_stationery() );
} /* scabbards() */

/** @ignore yes */
int instruments() {
    return print_list("Musical instruments:\n%-*#s\n", query_instruments() );
} /* scabbards() */

/** @ignore yes */
int ores() {
    return print_list("Ores:\n%-*#s\n", query_ores() );
} /* ores() */

/** @ignore yes */
int request( string word ) {
    int percent, i;
    object thing;
    string *words;

    if( !word || word == "")
        return notify_fail("Request what?\n");

    words = explode( word, " ");

    if( sizeof(words) < 2 )
        return notify_fail("Syntax: request <item name> <percent>\n");

    i = sizeof(words);

    if( !percent = to_int(words[i-1]) )
        return notify_fail("Syntax: request <item name> <percent>\n");

    words = words - ({ words[i-1] });
    word = implode( words, " ");
    thing = request_item( word, percent );

    if( !thing )
        return notify_fail( word+" not found.\n");

    if( thing->move(TP) ) {
        write( thing->the_short()+" has been placed in here.\n");
        thing->move(TO);
    } else {
        write( thing->the_short()+" has been placed in your inventory.\n");
    }

    return 1;

} /* request() */

/** @ignore yes */
int do_rehash() {
    rehash();
    write("Rehash completed.\n");
    return 1;
} /* do_rehash() */

/** @ignore yes */
void init() {
    ::init();

    add_command("rehash", "");

    add_command("request", "<string'item name> <percent'>",
        (: request($4[0]) :) );

    foreach( string comm in ({"weapons", "armour", "clothing", "jewellery",
        "scabbards", "stationery", "instruments", "ores"}) )
        add_command( comm, "", (: call_other( TO, $(comm) ) :) );

} /* init() */

#ifdef ITEM_LOG
/** @ignore yes */
private void do_logging() {
    mapping misses, unique, saved;
    string str;
    string missing = "", extra = "";
    int i, total_missing, total_extra, changed;

    if( find_call_out(call_id) == -1 )
        call_id = call_out( (: do_logging :), 3600 );

    misses = ([ ]);

    if( file_exists(SAVE_FILE) )
        saved = restore_variable( unguarded( (: read_file, SAVE_FILE :) ) );

    if( !mapp(saved) )
        saved = ([ ]);

    // First create a mapping of - ([ filename : misses ])
    foreach( str, class item_data data in item_list )
        misses[data->file] = data->misses;

    // Make a mapping of all cloned armoury objects based on their
    // base name - ([ basename : ({ objects }) ])
    unique = unique_mapping( objects( (: clonep($1) &&
        !undefinedp( $(misses)[base_name($1)] ) :) ),
        (: base_name($1) :) );

    // Now check how many extra objects we have (bad, because something
    // is cloning items, but not through the armoury), or how many we are
    // missing (bad, because something is destructing items instead of
    // sending them to the rubbish room).
    // This will break a little when someone with a lot of armoury items
    // logs on though... But... nothing helps against that.
    foreach( str in sort_array( keys(misses), 1 ) ) {
        if( i = misses[str] - sizeof( unique[str] ) ) {
            if( saved[str] != i ) {
                changed = 1;
                saved[str] = i;
            }

            if( i > 4 ) {
                missing += sprintf("%5d %s\n", i, str );
                total_missing += i;
                continue;
            }

            if( i < -4 ) {
                extra += sprintf("%5d %s\n", -i, str );
                total_extra -= i;
                continue;
            }
        }
    }

    if( changed ) {
        if( sizeof(saved) )
            unguarded( (: write_file, SAVE_FILE, save_variable(saved), 1 :) );

        if( missing != "")
            log_file("ARMOURY_RECYCLE_LOG", "%s - %i missing "
                "items:\n%s", ctime(time()), total_missing, missing );

        if( extra != "")
            log_file("ARMOURY_RECYCLE_LOG", "%s - %i extra "
                "items:\n%s", ctime(time()), total_extra, extra );
    }

} /* do_logging() */

/** @ignore yes */
void force_logging() {
    if( adminp( previous_object(-1) ) )
        do_logging();
} /* force_logging() */
#endif

/** @ignore yes */
mixed stats() {
    mixed arr;
    int misses, hits;
    class item_data data;

    foreach( data in values(item_list) ) {
        hits += data->hits;
        misses += data->misses;
    }

    arr = ({ ({"total hits", hits }), ({"total misses", misses }) });

    if( cont ) {
        arr += ({
            ({"container", cont }),
            ({"recycled", sizeof(INV(cont)) }),
        });
    }

    arr += ({
        ({"weapons", sizeof( query_weapons() ) }),
        ({"armour", sizeof( query_armour() ) }),
        ({"clothes", sizeof( query_clothing() ) }),
        ({"jewellery", sizeof( query_jewellery() ) }),
        ({"scabbards", sizeof( query_scabbards() ) }),
        ({"stationery", sizeof( query_stationery() ) }),
        ({"instruments", sizeof( query_instruments() ) }),
        ({"ores", sizeof( query_ores() ) }),
        ({"total items", sizeof( item_list) }),
        ({"guttered items", sizeof( query_guttered() ) }),
    });

#ifdef ITEM_LOG
    if( ( hits = find_call_out(call_id) ) != -1 )
        arr += ({ ({"next logging", hits }) });
#endif

    return arr;

} /* stats() */