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/
/**
 * A printing workshop where players can create their own leaflets.
 * <P>
 * This can be divided up into two rooms, an office (where you pay for the
 * printing to be done) and a collection room (where you do the collection).
 * To enable this behaviour the collection room needs to know about the
 * office.  The office stores all the information, so you call
 * set_office_room(room_path); on the collection room and
 * set_no_collection() on the office.
 * If you want to use a shopkeeper, please use the built-in shopkeeper
 * variable, also don't forget to call set_use_shopkeeper(), which will
 * tell the room to work in shopkeeper mode.
 * @author Sandoz, based on Pinkfish's print shop.
 * @see set_office_room()
 * @see set_no_collection()
 */

#include <language.h>
#include <leaflet.h>
#include <time.h>

#define CM(x)                   TP->convert_message(x)
#define QMS(x)                  CM( query_multiple_short( x, "the") )
#define MSTR(x)                 MONEY_H->money_value_string( x, place )

/** This is the amount of chars that will fit in the largest leaflet. */
#define MAX_CHARS               2000
/** This is the maximum number of copies we can make at a time. */
#define MAX_COPIES              50
/** This is the cost of claiming copyright on a leaflet. */
#define COPYRIGHT_COST          6000
/** This is the default cost per 10 letters. */
#define DEFAULT_LETTER_COST     4
/** This is the base cost of printing a leaflet. */
#define DEFAULT_MATERIAL_COST   50
/** This is the base cost of an order. */
#define DEFAULT_COST_PER_ORDER  2000
/** This is the minimum time it takes to complete an order. */
#define DEFAULT_TIME_TO_COLLECT (2*60*60)
/** This is the minimum amount of time it takes to print one copy. */
#define DEFAULT_TIME_PER_COPY   120
/** This is the time it takes to print 10 letters. */
#define DEFAULT_TIME_PER_LETTER 60

nosave inherit ROOM_OBJ;

nosave object shopkeeper;
nosave function open_func;
nosave mapping translation_costs, discount;
nosave int keeper, letter_cost, material_cost, time_to_collect, time_per_copy;
nosave int no_collect, cur_num, cost_per_order, id;
nosave string default_language, office_room;

/** @ignore yes */
void create() {
    string shop_name, leaf_long;

    translation_costs = ([ ]);
    discount = ([ 1  : 100,
                  5   : 95,
                  10  : 90,
                  20  : 85,
                  50  : 80,
                  100 : 75,
                  ]);

    ::create();
    add_help_file("leaflet_shop");

    if( __FILE__[0..<3] == base_name(TO) )
        return;

    shop_name = query_property("shop_name");
    leaf_long = query_property("leaf_long");

    remove_property("shop_name");
    remove_property("leaf_long");

    if( !shop_name )
        error("No shop name specified.\n");

    if( !leaf_long )
        error("No leaflet long description specified.\n");

    id = LEAFLET_H->add_printer( shop_name, leaf_long );

} /* create() */

/**
 * This method returns the id of the shop.
 * @return our id
 */
int query_print_shop_id() { return id; }

/**
 * This method queries whether or not we are a leaflet shop.
 * This is used by the leaflet handler.
 * @return always return 1
 */
int query_leaflet_shop() { return 1; }

/**
 * This method returns the discount schedule.  There is a default
 * discount schedule setup for printing shops. The discount schedule
 * tells how much of a discount you get for certain numbers of a run.
 * It returns a mapping of the form:
 * <pre>
 * ([ num1 : dis1, num2 : dis2, ... ])
 * </pre>
 * Where each num is the number of items at and above which the discount
 * dis applies.
 * @return the discount schedule
 * @see set_discount_schedule()
 */
mapping query_discount_schedule() { return discount; }

/**
 * Sets the discount schedule for this object.  See the
 * query_discount_schedule help for the format of the mapping.
 * @param value the new discount schedule.
 * @see query_discount_schedule()
 */
void set_discount_schedule( mapping map ) { discount = map; }

/**
 * Sets the office room to which this collection room is associated.  If
 * this is set on a room, you cannot setup print jobs in the room and this
 * room specified here is queried for the information about the jobs to
 * collect.
 * @param room the new office room
 * @see query_office_room()
 * @see set_no_collection()
 */
void set_office_room( string room ) { office_room = room; }

/**
 * Returns the current office room associated with this room.
 * @return the current office room
 * @see set_office_room()
 * @see query_no_collection()
 */
string query_office_room() { return office_room; }

/**
 * This sets the no collection flag.  It makes it so this room cannot be
 * used for collections.  If this is set then there should be an associated
 * collection room used to pick up the books from.  This room should
 * use the set_office_room() function to set the office room to use
 * for the collections.
 * @param collect the new value of no_collections flag
 * @see query_no_collection()
 * @see set_office_room()
 */
void set_no_collection( int collect ) { no_collect = collect; }

/**
 * This returns the no collection flag used by the room.
 * @return the no collection flag
 * @see set_no_collection()
 * @see query_office_room()
 */
int query_no_collection() { return no_collect; }

/**
 * This method sets the function to evaluate to check to see if the shop
 * is open or not.  This should set any error messages which are needed
 * and return 1 for open status or 0 for closed.
 * @param func the open function
 * @see query_open_func()
 * @see do_print()
 * @see do_print_copies()
 * @see do_collect()
 */
void set_open_func( function func ) { open_func = func; }

/**
 * This method returns the function which is used to check for the
 * open status of the shop.
 * @see set_open_func()
 * @return the current open function
 */
function query_open_func() { return open_func; }

/**
 * This method will add the cost to translate from one language to
 * another.  The default is translating to the common language and
 * this cost will be used in both directions.  ie: the cost of translating
 * from djelian to common is the same as translating from common to
 * djelian.  If translating between two languages that are not the
 * default language, say the default is common and we want to translate
 * from djelian to wombat, then the cost from djelian->common and then
 * common->wombat will be used.
 * @param lang the language to set the translation cost of
 * @param cost the cost is in percentage, 200 means twice the price
 * @see set_default_language()
 * @see remove_translation_cost()
 * @see query_all_translation_costs()
 */
void add_translation_cost( string lang, int cost ) {
    translation_costs[lang] = cost;
} /* add_translation_cost() */

/**
 * This method will remove the translation cost for a specific language.
 * @param lang the language to remove the translation cost of
 * @see set_default_language()
 * @see add_translation_cost()
 * @see query_all_translation_costs()
 */
void remove_translation_cost( string lang ) {
    map_delete( translation_costs, lang );
} /* remove_translation_cost() */

/**
 * This method will return a mapping of all the translation costs.
 * The keys are the languages and the values are the costs in terms
 * of percentages.
 * @return the current translation cost mapping
 * @see add_translation_cost()
 * @see remove_translation_cost()
 */
mapping query_all_translantion_costs() { return translation_costs; }

/**
 * This method sets the name of the print shop which will be used on
 * leaflets when they are printed.
 * @param name the name of the print shop
 */
void set_print_shop_name( string name ) { add_property("shop_name", name ); }

/**
 * This method will return the current name of the print shop.
 * @return the name of the print shop
 */
string query_print_shop_name() { return LEAFLET_H->query_printer_name(id); }

/**
 * This method sets the long description for leaflets printed here.
 * If none is set, a default description will be used.
 * Note: $size$ and $shop$ expansion will be done on the string,
 * so if you want the long desc reflect the size of the leaflet,
 * then $size$ will be expanded to "small", "medium sized", "large",
 * "huge", etc., based on the number of characters in the leaflet, and
 * $shop$ will be expanded to the shop name.
 * @param str the long description for leaflets
 * @see query_leaflet_long()
 * @example set_leaflet_long("This $size$ leaflet looks like it has been "
 *              "churned out from one of the cities' printing presses.");
 */
void set_leaflet_long( string str ) { add_property("leaf_long", str ); }

/**
 * This method will return the long description of leaflets
 * printed here.
 * @return the long description of leaflets printed here
 * @see set_leaflet_long()
 */
string query_leaflet_long() { return LEAFLET_H->query_leaflet_long(id); }

/**
 * This method returns the maximum amount of characters
 * printable on a leaflet.
 * @return the maximum amount of characters printable on a leaflet
 */
int query_max_chars() { return MAX_CHARS; }

/**
 * This method sets the cost per order.
 * @param cost the cost per order
 */
int set_cost_per_order( int cost ) {
    if( cost > 0 )
        cost_per_order = cost;
} /* set_cost_per_order() */

/**
 * This method returns the cost per order.
 * @return the cost per order
 */
int query_cost_per_order() {
    return cost_per_order || DEFAULT_COST_PER_ORDER;
} /* query_cost_per_order() */

/**
 * This method tells the room to work in shopkeeper mode.
 * In shopkeeper mode all messages will be spoken through
 * the shopkeeper.
 */
void set_use_shopkeeper() { keeper = 1; }

/**
 * This method queries whether or not we are working in
 * shopkeeper mode.
 * @return 1 if we are in shopkeeper mode, 0 if not
 */
int query_use_shopkeeper() { return keeper; }

/**
 * This queries the cost per 10 letters.
 * @return the cost per letter
 * @see set_letter_cost()
 */
int query_letter_cost() { return letter_cost || DEFAULT_LETTER_COST; }

/**
 * This sets the cost per 10 letters.
 * @param value the new cost per letter
 * @see query_letter_cost()
 */
void set_letter_cost( int value ) { letter_cost = value; }

/**
 * This queries the material cost per leaflet.
 * This will be added to the cost of printing each leaflet.
 * @return the material cost per leaflet
 * @see set_material_cost()
 */
int query_material_cost() { return material_cost || DEFAULT_MATERIAL_COST; }

/**
 * This sets the material cost per leaflet.
 * This will be added to the cost of printing each leaflet.
 * @param value the new material cost per leaflet
 * @see query_material cost_cost()
 */
void set_material_cost( int value ) { material_cost = value; }

/**
 * This queries the minimum time per order.
 * @return the minimum time per order
 * @see set_time_per_order()
 */
int query_time_to_collect() {
    return time_to_collect || DEFAULT_TIME_TO_COLLECT;
} /* query_time_to_collect() */

/**
 * This sets the minimum time per order.
 * @param time the time per order
 * @see query_time_per_order()
 */
void set_time_to_collect( int time ) { time_to_collect = time; }

/**
 * This queries the time it takes to print one copy.
 * @return the minimum time per copy
 * @see set_time_per_copy()
 */
int query_time_per_copy() { return time_per_copy = DEFAULT_TIME_PER_COPY; }

/**
 * This sets the minimum time it takes to print a copy.
 * @param time the time per copy
 * @see query_time_per_copy()
 */
void set_time_per_copy( int time ) { time_per_copy = time; }

/**
 * This method sets the default language to use in the print shop.
 * Anything written in this language will cost nothing extra to
 * duplicate.
 * @param lang the new default language
 * @see query_default_language()
 * @see add_translation_cost()
 * @see check_for_untranslatable_language()
 */
void set_default_language( string lang ) { default_language = lang; }

/**
 * This method will return the current default language for the
 * print shop.
 * @return the current default language
 * @see set_default_language()
 * @see add_translation_cost()
 * @see check_for_untranslatable_language()
 */
string query_default_language() { return default_language || "common"; }

/** @ignore yes */
private int do_open_check() {
    if( keeper && ( !shopkeeper || ENV(shopkeeper) != TO ) ) {
        add_failed_mess("There is no-one here to serve you.\n");
        return 0;
    }

    return !open_func || evaluate( open_func );

} /* do_open_check() */

/** @ignore yes */
void notify_player( string mess ) {
    if( keeper && shopkeeper )
        return shopkeeper->do_command("sayto "+TP->query_name()+" "+mess );

    tell_object( TP, mess+"\n");

} /* notify_player() */

/** @ignore yes */
varargs int add_failed( string mess ) {
    if( keeper && shopkeeper ) {
        shopkeeper->do_command("sayto "+TP->query_name()+" "+mess );
        notify_fail("");
        return 1;
    }

    add_failed_mess( mess+"\n");
    return 0;

} /* add_failed() */

/**
 * Figure out how much this object will cost to make.
 * @param ob the object to price
 * @param num the number of them to print
 * @return the cost of the item
 */
int price_object( object ob, int num, string to_language ) {
    int i, cost, key, multiplier;
    mixed stuff;

    if( num < 1 || !ob || !ob->query_leaflet() )
        return 0;

    if( !sizeof( stuff = ob->query_text() ) )
        return 0;

    i = strlen( stuff[READ_MESS] );

    if( stuff[READ_LANG] != query_default_language() ) {
        cost = translation_costs[ stuff[READ_LANG] ];
        if( !cost )
            cost = 1000;
        i = i * cost / 100;
    }

    if( to_language != query_default_language() ) {
        cost = translation_costs[to_language];
        if( !cost )
            cost = 1000;
        i = i * cost / 100;
    }

    cost = ob->query_value() + i / 10 * query_letter_cost();

    foreach( key in sort_array( keys(discount), 1 ) ) {
        if( num >= key )
            multiplier = discount[key];
        else
            break;
    }

    cost += query_material_cost();

    i = ( cost * num * multiplier ) / 100;

    return query_cost_per_order() + i;

} /* price_object() */

/** @ignore yes */
protected void check_copyright( string str, object *obs, int value ) {
    object ob;
    string place;

    if( !strlen(str) || ( str[0] != 'y' && str[0] != 'Y' ) )
        return notify_player("As you wish.  See you again soon.");

    if( !do_open_check() ) {
        write("The shop seems to have been closed in the meantime, sorry.\n");
        return;
    }

    place = query_property("place") || "default";
    TP->pay_money( MONEY_H->create_money_array( value, place ), place );

    foreach( ob in obs )
        LEAFLET_H->copyright_leaflet( ob->query_leaflet_id(),
            TP->query_name() );

    notify_player("Your copyright request on "+QMS(obs)+" has been "
        "successful.");

} /* check_copyright() */

/**
 * This method sets up the copyright for the objects.  This will check for
 * existing copyright status and then check with the book handler to see
 * if it still fits the criteria.  If it does not then it will add itself
 * as a new book.
 * @param obs the objects to claim copyright on
 */
protected int do_claim( object *obs ) {
    object *bad;
    string place, ret;
    int value, player_money, ident, new_id;
    mapping uniques;

    if( !do_open_check() )
        return 0;

    if( keeper && shopkeeper )
        tell_object( TP, "You enquire about claiming copyright on "+
            QMS(obs)+".\n");

    tell_room( TO, TP->the_short()+" "+verbalize("enquire")+" about "
        "claiming copyright on "+QMS(obs)+".\n", TP );

    bad = filter( obs, (: !$1->query_leaflet() :) );
    if( !sizeof( obs -= bad ) )
        return add_failed( query_multiple_short( bad, "the")+" "+
            verbalize("do")+" not appear to be "+( sizeof(bad) > 1 ?
            "leaflets" : "a leaflet")+".");

    bad = filter( obs, (: $1->query_copyright() :) );
    if( !sizeof( obs -= bad ) )
        return add_failed("I'm afraid "+query_multiple_short( bad, "the")+" "+
            verbalize("have")+" already been copyrighted.");

    uniques = unique_mapping( obs, (: $1->query_leaflet_id() :) );

    foreach( player_money, obs in uniques ) {
        if( sizeof(obs) > 1 )
            ident = 1;
        uniques[player_money] = obs[0];
        if( ( new_id = LEAFLET_H->query_copyright_protected(
            obs[0]->query_text()[READ_MESS] ) ) &&
            LEAFLET_H->query_copyright(new_id) != TP->query_name() ) {
            bad += ({ obs[0] });
            map_delete( uniques, player_money );
            continue;
        }
        value += COPYRIGHT_COST;
    }

    ret = "";

    if( ident )
        ret += "You cannot claim copyright on several identical leaflets";

    if( sizeof(bad) ) {
        if( sizeof(ret) )
            ret += " and ";
        ret += "I'm afraid "+QMS(bad)+" "+verbalize("have")+" already been "
            "copyrighted";
    }

    if( sizeof(ret) )
        notify_player( ret+".");

    place = query_property("place") || "default";
    player_money = (int)TP->query_value_in( place );

    if( place != "default")
        player_money += (int)TP->query_value_in("default");

    obs = values(uniques);
    ret = "It would cost you "+MSTR(value)+" to claim copyright on "+QMS(obs);

    if( player_money >= value ) {
        notify_player( ret+".");
        write("Do you wish to continue [y|n]? ");
        input_to( (: check_copyright :), 0, obs, value );
    } else {
        notify_player( ret+", but you do not have enough money.");
    }

    add_succeeded_mess("");
    return 1;

} /* do_claim() */

/**
 * This adds an object into the current set to be collected,
 * and saves the auto load info for the object.
 * @param name the name of the person adding the run
 * @param ob the object being added
 * @param num the number to be printed
 * @param lang the language to print it in
 * @return the print data class
 * @see do_collect()
 */
private class print_data add_print_run( string name, object ob, int num,
                                        string lang ) {
    class print_data data;
    int new_leaflet;

    if( new_leaflet = ob->query_property("new_leaflet") )
        ob->remove_property("new_leaflet");

    data = new( class print_data,
           id     : id,
           time   : time() + sizeof(ob->query_text()[READ_MESS]) / 10 *
                    DEFAULT_TIME_PER_LETTER + query_time_to_collect() +
                    query_time_per_copy() * num,
           number : num,
           lang   : lang,
           file   : base_name(ob),
           save   : ({ ob->query_static_auto_load(),
                       ob->query_dynamic_auto_load() }),
           new_leaflet : new_leaflet );

    if( new_leaflet )
        ob->dest_me();

    if( !LEAFLET_H->add_print_run( name, data ) )
        return 0;

    return data;

} /* add_print_run() */

/**
 * This is called when the player comes back to collect
 * the leaflet they have printed.
 * @return 1 on success, 0 on failure
 */
protected int do_collect() {
    object ob, office, *obs;
    int printed, i, failed;
    class print_data info, *collectables;
    mixed auto_load;
    mapping move;
    string ret;

    if( !do_open_check() )
        return 0;

    office = ( office_room ? load_object(office_room) : TO );
    collectables = LEAFLET_H->query_print_run( id, TP->query_name() );

    if( keeper && shopkeeper )
        tell_object( TP, "You enquire about collecting some leaflets.\n");

    tell_room( TO, TP->the_short()+" "+verbalize("enquire")+" about "
        "collecting "+verbalize("their", TP->HIS )+" leaflets.\n", TP );

    if( !collectables )
        return add_failed("Sorry, there are no leaflets for you to collect.");

    foreach( info in collectables ) {
        if( time() < info->time ) {
            if( !failed || info->time < failed )
                failed = info->time;
            continue;
        }

        auto_load = info->save;
        ob = clone_object(info->file);

        if( auto_load[0] )
            ob->init_static_arg( auto_load[0] );
        if( auto_load[1] )
            ob->init_dynamic_arg( auto_load[1] );

        auto_load = ob->query_text();

        if( auto_load[READ_LANG] != info->lang ) {
            auto_load[READ_LANG] = info->lang;
            i = LEAFLET_H->new_leaflet( ob->query_author(), auto_load );
            ob->set_leaflet_id(i);
        }

        auto_load = ({ ob->query_static_auto_load(),
                       ob->query_dynamic_auto_load() });

        ob->dest_me(); // Kill the sample.
        LEAFLET_H->remove_print_run( id, TP->query_name(), info );

        obs = ({ });

        for( i = 0; i < info->number; i++ ) {
            ob = clone_object(info->file);
            ob->set_player(TP);
            if( auto_load[0] )
                ob->init_static_arg( auto_load[0] );
            if( auto_load[1] )
                ob->init_dynamic_arg( auto_load[1] );
            obs += ({ ob });
        }

        move = unique_mapping( obs, (: $1->move(TP) != 0 :) );
        ret = "";

        if( sizeof(move[0]) ) {
            if( shopkeeper ) {
                ret = shopkeeper->the_short()+" gives "+
                    query_num(sizeof(move[0]))+" "+( sizeof(move[0]) == 1 ?
                    "copy" : "copies")+" of "+move[0][0]->the_short()+" to "+
                    TP->the_short();
            } else {
                ret = "You receive your "+( sizeof(move[0]) > 1 ?
                    query_num(sizeof(move[0]))+" copies" : "copy")+" of "+
                    move[0][0]->the_short();
            }
        }

        if( sizeof(move[1]) ) {
            move[1]->move(TO);
            if( shopkeeper ) {
                if( !sizeof( move[0] ) ) {
                    ret = shopkeeper->the_short()+" places "+
                        TP->poss_short()+" "+( sizeof(move[1]) == 1 ? "copy" :
                        query_num(sizeof(move[1]))+" copies")+" of "+
                        move[1][0]->the_short()+" on the floor.\n";
                } else {
                    ret += " and places the rest on the floor.\n";
                }
            } else {
                if( !sizeof( move[0] ) ) {
                    ret = "Your "+( info->number > 1 ?
                        query_num(info->number)+" copies" : "copy")+" of "+
                        ob->the_short()+" have been placed on the floor.\n";
                } else {
                    ret += " and the rest of your copies are placed on the "
                        "floor.\n";
                }
            }
        } else {
            ret += ".\n";
        }

        if( shopkeeper )
            tell_room( TO, ret );
        else
            write( ret );
        printed++;
    }

    if( !printed )
        return add_failed("Sorry, you need to wait until "+
            mudtime(failed)+" to collect your work.");

    return printed;

} /* do_collect() */

/**
 * Checks to see if the leaflet is in a language we cannot translate.
 * @param ob the leaflet to check for languages
 * @return 1 if there is a language we cannot deal with
 * @see set_default_language()
 * @see add_translation_cost()
 */
int check_for_untranslatable_language( object ob ) {
    mixed stuff;
    string lang;

    if( !sizeof( stuff = ob->query_text() ) )
        return 0;

    lang = stuff[READ_LANG];

    return ( lang != query_default_language() && !translation_costs[lang] );

} /* check_for_untranslatable_language() */

/** @ignore yes */
object find_leaflets( object *obs ) {
    int tmp;
    object *bad;
    mapping failed;
    function f;

    f = function( mapping map ) {
            string ret;

            if( sizeof( map["not"] ) ) {
                ret = "You cannot print copies of "+query_multiple_short(
                    map["not"], "the")+" because "+verbalize("they are not "
                    "leaflets", "it is not a leaflet")+".";
                map_delete( map, "not");
                if( sizeof(map) )
                    notify_player(ret);
            }

            if( sizeof( map["copy"] ) ) {
                ret = query_multiple_short( map["copy"], "the")+" "+verbalize(
                    "have")+" been copyrighted by "+query_multiple_short( map(
                    map["copy"], (: CAP($1->query_copyright()) :) ) )+" and "
                    "cannot be copied.";
                map_delete( map, "copy");
                if( sizeof(map) )
                    notify_player(ret);
            }

            if( sizeof( map["text"] ) ) {
                ret = query_multiple_short( map["text"], "the")+" "+verbalize(
                    "have")+" no text on "+verbalize("them", "it")+"!";
                map_delete( map, "text");
                if( sizeof(map) )
                    notify_player(ret);
            }

            if( map["obs"] )
                ret = "You can only print copies of one leaflet at a time, "
                      "please be more specific.";

            add_failed(ret);
            return 0;

        };

    failed = ([ ]);

    if( sizeof( bad = filter( obs, (: !$1->query_leaflet() :) ) ) )
        failed["not"] = bad;
    if( !sizeof( obs -= bad ) )
        return evaluate( f, failed );

    if( sizeof( bad = filter( obs, (: $1->query_copyright() &&
        $1->query_copyright() != $2 :), TP->query_name() ) ) )
        failed["copy"] = bad;
    if( !sizeof( obs -= bad ) )
        return evaluate( f, failed );

    if( sizeof( bad = filter( obs, (: !sizeof( $1->query_text() ) :) ) ) )
        failed["text"] = bad;
    if( !sizeof( obs -= bad ) )
        return evaluate( f, failed );

    if( sizeof(obs) > 1 ) {
        failed["obs"] = 1;
        return evaluate( f, failed );
    }

    if( obs[0]->query_copyright() == TP->query_name() )
        return obs[0];

    if( ( tmp = LEAFLET_H->query_copyright_protected(
        obs[0]->query_text()[READ_MESS] ) ) &&
        LEAFLET_H->query_copyright(tmp) != TP->query_name() ) {
        add_failed("The text on "+obs[0]->the_short()+" looks awfully "
            "similar to materials copyrighted by someone other than you.  "
            "I'm afraid we cannot copy that.");
        return 0;
    }

    return obs[0];

} /* find_leaflets() */

/**
 * This method will print out the pricing schedule for the object.
 * @param ob the object to get a pricing schedule of.
 */
void print_pricing( object ob, string language ) {
    int num, cols;
    string place, ret, *bits;
    mixed stuff;
    function asterisk;

    place = query_property("place") || "default";

    asterisk = function( string *bits, int cols ) {
                   string tmp, ret = "";

                   foreach( tmp in bits )
                       ret += sprintf(" *%s", indent( tmp, 3, cols )[2..] );

                   return ret;

               };

    bits = ({ });
    cols = sizeof(ob->query_text()[READ_MESS]) / 10 * DEFAULT_TIME_PER_LETTER;

    foreach( num in sort_array( keys(discount), 1 ) ) {
        if( num <= MAX_COPIES )
            bits += ({ sprintf("%i for %s and will be ready at %s.\n",
                num, MSTR( price_object( ob, num, language ) ), mudtime(
                query_time_to_collect() + query_time_per_copy() * num + cols +
                time() ) ) });
    }

    cols = (int)TP->query_cols();

    if( sizeof(translation_costs) ) {
        ret = "You can translate a book to or from "+query_multiple_short(
            keys(translation_costs)+({ query_default_language() }) )+", the "
            "cost of doing the translation is defined in the following "
            "table.";

        if( sizeof(translation_costs) > 2 )
            ret += "  Translating between two of these languages is also "
                "possible, but it will cost the amount to translate from the "
                "language to "+query_default_language()+" and back again.";

        ret += "\n";
        bits += ({ ret });
        ret = evaluate( asterisk, bits, cols );

        asterisk = function( int i, int j ) {
                    if( i < j )
                        return 1;
                    if( i > j )
                        return -1;
                    return 0;
                };

        num = sort_array( map( keys(translation_costs), (: sizeof($1) :) ),
            asterisk )[0] + 2;

        if( num < 20 )
            num = 20;

        foreach( language, stuff in translation_costs )
            ret += sprintf("%-=*s %'.'-=*s %d%%\n", 6, "", num, language,
                stuff );
        write("The cost of copying different numbers of "+
            ob->the_short()+" is:\n"+ret );
        return;
    }

    write("The cost of copying different numbers of "+
        ob->the_short()+" is:\n"+evaluate( asterisk, bits, cols ) );

} /* print_pricing() */

/**
 * This method will be called by the print add_command.
 * It will print out the pricing schedule and how long
 * the item will take to make.
 * @param obs the objects which have been matched
 * @param language the language to print the book in
 * @return 1 on success, 0 on failure
 * @see do_print_copies()
 */
int do_print( object *obs, string language ) {
    object ob;

    if( !do_open_check() )
        return 0;

    tell_room( TO, TP->the_short()+" "+verbalize("enquire")+" about the cost "
        "of printing copies of "+QMS(obs)+".\n", TP );

    if( !ob = find_leaflets(obs) )
        return 0;

    print_pricing( ob, language );
    write("Please use 'print <number> of <leaflet>' to print copies.\n");

    add_succeeded_mess("");
    return 1;

} /* do_print() */

/**
 * This method does the actual print run.  It creates all the objects
 * and makes the player pay for them all.
 * @param ob the object to print
 * @param number the number to print
 * @param cost the cost of the object
 * @param the language to translate things to
 * @see do_print_copies()
 */
void do_print_run( object ob, int number, int cost, string language ) {
    string place;
    int player_money;
    class print_data data;

    place = query_property("place") || "default";

    player_money = (int)TP->query_value_in( place );
    if( place != "default" )
        player_money += (int)TP->query_value_in("default");

    if( player_money < cost ) {
        if( ob->query_property("new_leaflet") ) {
            LEAFLET_H->delete_leaflet( ob->query_leaflet_id() );
            ob->dest_me();
        }
        return notify_player("You do not seem to have enough money any "
            "more.");
    }

    TP->pay_money( (mixed)MONEY_H->create_money_array( cost, place ), place );

    if( !data = add_print_run( TP->query_name(), ob, number, language ) )
        return notify_player("Sorry, something seems to have gone with your "
            "request.");

    notify_player("Your copies will be ready for collection"+
        ( no_collect ? " at the collection office" : "")+" at "+
        mudtime(data->time)+".  Please note that we dispose of unclaimed "
        "items after "+query_num( LEAFLET_H->query_time_out() )+" days.  "
        "Thank you!");

} /* do_print_run() */

/** @ignore yes */
void check_cost( string str, object ob, int number, int cost, string lang ) {
    if( strlen(str) < 1 || ( str[0] != 'y' && str[0] != 'Y' ) ) {
        if( ob->query_property("new_leaflet") ) {
            LEAFLET_H->delete_leaflet( ob->query_leaflet_id() );
            ob->dest_me();
        }
        return notify_player("As you wish.  See you again.");
    }

    if( !do_open_check() ) {
        if( ob->query_property("new_leaflet") ) {
            LEAFLET_H->delete_leaflet( ob->query_leaflet_id() );
            ob->dest_me();
        }
        write("The shop seems to have been closed in the meantime, sorry.\n");
        return;
    }

    do_print_run( ob, number, cost, lang );

} /* check_cost() */

/**
 * This method will be called when the player tries to print
 * a certain number of copies of a leaflet.
 * @param obs the objects which have been matched
 * @param number the number of prints to do
 * @param language the language to print the leaflet in
 * @return 1 on success, 0 on failure
 * @see do_print()
 */
int do_print_copies( object *obs, int number, string language ) {
    object ob;
    int cost, player_money;
    string place, ret;

    if( !do_open_check() )
        return 0;

    if( keeper && shopkeeper )
        tell_object( TP, "You enquire about copying some leaflets.\n");

    tell_room( TO, TP->the_short()+" "+verbalize("enquire")+" about copying "
        "some leaflets.\n", TP );

    if( number < 1 )
        return add_failed("You must print at least one copy.");

    if( number > MAX_COPIES )
        return add_failed("Sorry, we don't print more than "+
            query_num(MAX_COPIES)+" copies at a time.");

    if( !ob = find_leaflets(obs) )
        return 0;

    place = query_property("place") || "default";
    cost = price_object( ob, number, language );

    player_money = (int)TP->query_value_in( place );
    if( place != "default")
        player_money += (int)TP->query_value_in("default");

    ret = "Printing "+query_num(number)+" "+( number == 1 ? "copy" :
        "copies")+" of "+ob->the_short()+" will cost you "+MSTR(cost);

    if( player_money < cost )
        return add_failed( ret+", but you do not have enough money to "
            "afford it.", ({ ob }) );

    notify_player( ret+".  Do you wish to continue?");
    input_to( (: check_cost :), 0, ob, number, cost, language );
    add_succeeded_mess("");
    return 1;

} /* do_print_copies() */

/** @ignore yes */
int do_print_new() {
    if( !do_open_check() )
        return 0;

    if( shopkeeper )
        tell_object( TP, "You enquire about printing a new leaflet.\n");

    tell_room( TO, TP->the_short()+" "+verbalize("enquire")+" about "
        "printing "+verbalize("new leaflets", "a new leaflet")+".\n", TP );

    notify_player("Please edit what you would like your leaflet to say.  "
       "Keep in mind however that the maximum amount of characters we can "
       "print on a leaflet is "+query_num(MAX_CHARS)+".");

    tell_room( TO, TP->the_short()+" "+verbalize("start")+" editing the text "
        "for "+verbalize("their new leaflets", TP->HIS+" new leaflet")+".\n",
        TP );

    call_out( (: call_other( $(TP), "do_edit", 0, "finish_write") :), 2 );
    return 1;

} /* do_print_new() */

/** @ignore yes */
void check_number( string str, object ob ) {
    int cost, number;
    int player_money;
    string place;

    if( !sizeof(str) || str[0] == 'q' || str[0] == 'Q' ) {
        if( ob->query_property("new_leaflet") ) {
            LEAFLET_H->delete_leaflet( ob->query_leaflet_id() );
            ob->dest_me();
        }
        return notify_player("As you wish.  See you next time.");
    }

    if( !do_open_check() ) {
        if( ob->query_property("new_leaflet") ) {
            LEAFLET_H->delete_leaflet( ob->query_leaflet_id() );
            ob->dest_me();
        }
        write("The shop seems to have been closed in the meantime, sorry.\n");
        return;
    }

    sscanf( str, "%s%d", str, number );

    if( number < 1 ) {
        notify_player("You must print at least one copy.  How many copies "
            "would you like?");
        input_to( (: check_number :), ob );
        return;
    }

    if( number > MAX_COPIES ) {
        notify_player("We cannot print more than "+
            query_num(MAX_COPIES)+" copies at a time.  How many copies would "
            "you like?");
        input_to( (: check_number :), ob );
        return;
    }

    place = query_property("place") || "default";
    cost = price_object( ob, number, query_default_language() );

    player_money = (int)TP->query_value_in( place );

    if( place != "default" )
        player_money += (int)TP->query_value_in("default");

    if( player_money < cost ) {
        if( ob->query_property("new_leaflet") ) {
            LEAFLET_H->delete_leaflet( ob->query_leaflet_id() );
            ob->dest_me();
        }
        return notify_player("Printing "+query_num(number)+" "+( number == 1 ?
            "copy" : "copies")+" would cost you "+MSTR(cost)+", but you do "
            "not have enough money to afford it.");
    }

    notify_player("Printing "+query_num(number)+" "+( number == 1 ? "copy" :
        "copies")+" will cost you "+MSTR(cost)+".  Do you wish to continue?");

    input_to( (: check_cost :), 0, ob, number, cost,
        query_default_language() );

} /* check_number() */

/** @ignore yes */
void finish_write( string input ) {
    object ob;
    string adj;
    int i, new_id;

    if( !do_open_check() ) {
        write("The shop seems to have been closed in the meantime, sorry.\n");
        return;
    }

    tell_room( TO, TP->the_short()+" "+verbalize("finish")+" writing the "
        "text for "+verbalize("their", TP->HIS )+" new leaflet.\n", TP );

    if( !input || input == "")
        return notify_player("What would be the point of printing a leaflet "
            "with no writing on it?");

    i = strlen(input);

    if( i > MAX_CHARS )
        return notify_player("Sorry, but we have no leaflets big enough to "
            "print "+query_num(i)+" characters on.  The most we can print "
            "on a leaflet is "+query_num(MAX_CHARS)+" characters.");

    if( ( new_id = LEAFLET_H->query_copyright_protected( input ) ) &&
        LEAFLET_H->query_copyright(new_id) != TP->query_name() )
        return notify_player("I'm sorry, but someone other than you is "
            "holding the copyright on the text you have written.");

    ob = clone_object(LEAFLET_OBJ);
    ob->set_name("leaflet");
    ob->set_weight(0);

    switch( i ) {
        case 0..100 :
          adj = "tiny";
          ob->set_value( 1 );
        break;
        case 101..400 :
          adj = "small";
          ob->set_value( 2 );
        break;
        case 401..800:
          adj = "medium sized";
          ob->set_value( 3 );
        break;
        case 801..1600:
          adj = "large";
          ob->set_value( 4 );
        break;
        default:
          adj = "huge";
          ob->set_value( 5 );
          ob->set_weight( 1 );
    }

    ob->set_short( adj+" leaflet");

    if( !new_id )
        new_id = LEAFLET_H->new_leaflet( TP->query_name(),
            ({ input, "printing", "common", 1 }) );

    ob->set_printer_id(id);
    ob->set_leaflet_id(new_id);
    ob->set_leaflet_size(adj);
    ob->add_property("new_leaflet", 1 );

    print_pricing( ob, query_default_language() );

    notify_player("How many copies would you like?");
    input_to( (: check_number :), ob );

} /* finish_write() */

/** @ignore yes */
void init() {
    string languages;

    ::init();

    if( !office_room ) {
        add_command("print", "<indirect:object:me>",
            (: do_print( $1, query_default_language() ) :));
        add_command("print", "new leaflet",
            (: do_print_new() :));
        add_command("print", "<number> [copies] of <indirect:object:me>",
            (: do_print_copies( $1, $4[0], query_default_language() ) :) );
        add_command("claim", "copyright on <indirect:object:me>",
            (: do_claim :) );
        if( sizeof(translation_costs) ) {
            languages = implode(
                keys(translation_costs)+({ query_default_language() }), "|");
            add_command("print", "<indirect:object:me> in {"+languages+"}",
                (: do_print($1, $4[1]) :));
            add_command("print", "<number> [copies] of <indirect:object:me> "
                "in {"+languages+"}",
                (: do_print_copies( $1, $4[0], $4[2] ) :) );
        }
    }

    if( !no_collect )
        add_command("collect", "", (: do_collect :) );

} /* init() */

/** @ignore yes */
mixed stats() {
    return ::stats() + ({
        ({ "no collection", no_collect }),
        ({ "office room", office_room }),
        ({ "shop id", query_print_shop_id() }),
        ({ "shop name", query_print_shop_name() }),
        ({ "letter cost", query_letter_cost() }),
        ({ "default language", query_default_language() }),
        ({ "shopkeeper", keeper }),
        ({ "cost per order", query_cost_per_order() }),
    });
} /* stats() */