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/
/**
 * This handles all the methods for determining values of coins and
 * the current valid set of coins.   It also handles change calculation.
 * This was written originaly by Pinkfish, reworked significantly by
 * Deutha to add in the multiple currency areas.
 * @see /std/living/money.c
 * @author Pinkfish
 * @changed Fixed up the code that deals with different currency areas.
 * Also added money_array_from_string() and made value_from_string()
 * work properly with different types of currencies.
 * - Sandoz, April 2003.
 */

#define DATA ((class money_data)details[type])

#define __MONEY_CLASS__
#include <money.h>

private mapping values;
private mapping details;
private mapping aliases;
private object parse_cont;

private void add_coin_type( string type, string head_short, string tail_short,
                            string head_long, string tail_long,
                            string material, string plural, string adj,
                            int weight ) {

    DATA = new( class money_data,
                head_short : head_short,
                tail_short : tail_short,
                head_long  : head_long,
                tail_long  : tail_long,
                material   : material,
                plural     : plural,
                adj        : adj,
                weight     : weight );

} /* add_coin_type() */

void create() {
    values = ([
        "default": ({
            "copper", 1,
            "silver", 10,
            "electrum", 100,
            "gold", 2000,
            "platinum", 6000,
            }),
        "calarien": ({
            "Calarien rahn", 1,
            "Calarien tablis", 100,
            "Calarien reaal", 10000,
            }),
        ]);

    details = ([ ]);

    add_coin_type("copper", "heads", "tails",
        "a head", "a tail", "copper", 0, "small", 10 );
    add_coin_type("silver", "heads", "tails",
        "a head", "a tail", "silver", 0, "thin and slighty scratched", 13 );
    add_coin_type("electrum", "heads", "tails",
        "a head", "a tail", "electrum", 0, "slightly scratched", 15 );
    add_coin_type("gold", "heads", "tails",
        "a head", "a tail", "gold", 0, "thin", 18 );
    add_coin_type("platinum", "heads", "tails",
        "a head", "a tail", "platinum", 0, "large and pretty heavy", 20 );

    // Weight a little less than 3 grams.
    add_coin_type("Calarien rahn", "heads", "tails",
        "an ornate number one, imprinted in a grubby surface",
        "a scratched carving of what might be a blooming sunflower",
        "copper", "rahns", "thin and scratched", 5 );
    // Weight a little over 7 grams.
    add_coin_type("Calarien tablis", "heads", "tails",
        "a crudely carved sun", "a delicate waxing moon",
        "silver", "tabli", "slightly scratched", 15 );
    // Weight a little over 12 grams.
    add_coin_type("Calarien reaal", "heads", "tails", "a small imprint of "
        "the Calarien crest along with the words \"1 REAAL\" underneath it",
        "a delicate carving of an eagle, its beak wide open and wings spread "
        "in their full glory", "gold", "reaali", "large and fairly heavy", 25 );

    aliases = ([
        "Calarien rahn"   : ({"rahn"}),
        "Calarien tablis" : ({"tablis"}),
        "Calarien reaal"  : ({"reaal"}),
    ]);

} /* create() */

/**
 * This method returns the mapping containing all the values of the
 * currently valid money types.   The mapping has keys of the domain
 * of the money and has a value of an array.   The array contains
 * alternating name, value pairs.
 * <pre>
 * ([ "default": ({ "brass", 1, "copper", 10, "silver", 100,
 *                  "gold", 2000, "platinum", 6000 }) ])
 * </pre>
 * @return the mapping of values
 * @see query_values()
 * @see query_values_in()
 */
mapping query_all_values() { return copy(values); }

/**
 * This method returns the current set of areas in which types can
 * be found.
 * @return the set of places
 */
string *query_all_places() { return keys(values); }

/**
 * This method returns the values in the default area.
 * This method returns the array as given in the value above.
 * It contains name, value pairs and is for the "default"
 * area.
 * @return the array of values
 * @see query_all_values()
 * @see query_values_in()
 */
mixed *query_values() { return copy( values["default"] ); }

/**
 * This method returns the values in the specified area.
 * It contains name, value pairs and is for the "default"
 * area.
 * @return the array of values
 * @param where the area in which to return the values for
 * @see query_all_values()
 * @see query_values()
 * @see add_type()
 */
mixed query_values_in( string where ) {
    if( !where || where == "")
        where = "default";
    return copy( values[where] );
} /* query_values_in() */

/**
 * This method returns all the details for the current set of
 * coins.   The details are information which is shown when the coin
 * is looked at.   Stuff about heads and tails and things.
 * @return the mapping of details for all coin types
 * @see /include/money.h
 */
mapping query_details() { return copy( details ); }

/**
 * This method returns the details for a specified type of money.
 * It will return a class of the form:
 * <pre>
 * ({ forward short, reverse short,
 *    forward long, reverse long, composition,
 *    plural, adjectives, weight })
 * </pre>
 * @param type the money type to get the details for
 * @see /include/money.h
 */
class money_data query_details_for( string type ) {
    if( DATA )
        return copy(DATA);
    return 0;
} /* query_details_for() */

/**
 * This method returns all the current aliases for the given type
 * of money.
 * @param type the type of money to get the aliases for
 * @return the aliases for the money type
 */
string *query_aliases_for( string type ) {
    string *ret;

    if( !DATA || !DATA->plural )
        ret = ({ "coin" });
    else
        ret = ({ explode( type, " ")[<1] });

    if( aliases[ type ] )
        ret += aliases[ type ];

    return ret;

} /* query_aliases_for() */

/**
 * This method returns the short description of the money type.
 * @param type the money type to get the short description for
 * @return the short description for the money object
 * @see query_main_plural_for()
 */
string query_short_for( string type ) {
    if( !DATA || !DATA->plural )
        return type+" coin";
    return type;
} /* query_short_for() */

/**
 * This method returns the short plural description of the money type.
 * This returns just the one word, like 'coins' or 'talons'.
 * @param type the money type to get the short plural description for
 * @return the short plural description for the money object
 * @see query_main_plural_for()
 */
string query_plural_for( string type ) {
    if( !DATA || !DATA->plural )
        return "coins";
    return DATA->plural;
} /* query_plural_for() */

/**
 * This method returns the main short plural description of the money type.
 * This returns the expanded plural version like 'Ankh-Morpork pennies'.
 * @param type the money type to get the short plural description for
 * @return the short plural description for the money object
 * @see query_plural_for()
 * @see query_short_for()
 */
string query_main_plural_for( string type ) {
    if( !DATA || !DATA->plural )
        return type+" coins";

    return implode( explode( type, " ")[0..<2] + ({ DATA->plural }), " ");

} /* query_main_plural_for() */

/**
 * This method returns the weight of 100 coins of the money type.
 * @param type the money type to get the weight of 100 coins for
 * @return the weight of 100 coins of the specified type
 */
int query_weight_for( string type ) {
    if( !DATA )
        return 10;
    return DATA->weight || 10;
} /* query_weight_for() */

/**
 * This method returns the value of a specified type of money in a certain
 * money area.
 * @param type the type of money to get the value for
 * @param where the money area the money is in
 * @return the integer value of the money
 * @see query_total_value()
 */
varargs int query_value( string type, string where ) {
    int i;

    if( !where || where == "")
        where = "default";

    if( !values[where] )
        return 0;

    if( ( i = member_array( type, values[where] ) ) == -1 )
        return 0;

    return values[where][i+1];

} /* query_value() */

/**
 * This method determines the total value of a specified money array.
 * A money array consists of pairs of values ({ type, number })
 * @param mon_array the array to find the value of
 * @param where the money area to get the value in
 * @return the total value as an integer
 * @see query_value()
 */
varargs int query_total_value( mixed mon_array, string where ) {
    int i, amt;

    if( !where || where == "")
        where = "default";

    for( i = 0; i < sizeof( mon_array ); i += 2 )
        amt += mon_array[ i + 1 ] * query_value( mon_array[ i ], where );

    return amt;

} /* query_total_value() */

/**
 * This method converts a money array into a string so it can be displayed.
 * @param mon_array the money array to convert into a string
 * @see money_value_string()
 */
string money_string( mixed mon_array ) {
    int i;
    string ret;

    if( !sizeof(mon_array) )
        return "nothing";

    ret = "";

    while( i < sizeof(mon_array) ) {
        if( !mon_array[ i + 1 ] )
            mon_array = delete( mon_array, i, 2 );
        else
           i += 2;
    }

    for( i = 0; i < sizeof(mon_array); i += 2 ) {
        ret += query_num(mon_array[ i + 1 ])+" ";

        if( mon_array[ i + 1 ] == 1 )
            ret += query_short_for( mon_array[ i ] );
        else
            ret += query_main_plural_for( mon_array[ i ] );

        if( i == sizeof(mon_array) - 4 )
            ret += " and ";
        else if ( i != sizeof(mon_array) - 2 )
            ret += ", ";
    }

    return ret;

} /* money_string() */

/**
 * This method creates a money array from a certain value in a particular
 * money area. A money array consists of ({ type, number }) pairs in an
 * array.   ie: ({ "brass", 12, "copper", 24 }).
 * @example
 * place = query_property("place");
 * if (!place) {
 *      place = "default";
 * }
 * mon_array = create_money_array( 1000, place);
 * @param value the value to get the money array for
 * @param where the money area to get the value in
 * @return a money array for the value in the area
 * @see money_value_string()
 */
varargs mixed create_money_array( int value, string where ) {
    int i, amt;
    mixed mon_array;

    if( !where || where == "")
        where = "default";

    if( !value )
        return ({ });

    mon_array = ({ });

    for( i = sizeof( values[ where ] ) - 2; i >= 0; i -= 2 ) {
        if( value >= values[ where ][ i + 1 ] ) {
            mon_array += ({ values[ where ][ i ], amt = value /
                            values[ where ][ i + 1 ] });
            value -= amt * values[ where ][ i + 1];
        }
    }

    return mon_array;

} /* create_money_array() */

/**
 * This method returns a string which is based on the value of
 * the money in a certain money area.
 * @param value the value to get the string for
 * @param where the place to get the string for
 * @return a string of the money value in the certain money area
 * @see create_money_array()
 * @see money_string()
 * @see value_from_string()
 */
varargs string money_value_string( int value, string where ) {
    if( !where || where == "")
        where = "default";

    if( value < 0 )
        return "negative "+money_string( create_money_array( -value, where ) );

    return money_string( create_money_array( value, where ) );

} /* money_value_string() */

/**
 * @ignore yes
 * This method is used both by value_from_string() and
 * money_array_from_string(). If the flag argument is 0, then it
 * will return the overall value of the money in the input string.
 * If the flag argument is 1, then it will parse the input string
 * and return it as a money array, if the flag is greater than 1,
 * then it will return on partial matches.
 */
private mixed int_money_from_string( string str, string where, int flag ) {
    mixed types, bits, ret;

    if( !where )
        where = "default";

    if( !types = values[where] )
        return 0;

    str = lower_case(str);
    bits = explode( replace( str, ({" and ", ",", " & ", ","}) ), ",");
    bits = map( bits, (: explode( $1, " ") - ({""}) :) );

    if( flag )
        ret = ({ });

    for( int i = 0; i < sizeof(types); i += 2 ) {
        string type, plural, *adj, *alias;

        type = types[i];

        if( sizeof( alias = aliases[type] ) ) {
            adj = explode( lower_case(type), " ")[0..<2];
            plural = DATA->plural;
        } else {
            alias = ({"coin"});
            adj = explode( lower_case(type), " ");
            plural = "coins";
        }

        for( int j = 0; j < sizeof(bits); j++ ) {
            string *bit, *match;
            int number;

            if( !sizeof( bit = bits[j] ) ) {
                bits = delete( bits, j--, 1 );
                continue;
            }

            if( sscanf( bit[0], "%d", number ) == 1 ) {
                // Nothing but a number, or a negative number specified.
                if( number < 1 || !sizeof( bit = bit[1..] ) ) {
                    bits = delete( bits, j--, 1 );
                    continue;
                }

                if( number == 1 )
                    match = alias;
                else
                    match = ({ plural });

            } else {
                number = 1;
                match = alias;
            }

            // Let's not match on a mere "1 coin".
            if( sizeof( bit ) == 1 ) {
                switch( bit[0] ) {
                  case "coin":
                  case "coins":
                    bits = delete( bits, j--, 1 );
                    continue;
                  default:
                }
            }

            // No match on the name/alias.
            if( member_array( bit[<1], match ) == -1 )
                continue;

            if( sizeof(bit) > 1 ) {
                int k, fail;

                fail = 0;
                k = sizeof(bit) - 1;

                while( k-- ) {
                    // Invalid adjective in the input string.
                    // No match.
                    if( member_array( bit[k], adj ) == -1 ) {
                        fail = 1;
                        break;
                    }
                }

                if( fail )
                    continue;
            }

            // Everything matched.
            if( flag ) {
                int k;

                if( ( k = member_array( type, ret ) ) == -1 )
                    ret += ({ type, number });
                else
                    ret[k+1] += number;

            } else {
                ret += number * types[i+1];
            }

            bits = delete( bits, j--, 1 );

        }
    }

    switch( flag ) {
      case 0 :
      case 1:
        return ret;
      default:
        // Do not accept partial matches with a flag greater than 1.
        if( !sizeof(bits) )
            return ret;
        return 0;
    }

} /* int_money_from_string() */

/**
 * This method attempts to find a money value from a string.  It will
 * attempt to do fuzzy matching of the type.  This means it will match on
 * partial matches, this could lead to somewhat weird behaviour...  So it
 * goes.
 * @param str the string to find the value of
 * @see money_value_string()
 * @see money_array_from_string()
 * @example
 * // This will tell us the integer money value of the string.
 * write( MONEY_H->value_from_string("1 dollar and 12 pence",
 *                                   "Ankh-Morpork"));
 */
int value_from_string( string str, string where ) {
    return int_money_from_string( str, where, 0 );
} /* value_from_string() */

/**
 * This method attempts to create a money array from a string.  It will
 * attempt to do fuzzy matching of the type.  This means it will match on
 * partial matches, this could lead to somewhat weird behaviour.
 * @param str the string to find the value of
 * @param where the currency area to get the money array for
 * @param flag if the flag is set, then we will return 0 on a partial match
 * @see money_value_string()
 * @see value_from_string()
 * @example
 * MONEY_H->money_array_from_string("12 Calarien rahns and 37 tabli",
 *                                  "calarien");
 */
mixed money_array_from_string( string str, string where, int flag ) {
    return int_money_from_string( str, where, flag ? 2 : 1 );
} /* money_array_from_string() */

/**
 * This method calculates the change of a certain value from a
 * given money array.   This makes sure that the change does not include
 * money that does not actually exist.
 * @param value the value of the change to calculate
 * @param mon_array the money array to determine the change from
 * @return the money array containing the change to use
 * @see make_payment()
 * @see pay_amount_from()
 */
mixed calc_change( int value, mixed *mon_array ) {
    int i, num;
    mixed ret;

    ret = ({ });

    for( i = sizeof( mon_array ) - 2; i >= 0; i -= 2 ) {
        if( value >= mon_array[ i + 1 ] ) {
            num = value / mon_array[ i + 1 ];
            value = value % mon_array[ i + 1 ];
            ret += ({ mon_array[ i ], num });

            if( !value )
                return ret;
        }
    }

    return ret;

} /* calc_change() */

/**
 * This method makes a payment from a money array.  It returns the
 * depleted money array, the amount taken out and the change
 * needed.  If the type is not set, then the best fit for the value
 * is found from the array.
 * <p>
 * The return array is formated as:<br>
 * ({ depleted_money_array, change, taken_from })<br>
 * The change is an integer value.
 * @param type the type of money to take out
 * @param value the amount of the type to take out
 * @param mon_array the money array to use
 * @param where the money area
 * @param use_default allow the use of the default money type
 * @return the return array as formated above
 */
mixed make_money_array_payment( string type, int value, mixed mon_array,
                                string where, int use_default ) {

    int i, j, num, total, cur_match;
    string mon_name;
    mixed poss_values, ret;

    // Figure out the money type.
    if( !where || where == "")
        where = "default";

    // See if the money is there and it's all easy.
    if( type ) {
        if( ( i = member_array( type, mon_array ) ) != -1 ) {
            if( value <= mon_array[ i + 1 ] ) {
                mon_array[ i + 1] -= value;
                return ({ ({ type, value }), 0, mon_array });
            }
        }

        // Damn, its not easy.  Figure out the real value and see if we can
        // get it out of the arrays.
        value = value * query_value( type, where );
    }

    // Check to make sure the total is ok.
    total = query_total_value( mon_array, where );
    if( use_default  &&  where != "default")
        total += query_total_value( mon_array, "default");

    // If the value is more than the total...
    if( value > total )
        return 0;

    // Get the possible values.
    poss_values = ({ });
    if( where != "default" && use_default )
        poss_values += values["default"];

    poss_values += values[ where ];

    ret = ({ });

    // This attempts an exact match of coins.
    for( i = ( sizeof( poss_values ) - 2 ); i >= 0; i -= 2 ) {
        j = member_array( poss_values[ i ], mon_array );
        if( j != - 1 ) {
            if ( poss_values[ i + 1 ] <= value ) {
                num = value / poss_values[ i + 1 ];

                if( num > mon_array[ j + 1 ] )
                    num = mon_array[ j + 1 ];

                mon_array[ j + 1] -= num;
                value -= num * poss_values[ i + 1 ];
                ret += ({ poss_values[ i ], num });

                if( !value )
                    return ({ ret, value, mon_array });
            }
        }
    }

    // No exact match...
    // Now we need to figure out how much change to give.
    // Zoom through the array finding which one has the closest match.
    cur_match = value + 10000000;

    for( i = 0; i < sizeof(poss_values); i +=2 ) {
        j = member_array( poss_values[ i ], mon_array );
        if( j != -1 && mon_array[j+1] > 0 &&
            poss_values[i+1] >= value &&
            poss_values[i+1] - value <= cur_match - value ) {
            cur_match = poss_values[i+1];
            mon_name = poss_values[i];
        }
    }

    if( mon_name ) {
        j = member_array( mon_name, mon_array );
        i = member_array( mon_name, poss_values );
        mon_array[j+1] -= 1;
        value = poss_values[i+1] - value;
        ret += ({ poss_values[ i ], 1 });
    } else {
        return 0;
    }

    return ({ ret, value, mon_array });

} /* make_money_array_payment() */

/**
 * This method makes a payment of a particular amount in a particular
 * money area.   Please note that player or living objects can double
 * as money objects in this circumstance.  The first element of the
 * payment array is the values which should be used to take off
 * the player, the second element is the change needed to be payed
 * back.
 * @param type the type of money to pay in
 * @param value the number of the type to pay
 * @param thing the thing which is doing the payment (money object)
 * @param where the money area the payment will occur in
 * @return the payment array
 * @see pay_amount_from()
 * @see calc_change()
 */
varargs mixed make_payment( string type, int value, object thing,
                            string where ) {
    mixed mon_array, stuff;

    if( !type )
        return 0;

    mon_array = copy( thing->query_money_array() );

    stuff = make_money_array_payment( type, value, mon_array, where, 1 );
    if( !stuff )
        return stuff;

    if( stuff[MONEY_PAY_CHANGE] )
        return ({ stuff[MONEY_PAY_RETURN],
                  calc_change( stuff[MONEY_PAY_CHANGE], values[where] ) });

    return ({ stuff[MONEY_PAY_RETURN], stuff[MONEY_PAY_CHANGE] });

} /* make_payment() */

/**
 * This method makes a payment from a specified money object.
 * @param value the amount to pay
 * @param money the money object to pay from
 * @param where the money area the payment occurs in
 * @return the change object
 * @see make_payment()
 * @see calc_change()
 */
varargs object pay_amount_from( int value, object money, string where ) {
    int i, j;
    object change;
    mixed m_array, p_array;

    if( !where || where == "")
        where = "default";

    change = clone_object( MONEY_OBJECT );
    m_array = create_money_array( value, where );

    for( i = 0; i < sizeof(m_array); i += 2 ) {
        p_array = make_payment( m_array[ i ], m_array[ i + 1 ], money, where );

        if( !pointerp( p_array ) )
            continue;

        for( j = 0; j < sizeof( p_array[0] ); j += 2 )
            money->adjust_money( -p_array[ 0 ][ j + 1 ], p_array[ 0 ][ j ] );

        if( sizeof( p_array[ 1 ] ) )
            change->adjust_money( p_array[ 1 ] );
    }

    if( !sizeof( change->query_money_array() ) ) {
        change->dest_me();
        return 0;
    }

    return change;

} /* pay_amount_from() */

/**
 * This method creates a money object of a certain value in a certain
 * money area.
 * @param value the value to create the new money object with
 * @param where the area to create the new money object in
 * @return the new money object
 */
varargs object make_new_amount( int value, string where ) {
    object money;

    if( !where || where == "")
        where = "default";

    money = clone_object( MONEY_OBJECT );
    money->set_money_array( create_money_array( value, where ) );

    if( !money->query_value_in( where ) ) {
        money->dest_me();
        return 0;
    }

   return money;

} /* make_new_amount() */

/**
 * This method figures out the legal and illegal tender money from
 * the specified money object in the specified money area.   This method
 * returns a two element array which consists of the legal and illegal
 * tender for the given money area.   ({ legal, illegal })
 * @param money the money object to get the legal tender from
 * @param where the money area the tender is for
 * @return an two element array of objects ({ legal, illegal })
 * @see parse_money()
 */
varargs object *filter_legal_tender( object money, string where ) {
    int i;
    object good, no_good;
    mixed mon_array, poss_values;

    if( !where || where == "")
        where = "default";

    if( !sizeof( mon_array = money->query_money_array() ) ) {
        money->dest_me();
        return ({ 0, 0 });
    }

    if( !( poss_values = values[ where ] ) )
        poss_values = ({ });

    if( where != "default" )
        poss_values += values["default"];

    for( i = 0; i < sizeof(mon_array); i += 2 ) {
        if( member_array( mon_array[ i ], poss_values ) != -1 ) {
            if( !good )
                good = clone_object(MONEY_OBJECT);
            good->adjust_money( mon_array[ i + 1 ], mon_array[ i ] );
        } else {
            if( !no_good )
                no_good = clone_object(MONEY_OBJECT);
            no_good->adjust_money( mon_array[ i + 1 ], mon_array[ i ] );
        }
    }

    money->dest_me();

    if( good && !sizeof( good->query_money_array() ) )
        good->dest_me();

    if( no_good && !sizeof( no_good->query_money_array() ) )
        no_good->dest_me();

    return ({ good, no_good });

} /* filter_legal_tender() */

/**
 * This method determines all the money from the player object and moves
 * it into a container.  It then figured out the legal tender for
 * specified money area and tells the player if the given money is
 * legal tender for the current area.
 * @param words the string to match the money on
 * @param player the player who is attempting the transaction
 * @param place the money area the transaction is taking place
 * @return a money object consisting of the legal tender
 * @see filter_legal_tender()
 */
varargs mixed parse_money( string words, object player, string place ) {
    object thing, *monies, *things;

    things = match_objects_for_existence( words, ({ player }) );
    if( !sizeof(things) )
        return NO_MATCH;

    if( !parse_cont ) {
        parse_cont = clone_object("/std/container");
    } else if( sizeof( INV(parse_cont) ) ) {
        parse_cont->dest_me();
        parse_cont = clone_object("/std/container");
    }

    foreach( thing in things )
        if( thing->query_property("money") )
            thing->move(parse_cont);

    if( !sizeof( things = INV(parse_cont) ) )
        return NO_MONEY;

    monies = filter_legal_tender( things[ 0 ], place );

    if( monies[ 1 ] ) {
        if( monies[ 1 ]->move(player) ) {
            monies[ 1 ]->move( ENV(player) );
            tell_object( player, "Oh dear, you seem to be somewhat "
                "overburdened and fumble "+monies[ 1 ]->the_short()+".\n");
        }

        tell_object( player, monies[ 1 ]->the_short()+
            ( monies[ 1 ]->query_number_coins() == 1 ? " is" : " are")+" not "
            "legal tender here.\n");

        if( !monies[ 0 ] )
            return NO_LEGAL;

    }

    return monies[ 0 ];

} /* parse_money() */

/**
 * This method makes a payment from one person to another.
 * This method figures out what money should be given to the player
 * and what should be taken from the other to make a payment of the
 * correct value in the correct place.
 * @param value the value to pay
 * @param place the place to make the payment in
 * @param payer the person the money is payed from
 * @param payee the person the money is payed to
 * @return two element array, or 0 if it cannot be done
 */
mixed query_person_payments( int value, string place, object payer,
                             object payee ) {
    mixed stuff, mon_array, rabbit;

    mon_array = copy( payer->query_money_array() );

    stuff = make_money_array_payment( 0, value, mon_array, place, 0 );
    if( !stuff )
        return 0;

    if( stuff[MONEY_PAY_CHANGE] ) {
        // Now check to see if we can get the change from the other guy.
        mon_array = copy( payee->query_money_array() );
        rabbit = make_money_array_payment( 0, stuff[MONEY_PAY_CHANGE],
                 mon_array, place, 0 );

        if( !rabbit || rabbit[MONEY_PAY_CHANGE] )
            return 0;

        return ({ stuff[MONEY_PAY_RETURN], rabbit[MONEY_PAY_RETURN] });
    }

    return ({ stuff[MONEY_PAY_RETURN], ({ }) });

} /* query_person_payments() */

/**
 * This returns a list of valid coin types
 * @return an array of valid coin types
 */
string *query_valid_types() {
    string *tmp, *valid_types = ({ });
    mixed elem;
    int i;

    tmp = values( query_all_values() );

    foreach( elem in tmp ) {
        for( i = 0; i < sizeof(elem); i++ ) {
            if( stringp( elem[i] ) )
                valid_types += ({ elem[i] });
        }
    }

    return valid_types;

}/* query_valid_types() */

/**
 * This takes a coin type and returns the place it is associated with.
 * @param type the coin type i.e. "Ankh-Morpork dollar"
 * @return the place i.e. "Ankh-Morpork"
 */
string query_origin_of( string type ) {
    string elem, *places;

    if( member_array( type, query_valid_types() ) == -1 )
        return 0;

    places = query_all_places();

    foreach( elem in places )
        if( member_array( type, query_values_in( elem ) ) != -1 )
            return elem;

} /* query_origin_of() */

/**
 * This converts a currency type's alias (i.e. "royal" ) and returns
 * its 'real' names (i.e. "Ankh-Morpork royal"
 * @param word the alias to find the real name of
 * @return an array of real names, or 0 if it's not a real alias
 */
string *query_aliases_of( string word ) {
    string *types, elem, *aliases = ({ });

    types = query_valid_types();

    foreach( elem in types ) {
        if( member_array( word, query_aliases_for( elem ) ) != -1 )
            aliases += ({ elem });
    }

    return aliases;

} /* query_aliases_of */

/**
 * This returns the value of a currency type.
 * @param type currency type
 * @return an int of the currency type's value
 */
int query_value_of( string type ) {
    if( member_array( type, query_valid_types() ) == -1 )
        return 0;
    return query_value( type, query_origin_of( type ) );
} /* query_value_of() */

/**
 * This returns the smallest unit of currency in this place.
 * @param place The place to query.
 * @return a string of the smallest unit of currency
 */
string smallest_in( string place ) {
    int i, j, smallest;
    mixed values;

    values = query_values_in( place );
    for( i = 1; i < sizeof(values); i += 2 ) {
        if( !smallest || values[i] < smallest ) {
            smallest = values[i];
            j = i;
        }
    }

    return values[j-1];

} /* smallest_in() */