final_realms_fluffos_v1/
final_realms_fluffos_v1/bin/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/ChangeLog.old/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/Win32/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/compat/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/compat/simuls/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/include/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/clone/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/command/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/data/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/etc/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/include/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/inherit/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/inherit/master/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/log/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/tests/compiler/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/tests/efuns/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/tests/operators/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/u/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/tmp/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/windows/
final_realms_fluffos_v1/lib/baseobs/guilds/
final_realms_fluffos_v1/lib/baseobs/misc/
final_realms_fluffos_v1/lib/baseobs/races/shadows/
final_realms_fluffos_v1/lib/cmds/god/
final_realms_fluffos_v1/lib/cmds/handlers/
final_realms_fluffos_v1/lib/cmds/handlers/cmds/
final_realms_fluffos_v1/lib/d/heaven/
final_realms_fluffos_v1/lib/d/heaven/heaven/ave/
final_realms_fluffos_v1/lib/d/mudlib/
final_realms_fluffos_v1/lib/d/newbie/
final_realms_fluffos_v1/lib/d/newbie/docs/
final_realms_fluffos_v1/lib/d/newbie/drow/armour/
final_realms_fluffos_v1/lib/d/newbie/drow/items/
final_realms_fluffos_v1/lib/d/newbie/drow/mobs/
final_realms_fluffos_v1/lib/d/newbie/drow/oldmobs/
final_realms_fluffos_v1/lib/d/newbie/drow/weapons/
final_realms_fluffos_v1/lib/d/newbie/duergar/weapons/
final_realms_fluffos_v1/lib/d/newbie/dwarf/weapons/
final_realms_fluffos_v1/lib/d/newbie/elf/cafe/
final_realms_fluffos_v1/lib/d/newbie/elf/chars/equip/
final_realms_fluffos_v1/lib/d/newbie/elf/items/armours/
final_realms_fluffos_v1/lib/d/newbie/elf/items/obj/
final_realms_fluffos_v1/lib/d/newbie/elf/items/weapons/
final_realms_fluffos_v1/lib/d/newbie/elf/quick_fix/
final_realms_fluffos_v1/lib/d/newbie/gnome/armour/
final_realms_fluffos_v1/lib/d/newbie/gnome/buildings/
final_realms_fluffos_v1/lib/d/newbie/gnome/items/
final_realms_fluffos_v1/lib/d/newbie/gnome/npcs/clones/
final_realms_fluffos_v1/lib/d/newbie/gnome/rooms/northrooms/
final_realms_fluffos_v1/lib/d/newbie/gnome/weapons/
final_realms_fluffos_v1/lib/d/newbie/goblin/armour/
final_realms_fluffos_v1/lib/d/newbie/goblin/items/
final_realms_fluffos_v1/lib/d/newbie/grads/log/
final_realms_fluffos_v1/lib/d/newbie/grads/npcs/
final_realms_fluffos_v1/lib/d/newbie/grads/rooms/
final_realms_fluffos_v1/lib/d/newbie/grads/rooms/cave1/
final_realms_fluffos_v1/lib/d/newbie/grads/temp/
final_realms_fluffos_v1/lib/d/newbie/guests/weapons/
final_realms_fluffos_v1/lib/d/newbie/half-elf/items/
final_realms_fluffos_v1/lib/d/newbie/half-elf/newroomss/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/castle/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/drows/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/savannah/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/secret/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/town/
final_realms_fluffos_v1/lib/d/newbie/halfling/
final_realms_fluffos_v1/lib/d/newbie/halfling/misc/
final_realms_fluffos_v1/lib/d/newbie/halfling/rooms/cave/
final_realms_fluffos_v1/lib/d/newbie/human/
final_realms_fluffos_v1/lib/d/newbie/human/armour/
final_realms_fluffos_v1/lib/d/newbie/human/monsters/
final_realms_fluffos_v1/lib/d/newbie/human/obj/
final_realms_fluffos_v1/lib/d/newbie/human/weapons/
final_realms_fluffos_v1/lib/d/newbie/lizard/armour/
final_realms_fluffos_v1/lib/d/newbie/lizard/items/
final_realms_fluffos_v1/lib/d/newbie/lizard/underwater/
final_realms_fluffos_v1/lib/d/newbie/lizard/weapons/
final_realms_fluffos_v1/lib/d/newbie/logs/
final_realms_fluffos_v1/lib/d/newbie/new_halfelf/
final_realms_fluffos_v1/lib/d/newbie/new_halfelf/npcs/
final_realms_fluffos_v1/lib/d/newbie/newdrow/npcs/
final_realms_fluffos_v1/lib/d/newbie/newdrow/rooms/
final_realms_fluffos_v1/lib/d/newbie/newelf/
final_realms_fluffos_v1/lib/d/newbie/newelf/chars/
final_realms_fluffos_v1/lib/d/newbie/newelf/npcs/
final_realms_fluffos_v1/lib/d/newbie/newelf/npcs/recopied/
final_realms_fluffos_v1/lib/d/newbie/newelf/obj/
final_realms_fluffos_v1/lib/d/newbie/newelf/quest_docs./
final_realms_fluffos_v1/lib/d/newbie/newken/
final_realms_fluffos_v1/lib/d/newbie/newken/chars/
final_realms_fluffos_v1/lib/d/newbie/newken/misc/
final_realms_fluffos_v1/lib/d/newbie/newken/npcs/
final_realms_fluffos_v1/lib/d/newbie/newken/obj/
final_realms_fluffos_v1/lib/d/newbie/newliz/
final_realms_fluffos_v1/lib/d/newbie/newliz/cave/
final_realms_fluffos_v1/lib/d/newbie/newliz/npcs/
final_realms_fluffos_v1/lib/d/newbie/orc/items/misc/
final_realms_fluffos_v1/lib/d/newbie/orc/items/weapons/
final_realms_fluffos_v1/lib/d/newbie/orc/tower/
final_realms_fluffos_v1/lib/d/vehicle/
final_realms_fluffos_v1/lib/doc/
final_realms_fluffos_v1/lib/doc/driver/
final_realms_fluffos_v1/lib/doc/driver/concepts/
final_realms_fluffos_v1/lib/doc/driver/driver/
final_realms_fluffos_v1/lib/doc/driver/efuns/arrays/
final_realms_fluffos_v1/lib/doc/driver/efuns/bitstrings/
final_realms_fluffos_v1/lib/doc/driver/efuns/communication/
final_realms_fluffos_v1/lib/doc/driver/efuns/core/
final_realms_fluffos_v1/lib/doc/driver/efuns/debugging/
final_realms_fluffos_v1/lib/doc/driver/efuns/filesystem/
final_realms_fluffos_v1/lib/doc/driver/efuns/interactive/
final_realms_fluffos_v1/lib/doc/driver/efuns/mappings/
final_realms_fluffos_v1/lib/doc/driver/efuns/objects/
final_realms_fluffos_v1/lib/doc/driver/efuns/security/
final_realms_fluffos_v1/lib/doc/driver/efuns/strings/
final_realms_fluffos_v1/lib/doc/driver/efuns/system/
final_realms_fluffos_v1/lib/doc/driver/efuns/types/
final_realms_fluffos_v1/lib/doc/driver/lpc/constructs/
final_realms_fluffos_v1/lib/doc/driver/lpc/types/
final_realms_fluffos_v1/lib/doc/driver/platforms/
final_realms_fluffos_v1/lib/doc/lpc/
final_realms_fluffos_v1/lib/doc/mail/
final_realms_fluffos_v1/lib/doc/man/
final_realms_fluffos_v1/lib/doc/man/html/
final_realms_fluffos_v1/lib/doc/man/html/applies/
final_realms_fluffos_v1/lib/doc/man/html/applies/parsing/
final_realms_fluffos_v1/lib/doc/man/html/driver/
final_realms_fluffos_v1/lib/doc/man/html/efuns/
final_realms_fluffos_v1/lib/doc/man/html/efuns/arrays/
final_realms_fluffos_v1/lib/doc/man/html/efuns/buffers/
final_realms_fluffos_v1/lib/doc/man/html/efuns/compile/
final_realms_fluffos_v1/lib/doc/man/html/efuns/floats/
final_realms_fluffos_v1/lib/doc/man/html/efuns/functions/
final_realms_fluffos_v1/lib/doc/man/html/efuns/general/
final_realms_fluffos_v1/lib/doc/man/html/efuns/numbers/
final_realms_fluffos_v1/lib/doc/man/html/efuns/parsing/
final_realms_fluffos_v1/lib/doc/man/local/
final_realms_fluffos_v1/lib/doc/man/local/applies/
final_realms_fluffos_v1/lib/doc/man/local/applies/interactive/
final_realms_fluffos_v1/lib/doc/man/local/applies/master/
final_realms_fluffos_v1/lib/doc/man/local/concepts/
final_realms_fluffos_v1/lib/doc/man/local/defines/
final_realms_fluffos_v1/lib/doc/man/local/driver/
final_realms_fluffos_v1/lib/doc/man/local/efuns/
final_realms_fluffos_v1/lib/doc/man/local/efuns/arrays/
final_realms_fluffos_v1/lib/doc/man/local/efuns/buffers/
final_realms_fluffos_v1/lib/doc/man/local/efuns/calls/
final_realms_fluffos_v1/lib/doc/man/local/efuns/compile/
final_realms_fluffos_v1/lib/doc/man/local/efuns/filesystem/
final_realms_fluffos_v1/lib/doc/man/local/efuns/floats/
final_realms_fluffos_v1/lib/doc/man/local/efuns/functions/
final_realms_fluffos_v1/lib/doc/man/local/efuns/general/
final_realms_fluffos_v1/lib/doc/man/local/efuns/interactive/
final_realms_fluffos_v1/lib/doc/man/local/efuns/internals/
final_realms_fluffos_v1/lib/doc/man/local/efuns/mappings/
final_realms_fluffos_v1/lib/doc/man/local/efuns/mudlib/
final_realms_fluffos_v1/lib/doc/man/local/efuns/numbers/
final_realms_fluffos_v1/lib/doc/man/local/efuns/objects/
final_realms_fluffos_v1/lib/doc/man/local/efuns/parsing/
final_realms_fluffos_v1/lib/doc/man/local/efuns/sockets/
final_realms_fluffos_v1/lib/doc/man/local/efuns/strings/
final_realms_fluffos_v1/lib/doc/man/local/efuns/system/
final_realms_fluffos_v1/lib/doc/man/local/historical/
final_realms_fluffos_v1/lib/doc/man/local/lfun/QC/
final_realms_fluffos_v1/lib/doc/man/local/lfun/events/
final_realms_fluffos_v1/lib/doc/man/local/lfun/monster/
final_realms_fluffos_v1/lib/doc/man/local/lfun/properties/
final_realms_fluffos_v1/lib/doc/man/local/lpc/
final_realms_fluffos_v1/lib/doc/man/local/lpc/constructs/
final_realms_fluffos_v1/lib/doc/man/local/lpc/types/
final_realms_fluffos_v1/lib/doc/man/local/standards/
final_realms_fluffos_v1/lib/doc/man/local/tutorials/
final_realms_fluffos_v1/lib/doc/man/local/tutorials/basic/
final_realms_fluffos_v1/lib/doc/man/local/tutorials/intermediate/
final_realms_fluffos_v1/lib/doc/man/mudos/applies/
final_realms_fluffos_v1/lib/doc/man/mudos/applies/interactive/
final_realms_fluffos_v1/lib/doc/man/mudos/applies/parsing/
final_realms_fluffos_v1/lib/doc/man/mudos/concepts/
final_realms_fluffos_v1/lib/doc/man/mudos/driver/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/arrays/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/buffers/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/calls/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/compile/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/filesystem/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/floats/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/functions/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/general/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/mappings/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/mixed/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/mudlib/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/numbers/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/parsing/
final_realms_fluffos_v1/lib/doc/man/mudos/lpc/constructs/
final_realms_fluffos_v1/lib/doc/man/mudos/lpc/types/
final_realms_fluffos_v1/lib/doc/races/
final_realms_fluffos_v1/lib/doc/races/old_race/
final_realms_fluffos_v1/lib/global/virtual/
final_realms_fluffos_v1/lib/global/wiz_backup/
final_realms_fluffos_v1/lib/net/config/
final_realms_fluffos_v1/lib/net/daemon/chars/
final_realms_fluffos_v1/lib/net/inherit/
final_realms_fluffos_v1/lib/net/intermud3/
final_realms_fluffos_v1/lib/net/intermud3/cmds/
final_realms_fluffos_v1/lib/net/intermud3/save/
final_realms_fluffos_v1/lib/net/intermud3/services/
final_realms_fluffos_v1/lib/net/obj/
final_realms_fluffos_v1/lib/net/old/
final_realms_fluffos_v1/lib/net/old/intermud/
final_realms_fluffos_v1/lib/net/old/intermud/adm/
final_realms_fluffos_v1/lib/net/old/intermud/services/
final_realms_fluffos_v1/lib/net/old/intermud/udp/
final_realms_fluffos_v1/lib/net/virtual/
final_realms_fluffos_v1/lib/obj/b_day/
final_realms_fluffos_v1/lib/obj/chars/
final_realms_fluffos_v1/lib/obj/handlers/lists/
final_realms_fluffos_v1/lib/obj/handlers/useless/
final_realms_fluffos_v1/lib/obj/monsters/
final_realms_fluffos_v1/lib/obj/roomgen/
final_realms_fluffos_v1/lib/obj/soul/
final_realms_fluffos_v1/lib/obj/vegetation/
final_realms_fluffos_v1/lib/obj/weapons/oldsys/
final_realms_fluffos_v1/lib/open/
final_realms_fluffos_v1/lib/players/g/
final_realms_fluffos_v1/lib/releasefiles/d/heaven/
final_realms_fluffos_v1/lib/releasefiles/d/mudlib/
final_realms_fluffos_v1/lib/releasefiles/d/newbie/
final_realms_fluffos_v1/lib/releasefiles/doc/
final_realms_fluffos_v1/lib/releasefiles/players/g/
final_realms_fluffos_v1/lib/releasefiles/save/
final_realms_fluffos_v1/lib/releasefiles/save/environ/
final_realms_fluffos_v1/lib/releasefiles/save/roomgen/
final_realms_fluffos_v1/lib/releasefiles/secure/
final_realms_fluffos_v1/lib/releasefiles/w/
final_realms_fluffos_v1/lib/releasefiles/w/god/
final_realms_fluffos_v1/lib/room/
final_realms_fluffos_v1/lib/save/
final_realms_fluffos_v1/lib/save/environ/
final_realms_fluffos_v1/lib/save/roomgen/
final_realms_fluffos_v1/lib/scripts/
final_realms_fluffos_v1/lib/secure/crerem/
final_realms_fluffos_v1/lib/secure/dom/
final_realms_fluffos_v1/lib/secure/log/
final_realms_fluffos_v1/lib/secure/misc/
final_realms_fluffos_v1/lib/std/adnd/
final_realms_fluffos_v1/lib/std/commands/shadows/
final_realms_fluffos_v1/lib/std/creator/
final_realms_fluffos_v1/lib/std/curses/
final_realms_fluffos_v1/lib/std/curses/old_sys/
final_realms_fluffos_v1/lib/std/curses/shadows/
final_realms_fluffos_v1/lib/std/dom/
final_realms_fluffos_v1/lib/std/effects/
final_realms_fluffos_v1/lib/std/effects/healing/
final_realms_fluffos_v1/lib/std/effects/other/
final_realms_fluffos_v1/lib/std/effects/poisons/
final_realms_fluffos_v1/lib/std/environ/
final_realms_fluffos_v1/lib/std/guilds/
final_realms_fluffos_v1/lib/std/guilds/priests/samples/
final_realms_fluffos_v1/lib/std/guilds/wizards/
final_realms_fluffos_v1/lib/std/living/baldy/
final_realms_fluffos_v1/lib/std/living/divstuff/
final_realms_fluffos_v1/lib/std/paran/
final_realms_fluffos_v1/lib/std/poisons/
final_realms_fluffos_v1/lib/std/poisons/shadows/
final_realms_fluffos_v1/lib/std/poisons/weapons/
final_realms_fluffos_v1/lib/std/race_groups/
final_realms_fluffos_v1/lib/std/room/
final_realms_fluffos_v1/lib/std/room/old/
final_realms_fluffos_v1/lib/std/rooms/
final_realms_fluffos_v1/lib/std/shadows/
final_realms_fluffos_v1/lib/std/shadows/test_shad/
final_realms_fluffos_v1/lib/std/socket/
final_realms_fluffos_v1/lib/std/spells/
final_realms_fluffos_v1/lib/std/vaults/
final_realms_fluffos_v1/lib/tmp/
final_realms_fluffos_v1/lib/w/
final_realms_fluffos_v1/lib/w/god/
final_realms_fluffos_v1/old/
final_realms_fluffos_v1/win32/
inherit "/std/room";
/* adaptive prices added by Anirudh, March 1996 
   This is not meant to be exactly a free market system.
   Prices are adjusted to control (limit) the flow of items from 
   the shop into the mud and sales of items to the shop. */
/* Reworked by Hamlet July/August 1995. */
/* New features:
    1)  DOCUMENTATION!  
    2)  A more sensical scaled_value()  (makes more sense to me at least)
    3)  Ability to force-set the price the shop will offer for an item;
        set_resale_value(), adjust_resale_value(), query_resale_value(),
        prevent_resale(), and allow_resale()  all added to 
       /std/basic/misc.c (so, /std/object).
    4)  Stolen items are worth less now.  % modifier and 
        set_stolen_modifier() to alter that modifier.  Also
        set_stolen_modifier(), query_stolen_modifier(), and
        no_sell_if_stolen() in /std/basic/misc.c
    5)  A shop can be sell-only.  The commands "value" and "sell"
        are turned off for that.  Put sell_only() in setup();
    6)  You can specify a special function in your shop to be run
        ever time something is sold or bought.  call is
        set_sell_func("func") and set_buy_func("func");
        func should look like:  void func(object *stuff);
        Yes, this means that stuff is an ARRAY of items being bought
        or sold.

*/

// Edited 11 SEP 94 by Timion and Taniwha to fix the sell item bug.

/*
 * Original made who knows when.
 * Modified by bil to make the list a lot nicer.
 * Modified by Pinkfish to give shops types and make them send out
 * reps to sell/buy things from other shops.
 */

/* I am not sure whose code is whose any more.  This *is* an extensive
   rewrite, and a lot of it is now mine.  Credits stay, though, since
   I don't know which is which. - Hamlet
*/
/* Note:  rewrite is not done.  A lot of the code is original still.
        Don't expect that to be true for long (muhahaha)
*/

#include "money_adjust.h"
#include "money.h"
#include "move_failures.h"
#include "shop.h"
#include "armoury.h"
#include "timestuff.h"
#define MIN_PRICE 10

/* our_table is the table for setting sales goals */
object our_storeroom;
mixed our_table;
string storename;
mixed buy_mess, sell_mess, list_mess, value_mess, browse_mess,
open_cond, *other_shops;
/* the variables for item sales data and adjust time, Anirudh */
mapping market_data, race_prefs;
int last_changed_price,handled_since_last;
int no_price_reduce;

int amount_sold,
amount_bought;
string shop_type;
int stolen_modifier;  /* This will be a percent value */
int only_sell = 0;
string sell_func, buy_func;

void set_store_room(mixed ob);
string query_name(object ob);
string query_short(object ob);
int check_inv(object ob, string str);
string shop_list(mixed arr, int detail);
void do_buy(object *ob, int cost, object pl);
string shop_parse(string str, mixed ob, object client, string money,
  string extra);
void do_parse(mixed arr, mixed ob, object client, string money,
  string extra);
/* adaptive price functions, Anirudh */
int no_lower_price(int arg) { no_price_reduce = arg; }
int do_weight_min(int amt, int mass, int material, int sellbuy);
int do_cha_adjust(int amt, int cha, int updown);
int do_race_adjust(int amt, string race, int updown);
int set_race_pref(string race, int race_perc);
int query_multiplier(object ob);
void add_bought(object ob);
void add_sold(object ob);
void add_new_item(object ob,string str);
void check_adjust_prices();
void check_shop_table();
void check_cloned_items();
void adjust_prices();
void reset_market();
string query_storename() { return storename; }


void create() {
    market_data = ([ ]);
    race_prefs = ([ ]);
    seteuid((string)"/secure/master"->
      creator_file(file_name(this_object())));
    restore_object(file_name(this_object()));
    buy_mess = ({ "You buy $ob$ for $money$.\n",
      "$client$ buys $ob$.\n" });
    sell_mess = ({ "You sell $ob$ for $money$.\n",
      "$client$ sells $ob$.\n" });
    list_mess = "$extra$";
    value_mess = "The $ob$ is valued at $money$.\n";
    browse_mess = "The $ob$ costs $money$, it looks like:\n$extra$";
    open_cond = 1;
    other_shops = ({ });
    shop_type = "general";
    stolen_modifier = 33;  /* 33% of normal value */
    ::create();
}

/* These make spiffy messages for various actions. */
void set_sell_message(mixed str) { sell_mess = str; }
void set_buy_message(mixed str) { buy_mess = str; }
void set_value_message(mixed str) { value_mess = str; }
void set_browse_message(mixed str) { browse_mess = str; }
void set_list_message(mixed str) { list_mess = str; }

void set_open_condition(mixed str) { open_cond = str; }

mixed query_sell_mess() { return sell_mess; }
mixed query_list_mess() { return list_mess; }
mixed query_value_mess() { return value_mess; }
mixed query_buy_mess() { return buy_mess; }
mixed query_browse_mess() { return browse_mess; }

/* These initialize sell_func and buy_func, which are special functions
   that can be set to run when something is bought or sold.
*/
void set_sell_func(string str) {  sell_func = str; }
void set_buy_func(string str) { buy_func = str; }

mixed query_open_condition() { return open_cond; }

object check_storeroom()
{
    if(stringp(our_storeroom) || !our_storeroom)
    set_store_room(storename);
    return our_storeroom;

}

/* This is whether the shop is open or not.  open_cond can be
   an int (true/false). Or a string, in which case it 'points'
   to a function in the current object to run.  OR, it can be
   an array.  ({ "object/name", "function_name" }) where it runs
   "object/name"->function_name() to determine whether the shop is
   open.
*/
int test_open() {
    if (stringp(open_cond))
    return (int)call_other(this_object(), open_cond);
    if (intp(open_cond))
    return open_cond;
    return (int)call_other(open_cond[0], open_cond[1]);
}

int sell_only() {  only_sell = 1; return 1; }

int set_race_pref(string race, int race_perc) {
    int i;
    if(!m_sizeof(race_prefs)) race_prefs = ([ ]);
    if(race_perc != -1 && race_perc < 100) race_perc = 100;
    if(race == "good") {
    for(i=0;i<sizeof(GOOD_RACES);i++)
        race_prefs[GOOD_RACES[i]] = race_perc;
    return race_perc;
    }
    if(race == "neutral") {
    for(i=0;i<sizeof(NEUTRAL_RACES);i++)
        race_prefs[NEUTRAL_RACES[i]] = race_perc;
    return race_perc;
    }
    if(race == "evil") {
    for(i=0;i<sizeof(EVIL_RACES);i++)
        race_prefs[EVIL_RACES[i]] = race_perc;
    return race_perc;
    }
    race_prefs[race] = race_perc;
    return race_perc;
}

void init() {
    ::init();
    add_action("sell", "sell");
    add_action("buy", "buy");
    add_action("list", "list");
    add_action("browse", "browse");
    add_action("value", "value");
}

/* This determines how much the shopkeeper will offer for an item, according
   to its value.  It only gets called if set_no_resell() has not been called
   and resale_value has not been hand-set to something.
*/
int scaled_value(int n)
{
    int *prates;
    int i, tot;

    tot = 0;
    prates = PAY_RATES;
    for(i=0;( (i<sizeof(prates)) && (n > prates[i]) );i+=2);

    if(i>0)
    i-=2;/* prates[i] is now the rate-increment directly below the value. */

    tot = (n - prates[i]) * ((prates[i+2] / prates[i+3]) - 
      (prates[i] / prates[i+1]));
    tot /= (prates[i+2] - prates[i]);
    tot += (prates[i] / prates[i+1]);

    /* For those curious, we just defined a line segment.  Basically, we
     used  y - y1 = m(x - x1).  And found the y value for x = n.
     Read shop.h for better explanation.
    */

    return tot;
}

int set_stolen_modifier(int amt) { 
    if(amt > 100)
    amt = 100;
    if(amt < 0)
    amt = 0;

    stolen_modifier = amt;

    return amt;
}

/* This checks the player to make sure they have the item. 
   I *think* this is a paranoia check, but I'll leave it.
*/
int check_inv(object thing, string str)
{
    int i;
    object *inv = find_match(str,this_player());

    for(i =0; i < sizeof(inv); i++) {
    if(inv[i] == thing) return(1);
    }

    return(0);
}

int sell(string str) {
    object *obs, *selling, *cannot;
    mixed *m_array;
    int i, j, no, amt, material, mass, value, total_amt;
    string s;

    if (!test_open())
    return 0;

    if(only_sell) {
    tell_object(this_player(),"This shop does not buy merchandise.\n");
    return 1;
    }

    if (!str || str == "") {
    notify_fail("Usage: sell <objects>\n");
    return 0;
    }
    obs = find_match(str, this_player());
    if (!sizeof(obs)) {
    notify_fail("Nothing to sell.\n");
    return 0;
    }
    if(sizeof(obs) > MAX_OBS) {
    write("The shopkeeper can't cope with all those objects.\n");
    obs = obs[0..MAX_OBS - 1];
    }
    check_storeroom();
    selling = cannot = ({ });
    for (i=0;i<sizeof(obs);i++) {
    if( (obs[i]->query_value() > 0) && !obs[i]->do_not_sell() &&
      (obs[i]->query_resale_value() != -1) && 
      ((obs[i]->query_stolen_modifier() != -1) || 
        !obs[i]->query_property("stolen")) && !obs[i]->query_in_use()) {
        /* O.K. this SHOULD check to see if the item IS in the
           inventory
           before we move it */
        if(check_inv(obs[i],str)) {
        if (obs[i]->move(our_storeroom)) {
            if (obs[i]->short())
            cannot += ({ obs[i] });
            continue;
        }
        /* the call other (buried) in the below is so that we can update 
           /std/shop and have all the shops prices fall in line
           consistently */
        amt = obs[i]->query_resale_value();
        if(!amt) {
            amt = (int)"/std/shop"->scaled_value((int)obs[i]->query_value());
            if(amt > MAX_AMOUNT)
            amt = MAX_AMOUNT;
        }

        /* Let's not let something sell back for more than it was bought
           for */
        if(amt > obs[i]->query_value())
            amt = obs[i]->query_value();

        /* "hot" goods lose value!  */      
        if(obs[i]->query_property("stolen")) {
            if(obs[i]->query_stolen_modifier() == 0)
            amt = amt * stolen_modifier / 100;
            else
            amt = amt * obs[i]->query_stolen_modifier() / 100;
        }
        /* Adjusts price by item's adaptive multiplier (in 1/10 %) */
           /*Adjust by mudwide scale factor */
                amt=amt*MONEY_TRACKER->query_adj_fact(SBFLAG)/1000;
        amt=amt*query_multiplier(obs[i])/1000;
        amt = do_weight_min(amt,obs[i]->query_weight(),
          obs[i]->query_material(),1);
        amt = do_cha_adjust(amt,this_player()->query_cha(),1);
        if((amt = do_race_adjust(amt,this_player()->query_race(),1))==
          -101) { notify_fail("This shop refuses to deal with your "+
              "race.\n");
            amt = 0;
            return 0;
        }
        /* Counts how many of each item the shop buys */
        if(!(this_player()->query_creator()) &&
          strsrch(this_player()->query_name(),"test") == -1)
            add_bought(obs[i]);
        total_amt += amt;
        selling += ({ obs[i] });
        obs[i]->being_sold();
        }else if (obs[i]->short())
        cannot += ({ obs[i] });
        /* end of test if exists, not that this DOESN'T do the cannot that it should
        */
    }
    else if (obs[i]->short())
        cannot += ({ obs[i] });
    }
    if (!sizeof(selling)) {
    if (sizeof(cannot))
        notify_fail("You cannot sell "+query_multiple_short(cannot)+", maybe you are holding or wearing it, or just don't have one.\n");
    else
        notify_fail("Nothing to sell.\n");
    return 0;
    }
    amount_sold += total_amt;
    m_array = (mixed *)MONEY_HAND->create_money_array(total_amt);
    this_player()->adjust_money(m_array);
    if (sizeof(cannot))
    write("You cannot sell "+query_multiple_short(cannot)+", maybe you are wearing or holding it, or just don't have one.\n");
    do_parse(sell_mess, selling, this_player(),
      (string)MONEY_HAND->money_string(m_array), "");
    if(sell_func)  call_other(this_object(),sell_func,selling,total_amt);
    return 1;
}

int buy(string str) {
    int i, amt, material, mass, ob_amt, total_cost, high_cost_flag;
    object *obs, *to_buy, *cannot, *too_much;
    string s;

    if (!test_open())
    return 0;

    if (!str || str == "") {
    notify_fail("Usage: buy <objects>\n");
    return 0;
    }
    check_storeroom();
    obs = find_match(str, our_storeroom);
    if (!sizeof(obs)) {
    notify_fail("Cannot find "+str+".\n");
    return 0;
    }
    if(sizeof(obs) > MAX_OBS) {
    write("The shopkeeper can't cope with all those objects.\n");
    obs = obs[0..MAX_OBS-1];
    }
    to_buy = too_much = cannot = ({ });
    amt = (int)this_player()->query_value();
    while (i<sizeof(obs)) {
    /* adjusts price by adaptive multiplier of object */
      high_cost_flag = 0;
      if((ob_amt=(obs[i]->query_value()))>100000) {
         high_cost_flag = 1;
         ob_amt /= 100;
      }
       ob_amt=ob_amt*MONEY_TRACKER->
            query_adj_fact(SSFLAG)/1000;
         ob_amt=ob_amt*query_multiplier(obs[i])/1000;
/*
if(ob_amt>2000000) {
       ob_amt=0;
         secure_log_file("ani",this_player()->query_name()+" "+ctime(time())+
     "\n");
}
*/
    ob_amt = do_weight_min(ob_amt,obs[i]->query_weight(),
      obs[i]->query_material(),0);
    ob_amt = do_cha_adjust(ob_amt,this_player()->query_cha(),0);
    if((ob_amt = do_race_adjust(ob_amt,this_player()->query_race(),0))==
      -101) { notify_fail("This shop refuses to deal with your "+
          "race.\n");
        return 0;
    }
     if(obs[i]->query_property("playersetvalue")){
        high_cost_flag = 0;
        ob_amt = obs[i]->query_property("playersetvalue");
        // voided my hard work, better have a good reason
        secure_log_file("SHOPS",file_name(this_object())+" "+
                         file_name(obs[i])+" player set value\n");
     }
     if(high_cost_flag) ob_amt *= 100;
        if (ob_amt < 1) {
           ob_amt = 1;
         secure_log_file("SHOPS",file_name(this_object())+" "+
            file_name(obs[i])+" 0 value, "
               +this_player()->query_name()+"\n");
        }
    if (ob_amt > amt) {
        if (obs[i]->short())
        too_much += ({ obs[i] });
        obs = delete(obs, i, 1);
        continue;
    }
    if (obs[i]->move(this_player())) {
        if (obs[i]->short())
        cannot += ({ obs[i] });
        i++;
        continue;
    }
    obs[i]->move(our_storeroom);
    amt -= ob_amt;
    total_cost += ob_amt;
    to_buy += ({ obs[i] });
    i++;
    }
    amount_bought += total_cost;
    s = "";
    if (sizeof(cannot))
    s += "You cannot pick up "+query_multiple_short(cannot)+".\n";
    if (sizeof(too_much))
    s += capitalize(query_multiple_short(too_much))+" costs too much.\n";
    if(!sizeof(to_buy)) {
    if(s != "")
        notify_fail(s);
    else
        notify_fail("Nothing to buy.\n");
    return 0;
    } else {
    write(s);
    }
    do_buy(to_buy, total_cost, this_player());
    if(buy_func)  call_other(this_object(),buy_func,to_buy,total_cost);
    return 1;
}

void do_buy(object *obs, int cost, object pl) {
    int i;
    mixed fish;

    for (i=0;i<sizeof(obs);i++) {
    /* counts how many of each item the shop sells */
    if(!(this_player()->query_creator()) &&
      strsrch(this_player()->query_name(),"test") == -1)
        add_sold(obs[i]);
       obs[i]->remove_property("playersetvalue");
    obs[i]->move(pl);
    }
    pl->pay_money(fish = (int)MONEY_HAND->create_money_array(cost));
    do_parse(buy_mess, obs, pl,
      (string)MONEY_HAND->money_string(fish), "");
}
int list(string str) {

    if (!test_open())
    return 0;
    check_storeroom();    
    if(!our_storeroom)
    {
    notify_fail("The storeroom has been damaged, the shop is closed for now.\n");
    return 0;
    }
    if (!str || str == "" || str == "all") {
    do_parse(list_mess, this_object(), this_player(), "",
      shop_list(all_inventory(our_storeroom), 0));
    return 1;
    }
    do_parse(list_mess, this_object(), this_player(), "",
      shop_list(find_match(str, our_storeroom), 1));
    return 1;
}

int browse(string str) {
    object *obs;
    int i, ob_amt, mass, material, high_cost_flag;

    if (!test_open())
    return 0;
    if (!str || str == "") {
    notify_fail("Usage: browse <objects>\n");
    return 0;
    }
    check_storeroom();
    obs = find_match(str, our_storeroom);
    if (!sizeof(obs)) {
    notify_fail("Cannot find "+str+".\n");
    return 0;
    }
    for (i=0;i<sizeof(obs);i++) {
      high_cost_flag = 0;
      if((ob_amt=(obs[i]->query_value()))>100000) {
         high_cost_flag = 1;
         ob_amt /= 100;
      }
       ob_amt=ob_amt*MONEY_TRACKER->
            query_adj_fact(SSFLAG)/1000;
         ob_amt=ob_amt*query_multiplier(obs[i])/1000;
/*
if(ob_amt>2000000) {
       ob_amt=0;
}
*/
    ob_amt = do_weight_min(ob_amt,obs[i]->query_weight(),
      obs[i]->query_material(),0);
    ob_amt = do_cha_adjust(ob_amt,this_player()->query_cha(),0);
    if((ob_amt = do_race_adjust(ob_amt,this_player()->query_race(),0))==
      -101) { notify_fail("This shop refuses to deal with your "+
          "race.\n");
        return 0;
    }
     if(obs[i]->query_property("playersetvalue")){
        high_cost_flag = 0;
        ob_amt = obs[i]->query_property("playersetvalue");
     }
     if(high_cost_flag) ob_amt *= 100;
    if (ob_amt < 1) ob_amt = 1;
    do_parse(browse_mess, obs[i], this_player(),
      (string)MONEY_HAND->money_value_string(ob_amt),
      (string)obs[i]->long());
    }
    /*
    write("You look at "+obs[i]->short()+" it costs "+
         MONEY_HAND->money_string(obs[i]->query_money_array())+"\n"+
        obs[i]->long());
     */
    return 1;
}
int value(string str) {
    object *obs;
    int i, val, mass, material;

    if (!test_open())
    return 0;

    if(only_sell) {
    tell_object(this_player(),"This shop cannot appraise your goods.\n");
    return 1;
    }

    if (!str || str =="") {
    notify_fail("Usage: value <object>\n");
    return 0;
    }

    obs = find_match(str, this_player());
    if (!sizeof(obs)) {
    notify_fail("Cannot find "+str+".\n");
    return 0;
    }
    for (i=0;i<sizeof(obs);i++) {
    /* the call other is so that we can change the PAY_RATES array, and 
         then just update /std/shop to immediately and consistently effect 
         all shops */
    val = obs[i]->query_resale_value();

    if(!val) {
        val = (int)"/std/shop"->scaled_value((int)obs[i]->query_value());
        if (val > MAX_AMOUNT)
        val = MAX_AMOUNT;
    }

    if(val > obs[i]->query_value())
        val = obs[i]->query_value();

    /* "hot" goods lose value!  */      
    if(obs[i]->query_property("stolen")) {
        if(obs[i]->query_stolen_modifier() == 0)
        val = val * stolen_modifier / 100;
        else
        val = val * obs[i]->query_stolen_modifier() / 100;
    }
    /* adjust price offered by the adaptive multiplier of the item */
                val=val*MONEY_TRACKER->query_adj_fact(SBFLAG)/1000;
    val = val*query_multiplier(obs[i])/1000;
    val = do_weight_min(val,obs[i]->query_weight(),
      obs[i]->query_material(),1);
    val = do_cha_adjust(val,this_player()->query_cha(),1);
    if((val = do_race_adjust(val,this_player()->query_race(),1))==
      -101) { notify_fail("This shop refuses to deal with your "+
          "race.\n");
        return 0;
    }
    do_parse(value_mess, obs[i], this_player(),
      (string)MONEY_HAND->money_value_string(val),
      (string)(obs[i]->do_not_sell() || 
        (obs[i]->query_resale_value() == -1)) );
    }
    return 1;
}

string shop_list(mixed arr, int detail) {
    mapping inv, costs;
    object *list;
    string s, mon, *shorts, *vals;
    int i, j, mass, material, ob_amt, high_cost_flag;
    mixed ind;

    if (pointerp(arr))
    list = arr;
    else
    list = all_inventory(this_object()); 
    /* only keep track of things with shorts ;) */
    inv = ([ ]);
    for (i=0; i<sizeof(list); i++) {
    s = (string)list[i]->short();
    if (!s || !list[i]->query_value())
        continue;
    if(!stringp(s))
        s = "get a creator for this one!";
    if (inv[s])
        inv[s] += ({ list[i] });
    else
        inv[s] = ({ list[i] });
    }
    /* ok print it */
    s = "";
    shorts = m_indices(inv);
    if(!sizeof(shorts)) {
    if(detail)
        return "The shop is all out of what you wanted.\n";
    else
        return "The shop is totally out of stock.\n";
    }
    s = "You find on offer:\n";
    for (i=0; i<sizeof(shorts); i++) {
    ind = inv[shorts[i]];
    switch(sizeof(ind)) {
    case 1:
        s += "Our very last " + shorts[i];
        break;
    case 2..5:
        s += capitalize(query_num(sizeof(ind), 0) + " " +
          (string)ind[0]->query_plural());
        break;
    default:
        if(detail)
        s += capitalize(query_num(sizeof(ind), 0) + " " +
          (string)ind[0]->query_plural());
        else
        s += "A large selection of " +
        (string)ind[0]->query_plural();
    }
    if(detail) {
        costs = ([ ]);
        for(j=0;j<sizeof(ind);j++) {
        /* lists price after multiplier is applied */
      high_cost_flag = 0;
      if((ob_amt=(ind[i]->query_value()))>100000) {
         high_cost_flag = 1;
         ob_amt /= 100;
      }
       ob_amt=ob_amt*MONEY_TRACKER->
            query_adj_fact(SSFLAG)/1000;
         ob_amt=ob_amt*query_multiplier(ind[i])/1000;
        ob_amt = do_weight_min(ob_amt,ind[i]->query_weight(),
          ind[i]->query_material(),0);
        ob_amt = do_cha_adjust(ob_amt,this_player()->query_cha(),0);
        if((ob_amt = do_race_adjust(ob_amt,this_player()->query_race(),0))==
          -101) { notify_fail("This shop refuses to deal with your "+
              "race.\n");
            return 0;
        }
     if(ind[i]->query_property("playersetvalue")){
        high_cost_flag = 0;
        ob_amt = ind[i]->query_property("playersetvalue");
     }
     if(high_cost_flag) ob_amt *= 100;
        if (ob_amt < 1) ob_amt = 1;
        mon=(string)MONEY_HAND->money_value_string(ob_amt);
        if(!costs[mon])
            costs[mon] = ({ "" + (j + 1) });
        else
            costs[mon] += ({ "" + (j + 1) });
        }
        if(m_sizeof(costs) == 1) {
        s += " for " + m_indices(costs)[0];
        if(sizeof(m_values(costs)[0]) > 1)
            s += " each.\n";
        else
            s += ".\n";
        } else {
        s += ":-\n";
        vals = m_indices(costs);
        for(j=0;j<sizeof(vals);j++)
            s += "  [#" + implode(costs[vals[j]], ",") + "] for " + vals[j] +
            ".\n";
        }
    } else {
        s += ".\n";
    }
    }
    return s;
}
void set_store_room(mixed ob) {
    if (stringp(ob)) {
    storename = ob;
    our_storeroom = find_object(ob);
    if (!our_storeroom)
        call_other(ob, "??");
    our_storeroom = find_object(ob);
    }
    else if(objectp(ob))
    {
    storename = explode(file_name(ob),"#")[0];
    our_storeroom = ob;
    }   
if(our_table && our_storeroom) check_shop_table();
}
object query_store_room() { return our_storeroom; }

void do_parse(mixed arr, mixed ob, object client, string money,
  string extra) {
    if (stringp(arr))
    write(shop_parse(arr, ob, client, money, extra));
    else {
    write(shop_parse(arr[0], ob, client, money, extra));
    say(shop_parse(arr[1], ob, client, money, extra));
    }
}
string shop_parse(string str, mixed ob, object client, string money,
  string extra) {
    string s1, s2, s3, rest;

    rest = "";
    while(sscanf(str,"%s$%s$%s", s1, s2, s3) == 3)
    switch (s2) {
    case "ob" :
    if (pointerp(ob))
        str = s1+query_multiple_short(ob)+s3;
    else
        str = s1+ob->short()+s3;
    break;
    case "client" :
    str = s1+client->query_cap_name()+s3;
    break;
    case "extra" :
    str = s1+extra+s3;
    break;
    case "money" :
    str = s1+money+s3;
    break;
    default :
    rest = s1+"$"+s2+"$";
    str = s3;
    break;
    }
    return rest+str;
}


/*
 * The shop types are:
 *  Jewelry
 *  Armory
  *  Magic
 *  General
 */
object *query_stock(string type) {
    mixed *obs;
    int i;
    check_storeroom();
    obs = unique_array(all_inventory(our_storeroom), "query_shop_type");
    for (i=0;i<sizeof(obs);i++)
    if ((string)obs[i][0]->query_shop_type() == type)
        return obs[i];
    return ({ });
}

mixed *stats() {
    return ::stats() + ({
      ({ "total sold", amount_sold }),
      ({ "total bought", amount_bought }),
    });
}
string query_shop_type() { return shop_type; }
void set_shop_type(string ty) { shop_type = ty; }

/* The new adaptive pricing functions, keep track of buys and sells,
   return multipliers, figure out when and how to change multipliers,
   save and recall the shop's data */
int do_race_adjust(int amt, string race,int updown) {
    int temp;
    if(!m_sizeof(race_prefs)) race_prefs = ([ ]);
    if(!race_prefs[race]) return amt;
    if(race_prefs[race] == -1) return -101;
    if(updown) {
    temp = amt*100/race_prefs[race]+1;
    if(temp > amt) return amt;
    return temp;
    }
    else {
    temp = amt*race_prefs[race]/100-1;
    if(temp < amt) return amt;
    return temp;
    }
    return amt;
}

int do_weight_min(int amt,int mass, int material, int buysell) {
    if(buysell) {
    if (material == 2 && amt < mass) amt = mass;
    else if (material == 1 && amt < mass/4) amt = mass/4;
    else if (material == 3 && amt < mass/7) amt = mass/7;
    else if (amt < mass/10) amt = mass/10;
    }
    else {
    if (material == 2 && amt < mass*3/2) amt=mass*3/2;
    else if (material == 1 && amt < mass*3/8 ) amt=mass*3/8;
    else if (material == 3 && amt < mass*3/14) amt=mass*3/14;
    else if (amt < mass*3/20) amt = mass*3/20;
    }
    return amt;
}

int do_cha_adjust(int amt, int cha, int updown) {
    int temp;
    if(!cha) return amt;
    if(cha > 19) cha = 19;
    if(cha > AVG_CHA) {
    temp = 10*(cha - AVG_CHA)*CHA_AD/(18-AVG_CHA);
    if(updown) {
        temp = amt*(1000+temp)/1000-1;
        if(temp < amt) return amt;
    }
    else {
        temp = amt*1000/(1000+temp)+1;
        if(temp > amt) return amt;
    }
    return temp;
    }
    if(cha < AVG_CHA) {
    temp = 10*(AVG_CHA-cha)*CHA_AD/(AVG_CHA-3);
    if(updown) {
        temp = amt*1000/(1000+temp)+1;
        if(temp > amt) return amt;
    }
    else {
        temp = amt*(1000+temp)/1000-1;
        if(temp < amt) return amt;
    }
    return temp;
    }
    return amt;
}

int query_multiplier(object ob) {
    int i;
    string item_path,*exper; 
    if (ob->query_property("fixed_price")) {
       secure_log_file("SHOPS",file_name(this_object())+" "+file_name(ob)+
                     " fixed price\n");
       return 1000;
    }
    if (!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
    exper = explode(file_name(ob),"#");
    item_path = exper[0];
    if(!mappingp(market_data))
    {
    market_data = ([ ]);
    return 1000;
    }
    if (market_data[item_path]) {
    if(only_sell && market_data[item_path][4] < 1000 &&
      no_price_reduce) {
        market_data[item_path][4] = 1000;
         secure_log_file("SHOPS",file_name(this_object())+" no reduce\n");
    }
    return market_data[item_path][4];
    }
    else 
    return 1000;
} 

/* note:  this is the function when the SHOP buys something */
void add_bought(object ob) {
    int i;
    string item_path;
    if (!m_sizeof(market_data)) 
    restore_object(file_name(this_object()),1);
    item_path = explode(file_name(ob),"#")[0];
    if (market_data[item_path])
    market_data[item_path][1]++;
    else {
    add_new_item(ob,item_path);
    if (market_data[item_path])
        market_data[item_path][1]++;
    }
    handled_since_last++;
    check_adjust_prices();
    if (m_sizeof(market_data))
    save_object(file_name(this_object()));
}

/* and this is when the SHOP sells something */
void add_sold(object ob) {
    int i;
    string item_path;
    if (!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
    if(!m_sizeof(market_data)) return ; // Taniwha, no shop table.
    item_path = explode(file_name(ob),"#")[0];
    if (market_data[item_path])
    market_data[item_path][2]++;
    else {
    add_new_item(ob,item_path);
    if (market_data[item_path])
        market_data[item_path][2]++;
    }
    handled_since_last++;
    if (market_data[item_path][3] && market_data[item_path][2] >=
      3*market_data[item_path][3])
    adjust_prices();
    else
    check_adjust_prices();
    if (m_sizeof(market_data))
    save_object(file_name(this_object()));
}

void add_new_item(object ob, string item_path) {
    check_cloned_items();
    if (!market_data[item_path]) {
    market_data[item_path] = ({ ob->query_value(),0,0,0,1000,0 });
    }
}

void set_item_table(mixed ob) {
    if (stringp(ob)) {
    our_table = find_object(ob);
    if (!our_table)
        call_other(ob, "??");
    our_table = find_object(ob);
    }
    our_table = ob;
   if(our_storeroom && our_table) check_shop_table();
}
object query_item_table() { return our_table; }

/* this will put the numbers in the table into market_data */
void check_shop_table() {
    int i, clone_flag;
    string *item_paths,ite;
    mapping shelves;
    if (!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
    shelves = our_table->query_shelves();
    if(shelves) // Taniwha 1996
    item_paths = m_indices(shelves);
    if(sizeof(our_storeroom->query_room_clones())) clone_flag = 1;
    for (i=0;i<sizeof(item_paths);i++) {
    ite = 0;
    ite = explode(item_paths[i],".c")[0];
    if (!market_data[ite]) add_new_item(load_object(ite),ite);
    market_data[ite][3]=shelves[item_paths[i]][0];
    if (!clone_flag)
        our_storeroom->add_clone(ite,shelves[item_paths[i]][1]);
    }
    if (!clone_flag)
    our_storeroom->reset();
    if (m_sizeof(market_data))
    save_object(file_name(this_object()));
}

void check_cloned_items() {
    int i,count,price;
    object dummy;
    mixed *cloned_items;
   check_storeroom();
    cloned_items = our_storeroom->query_room_clones();
    for (i=0;i<sizeof(cloned_items);i++) {
    if (!cloned_items[i] || objectp(cloned_items[i])) {
        count++;
    }
    else {
        dummy = clone_object(cloned_items[i]);    
        if (dummy) {
        cloned_items[i] = explode(cloned_items[i],".c")[0];
        price = dummy->query_value();
        if (!market_data[cloned_items[i]] || 
          market_data[cloned_items[i]][0]!=price) {
            if (price < 10000) market_data[cloned_items[i]] = 
            ({ price,0,0,count*3,1000,1 });        
            else market_data[cloned_items[i]] =
            ({ price,0,0,count*2,1000,1 });
        }
        dummy->dest_me();
        }
        count = 0;
    }
    }
}

void check_adjust_prices() {
    int timelapsed = TIMEKEEPER->query_running_time()-
    last_changed_price;
    if (timelapsed <= 0 || last_changed_price == 0) {
    reset_market();
    }
    else if ( handled_since_last > 300 || timelapsed > BASE_WEEK) {
    adjust_prices();
    }
}

void adjust_prices() {
    string *item_paths,ite;        
    int i,goaldif,changemult,goal,timelapsed,devisor;
    if(!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
    timelapsed = TIMEKEEPER->query_running_time()-last_changed_price;
    /* don't want to overflow maxint here (percent of a week here) */
    if (timelapsed < 20000000) {
    timelapsed = timelapsed*100/BASE_WEEK;
    }
    else timelapsed = timelapsed*10/BASE_WEEK*10;
    item_paths = m_indices(market_data);
    for (i=0;i<sizeof(item_paths);i++) {
    ite = item_paths[i];
    if (market_data[ite][5]) {
        market_data[ite][5] = 0;
        market_data[ite][1]=market_data[ite][2]=0;
        continue;
    }
    /* going to deal in 100ths of items... */
    goal = market_data[ite][3]*timelapsed;
    goaldif=100*(market_data[ite][2]-market_data[ite][1])-goal;
    if (goal) {
        if (goal > 100*market_data[ite][2])
        changemult = goaldif*goaldif/goal;
        else
        {
        // Taniwha /0 insanities
        if(market_data[ite][2] == 0) changemult = 1;
        else changemult = goaldif*goaldif/100/market_data[ite][2];
        }
        if (goaldif > 0) {
        if (changemult > 2000) changemult = 2000;
        market_data[ite][4] = market_data[ite][4]*
        (1000+changemult)/1000;
        }
        if (goaldif < 0) { 
        if (changemult > 1000) changemult = 1000;
        market_data[ite][4] = market_data[ite][4]*
        1000/(1000+changemult);
        if (market_data[ite][4] < MIN_PRICE)
            market_data[ite][4]=MIN_PRICE;
        }
        market_data[ite][1]=market_data[ite][2]=0;
    }
    else {
        goaldif+=100;
        devisor = 2*market_data[ite][2]+market_data[ite][1];
        if (!devisor) devisor = 10;
        changemult = goaldif*goaldif/(100*devisor);
        if (goaldif > 0) {
        market_data[ite][4] = market_data[ite][4]*11/10;
        if (market_data[ite][4] > 1000)
            market_data[ite][4] = 1000;
        }
        if (goaldif < 0) {
        if (changemult > 2000) changemult = 2000;
        market_data[ite][4] = market_data[ite][4]*
        1000/(1000+changemult);
        if (market_data[ite][4]<MIN_PRICE)
            market_data[ite][4]=MIN_PRICE;
        }
        market_data[ite][1]=market_data[ite][2]=0;
        if (!market_data[ite][3] && market_data[ite][4] == 1000)
        market_data = m_delete(market_data,ite);
    }
    }        
    last_changed_price = TIMEKEEPER->query_running_time();
    handled_since_last = 0;
    if (m_sizeof(market_data))
    save_object(file_name(this_object()));
}
mapping query_market_data() {
    return market_data;
}

void reset_market() {
    string *item_paths,ite;
    int i;
    if (!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
    item_paths = m_indices(market_data);
    for (i=0;i<sizeof(item_paths);i++) {
    ite = item_paths[i];
    market_data[ite][5] = market_data[ite][1]=
    market_data[ite][2]=0;
    }
    last_changed_price = TIMEKEEPER->query_running_time();
    handled_since_last = 0;
    if (m_sizeof(market_data)) save_object(file_name(this_object()));
}
int set_md_value(string which_item,int which_one,int new_value) {
    if (!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
    if(market_data[which_item]) {
    market_data[which_item][which_one] = new_value;
    }
    if (m_sizeof(market_data)) save_object(file_name(this_object()));
    if(market_data[which_item])
    return market_data[which_item][which_one];
    else return -101;
}
/* clean up the storeroom when we die */
void dest_me()
{
    if(our_storeroom) our_storeroom->dest_me();
    ::dest_me();
}