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

/*
** area.c - base object for a terrain-like set of rooms.
*/

#include <dirs.h>
#include <image.h>

inherit "/std/room";

mapping direction_bits = ([
    "north": 1,
    "northeast": 2,
    "east": 4,
    "southeast": 8,
    "south": 16,
    "southwest": 32,
    "west": 64,
    "northwest": 128,
    "up": 256,
    "down": 512,
]);

class AREA_INFO {
  string base;
  int *origin;    // Origin of area; room centers are 2*size offset from this
  int *size;      // Size of each room
  mixed *bbox;    // Keeps track of bounding box of area (absolute)
  mixed *vertices;  // Outline of area (absolute)
  class IMAGE_INFO height; // Height map of area
  class IMAGE_INFO exits;  // Map of exits (for twisty little passages :)
} /* AREA_INFO */

private int dbg_lvl = 0;
private string debugger = "jeremy";
private string _handler;

private class AREA_INFO *areas = ({ });

private mapping room_cache = ([ ]);
private mapping area_cache = ([ ]);

/**
 * This method sets the handler of the topographic region.
 * @param handler the handler to set
 */
void set_handler(string handler) {
   _handler = handler;
}

/**
 * This method returns the handler of the topographic region.
 * @return the handler of the whole region
 */
string query_handler() {
   return _handler;
} /* query_handler() */

/**
 * This method sets the creator to whom debugging messages are sent.
 * @param d name of creator
 */
void set_debugger(string s) { debugger = s; }

/**
 * This method returns the name of the creator to whom debugging messages
 * are sent.
 * @return name of creator
 */
string query_debugger() { return debugger; }

/**
 * This method sets the level of debugging messages printed.
 * @param l debugging level (0 is off)
 */
void set_debug_level(int l) { dbg_lvl = l; }

/**
 * This method returns the current debugging level.
 * @return current debug level (0 is off)
 */
int query_debug_level() { return dbg_lvl; }

/**
 * @ignore
 * For debugging only
 */
mixed query(string s) { return fetch_variable(s); }

void set_base(int i, string s) { areas[i]->base = s; }
string query_base(int i) { return areas[i]->base; }

void set_origin(int i, int *o) { areas[i]->origin = copy(o); }
int *query_origin(int i) { return copy(areas[i]->origin); }

void create() {

  do_setup++;
  ::create();
  do_setup--;

  // Keeps us from being unloaded (one of the drawbacks of making the
  // handler a room; I wonder if that was a smart move...).
  set_keep_room_loaded(1);

  if ( !do_setup ) {
    this_object()->setup();
    this_object()->reset();
  }
} /* create() */

// Quantize coord to origin in area a
int *quantize_to_origin(int *coord_r, int a) {
  int size2, i, *coord_q;

  coord_q = allocate(3);
  for (i = 0; i < 3; i++) {
    size2 = areas[a]->size[i] * 2;
    if (coord_r[i] < areas[a]->origin[i]) {
      coord_q[i] = coord_r[i] - areas[a]->size[i];
    } else {
      coord_q[i] = coord_r[i] + areas[a]->size[i];
    }
    coord_q[i] = ((coord_q[i] - areas[a]->origin[i]) / size2) * size2
      + areas[a]->origin[i];
  }
  return coord_q;
} /* quantize_to_origin() */

void set_size(int i, mixed s) {
  if (intp(s)) {
    areas[i]->size = ({ s, s, s });
  } else if (arrayp(s) && (sizeof(s) == 3)) {
    areas[i]->size = copy(s);
  } else {
    error("Illegal size; must be int or 3-element array.\n");
  }
} /* set_size() */

//int *query_size(int i) { return copy(areas[i]->size); }

varargs void set_height_map(int i, string map_file, int rle) {
  int *nw;

  areas[i]->height = IMAGE_HANDLER->load_image(map_file, rle);
  if (arrayp(areas[i]->bbox)) {
    // Set up coordinate of NW corner
    nw = copy(areas[i]->bbox[0]);
    nw[0] = areas[i]->bbox[1][0] - 1;
    nw[1] += 1;
    nw[2] += 1;
    areas[i]->height->nw_coord = quantize_to_origin(nw, i);
  }
}

varargs void set_exits_map(int i, string map_file, int rle) {
  int *nw;

  areas[i]->exits = IMAGE_HANDLER->load_image(map_file, rle);
  if (arrayp(areas[i]->bbox)) {
    // Set up coordinate of NW corner
    nw = copy(areas[i]->bbox[0]);
    nw[0] = areas[i]->bbox[1][0] - 1;
    nw[1] += 1;
    nw[2] += 1;
    areas[i]->exits->nw_coord = quantize_to_origin(nw, i);
  }
}

int new_area() {
  areas += ({ new(class AREA_INFO) });
} /* new_area() */

// Note: this must be done after the origin is set
void set_vertices(int a, mixed *vs) {
  int v, i;

  if (!arrayp(areas[a]->origin)) {
    error("Origin unset - setting to (0,0,0).\n");
    areas[a]->origin = ({ 0, 0, 0 });
  }
  areas[a]->vertices = copy(vs);
  // Initialize bounding box
  areas[a]->bbox = ({ copy(vs[0]), copy(vs[0]) });
  for (i = 0; i < 3; i++) {
    areas[a]->bbox[0][i] += areas[a]->origin[i];
    areas[a]->bbox[1][i] += areas[a]->origin[i];
  }
  // Change to absolute coordinates
  for (v = 0; v < sizeof(areas[a]->vertices); v++) {
    for (i = 0; i < 3; i++) {
      areas[a]->vertices[v][i] += areas[a]->origin[i];
      if (areas[a]->vertices[v][i] < areas[a]->bbox[0][i]) {
        areas[a]->bbox[0][i] = areas[a]->vertices[v][i];
      } else if (areas[a]->vertices[v][i] > areas[a]->bbox[1][i]) {
        areas[a]->bbox[1][i] = areas[a]->vertices[v][i];
      }
    }
  }
} /* set_vertices() */

int in_bbox(int *coord, mixed *bbox) {
  if ((coord[0] < bbox[0][0]) || (coord[0] > bbox[1][0])) {
    return 0;
  }
  if ((coord[1] < bbox[0][1]) || (coord[1] > bbox[1][1])) {
    return 0;
  }
  if ((coord[2] < bbox[0][2]) || (coord[2] > bbox[1][2])) {
    return 0;
  }
  return 1;
} /* in_bbox() */

int in_area(int a, int *v) {
  // This counts how many times a line from v straight north crosses
  // the edges.  If it's odd, we're in the area.
  // REF: Foley, J.D. and A. Van Dam, Fundamentals of Interactive Computer
  //      Graphics, Addison-Wesley, 1982, pp 457-458.
  // This may be more complicated than it has to be.  I found a much simpler
  // implementation in C, but I haven't verified it yet.
  int crossings, i, i0, i1, de, int_n, below_vertex;
  mixed *vs;

  if (!in_bbox(v, areas[a]->bbox)) {
    //printf("Outside (bbox)...\n");
    return 0;
  }
  // This looks complicated, but most of the time it shouldn't get past
  // the first four tests.
  vs = allocate(2);
  for (i = 0; i < sizeof(areas[a]->vertices); i++) {
    below_vertex = 0;
    vs[0] = areas[a]->vertices[i];
    if (i < sizeof(areas[a]->vertices)-1) {
      vs[1] = areas[a]->vertices[i+1];
    } else {
      vs[1] = areas[a]->vertices[0];
    }
    if ((v[1] < vs[0][1]) && (v[1] < vs[1][1])) {
      //printf("Outside (west)...\n");
      continue;
    }
    if ((v[1] > vs[0][1]) && (v[1] > vs[1][1])) {
      //printf("Outside (east)...\n");
      continue;
    }
    if ((v[0] > vs[0][0]) && (v[0] > vs[1][0])) {
      //printf("Outside (north)...\n");
      continue;
    }
    if ((v[0] < vs[0][0]) && (v[0] < vs[1][0])) {
      // We're below the line segment.
      if (v[1] != vs[0][1]) {
        // We're not below the first vertex...
        if (v[1] != vs[1][1]) {
          // We're not below the second vertex, so we cross the line.
          crossings++;
        }
        // Don't count hitting the vertex on the second point (see below)
        continue;
      } else {
        // Need to check whether to count the vertex as a crossing.
        below_vertex = 1;
      }
    }
    // Okay, now we get into some fuzzier cases.  We're somewhere in the
    // bounding box of the line segment, or we hit a vertex.
    if (vs[0][1] == vs[1][1]) {
      // Don't count vertical lines unless we're sitting right on it.
      if (!below_vertex) {
        return 1;
      }
      continue;
    }
    if ((v[0] == vs[0][0]) && (v[1] == vs[0][1])) {
      // We're on a vertex - we're "in".
      return 1;
    }
    if ((vs[0][0] == vs[1][0]) && !below_vertex) {
      // We're on a horizontal line - we're "in".
      return 1;
    }
    // Vertices are tough...we need to find if it's concave or convex
    if (v[1] == vs[1][1]) {
      // Don't count vertex hit on second point (or else it'll get
      // counted twice).
      continue;
    }
    if (v[1] == vs[0][1]) {
      if (v[0] > vs[0][0]) {
        // We're above the first vertex.  No intersection.
        continue;
      }
      // Find closest bend on one side...
      i0 = i;
      while (areas[a]->vertices[i0][1] == v[1]) {
        i0--;
        if (i0 < 0) i0 = sizeof(areas[a]->vertices) - 1;
      }
      // Find closest bend on the other side...
      i1 = i;
      while (areas[a]->vertices[i1][1] == v[1]) {
        i1++;
        if (i1 >= sizeof(areas[a]->vertices)) i1 = 0;
      }
      // This counts as at least one hit.
      crossings++;
      if (((areas[a]->vertices[i0][1] > v[1]) &&
           (areas[a]->vertices[i1][1] > v[1])) ||
          ((areas[a]->vertices[i0][1] < v[1]) &&
           (areas[a]->vertices[i1][1] < v[1]))) {
        // Concave/convex count as 2 crossings.
        crossings++;
      }
      continue;
    }
    // Nothing left to do but find the intersection
    de = vs[1][1] - vs[0][1];
    int_n = ceil(to_float(vs[1][0] - vs[0][0])*(v[1] - vs[0][1])/de
                 + vs[0][0] + 0.5);
    if (int_n > v[0]) {
      crossings++;
    }
  }
  // LSB indicates if it's odd.
  return (crossings & 1);
} /* in_area() */

object clone_room(int a, int *coord_q, string coord_s) {
  int i, j, e, bit;
  string dir;
  object room;

  room = clone_object(areas[a]->base);
  room_cache[coord_s] = room;
  area_cache[coord_s] = a;
  room->set_room_size(areas[a]->size);
  // TODO: add height map stuff
  room->set_co_ord(coord_q);
  if (areas[a]->exits) {
    // Add exits to room according to map
    i = (areas[a]->origin[0] - coord_q[0])/(2*areas[a]->size[0]);
    j = (coord_q[1] - areas[a]->origin[1])/(2*areas[a]->size[1]);
    if ((i < areas[a]->exits->size[0]) && (j < areas[a]->exits->size[1])
        && (i >= 0) && (j >= 0)) {
      e = areas[a]->exits->image[i][j];
      foreach (dir, bit in direction_bits) {
        if (e & bit) {
          // TODO: should put a field for the exit type in the class...
          room->add_exit(dir, "", "path");
        }
      }
      // This is a bit of a hack, but it's easy.
      room->add_property("image_cell", ({ i, j }));
    }
  }
  // Other room initialization TBD.
  return room;
}

object find_room_at_coord(int *coord) {
  int a, ac, *coord_q;
  string coord_s;
  object room;

  // Check to see if it's in the cache as-is.
  coord_s = sprintf("%d:%d:%d", coord[0], coord[1], coord[2]);
  if (objectp(room = room_cache[coord_s])) {
    return room;
  }
  if (!undefinedp(ac = area_cache[coord_s])) {
    // There used to be a room here.
    return clone_room(ac, coord, coord_s);
  }
  for (a = 0; a < sizeof(areas); a++) {
    // Quantize coordinates to room centers for this area.
    coord_q = quantize_to_origin(coord, a);
    // Check the cache again.
    coord_s = sprintf("%d:%d:%d", coord_q[0], coord_q[1], coord_q[2]);
    if (objectp(room = room_cache[coord_s])) {
      return room;
    }
    if (!undefinedp(ac = area_cache[coord_s])) {
      // There used to be a room here.
      return clone_room(ac, coord_q, coord_s);
    }
    if (!in_area(a, coord_q)) {
      continue;
    }
    return clone_room(a, coord_q, coord_s);
  }
  return 0;
} /* find_room_at_coord() */

object find_room_at_exit(object r, int *d, string direc) {
  int a, ac, i, *coord, *coord_r, *coord_q;
  string coord_s;
  object room;
  mixed size_r;

  if (dbg_lvl > 0) {
    tell_creator(debugger, "%s::find_room_at_exit()\n"
                 "  r: %O\n"
                 "  d: %O\n"
                 "  direc: %O\n",
                 file_name(this_object()), r, d, direc);
  }
  if (!arrayp(d)) {
    return 0;
  }
  coord = r->query_co_ord();
  // Some rooms (like milestones) have "fake" sizes.
  size_r = r->query_actual_room_size();
  if (!arrayp(size_r)) {
    size_r = r->query_room_size();
    if (!arrayp(size_r)) {
      // Must be a single int for all 3 dimensions.
      size_r = ({ size_r, size_r, size_r });
    }
  }
  coord_r = allocate(3);
  for (a = 0; a < sizeof(areas); a++) {
    for (i = 0; i < 3; i++) {
      coord_r[i] = coord[i] + (size_r[i] + areas[a]->size[i]) * d[i];
    }
    // Use the drivers virtual mapping stuff to do the cacheing for us.
    coord_s = sprintf("%d:%d:%d", coord_r[0], coord_r[1], coord_r[2]);
    return load_object(_handler + ":" + coord_s);
#if 0
    // Check to see if it is (or has been) in the cache as-is.
    if (objectp(room = room_cache[coord_s])) {
      if (dbg_lvl > 0) {
        tell_creator(debugger, "%s::find_room_at_exit()\n"
                 "  found room %O cached at %s...\n",
                 file_name(this_object()), room, coord_s);
      }
      return room;
    }
    if (!undefinedp(ac = area_cache[coord_s])) {
      // There used to be a room here.
      if (dbg_lvl > 0) {
        tell_creator(debugger, "%s::find_room_at_exit()\n"
                 "  found area %O cached at %s...\n",
                 file_name(this_object()), ac, coord_s);
      }
      return clone_room(ac, coord_r, coord_s);
    }
    coord_q = quantize_to_origin(coord_r, a);
    // Check the cache again.
    coord_s = sprintf("%d:%d:%d", coord_q[0], coord_q[1], coord_q[2]);
    if (objectp(room = room_cache[coord_s])) {
      return room;
    }
    if (!undefinedp(ac = area_cache[coord_s])) {
      // There used to be a room here.
      return clone_room(ac, coord_q, coord_s);
    }
    if (!in_area(a, coord_q)) {
      continue;
    }
    return clone_room(a, coord_q, coord_s);
#endif
  }
  return 0;
} /* find_room_at_exit() */

// This is a testing convenience function
int goto_room_at_coord(int *coord) {
  return this_player()->move_with_look(find_room_at_coord(coord));
} /* goto_room_at_coord() */

int goto_room_at_exit(int *d, string direc) {
  return this_player()->move_with_look(find_room_at_exit(
                        environment(this_player()), d, direc));
}

void print_images(int a) {
  if (areas[a]->height) {
    printf("-------- Height:\n");
    IMAGE_HANDLER->print_image(areas[a]->height);
  }
  if (areas[a]->exits) {
    printf("-------- Exits:\n");
    IMAGE_HANDLER->print_image(areas[a]->exits);
  }
}

void print_map(int a) {
  int s, e;
  string l = "";
  class IMAGE_INFO exits;

  if (areas[a]->exits) {
    exits = areas[a]->exits;
    for (s = 0; s < exits->size[1]; s++) {
      for (e = 0; e < exits->size[0]; e++) {
        l += (exits->image[s][e] & 128)?"\\":" ";
        l += (exits->image[s][e] & 1)  ?"|":" ";
        l += (exits->image[s][e] & 2)  ?"/":" ";
      }
      l += "\n";
      for (e = 0; e < exits->size[0]; e++) {
        l += (exits->image[s][e] & 64) ?"-":" ";
        l += "*";
        l += (exits->image[s][e] & 4)  ?"-":" ";
      }
      l += "\n";
      for (e = 0; e < exits->size[0]; e++) {
        l += (exits->image[s][e] & 32) ?"/":" ";
        l += (exits->image[s][e] & 16) ?"|":" ";
        l += (exits->image[s][e] & 8)  ?"\\":" ";
      }
      l += "\n";
    }
    write(l);
  }
}