skylib_fluffos_v3/
skylib_fluffos_v3/bin/
skylib_fluffos_v3/bin/db/
skylib_fluffos_v3/fluffos-2.9-ds2.04/
skylib_fluffos_v3/fluffos-2.9-ds2.04/ChangeLog.old/
skylib_fluffos_v3/fluffos-2.9-ds2.04/Win32/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/simuls/
skylib_fluffos_v3/fluffos-2.9-ds2.04/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/clone/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/command/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/data/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/etc/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/master/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/log/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/compiler/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/efuns/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/operators/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/u/
skylib_fluffos_v3/fluffos-2.9-ds2.04/tmp/
skylib_fluffos_v3/fluffos-2.9-ds2.04/windows/
skylib_fluffos_v3/mudlib/
skylib_fluffos_v3/mudlib/cmds/
skylib_fluffos_v3/mudlib/cmds/admin/
skylib_fluffos_v3/mudlib/cmds/guild-race/
skylib_fluffos_v3/mudlib/cmds/living/broken/
skylib_fluffos_v3/mudlib/cmds/player/group_cmds/
skylib_fluffos_v3/mudlib/cmds/playtester/
skylib_fluffos_v3/mudlib/d/admin/
skylib_fluffos_v3/mudlib/d/admin/room/
skylib_fluffos_v3/mudlib/d/admin/room/we_care/
skylib_fluffos_v3/mudlib/d/admin/save/
skylib_fluffos_v3/mudlib/d/admin/text/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/buildings/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/map/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/roads/
skylib_fluffos_v3/mudlib/d/learning/chars/
skylib_fluffos_v3/mudlib/d/learning/functions/
skylib_fluffos_v3/mudlib/d/learning/handlers/
skylib_fluffos_v3/mudlib/d/learning/help_topics/
skylib_fluffos_v3/mudlib/d/learning/help_topics/npcs/
skylib_fluffos_v3/mudlib/d/learning/help_topics/objects/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/crowd/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/situations/
skylib_fluffos_v3/mudlib/d/learning/save/
skylib_fluffos_v3/mudlib/d/learning/school/
skylib_fluffos_v3/mudlib/d/learning/school/add_sc/
skylib_fluffos_v3/mudlib/d/learning/school/characters/
skylib_fluffos_v3/mudlib/d/learning/school/general/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/basic_commands/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/edtutor/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_fluffos_v3/mudlib/d/learning/school/items/
skylib_fluffos_v3/mudlib/d/learning/school/npc_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/room_basic/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/situations/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_fluffos_v3/mudlib/d/learning/text/
skylib_fluffos_v3/mudlib/d/liaison/
skylib_fluffos_v3/mudlib/d/mudlib/
skylib_fluffos_v3/mudlib/d/mudlib/changes/
skylib_fluffos_v3/mudlib/d/playtesters/
skylib_fluffos_v3/mudlib/d/playtesters/effects/
skylib_fluffos_v3/mudlib/d/playtesters/handlers/
skylib_fluffos_v3/mudlib/d/playtesters/items/
skylib_fluffos_v3/mudlib/d/sage/
skylib_fluffos_v3/mudlib/doc/
skylib_fluffos_v3/mudlib/doc/creator/
skylib_fluffos_v3/mudlib/doc/driver/
skylib_fluffos_v3/mudlib/doc/driver/efuns/arrays/
skylib_fluffos_v3/mudlib/doc/driver/efuns/buffers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/calls/
skylib_fluffos_v3/mudlib/doc/driver/efuns/compile/
skylib_fluffos_v3/mudlib/doc/driver/efuns/filesystem/
skylib_fluffos_v3/mudlib/doc/driver/efuns/floats/
skylib_fluffos_v3/mudlib/doc/driver/efuns/functions/
skylib_fluffos_v3/mudlib/doc/driver/efuns/general/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mappings/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mixed/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mudlib/
skylib_fluffos_v3/mudlib/doc/driver/efuns/numbers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/parsing/
skylib_fluffos_v3/mudlib/doc/login/
skylib_fluffos_v3/mudlib/doc/lpc/basic_manual/
skylib_fluffos_v3/mudlib/doc/lpc/intermediate/
skylib_fluffos_v3/mudlib/doc/new/add_command/
skylib_fluffos_v3/mudlib/doc/new/events/
skylib_fluffos_v3/mudlib/doc/new/handlers/
skylib_fluffos_v3/mudlib/doc/new/living/race/
skylib_fluffos_v3/mudlib/doc/new/living/spells/
skylib_fluffos_v3/mudlib/doc/new/object/
skylib_fluffos_v3/mudlib/doc/new/player/
skylib_fluffos_v3/mudlib/doc/new/room/guild/
skylib_fluffos_v3/mudlib/doc/new/room/outside/
skylib_fluffos_v3/mudlib/doc/new/room/storeroom/
skylib_fluffos_v3/mudlib/doc/object/
skylib_fluffos_v3/mudlib/doc/playtesters/
skylib_fluffos_v3/mudlib/doc/policy/
skylib_fluffos_v3/mudlib/doc/weapons/
skylib_fluffos_v3/mudlib/global/
skylib_fluffos_v3/mudlib/global/creator/
skylib_fluffos_v3/mudlib/handlers/
skylib_fluffos_v3/mudlib/include/casino/
skylib_fluffos_v3/mudlib/include/cmds/
skylib_fluffos_v3/mudlib/include/effects/
skylib_fluffos_v3/mudlib/include/npc/
skylib_fluffos_v3/mudlib/include/room/
skylib_fluffos_v3/mudlib/include/shops/
skylib_fluffos_v3/mudlib/net/daemon/
skylib_fluffos_v3/mudlib/net/daemon/chars/
skylib_fluffos_v3/mudlib/net/inherit/
skylib_fluffos_v3/mudlib/net/obj/
skylib_fluffos_v3/mudlib/net/obj/BACKUPS/
skylib_fluffos_v3/mudlib/obj/amulets/
skylib_fluffos_v3/mudlib/obj/armours/plate/
skylib_fluffos_v3/mudlib/obj/b_day/
skylib_fluffos_v3/mudlib/obj/clothes/transport/horse/
skylib_fluffos_v3/mudlib/obj/faith/symbols/
skylib_fluffos_v3/mudlib/obj/fungi/
skylib_fluffos_v3/mudlib/obj/gatherables/
skylib_fluffos_v3/mudlib/obj/instruments/
skylib_fluffos_v3/mudlib/obj/media/
skylib_fluffos_v3/mudlib/obj/misc/player_shop/
skylib_fluffos_v3/mudlib/obj/monster/godmother/
skylib_fluffos_v3/mudlib/obj/monster/transport/
skylib_fluffos_v3/mudlib/obj/rings/
skylib_fluffos_v3/mudlib/obj/scabbards/
skylib_fluffos_v3/mudlib/obj/spells/
skylib_fluffos_v3/mudlib/obj/stationery/
skylib_fluffos_v3/mudlib/obj/stationery/envelopes/
skylib_fluffos_v3/mudlib/obj/toys/
skylib_fluffos_v3/mudlib/obj/vessels/
skylib_fluffos_v3/mudlib/obj/weapons/axes/
skylib_fluffos_v3/mudlib/obj/weapons/chains/
skylib_fluffos_v3/mudlib/obj/weapons/maces/BACKUPS/
skylib_fluffos_v3/mudlib/save/autodoc/
skylib_fluffos_v3/mudlib/save/book_handler/
skylib_fluffos_v3/mudlib/save/books/history/calarien/
skylib_fluffos_v3/mudlib/save/mail/
skylib_fluffos_v3/mudlib/save/new_soul/data/
skylib_fluffos_v3/mudlib/save/parcels/
skylib_fluffos_v3/mudlib/save/playerinfo/
skylib_fluffos_v3/mudlib/save/players/d/
skylib_fluffos_v3/mudlib/save/players/s/
skylib_fluffos_v3/mudlib/save/random_names/
skylib_fluffos_v3/mudlib/save/random_names/data/
skylib_fluffos_v3/mudlib/save/terrains/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_desert/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_grassy_field/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_mountain/
skylib_fluffos_v3/mudlib/save/todo_lists/
skylib_fluffos_v3/mudlib/secure/
skylib_fluffos_v3/mudlib/secure/cmds/admin/
skylib_fluffos_v3/mudlib/secure/cmds/lord/
skylib_fluffos_v3/mudlib/secure/config/
skylib_fluffos_v3/mudlib/secure/handlers/autodoc/
skylib_fluffos_v3/mudlib/secure/handlers/intermud/
skylib_fluffos_v3/mudlib/secure/include/global/
skylib_fluffos_v3/mudlib/secure/save/
skylib_fluffos_v3/mudlib/secure/save/handlers/
skylib_fluffos_v3/mudlib/secure/std/
skylib_fluffos_v3/mudlib/secure/std/classes/
skylib_fluffos_v3/mudlib/secure/std/modules/
skylib_fluffos_v3/mudlib/std/creator/
skylib_fluffos_v3/mudlib/std/dom/
skylib_fluffos_v3/mudlib/std/effects/
skylib_fluffos_v3/mudlib/std/effects/external/
skylib_fluffos_v3/mudlib/std/effects/fighting/
skylib_fluffos_v3/mudlib/std/effects/magic/
skylib_fluffos_v3/mudlib/std/effects/magic/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/other/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/priest/
skylib_fluffos_v3/mudlib/std/effects/room/
skylib_fluffos_v3/mudlib/std/environ/
skylib_fluffos_v3/mudlib/std/guilds/
skylib_fluffos_v3/mudlib/std/guilds/old/
skylib_fluffos_v3/mudlib/std/languages/
skylib_fluffos_v3/mudlib/std/liquids/
skylib_fluffos_v3/mudlib/std/npc/
skylib_fluffos_v3/mudlib/std/npc/goals/
skylib_fluffos_v3/mudlib/std/npc/goals/basic/
skylib_fluffos_v3/mudlib/std/npc/goals/misc/
skylib_fluffos_v3/mudlib/std/npc/plans/
skylib_fluffos_v3/mudlib/std/npc/plans/basic/
skylib_fluffos_v3/mudlib/std/npc/types/
skylib_fluffos_v3/mudlib/std/npc/types/helper/
skylib_fluffos_v3/mudlib/std/npcs/
skylib_fluffos_v3/mudlib/std/outsides/
skylib_fluffos_v3/mudlib/std/races/shadows/
skylib_fluffos_v3/mudlib/std/room/basic/BACKUPS/
skylib_fluffos_v3/mudlib/std/room/basic/topography/
skylib_fluffos_v3/mudlib/std/room/controller/
skylib_fluffos_v3/mudlib/std/room/inherit/topography/
skylib_fluffos_v3/mudlib/std/room/topography/area/
skylib_fluffos_v3/mudlib/std/room/topography/iroom/
skylib_fluffos_v3/mudlib/std/room/topography/milestone/
skylib_fluffos_v3/mudlib/std/shadows/curses/
skylib_fluffos_v3/mudlib/std/shadows/disease/
skylib_fluffos_v3/mudlib/std/shadows/fighting/
skylib_fluffos_v3/mudlib/std/shadows/healing/
skylib_fluffos_v3/mudlib/std/shadows/magic/
skylib_fluffos_v3/mudlib/std/shadows/poison/
skylib_fluffos_v3/mudlib/std/shadows/room/
skylib_fluffos_v3/mudlib/std/shops/controllers/
skylib_fluffos_v3/mudlib/std/shops/objs/
skylib_fluffos_v3/mudlib/std/shops/player_shop/
skylib_fluffos_v3/mudlib/std/socket/
skylib_fluffos_v3/mudlib/std/soul/d/
skylib_fluffos_v3/mudlib/std/soul/e/
skylib_fluffos_v3/mudlib/std/soul/i/
skylib_fluffos_v3/mudlib/std/soul/j/
skylib_fluffos_v3/mudlib/std/soul/k/
skylib_fluffos_v3/mudlib/std/soul/l/
skylib_fluffos_v3/mudlib/std/soul/n/
skylib_fluffos_v3/mudlib/std/soul/o/
skylib_fluffos_v3/mudlib/std/soul/q/
skylib_fluffos_v3/mudlib/std/soul/r/
skylib_fluffos_v3/mudlib/std/soul/u/
skylib_fluffos_v3/mudlib/std/soul/v/
skylib_fluffos_v3/mudlib/std/soul/y/
skylib_fluffos_v3/mudlib/std/soul/z/
skylib_fluffos_v3/mudlib/std/stationery/
skylib_fluffos_v3/mudlib/w/
skylib_fluffos_v3/mudlib/w/default/
skylib_fluffos_v3/mudlib/w/default/armour/
skylib_fluffos_v3/mudlib/w/default/clothes/
skylib_fluffos_v3/mudlib/w/default/item/
skylib_fluffos_v3/mudlib/w/default/npc/
skylib_fluffos_v3/mudlib/w/default/room/
skylib_fluffos_v3/mudlib/w/default/weapon/
skylib_fluffos_v3/mudlib/www/
skylib_fluffos_v3/mudlib/www/java/
skylib_fluffos_v3/mudlib/www/secure/
skylib_fluffos_v3/mudlib/www/secure/lpc/advanced/
skylib_fluffos_v3/mudlib/www/secure/lpc/intermediate/
skylib_fluffos_v3/win32/
#include <tasks.h>

inherit OUTSIDE_OBJ;

/**
 * This is a standard rooftop inheritable. It allows you to setup a rooftop
 * location including such things as slope, strength, jumping locations etc.
 *
 * @example
 * inherit "/std/rooftop"
 *
 * void setup() {
 *    set_fall_damage( "all", 500 );
 *    set_slope( 60, "ledge", PATH + "womble01" );
 *    set_weak_messages(
 *      "The ledge crumbles under your weight.",
 *      "$short$ falls from the crumbling ledge.",
 *      "$short$ comes crashing to the ground.",
 *      "The paving stones shift beneath your feet.",
 *    );
 *    set_weak_roof( 2000, PATH + "womble01" );
 *    set_jump( ({ "north", "n" }), PATH + "ledge01", PATH + "womble01", 6 );
 * }
 *
 * @see set_wall
 * @author shrike
 */
#undef DEBUG

#define ROCK "general.climbing.rock"
#define ROPE "general.climbing.rope"

/* function prototypes */
void   set_death_reason( string );
void   set_fall_damage( string, int );
mixed  query_fall_damage( string );
int    calc_fall_damage( string );
void   set_weak_roof( int, string );
void   set_slope( int, string, string );
string process_string( string, mapping );
string process_mess( string, object, string );

/* object variables */
mapping  damages;          // damages for all the various types of falling.
string * damage_types;
int      roof_max_weight;  // in units (20 units == 1 kg)
int      gradient;         // percentage grade of the roof.
string   weak_roof_dest;   // where you fall if the roof collapses.
string   slope_dest;       // where you fall if you slip off the roof.
string   place;            // where you fall off of. (ie "edge of the roof
                           //  bordering Filigree Street" )
string   death_reason;     // used when you die.

/*
 * Message arrays. most are of the form
 * ({ player_mess, exit_mess, enter_mess })
 * Where player_mess is what the player who's jumping/falling sees.
 * exit mess is the message sent to the other objects in the starting room,
 * and enter_mess is what the objects in the target room see.
 * weak_messages has an additional 4th parameter, which is the message to
 * the room when the roof is about to collapse, and jump_tm_messages will
 * be randomly selected from if the player gets a TM while jumping.
 */
string * weak_messages;    // for when a roof collapses.
string * slope_messages;   // falling off
string * step_messages;    // stepping off when you should have jumped
string * jump_tm_messages;       // tm messages. it will pick a rnadom one
string * jump_success_messages;  // jumping successfully
string * jump_failure_messages;  // jumping unsuccessfully
string * ghost_fall_messages;    // a ghost drifting to the ground
string * item_slope_messages;    // a non-corpse item sliding off the edge
string * corpse_slope_messages;  // a corpse sliding off the edge

/*
 * Info for jumping from roof to roof. each element is of the form
 * <string:key>: ({             Name of the exit
 *    <string:destination>,     Filename of the destination room
 *    <string:fall_dest>,       filename of the room where you fall on failure
 *    <int:distance>            Distance. (streets in AM are ~5-20 wide
 * })
 */
mapping jump_info;

/*
 * Translates from direction aliases to jump_info keys. Each element looks
 * like <string:name> : <string: jump_info key>
 * In order to pull up the jump info for a particular location, you'd
 * use jump_info[ translations["name"] ].
 */
mapping translations;

/** @ignore yes */
void init() {
   ::init();
   add_command( "jump", "<word'direction'>",
     (: TO->do_roofjump( $4[0] ) :) );
} /* init() */

/** @ignore yes */
void create() {
   do_setup++;
   ::create();
   do_setup--;

   weak_messages = ({
     "The roof collapses! This is going to be painful...\n",
     "$short$ crashes down through a weak spot in the roof.",
     "$short$ comes crashing to the ground, landing in a rain of debris.",
     "You hear an ominous creak.\n"
   });

   slope_messages = ({
     "The roof is to steep for you to stand on! It's time to make friends "
       "with the floor...\n",
     "$short$ gets in touch with gravity and slides over the edge of the "
       "roof.",
     "$short$ comes crashing to the ground, landing in a heap."
   });

   step_messages = ({
     "You step off the edge of the roof into midair.\n",
     "$short$ steps off the edge of the roof and plummets earthwards.",
     "$short$ comes crashing to the ground, landing in a heap."
   });

   jump_tm_messages = ({
     "You leap more gracefully through the air.",
     "You feel more able to leap tall buildings in a single bound.",
     "You jump like a mountain goat."
   });

   jump_success_messages = ({
     "You launch yourself off the edge of the roof and land gracefully on "
       "the other side.\n",
     "$short$ jumps gracefully across the gap to the $dir$.",
     "$short$ jumps in from across the gap to the $opp_dir$."
   });

   jump_failure_messages = ({
     "You launch yourself off the edge of the roof!\nUnfortunately you "
       "misjudge the distance and plummet earthwards. This is going to "
       "hurt...\n",
     "$short$ jumps off to the $dir$, but misjudges and plummets "
       "earthwards.",
     "$short$ plummets to the ground, landing in a heap."
   });

   ghost_fall_messages = ({
      "You find your consciousness drifting earthwards.\n",
      "$the_short$ drifts earthwards.",
      "$the_short$ drifts in from above, looking somewhat dazed."
   });

   item_slope_messages = ({
     "$the_short$ tumbles over the edge and plummets to the ground.\n",
     "Hearing a noise, you look up just as $a_short$ falls off the edge "
       "of the roof and hits the ground.\n"
   });

   corpse_slope_messages = ({
     "$the_short$ tumbles over the edge and plummets to the ground with "
       "a sickening thud.\n",
     "Hearing a noise, you look up just as $the_short$ tumbles over the "
       "edge of the roof and hits the ground with a sickening thud.\n"
   });

   damages = ([ ]);
   damage_types = ({ "weak", "slope", "step", "jump" });
   translations = ([ ]);
   jump_info = ([ ]);

   TO->setup();
} /* create() */

/* Customize the message sets */

/**
 * Set the messages for when a player falls through a weak roof.
 *
 * @param player the message shown to the player.
 * @param from the message shown in the room the player is leaving.
 * @param to the message shown in the room the player is entering.
 * @param warn the message shown to the room just before the roof collapses.
 *
 * @see set_weak_roof
 */
void set_weak_messages( string player, string from, string to, string warn ) {
   weak_messages = ({ player, from, to, warn });
} /* set_weak_messages() */

/**
 * Set the messages for when a player slips off a sloping roof.
 *
 * @param player the message shown to the player.
 * @param from the message shown in the room the player is leaving.
 * @param to the message shown in the room the player is entering.
 *
 * @see set_slope
 */
void set_slope_messages( string player, string from, string to ) {
   slope_messages = ({ player, from, to });
} /* set_slope_messages() */

/**
 * Set the messages for when a player falls off by moving in the wrong
 * direction.
 *
 * @param player the message shown to the player.
 * @param from the message shown in the room the player is leaving.
 * @param to the message shown in the room the player is entering.
 *
 * @see set_jump
 */
void set_step_messages( string player, string from, string to ) {
   step_messages = ({ player, from, to });
} /* set_step_messages() */

/**
 * Set the messages for when a player gets a TM by jumping. These messages
 * will be selected at random, and then coloured appropriately.
 *
 * @param messages the array of messages from which to choose.
 *
 * @see set_jump
 */
void set_jump_tm_messages( string * messages ) {
   jump_success_messages = messages;
} /* set_jump_tm_messages() */

/**
 * Set the messages for when a player successfully jumps a gap.
 *
 * @param player the message shown to the player.
 * @param from the message shown in the room the player is leaving.
 * @param to the message shown in the room the player is entering.
 *
 * @see set_jump
 */
void set_jump_success_messages( string player, string from, string to ) {
   jump_success_messages = ({ player, from, to });
} /* set_jump_success_messages() */

/**
 * Set the messages for when a player falls off by failing to jump across
 * a gap.
 *
 * @param player the message shown to the player.
 * @param from the message shown in the room the player is leaving.
 * @param to the message shown in the room the player is entering.
 *
 * @see set_jump
 */
void set_jump_failure_messages( string player, string from, string to ) {
   jump_failure_messages = ({ player, from, to });
} /* set_jump_failure_messages() */

/**
 * Set the messages for when a ghost falls off a roof.
 *
 * @param player the message shown to the player.
 * @param from the message shown in the room the player is leaving.
 * @param to the message shown in the room the player is entering.
 *
 * @see set_slope
 */
void set_ghost_fall_messages( string player, string from, string to ) {
   ghost_fall_messages = ({ player, from, to });
} /* set_ghost_fall_messages() */

/**
 * Set the messages for when a corpse slides off a sloping roof.
 *
 * @param from the message shown in the room the corpse is leaving.
 * @param to the message shown in the room the corpse is entering.
 *
 * @see set_slope
 */
void set_corpse_slope_messages( string from, string to ) {
  corpse_slope_messages = ({ from, to });
} /* set_item_slope_messages() */

/**
 * Set the messages for when a non-corpse item slides off a sloping roof.
 *
 * @param from the message shown in the room the object is leaving.
 * @param to the message shown in the room the object is entering.
 *
 * @see set_slope
 */
void set_item_slope_messages( string from, string to ) {
   item_slope_messages = ({ from, to });
} /* set_item_slope_messages() */

/**
 * Set the amount of damage the player will take if they fall off this
 * roof.  This amount is somewhat randomised.
 *
 * @param type The type of fall (weak, slope, step or jump; all to set all damages the same)
 * @param damage The amount of damage.
 *
 * @see set_slope, set_jump, set_weak_roof
 */
void set_fall_damage( string type, int damage ) {
   if( damage < 0 )
      damage = -damage;

   if( type == "all" ) {
      foreach( type in damage_types )
         damages[type] = damage;
   } else if( member_array( type, damage_types ) >= 0 ) {
      damages[type] = damage;
   } else
      return;
} /* set_fall_famage() */

/**
 * Find out the damage for falling from this location.
 *
 * @param type The type ( weak, slope, step, jump, or all )
 * @return An int, or an integer array of the damage(s)
 *
 * @see set_fall_damage
 */
mixed query_fall_damage( string type ) {
   if( type == "all" )
      return damages;
   else
      return damages[type];
} /* query_fall_famage() */

/** @ignore yes */
int calc_fall_damage( string type ) {
   if( type == "all" )
      return 0;
   return query_fall_damage( type ) + random( query_fall_damage( type ) );
} /* calc_fall_famage() */

/**
 * Set the maximum weight this location can support.
 *
 * @param maxweight the maximum weight capacity of the roof.
 * @param dest the room you go to if the roof collapses.
 */
void set_weak_roof( int maxweight, string dest ) {
   roof_max_weight = maxweight;
   weak_roof_dest = dest;
} /* set_weak_roof() */

/**
 * Set the gradient of this location.
 *
 * @param angle the angle (in degrees).
 * @param loc a short description of the area to show to players.
 * @param dest the fall destination.
 */
void set_slope( int angle, string loc, string dest ) {
   gradient = ( angle * 100 ) / 90;
   place = loc;
   slope_dest = dest;
} /* set_slope() */

/**
 * Setup a jumping exit. The player will be able to "jump <dir>" and a skill
 * test will be performed and they'll succeed or fail.
 *
 * Streets in AM are usually 5-20 wide.
 * if you want to do something other than the standard fall function,
 * you'll need to mask do_fall() in the child room.
 *
 * @param dir direction names
 * @param dest the destination
 * @param fall_dest the destination if they fall
 * @param distance the distance of the jump
 * @return -1 if any of the keys in dir already exists, 0 if dir is
 * malformed (string and string * are the only acceptable types), or
 * 1 on success.
 *
 * @example
 * set_jump( ({ "north", "n" }), RUN + "run12", FILIGREE + "filigree10", 6 );
 */
int set_jump( mixed dir, string dest, string fall_dest, int distance ) {
   string * dirs;
   mixed foo;
   string bar;

   if( stringp( dir ) ) {
      dirs = ({ dir });
   } else if( arrayp(dir) ) {
      foreach( foo in dir )
         if( !stringp( foo ) )
            return 0;
      dirs = sort_array( dir, 1 );
   }

   foreach( bar in dir )
      if( !undefinedp( translations[bar] ) )
         return -1;

   // setup the mappings
   jump_info[ dir[0] ] = ({ dest, fall_dest, distance });
   foreach( bar in dir )
      translations[bar] = dir[0];

   if( !query_exit( dir[0] ) )
      add_exit( dir[0], dest, "roof" );
   modify_exit( dir[0], ({
     "closed", 1,
     "function", (: TO->silly_move(
       jump_info[translations[$1]][1], "step", step_messages ) :),
     "look", "You'll have to jump across to see what's on the other side."
   }) );

   return 1;
} /* set_jump() */

/**
 * @ignore yes
 * Internal function used if a player steps off the edge of a roof.
 */
int silly_move( mixed dest, string dam_type, string * messages ) {
   TO->do_fall( TP, dest, dam_type, messages, 0 );
   return notify_fail( "" );
} /* silly_move() */

/**
 * @ignore yes
 * Internal function to handle falling. You can overload this if you so
 * desire.
 */
void do_fall( object obj, mixed dest, string dam_type, string * messages,
  string dir ) {
   int damage, i;
   object destob;

   for( i = 0; i < sizeof( messages ); i++ )
      messages[i] = process_mess( messages[i], obj, dir );

   if( stringp( dest ) ) {
      if( !(destob = load_object( dest ) ) ) {
         tell_object( obj, "Cannot find " + dest + ".\n"
           "Moving you to the void - Please contact a creator.\n" );
         obj->move( "/room/void", "Poof. $N appears.\n",
           "$N plummets earthwards.\n" );
      }
   } else if( objectp( dest ) ) {
      destob = dest;
   } else
      return;

   tell_object( obj, messages[0] );
   obj->move_with_look( destob, messages[2], messages[1] );
   if( obj->query_property( "dead" ) )
      return;

   damage = calc_fall_damage( dam_type );
   if( damage >= obj->query_hp() ) {
      set_death_reason( "plummeting from the rooftops" );
      obj->attack_by( TO );
      obj->do_death();
   } else
      obj->adjust_hp( -damage );

   if(obj->query_monitor())
      HEALTH_H->monitor_points(obj, 0);
} /* do_fall() */

/**
 * @ignore yes
 * Deals with falling through or off roofs. also takes care of dropped
 * items/corpses on sloped roofs.
 */
void event_enter( object obj, object from ) {
   int totalweight, objectweight, i;
   float encum, diff;
   int fall;
   object * contents;
   object destination;

   if( !obj ) return;

   if( obj->query_property( "demon" )
     || obj->query_property( "floating" ) ) {
      return;
   }

   // deal with weak roofs.  Calculate the total weight of the objects
   // here, including carried items.
   if( roof_max_weight ) {
      contents = all_inventory( TO );

      for( i = 0; i < sizeof(contents); i++ ) {
         objectweight = contents[i]->query_weight();
         objectweight += contents[i]->query_loc_weight();
         totalweight += objectweight;
#ifdef DEBUG
         debug_printf( "event_enter: Total weight of %s is %d units.\n",
           obj->query_name(), objectweight );
#endif
      }
#ifdef DEBUG
      debug_printf( "event_enter: The current weight on this roof is %d "
        "units. Max weight is set to %d.\n", totalweight, roof_max_weight );
#endif

      // Have we exceeded the maxweight?
      if( totalweight > roof_max_weight ) {
         fall = 1;
         tell_room( environment( obj ), weak_messages[3] );
         if( !(destination = load_object( weak_roof_dest ) ) ) {
            tell_room( TO, "Error loading room "
              + weak_roof_dest + ", moving you to the void.\n"
              "Please contact a creator.\n" );
            for( i = 0; i < sizeof(contents); i++ )
               contents[i]->move_with_look( "/room/void" );
            return;
         }
         for( i = 0; i < sizeof(contents); i++ )
            call_out( "do_fall", 1, contents[i], destination, "weak",
              weak_messages, 0 );
      }
   }

   if( gradient && !fall ) {
      if( living( obj ) ) {
         if( ( obj->query_property( "dead" ) )
           || !( obj->query_max_weight() ) ) {
            call_out( "do_fall", 1, obj, slope_dest, "step",
              ghost_fall_messages );
            return;
         }
         encum = ( 100 * to_float( obj->query_loc_weight() ) )
           / to_float( obj->query_max_weight() );
         diff = to_int( sin( ( 3.1415926536 / 180.0 ) * gradient )
           * ( encum * 10 ) );
         call_out( "gradient_check", 1, obj, slope_dest,
           to_int( diff + ( gradient * 2 ) ) );
      } else {
         if( member_array( obj->query_name(),
           ({ "death", "binky" }) ) >= 0 )
            return;
         if( gradient > 3 ) {
            if( obj->query_corpse() ) {
               obj->move( slope_dest,
                 process_mess( corpse_slope_messages[1], obj, 0 ),
                 process_mess( corpse_slope_messages[0], obj, 0 ) );
            } else {
               obj->move( slope_dest,
                 process_mess( item_slope_messages[1], obj, 0 ),
                 process_mess( item_slope_messages[0], obj, 0 ) );
            }
         }
      }
   }
} /* event_enter() */

/** @ignore yes
 *  Internal function to perform the skillcheck for sloping roofs.
 */
void gradient_check( object obj, string destination, int diff ) {
   object destob;

#ifdef DEBUG
   debug_printf( "gradient_check( %s, \"%s\", %d )",
     obj->query_name(), destination, diff );
#endif

   switch( TASKER->perform_task( obj, ROCK, diff + 1, TM_FIXED ) ) {
   case AWARD:
      tell_object( obj, "%^YELLOW%^" + ({
        "You balance more confidently on the " + place + ".",
        "Climbing becomes easier."
      })[ random(2) ] + "%^RESET%^\n" );
   case SUCCEED:
      tell_object( obj, "The " + place + " is steep, but you manage "
        "not to fall.\n" );
      break;
   case FAIL:
      if( !( destob = load_object( destination ) ) ) {
         tell_object( obj, "Error loading room " + destination +
           ", moving you to the void.\nPlease contact a creator.\n" );
         obj->move_with_look( "/room/void" );
      } else
         do_fall( obj, destob, "slope", slope_messages, 0 );
      break;
   default:
      write( "Gnaaaaaaaaaaaah! You should not be getting this message.  "
        "Please contact a creator.\n" );
      break;
   }
} /* gradient_check() */

/** @ignore yes */
int do_roofjump( string dir ){
   mixed * info;
   int distance;
   float weight, max_weight;
   object destination, fall_destination;
   string key;

   if( !( key = translations[dir] ) || !( info = jump_info[key] ) ) {
      add_failed_mess( "You can't jump there!\n" );
      return 0;
   }

   if( !(destination = load_object( info[0] ) ) ) {
      add_failed_mess( "Error! The file " + info[0] + " does not exist "
        "or does not load. Please contact a creator.\n" );
      return 0;
   }
   if( !(fall_destination = load_object( info[1] ) ) ) {
      add_failed_mess( "Error! The file " + info[1] + " does not exist "
        "or does not load. Please contact a creator.\n" );
      return 0;
   }
   distance = info[2];

   if( distance ) {
      weight = TP->query_loc_weight();
      max_weight = TP->query_max_weight();
      // at this rate, a 300-bonus, unencumbered
      // player can handle a 20-foot gap.
      distance *= to_float( ( to_float(weight) * 7) /
           to_float(max_weight) ) + 15;

      switch( TASKER->perform_task( TP, ROCK, distance, TM_FIXED ) ) {
         case AWARD:
            write( "%^YELLOW%^"
              + jump_tm_messages[ random( sizeof( jump_tm_messages ) ) ]
              + "%^RESET%^\n" );
         case SUCCEED:
            write( process_mess( jump_success_messages[0], TP, dir ) );
            TP->move_with_look( destination,
              process_mess( jump_success_messages[2], TP, dir ),
              process_mess( jump_success_messages[1], TP, dir ), );
            break;
         case FAIL:
            do_fall( TP, fall_destination, "jump",
              jump_failure_messages, dir );
            break;
         default:
            write( "Oh dear. Something is broken. Please inform a "
              "creator.\n" );
      }
      return 1;
   }
} /* do_roofjump() */

/** @ignore yes */
string query_death_reason() {
   call_out( (: death_reason = 0 :), 2 );
   if( death_reason )
      return PLAYER_OBJ->convert_message( death_reason );
   return "a rooftop (" + file_name( TO )
     + ") with an incorrectly set death message";
} /* query_death_reason() */

/** @ignore yes */
void set_death_reason( string str ) {
   death_reason = str;
} /* set_death_reason() */

/** @ignore yes */
string process_string( string str, mapping transforms ) {
   string foo, bar;

   foreach( foo, bar in transforms )
      if( bar ) str = replace_string( str, foo, bar );
   return PLAYER_OBJ->convert_message( str );
} /* process_string() */

/** @ignore yes */
string process_mess( string str, object ob, string direction ) {
   string opp_dir;
   string * directions = ({ "north", "northeast", "east", "southeast",
     "south", "southwest", "west", "northwest" });

   if( !str || ( str == "" ) )
      return "";

   if( stringp( direction ) ) {
      if( member_array( direction, directions ) < 0 ) {
         opp_dir = 0;
      } else {
         opp_dir =
           directions[ ( member_array( direction, directions ) + 4 ) % 8 ];
      }
   }

   str = process_string( str, ([
     "$dir$"       : direction,
     "$opp_dir$"   : opp_dir,
     "$short$"     : ob->query_short(),
     "$poss$"      : ob->query_possessive(),
     "$pronoun$"   : ob->query_pronoun(),
     "$obj$"       : ob->query_objective(),
     "$a_short$"   : ob->a_short(),
     "$the_short$" : ob->the_short(),
     "$one_short$" : ob->one_short()
   ]) );

   return implode( explode( str, ". " ),
     (: "$C$" + $1 + ". " + "$C$" + $2 :) );
} /* process_mess() */