dw_fluffos_v2/
dw_fluffos_v2/fluffos-2.9-ds2.05/
dw_fluffos_v2/fluffos-2.9-ds2.05/ChangeLog.old/
dw_fluffos_v2/fluffos-2.9-ds2.05/Win32/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/simuls/
dw_fluffos_v2/fluffos-2.9-ds2.05/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/clone/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/command/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/data/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/etc/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/master/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/log/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/compiler/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/efuns/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/operators/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/u/
dw_fluffos_v2/fluffos-2.9-ds2.05/tmp/
dw_fluffos_v2/fluffos-2.9-ds2.05/windows/
dw_fluffos_v2/lib/
dw_fluffos_v2/lib/binaries/cmds/
dw_fluffos_v2/lib/binaries/cmds/creator/
dw_fluffos_v2/lib/binaries/cmds/living/
dw_fluffos_v2/lib/binaries/cmds/player/
dw_fluffos_v2/lib/binaries/d/admin/obj/
dw_fluffos_v2/lib/binaries/d/liaison/
dw_fluffos_v2/lib/binaries/global/virtual/
dw_fluffos_v2/lib/binaries/global/virtual/setup_compiler/
dw_fluffos_v2/lib/binaries/obj/handlers/autodoc/
dw_fluffos_v2/lib/binaries/obj/handlers/terrain_things/
dw_fluffos_v2/lib/binaries/obj/misc/
dw_fluffos_v2/lib/binaries/obj/misc/buckets/
dw_fluffos_v2/lib/binaries/obj/monster/
dw_fluffos_v2/lib/binaries/obj/reactions/
dw_fluffos_v2/lib/binaries/obj/reagents/
dw_fluffos_v2/lib/binaries/secure/cmds/creator/
dw_fluffos_v2/lib/binaries/secure/master/
dw_fluffos_v2/lib/binaries/std/
dw_fluffos_v2/lib/binaries/std/dom/
dw_fluffos_v2/lib/binaries/std/effects/object/
dw_fluffos_v2/lib/binaries/std/guilds/
dw_fluffos_v2/lib/binaries/std/languages/
dw_fluffos_v2/lib/binaries/std/races/
dw_fluffos_v2/lib/binaries/std/room/
dw_fluffos_v2/lib/binaries/std/room/basic/
dw_fluffos_v2/lib/binaries/std/shops/
dw_fluffos_v2/lib/binaries/std/shops/inherit/
dw_fluffos_v2/lib/binaries/www/
dw_fluffos_v2/lib/cmds/guild-race/
dw_fluffos_v2/lib/cmds/guild-race/crafts/
dw_fluffos_v2/lib/cmds/guild-race/other/
dw_fluffos_v2/lib/cmds/playtester/
dw_fluffos_v2/lib/cmds/playtester/senior/
dw_fluffos_v2/lib/d/admin/
dw_fluffos_v2/lib/d/admin/log/
dw_fluffos_v2/lib/d/admin/mapper/31-10-01/mapmaker/event/
dw_fluffos_v2/lib/d/admin/meetings/
dw_fluffos_v2/lib/d/admin/obj/
dw_fluffos_v2/lib/d/admin/room/we_care/
dw_fluffos_v2/lib/d/admin/save/
dw_fluffos_v2/lib/d/dist/
dw_fluffos_v2/lib/d/dist/mtf/
dw_fluffos_v2/lib/d/dist/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/chars/
dw_fluffos_v2/lib/d/dist/pumpkin/desert/
dw_fluffos_v2/lib/d/dist/pumpkin/gumboot/
dw_fluffos_v2/lib/d/dist/pumpkin/hospital/
dw_fluffos_v2/lib/d/dist/pumpkin/inherit/
dw_fluffos_v2/lib/d/dist/pumpkin/map/
dw_fluffos_v2/lib/d/dist/pumpkin/plain/
dw_fluffos_v2/lib/d/dist/pumpkin/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/save/
dw_fluffos_v2/lib/d/dist/pumpkin/squash/
dw_fluffos_v2/lib/d/dist/pumpkin/terrain/
dw_fluffos_v2/lib/d/dist/pumpkin/woods/
dw_fluffos_v2/lib/d/dist/start/
dw_fluffos_v2/lib/d/learning/TinyTown/buildings/
dw_fluffos_v2/lib/d/learning/TinyTown/map/
dw_fluffos_v2/lib/d/learning/TinyTown/roads/
dw_fluffos_v2/lib/d/learning/add_command/
dw_fluffos_v2/lib/d/learning/arms_and_weps/
dw_fluffos_v2/lib/d/learning/chars/
dw_fluffos_v2/lib/d/learning/cutnpaste/
dw_fluffos_v2/lib/d/learning/examples/npcs/
dw_fluffos_v2/lib/d/learning/examples/player_houses/npcs/
dw_fluffos_v2/lib/d/learning/examples/terrain_map/basic/
dw_fluffos_v2/lib/d/learning/functions/
dw_fluffos_v2/lib/d/learning/handlers/
dw_fluffos_v2/lib/d/learning/help_topics/npcs/
dw_fluffos_v2/lib/d/learning/help_topics/objects/
dw_fluffos_v2/lib/d/learning/help_topics/rcs_demo/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/crowd/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/situations/
dw_fluffos_v2/lib/d/learning/items/
dw_fluffos_v2/lib/d/learning/save/
dw_fluffos_v2/lib/d/liaison/
dw_fluffos_v2/lib/d/liaison/NEWBIE/doc/
dw_fluffos_v2/lib/d/liaison/NEWBIE/save/oldlog/
dw_fluffos_v2/lib/db/
dw_fluffos_v2/lib/doc/
dw_fluffos_v2/lib/doc/creator/
dw_fluffos_v2/lib/doc/creator/autodoc/include/reaction/
dw_fluffos_v2/lib/doc/creator/autodoc/include/ritual_system/
dw_fluffos_v2/lib/doc/creator/autodoc/include/talker/
dw_fluffos_v2/lib/doc/creator/autodoc/include/terrain_map/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/baggage/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clock/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clothing/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/cont_save/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/corpse/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/money/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/monster/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/scabbard/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/service_provider/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/state_changer/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/wand/
dw_fluffos_v2/lib/doc/creator/autodoc/std/book_dir/
dw_fluffos_v2/lib/doc/creator/autodoc/std/key/
dw_fluffos_v2/lib/doc/creator/autodoc/std/learning/
dw_fluffos_v2/lib/doc/creator/autodoc/std/map/
dw_fluffos_v2/lib/doc/creator/autodoc/std/race/
dw_fluffos_v2/lib/doc/creator/autodoc/std/weapon_logic/
dw_fluffos_v2/lib/doc/creator/files/
dw_fluffos_v2/lib/doc/creator/policy/
dw_fluffos_v2/lib/doc/creator/room/
dw_fluffos_v2/lib/doc/effects/
dw_fluffos_v2/lib/doc/ideas/
dw_fluffos_v2/lib/doc/known_command/
dw_fluffos_v2/lib/doc/lpc/basic_manual/
dw_fluffos_v2/lib/doc/lpc/intermediate/
dw_fluffos_v2/lib/doc/new/add_command/
dw_fluffos_v2/lib/doc/new/handlers/
dw_fluffos_v2/lib/doc/new/living/
dw_fluffos_v2/lib/doc/new/living/race/
dw_fluffos_v2/lib/doc/new/living/spells/
dw_fluffos_v2/lib/doc/new/player/
dw_fluffos_v2/lib/doc/new/room/guild/
dw_fluffos_v2/lib/doc/new/room/outside/
dw_fluffos_v2/lib/doc/new/room/storeroom/
dw_fluffos_v2/lib/doc/object/
dw_fluffos_v2/lib/doc/playtesters/
dw_fluffos_v2/lib/doc/policy/
dw_fluffos_v2/lib/doc/weapons/
dw_fluffos_v2/lib/global/handlers/
dw_fluffos_v2/lib/global/virtual/setup_compiler/
dw_fluffos_v2/lib/include/
dw_fluffos_v2/lib/include/cmds/
dw_fluffos_v2/lib/include/effects/
dw_fluffos_v2/lib/include/npc/
dw_fluffos_v2/lib/include/shops/
dw_fluffos_v2/lib/net/daemon/chars/
dw_fluffos_v2/lib/net/inherit/
dw_fluffos_v2/lib/net/intermud3/
dw_fluffos_v2/lib/net/intermud3/services/
dw_fluffos_v2/lib/net/obj/
dw_fluffos_v2/lib/net/save/
dw_fluffos_v2/lib/net/smnmp/
dw_fluffos_v2/lib/net/snmp/
dw_fluffos_v2/lib/obj/amulets/
dw_fluffos_v2/lib/obj/b_day/
dw_fluffos_v2/lib/obj/examples/
dw_fluffos_v2/lib/obj/food/alcohol/
dw_fluffos_v2/lib/obj/food/chocolates/
dw_fluffos_v2/lib/obj/food/fruits/
dw_fluffos_v2/lib/obj/food/meat/
dw_fluffos_v2/lib/obj/food/nuts/
dw_fluffos_v2/lib/obj/food/seafood/
dw_fluffos_v2/lib/obj/food/vegetables/
dw_fluffos_v2/lib/obj/fungi/
dw_fluffos_v2/lib/obj/furnitures/artwork/
dw_fluffos_v2/lib/obj/furnitures/bathroom/
dw_fluffos_v2/lib/obj/furnitures/beds/
dw_fluffos_v2/lib/obj/furnitures/cabinets/
dw_fluffos_v2/lib/obj/furnitures/chairs/
dw_fluffos_v2/lib/obj/furnitures/chests/
dw_fluffos_v2/lib/obj/furnitures/clocks/
dw_fluffos_v2/lib/obj/furnitures/crockery/
dw_fluffos_v2/lib/obj/furnitures/cupboards/
dw_fluffos_v2/lib/obj/furnitures/cushions/
dw_fluffos_v2/lib/obj/furnitures/fake_plants/
dw_fluffos_v2/lib/obj/furnitures/lamps/
dw_fluffos_v2/lib/obj/furnitures/mirrors/
dw_fluffos_v2/lib/obj/furnitures/outdoor/
dw_fluffos_v2/lib/obj/furnitures/safes/
dw_fluffos_v2/lib/obj/furnitures/shelves/
dw_fluffos_v2/lib/obj/furnitures/sideboards/
dw_fluffos_v2/lib/obj/furnitures/sofas/
dw_fluffos_v2/lib/obj/furnitures/stoves/
dw_fluffos_v2/lib/obj/furnitures/tables/
dw_fluffos_v2/lib/obj/furnitures/wardrobes/
dw_fluffos_v2/lib/obj/handlers/
dw_fluffos_v2/lib/obj/handlers/autodoc/
dw_fluffos_v2/lib/obj/jewellery/anklets/
dw_fluffos_v2/lib/obj/jewellery/bracelets/
dw_fluffos_v2/lib/obj/jewellery/earrings/
dw_fluffos_v2/lib/obj/jewellery/misc/
dw_fluffos_v2/lib/obj/jewellery/necklaces/
dw_fluffos_v2/lib/obj/jewellery/rings/
dw_fluffos_v2/lib/obj/media/
dw_fluffos_v2/lib/obj/misc/buckets/
dw_fluffos_v2/lib/obj/misc/jars/
dw_fluffos_v2/lib/obj/misc/papers/
dw_fluffos_v2/lib/obj/misc/player_shop/
dw_fluffos_v2/lib/obj/misc/shops/
dw_fluffos_v2/lib/obj/misc/traps/
dw_fluffos_v2/lib/obj/monster/
dw_fluffos_v2/lib/obj/monster/godmother/
dw_fluffos_v2/lib/obj/monster/transport/
dw_fluffos_v2/lib/obj/plants/inherit/
dw_fluffos_v2/lib/obj/potions/
dw_fluffos_v2/lib/open/boards/
dw_fluffos_v2/lib/save/autodoc/
dw_fluffos_v2/lib/save/bank_accounts/
dw_fluffos_v2/lib/save/boards/frog/
dw_fluffos_v2/lib/save/books/bed_catalog/
dw_fluffos_v2/lib/save/creators/
dw_fluffos_v2/lib/save/mail/
dw_fluffos_v2/lib/save/mail/p/
dw_fluffos_v2/lib/save/soul/data/
dw_fluffos_v2/lib/save/tasks/
dw_fluffos_v2/lib/save/vaults/
dw_fluffos_v2/lib/secure/cmds/lord/
dw_fluffos_v2/lib/secure/config/
dw_fluffos_v2/lib/secure/items/
dw_fluffos_v2/lib/secure/player/
dw_fluffos_v2/lib/soul/
dw_fluffos_v2/lib/soul/i/
dw_fluffos_v2/lib/soul/j/
dw_fluffos_v2/lib/soul/k/
dw_fluffos_v2/lib/soul/o/
dw_fluffos_v2/lib/soul/q/
dw_fluffos_v2/lib/soul/to_approve/
dw_fluffos_v2/lib/soul/u/
dw_fluffos_v2/lib/soul/v/
dw_fluffos_v2/lib/soul/wish_list/
dw_fluffos_v2/lib/soul/y/
dw_fluffos_v2/lib/soul/z/
dw_fluffos_v2/lib/std/creator/
dw_fluffos_v2/lib/std/effects/
dw_fluffos_v2/lib/std/effects/attached/
dw_fluffos_v2/lib/std/effects/external/
dw_fluffos_v2/lib/std/effects/fighting/
dw_fluffos_v2/lib/std/effects/other/
dw_fluffos_v2/lib/std/environ/
dw_fluffos_v2/lib/std/guilds/
dw_fluffos_v2/lib/std/hospital/
dw_fluffos_v2/lib/std/house/
dw_fluffos_v2/lib/std/house/onebedhouse/
dw_fluffos_v2/lib/std/house/onebedhut/
dw_fluffos_v2/lib/std/house/tworoomflat/
dw_fluffos_v2/lib/std/languages/
dw_fluffos_v2/lib/std/liquids/
dw_fluffos_v2/lib/std/nationality/
dw_fluffos_v2/lib/std/nationality/accents/
dw_fluffos_v2/lib/std/nationality/accents/national/
dw_fluffos_v2/lib/std/nationality/accents/regional/
dw_fluffos_v2/lib/std/npc/goals/
dw_fluffos_v2/lib/std/npc/goals/basic/
dw_fluffos_v2/lib/std/npc/goals/misc/
dw_fluffos_v2/lib/std/npc/inherit/
dw_fluffos_v2/lib/std/npc/plans/
dw_fluffos_v2/lib/std/npc/plans/basic/
dw_fluffos_v2/lib/std/outsides/
dw_fluffos_v2/lib/std/races/shadows/
dw_fluffos_v2/lib/std/room/basic/topography/
dw_fluffos_v2/lib/std/room/controller/
dw_fluffos_v2/lib/std/room/controller/topography/
dw_fluffos_v2/lib/std/room/furniture/games/
dw_fluffos_v2/lib/std/room/furniture/inherit/
dw_fluffos_v2/lib/std/room/inherit/carriage/
dw_fluffos_v2/lib/std/room/inherit/topography/
dw_fluffos_v2/lib/std/room/punishments/
dw_fluffos_v2/lib/std/room/topography/area/
dw_fluffos_v2/lib/std/room/topography/iroom/
dw_fluffos_v2/lib/std/room/topography/milestone/
dw_fluffos_v2/lib/std/shadows/
dw_fluffos_v2/lib/std/shadows/attached/
dw_fluffos_v2/lib/std/shadows/curses/
dw_fluffos_v2/lib/std/shadows/disease/
dw_fluffos_v2/lib/std/shadows/fighting/
dw_fluffos_v2/lib/std/shadows/room/
dw_fluffos_v2/lib/std/shops/controllers/
dw_fluffos_v2/lib/std/shops/objs/
dw_fluffos_v2/lib/std/shops/player_shop/
dw_fluffos_v2/lib/std/shops/player_shop/office_code/
dw_fluffos_v2/lib/std/socket/
dw_fluffos_v2/lib/www/
dw_fluffos_v2/lib/www/external/autodoc/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/images/
dw_fluffos_v2/lib/www/external/java/telnet/examples/
dw_fluffos_v2/lib/www/external/java/telnet/tools/
dw_fluffos_v2/lib/www/pics/
dw_fluffos_v2/lib/www/secure/creator/
dw_fluffos_v2/lib/www/secure/editors/
dw_fluffos_v2/lib/www/secure/survey_results/
dw_fluffos_v2/win32/
/**
 * The standard inheritable object for player-run shop storerooms.
 * 
 * <p><b>Description</b></p>
 * <p>The storeroom does not directly contain any stock, rather it acts
 * as an interface between the employees and the stock cabinets. A shop
 * may contain a varying number of cabinets between a specified minimum
 * and maximum level. Any cabinets above the minimum are rented for a set
 * fee. 
 * </p>
 * <p>This room contains functions to add items to and remove items from
 * the cabinets, which are assigned a particular item to store. Each
 * cabinet will hold a maximum number of items and the code, therefore,
 * has been designed to be quite flexible.
 * </p>
 * <p>In order to accommodate the _npc shopkeeper_, as well as the
 * newer/lazier employees, the storeroom can automatically assign items to
 * or retrieve items from a cabinet depending on the settings specified by
 * the managers. However, employees can also specify a particular cabinet
 * when adding/removing items or listing the stock. The actions will then
 * take place on that cabinet, as long as it is assigned that item. All
 * additions and removals to the stock are logged. 
 * </p>
 * <p>Specific products can be stored in more than one cabinet, and more
 * than one type of product can be stored in a single cabinet. This ensures
 * maximum flexibility within the stockroom.
 * </p>
 * <p>Bearing in mind that in the old model, the average size of a medium
 * stock file was 650k, the major benefits of multiple stock cabinets are:
 * <ul>
 * <li>Greater efficiency - A maximum of 50 objects are saved at a time,
 * instead of potentially several thousand.</li>
 * <li>Reduction in risk - Less chance that a crash will result in
 * catastrophic loss of stock due to data loss whilst writing.</li>
 * </ul></p>
 * <p>The cabinets are loaded only when needed, and then unloaded a set
 * time later.  If they are needed again during this time, the time to
 * unload is reset.  This means that the disk access is kept to a minumum,
 * whilst also conserving memory (remember, each cabinet - when full - can
 * take up around 50kb).
 * </p>
 * <p>Finally, on a more cosmetic note, a shopping bag dispenser is fitted
 * as standard. Pulling the roll dispenses a bag complete with message. 
 * </p>
 * 
 * @example
 * #include "path.h"
 * 
 * inherit "/std/shops/player_shop/storeroom";
 * 
 * void setup() {
 *    set_light(60);
 *    set_directions( "north", "north", "north" );
 *    set_office( PATH+ "office" );
 * 
 *    set_short( "storeroom of Tarnach's shop" );
 *    set_long( "This is the storeroom of the Creel Springs branch of "
 *        "Tarnach Fendertwin's Quality Consumables.\n" );
 *    add_exit( "north", PATH+ "counter", "door");
 * }
 * 
 * @see /include/player_shop.h
 * @see /std/shops/player_shop/office.c
 * @see /std/shops/player_shop/mgr_office.c
 * @see /std/shops/player_shop/counter.c
 * @see /std/shops/player_shop/shop_front.c
 * @see /std/shops/player_shop/shopkeeper.c
 * @author Ringo
 * @started 1st August 1999
 */
inherit "/std/room/basic_room";

#include <player_shop.h>
#include <move_failures.h>
#include "patterns.h"

int do_list( mixed *, string );
int do_add( object *, mixed * );
int do_remove( mixed * );

private nosave string _office = "", 
_counter = "",
_mgr_office = "",
_shop_front = "",
_office_dir = "", 
_counter_dir = "",
_shop_dir = "";

private nosave object *_cabinets = 0;

private nosave int _num_cabinets, _call_cabs_clear;

int add_cabinet();
private void clear_cabinets();
string directions_to(string);
private int do_add(object *, mixed *);
private int do_list(mixed *, string);
private int do_remove(mixed *);
private void init_cabinets();
private int pull_roll();
int query_num_items(string, int);
string query_office();
object *query_stock(int);
string remove_cabinet();
protected void set_directions(string, string, string);
protected void set_office(string);

/** @ignore yes */
void create()
{
    do_setup++;
    ::create();
    do_setup--;
    add_property("no burial", 1);
    add_property("determinate", "");
    add_item("cabinet", "There are several cabinets in the room, holding "
      "the entire stock of the shop.  If you are authorised to do so, you "
      "may \"list\" the stock, as well as \"add\" and \"remove\" "
      "items from the cabinets.");
    add_item(({"roll", "bag"}), "You could probably \"pull\" a bag off "
      "the roll and give it to a customer with their purchase.\n"
      "Bags should only be handed out with purchases of 10 or more items.");
    if (!do_setup)
    {
        this_object()->setup();
        this_object()->reset();
    }
    add_help_file("player_shop_storeroom");
}
/* create() */


/** @ignore yes */
void init()
{
    ::init();
    if (!_office || _office == "") return;
    add_command("add", ({"<indirect:object:me'item(s)'>", 
        "<indirect:object:me'item(s)'> to cabinet <number'cabinet'>"}),
      (: do_add($1,$4) :));
    add_command("pull", "roll", (: pull_roll() :));
    if (_office->query_employee(this_player()->query_name()) ||
      this_player()->query_creator())
    {
        add_command("list", ({LIST_BLANK, LIST_CABINET,
            LIST_ITEM, LIST_ITEM_CABINET}),
          (: do_list($4,$5) :));
        add_command("remove", ({"<number> <string'item(s)'>", 
            "<number> <string'item(s)'> from cabinet <number'cabinet'>"}),
          (: do_remove($4) :));
    }
    else if (_office->query_retired(this_player()->query_name()))
        add_command("list", ({LIST_BLANK, LIST_CABINET,
            LIST_ITEM, LIST_ITEM_CABINET}), (: do_list($4,$5) :));
}
/* init() */


/** @ignore yes */
int add_cabinet()
{
    object cabinet;
    string cab_name;

    if (previous_object() && previous_object() != find_object(_office))
    {
        LOG_ERROR("storeroom.c", "add_cabinet()");
        return 0;
    }
    if ((_num_cabinets) == MAX_CABINETS) return 0;
    init_cabinets();
    cab_name = "cabinet"+ _num_cabinets++;
    cabinet = clone_object(CABINET);
    cabinet->set_name(cab_name);
    cabinet->set_save_file(_office->query_savedir()+ cab_name);
    _cabinets += ({cabinet});
    return 1;
}
/* add_cabinet() */


/** @ignore yes */
private void clear_cabinets()
{
    if (!_cabinets) return;
#ifdef DEBUG
    tell_creator(CREATOR, "Clearing cabinets.\n");
#endif
    foreach (object cabinet in _cabinets) cabinet->dest_me();
    _cabinets = 0;
}
/* clear_cabinets() */


/** @ignore yes */
void dest_me()
{
    remove_call_out(_call_cabs_clear);
    clear_cabinets();
    ::dest_me();
}
/* dest_me() */


/** @ignore yes */
string directions_to(string place)
{
    if (place == _counter) return copy(_counter_dir);
    if (place == _office) return copy(_office_dir);
    if (place == _shop_front) return copy(_shop_dir);
    return "here";
}
/* directions_to() */


/** @ignore yes */
private int do_add(object *items, mixed *args)
{
    int cab_no = 0;
    object *okay = ({}),
    *failed = ({});

    add_succeeded_mess("");
    if (sizeof(args) > 1)
    {
        cab_no = args[1];
        if (cab_no < 1 || cab_no > _num_cabinets)
        {
            tell_object(this_player(), "That cabinet does not exist!\n");
            return 1;
        }
    }
    init_cabinets();
    foreach (string plural in _office->query_list_array())
    {
        int tot_i, temp_num;
        object *total_inv = ({});
        mixed *test;

        parse_command(plural, items, "%i", test);
        if (!test || !sizeof(test)) continue;
        if (!sizeof(_office->query_cabinet(plural)))
        {
            tell_object(this_player(), "There are no cabinets assigned to "+
              plural+ "!\n");
            return 1;
        }
        foreach (object cabinet in _cabinets)
        total_inv += match_objects_in_environments(plural, cabinet)->objects;
        tot_i = _office->query_max(plural) - sizeof(total_inv);
        if (tot_i < 1)
        {
            tell_object(this_player(),
              "The shop is already fully stocked on "+ plural +".\n");
            test = ({});
            continue;
        }
        test = test[1..];
        if (cab_no)
        {
            int cab_i = STOCK_PER_CABINET - 
            sizeof(all_inventory(_cabinets[cab_no - 1]));

            if (cab_i < 1)
            {
                tell_object(this_player(), "That cabinet is already full.\n");
                return 1;
            }
            if (member_array(cab_no, _office->query_cabinet(plural)) == -1)
            {
                tell_object(this_player(), plural +
                  " do not belong in that cabinet.\n");
                return 1;
            }
            if (sizeof(test) > cab_i)
                tell_object(this_player(), "You cannot add all of the "+ plural +
                  " to cabinet "+ cab_no+ " without exceeding the maximum.\n");
            test = test[0 .. (cab_i - 1)];
        }
        else if (sizeof(test) > tot_i)
        {
            tell_object(this_player(), "You cannot add all of the "+ plural +
              " to the stock without exceeding the maximum.\n");
            test = test[0 .. (tot_i - 1)];
        }      
        okay += test;
        temp_num = sizeof(test);
        if (cab_no)
        {
            object *temp_fail = _cabinets[cab_no - 1]->
            add_items(test, this_player());
            failed += temp_fail;
            temp_num -= sizeof(temp_fail);
        }
        else
        {
            int cab_i;

            foreach(cab_no in _office->query_cabinet(plural))
            {
                object *temp_fail;

                if (!sizeof(test)) break;
                cab_i = STOCK_PER_CABINET - 
                sizeof(all_inventory(_cabinets[cab_no - 1]));
                if (cab_i < 1) continue;
                temp_fail = _cabinets[cab_no - 1]->
                add_items(test[0 .. (cab_i - 1)], this_player());
                failed += temp_fail;
                temp_num -= sizeof(temp_fail);
                test -= test[0 .. (cab_i - 1)];
            }
            if (sizeof(test))
            {
                okay -= test;
                tell_object(this_player(), "There is not enough room in the "
                  "assigned cabinets for "+ query_multiple_short(test)+ ".\n");
                temp_num -= sizeof(test);
            }
            cab_no = 0;
        }
        test = ({});
        _office->adjust_bought(plural, temp_num);
    }     
    okay -= failed;
    if (sizeof(failed))
    {
        tell_room(environment(this_player()), this_player()->query_short()+
          " accidentally drops "+ query_multiple_short(failed)+
          " on the floor.\n", ({this_player()}));
        tell_object(this_player() , "You accidentally drop "+
          query_multiple_short(failed)+ " on the floor.\n");
    }
    if (sizeof(okay))
    {
        _office->shop_log(PURCHASE, this_player()->query_name(),
          this_player()->convert_message(query_multiple_short(okay))+
          " added to stock", UNPAID);
        add_succeeded_mess("$N $V "+ query_multiple_short(okay)+ 
          " to the stock.\n");
    }
    return 1;
}
/* do_add() */


/** @ignore yes */
private int do_list(mixed *args, string pattern)
{
    object *found_items = ({});
    int i = 0;

    add_succeeded_mess("");
    init_cabinets();
    foreach (object cabinet in _cabinets)
    i += sizeof(all_inventory(cabinet));
    if (!i)
    {
        tell_object(this_player(), 
          "There is nothing in stock at the moment.\n");
        return 1;
    }

    /* Plain old full stock list */
    if (pattern == LIST_BLANK)
    {
            string result = sprintf("     Stock of %s\n     As at %s\n\n",
              _office->query_shop_name(), ctime(time()));
            foreach(string key in _office->query_list_array())
            {
                found_items = ({});
                reset_eval_cost();
                found_items += match_objects_in_environments(key, _cabinets)->objects;
                if (sizeof(found_items))
                    result += query_multiple_short( found_items )+ "\n";
            }
        tell_object(this_player(), "$P$Stock list$P$"+ result);
        return 1;
    }

    /* List of stock in specified cabinet */
    if (pattern == LIST_CABINET)
    {
        string result;

        if (args[0] < 1 || args[0] > _num_cabinets)
        {
            tell_object(this_player(), "That cabinet does not exist!\n");
            return 1;
        }
            if (!sizeof(all_inventory(_cabinets[args[0] - 1])))
            {
                result = "There is nothing in that cabinet at the moment.\n";
            }
            else
            {
                result = sprintf("     Stock of cabinet %d\n     As at %s\n\n",
                  args[0], ctime(time()));
                foreach(string key in _office->query_list_array())
                {
                    if (sizeof(found_items = match_objects_in_environments(key,
                          _cabinets[args[0]-1])->objects ))
                    {
                        result += query_multiple_short(found_items)+ "\n";
                    }
                }
            }
        tell_object(this_player(), "$P$Cabinet "+ args[0]+ 
          " stock list$P$"+ result);
        return 1;
    }

    /* Plain old item search */
    if (pattern == LIST_ITEM)
    {
        string result;

        found_items += match_objects_in_environments(args[0], _cabinets)->objects;
        if (!sizeof(found_items))
        {
            tell_object(this_player(),  "There are no "+ args[0]+
              " in stock.\n");
            return 1;
        }
        result = sprintf("     List of %s\n     As at %s\n\n%s", args[0],
          ctime(time()), query_multiple_short(found_items));
        tell_object(this_player(), "$P$List of " + args[0]+ "$P$"+ result);
        return 1;
    }

    /* List of specific items in specified cabinet */
    if (args[1] < 1 || args[1] > _num_cabinets)
    {
        tell_object(this_player(), "That cabinet does not exist!\n");
        return 1;
    }
    if (!sizeof(all_inventory(_cabinets[args[1] - 1])))
    {
        tell_object(this_player(), "There is nothing in that cabinet at "
          "the moment.\n");
        return 1;
    }
    found_items = match_objects_in_environments(args[0],
      _cabinets[args[1]-1])->objects;
    if (!sizeof(found_items))
    {
        tell_object(this_player(), "There are no "+ args[0]+ " in stock.\n");
        return 1;
    }
    tell_object(this_player(), "$P$List of "+ args[0]+ " in cabinet "+
      args[1]+ "$P$"+ sprintf("     List of %s in cabinet %d\n     "
        "As at %s\n\n%s", args[0], args[1], ctime(time()),
        query_multiple_short(found_items)));
    return 1;
}
/* do_list() */


/** @ignore yes */
private int do_remove(mixed *args)
{
    int cab_no = 0;
    object *items = ({}), *failed;

    failed = ({});
    add_succeeded_mess("");
    if (sizeof(args) > 2) cab_no = args[2];
    if (query_num_items( args[1], cab_no ) < args[0])
    {
        tell_object(this_player(), "The stock does not contain "+ 
          args[0] + " "+ args[1]+ " to remove.\n");
        return 1;
    }
    init_cabinets();
    if (!cab_no)
    {
        int number = args[0];

        for(int i = sizeof(_cabinets); i > 0; i--)
        {
            object *stock = match_objects_in_environments(args[1],
              _cabinets[i-1])->objects;
            if (sizeof(stock) > number) stock = stock[ 0 .. (number-1) ];
            items += stock;
            failed += _cabinets[i-1]->remove_items(stock, this_player());
            number -= sizeof(stock);
            if (!number) break;
        }
    }
    else
    {
        items = match_objects_in_environments(args[1],
          _cabinets[cab_no-1])->objects[0 .. (args[0] - 1)];
        failed = _cabinets[cab_no - 1]->remove_items(items, this_player());
    }
    items -= failed;
    if (sizeof(failed))
    {
        tell_room(environment(this_player() ), this_player()->query_short()+
          " accidentally drops "+ query_multiple_short(failed)+
          " on the floor.\n", ({this_player()}));
        tell_object(this_player() , "You accidentally drop "+
          query_multiple_short(failed)+ " on the floor.\n");
    }
    if (find_object(_office->query_shopkeeper()) &&
      this_player() == find_object(_office->query_shopkeeper()))
        _office->query_shopkeeper()->set_failed(sizeof(failed));
    if (sizeof(items))
    {
        _office->shop_log(SALE, this_player()->query_name(),
          this_player()->convert_message(query_multiple_short(items))+
          " removed from stock", UNPAID);
        foreach (string plural in _office->query_list_array())
        {
            object *test = ({});
            parse_command(plural, items, "%i", test);
            if (!test || !sizeof(test)) continue;
            _office->adjust_sold(plural, sizeof(test) - 1);
        } 
        add_succeeded_mess("$N $V "+ query_multiple_short(items)+
          " from the stock.\n");
    }
    return 1;
}
/* do_remove() */


/** @ignore yes */
void event_death(object k, object *o, object k2, string r, string k3)
{
    _office->event_death(k,o,k2,r,k3);
}
/* event_death() */


/** @ignore yes */
void event_enter(object ob, string message, object from)
{
    _office->event_enter(ob, message, from);
}
/* event_enter() */


/** @ignore yes */
string long(string word, int dark)
{
    return sprintf("%sThere are currently %d store cabinets "
      "in the room.\n", ::long(word,dark), _num_cabinets); 
}
/* long() */


/** @ignore yes */
private void init_cabinets()
{
    if (remove_call_out(_call_cabs_clear) == -1 && !_cabinets)
    {
#ifdef DEBUG
        tell_creator(CREATOR, "Initialising cabinets.\n");
#endif
        _cabinets = ({});
        for (int i = 0; i < _num_cabinets; i++)
        {
            string cab_name = "cabinet"+ i;
            object cabinet = clone_object(CABINET);
            cabinet->set_name(cab_name);
            cabinet->set_save_file(_office->query_savedir()+ cab_name);
            _cabinets += ({cabinet});
        }
    }
    _call_cabs_clear = call_out((: clear_cabinets() :), CLEAR_DELAY);
}
/* init_cabinets() */


/** @ignore yes */
private int pull_roll()
{
    object bag;
    string message, day, day2, month;

    bag = clone_object(SHOP_BAG);
    sscanf(amtime(time()), "%*s %s %s %s", day, day2, month);
    if (member_array( month, ({"Offle", "February", "March",
          "April", "May", "June", "Grune", "August", "Spune", "Sektober",
          "Ember", "December", "Ick"}) ) == -1)
        message = sprintf("A very happy %s %s %s\n\nfrom everyone at\n\n%s, %s",
          day, day2, month, _office->query_shop_name(),
          _office->query_place());
    else message = sprintf("With the compliments of\n\n%s, %s.",
          _office->query_shop_name(), _office->query_place());
    bag->set_read_mess(message);
    bag->set_max_cond(400);
    bag->set_cond(400);
    if ((int)bag->move(this_player()) != MOVE_OK)
    {
        bag->move(this_object());
        tell_object(this_player(), 
          "You drop the bag as you're carrying too much.\n");
    }
    add_succeeded_mess("$N $V the roll and $I comes off in $p hand.\n",
      ({bag}) );
    return 1;
}
/* pull_roll() */


/**
 * Query the current number of items in stock.
 * @param item The item to query.
 * @param cabinet The cabinet to look in (0 to look at all stock).
 * @return The number of that item in stock.
 */
int query_num_items(string item, int cabinet)
{
   init_cabinets();
   if (cabinet)
   {
      return sizeof(match_objects_in_environments(item,
         _cabinets[cabinet-1])->objects);
   }
   else
   {
      return sizeof(match_objects_in_environments(item,
         _cabinets)->objects);
   }
}
/* query_num_items() */


/**
 * Query the path to the office.
 * @return The path to the office.
 */
string query_office() { return copy(_office); }


/**
 * Query the current stock.
 * @param cabinet The cabinet to look in (0 to look at all stock).
 * @return The stock.
 */
object *query_stock(int cabinet)
{
    object *items = ({});

    init_cabinets();
    if (cabinet) return copy(all_inventory(_cabinets[cabinet-1]));
    for (int i = 0; i < _num_cabinets; i++)
        items += all_inventory( _cabinets[i] );
    return copy(items);
}
/* query_stock() */


/** @ignore yes */
string remove_cabinet()
{
    object cabinet;

    if (previous_object() && previous_object() != find_object(_office))
    {
        LOG_ERROR("storeroom.c", "remove_cabinet()");
        return "";
    }
    if ((_num_cabinets) == MIN_CABINETS) return "";
    init_cabinets();
    _num_cabinets--;
    cabinet = _cabinets[_num_cabinets];
    _cabinets -= ({cabinet});
    cabinet->move("/room/rubbish");
    return cabinet->query_name();
}
/* remove_cabinet() */


/**
 * Set the directions to other parts of the shop.
 * This function is used by the npc shopkeeper to navigate
 * around the shop, using the exits at the given directions.
 * These directions should be the standard "north", "southeast" etc.
 * @param office The direction to the office.
 * @param counter The direction to the counter.
 * @param shop The direction to the shop front.
 */
protected void set_directions(string office, string counter, string shop)
{
    _office_dir = office;
    _counter_dir = counter;
    _shop_dir = shop;
}
/* set_directions() */


/** @ignore yes */
protected void set_long(string long_desc)
{
    long_desc += "Employees can \"add\" something to, \"remove\" "
    "something from and \"list\" the stock.\nThere is a roll of "
    "shopping bags conveniently located on one wall.\n";
    ::set_long(long_desc);
}
/* set_long() */


/**
 * Set the path of the main office.
 * @param path The full path & filename.
 */
protected void set_office(string path)
{
    _office = path;
    _counter = _office->query_counter();
    _mgr_office = _office->query_mgr_office();
    _shop_front = _office->query_shop_front();
    _num_cabinets = _office->query_num_cabinets();
}
/* set_office() */