dw_fluffos_v1/
dw_fluffos_v1/fluffos-1.22c11/
dw_fluffos_v1/fluffos-1.22c11/ChangeLog.old/
dw_fluffos_v1/fluffos-1.22c11/Win32/
dw_fluffos_v1/fluffos-1.22c11/compat/
dw_fluffos_v1/fluffos-1.22c11/compat/simuls/
dw_fluffos_v1/fluffos-1.22c11/include/
dw_fluffos_v1/fluffos-1.22c11/mudlib/
dw_fluffos_v1/fluffos-1.22c11/testsuite/
dw_fluffos_v1/fluffos-1.22c11/testsuite/clone/
dw_fluffos_v1/fluffos-1.22c11/testsuite/command/
dw_fluffos_v1/fluffos-1.22c11/testsuite/data/
dw_fluffos_v1/fluffos-1.22c11/testsuite/etc/
dw_fluffos_v1/fluffos-1.22c11/testsuite/include/
dw_fluffos_v1/fluffos-1.22c11/testsuite/inherit/
dw_fluffos_v1/fluffos-1.22c11/testsuite/inherit/master/
dw_fluffos_v1/fluffos-1.22c11/testsuite/log/
dw_fluffos_v1/fluffos-1.22c11/testsuite/single/
dw_fluffos_v1/fluffos-1.22c11/testsuite/single/tests/compiler/
dw_fluffos_v1/fluffos-1.22c11/testsuite/single/tests/efuns/
dw_fluffos_v1/fluffos-1.22c11/testsuite/single/tests/operators/
dw_fluffos_v1/fluffos-1.22c11/testsuite/u/
dw_fluffos_v1/fluffos-1.22c11/tmp/
dw_fluffos_v1/lib/
dw_fluffos_v1/lib/binaries/cmds/
dw_fluffos_v1/lib/binaries/cmds/creator/
dw_fluffos_v1/lib/binaries/cmds/living/
dw_fluffos_v1/lib/binaries/cmds/player/
dw_fluffos_v1/lib/binaries/d/admin/obj/
dw_fluffos_v1/lib/binaries/d/liaison/
dw_fluffos_v1/lib/binaries/global/virtual/
dw_fluffos_v1/lib/binaries/global/virtual/setup_compiler/
dw_fluffos_v1/lib/binaries/obj/handlers/autodoc/
dw_fluffos_v1/lib/binaries/obj/handlers/terrain_things/
dw_fluffos_v1/lib/binaries/obj/misc/
dw_fluffos_v1/lib/binaries/obj/misc/buckets/
dw_fluffos_v1/lib/binaries/obj/monster/
dw_fluffos_v1/lib/binaries/obj/reactions/
dw_fluffos_v1/lib/binaries/obj/reagents/
dw_fluffos_v1/lib/binaries/secure/cmds/creator/
dw_fluffos_v1/lib/binaries/secure/master/
dw_fluffos_v1/lib/binaries/std/
dw_fluffos_v1/lib/binaries/std/dom/
dw_fluffos_v1/lib/binaries/std/effects/object/
dw_fluffos_v1/lib/binaries/std/guilds/
dw_fluffos_v1/lib/binaries/std/languages/
dw_fluffos_v1/lib/binaries/std/races/
dw_fluffos_v1/lib/binaries/std/room/
dw_fluffos_v1/lib/binaries/std/room/basic/
dw_fluffos_v1/lib/binaries/std/shops/
dw_fluffos_v1/lib/binaries/std/shops/inherit/
dw_fluffos_v1/lib/binaries/www/
dw_fluffos_v1/lib/cmds/guild-race/
dw_fluffos_v1/lib/cmds/guild-race/crafts/
dw_fluffos_v1/lib/cmds/guild-race/other/
dw_fluffos_v1/lib/cmds/playtester/
dw_fluffos_v1/lib/cmds/playtester/senior/
dw_fluffos_v1/lib/d/admin/
dw_fluffos_v1/lib/d/admin/log/
dw_fluffos_v1/lib/d/admin/mapper/31-10-01/mapmaker/event/
dw_fluffos_v1/lib/d/admin/meetings/
dw_fluffos_v1/lib/d/admin/obj/
dw_fluffos_v1/lib/d/admin/room/we_care/
dw_fluffos_v1/lib/d/admin/save/
dw_fluffos_v1/lib/d/dist/
dw_fluffos_v1/lib/d/dist/mtf/
dw_fluffos_v1/lib/d/dist/pumpkin/
dw_fluffos_v1/lib/d/dist/pumpkin/chars/
dw_fluffos_v1/lib/d/dist/pumpkin/desert/
dw_fluffos_v1/lib/d/dist/pumpkin/gumboot/
dw_fluffos_v1/lib/d/dist/pumpkin/hospital/
dw_fluffos_v1/lib/d/dist/pumpkin/inherit/
dw_fluffos_v1/lib/d/dist/pumpkin/map/
dw_fluffos_v1/lib/d/dist/pumpkin/plain/
dw_fluffos_v1/lib/d/dist/pumpkin/pumpkin/
dw_fluffos_v1/lib/d/dist/pumpkin/save/
dw_fluffos_v1/lib/d/dist/pumpkin/squash/
dw_fluffos_v1/lib/d/dist/pumpkin/terrain/
dw_fluffos_v1/lib/d/dist/pumpkin/woods/
dw_fluffos_v1/lib/d/dist/start/
dw_fluffos_v1/lib/d/learning/TinyTown/buildings/
dw_fluffos_v1/lib/d/learning/TinyTown/map/
dw_fluffos_v1/lib/d/learning/TinyTown/roads/
dw_fluffos_v1/lib/d/learning/add_command/
dw_fluffos_v1/lib/d/learning/arms_and_weps/
dw_fluffos_v1/lib/d/learning/chars/
dw_fluffos_v1/lib/d/learning/cutnpaste/
dw_fluffos_v1/lib/d/learning/examples/npcs/
dw_fluffos_v1/lib/d/learning/examples/player_houses/npcs/
dw_fluffos_v1/lib/d/learning/examples/terrain_map/basic/
dw_fluffos_v1/lib/d/learning/functions/
dw_fluffos_v1/lib/d/learning/handlers/
dw_fluffos_v1/lib/d/learning/help_topics/npcs/
dw_fluffos_v1/lib/d/learning/help_topics/objects/
dw_fluffos_v1/lib/d/learning/help_topics/rcs_demo/
dw_fluffos_v1/lib/d/learning/help_topics/rooms/
dw_fluffos_v1/lib/d/learning/help_topics/rooms/crowd/
dw_fluffos_v1/lib/d/learning/help_topics/rooms/situations/
dw_fluffos_v1/lib/d/learning/items/
dw_fluffos_v1/lib/d/learning/save/
dw_fluffos_v1/lib/d/liaison/
dw_fluffos_v1/lib/d/liaison/NEWBIE/doc/
dw_fluffos_v1/lib/d/liaison/NEWBIE/save/oldlog/
dw_fluffos_v1/lib/db/
dw_fluffos_v1/lib/doc/
dw_fluffos_v1/lib/doc/creator/
dw_fluffos_v1/lib/doc/creator/autodoc/include/reaction/
dw_fluffos_v1/lib/doc/creator/autodoc/include/ritual_system/
dw_fluffos_v1/lib/doc/creator/autodoc/include/talker/
dw_fluffos_v1/lib/doc/creator/autodoc/include/terrain_map/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/baggage/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/clock/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/clothing/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/cont_save/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/corpse/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/money/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/monster/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/scabbard/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/service_provider/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/state_changer/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/wand/
dw_fluffos_v1/lib/doc/creator/autodoc/std/book_dir/
dw_fluffos_v1/lib/doc/creator/autodoc/std/key/
dw_fluffos_v1/lib/doc/creator/autodoc/std/learning/
dw_fluffos_v1/lib/doc/creator/autodoc/std/map/
dw_fluffos_v1/lib/doc/creator/autodoc/std/race/
dw_fluffos_v1/lib/doc/creator/autodoc/std/weapon_logic/
dw_fluffos_v1/lib/doc/creator/files/
dw_fluffos_v1/lib/doc/creator/policy/
dw_fluffos_v1/lib/doc/creator/room/
dw_fluffos_v1/lib/doc/effects/
dw_fluffos_v1/lib/doc/ideas/
dw_fluffos_v1/lib/doc/known_command/
dw_fluffos_v1/lib/doc/lpc/basic_manual/
dw_fluffos_v1/lib/doc/lpc/intermediate/
dw_fluffos_v1/lib/doc/new/add_command/
dw_fluffos_v1/lib/doc/new/handlers/
dw_fluffos_v1/lib/doc/new/living/
dw_fluffos_v1/lib/doc/new/living/race/
dw_fluffos_v1/lib/doc/new/living/spells/
dw_fluffos_v1/lib/doc/new/player/
dw_fluffos_v1/lib/doc/new/room/guild/
dw_fluffos_v1/lib/doc/new/room/outside/
dw_fluffos_v1/lib/doc/new/room/storeroom/
dw_fluffos_v1/lib/doc/object/
dw_fluffos_v1/lib/doc/playtesters/
dw_fluffos_v1/lib/doc/policy/
dw_fluffos_v1/lib/doc/weapons/
dw_fluffos_v1/lib/global/handlers/
dw_fluffos_v1/lib/global/virtual/setup_compiler/
dw_fluffos_v1/lib/include/
dw_fluffos_v1/lib/include/cmds/
dw_fluffos_v1/lib/include/effects/
dw_fluffos_v1/lib/include/npc/
dw_fluffos_v1/lib/include/shops/
dw_fluffos_v1/lib/net/daemon/chars/
dw_fluffos_v1/lib/net/inherit/
dw_fluffos_v1/lib/net/intermud3/
dw_fluffos_v1/lib/net/intermud3/services/
dw_fluffos_v1/lib/net/obj/
dw_fluffos_v1/lib/net/save/
dw_fluffos_v1/lib/net/smnmp/
dw_fluffos_v1/lib/net/snmp/
dw_fluffos_v1/lib/obj/amulets/
dw_fluffos_v1/lib/obj/b_day/
dw_fluffos_v1/lib/obj/examples/
dw_fluffos_v1/lib/obj/food/alcohol/
dw_fluffos_v1/lib/obj/food/chocolates/
dw_fluffos_v1/lib/obj/food/fruits/
dw_fluffos_v1/lib/obj/food/meat/
dw_fluffos_v1/lib/obj/food/nuts/
dw_fluffos_v1/lib/obj/food/seafood/
dw_fluffos_v1/lib/obj/food/vegetables/
dw_fluffos_v1/lib/obj/fungi/
dw_fluffos_v1/lib/obj/furnitures/artwork/
dw_fluffos_v1/lib/obj/furnitures/bathroom/
dw_fluffos_v1/lib/obj/furnitures/beds/
dw_fluffos_v1/lib/obj/furnitures/cabinets/
dw_fluffos_v1/lib/obj/furnitures/chairs/
dw_fluffos_v1/lib/obj/furnitures/chests/
dw_fluffos_v1/lib/obj/furnitures/clocks/
dw_fluffos_v1/lib/obj/furnitures/crockery/
dw_fluffos_v1/lib/obj/furnitures/cupboards/
dw_fluffos_v1/lib/obj/furnitures/cushions/
dw_fluffos_v1/lib/obj/furnitures/fake_plants/
dw_fluffos_v1/lib/obj/furnitures/lamps/
dw_fluffos_v1/lib/obj/furnitures/mirrors/
dw_fluffos_v1/lib/obj/furnitures/outdoor/
dw_fluffos_v1/lib/obj/furnitures/safes/
dw_fluffos_v1/lib/obj/furnitures/shelves/
dw_fluffos_v1/lib/obj/furnitures/sideboards/
dw_fluffos_v1/lib/obj/furnitures/sofas/
dw_fluffos_v1/lib/obj/furnitures/stoves/
dw_fluffos_v1/lib/obj/furnitures/tables/
dw_fluffos_v1/lib/obj/furnitures/wardrobes/
dw_fluffos_v1/lib/obj/handlers/
dw_fluffos_v1/lib/obj/handlers/autodoc/
dw_fluffos_v1/lib/obj/jewellery/anklets/
dw_fluffos_v1/lib/obj/jewellery/bracelets/
dw_fluffos_v1/lib/obj/jewellery/earrings/
dw_fluffos_v1/lib/obj/jewellery/misc/
dw_fluffos_v1/lib/obj/jewellery/necklaces/
dw_fluffos_v1/lib/obj/jewellery/rings/
dw_fluffos_v1/lib/obj/media/
dw_fluffos_v1/lib/obj/misc/buckets/
dw_fluffos_v1/lib/obj/misc/jars/
dw_fluffos_v1/lib/obj/misc/papers/
dw_fluffos_v1/lib/obj/misc/player_shop/
dw_fluffos_v1/lib/obj/misc/shops/
dw_fluffos_v1/lib/obj/misc/traps/
dw_fluffos_v1/lib/obj/monster/
dw_fluffos_v1/lib/obj/monster/godmother/
dw_fluffos_v1/lib/obj/monster/transport/
dw_fluffos_v1/lib/obj/plants/inherit/
dw_fluffos_v1/lib/obj/potions/
dw_fluffos_v1/lib/open/boards/
dw_fluffos_v1/lib/save/autodoc/
dw_fluffos_v1/lib/save/bank_accounts/
dw_fluffos_v1/lib/save/boards/frog/
dw_fluffos_v1/lib/save/books/bed_catalog/
dw_fluffos_v1/lib/save/creators/
dw_fluffos_v1/lib/save/mail/
dw_fluffos_v1/lib/save/mail/p/
dw_fluffos_v1/lib/save/newsrc/b/
dw_fluffos_v1/lib/save/newsrc/c/
dw_fluffos_v1/lib/save/newsrc/d/
dw_fluffos_v1/lib/save/newsrc/f/
dw_fluffos_v1/lib/save/newsrc/p/
dw_fluffos_v1/lib/save/newsrc/s/
dw_fluffos_v1/lib/save/newsrc/w/
dw_fluffos_v1/lib/save/players/c/
dw_fluffos_v1/lib/save/players/d/
dw_fluffos_v1/lib/save/players/g/
dw_fluffos_v1/lib/save/players/p/
dw_fluffos_v1/lib/save/players/s/
dw_fluffos_v1/lib/save/soul/data/
dw_fluffos_v1/lib/save/tasks/
dw_fluffos_v1/lib/save/vaults/
dw_fluffos_v1/lib/secure/cmds/lord/
dw_fluffos_v1/lib/secure/config/
dw_fluffos_v1/lib/secure/items/
dw_fluffos_v1/lib/secure/player/
dw_fluffos_v1/lib/soul/
dw_fluffos_v1/lib/soul/i/
dw_fluffos_v1/lib/soul/j/
dw_fluffos_v1/lib/soul/k/
dw_fluffos_v1/lib/soul/o/
dw_fluffos_v1/lib/soul/q/
dw_fluffos_v1/lib/soul/to_approve/
dw_fluffos_v1/lib/soul/u/
dw_fluffos_v1/lib/soul/v/
dw_fluffos_v1/lib/soul/wish_list/
dw_fluffos_v1/lib/soul/y/
dw_fluffos_v1/lib/soul/z/
dw_fluffos_v1/lib/std/creator/
dw_fluffos_v1/lib/std/effects/
dw_fluffos_v1/lib/std/effects/attached/
dw_fluffos_v1/lib/std/effects/external/
dw_fluffos_v1/lib/std/effects/fighting/
dw_fluffos_v1/lib/std/effects/other/
dw_fluffos_v1/lib/std/environ/
dw_fluffos_v1/lib/std/guilds/
dw_fluffos_v1/lib/std/hospital/
dw_fluffos_v1/lib/std/house/
dw_fluffos_v1/lib/std/house/onebedhouse/
dw_fluffos_v1/lib/std/house/onebedhut/
dw_fluffos_v1/lib/std/house/tworoomflat/
dw_fluffos_v1/lib/std/languages/
dw_fluffos_v1/lib/std/liquids/
dw_fluffos_v1/lib/std/nationality/
dw_fluffos_v1/lib/std/nationality/accents/
dw_fluffos_v1/lib/std/nationality/accents/national/
dw_fluffos_v1/lib/std/nationality/accents/regional/
dw_fluffos_v1/lib/std/npc/goals/
dw_fluffos_v1/lib/std/npc/goals/basic/
dw_fluffos_v1/lib/std/npc/goals/misc/
dw_fluffos_v1/lib/std/npc/inherit/
dw_fluffos_v1/lib/std/npc/plans/
dw_fluffos_v1/lib/std/npc/plans/basic/
dw_fluffos_v1/lib/std/outsides/
dw_fluffos_v1/lib/std/races/shadows/
dw_fluffos_v1/lib/std/room/basic/topography/
dw_fluffos_v1/lib/std/room/controller/
dw_fluffos_v1/lib/std/room/controller/topography/
dw_fluffos_v1/lib/std/room/furniture/games/
dw_fluffos_v1/lib/std/room/furniture/inherit/
dw_fluffos_v1/lib/std/room/inherit/carriage/
dw_fluffos_v1/lib/std/room/inherit/topography/
dw_fluffos_v1/lib/std/room/punishments/
dw_fluffos_v1/lib/std/room/topography/area/
dw_fluffos_v1/lib/std/room/topography/iroom/
dw_fluffos_v1/lib/std/room/topography/milestone/
dw_fluffos_v1/lib/std/shadows/
dw_fluffos_v1/lib/std/shadows/attached/
dw_fluffos_v1/lib/std/shadows/curses/
dw_fluffos_v1/lib/std/shadows/disease/
dw_fluffos_v1/lib/std/shadows/fighting/
dw_fluffos_v1/lib/std/shadows/room/
dw_fluffos_v1/lib/std/shops/controllers/
dw_fluffos_v1/lib/std/shops/objs/
dw_fluffos_v1/lib/std/shops/player_shop/
dw_fluffos_v1/lib/std/shops/player_shop/office_code/
dw_fluffos_v1/lib/std/socket/
dw_fluffos_v1/lib/www/
dw_fluffos_v1/lib/www/external/autodoc/
dw_fluffos_v1/lib/www/external/java/telnet/Documentation/
dw_fluffos_v1/lib/www/external/java/telnet/Documentation/images/
dw_fluffos_v1/lib/www/external/java/telnet/examples/
dw_fluffos_v1/lib/www/external/java/telnet/tools/
dw_fluffos_v1/lib/www/pics/
dw_fluffos_v1/lib/www/secure/creator/
dw_fluffos_v1/lib/www/secure/editors/
dw_fluffos_v1/lib/www/secure/survey_results/
/*  RCS stuff...  -*- LPC -*-
 * $Locker: pinkfish $
 *
 * $Id: basic_room.c,v 1.10 2001/01/14 03:28:59 ceres Exp pinkfish $
 *
 */

/**
 * The standard room inheritable.  This contains all the stuff needed to
 * construct a standard room.
 * @author Pinkfish
 * @see /std/room/outside.c
 */

#include <armoury.h>
#include <dirs.h>
#include <door.h>
#include <move_failures.h>
#include <room.h>
#include <position.h>
#include <situations.h>
#include <twilight.h>
#include <nroff.h>

inherit "/std/basic/cute_look";
inherit "/std/basic/desc";
inherit "/std/basic/extra_look";
inherit "/std/basic/light";
inherit "/std/basic/property";
inherit "/std/basic/export_inventory";
inherit "/std/basic/help_files";

nosave int do_setup;
nosave int *co_ord;
nosave int co_ord_calculated;
nosave string long_exit;
nosave string short_exit;
nosave string theft_handler;
nosave string *aliases;
nosave string *exits;

nosave object item;
nosave object chatter;
nosave object sitchanger;
nosave object effects;
nosave object linker;
nosave object terrain;
nosave object wall; 
nosave object *hidden_objects;
private nosave object* _use_internal_objects;
nosave mapping door_control;
nosave mixed *dest_other;
nosave int enchant_time;
nosave int background_enchant;
nosave float dynamic_enchant;
private nosave int last_visited;

// This is the day/night stuff.
nosave string *variablelongs;
nosave mixed variablechats;
nosave mixed variableitems;
nosave int is_day = -1;

varargs int add_item( mixed shorts, mixed desc, int no_plural );
int remove_item( string word );
varargs void room_chat( mixed *args, object chatobj );
void set_not_replaceable(int replace);
int query_not_replaceable();
void set_night_long( string str );

protected void create() {
   object *npcs;
   object virt_room;
   string *inhs;

   desc::create();
   extra_look::create();
   property::create();
   export_inventory::create();
   light::create();
   set_can_export_inventory();
   set_ignore_livings_in_inventory( 0 );
   aliases = ({ });
   exits = ({ });
   hidden_objects = ({ });
   _use_internal_objects = ({ });
   door_control = ([ ]);
   dest_other = ({ });
   seteuid( (string)"/secure/master"->creator_file( file_name(
           this_object() ) ) );
   add_property( "location", "inside" );
   add_property( "here", "on the floor" );
   if ( !do_setup ) {
      this_object()->setup();
      this_object()->reset();
   }
   if ( find_object( "/obj/handlers/map" ) ) {
      catch( "/obj/handlers/map"->check_map( file_name( this_object() ) ) );
   }
   if( (virt_room = find_object("/room/virtual") ) ){
     npcs = ({}) + all_inventory(virt_room);
     catch(npcs->real_room(file_name()));
   }

   // Check to see if the room is replaceable...
   inhs = inherit_list(this_object());
   if (sizeof(inhs) == 1) {
      if (replaceable(this_object(), ({ "setup" }))) {
         // Do it after a delay so that setup() has definately finished.
         call_out(function(string fname) {
           if (!query_not_replaceable()) {
             replace_program(fname);
           }
         }, 0, inhs[0]);
      }
   }
} /* create() */

/**
 * Returns 1 to indicate that this object is a room.
 * @return 1 to indicate that this is a room
 */
int query_is_room()
{
  return 1;
}

/**
 * Returns the current enchantment level of the room.  The enchanment
 * level controls things like what happens when you flip coins and
 * some special messages which give wizards some idea about magic
 * levels.
 * @return the current enchantment
 * @see set_enchant()
 */
int query_enchant() {
  int enchant_level =  to_int( floor( 0.5 + dynamic_enchant *
                        exp( -0.693 *
                             ( time() - enchant_time ) /
                             ENCHANT_HALF)) +
                 background_enchant );
  if ( enchant_level > 5000 ) {
    return 5000;
  }

  return enchant_level;
} /* query_enchant() */

/**
 * Sets the current enchantment level of the room.  The enchanment
 * level controls things like what happens when you flip coins and
 * some special messages which give wizards some idea about magic
 * levels.
 * When called from the room itself, it sets a background level of 
 * enchantment that don't decay, when called from another object it
 * sets the current enchantment which then decays towards the background 
 * level.
 * @param number the new enchantment level to set
 * @see query_enchant()
 */
int set_enchant(int number) {
  if (number < 0) {
    number = 0;
  }

  if (previous_object()==this_object()) { 
    /* setting up the background enchantment */
    background_enchant = (float) number;
    dynamic_enchant = 0.0;
    enchant_time = time();
  } else {
    /* by design, this can result in negative dynamic enchantment
     * it is definitely possible to suck out all magic in an area,
     * but it'll seep back in if the background level is higher.
     */
    dynamic_enchant = number - background_enchant;
    enchant_time=time();
  }
  return number;
} /* set_enchant() */

/**
 * Adds number to the current enchantment level of the room.
 * The enchanment level controls things like what happens when you
 * flip coins and some special messages which give wizards some 
 * idea about magic levels.
 * @param number the new enchantment level to set
 * @see query_enchant()
 */
int add_enchant( int number ) {
  dynamic_enchant = dynamic_enchant * exp( -0.693 * 
                                           ( time() - enchant_time ) /
                                           ENCHANT_HALF ) + number;
  enchant_time = time();
  return floor( 0.5 + dynamic_enchant ) + background_enchant;
} /* add_enchant() */
  
/**
 * This method sets the background enchantment of the room.
 * @return the theft handler of the room
 * @see set_enchant()
 */
void set_background_enchant( int number ) { 
  background_enchant = number;
} /* set_background_enchant() */

/**
 * This method sets the current dynamic enchantment of the room.
 * @return the theft handler of the room
 * @see set_enchant()
 */
void set_dynamic_enchant( float number ) { 
  dynamic_enchant = number;
  enchant_time = time();
} /* set_dynamic_enchant() */

/**
 * This method returns the background enchantment of the room.
 * @return the theft handler of the room
 * @see query_enchant()
 */
int query_background_enchant() { 
  return background_enchant;
} /* query_background_enchant() */

/**
 * This method returns the current dynamic enchantment of the room.
 * @return the theft handler of the room
 * @see query_enchant()
 */
float query_dynamic_enchant() { 
  dynamic_enchant = dynamic_enchant * exp( -0.693 * 
                                           ( time() - enchant_time ) /
                                           ENCHANT_HALF );
  enchant_time = time();
  return dynamic_enchant;
} /* set_dynamic_enchant() */

/**
 * Returns the current co-ordinates of the room.  The co-ordinates are
 * 3d, ({ x, y, z }).  So an array with three elements.
 * @return the current co-ordinates
 * @see set_co_ord()
 */
int *query_co_ord() {
  if ( pointerp( co_ord ) ) {
    return copy(co_ord);
  }
  return 0;
} /* query_co_ord() */

/**
 * Sets the current co-ordinates of the room.  The co-ordinates are
 * 3d, ({ x, y, z }).  So an array with three elements.
 * @param new_co_ord the new co-ordinates for the room.
 * @see query_co_ord()
 * @see query_co_ord_calculated()
 */
void set_co_ord( int *new_co_ord ) {
  if ( !pointerp( new_co_ord ) ) {
    write( "Warning: Co-ordinate must be an array.\n" );
    return;
  }
  if ( sizeof( new_co_ord ) != 3 ) {
      write( "Warning: The co-ordinate must have three elements.\n" );
      return;
  }
  co_ord = new_co_ord;
  if ( previous_object() == this_object() ) {
    co_ord_calculated = 0;
  } else {
    co_ord_calculated = 1;
  }
} /* set_co_ord() */

/**
 * This tells us if the co-ordinates were set or if they were calculated.
 * If they were set with set_co_ord then the value of this will be 0
 * otherwise it will be 1.
 * @return 1 if it is calculated, 0 if it is not
 * @see query_co_ord()
 * @see set_co_ord()
 */
int query_co_ord_calculated() { return co_ord_calculated; }

/**
 * This returns the long exit string.  This is calculated when it is
 * first needed by the calc_long_exit function.
 * @return the long exit string
 * @see calc_long_exit()
 * @see long()
 */
string query_long_exit() { return long_exit; }

/**
 * This method creates the long exit description used in the room long
 * descriptions.
 * @see query_long_exit()
 */
void calc_long_exit() {
  int i, add;
  string *words;
  mixed tmp;
  
  words = ({ });
  for ( i = 0; i < sizeof( dest_other ); i += 2 ) {
    tmp = dest_other[ i + 1 ][ ROOM_OBV ];
    if ( !tmp ) {
      continue;
    }
    if ( intp( tmp ) && tmp ) {
      add = 1;
    }
    if ( stringp( tmp ) ) {
      add = (int)call_other( this_object(), tmp, dest_other[ i ] );
    }
    if ( pointerp( tmp ) ) {
      add = (int)call_other( tmp[ 0 ], tmp[ 1 ], dest_other[ i ] );
    }
    if ( add ) {
      if(dest_other[i+1][ROOM_REL]) {
        words += ({ "$R$-"+ dest_other[ i ] +"$R$" });
      } else {
        words += ({ dest_other[i] });
      }
    }
  }
  switch ( sizeof( words ) ) {
  case 0 :
    long_exit = "There are no obvious exits.";
    break;
  case 1 :
    long_exit = "There is one obvious exit: "+ words[ 0 ];
    break;
  default :
    long_exit = "There are "+ query_num( sizeof( words ), 0 ) +
      " obvious exits: "+ query_multiple_short( words ) +
      ".";
  }
} /* calc_long_exit() */

/**
 * This method returns the current theft handler for the room.
 * @return the theft handler of the room
 * @see set_theft_handler()
 */
string query_theft_handler() { return theft_handler; }

/**
 * This method sets the current theft handler for the room.
 * @param word the new theft handler for the room
 * @see query_theft_handler()
 */
void set_theft_handler( string word ) { theft_handler = word; }

/**
 * This method returns the current exit aliases for the room.
 * @return the exit aliases of the room
 * @see add_alias()
 * @see remove_alias()
 */
string *query_aliases() { return copy( aliases ); }

/**
 * This method adds an exit alias to the room.
 * Aliases are convenient extra forms that can be attached to certain
 * exits. In the above functions, the variable names is either a string
 * or an array of strings and is, respectively, the alias or aliases
 * for the direction passed in word. Since, sometimes, the same alias
 * could be used for more than one exit, remove_alias() requires both
 * alias(es) and direction in order to remove the correct alias(es). 
 * @param names the exit names to alias
 * @param word the name to alias them too
 * @see query_aliases()
 * @see remove_alias()
 * @example
 * add_exit( "north", PATH +"dining_hall", "corridor" );
 * add_alias( ({ "enter", "enter hall", "enter dining hall" }), "north" );
 * @example
 * add_exit( "board carriage", PATH +"carriage", "door" );
 * add_alias( "board", "board carriage" );
 */
void add_alias( mixed names, string word ) {
  string name;

  if ( !aliases ) {
    aliases = ({ });
  }
  if ( pointerp( names ) ) {
    foreach ( name in names ) {
      add_alias( name, word );
    }
    return;
  }
  aliases += ({ word, names });
  if ( find_call_out( "calc_exits" ) == -1 ) {
    call_out( "calc_exits", 1 );
  }
} /* add_alias() */

/**
 * This method removes the exit aliases from the room.
 * Aliases are convenient extra forms that can be attached to certain
 * exits. In the above functions, the variable names is either a string
 * or an array of strings and is, respectively, the alias or aliases
 * for the direction passed in word. Since, sometimes, the same alias
 * could be used for more than one exit, remove_alias() requires both
 * alias(es) and direction in order to remove the correct alias(es). 
 * @param names the names to remove
 * @param word what they were aliased to
 * @see add_alias()
 * @see query_aliases()
 * @example
 * remove_exit( "board carriage" );
 * remove_alias( "board", "board carriage" );
 */
void remove_alias( mixed names, string word ) {
  int i;
  string name;

  if ( !aliases ) {
    return;
  }
  if ( pointerp( names ) ) {
    foreach ( name in names ) {
      remove_alias( name, word );
    }
    return;
  }
  for ( i = sizeof( aliases ) - 2; i >= -1; i -= 2 ) {
    if ( ( aliases[ i ] == word ) && ( aliases[ i + 1 ] == names ) ) {
      aliases = delete( aliases, i, 2 );  
    }
  }
} /* remove_alias() */

/**
 * This returns the current array of exits.
 * @return the exits array
 * @see add_exit()
 * @see remove_exit()
 * @see modify_exit()
 */
string *query_exits() { return copy(exits); }

/**
 * This method removes all the current exits in the room.
 * @see add_exit()
 * @see remove_exit()
 * @see modify_exit()
 */
void reset_exits() { exits = ({ }); }

/**
 * This method returns the current item object.
 * @return the current item object
 * @see add_item()
 */
object query_item() { return item; }

/**
 * This method returns the current chatter object.
 * @return the chatter object
 * @see add_room_chat()
 */
object query_chatter() { return chatter; }

/**
 * This method returns the current situation changer object.
 * @return the situation changer object
 * @see add_situation()
 * @see automate_situation()
 * @see change_situation
 */
object query_situation_changer() { return sitchanger; }

/**
 * This method returns the current effects object.
 * @return the effects object
 * @see add_effect()
 */
object query_effects() { return effects; }

/**
 * This method returns the current linker object.
 * @return the linker object
 */
object query_linker() { return linker; }

/**
 * This method returns the current terrain object.
 * @return the terrain object
 * @see add_room_chat()
 */
object query_terrain() { return terrain; }

/**
 * This method returns the current wall object.
 * @return the wall object
 * @see add_room_chat()
 */
object query_wall() { return wall; }

/**
 * This returns the current array of hidden objects.  The hidden objects
 * are used to allow things to not actually be in the room description
 * but be able to be manipulated by commands.
 * @see add_hidden_object()
 * @see remove_hidden_object()
 * @return the array of hidden objects
 */
object *query_hidden_objects() { return hidden_objects + ({ }); }

/**
 * This puts a hidden object into a room. A hidden object is an object that
 * exists in the room as far as all the find_match calls go. So, for look at's
 * and so on, but does not actually exist in the room so it does not show up
 * in the inventory when the player does a look. This is the method used for
 * putting signs and doors into rooms, that actually have shorts and you can
 * do things to, but do not show up in the inventory. The function init is also
 * called on these objects when init is called in the room. The only thing you
 * cannot put in your init function is an add_action. You can however define
 * up bunches of add_commands...
 * <p>
 * If this sounds complicated. Think of it as an object that IS in the room, but
 * you cannot see it. 
 * <p>
 * A word of warning here, the init() function will *not* be called on all
 * the players when the object is added as hidden.  This means that the
 * commands on it will not be available until the player re-enters the room.
 * You could get around this by moving everyone out of the room and
 * then back in again.
 * @example
 * #include <room.h>
 * sign = clone_object(PATH + SIGN);
 * add_hidden_object(sign);
 * @example
 * // Add a hidden object that has actions we want players to be able to
 * // use.
 * add_hidden_object(fluffy_container);
 * players = filter(all_inventory(), (: living($1) :));
 * players->move(ROOM_VOID);
 * // This forces init() to be recalled.  (This is realtivatively icky
 * // way of doing it, but the driver does not give us many alternatives).
 * players->move(this_object());
 * @see query_hidden_object()
 * @see remove_hidden_object()
 * @param thing the hidden object to add
 * @return 1 if successful, 0 on a failure
 */
int add_hidden_object( object thing ) {
  if ( member_array( thing, hidden_objects ) != -1 ) {
    return 0;
  }
  hidden_objects += ({ thing });
  return 1;
} /* add_hidden_object() */

/**
 * This method removes a hidden object.
 * @param thing the hidden object to remove
 * @return 1 on success, 0 on failure
 * @see add_hidden_object()
 * @see query_hidden_objects()
 */
int remove_hidden_object( object thing ) {
  int i;

  i = member_array( thing, hidden_objects );
  if ( i == -1 ) {
    return 0;
  }
  hidden_objects = hidden_objects[0..i - 1] + hidden_objects[i + 1..];
  return 1;
} /* remove_hidden_object() */

/**
 * This method adds an object whose interior bits want to be able to export
 * commands.  You can use this for tables an so on, so that stuff on a table
 * can still be used.
 * @param thing the thing whose inventory bits are to be exported
 */
void add_use_internal_object(object thing) {
   _use_internal_objects |= ({ thing });
} /* add_use_internal_objects() */

/**
 * This method removes an object whose interor bits want to export.
 * @param thing the object to remove
 */
void remove_use_internal_object(object thing) {
   _use_internal_objects -= ({ thing });
} /* remove_use_internal_object() */

/**
 * This method returns all the current use internal objects available.
 * @return the list of use internal objects here
 */
object* query_use_internal_objects() {
   return _use_internal_objects;
} /* query_use_internal_objects() */

/**
 * This returns the information about the door in the specified direction.
 * @param direc the direction to query the door in
 * @return the door control information
 * @see modify_exit()
 */
varargs mixed query_door_control( string direc ) {
   if ( !stringp( direc ) ) {
      return copy( door_control );
   }
   return door_control[ direc ];
} /* query_door_control() */

/**
 * This returns information about the exits in the room.  This is the
 * information set by modify_exit().  The values from this are probably
 * not very useful for normal coding.
 * @see modify_exit()
 * @see query_dest_dir()
 */
varargs mixed *query_dest_other( string direc ) {
  int i;

  if ( !stringp( direc ) ) {
    return copy( dest_other );
  }
  i = member_array( direc, dest_other );
  if ( i == -1 ) {
    return 0;
  }
  return copy( dest_other[ i + 1 ] );
} /* query_dest_other() */

/**
 * Returns an array containing just the destinations and directions used to
 * get there. This is useful for monster or whatever that you want to scan a
 * room for exits to leave out of. The array is of the format. ({ direction1,
 * destination1, direction2, destination2, ... })
 * <p>
 * The thing passed in is used as the basis for the relative directions
 * if it is an object.  If it is not an object then this is ignored
 * altogether.
 * @see query_dest_other()
 * @see add_exit()
 * @param thing used to get the relative directions according to thing
 * @return the array of direction, destination pairs
 */
varargs string *query_dest_dir( object thing ) {
  int i;
  string *ret;
  
  ret = ({ });
  for ( i = sizeof( dest_other ) - 2; i > -1; i -= 2 ) {
    if ( !dest_other[ i + 1 ][ ROOM_REL ] || !objectp( thing ) ) {
      ret += ({ dest_other[ i ], dest_other[ i + 1 ][ ROOM_DEST ] });
    } else {
      ret += ({ (string)thing->find_rel( dest_other[ i ] ),
                  dest_other[ i + 1 ][ ROOM_DEST ] });
    }
  }
  return ret;
} /* query_dest_dir() */

/**
 * This method just returns all the directions available to leave from
 * the room.
 * <p>
 * The thing passed in is used as the basis for the relative directions
 * if it is an object.  If it is not an object then this is ignored
 * altogether.
 * <p>
 * <b>Strawberries</b>
 * <p>
 * Starting from a above,<br>
 * Working slowly down under.<br>
 * Sliding up the sides<br>
 * Eating a meal, fresh cream and syrup.<br>
 * <p>
 * Round and round, and round again<br>
 * Grining micheviously<br>
 * One tongue at play<br>
 * Firm and hard, fresh strawberries today.
 *
 * @see query_dest_other()
 * @see add_exit()
 * @param thing used to get the relative directions according to thing
 * @return the array of directions
 */
varargs string *query_direc( object thing ) {
  int i;
  string *ret;
  
  ret = ({ });
  for ( i = sizeof( dest_other ) - 2; i > -1; i -= 2 ) {
    if ( !dest_other[ i + 1 ][ ROOM_REL ] || !objectp( thing ) ) {
      ret += ({ dest_other[ i ] });
    } else {
      ret += ({ (string)thing->find_rel( dest_other[ i ] ) });
    }
  }
  return ret;
} /* query_direc() */

/**
 * This method returns the destination room for an exit.
 * @param exit the exit name
 * @return the path of the destination room, or ROOM_VOID on error
 * @see query_dest_dir()
 * @example
 * #include <room.h>
 * string dest;
 *
 * dest = room->query_destination("south");
 * if (dest == ROOM_VOID) {
 *    do_error();
 * } else {
 *    do_move("south");
 * }
 */
string query_destination( string exit ) {
   int i;

   i = member_array( exit, dest_other );
   if ( ( i < 0 ) && objectp( this_player() ) )
      i = member_array( (string)this_player()->reorient_rel( exit ),
            dest_other );
   if ( i < 0 )
      return ROOM_VOID;
   return dest_other[ i + 1 ][ ROOM_DEST ];
} /* query_destination() */

/** @ignore yes */
int test_add( object thing, int flag ) { return 1; }

/** @ignore yes */
int test_remove( object thing, int flag, mixed dest ) { return 1; }

/** @ignore yes */
int add_weight( int number ) { return 1; }

/** @ignore yes */
int query_no_writing() { return 1; }

/** @ignore yes */
int query_decay() { return 10; }

/**
 * This method sets the default attack speed for the room.
 * This defaults to 15.
 * @return the default attack speed
 */
int attack_speed() { return 15; }

/**
 * This is the message to print instead of the room description when the
 * room is dark.  It defaults to the message "It's dark in here isn't it?".
 * @return the dark message
 * @see set_dark_mess()
 * @see long()
 * @see query_bright_mess()
 */
string query_dark_mess() {
  mixed dark_mess;

  if ( !stringp( dark_mess = query_property( "dark mess" ) ) ) {
    return "It's dark here, isn't it?";
  }
  return dark_mess;
} /* query_dark_mess() */

/**
 * This method sets the dark message associated with the room.
 * @param word the new dark message
 * @see query_dark_mess()
 * @see long()
 */
void set_dark_mess( string word ) {
    add_property( "dark mess", word );
} /* set_dark_mess() */

/**
 * This method returns the message to use when it is too bright to see in
 * the room.  It defaults to: "It's too bright to see anything!".
 * @return the message to print when it is too bright
 * @see query_dark_mess()
 * @see long()
 * @see set_bright_mess()
 */
string query_bright_mess() {
  mixed bright_mess;
 
  if ( !stringp( bright_mess = query_property( "bright mess" ) ) ) {
    return "It's too bright to see anything!";
  }
  return bright_mess;
} /* query_bright_mess() */

/**
 * This method sets the bright message associated with the room.
 * @param word the new bright message
 * @see query_bright_mess()
 * @see long()
 */
void set_bright_mess( string word ) { add_property( "bright mess", word ); }

/**
 * This method queries the size of the room.  The default size of a room
 * is 10x10x10.  A room can be any rectangular size, this method will return
 * an array of three elements if the room is a non-cube.  If it returns
 * a single number then the room is assumed to be cubic.
 * <p>
 * ({ north-south size, east-west size, up-down size })
 * <p>
 * The sizes are all radii's so they are half the actual width of the room.
 * @return the size of the room
 * @see set_room_size()
 * @see query_room_size_array()
 */
mixed query_room_size() {
   mixed room_size;

   room_size = query_property( "room size" );
   if ( !room_size ) {
      return 10;
   }
   return room_size;
} /* query_room_size() */

/**
 * This method returns the size of the room as a three element array always.
 * <p>
 * ({ north-south size, east-west size, up-down size })
 * <p>
 * The sizes are all radii's so they are half the actual width of the room.
 * @return the size of the room as a three element array
 * @see query_room_size()
 * @see set_room_size()
 */
int *query_room_size_array() {
   mixed room_size;

   room_size = query_room_size();
   if ( pointerp( room_size ) ) {
      return room_size;
   }
   return ({ room_size, room_size, room_size });
} /* query_room_size_array() */

/**
 * This method sets the rooms principle radii.  If the parameter isa single
 * number then the room is assumed to be cubic and dimension applies in
 * all directions.  If the input is a three element array then the elements
 * apply to all the directions.<br>
 * ({ north-south size, east-west size, up-down size })
 * <p>
 * The sizes are all radii's so they are half the actual width of the room.
 * @param number the new size of the room
 * @see query_room_size()
 * @see query_room_size_array()
 */
void set_room_size( mixed number ) {
   if ( intp( number ) ) {
      add_property( "room size", number );
      return;
   }
   if ( pointerp( number ) ) {
      if ( sizeof( number ) == 3 ) {
         add_property( "room size", number );
         return;
      }
   }
   write( "Room size must be an integer or an array of three integers.\n" );
} /* set_room_size() */

/** @ignore yes */
int id( string word ) { return 0; }

string expand_alias( string word ) {
   int i;

   if ( !aliases || !sizeof( aliases ) ) {
      return word;
   }
   i = member_array( word, aliases );
   if ( i == -1 ) {
      return word;
   }
   if ( i % 2 ) {
      return aliases[ i - 1 ];
   }
   return word;
} /* expand_alias() */

/**
 * This method returns the exit string used when in brief mode.
 * @return the brief exit string
 * @see calc_exit_string()
 */
string calc_short_exit_string() {
   int i, add;
   string *words;
   mixed tmp;

   words = ({ });
   for ( i = 0; i < sizeof( dest_other ); i += 2 ) {
      tmp = dest_other[ i + 1 ][ ROOM_OBV ];
      if ( !tmp ) {
         continue;
      }
      if ( intp( tmp ) && tmp ) {
         add = 1;
      }
      if ( stringp( tmp ) ) {
         add = (int)call_other( this_object(), tmp, dest_other[ i ] );
      }
      if ( pointerp( tmp ) ) {
         add = (int)call_other( tmp[ 0 ], tmp[ 1 ], dest_other[ i ] );
      }
      if ( add ) {
         if ( tmp = SHORTEN[ dest_other[ i ] ] ) { // is there a short form?
            if (dest_other[i+1][ROOM_REL]) {// is the exit relative
               words += ({ "$r$-"+tmp+"$r$" });
            } else {
               words += ({ tmp });
            }
         } else {                // no short form
            if (dest_other[i+1][ROOM_REL]) { // is the exit relative?
               words += ({ "$r$-"+dest_other[ i ]+"$r$" });
            } else {
               words += ({ dest_other[i] });
            }
         }
      }
   }
   if(!sizeof(words)) {
     return " [none]";
   }
   return " ["+ implode( words, "," ) +"]";
} /* calc_short_exit_string() */

/**
 * This method returns the short exit string.  The short exit string is the
 * string used in 'brief' mode of a players look.
 * @return the short exit string
 * @see calc_short_exit_string()
 * @see query_exit_string()
 */
string query_short_exit_string() {
   string tmp;
  
   if(short_exit) {
      return this_player()->colour_event("exits", "%^GREEN%^") +
     short_exit + "%^RESET%^";
   }
   
   tmp = calc_short_exit_string();
   if (!query_property("no exit cache")) {
      short_exit = tmp;
   }
   return this_player()->colour_event("exits", "%^GREEN%^") +
     tmp + "%^RESET%^";
} /* query_short_exit_string() */

/**
 * @ignore yes
 */
string enchant_string() {
   string words;
   
   words = (string)this_object()->query_property( "octarine_mess" );
   if ( words ) {
      return words +"\n";
   }
   switch ( query_enchant() ) {
      case 0 .. 49 :
         return "";
      case 50 .. 149 :
         return "There is the residual taste of magic in this place.\n";
      case 150 .. 299 :
         return "This place has seen some use of magic.\n";
      case 300 .. 499 :
         return "A considerable amount of magic has been used here.\n";
      case 500 .. 749 :
         return "A very large quantity of magic has been manipulated here.\n";
      case 750 .. 1000 :
         return "You can feel the Dungeon Dimensions trying to push in.\n";
      case 1001 .. 1500 :
         return "Little sparks flash in from the Dungeon Dimensions.\n";
      case 1501 .. 2000 :
         return "Apparations of things with lots of tentacles seem to be "
                "on the edge of your vision.\n";
      default :
         return "So much magic has been expended here that the area is in "+
               "danger of dumping itself into the Dungeon Dimensions.\n";
   }
} /* enchant_string() */

/** @ignore yes */
string long( string word, int dark ) {
   string ret;

   if ( !long_exit ) {
      calc_long_exit();
   }
   if ( dark ) {
      if ( dark < 0 ) {
         ret = this_object()->query_dark_mess() +"\n";
      } else {
         ret = this_object()->query_bright_mess() +"\n";
      }
      if ( query_property( "location" ) == "outside" ) {
         ret += "$weather$";
      }
      if ( ( dark == 1 ) || ( dark == -1 ) ) {
         ret = "$C$"+ a_short() +".  "+ ret +
           this_player()->colour_event("exits", "%^GREEN%^") +long_exit
           +"%^RESET%^\n";
         if ( query_contents( "" ) != "" ) {
            ret += this_player()->colour_event("inventory", "") + "Some objects you can't make out are here.%^RESET%^\n";
         }
      }
   } else {
      if ( query_property( "location" ) == "outside" ) {
         ret = "$long$";
      } else {
         ret = query_long();
      }

      if(!ret) {
         ret = "Erk, this room seems to be broken.\n";
      }
      
      word = calc_extra_look();
      if ( stringp( word ) && ( word != "" ) ) {
         ret += word;
      }
      if ( this_player()->query_see_octarine() ) {
         ret += enchant_string();
      }
      if ( query_property( "location" ) == "outside" ) {
         ret += "$weather$";
      }
      ret += this_player()->colour_event("exits", "%^GREEN%^") +
        long_exit +"%^RESET%^\n"+ query_contents( "" );
   }
   if ( query_property( "no exit cache" ) )  {
      long_exit = 0;
   }
   return ret;
} /* long() */

/** @ignore yes */
string pretty_short( object thing ) {
   int dark;

   if ( thing ) {
      dark = (int)thing->check_dark( (int)this_object()->query_light() );
   }
   return ::short( dark );
} /* pretty_short() */

/**
 * This method calculates the co-ordinates of this room.  The co-ordinates
 * are based on the surrounding rooms co-ordinates, if one of those rooms
 * are loaded.
 * @see query_co_ord()
 * @see modify_exit()
 */
void calc_co_ord() {
  int i, j, k, shift, *delta, *other_co_ord;
  string other;
   
  for ( i = sizeof( dest_other ) - 2; ( i > -1 ) && !co_ord; i -= 2 ) {
    /* if destination isn't loaded, skip it */
    other = dest_other[ i + 1 ][ ROOM_DEST ];
    if ( !find_object( other ) ) {
      continue;
    }
    /* if destination has no coordinates, skip it */
    other_co_ord = (int *)other->query_co_ord();
    if ( !other_co_ord ) {
      continue;
    }

    /* if exit had a delta defined, use that */
    j = -1;
    if ( delta = dest_other[ i + 1 ][ ROOM_DELTA ] ) {
      co_ord = copy( other_co_ord );
      if (pointerp(delta)) {
        k = 3;
        while ( k-- ) {
          /*
           * it's -= to make delta here the offset from this
           * room to the destination 
           */
          co_ord[ k ] -= delta[ k ];
        }
        continue;
      } else {
        j = member_array(delta, STD_ORDERS);
      }
    }

    /* if exit isn't a direction, skip it */
    if (j == -1) {
      j = member_array( dest_other[ i ], STD_ORDERS );
      if ( j == -1 ) {
        continue;
      }
    }

    co_ord = copy( other_co_ord );
    delta = query_room_size_array() + (int *)other->query_room_size_array();
    for ( k = 0; k < 3; k++ ) {
      co_ord[ k ] += STD_ORDERS[ j + 1 ][ k ] *
        ( delta[ k ] + delta[ k + 3 ] );
    }
    if ( ( j < 16 ) && dest_other[ i + 1 ][ ROOM_GRADE ] ) {
      /* one of the lateral directions */
      switch ( j ) {
      case 0 .. 1 :
        shift = delta[ 0 ] + delta[ 3 ];
        break;
      case 2 .. 3 :
        shift = delta[ 1 ] + delta[ 4 ];
        break;
      default :
        shift = delta[ 0 ] + delta[ 1 ] + delta[ 3 ] + delta[ 4 ];
      }
      co_ord[ 2 ] -= ( dest_other[ i + 1 ][ ROOM_GRADE ] * shift ) / 100;
      }
    co_ord_calculated = 1;
  }
} /* calc_co_ord() */

/**
 * This method calculates all the exit strings to be used for this room.
 */
void calc_exits() {
   int i, j;
   string exit, word, *tmp_al;

   exits = ({ });
   for ( i = sizeof( dest_other ) - 2; i > -1; i -= 2 ) {
      exit = dest_other[ i ];
      if ( member_array( exit, exits ) == -1 ) {
         exits += ({ exit });
         word = SHORTEN[ exit ];
         if ( stringp( word ) ) {
            exits += ({ word });
         }
      }
      tmp_al = aliases;
      j = member_array( exit, tmp_al );
      while ( j != -1 ) {
         if ( j % 2 ) {
            j--;
         } else {
            word = tmp_al[ j + 1 ];
            if ( member_array( word, exits ) == -1 ) {
               exits += ({ word });
            }
         }
         tmp_al = delete( tmp_al, j, 2 );
         j = member_array( exit, tmp_al );
      }
   }
} /* calc_exits() */

/** @ignore yes */
void init() {
  object ob;
  int i;
  
  /* This is some experimental XP stuff for exploration.
   *
  if(this_player() &&
     !this_player()->query_queued_commands() &&
     ((!last_visited && uptime() > 1800 + random(3600)) ||
      (random(time() - last_visited) > 900))) {
    this_player()->adjust_xp(random(random(500)), 0);
  }
  */

  
  // Has the day/night changed and do we care?
  if(is_day != -1 && ((WEATHER_HANDLER->query_day() > 0) != is_day)) {
    is_day = (1 - is_day);
    
    // Do longs;
    if(variablelongs && strlen(variablelongs[is_day]))
      set_long(variablelongs[is_day]);
    
    // Do items.
    if(variableitems) {
      for(i=0; i<sizeof(variableitems[1-is_day]); i += 2)
        remove_item(variableitems[1-is_day][i]);
      
      for(i=0; i<sizeof(variableitems[is_day]); i += 2)
        add_item(variableitems[is_day][i], variableitems[is_day][i+1]);
    }
    
    // Do chats.
    if(variablechats) 
      room_chat(variablechats[is_day]);
  }

  if(chatter)
    chatter->check_chat();

  if(sitchanger)
    sitchanger->check_situations();

  if(!sizeof(exits))
    calc_exits();

  if(!pointerp(co_ord))
    this_object()->calc_co_ord();

  foreach (ob in hidden_objects) {
    if ( ob && objectp( ob ) ) {
      ob->init();
    } else {
      hidden_objects -= ({ 0, ob });
    }
  }

  if (userp(this_player())) {
    foreach (ob in _use_internal_objects) {
      if (ob && objectp(ob)) {
        _use_internal_objects->find_inv_match("all", this_player())->init();
      } else {
        _use_internal_objects -= ({ 0, ob });
      }
    }
  }

  if(item)
    item->init();
}

/**
 * This method returns the set of move zones for this room.  This is used
 * by npcs to see which rooms they are allowed to move into.
 * @see add_zone()
 * @see /obj/monster->add_move_zone()
 */
string *query_zones() {
  string *zones;

  zones = query_property( "room zone" );
  if ( !zones ) {
    return ({ "nowhere" });
  }
  return zones + ({ });
} /* query_zones() */

/**
 * This method adds a move zone into the current list of movement zones
 * for the room.  The move zones are used by npcs to see which rooms they
 * are allowed to move into.
 * @see set_zone()
 * @see query_zones()
 * @see /obj/monster->add_move_zone()
 */
void add_zone(string zone) {
   string *zones;

   zones = query_property( "room zone" );
   if ( !zones ) {
      zones = ({ zone });
   } else {
      zones += ({ zone });
   }
   add_property( "room zone", zones );
} /* add_zone() */

/**
 * This method adds a move zone into the current list of zones.
 * This method is depreciated, add_zone should be used instead.
 * @see add_zone()
 * @see query_zones()
 */
void set_zone( string zone ) {
   add_zone(zone);
} /* set_zone() */

/**
 * This method determines if there is an exit in the specified direction.
 * @param direc the exit to test for
 * @return 1 if it exists, 0 if it does now
 */
int query_exit( string direc ) {
  return ( member_array( direc, dest_other ) != -1 );
} /* query_exit() */

/**
 * This method adds an exit to the room.   The direction is the direction in
 * which the exit should go.  This is something like "north" or "enter
 * gate".  The destination field is where the player will go when they
 * enter the exit.  The type is a set type that sets a whole bunch of
 * defaults for the room.  The destination can be either a strong
 * or an object.
 * <p>
 * The types are controlled by /obj/handlers/room_handler.c and the current
 * types and what this all means are:
 * <dl>
 * <dd>
 * <dl>
 * <dt>road
 * <dd>Wide road.
 * <dt>path
 * <dd>Narrower path
 * <dt>door
 * <dd>And exit with a door.  Defaults to closed but not locked.
 * <dt>secret
 * <dd>A secret door.  Defaults to closed but not locked.
 * <dt>corridor
 * <dd>A corridor (bing).
 * <dt>hidden
 * <dd>A hidden exit without a door
 * </dl>
 * </dl>
 * <p>
 * The room aliases are used to expand things for exits.  However they
 * don't expand the entire exit name.  They expand it in bits.  For
 * instance, if the exit was "enter live eel", you could
 * add_alias("eel", "live eel"); and add_alias("bing", "enter"); to
 * get both of the bits of the exit.  So "bing eel", "enter eel",
 * "bing live eel" etc would work.
 * @example
 * add_exit("north", PATH + "market2", "road");
 * add_alias("eel", "live eel");
 * add_exit("enter live eel", PATH + "live_eel", "secret");
 * @example
 * object fluffy_room;
 *
 * fluffy_room = clone_object(PATH + "fluffy_room");
 * add_exit("north", fluffy_room, "road");
 * @see modify_exit()
 * @see query_dest_dir()
 * @see remove_exit()
 * @see /obj/handlers/room_handler
 */
int add_exit( string direc, mixed dest, string type ) {
   mixed *stuff;

   if ( !dest_other ) dest_other = ({ });
   if ( member_array( direc, dest_other ) != -1 ) return 0;
   if ( objectp( dest ) )
      dest = file_name( dest );
   if ( dest[ 0 .. 0 ] != "/" )
      dest = "/"+ dest;
   stuff = ({ dest }) + (mixed *)ROOM_HANDLER->query_exit_type( type, direc );
   dest_other += ({ direc, stuff });
   if ( ( stuff = (mixed *)ROOM_HANDLER->query_door_type( type, direc,
                                                         dest ) ) ) {
      door_control[ direc ] = clone_object( DOOR_OBJECT );
      door_control[ direc ]->setup_door( direc, this_object(), dest, stuff,
                                         type);
      hidden_objects += ({ door_control[ direc ] });
      door_control[ dest ] = direc;
   }
   if ( find_call_out( "calc_exits" ) == -1 )
      call_out( "calc_exits", 1 );
   long_exit = 0;
   short_exit = 0;
   return 1;
} /* add_exit() */

/**
 * This method modifies the parameters for the exit.  See the docs in
 * /doc/new/room/modify_exit for more complete information.
 */
int modify_exit( mixed direc, mixed *data ) {
   int i, j, k;
   
   if(pointerp(direc)) {
     for(k = 0; k < sizeof(direc); k++) {
       modify_exit(direc[k], data);
     }
     return 0;
   }
   if ( ( i = member_array( direc, dest_other ) ) == -1 ) {
     return 0;
   }
   for ( j = 0; j < sizeof( data ); j+= 2 ) {
     switch ( lower_case( data[ j ] ) ) {
     case "message" :
       dest_other[ i + 1 ][ ROOM_EXIT ] = data[ j + 1 ];
       break;
     case "exit mess" :
     case "exit_mess" :
       dest_other[ i + 1 ][ ROOM_EXIT ] = data[ j + 1 ];
       break;
     case "move mess" :
       dest_other[ i + 1 ][ ROOM_MESS ] = data[ j + 1 ];
       break;
     case "linker mess" :
       dest_other[ i + 1 ][ ROOM_LINK_MESS ] = data[ j + 1 ];
       break;
     case "obvious" :
       dest_other[ i + 1 ][ ROOM_OBV ] = data[ j + 1 ];
       if ( !intp( data[ j + 1 ] ) )
         add_property( "no exit cache", 1 );
       long_exit = 0;
       short_exit = 0;
       break;
     case "function" :
       dest_other[ i + 1 ][ ROOM_FUNC ] = data[ j + 1 ];
       break;
     case "size" :
       dest_other[ i + 1 ][ ROOM_SIZE ] = data[ j + 1 ];
       break;
     case "upgrade" :
       dest_other[ i + 1 ][ ROOM_GRADE ] = data[ j + 1 ];
       break;
     case "downgrade" :
       dest_other[ i + 1 ][ ROOM_GRADE ] = -data[ j + 1 ];
       break;
     case "enter" :
       dest_other[ i + 1 ][ ROOM_ENTER ] = data[ j + 1 ];
       break;
     case "enter mess" :
     case "enter_mess" :
       if ( sizeof( dest_other[ i + 1 ][ ROOM_ENTER ] ) == 2 )
         dest_other[ i + 1 ][ ROOM_ENTER ] = replace( data[ j + 1 ],
           "$F", dest_other[ i + 1 ][ ROOM_ENTER ][ 1 ] );
       else
         dest_other[ i + 1 ][ ROOM_ENTER ] = data[ j + 1 ];
       break;
     case "dest" :
       dest_other[ i + 1 ][ ROOM_DEST ] = data[ j + 1 ];
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->set_dest( data[ j + 1 ] );
         door_control[ data[ j + 1 ] ] = direc;
       }
       break;
     case "relative" :
       dest_other[ i + 1 ][ ROOM_REL ] = data[ j + 1 ];
       break;
     case "look" :
       dest_other[ i + 1][ ROOM_LOOK ] = data[ j + 1 ];
       break;
     case "look func" :
       dest_other[ i + 1][ ROOM_LOOK_FUNC ] = data[ j + 1 ];
       break;
     case "no map" :
       dest_other[ i + 1][ ROOM_NO_MAP ] = data[ j + 1 ];
       break;
     case "delta" :
       dest_other[ i + 1][ ROOM_DELTA ] = data[ j + 1 ];
       break;
     case "closed" :
       if ( objectp( door_control[ direc ] ) ) {
         data[j+1] ? door_control[ direc ]->set_closed() :
           door_control[ direc ]->set_open();
       }
       break;
     case "open" :
       if ( objectp( door_control[ direc ] ) ) {
         data[j+1] ? door_control[ direc ]->set_open() :
           door_control[ direc ]->set_closed();
       }
       break;
     case "transparent" :
       if ( objectp( door_control[ direc ] ) ) {
         data[j+1] ? door_control[ direc ]->set_transparent() :
           door_control[ direc ]->reset_transparent();
       }
       break;
     case "stuck" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->set_stuck( data[ j + 1 ] );
       }
       break;
     case "locked" :
       if ( objectp( door_control[ direc ] ) ) {
         if(data[j+1]) {
           door_control[ direc ]->set_closed();
           door_control[ direc ]->set_locked();
         } else
           door_control[ direc ]->set_unlocked();
       }
       break;
     case "unlocked" :
       if ( objectp( door_control[ direc ] ) ) {
         data[j+1] ? door_control[ direc ]->set_unlocked() :
           door_control[ direc ]->set_locked();
       }
       break;
     case "autolock":
       if ( objectp( door_control [direc ] ) ) {
         door_control[ direc ]->set_autolock( data[ j + 1 ] );
       }
       break;
     case "key" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->set_key( data[ j + 1 ] );
       }
       break;
     case "other" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->set_other_id( data[ j + 1 ] );
       }
       break;
     case "difficulty" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->set_difficulty( data[ j + 1 ] );
       }
       break;
     case "door long" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->set_long( data[ j + 1 ] );
       }
       break;
     case "open/close func" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[direc]->set_open_trap(data[j+1][0], data[j+1][1]);
       }
       break;
     case "lock/unlock func" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[direc]->set_lock_trap(data[j+1][0], data[j+1][1]);
       }
       break;
     case "door short" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->set_short( data[ j + 1 ] );
       }
       break;
     case "double doors" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->set_how_many( data[ j + 1 ] );
       }
       break;
     case "one way" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->set_one_way( data[ j + 1 ] );
       }
       break;
     case "secret" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->remove_hide_invis( "secret" );
         if ( data[ j + 1 ] > 0 ) {
           door_control[ direc ]->add_hide_invis( "secret", 0,
                                                  data[ j + 1 ], 0 );
         }
       }
       break;
     case "undoor" :
       if ( objectp( door_control[ direc ] ) ) {
         door_control[ direc ]->go_away();
         hidden_objects -= ({ door_control[ direc ] });
         door_control = m_delete( door_control, direc );
         door_control = m_delete( door_control,
                                  dest_other[ i + 1 ][ ROOM_DEST ] );
         /* Hope that something takes care of the other side. */
       }
       break;
     }
   }
   return 1;
} /* modify_exit() */

/**
 * This method removes the specified exit from the room.
 * @see add_exit()
 * @see modify_exit()
 */
int remove_exit( string direc ) {
  int i;

  if ( !dest_other ) {
    dest_other = ({ });
    return 0;
  }
  i = member_array( direc, dest_other );
  if ( i == -1 )
    return 0;
  if ( door_control[ direc ] ) {
    door_control[ direc ]->dest_me();
    hidden_objects -= ({ door_control[ direc ] });
    door_control = m_delete( door_control, direc );
    door_control = m_delete( door_control, dest_other[ i + 1 ][ ROOM_DEST ] );
  }
  dest_other = delete( dest_other, i, 2 );
  if ( find_call_out( "calc_exits" ) == -1 )
    call_out( "calc_exits", 1 );
   long_exit = 0;
   short_exit = 0;
  return 1;
} /* remove_exit() */

/**
 * This method checks to see if the door is open.
 * @param direc the direction of the door
 * @return -1 on an error, 0 for closed, 1 for open
 * @see modify_exit()
 */
int query_door_open( string direc ) {
  if ( !objectp( door_control[ direc ] ) ) {
    return -1;
  }
  return (int)door_control[ direc ]->query_open();
} /* query_door_open() */

/**
 * This method checks to see if the exit is a relative one.
 * @param direc the direction to check
 * @see modify_exit()
 */
int query_relative( string direc ) {
   int i;

   i = member_array( direc, dest_other );
   if ( i == -1 ) {
      return 0;
   }
   return dest_other[ i + 1 ][ ROOM_REL ];
} /* query_relative() */

string query_look( string direc ) {
   int i;

   i = member_array( direc, dest_other );
   if ( i == -1 )
      return 0;
   if ( !dest_other[ i + 1 ] )
      return 0;
   return (string)evaluate(dest_other[ i + 1 ][ ROOM_LOOK ]);
} /* query_look() */

mixed *query_look_func( string direc ) {
  int i;
  if ( ( i = member_array( direc, dest_other ) ) == -1 ) return 0;
  if( !dest_other[ i + 1 ] ) return 0;
  return dest_other[ i + 1 ][ ROOM_LOOK_FUNC ];
}

/**
 * This method returns the size of the exit.  This is used to check to make
 * sure that people can enter it.
 * @param direc the direction of the exit to check
 * @return the size of the exit
 * @see modify_exit()
 */
int query_size( string direc ) {
  int i;
  if ( ( i = member_array( direc, dest_other ) ) == -1 ) return 0;
  if ( stringp( dest_other[ i + 1 ][ ROOM_SIZE ] ) )
    return (int)call_other( this_object(), dest_other[ i + 1 ][ ROOM_SIZE ] );
  if ( pointerp( dest_other[ i + 1 ][ ROOM_SIZE ] ) )
    return (int)call_other( dest_other[ i + 1 ][ ROOM_SIZE ][ 0 ],
        dest_other[ i + 1 ][ ROOM_SIZE ][ 1 ] );
  return dest_other[ i + 1 ][ ROOM_SIZE ];
} /* query_size() */
 
/** @ignore yes */
void event_magic( object channel, int amount, object caster ) {
   add_enchant( amount / 5 );
} /* event_magic() */

/** @ignore yes */
void event_theft( object command_ob, object thief, object victim,
                  object *stolen ) {
  log_file( "THEFT", "%s: %s stole %s from %s in %s\n",
            ctime( time() ), (string)thief->query_short(),
            implode( (string *)stolen->query_short(), ", " ),
            (string)victim->query_short(), file_name() );
  
  if ( stringp( theft_handler )) {
    if( theft_handler != "none" )
      theft_handler->handle_theft( this_object(), command_ob, thief,
                                   victim, stolen );
  } else
    "/obj/handlers/theft_handler"->handle_theft( this_object(), command_ob,
                                                 thief, victim, stolen );
} /* event_theft() */

/** @ignore yes */
void event_exit(object ob, string message, object to) {
    if(interactive(ob))
    last_visited = time();
} /* event_exit() */

/** @ignore yes */
int query_last_visited() { return last_visited; }

/**
 * This method adds an item description to a room.  This allows you to
 * set up objects which do not as such exist, but can be looked at for
 * instance.  There should be a lot of these in rooms.  The name of
 * the item can be multiple word, and the plural for it is
 * automagicaly added, unless the no_plural flag is set.  If the name
 * is an array all of the elements in the array respond to the
 * description.
 * <p>
 * If the desc is set to an array, you can use this for handling
 * things like read messages and so on too.  Every second element in
 * the array is the description/text to be printed and the other
 * element is the command upon which the text should be printed.  The
 * special command 'long' is used to set the long description.
 * <p>
 * The special type 'position' is used to allow people to use that
 * item to do positions on, like stand, sit, lie etc.
 * <p>
 * This method also allows you to setup add_command patterns.  If the
 * name after the verb is just a string, then the string will be printed
 * when that verb is used.  If it is just a function pointer then the
 * function will be evaluated and the return result printed.  If it
 * is an array, then the first element must be a function pointer and
 * the second optional element is the pattern to use for that method.
 * Multiple patterns and functions may be specified.
 * @param shorts the short description of the item
 * @param desc the description of the item
 * @param no_plural do not automaticaly add a plural for the item
 * @return 1 if successfully added, 0 if not
 * @example
 * add_item("green pot plant", "It is a nasty green pot plant lurking by "
 *                             "the door.\n");
 * @example
 * add_item(({ "telephone", "red phone" }),
 *          "Sitting in the corner is the red phone, it is staring unhappily "
 *          "into space thinking of cupcakes and better times.\n");
 * @example
 * add_item("small book", ({ "long", "A small red book with dots on the
 *                                   "cover.\n",
 *                           "read", "It says 'Rabbit!' in big letters.\n" }) );
 * @example
 * add_item("green leather couch",
 *          ({ "long", "The green leather couch is wonderful , so comfy!  "
 *                     " So... Comfy!\n"m
 *             "position", "the green leather couch" }) );
 * @example
 * add_item("rotating hologram", (: query_current_hologram_string() :));
 * @example
 * add_item("glue stick",
 *          ({ "long", "The glue stick looks sticky, like you could slime "
 *                     "something with it.\n",
 *             "slime", ({ (: do_slime :),
 *                         "<indirect:living> with <direct:object>" }) }) );
 * @see query_item()
 * @see remove_item()
 * @see modify_item()
 */
varargs int add_item( mixed shorts, mixed desc, int no_plural ) {
  if (!desc) {
     // A 0 description is a definate no no.
     printf("Error!  In %O add_item(%O, 0), not added.\n", file_name(),
                                                           shorts);
     return 0;
  }

  if ( !item ) {
     item = clone_object( ITEM_OBJECT );
  }
  item->setup_item( shorts, desc, no_plural );
  return 1;
} /* add_item() */

/**
 * This method will attempt to remove the item defined by the given string.
 * This will remove everything associated with that item, verbs, patterns,
 * everything.
 * @param word the name of the item to remove
 * @return 1 if successful, 0 on a failure
 * @example
 * add_item("frog", "Cute, green and sitting on a lilly pad.  Yes!\n");
 * ...
 * remove_item("frog");
 * @example
 * add_item(({ "big bad chicken", "clucker" }),
 *          "The big bad chicken sits and stares at you.\n");
 * ...
 * remove_item("big bad chicken");
 * @see add_item()
 * @see query_item()
 */
int remove_item( string word ) {
  if ( !item ) {
    return 1;
  }
  return (int)item->remove_item( word );
} /* remove_item() */

/**
 * This method will modify certain bits of the specified item.  This will
 * change only the bits of the pattern that are specified.  If you wish to
 * remove elements a better method would be to remove the item and
 * then readd it.  The format of the new_desc array is the same as in the
 * add_item code.
 * @param word the name of the item to change
 * @param new_desc the bits of the item to change
 * @see remove_item()
 * @see add_item()
 */
int modify_item( string word, mixed new_desc ) {
  if ( !item ) {
    return 0;
  }
  return (int)item->modify_item( word, new_desc );
} /* modify_item() */

/** @ignore yes */
void add_effect( string eff, mixed arg ) {
   effects = clone_object( "/std/shadows/misc/effects" );
   effects->setup_shadow( this_object() );
   effects->add_effect( eff, arg );
} /* add_effect() */

/**
 * This method sets up a linkage between the current room and othert
 * rooms.  The linkage broadcasts things like says and enter/exit
 * messages between the rooms.
 * <P>
 * The the dynamic preposition is used when someone enters/exits
 * the room, the static preposition is used when someone says something
 * in the room.  The dynamic proposition defaults to "into" and the
 * static preposition defaults to "in".
 * @param rooms the rooms to link together
 * @param d_prep the dynamic preposition
 * @param s_prep the static preposition
 * @param r_name the name of the room/area
 * @example
 * set_linker( ({ PATH + "room1", PATH + "room2", }),
 *             "into", "in", "fluffy square");
 */
varargs int set_linker( string *rooms, string d_prep, string s_prep,
    string r_name ) {
  if ( linker ) {
    return 0;
  }
  linker = clone_object( LINKER_OBJECT );
  linker->setup_shadow( this_object(), rooms, d_prep, s_prep, r_name );
  return 1;
} /* set_linker() */

int set_terrain( string terrain_name ) {
   if ( terrain ) {
      return 0;
   }
   terrain = clone_object( TERRAIN_OBJECT );
   terrain->setup_shadow( this_object(), terrain_name );
   set_not_replaceable(1);
   return 1;
} /* set_terrain() */

void set_wall( mixed *args ) {
   if ( !wall ) {
      wall = clone_object( WALL_OBJECT );
      wall->setup_shadow( this_object() );
   }
   wall->set_wall( args );
} /* set_wall() */

/**
 * This method sets the default position for the room.  Se the set
 * default position in the living code for a more complete
 * example of this.
 * @param pos the default position
 * @see /ostd/living/living->set_default_position()
 */
void set_default_position(mixed stuff) {
  add_property(DEFAULT_POSITION_PROPERTY, stuff);
} /* set_default_position() */

/**
 * This method returns the current default position asigned to this
 * room.
 * @return the current default position
 */
mixed query_default_position() {
   return query_property(DEFAULT_POSITION_PROPERTY);
} /* query_default_position() */

/**
 * This method tells us if the passed i nposition is
 * allowed in this type of room.
 * @param poss the position to check
 */
int is_allowed_position(string poss) {
  switch (poss) {
    case SITTING :
    case STANDING :
    case KNEELING :
    case LYING :
    case MEDITATING :
    case CROUCHING :
      return 1;
    default :
      return 0;
  }
} /* is_allowed_position() */

/** @ignore yes */
void dest_me() {
   int in_armoury, in_void;
   object thing, *things;

   if ( file_name( this_object() ) == ARMOURY )
      in_armoury = 1;
   if ( file_name( this_object() ) == ROOM_VOID )
      in_void = 1;

   /* If this is not the void, remove contents to /room/rubbish for
      recycling. Move players to the void */
   if ( !in_void ) {
      things = all_inventory( this_object() );
      foreach( thing in things ) {
         if ( userp( thing ) ) {
            thing->move_with_look( ROOM_VOID, "$N fall$s into the void." );
            continue;
         }
         if(thing->cleaning_room())
           continue;
         
         thing->move("/room/rubbish");
      }
   }
   if ( chatter )
      chatter->dest_me();
   if ( sitchanger )
      sitchanger->dest_me();
   if ( effects )
      effects->destruct_shadow( effects );
   if ( linker )
      linker->destruct_shadow( linker );
   if ( terrain )
      terrain->destruct_shadow( terrain );
   if(wall)
     wall->destruct_shadow(wall);
   if ( item )
      item->dest_me();
    
   if(door_control)
     foreach(thing in keys(door_control))
       if(objectp(thing))
         catch(thing->dest_me());

   if ( sizeof( hidden_objects ) )
      foreach( thing in hidden_objects ) {
         // Don't dest thing if it's hidden in multiple rooms
         if ( objectp( thing ) && ( thing->multiple_hidden() == 0 ) )
           catch( thing->dest_me() );
      }
   destruct( this_object() );
} /* dest_me() */

/**
 * This method sets the flag that enables or disables the room being
 * cleaned up.  If they flag is set to 1, then room is never cleaned up.
 * @param flag the room being cleaned up flag
 * @see query_keep_room_loaded()
 */
void set_keep_room_loaded(int flag) {
   add_property(ROOM_KEEP_PROP, flag);
} /* set_keep_room_loaded() */

/**
 * This method returns the status of the keep room loaded flag.  If they
 * flag is non-0 then the room with not be unloaded.
 * @return the status of the keep room loaded flag
 */
int query_keep_room_loaded() {
   return query_property(ROOM_KEEP_PROP);
} /* query_keep_room_loaded() */
 
/** @ignore yes */
int clean_up( int parent ) {
  if (parent) {
    return 0;
  }
  if (query_keep_room_loaded()) {
      return 0;
  }
  call_out("real_clean", 30 + random(120));
  return 1;
} /* clean_up() */

/** @ignore yes */
int real_clean() {
   object thing;

   /*
    * Don't clean up the room if:
    * there's a player in it, there's a unique npc in it and it's been visited
    * by a player in the last hour, it's a slave room or there's a corpse in
    * it.
    */
   foreach ( thing in all_inventory( this_object() ) ) {
     if ( thing->query_property( "player" ) ||
          (thing->query_property( "unique" ) &&
           last_visited > time() - 3600) ||
          thing->query_slave() ||
          thing->query_name() == "corpse") {
         return 0;
      }
   }
   dest_me();
   return 1;
} /* real_clean() */

/** 
 * This method returns all the matchable objects in the room.  This is used
 * by find_match to determine the group of objects to select from.
 * @param words the words to match on
 * @param looker the person doing the pmacthing
 * @return the array of objects to match on
 */
object *find_inv_match( string words, object looker ) {
   object *things;

   things = all_inventory( this_object() );
   if ( pointerp( hidden_objects ) ) {
      things += hidden_objects;
   }

   //
   // Only do these extra checks for players.
   //
   if (looker && userp(looker)) {
      /* Chekced to this filter thing to speed it up. */
      things = filter(things, (: $1 && $1->short(0) &&
                              (!$2 || $1->query_visible($2)) :), looker);
   }

   if ( item ) {
      things += ({ item });
   }
   return things;
} /* find_inv_match() */

/**
 * This method adds a sign into the room.  Any of these elements can
 * be set to 0, except the long description.
 * @param sign_long the long description of the sign
 * @param sign_read_mess the readable message on the sign
 * @param sign_short the short description of the sign
 * @param sign_name the name of the sign
 * @param sign_language the language the sign is written in
 * @return the object for the sign
 */
varargs object add_sign( string sign_long, mixed sign_read_mess, string
    sign_short, mixed sign_name, string sign_language ) {
  object sign;
  string* bits;

  sign = clone_object( "/std/object" );
  if ( !sign_name ) {
     sign_name = "sign";
  }
  if (pointerp(sign_name)) {
    bits = explode(sign_name[0], " ");
    sign->set_name( bits[<1] );
    sign->add_adjective( bits[0..<2]);
    sign->add_alias(sign_name[1..]);
  } else {
    bits = explode(sign_name, " ");
    sign->set_name( bits[<1] );
    sign->add_adjective( bits[0..<2]);
  }
  sign->set_long( sign_long );
  if ( !sign_language ) sign_language = "common";
  sign->set_read_mess( sign_read_mess, sign_language );
  sign->reset_get();
  if ( sign_short && ( sign_short != "" ) ) {
    sign->set_short( sign_short );
    sign->set_main_plural( pluralize( sign_short ) );
    sign->move( this_object() );
    sign->add_property("there", "here");
  } else hidden_objects += ({ sign });
  return sign;
} /* add_sign() */

/** @ignore yes */
void tell_door( string direc, string message, object thing ) {
   if ( objectp( door_control[ direc ] ) )
      door_control[ direc ]->tell_door( message, thing );
} /* tell_door() */

/** @ignore yes */
varargs mixed call_door( string direc, string func, mixed arg1, mixed arg2,
      mixed arg3 ) {
   if ( objectp( door_control[ direc ] ) )
      return (mixed)call_other( door_control[ direc ], func, arg1, arg2,
            arg3 );
} /* call_door() */

/**
 * This method determines if the specified exit is a door or not.
 * @param dest the destination to check for being a door
 * @see query_exit()
 * @see add_exit()
 */
string query_door( mixed dest ) {
   int i;
   string direc;
   mixed bing;

   if ( objectp( dest ) ) {
      dest = file_name( dest );
   }
   if ( !stringp( dest ) ) {
      return 0;
   }
   if ( bing = door_control[ dest ] ) {
      if ( !objectp( bing ) ) {
         direc = bing;
      }
   }
   if ( !direc ) {
      return 0;
   }
   bing = door_control[ direc ];
   if ( objectp( bing ) ) {
      return direc;
   }
   bing = clone_object( DOOR_OBJECT );
   i = member_array( direc, dest_other );
   bing->setup_door( direc, this_object(), dest, dest_other[ i + 1 ] );
   hidden_objects += ({ bing });
   door_control[ direc ] = bing;
   return direc;
} /* query_door() */

/**
 * This method stops all the room chats for the room.  It also removes
 * all the room chats, so if you want to have any more you must
 * add them again.
 * @see room_chat()
 */
void stop_room_chats() {
   if ( chatter ) {
      chatter->dest_me();
   }
} /* stop_room_chats() */

/**
 * Allows the chat interval to be changed.
 * @param min minimum interval between chats (seconds)
 * @param max maximum interval between chats (seconds)
 */
void set_chat_min_max( int min,int  max ) {
  if (chatter) chatter->set_chat_min_max(min,max);
}

/**
 * Adds more chats to the existing set of room chats
 * managed by this chatter object.
 * @param new_chats an array of new chat strings
 * @see remove_room_chats
 * @see query_room_chats
 * @see /std/room/basic/chatter
 */
void add_room_chats( string *new_chats ) {
  if (chatter) chatter->add_room_chats( new_chats );
} /* add_room_chats() */

/**
 * Removes chats from the set of room chats
 * managed by this chatter object.  If there are no chats
 * left the chatter is destructed.
 * @param dead_chats an array of chat strings to remove
 * @see add_room_chats
 * @see query_room_chats
 * @see /std/room/basic/chatter
 */
void remove_room_chats( string *dead_chats ) {
 if (chatter) chatter->remove_room_chats( dead_chats );
} /* remove_room_chats() */

/**
 * Returns the set of room chats
 * managed by the chatter object.  
 * @return pointer to the mixed array of chat args
 * @example
 *  ({ 120, 240, ({ "A frog gimbles the curtains.",
 *                  "A truly revolting smell drifts insidiously "
 *                  "from the rug." }) })
 * @see add_room_chats
 * @see remove_room_chats
 * @see room_chat
 * @see /std/room/basic/chatter
 */
mixed *query_room_chats() { 
  if (chatter) return chatter->query_room_chats();
  return 0;
} /* query_room_chats() */

/**
 * This method sets up the room chats.
 * Room chats are strings which are printed at (semi) random intervals
 * in rooms.  They are used to add atmosphere to a room. A chat will
 * be picked at random from the array of chats with a frequency
 * controlled by the times min and max. ie. one will be picked every n
 * seconds where is varies between min and max seconds. Please don't
 * make the values for min and max too small or the messages just
 * become annoying!
 * <p>
 * The argument to the room_chat method is an array of the format:<br>
 * ({ int min, int max, ({ string *chats }) }).  In place of a chat
 * string you may use "#function_name" where function_name is a
 * function that exists on the room object.
 * <p>
 * Repeated calls to this function overwrite the chats for
 * the default chatter.
 * @param args the room chat arguments
 * @param chatobj chatter object in case the default offends you.
 *                This argument may be omitted in which case you get 
 *                /std/room/basic/chatter.c
 * @example
 * room_chat(({ 120, 240, ({ "A string frog wanders past.",
 *                           "#make_soggy_bread",
 *                           "A trully revolting smell drifts insidiously "
 *                                "from the bakery." }) }) );
 * @see stop_room_chat()
 * @see add_room_chats()
 * @see remove_room_chats()
 * @see set_chat_min_max()
 */
varargs void room_chat( mixed *args, object chatobj ) {
   if ( !pointerp( args[ 2 ] ) ) {
      write( "Error: second argument of room_chat args is not an array.\n" );
      return;
   }
  if ( chatter ) {
    chatter->setup_chatter( this_object(), args );
    return;
  }
  if (objectp(chatobj)) chatter = chatobj;
  else chatter = clone_object( CHATTER_OBJECT );
  chatter->setup_chatter( this_object(), args );
} /* room_chat() */

/**
 * Set a situation changer (in place of the default).
 * If there is no argument you get the default:
 * /std/room/basic/situation_changer.
 * You call this before any other situation related functions.
 * If you create your own changer it should inherit one of
 * /std/room/basic/situation_changer or
 * /std/room/basic/multiroom_situation_changer or
 * otherwsie provide the functionality of those objects.
 * @param changer optional parameter specifying either a path for
 * the changer object or an existing object to use.
 * @see add_situation
 * @see start_situation
 * @see automate_situation
 * @see change_situation
 * @example
 * If you have a special changer object used for more than one room
 * then in setup for those rooms you should have:
 * set_situation_changer(load_object("/w/me/mychanger"));
 * Where /w/me/mychanger inherits 
 * /std/room/basic/multiroom_situation_changer
 */
varargs object set_situation_changer( mixed changer ) {
  if (stringp(changer)) {
    sitchanger = clone_object( changer );  
  } else if (objectp(changer)) {
    sitchanger = changer; 
  } else {
    sitchanger = clone_object( SITUATION_CHANGER_OBJECT );
  }
  return (sitchanger = sitchanger->set_room( this_object() ));
} /* set_situation_changer() */

/**
 * Adds a situation to the room.  These situations can be
 * invoked manually with start_situation or automatically via
 * automate_situation.
 * @param label string or number labelling the situation
 * @param sit a structure (class) containing all the bits
 * of the situation you want to add.  It should be a
 * variable of class situation.  You should include
 * situations.h where this class is defined.
 * Every part is optional.
 * eg. 
 * start_func  function to be called at start of situation 
 *             that might be used to load NPC's or anything
 *             beyond a message.
 * 
 *             The start function is passed the label, 
 *             a do_start_mess flag and the room object.  
 *             If the flag is 1 the situation is starting 
 *             rather than being reloaded.  Thus if 
 *             do_start_mess is 0 then you should avoid
 *             any obvious start messages and make it look
 *             like the situation is already underway.
 *
 * end_func    function to be called an the end of a situation.  
 *             The end function is only
 *             passed the label and the room object.
 *
 * start_mess  message told to the room at start of situation
 *
 * end_mess    message told to the room at end of situation
 *
 * extra_look  extra look string appended to rooms long 
 *             during the situation
 * chat_rate   an array of 2 numbers giving the minimum and
 *             maximum delay between chats.  If this is set
 *             then the chats are not merged with the
 *             existing chats but added independently with
 *             their own chat rates as given.
 *
 * chats       an array of chat strings to be active 
 *             during the situation 
 *
 * add_items   a mixed array of ({ item, item description }) 
 *             pairs to be active during the situation
 * 
 * random_words  sets of words to insert into text to replace 
 *               the special character #n where n is a number.
 *             The form of the array is ({  #1array, #2array, ... })
 *             where #1array = ({ "#1word1","#1word2",... }) etc.
 *             For the duration of the situation one of the strings
 *             in #1array is used to replace all instances of #1
 *             in the extra_look, start_mess, end_mess, chats
 *             and key and the long description part of the add_items.
 *             In a situation compounded of many situations
 *             the same random seed is used for choosing all #1's
 *             for each individual situation for the duration, 
 *             and a different seed for all #2's etc. 
 *
 * @see start_situation
 * @see end_situation
 * @see automate_situation
 * @see change_situation
 * @see add_item
 * @see room_chat
 * @see add_extra_look
 * @see set_situation_changer
 * @see make_situation_seed
 * @see /include/situation.h
 * @see goto learning  search  situation  for working examples
 * @example
 * #include <situations.h>
 *
 * class situation frogs;
 * frogs = new(class situation, 
 *     start_mess: "Water seeps out of the ground to form puddles.",
 *     extra_look: "There are large puddles on the ground here.",
 *     chat_rate: ({ 120,180 }),
 *     chats: ({"A hidden frog croaks quietly.",
 *              "There is a blooping sound." }),
 *     add_items:({ ({"puddle", "The puddles are dark and murky.  " 
 *                    "They will probably dry up given time." }) }) );
 * add_situation( "frogs", frogs );
 *
 * @example
 * add_situation( "ship", new(class situation, 
 *      start_mess: "A #1 ship hoves into view.",
 *      extra_look: "There is a #1 ship forging up the river.",
 *      chats: ({"The #1 ship's sails flap in the breeze.",
 *               "Shouts of sailors carry over to you from the #1 ship." }),
 *      add_items: ({ ({"ship", "The #1 ship, the \"#2\" is a small "
 *                    "sailing vessel that transports cargo up and "
 *                    "down the river."}) }),
 *      random_words: ({ ({ "old","waterlogged","heavily laden" }),
 *                       ({ "Jemima", "Old Sea Dog", "Randy Mermaid" }) })
 *      ) );
 * When the situation is started a random choice (eg. "old") replaces #1 
 * and a name (eg. "Jemima") replaces #2 in the text strings for
 * the duration.  
 * 
 * @example
 * add_situation( "frogs", new(class situation, 
 *      start_mess: "Water seeps out of the ground to form puddles.",
 *      extra_look: "There are large puddles on the ground here.",
 *      chats: ({"A hidden frog croaks quietly.",
 *               "There is a blooping sound." }),
 *      add_items: ({ ({"puddle", "The puddles are dark and murky.  " 
 *                      "They will probably dry up given time." }) }) ));
 * @example
 * This is an empty situation, useful for making pauses in the action.
 * add_situation( "pause", new(class situation) );
 */
void add_situation( mixed label, class situation sit ) {
  if (!sitchanger) {
    sitchanger = clone_object( SITUATION_CHANGER_OBJECT );
    sitchanger->set_room( this_object() );
  }
  sitchanger->add_situation( label, sit );
} /* add_situation() */

/**
 * Makes a seed value for the random part of when 
 * situations turn on and off.  The two ints should be
 * constant for a given room -- eg. the coordinates.
 * If this function is not called the seed is 
 * generated from the file_name of the object.
 * For this reason, rooms that are clones will produce
 * erratic results unless this function is called.
 * @param xval integer to use to make a seed (eg. x coordinate)
 * @param yval integer to use to make a seed (eg. y coordinate)
 */
void make_situation_seed(int xval, int yval) {
  if (sitchanger) sitchanger->set_seed(xval,yval);
} /* make_situation_seed() */

/**
 * Starts a situation previously added to the room.  These situations can be
 * invoked manually with start_situation or automatically via
 * automate_situation.  The call is passed to the situation
 * changer object.  If there isn't one nothing happens. 
 * @param label label for the situation as passed to add_situation
 * @param do_start_mess 0 to supress the start_mess string
 *        This is to fake it that a situation has been 
 *        going for a while when really you just loaded it.
 * @see add_situation
 * @see end_situation
 * @see automate_situation
 * @see change_situation
 */
void start_situation(int label, int do_start_mess) {
  if (sitchanger) 
    sitchanger->start_situation( label, do_start_mess );
} /* start_situation */

/**
 * Ends a situation previously added and started on the room.  
 * These situations can be invoked manually with start_situation 
 * or automatically via automate_situation. 
 * @param label label for the situation
 * @see add_situation
 * @see start_situation
 * @see automate_situation
 * @see change_situation
 */
void end_situation(mixed label) {
  if (sitchanger) sitchanger->end_situation( label );
} /* end_situation() */

/**
 * Starts one or more situations that will end after a
 * specified duration.  You can use an array and make
 * further situations commence when others end.
 * @param label (mixed) label of the situation to start up.  
 * If you pass an array such as ({ "frog1", "frog2" }) for the 
 * label then that set of situations are started one at
 * a time and the total duration is split evenly between them.
 * Label is usually an integer or a string or an array of
 * integers and/or strings.
 * If the string is a list of labels
 * separated by , then multiple situations
 * are started using those labels.
 * @param duration (int) total time (seconds) the overall situation 
 * should last.  You can put an array of durations -- one for each
 * situation if the label lists more than one situation and then
 * the overall time is the sum of the numbers.
 * -1 is a special duration.  It means that the labelled situation goes on
 * forever (and thus nothing after it in the array will ever go).
 * @param words is a list of replacements for #n in the text OR
 * a random number seed to use to choose words from random_words.
 * eg. ({ "#1", "frog", "#2", "honey" }) or 22
 *
 * @return handle useful for halting the changes later.  It is typically
 * a small positive integer.
 * @see shutdown_situation
 * @see add_situation
 * @see automate_situation
 * @see goto learning  search  situation  for working examples
 * @example
 * handle=change_situation( ({ "sew1","sew2" }), ({ 60,60 }) );
 * 
 * if (over) shutdown_situation( handle, ({ "sew1","sew2" }) );
 * @example
 * change_situation( ({ "background,sew1","background,sew2" }), 120 );
 * @example
 * change_situation( ({ "building_falling","rubble" }), ({ 120, -1 }) );
 * @example
 * add_situation( "boat1", 
 *   new(class situation,
 *     start_mess: "A little fishing boat comes up to the pier.  "
 *        "It has the name \"#1\" painted on the side.\n"
 *        "A fisherman jumps off the boat and ties its painter to a post.",
 *     chats: ({"The little boat bobs up and down next to the pier.",
 *              "A fisherman hops off the little boat." }),
 *     chat_rate: ({ 20, 30 }),
 *     extra_look: "There is a little boat here.",
 *     add_items: ({ ({ ({ "#1","little boat" }), 
 *       "There is little fishing boat tied up at the pier here.  "
 *       "The name \"#1\" is painted on the side."   }) }),
 *     end_mess: "The fishermen get back on board and "
 *        "the little boat moves on.",
 *     random_words: ({ ({ "Honey Toad", "Piker", "Bing" }) })
 *   )
 * );
 * 
 * change_situation( "boat1", 120, ({ "#1","Floating Egg" }) );
 */
varargs mixed change_situation( mixed label, mixed duration, mixed words ) {
  if (sitchanger) 
    return sitchanger->change_situation(label,duration,words,0);

  return 0;
} /* change_situation() */

/**
 * Automate starting and ending of a situation.
 * These situations can be invoked manually with start_situation.
 * The automated starting and ending is unaffected by the room 
 * unloading.  When the room reloads the situation will be 
 * restarted unless its duration is up.
 * You must include the file situations.h for the definitions
 * of the when masks.  The random seed needs to be set
 * consistently for the situations.  This is probably ok
 * unless your rooms are clones (see make_situation_seed). 
 * @param label (mixed) label of the situation to start 
 *  up.  If you pass an array such as ({ "frog1", "frog2" }) for the 
 * label then that set of situations are started one at
 * a time and the total duration is split evenly between them.
 * Label is usually an integer or a string or an array of
 * integers and/or strings.
 * If the string is a list of labels
 * separated by , then multiple situations
 * are started using those labels.
 * @param duration (int) total time (seconds) the overall situation 
 * should last.  You can put an array of durations -- one for each
 * situation if the label lists more than one situation and then
 * the overall time is the sum of the numbers.
 * -1 is a special duration.  It means that the situaton given that
 * duration is not part of the set but a special background or
 * default situation that occurs all the time except when
 * this automated situation is going.
 * @param when (int) a time of the day mask.  This limits when
 * the situation is allowed to occur.  The mask is composed of
 * the allowed hours in AM time ( 24 hours clock, (1<<hour) and 
 * combined with | (OR) ).   You can just use these
 * predefined masks and ignore how it works:
 *  WHEN_WEE_HOURS, WHEN_EARLY_MORNING, WHEN_LATE_MORNING, WHEN_AFTERNOON
 *  WHEN_EVENING, WHEN_LATENIGHT, WHEN_MIDDAY, WHEN_MORNING, 
 *  WHEN_EARLY_MORNING, WHEN_LATE_MORNING, WHEN_NIGHT, WHEN_DAY
 *  WHEN_ANY_TIME    
 * The masks are defined in /include/situations.h.
 * @param chance  (int) chance in 1000 of starting the situation
 *  This is tested every duration seconds.
 * @param category (optional) if you specify a cateory for the situation
 *                 then no situations with the same category will overlap.
 *                 category would usually be a string eg. "boats".
 * @see add_situation
 * @see start_situation
 * @see end_situation
 * @see situations.h
 * @see set_situation_changer
 * @see make_situation_seed
 * @see goto learning  search  situation  for working examples
 * @example
 * #include <situations.h>
 *
 *  automate_situation( "frog", 300, WHEN_ANY_TIME, 200 );
 *
 * This will automatically start the situation labelled "frog" 
 * at a random time that is any time of the day with a 200/1000
 * chance of it starting per 300 seconds.  It will last for
 * 300 seconds (5 minutes).  
 * @example
 *  automate_situation( ({"frog1,pond","frog2,pond"}), 240, 
 *                        WHEN_EVENING|WHEN_NIGHT, 300 );
 *
 * This will automatically start a situation that is a combination 
 * of "frog1" and "pond" followed by "frog2" and "pond".  They start
 * at a random time but only in the evening or at night.  
 * There will be a 300/1000 chance of 
 * it starting per 240 seconds.  Both the "frog1" and "frog2" 
 * situations will get half the total time (as there are two),  
 * 120 seconds each, for a total duration of 240 seconds (4 minutes).
 * @example
 *  automate_situation( ({"frog1,pond","frog2,pond"}), ({ 80,160 }), 
 *                        WHEN_EVENING|WHEN_NIGHT, 300 );
 * Same as previous example except the durations of the individual
 * parts are set: "frog1,pond" for 80 seconds followed by "frog2,pond"
 * for 160 seconds.  The total time is 80+160.
 */
varargs void automate_situation( mixed label, mixed duration, mixed when, 
    mixed chance, mixed category ) {
  if (sitchanger) 
    sitchanger->automate_situation(label,duration,when,chance,category);
} /* automate_situation() */

/**
 * Shuts down all current and pending situations.  It also turns off the
 * automated situation manager so no more are added.  It does not
 * destruct this object so all the add_situations are still loaded
 * and make be recommenced with automate_situation.  dest_me is
 * the appropriate call to permanently remove all situations.  The
 * call is passed to the situation changer object.  If none exists
 * then nothing happens.  The situation changer is created when
 * an add_situation call is performed. 
 * @see add_situation
 * @see automate_situation
 * @see change_situation
 */
void shutdown_all_situations() {
  if (sitchanger) sitchanger->shutdown_all_situations();
} /* shutdown_all_situations() */

/**
 * Shuts down a situation or set of situations initiated with
 * change_situation based on the call_out handle
 * returned by the call to change_situation.
 * @param callout call_out handle.  If 0 then the last
 * known handle is used.
 * @param label label or array of labels of situations to clean 
 * up with end_situation
 * @param the_room the room
 * @see automate_situation
 * @see change_situation
 */
void shutdown_situation(int call, mixed label) {
  if (sitchanger) sitchanger->shutdown_situation(call,label);
} /* shutdown_situation() */

/**
 * This method checks to see if the program is replaceable.
 * @return 1 if the program is not replaceable
 * @see set_not_replaceable()
 */
int query_not_replaceable() {
   return query_property(ROOM_NOT_REPLACE_PROGRAM_PROP);
} /* query_not_replaceable() */

/**
 * This method sets a property to make the program replaceable.  A program
 * will only be replaced if there is only a setup() function in the room.
 * A reset() or a create() will stop the room from being replace and in
 * fact any other function existing in there will stop it from being
 * replaced as well.
 * @pram replace 1 to make the room not replacable
 * @see query_not_replaceable()
 */
void set_not_replaceable(int replace) {
   add_property(ROOM_NOT_REPLACE_PROGRAM_PROP, replace);
} /* set_not_replaceable() */

/** @ignore yes */
mixed stats() {
   int i;
   mixed *stuff;
   stuff = ({ });
   for ( i = sizeof( dest_other ) - 2; i > -1; i -= 2 )
      stuff += ({
         ({ dest_other[ i ], dest_other[ i + 1 ][ ROOM_DEST ] })
      });
   if ( co_ord )
      stuff += ({
         ({ "co-ord x", co_ord[ 0 ] }),
         ({ "co-ord y", co_ord[ 1 ] }),
         ({ "co-ord z", co_ord[ 2 ] })
      });
   return light::stats() + property::stats() + stuff + ({
      ({ "short", short( 0 ) }),
      ({ "enchantment", query_enchant() }),
      ({ "background enchantment", background_enchant }),
      ({ "dynamic enchantment", dynamic_enchant }),
      ({ "enchantment time", enchant_time }),
      ({ "theft handler", theft_handler }),
   });
} /* stats() */

/**
 * This method sets the long description to display during the day time.
 * @param str the new day long description
 * @see query_day_long()
 * @see set_night_long()
 */
void set_day_long( string str ) {
  if(!variablelongs)
    variablelongs = allocate(2);

  variablelongs[DAY] = str;

  if(is_day == -1)
    is_day = (WEATHER_HANDLER->query_day() > 0);

  if(is_day == DAY)
    set_long(str);
}

/**
 * This method sets up the night long for the room.  This will be the
 * long description displayed at night in the room.
 * @param str the new night long description
 * @see set_day_long()
 * @see query_night_long()
 */
void set_night_long( string str ) {
  if(!variablelongs)
    variablelongs = allocate(2);

  variablelongs[NIGHT] = str;

  if(is_day == -1)
    is_day = (WEATHER_HANDLER->query_day() > 0);
  if(is_day == NIGHT)
    set_long(str);
}

/**
 * This method returns the long description of the room at night.  This is
 * used to print out different strings for rooms during the day and during
 * the night.
 * @return the night long for the room.
 */
string query_night_long() {

   if(variablelongs && strlen(variablelongs[NIGHT]))
     return variablelongs[NIGHT];
   
   return this_object()->query_long();
} /* query_night_long() */

/* Returns the long part of the description. */
private string return_long(mixed desc) {
  int ma;

  if(!pointerp(desc))
    return (string)desc;

  ma = member_array("long", desc);
  if(ma < 0)
    return "Error: No long found.";
  
  return (string)desc[ma+1];
}

/**
 * This method sets up an item which will only be displayed during the
 * day.  All of the standard add_item things are available with this
 * method.
 * @see /std/room->add_item()
 * @see add_night_item()
 */
varargs int add_day_item(mixed shorts, mixed desc, mixed no_plural) {
  string the_item;
  
  if(pointerp(shorts))
    the_item = shorts[0];
  else
    the_item = shorts;

  if(!variableitems)
    variableitems = ({ ({ }), ({ }) });
  
  variableitems[DAY] += ({ the_item, return_long(desc) });

  if(is_day == -1)
    is_day = (WEATHER_HANDLER->query_day() > 0);
  if(is_day == DAY) 
    return add_item(shorts, desc, no_plural);
  
  return 1;
}

/**
 * This method sets up an item which will only be displayed during the
 * night.  All of the standard add_item things are available with this
 * method.
 * @see /std/room->add_item()
 * @see add_day_item()
 */
varargs int add_night_item(mixed shorts, mixed desc, mixed no_plural) {
  string the_item;
  
  if(pointerp(shorts))
    the_item = shorts[0];
  else
    the_item = shorts;

  if(!variableitems)
    variableitems = ({ ({ }), ({ }) });

  variableitems[NIGHT] += ({ the_item, return_long( desc ) });
  
  if(is_day == -1)
    is_day = (WEATHER_HANDLER->query_day() > 0);
  if(is_day == NIGHT) 
    return add_item(shorts, desc, no_plural);

  return 1;
}

/**
 * This method sets up chats for when the room is in the day cycle.
 * @param args the chatter arguements
 * @see room_night_chat()
 * @see /std/room->room_chat()
 */
void room_day_chat(mixed *args) {
  if(!variablechats)
    variablechats = allocate(2);
  
  variablechats[DAY] = args;
  
  if(is_day == -1)
    is_day = (WEATHER_HANDLER->query_day() > 0);
  if(is_day == DAY)
    room_chat(args);
}

/**
 * This method sets up chats for when the room is in the night cycle.
 * @param args the chatter arguements
 * @see room_day_chat()
 * @see /std/room->room_chat()
 */
void room_night_chat( mixed *args ) {
  if(!variablechats)
    variablechats = allocate(2);
  
  variablechats[NIGHT] = args;
  
  if(is_day == -1)
    is_day = (WEATHER_HANDLER->query_day() > 0);
  if(is_day == NIGHT)
    room_chat(args);
}

/** @ignore yes */
string query_help_file_directory() {
  return ROOM_HELP_FILE_DIR;
} /* query_help_file_directory() */