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/
/**
 * Auction Room Inheritable
 * This room will give you everything you need to make an auction
 * room.
 * @author Terano
 * @started 3 October, 1998
 * @changed 24 March, 1999 Many exciting things. Terano.
 * @changed 2 October, 1999 Added stability! Excitement!
 * An excessively complicated browse function! Terano.
 * @changed 8 January, 2000! Made Y2K compliant! (Just kidding)
 * Added some advertising stuff.
 * Fixed a missing case as well.
 * @changed 11 January, 2000 Fixed some advertising stuff.
 */

#include <money.h>
#include <move_failures.h>
#include <mail.h>

#define COLOUR_ID "colour code"

#define AUCTION_PLAYER_NAME 0
#define AUCTION_PLAYER_BID 1

#define ERRNOSPACE -1 //No space
#define ERRBADPARM -2 //Bad parameter
#define ERRBADCBOB -3 //Bad call back object
#define ERROBNOMOVE -4 //Autoload gen failed due to bad move
#define ERRGENFAIL -5 //General failure
#define ERRNORECV -6  //Could not recover autoloading
#define ERRRECVEMP -7 //Case recovered as empty
#define WARNUNDEST -8 //An object being converted was undestable.
#define WARNEXCL -9 //Bidder has been excluded
#define WARNNOLOTS "NULL" //We have no lots!

#define TCTP( x, y ) tell_creator( TP, x, y )
#define GECM( x ) "/global/player/events"->convert_message( x )

#define c_item class item
#define c_store class store
#define c_lot class lot

#define OPEN "open"
#define CLOSED "closed"
#define WAIT_SELLER "waitsell"
#define WAIT_BUYER "waitbuy"
#define WAIT_BUYER_LAPSE "waitbuylapse"
#define WAIT_CRE_INTERVENTION "waitcreint"

#define CHECK_CYCLE 10  //Apparently the control function is efficient enough

#define COLOURS ({ "red", "orange", "yellow", "blue", "green", "indigo",\
  "violet", "crimson", "puce", "emerald", "ochre", "tangerine", "aquamarine",\
  "silver", "gold", "copper", "lilac" })
#define NO_COLOURS sizeof( COLOURS )

nosave inherit ROOM_OBJ;  //Why save all those evil room variables?
inherit "/global/player/auto_load";

/**
 * In this new version, we aren't keeping the objects loaded,
 * because the auto_load code seems flaky outside of
 * /global/player.c
 * Instead keep a whole bunch of info about it on file.
 */

c_item {
  string name;
  string *alias;
  string *adjectives;
  string long;
  string read_mess;
  string enchant_mess;
}

c_store {
  int case_code;
  string colour;
  string inv_string;
  c_item *inventory;
}

/**
 * A few notes about this class, I didn't like the way the old one
 * worked, when a lot moved to expired_lots, there was no real way to recover it
 * Instead, we will keep one array of all lots, with differing status's depending
 * on whats happening.
 * IE: Open: Accepting bids.
 *     Waiting: Seller: It did not take any acceptable bids and it is waiting collection
 *       by the seller.
 *     Waiting: Buyer: A bid was taken and we are waiting for payment.
 *     Waiting: Buyer (lapsed): A bid was taken, but lapsed. There are no
 *       other bidders, so in the next cycle the seller will be mailed and
 *       status changed to Waiting: Seller.
 *     Waiting Creator Intervention:  A lot has fallen over in some way,
 *       and needs a creator to fix it.
 *     Closed: The bid has been collected (by either buyer or seller),
 *       lots will stay in this status for 2 hours after collection.
 *       Then payment will be credited to the payment array and the lot will
 *       be deleted.
 * Case code is used in reference to the store class.
 * The rest are the same as they were in the last version
 */

c_lot {
  int case_code; //The code that matches this bid.
  c_store assoc_store; //Associated store, to save processing!
  string seller; //Name of the person/object selling
  string status; //Either Open, Waiting: Seller, Waiting: Buyer or Closed.
  int expiration_time; //Time that this status stops
  int reserve_price; //Min price
  mapping bids; //Mapping of bids
  mixed *lot_autoload; //Autoload info for the bid
  mixed *current_bid; //Info on the current bid
  string *auto_bids; //I'm not sure yet, but it will become apparent
  string notes; //Player added notes
  string *excluded; //People player wants excluded from bidding.
}

c_lot *lots = ({ }); //Array of lots
mapping payments = ([ ]); //Stored as ([ "name": amount ]);
int lot_count = 0;
nosave string *used_colours = ({ });
nosave string currency = "default";
nosave string location = "unset";
nosave string shop_name = "REAS Auction Inheritable";
nosave int admin_cost = 2000; //defaults to AM$5
nosave float commission = ( 5.0/100.0 ); //Default to 5%

/**
 * I've decided that a large amount of problems with this code
 * were from the cases, to add realism, I've left them in, but
 * I've removed all the functionality from them and moved it in
 * here.
 */
mapping cases = ([ ]); //Something like: ([ /std/object#123: 0001 ])

void save_file();
void load_file();

void set_location( string loc );
void set_currency( string cur );
void set_admin_cost( int value );
void set_commission( int percent );
void set_case_desc( string *bits );
mixed recover_lot( mixed lot_autoload );

int change_status( int lot_ident, string new_status );
void adjust_money( int amount, object player );
mixed generate_auto_load( object *obs );
c_store generate_store( object *things, int lot_id );
c_lot query_status( int lot_ident );

int do_deposit( object *things, int auction_time, string time_type,
  string res_price );
int do_bid( string offer, object *boxes );
int do_collect( string pattern );
int do_list();
int do_withdraw( object *boxes);
int do_describe( object *boxes, string int_desc );
int do_exclude( object *cases, string excluded );
int do_browse( object *cases, string target, int identifier );
int do_unexclude( object *cases, string excluded );
string generate_advertising_string( c_lot lot );
string generate_random_adv_str();

/**
 * @ignore
*/
void create() {

    do_setup++;
    ::create();
    do_setup--;

    if ( !do_setup ) {
       TO->setup();
       TO->reset();
    }

    call_out( "load_file", 1 ); //To give time for location data to be restored
    call_out( "load_store", 2 ); //To give time for save data to be restored
    call_out( "lot_check", 5 ); //Lets do some work!
}

/**
 * @ignore
 */
void init() {

    TP->add_command( "bid", TO,
      "<string'amount'> {on|for} <indirect:object:here'case'>",
      (: do_bid( $4[0], $1 ) :) );

   TP->add_command( "collect", TO,
      ({ "successful bids", "money", "expired lots",
        "all" }),
      (: do_collect( $5 ) :) );

    TP->add_command( "deposit", TO,
      "<indirect:object:me'items'> for <number> "
      "{minute|hour|day} auction" ,
      (: do_deposit( $1, $4[1], $4[2], "" ) :) );

   TP->add_command( "deposit", TO,
      "<indirect:object:me'items'> for <number> "
      "{minute|hour|day} "
      "auction with [a] reserve price of <string'amount'>",
      (: do_deposit( $1, $4[1], $4[2], $4[3] ) :) );

    TP->add_command( "list", TO, "" );

   TP->add_command( "browse", TO,
       "<string'object'> in <indirect:object'case'>", (: do_browse( $1, $4[0], 0 ) :) );

    TP->add_command( "browse", TO,
       "<string'object'> <number> in <indirect:object'case'>",
       (: do_browse( $1, $4[0], $4[1] ) :) );

    TP->add_command( "withdraw", TO,
      "<indirect:object'case'> from auction",
      (: do_withdraw( $1 ) :) );

   TP->add_command( "write", TO,
      "<string'text'> on <indirect:object'case'>",
      (: do_describe( $1, $4[0] ) :) );

   TP->add_command( "exclude", TO,
      "<string'name'> from bidding on <indirect:object'case'>",
      (: do_exclude( $1, $4[0] ) :) );

   TP->add_command( "exclude", TO,
      "list for <indirect:object'case'>",
      (: do_exclude( $1, "list" ) :) );

   TP->add_command( "exclude", TO,
      "current ignore list from bidding on <indirect:object'case'>",
      (: do_exclude( $1, "ignore list" ) :) );

   TP->add_command( "unexclude", TO,
      "<string'name'> from bidding on <indirect:object'case'>",
      (: do_unexclude( $1, $4[0] ) :) );
}


/**
 * This function allows an object to deposit an item for auction,
 * Things are the items to auction, auction length is the length in seconds,
 * function_cb and object_cb are function names and object paths to allow a
 * call back to be scheduled for when the auction is over, res price is
 * the reserve price and int_desc is a description that will be written on
 * the case. If an error code is generated, it is upon the object calling
 * this function to pull those objects back. An object reference isn't
 * kept here.
 */
int automated_deposit( object *things, int auction_length,
 string function_cb, string object_cb, int res_price,
  string int_desc ) {

  mixed *auto_load_string;
  c_lot temp;
  c_store temp2;

 if ( !sizeof( COLOURS - used_colours ) ) {
    log_file( "REAS", "%s: ERRNOSPACE generated by: %s!\n", ctime( time() ),
      file_name( PO ) );
    return ERRNOSPACE;
  }

  if ( !sizeof( things ) || auction_length < 0 ) {
    log_file( "REAS", "%s: ERRBADPARM generated by: %s!\n", ctime( time() ),
      file_name( PO ) );
   return ERRBADPARM;
  }
  if ( !objectp( load_object( object_cb ) ) ) {
    log_file( "REAS", "%s: ERRBADCBOB generated by: %s!\n", ctime( time() ),
      file_name( PO ) );
    return ERRBADCBOB;
  }

  //Work out the new case ID;
 lot_count ++;

  //Generate the case info
  temp2 = generate_store( things, lot_count );

  //Store and destroy objects
  auto_load_string = generate_auto_load( things );

  if ( !arrayp( auto_load_string ) ) {
   if ( (int) auto_load_string == ERROBNOMOVE ) {
      log_file( "REAS", "%s: ERROBNOMOVE generated by: %s!\n", ctime( time() ),
        query_multiple_short( map( things, (: file_name( $1 ) :) ) ) );
      return ERROBNOMOVE;
    }
    log_file( "REAS", "%s: ERRGENFAIL generated by: %s!\n", ctime( time() ),
      query_multiple_short( map( things, (: file_name( $1 ) :) ) ) );
      return ERRGENFAIL;
    }

   temp = new( c_lot, assoc_store: temp2, case_code: lot_count, seller: "Auto", status: OPEN,
      expiration_time: time() + auction_length, reserve_price: res_price,
      bids: ([ ]), current_bid: allocate( 2 ), lot_autoload: auto_load_string,
      auto_bids: ({ function_cb, object_cb }), notes: int_desc, excluded: ({ }) );

    lots += ({ temp });

   return lot_count;
}


/**
 * @ignore
 */
mixed generate_auto_load( object *obs ) {

 object box = clone_object( BAGGAGE_OBJ );
 string *temp;

  box->set_name( "box" );
  box->set_long( "This is a box used in the auction room inheritable. "
    "How did you get hold of one?\n" );
  box->set_weight( 500000 );
  box->set_max_weight( 500000 );
  box->set_volume( 500000 );

 if ( sizeof( filter( obs->move( box ), (: $1 != 0 :) ) ) )
    //Not all obs moved in properly, scream and die!
   return ERROBNOMOVE;

  //So far so good.
  temp = create_auto_load( ({ box }), 0 );

  if ( !arrayp( temp ) )
   //Eek!
  return ERRGENFAIL;

   obs->dest_me();
   obs -= ({ 0 });

   //I might change this to a fatal error later, I'm not sure how autoloading
   //handles undestable objects.
   if ( sizeof( obs ) ) {
     log_file( "REAS", "%s: WARNUNDEST generated by object %s.\n", ctime( time() ),
     query_multiple_short( map( obs, (: file_name( $1 ) :) ) ) );
  }

   box->dest_me();
   return temp;
}

/**
 * Return a store class with info on the objects
 */
c_store generate_store( object *things, int lot_id ) {

  c_store temp;
  c_item temp2;
  object temp3;
  string *avail_colours = COLOURS - used_colours;
  string _colour = avail_colours[ random( sizeof( avail_colours ) ) ];

  temp = new( c_store, case_code: lot_id, colour: _colour,
    inventory: ({ }), inv_string: GECM( query_multiple_short( things ) ) );

    used_colours += ({ _colour });

  foreach( temp3 in things ) {
    temp2 = new( c_item, name: temp3->query_name(),
    alias: temp3->query_alias(), long: temp3->query_long(),
    read_mess: temp3->query_readable_message(), enchant_mess:
    temp3->enchant_string(), adjectives: temp3->query_adjectives() );
    temp->inventory += ({ temp2 });

    if ( !stringp( temp2->read_mess ) )
      temp2->read_mess = "";
  }

 return temp;
}

/**
 * A major component, this function is called once every few minutes to
 * change the state of our bids. It puts new bids out on display, and
 * modifies the state of in game lots as required. It also removes old ones.
 */
void lot_check() {
  c_lot temp_lot;
  c_store current_store;
  object new_case;
  object *all_new_cases = ({ });
  object *obs;
  object *exp_cases;
  int *active_lots;
  string name;
  int *bids;

  //Lets put the cases in first, this will avoid problems with lots that later
  //flip into another status not having cases when the room is loaded.

  //Get rid of null entries..
  cases = filter( cases, (: objectp( $1 ) :) );

  active_lots = map( filter( lots, (: ( (c_lot) $1)->status == OPEN :) ),
   (: ( (c_lot) $1)->case_code :) );

  if ( sizeof( cases ) < sizeof( active_lots ) ) {
    //At least one of our items isn't on display! Find out which one it is
    active_lots = active_lots - values( cases );

    foreach( int temp in active_lots ) {
      //Find our current store..
      temp_lot = filter( lots, (: $1->case_code == $(temp) :) )[0];
      current_store = temp_lot->assoc_store;

      new_case = clone_object( OBJECT_OBJ );
      new_case->set_name( "case" );
      new_case->set_short( current_store->colour + " case" );
      new_case->set_long( "This is a display case used in this auction shop. "
        "It contains " + current_store->inv_string +".\nYou can \"browse\" these"
        " items.\n" );
      new_case->add_adjective( current_store->colour );
      new_case->move( TO );
      new_case->reset_get();
      new_case->add_extra_look( TO );
      used_colours += ({ current_store->colour });
      cases += ([ new_case: temp ]);
      all_new_cases += ({ new_case });
    }
    //A hook for later on (if you want to put in a nifty message)
    if ( sizeof( all_new_cases ) )
      TO->add_new_case( all_new_cases );
  }

  //Lots which require a state change
  foreach( temp_lot in ( filter( lots, (: $1->expiration_time < time() :) ) ) ) {
    TCTP( "Looking at lot %d. ", temp_lot->case_code );
    TCTP( "Status is: %s\n", temp_lot->status );
    switch( temp_lot->status ) {
      case OPEN: //Switching to another state
      TCTP( "In open %s", "\n" );
        //Woo. The bidding on this item is done. Did someone grab it?
        //If so, let the buyer know someone got it.
        //Otherwise let the seller know that they can pick it up
        //Change state appropriately.
        //There are some situations where its neccessary to look up the inv string
        current_store = temp_lot->assoc_store;

        //Before we start, lets get the box in the room out of the way, we'll put a
        //call in here in case someone wants to use a funky message.
        exp_cases = filter( cases, (: $2 == $(temp_lot)->case_code :) );
        map( exp_cases, (: TO->remove_lot( $1 ) :) );

        //First lets check if its being automatically handled, if it is
        //we can let the code know, it should look after the result instantly
        //so we can close it. We have to return the objects at the same time.
        //This could be tricky.
        if ( sizeof( temp_lot->auto_bids ) ) {
          //Recover objects first.
          obs = recover_lot( temp_lot->lot_autoload );

          //Make the call back
          call_other( temp_lot->auto_bids[1], temp_lot->auto_bids[0],
          temp_lot->case_code, stringp( temp_lot->current_bid[ AUCTION_PLAYER_NAME ] ),
          temp_lot->current_bid[ AUCTION_PLAYER_NAME ],
          temp_lot->current_bid[ AUCTION_PLAYER_BID ], obs );

          //Ok, assuming that worked, the objects are recovered and the other
         //object has done what it was supposed to do with them, this means
          //we can close this lot.
          temp_lot->status = CLOSED;
          temp_lot->expiration_time = time() + ( 2 * 60 * 60 );

          //Yes, we aren't processing here anymore. The other object is
          //responsible for letting the players know.
          continue;
        }

        if ( stringp( name = temp_lot->current_bid[ AUCTION_PLAYER_NAME ] ) ) {
          //Someone got it!
          //Lets find out what they've won.
          if ( "/secure/login"->test_user( name ) ) {
            AUTO_MAILER->auto_mail( name, shop_name, "Your successful purchase!",
            "","Congratulations! You have successfully purchased "+
            current_store->inv_string +" with a bid of "
            + MONEY_HAND->money_value_string( temp_lot->current_bid[ AUCTION_PLAYER_BID ],
            currency )+ ".\n\nYou have one week to collect your items before they are "
            "forfeit.\n", 0, 0 );
          }
          temp_lot->status = WAIT_BUYER;
          temp_lot->expiration_time = time() + ( 7 * 24 * 60 * 60 );
          continue;
        }

        //We want to drop down through WAIT_BUYER_LAPSE if there was no buyer initially.

        case WAIT_BUYER_LAPSE:
        //No one got it. Mail seller.
        name = temp_lot->seller;

        if ( "/secure/login"->test_user( name ) ) {
          AUTO_MAILER->auto_mail( name, shop_name, "Your unsuccessful sale!",
          "", "Dear "+ capitalize( name ) +",\n\nIt is with some regret that I inform you "
          "that we were unable to sell " + current_store->inv_string +
          ".\n\nYou have one week to collect your items before they are forfeit.\n",
          0, 0 );
        }
        temp_lot->status = WAIT_SELLER;
        temp_lot->expiration_time = time() + ( 7 * 24 * 60 * 60 );

        continue;

      case WAIT_SELLER: //Free object
        name = temp_lot->seller;
        if ( LOGIN_OBJ->test_user( name ) ) {
          AUTO_MAILER->auto_mail( name, shop_name, "Your unsuccessful sale!",
          "", "Dear "+ name +",\n\nAs you have not collected your items within "
          "7 days, they have been disposed of.\n\nHave a nice day.\n",
         0, 0 );
        }
        temp_lot->status = CLOSED;
        temp_lot->expiration_time = time() + ( 2 * 60 * 60 );
        continue;

    case WAIT_BUYER: //Drop to next bidder

      name = temp_lot->current_bid[ AUCTION_PLAYER_NAME ];
      if ( LOGIN_OBJ->test_user( name ) ) {
        AUTO_MAILER->auto_mail( name, shop_name, "Your successful purchase!",
        "","Dear " + name +",\nBecause you have not picked up your items, "+
        "they have been sold to another client.\n\nHave a nice day.", 0, 0 );
      }

      map_delete( temp_lot->bids, name );

      if ( sizeof( temp_lot->bids ) == 0 ) {
        //there are no other bids, lets go to WAIT_BUYER_LAPSE
        temp_lot->status = WAIT_BUYER_LAPSE;
        temp_lot->expiration_time = time() + ( 2 * 60 * 60 ); //2 hrs
        continue;
      }

      //Sort all the remaining bids, pick the best one, mail them and reset the
      //expiration time.
      bids = sort_array( values( temp_lot->bids ), -1 );

      TCTP( "bids is %O.\n", bids );
      name = filter( temp_lot->bids, (: $2 == $(bids[0]) :) );

      //Now the name of the next best bidder should be kept in name,
      //and their bid is in bids[0]
      temp_lot->current_bid[ AUCTION_PLAYER_NAME ] = name;
      temp_lot->current_bid[ AUCTION_PLAYER_BID ] = bids[0];

      if ( LOGIN_OBJ->test_user( name ) ) {
        AUTO_MAILER->auto_mail( name, shop_name, "Your successful purchase!",
        "","Congratulations! You have successfully purchased "+
        current_store->inv_string +" with a bid of "
        + MONEY_HAND->money_value_string( temp_lot->current_bid[ AUCTION_PLAYER_BID ],
        currency )+ ".\n\nYou have one week to collect your items before they are "
        "forfeit.\n", 0, 0 );
      }
      temp_lot->status = WAIT_BUYER;
      temp_lot->expiration_time = time() + ( 7 * 24 * 60 * 60 );
      continue;

    case WAIT_CRE_INTERVENTION: //Lots waiting cre intervention
      log_file("REAS", "%s: Lot %d is still waiting for manual intervention!\n",
        ctime( time() ), temp_lot->case_code );
      temp_lot->expiration_time = time() + ( 7 * 24 * 60 * 60 );
      continue;

      case CLOSED: //Discard lot class also discard store class
        TCTP( "In closed %s", "" );
        lots -= ({ temp_lot }); //Remove the lot array.
        log_file( "REAS", "%s: Closed lot %d\n", ctime( time() ), temp_lot->case_code );
        continue;
    }
  }

  //Finally finished processing.. hopefully we haven't over evalled yet.
  call_out( "lot_check", CHECK_CYCLE );
  return ;
}

int do_deposit( object *things, int auction_time, string time_type, string res_price ) {
  mixed *auto_load_string;
  c_lot temp;
  c_store temp2;
  int value;
  int finishtime;

 if ( auction_time <= 0 || ( time_type == "day" && auction_time > 10 )
    || ( time_type == "minute" && auction_time > 59 ) ||
    ( time_type == "hour" && auction_time > 23 ) ) {
      TP->add_failed_mess( TO, "That's not a valid length.\n" );
      return 0;
  }

  if ( sizeof( res_price ) ) {
   value = MONEY_HAND->value_from_string( res_price, currency );

    if ( value == 0 ) {
      TP->add_failed_mess( TO, res_price +" isn't a valid reserve price.\n" );
      return 0;
    }
  }

 if ( !sizeof( COLOURS - used_colours ) ) {
    TP->add_failed_mess( TO, "The auction house "
      "doesn't have any display cases left to auction your item.\n" );
    return 0;
  }

  switch( time_type ) {
    case "minute":
      if ( auction_time < 5 ) {
        TP->add_failed_mess( TO,
          "Auctions must go for at least 5 minutes.\n" );
        return 0;
      }
      finishtime = time() + ( auction_time * 60 );
      break;
    case "hour":
       finishtime = time() + ( auction_time * 60 * 60 );
       break;
    case "day":
      if ( auction_time > 14 ) {
        TP->add_failed_mess( TO,
          "Auction can not go for longer then two weeks.\n" );
        return 0;
      }
      finishtime = time() + ( auction_time * 60 * 60 * 24 );
      break;
    default:
       return 0;
 }

  foreach( object tmp in things ) {
    if ( base_name( tmp ) == "/obj/money.c" ) {
      //Argh! Money! Scream and die.
      TP->add_failed_mess( TP, "You can't auction money.\n" );
      things->move( TP, "" );
      filter( things, (: ENV( $1 ) != TP :) )->
        move( ENV( TP ),  "$N falls to the floor!\n" );
      return 0;
    }
  }

  //Work out the new case ID;
  lot_count ++;

  //Generate the case info
  temp2 = generate_store( things, lot_count );

  //Store and destroy objects
  auto_load_string = generate_auto_load( things );

  if ( !arrayp( auto_load_string ) ) {
    //Something went wrong! Scream and die.
    TP->add_failed_mess( TP, "You can't auction that.\n" );
    things->move( TP, "" );
    filter( things, (: ENV( $1 ) != TP :) )->
      move( ENV( TP ),  "$N falls to the floor!\n" );
    return 0;
 }

  temp = new( c_lot, assoc_store: temp2, case_code: lot_count, seller: TP->query_name(),
    status: OPEN, expiration_time: finishtime, reserve_price: value,
    bids: ([ ]), current_bid: allocate( 2 ), lot_autoload: auto_load_string,
    auto_bids: ({ }), notes: "", excluded: ({ }) );

  lots += ({ temp });

 if ( strlen( res_price ) )
    TP->add_succeeded_mess( TO, "$N $V "+
    temp2->inv_string + " for "+ add_a( query_num( auction_time, 5000 ) ) +
    " " + time_type + " auction, with a reserve price of "+
      MONEY_HAND->money_value_string( value, currency ) +".\n" );
  else
    TP->add_succeeded_mess( TO, "$N $V "+
    temp2->inv_string +" for a "+ query_num( auction_time, 5000 ) +
    " " + time_type + " auction, with no reserve price.\n" );

    TCTP( "Generated lot %d.\n", lot_count );
    return 1;

}

int do_list() {
c_lot *_lots;
c_lot _lot;

  if ( !sizeof( cases ) ) {
    write( "There is nothing up for auction in this store.\n" );
    return 1;
  }

  write( "Items currently for auction:\n" );
  foreach( object _case in keys( cases ) ) {
    _lots = filter( lots, (: $1->case_code == $( cases[ _case ] ) :) );
    if ( !sizeof( _lots ) ) continue;
    _lot = _lots[0];

    tell_object( TP, "    " +
      capitalize( _lot->assoc_store->colour + " case" ) + ": " +
      GECM( _lot->assoc_store->inv_string ) + ".\n" );
  }
  return 1;
}

/**
 * @ignore
 * This function is meant to be masked, but remember to call it
 * otherwise your cases will never disappear.
 */
void remove_lot( object ob ) {

  if ( member_array( ob, keys( cases ) ) == -1 )
    return;
  map_delete( cases, ob );
  ob->dest_me();
  return;
}

/**
 * Basic add command function.. lets you bid on stuff
 */
int do_bid( string offer, object *boxes ) {

//Step one, work out what they are bidding on.
c_lot temp;
c_lot *temps;
c_store temp2;
object box;
int value;

 if ( sizeof( boxes ) > 1 ) {
    TP->add_failed_mess( TO, "You can only $V on one case at a time.\n" );
    return 0;
  }

  box = boxes[0];

  if ( member_array( box, keys( cases ) ) == -1 ) {
    TP->add_failed_mess( TO, "$I isn't being auctioned here.\n", ({ box }) );
    return 0;
  }

  temps = filter_array( lots, (: $1->case_code == cases[ $(box) ] :) );

  //We will need the bid info now.. the store info isn't needed if the lot
  //has been closed.. so lets return 1; if thats the case..

  temp = temps[0];
  temp2 = temp->assoc_store;

  if ( temp->status != OPEN ) {
    TP->add_failed_mess(TO, "The bidding on this item is finished.\n" );
    return 0;
  }

  if ( member_array( TP->query_name(),
       temp->excluded ) != -1 ) {
    write( "You have been excluded from bidding on this object.\n" );
    return WARNEXCL;
  }

  if ( !classp( temp2 ) ) {
    log_file( "REAS", "%s: Open lot without store! Lot code: %d.\n",
      ctime( time() ), temp->case_code );
    write( "Something has gone wrong. Please fetch a liaison post haste!\n" );
    printf( "Your lot code is: %d.\n", temp->case_code );
    temp->status = WAIT_CRE_INTERVENTION;
    temp->expiration_time = time() + ( 7 * 24 * 60 * 60 );
    TP->add_succeeded_mess( TO, "" );
    return 1;
  }

  value = MONEY_HAND->value_from_string( offer, currency );

  if ( value == 0 ) {
        TP->add_failed_mess( TO, offer +" isn't worth anything here.\n" );
        return 0;
  }

 if ( TP->query_value_in( currency ) < value ) {
   TP->add_failed_mess( TO, "You don't have that much.\n" );
   return 0;
 }

 if ( temp->reserve_price != 0 && value < temp->reserve_price ) {
   TP->add_failed_mess( TO, "The reserve price for this lot is "+
     MONEY_HAND->money_value_string( temp->reserve_price, currency ) +".\n" );
     return 0;
 }

  if ( value < 400 ) {
   TP->add_failed_mess( TO, "You must bid at least "+
     MONEY_HAND->money_value_string( 400, currency ) + ".\n" );
     return 0;
 }


 if ( sizeof( temp->current_bid ) &&
   temp->current_bid[ AUCTION_PLAYER_BID ] >= value ) {
   TP->add_failed_mess(TO, "Someone else has already bid more than that.\n");
   return 0;
 }

 if ( sizeof( temp->current_bid ) &&
   ( ( value - temp->current_bid[ AUCTION_PLAYER_BID ] ) <
     ( temp->current_bid[ AUCTION_PLAYER_BID ] / 20 ) ) ) {
     TP->add_failed_mess( TO, "You must bid 5% "
     "more then the current bid.\n" );
   return 0;
 }

 temp->bids[ TP->query_name() ] = value;
 temp->current_bid[0] = TP->query_name();
 temp->current_bid[1] = value;

 TP->add_succeeded_mess(TO, "$N $V "+ offer +" for "+ temp2->inv_string +".\n" );
 return 1;
}

/**
 * This function will be a bit horrible, but it is a nicer way of doing it
 * then keeping the objects around.
 * This function uses Terano's cheap and dirty parser (All rights reserved).
 * To be added - plural support! (using query_plural)
 */
int do_browse( object *boxes, string target, int identifier ) {

object box;
c_store container;
c_item temp;
mapping contents = ([ ]); //A list of all things in the box
string *names = ({ });
mixed *longadj = ({ });
string temp2;
mixed *contenders;
string *contender;
string *adjectives;
string name;
string word;
int keep_flag;

 if ( sizeof( boxes ) > 1 ) {
    TP->add_failed_mess( TO, "You can only $V one case at a time.\n" );
    return 0;
  }

  box = boxes[0];

 if ( member_array( box, keys( cases ) ) == -1 ) {
    TP->add_failed_mess( TO, "$I isn't being auctioned here.\n", ({ box }) );
    return 0;
  }

  container = filter( lots, (: $1->case_code == cases[ $(box) ] :) )[ 0 ]->assoc_store;
//TCTP( "Container: %O", container );
  TCTP( "The case code for this case is: %d.\n", container->case_code );
  //Go through the inventory of the array

  foreach( temp in container->inventory ) {
    //Compile a list of what it wants to be called.
    names = temp->alias + ({ temp->name });

    //There are some objects with aliases the same as the name
    //ie: bottle and bottle :P
    names = uniq_array( names );

    //Work out what it looks like.
    longadj = ({ temp->long + temp->read_mess +
      ( TP->query_see_octarine() ? temp->enchant_mess : "" ),
      temp->adjectives });

    //Ok, we have a nice list of all the names of this item
    foreach( temp2 in names ) {
    //TCTP( "Adding: %O\n", temp2 );
      if ( arrayp( contents[ temp2 ] ) )
        contents[ temp2 ] += ({ longadj });
      else
        contents[ temp2 ] = ({ longadj });
    }
  }

  //TCTP( "Object list: %O", contents );

 //Seeing if the string is one word, "bing".. or two words.. "blue bing".
  adjectives = explode( target, " " );

 //The name will be the bit at the end. The rest will be describing words.
    name = adjectives[ sizeof( adjectives ) - 1 ];
    adjectives -= ({ name });

  TCTP( "Search Name: %s ", name );
  TCTP( "Search Adj: %O.\n", adjectives );

  if ( !arrayp( contents[ name ] ) ) {
    TP->add_failed_mess( TO,
      "There is nothing like that in the case.\n" );
    return 0;
 }

  //Our matches! Let's strip down a level of complexity here to
  //avoid evilness.
  contenders = contents[ name ];
//TCTP( "Matches: %O\n", contenders );

  if ( sizeof( contenders ) == 1 ) {
    //That was easy. Theres only one of them about.
    contender = contenders[0];
    TP->add_succeeded_mess( TP, "$N $V "+ target +" in $I.\n", ({ box }) );
    call_out( (: tell_object( TP, $(GECM( contender[0]) ) ) :) );
    return 1;
  }

  //Ok, we've got more then one. If they gave us a number, we can use that.
  //Otherwise its fuzzy matching time. If they didn't give us any
  //adjectives to try and parse with, scream and die.
  if ( identifier != 0 ) {
    if ( identifier > sizeof( contenders ) ) {
     TP->add_failed_mess( TP,
        "There are only " + sizeof( contenders ) +
        " " + pluralize( target ) + " in $I.\n", ({ box }) );
       return 0;
      }
    TP->add_succeeded_mess( TP,
      "$N $V "+ add_a( target ) +" in $I.\n", ({ box }) );
    call_out( (: tell_object( TP,
      GECM( $(contenders[ identifier - 1 ][0]) ) ) :), 0 );
    return 1;
  }

  if ( !sizeof( adjectives ) ) {
    TP->add_failed_mess( TO,
      "There are "+ sizeof( contenders ) +" objects like that in the case.\n" );
    return 0;
 }

  //Ok, this bit is really going to suck.
  //Lets go through our list of contenders, and see how many we can find
  //with these descriptive words as adjectives.
  foreach ( contender in contenders ) {
    keep_flag = 0;
    foreach( word in contender[ 1 ] ) {
      if ( member_array( word, adjectives ) != -1 )
        //Mark it as one to keep.
        keep_flag = 0;
      continue;
    }
    //If keep_flag isn't set, dump it
    if ( !keep_flag )
      contenders -= ({ contender });
    continue;
  }

//TCTP( "Contenders 2: %O\n", contenders );

  if ( !sizeof( contenders ) ) {
    //Argh, after all that, we disqualified everything! Bloody players.
    TP->add_failed_mess( TO,
      "There is nothing matching "+ target +" in the case.\n" );
    return 0;
  }

  if ( sizeof( contenders ) > 1 ) {
     //Ok, there are still too many, scream and die.
     TP->add_failed_mess( TO,
       "There are " + sizeof( contenders ) + " items like that in the case. "
       "Please specify which one you want to browse.\n" );
     return 0;
  }

  //Woohoo! We found it!
  contender = contenders[0];
  TP->add_succeeded_mess( TP,
    "$N peruse "+ add_a( target ) +" in $I.\n", ({ box }) );
  call_out( (: tell_object( TP, GECM( $(contender[0]) ) ) :), 0 );

  return 1;
}

void adjust_money( int amount, object player ) {
    object money;

    if ( amount < 0 ) { //Taking money
        player->pay_money(MONEY_HAND->create_money_array(-amount, currency ));
        return;
    }
    money = MONEY_HAND->create_money_array( amount, currency );
    player->adjust_money( money, currency );
}

void load_file() {
    if ( !stringp( location ) ) return;
    if ( file_size( location +".o" ) < 0 ) return;
    unguarded( (: restore_object, location :) );
    return;
}

void save_file() {
    if ( location == "unset" ) return;
    unguarded( (: save_object, location :) );
    return;
}

void set_shop_name( string _name ) { shop_name = _name; }
void set_save_path( string path ) { location = path; }
void set_currency( string cur ) { currency = cur; }
void set_admin_cost( int value ) { admin_cost = value; }
void set_commission( int percent ) { commission = percent/100.0; }
mapping query_payments() { return payments; }

void dest_me() {
    save_file();
    if ( sizeof( cases ) ) keys( cases )->dest_me();
    ::dest_me();
}

mixed recover_lot( mixed lot_autoload ) {

  object *boxes;
  object *stuff;
  boxes = load_auto_load_to_array( lot_autoload, TP );

  if ( !objectp( boxes[0] ) ) {
    log_file( "REAS", "%s: Could not recover: %O.\n", ctime( time() ),
      lot_autoload );
    return ERRNORECV;
  }

  stuff = INV( boxes[ 0 ] ); //All that should be in this array is a box

  if ( !sizeof( stuff ) ) {
    log_file( "REAS", "%s: Recovered case as empty: %O.\n", ctime( time() ),
      lot_autoload );
    return ERRRECVEMP;
  }

  //5 seconds to deal with inventory of boxes. Lets be generous.
  call_out( (: $(boxes)->dest_me() :), 5 );
  return stuff;

}

/**
 * Withdraw an item from bidding
 */
int do_withdraw( object *boxes ) {

object box;
c_lot *_lots;
object *obs;

  if ( sizeof( boxes ) > 1  ) {
    TP->add_failed_mess( TO, "You can only $V on one case at a time.\n" );
      return 0;
  }

  box = boxes[0];

  if ( member_array( box, keys( cases ) ) == -1 ) {
    TP->add_failed_mess( TO, "$I isn't being auctioned here.\n", boxes );
    return 0;
  }

  _lots = filter( lots, (: $1->case_code == cases[ $(box) ] :) );

  if ( TP->query_name() != _lots[0]->seller && !creatorp(TP) ) {
     TP->add_failed_mess( TP, "This isn't your "
       "lot to withdraw!\n" );
     return 0;
  }

  //Close and wrap up in 2 hours
  _lots[0]->status = CLOSED;
  _lots[0]->expiration_time = time() + ( 2 * 60 * 60 );

  obs = recover_lot( _lots[0]->lot_autoload );

  if ( !arrayp( obs ) ) {
    write( "Something has gone wrong. Please fetch a liaison post haste!\n" );
    printf( "Your lot code is: %d.\n", _lots[0]->case_code );
    _lots[0]->status = WAIT_CRE_INTERVENTION;
    _lots[0]->expiration_time = time() + ( 7 * 24 * 60 * 60 );
    TP->add_succeeded_mess( TO, "" );
    return 1;
  }

  obs->move( TP, "You collect $N." );
  filter( obs, (: ENV( $1 ) != TP :) )->
    move( ENV( TP ), "$N falls to the floor!\n" );

  //Avoid problems with listing later on.
  TO->remove_lot( box );
  TP->add_succeeded_mess( TO, "" );
  return 1;
}

int do_describe( object *boxes, string int_desc ) {
    object box;
    c_lot *_lots;
    c_lot  _lot;
    int code;

    if ( sizeof( boxes ) > 1 ) {
        TP->add_failed_mess( TO, "You can only $V on one case at a time.\n" );
        return 0;
    }

    box = boxes[0];

    if ( member_array( box, keys( cases ) ) == -1 ) {
        TP->add_failed_mess( TO, "$I isn't being auctioned here.\n",
          ({ box }) );
        return 0;
    }

    code = cases[ box ];

    _lots = filter( lots, (: $1->case_code == $(code) :) );

    if ( sizeof( _lots ) != 1 ) {
        printf( "Please inform a creator, there are %d records to "
          "match this case.\n", sizeof( _lots ) );
        printf( "Your lot code is: %d.\n", code );
        TP->add_succeeded_mess( TO, "" );
        return 1;
    }

    _lot = _lots[0];

    if ( TP->query_name() != _lot->seller && !creatorp(TP) ) {
        TP->add_failed_mess( TP, "This isn't your "
          "lot to describe!\n" );
        return 0;
    }

    _lot->notes = int_desc;
    printf( "You neatly letter %s on the case.\n", int_desc );
    TP->add_succeeded_mess( TO, "" );
    return 1;
}

string extra_look( object ob ) {
    c_lot temp, *temp2;
    mixed bid_info;
    string ret;
    int code;

    if ( member_array( ob, keys( cases ) ) == -1 ) return "";

    code = cases[ ob ];
    temp2 = filter( lots, (: $1->case_code == $(code) :) );

    if ( sizeof( temp2 ) != 1 ) return sizeof( temp2 ) +" found in lot array!\n";

    temp = temp2[0];

    bid_info = temp->current_bid;

    ret = "";

    if ( !stringp( bid_info[ AUCTION_PLAYER_NAME ] ) ) {
        if ( temp->reserve_price ) {
          ret += "Reserve price is: ";
          ret += MONEY_HAND->money_value_string( temp->reserve_price, currency );
          ret += ".\n";
        }
        else
            ret += "No bid as of yet.\n";
    }
    else
      ret += "The current bid is "+ MONEY_HAND->money_value_string(
        bid_info[1], currency ) + ", made by "+ capitalize(
        bid_info[ AUCTION_PLAYER_NAME ] ) +".\n";

    ret += "The bidding on this lot stops at "+ mudtime( temp->expiration_time )+
      ".\n";

    if ( sizeof( temp->notes ) ) {
      ret += "Neatly lettered on the case is: ";
      ret += temp->notes;
      ret += ".\n";
    }
    return ret;
}

int do_collect( string pattern ) {
    int amount;
    c_lot _lot, *_lots = ({ }), *_exp_lots;
    object *items = ({ });

    //All lots that aren't OPEN, CLOSED or WAITing for a cre.
    _exp_lots = filter( lots, (: ((c_lot)$1)->status != OPEN :) );
    _exp_lots = filter( _exp_lots, (: ((c_lot)$1)->status != CLOSED :) );
    _exp_lots = filter( _exp_lots, (: ((c_lot)$1)->status != WAIT_CRE_INTERVENTION :) );

    if ( pattern == "all" ) {
        do_collect( "money" );
        do_collect( "successful bids" );
        do_collect( "expired lots" );
        return 1;
    }

    if ( pattern == "money" ) {
      _lots = filter( lots, (: ( $1->seller == $2 ) &&
        ( stringp( $1->current_bid[ AUCTION_PLAYER_NAME ] ) ) :),
        TP->query_name() );

      if ( undefinedp( payments[ TP->query_name() ] ) ) {
        if ( sizeof( _lots ) ) {
          foreach( c_lot tempy in _lots ) {
            write( capitalize( tempy->current_bid[ AUCTION_PLAYER_NAME ] ) +
              " must pay for the items they bid on before you can collect "
              "the money for them! They have until "+ mudtime( tempy->expiration_time )+".\n" );
            }
       }
      }

      if ( undefinedp( payments[ TP->query_name() ] ) ) {
        write( "You aren't owed any money!\n" );
        return 0;
      }

      amount = payments[ TP->query_name() ];
      adjust_money( amount - to_int( amount * commission ), TP );

      printf( "You recieve %s, minus %s commission.\n",
        MONEY_HAND->money_value_string( amount, currency ),
        MONEY_HAND->money_value_string( to_int( amount * commission ),
        currency ) );

      map_delete( payments, TP->query_name() );

      TP->add_succeeded_mess( TO, "$N $V some money from $D.\n" );
      save_file();
      return 1;
    }

    if ( pattern == "successful bids" ) {
        //Items that have expired with the player as the current bid,
        _lots = filter( _exp_lots,
          (: $1->current_bid[ AUCTION_PLAYER_NAME ] == $2 :),
          TP->query_name() );

        if ( !sizeof( _lots ) ) {
            write( "You aren't expecting any bids!\n" );
            return 0;
        }

        foreach( _lot in _lots )
          amount += _lot->current_bid[ 1 ];

        if ( TP->query_value_in( currency ) < amount ) {
            printf( "You have %d %s waiting, for a total cost of %s.\n"
              "You don't have enough money.\n",
              sizeof( _lots ),
              sizeof( _lots ) > 1 ? "lots" : "lot",
              MONEY_HAND->money_value_string( amount, currency ) );
            TP->add_failed_mess( TO, "" );
            return 0;
        }

        adjust_money( -amount, TP );

        foreach( _lot in _lots ) {
          items += recover_lot( _lot->lot_autoload );

          if ( undefinedp( payments[ _lot->seller ] ) )
            payments[ _lot->seller ] = _lot->current_bid[ AUCTION_PLAYER_BID ];
          else
            payments[ _lot->seller ] += _lot->current_bid[ AUCTION_PLAYER_BID ];

          _lot->status = CLOSED;
          _lot->expiration_time = time() + ( 2 * 60 * 60 ); //2 hrs
        }

        items->move( TP, "You collect $N." );
        filter( items, (: ENV( $1 ) != TP :) )->
          move( ENV( TP ), "$N falls to the floor!\n" );

        printf( "You had %d %s waiting, for a total cost of %s.\nYou "
          "hand over the money.\n", sizeof( _lots ),
          sizeof( _lots ) > 1 ? "lots" : "lot",
          MONEY_HAND->money_value_string( amount, currency ) );

        return 1;
    }

    if ( pattern == "expired lots" ) {
        //Items that didnt sell
        _lots = filter( _exp_lots,
          (: !stringp( $1->current_bid[ AUCTION_PLAYER_NAME ] ) &&
            $1->seller == $2 :), TP->query_name() );

        if ( !sizeof( _lots ) ) {
            TP->add_failed_mess( TO, "You aren't expecting "
              "any items.\n" );
            return 0;
        }

        amount = admin_cost * sizeof( _lots );

        if ( TP->query_value_in( currency ) < amount ) {
            printf( "You have %d %s waiting, for a total administration "
              "cost of %s.\n"
              "You don't have enough money.\n",
              sizeof( _lots ),
              sizeof( _lots ) > 1 ? "lots" : "lot",
              MONEY_HAND->money_value_string( amount, currency ) );
            return 0;
        }

        adjust_money( -amount, TP );

        foreach( _lot in _lots ) {
          items += recover_lot( _lot->lot_autoload );

          if ( undefinedp( payments[ _lot->seller ] ) )
            payments[ _lot->seller ] = _lot->current_bid[ AUCTION_PLAYER_BID ];
          else
            payments[ _lot->seller ] += _lot->current_bid[ AUCTION_PLAYER_BID ];

          _lot->status = CLOSED;
          _lot->expiration_time = time() + ( 2 * 60 * 60 ); //2 hrs
        }

        items->move( TP, "You collect $N." );
        filter( items, (: ENV( $1 ) != TP :) )->
          move( ENV( TP ), "$N falls to the floor!\n" );

        printf( "You had %d %s waiting, for a total administration "
          "cost of %s.\n"
          "You hand over the money.\n",
          sizeof( _lots ), sizeof( _lots ) > 1 ?
          "lots" : "lot",
          MONEY_HAND->money_value_string( amount, currency ) );
        return 1;
    }
}

int do_exclude( object *boxes, string excluded ) {
    object box;
    c_lot *_lots;
    c_lot  _lot;
    int code;
    string *ignored = TP->query_property( "ignoring" );

    if ( sizeof( boxes ) > 1 ) {
        TP->add_failed_mess( TO, "You can only $V people from one case at "
          "a time.\n" );
        return 0;
    }

    box = boxes[0];

    if ( member_array( box, keys( cases ) ) == -1 ) {
        TP->add_failed_mess( TO, "$I isn't being auctioned here.\n",
          ({ box }) );
        return 0;
    }

    code = cases[ box ];

    _lots = filter( lots, (: $1->case_code == $(code) :) );

    if ( sizeof( _lots ) != 1 ) {
        printf( "Please inform a creator, there are %d records to "
          "match this case.\n", sizeof( _lots ) );
        printf( "Your lot code is: %d.\n", code );
        TP->add_succeeded_mess( TO, "" );
        return 1;
    }

    _lot = _lots[0];

    if ( TP->query_name() != _lot->seller && !creatorp(TP) ) {
        TP->add_failed_mess( TP, "This isn't your "
          "lot to exclude people from!\n" );
        return 0;
    }

    if ( excluded == "list" ) {
      if ( !sizeof( _lot->excluded ) )
        write( "No one is being excluded from bidding on this lot.\n" );
      else
        write( query_multiple_short( _lot->excluded ) + " is being excluded from "
          "bidding on this lot.\n" );
      return 1;
    }

    if ( excluded != "ignore list" ) {
      if ( member_array( excluded, _lot->excluded ) != -1 ) {
        write( excluded + " is already excluded from this lot.\n" );
        return 1;
      }
      if ( !LOGIN_OBJ->test_user( excluded ) )
        return notify_fail( excluded +" is not a player here!\n" );
      else  {
        _lot->excluded += ({ excluded });
        _lot->excluded = uniq_array( _lot->excluded );
        write( excluded +" will not be allowed to bid on "+
          query_multiple_short( boxes ) +".\n" );
        return 1;
      }
    }
    if ( !arrayp( ignored ) || !sizeof( ignored ) ) {
      write( "You aren't ignoring anyone!\n" );
      return 1;
    }
    _lot->excluded += ignored;
    _lot->excluded = uniq_array( _lot->excluded );
    write( query_multiple_short( ignored ) + " will not be allowed to bid on "+
      query_multiple_short( boxes ) +".\n"  );
    TP->add_succeeded_mess( TO, "" );
    return 1;

}

int do_unexclude( object *boxes, string excluded ) {
    object box;
    c_lot *_lots;
    c_lot  _lot;
    int code;

    if ( sizeof( boxes ) > 1 ) {
        TP->add_failed_mess( TO, "You can only $V people from one case at "
          "a time.\n" );
        return 0;
    }

    box = boxes[0];

    if ( member_array( box, keys( cases ) ) == -1 ) {
        TP->add_failed_mess( TO, "$I isn't being auctioned here.\n",
          ({ box }) );
        return 0;
    }

    code = cases[ box ];

    _lots = filter( lots, (: $1->case_code == $(code) :) );

    if ( sizeof( _lots ) != 1 ) {
        printf( "Please inform a creator, there are %d records to "
          "match this case.\n", sizeof( _lots ) );
        printf( "Your lot code is: %d.\n", code );
        TP->add_succeeded_mess( TO, "" );
        return 1;
    }

    _lot = _lots[0];

    if ( TP->query_name() != _lot->seller && !creatorp(TP) ) {
        TP->add_failed_mess( TP, "This isn't your "
          "lot to unexclude people from!\n" );
        return 0;
    }

    if ( member_array( excluded, _lot->excluded ) == -1 ) {
      if ( !sizeof( _lot->excluded ) ) {
        write( "No one is excluded from bidding on this case!\n" );
        return 1;
      }
      write( "Only "+ query_multiple_short( _lot->excluded ) +
        ( sizeof( excluded ) == 1 ? " is " : " are " ) +
        " being excluded from bidding on this case!\n" );
      return 1;
    }

    _lot->excluded -= ({ excluded });
    write( capitalize( excluded ) + " is now allowed to bid on this case.\n" );
    TP->add_succeeded_mess( TO, "" );
    return 1;
}

/**
 * @ignore
 */
c_lot find_spec_lot( int pos ) { return lots[ pos ]; }

/**
 * This function generates a string that can be used in any advertising
 * you might want to do, it returns a human friendly string that passes
 * information about the lot. (Specifically - contents, cost and exp time)
 * It takes a lot as an arg.
 */
string generate_advertising_string( c_lot lot ) {
  //Return a string that we can do something with!
  //Something like: "<lot QMS>, currently going for <currency string>, "
  //"but hurry, bidding stops on <time>!"
  string c_string;

  if ( intp( lot->current_bid[ 0 ] ) && ( lot->current_bid[ 0 ] ) )
    c_string = MONEY_HAND->money_value_string( lot->current_bid[ 0 ], currency );
  else
    if ( intp( lot->reserve_price ) && lot->reserve_price )
      c_string = MONEY_HAND->money_value_string( lot->reserve_price, currency );
    else
     c_string = "make an offer";

  if ( c_string == "make an offer" )
    return lot->assoc_store->inv_string + ", " + c_string +
    " but hurry, bidding stops at " + mudtime( lot->expiration_time );

  return lot->assoc_store->inv_string + ", currently going for " + c_string +
    " but hurry, bidding stops at " + mudtime( lot->expiration_time );

}

/**
 * A more usable version of above function, call it and it picks a lot
 * at random and generates a string for it.
 * returns "NULL" if there are no lots.
 * Also returns NULL if the lot chosen isnt open
 */
string generate_random_adv_string() {
c_lot temp;
  if ( sizeof( lots ) ) {
    temp = lots[ random( sizeof( lots ) ) ];
    if ( temp->status != OPEN )
      return WARNNOLOTS;
    else return generate_advertising_string( temp );
  }
  else
    return WARNNOLOTS;
}