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:  $
 * $Id: broadcaster.c,v 1.12 2002/06/15 00:58:52 pinkfish Exp $
 * $Log: broadcaster.c,v $
 * Revision 1.12  2002/06/15 00:58:52  pinkfish
 * Fix up some issues.
 *
 * Revision 1.11  1999/09/15 02:44:36  pinkfish
 * Make it handle unguardeding the save/loads.
 *
 * Revision 1.10  1999/06/04 00:46:34  pinkfish
 * Make it handle lots of people online when someone shouts.
 *
 * Revision 1.9  1999/05/15 23:43:34  ceres
 * Modified to only colour shouts (hopefully)
 *
 * Revision 1.7  1999/04/19 20:25:37  pinkfish
 * Fix up an error that was causing a runtime.
 *
 * Revision 1.6  1999/01/30 23:12:38  pinkfish
 * Make it remove empty channels and add in a method to determine if a
 * channel exists or not.
 *
 * Revision 1.5  1998/10/23 08:41:00  pinkfish
 * Added in a channel history feasture.
 *
 * Revision 1.3  1998/10/11 12:34:35  pinkfish
 * Add in code to the broadcaster to deal with channels.
 *
 * Revision 1.2  1998/04/06 07:02:48  sin
 * Installed Shaggy's change to keep track of NPCs who want to hear shouts.
 *
 * Revision 1.1  1998/01/06 05:03:33  ceres
 * Initial revision
 * 
*/
/**
 * Basic sight and sound broadcaster.
 */

#define DIR_ARRAY ({ "east", "northeast", "north", "northwest", \
                     "west", "southwest", "south", "southeast", "east" })

#define SAVE_FILE "/save/broadcaster"
#define BROADCAST_HISTORY_LENGTH 10

void broadcast_event( object *things,   /* things that get told about it */
                      int *centre,      /* coords where event occurs */
                      string message,   /* what the things get told */
                      int range,        /* range of telling in room units */
                      int inside,       /* tell things if indoors */
                      int underwater ); /* tell things if underwater */
void npc_hear_shouts(object newlistener);
int npc_unhear_shouts(object oldlistener);
void npc_shout_event( object shouter,
                      string start, 
                      string message,
                      string lang, 
                      int *coord, 
                      int range ); /* arguments for event_person_shout */
private void load_me();
private void save_me();
  
private nosave object *_listeners;
private nosave mapping _channels;
private nosave mapping _channel_history;
private mapping _channel_ids;

void create() {
   _listeners = ({ });
   _channels = ([ ]);
   _channel_ids = ([ ]);
   _channel_history = ([ ]);
   load_me();
} /* create() */

/**
 * This method returns the square distance, the name of the direction
 * the sound comes from and the up down offset.  It is used by the shout
 * code and by various other things that require this inofmraiont.
 * The return array is formated as:<br>
 * ({ square_distance, name_of_direction, z_offset })
 * @param co_ord1 the first co-ordinate
 * @param co_ord2 the co-ordinate to compare against
 * @return the array as described above
 */
mixed *get_direc_dist( int *co_ord1, int *co_ord2 ) {
   int dx, dy, dz, sector;

   if (!pointerp(co_ord1) ||
       !pointerp(co_ord2)) {
      // Make it right here...
      return ({ 0, DIR_ARRAY[0], 0 });
   }

   dx = co_ord1[ 0 ] - co_ord2[ 0 ];
   dy = co_ord1[ 1 ] - co_ord2[ 1 ];
   dz = co_ord1[ 2 ] - co_ord2[ 2 ];
   if ( dx > 0 ) {
      if ( ( 1000 * dy ) > ( 2414 * dx ) ) {
         sector = 0;
      } else {
         if ( ( 1000 * dy ) > ( 414 * dx ) ) {
            sector = 1;
         } else {
            if ( ( 1000 * dy ) > ( -414 * dx ) ) {
               sector = 2;
            } else {
               if ( ( 1000 * dy ) > ( -2414 * dx ) ) {
                  sector = 3;
               } else {
                  sector = 4;
               }
            }
         }
      }
   } else {
      if ( ( 1000 * dy ) < ( 2414 * dx ) ) {
         sector = 4;
      } else {
         if ( ( 1000 * dy ) < ( 414 * dx ) ) {
            sector = 5;
         } else {
            if ( ( 1000 * dy ) < ( -414 * dx ) ) {
               sector = 6;
            } else {
               if ( ( 1000 * dy ) < ( -2414 * dx ) ) {
                  sector = 7;
               } else {
                  sector = 8;
               }
            }
         }
      }
   }
   return ({ dx * dx + dy * dy + dz * dz, DIR_ARRAY[ sector ], dz });
} /* get_direc_dist() */

/**
 * Sends an event out to all the things.  It checks to make sure they
 * can hear the event and all that stuff.
 *
 * @param things things that get told about it 
 * @param centre coords where event occurs 
 * @param message what the things get told 
 * @param range range of telling in room units 
 * @param inside tell things if indoors 
 * @param underwater tell things if underwater 
 */
void broadcast_event( object *things, int *centre, string message,
      int range, int inside, int underwater ) {
   int *to;
   string text;
   object thing, place;
   mixed *dir_direc;

   if ( !pointerp( things ) ||
        !pointerp( centre ) ||
        sizeof( centre ) != 3 ) {
      return;
   }
   foreach ( thing in things ) {
      if ( !living( thing ) ) {
         continue;
      }
      /* Maybe something to inform non-living things later */
      place = environment( thing );
      if ( !place ) {
         continue;
      }
      to = (int *)place->query_co_ord();
      if ( !pointerp( to ) || sizeof( to ) != 3 ) {
         continue;
      }
      switch ( (string)place->query_property( "location" ) ) {
         case "inside" :
            if ( !inside ) {
               continue;
            }
            break;
         case "underwater" :
            if ( !underwater ) {
               continue;
            }
            break;
         default :
      }
      dir_direc = get_direc_dist( centre, to );
      if ( dir_direc[ 0 ] < 0 ) {
         /* So far away it's hit two's complement. */
         continue;
      }
      /* Lo, no need for square roots. */
      if ( dir_direc[ 0 ] > range * range ) {
         continue;
      }
      // This code is huge and fluffy, need to reset the cost in here a
      // little.
      //reset_eval_cost();
      switch ( dir_direc[ 0 ] ) {
         case 0 :
            /* They're in the same room - they should get told elsewhere. */
            continue;
         case 1 .. 2500 :
            /* Very close: 1 to 50 units */
            if ( ( dir_direc[ 2 ] * dir_direc[ 2 ] ) > ( dir_direc[ 0 ] / 2 ) ) {
               if ( dir_direc[ 2 ] > 0 ) {
                  text = "Right above you, "+ message +"\n";
               } else {
                  text = "Right below you, "+ message +"\n";
               }
            } else {
               text = "Very close to the "+ dir_direc[ 1 ] + ", "+
                     message +"\n";
            }
            break;
         case 2501 .. 40000 :
            /* Nearby: 50 to 200 units */
            text = "Nearby to the "+ dir_direc[ 1 ] + ", "+ message +"\n";
            break;
         case 40001 .. 640000 :
            /* 200 to 800 units */
            text = "To the "+ dir_direc[ 1 ] + ", "+ message +"\n";
            break;
         case 640001 .. 10240000 :
            /* In the distance: 800 to 1600 units */
            text = "In the distance to the "+ dir_direc[ 1 ] + ", "+
                  message +"\n";
            break;
         default:
            /* Too far away */
            continue;
      }
      if(interactive(thing) && query_verb() == "shout") {
        text = thing->colour_event("shout", "") + text + "%^RESET%^";
      }
      thing->add_message( "$I$5="+ text, ({ }) );
   }
} /* broadcast_event() */

/**
 * Adds an NPC to the list of NPC's who are to receive shout events.
 * The NPC need not be removed from this list when he dies -- desting
 * the NPC object has the same effect as calling npc_unhear_shouts().
 * event_person_shout() is activated on the NPC for all shouts.
 * NPC's do not normally detect shouts.
 * event_person_shout() on the NPC should be replaced with similar code 
 * to that in the broadcaster to determine if the shouter is within 
 * range and to generate the desired response.
 *
 * @param newlistener NPC object to be added to the list
 *
 * @see /global/events->event_person_shout()
 * @see npc_unhear_shouts()
 */
void npc_hear_shouts(object newlistener) {
  int i;

  if (member_array(newlistener,_listeners)!=-1) {
     return;
  }
  i = member_array(0,_listeners);
  if (i != -1) {
    _listeners[i]=newlistener;
  } else {
    _listeners=_listeners+({newlistener});
  }
} /* npc_hear_shouts() */

/**
 * Removes an NPC from the list of NPC's who are to receive shout events.
 * The NPC need not be removed from this list when he dies -- desting
 * the NPC object has the same effect as calling npc_unhear_shouts().
 *
 * @param oldlistener NPC object to be removed from the list
 * @return 1 if successfully removed
 *
 * @see /global/events->event_person_shout()
 * @see npc_hear_shouts()
 */
int npc_unhear_shouts(object oldlistener) {
  int i;

  if (sizeof(_listeners)==0) {
    return 0;
  }

  i = member_array(oldlistener,_listeners);
  if (i == -1) {
    return 0;
  }

  // Remove the listener
  _listeners = _listeners[0..i] + _listeners[i+1..];
  return 1;
} /* npc_unhear_shouts() */

/**
 * This method is called by the shout command to filter the shouts onto
 * the npcs that are listening.
 * @param shouter the person who shouted
 * @param start the start of the message
 * @param message the message shouted
 * @param lang the language the message is in
 * @param coord the co-ordinate it was shouted from
 * @param range the range of the shout
 */
void npc_shout_event( object shouter, string start, string message,
      string lang, int *coord, int range ) {
  
  if (_listeners) {
    _listeners -= ({ 0 });
    _listeners->event_person_shout(shouter, start, message,
                                  lang, coord, range );
  }
} /* npc_shout_event() */

/**
 * This method adds an object to the list of objects to be told about the
 * specfied channel.  The method called on the object for the channel
 * will be event_channel_message.  The method will be called with
 * three arguements, the first is the object generating the event
 * the second is the channel the event is generated on and the
 * third is the message being sent to the channel.
 * @param channel_name the name of the channel
 * @param ob the object to add to the list
 */
void add_object_to_channel(string channel_name,
                           object ob) {
   if (!_channels[channel_name]) {
      _channels[channel_name] = ({ });
   }
   _channels[channel_name] += ({ ob });
} /* add_object_to_channel() */

/**
 * This method removes an object from the list of objects to be told about the
 * specified channel.
 * @param channel_name the name of the channel
 * @param ob the object to add to the channel
 */
int remove_object_from_channel(string channel_name,
                               object ob) {
   if (_channels[channel_name]) {
      if (member_array(ob, _channels[channel_name]) != -1) {
         _channels[channel_name] -= ({ ob });
         if (!sizeof(_channels[channel_name])) {
           map_delete(_channels, channel_name);
         }
         return 1;
      }
   }
   return 0;
} /* remove_object_from_channel() */

/**
 * Inform channel of message.  The message will get sent to all the objects
 * added to the list to the method event_channel_message.  The method
 * will be called with three arguements, first is the object that started
 * the event, the second the channel it is being send to and the last is the
 * message being sent to the channel.
 * @param ob the object creating the channel event
 * @param channel the channel to inform people about
 * @param message the message to tell the channel about
 */
void broadcast_to_channel(mixed ob,
                          string channel,
                          mixed message) {
   string str;

   if (!ob) {
      return ;
   }
   if (objectp(ob)) {
      str = ob->query_cap_name();
   }
   if (_channels[channel]) {
      _channels[channel] -= ({ 0 });
      _channels[channel]->event_channel_message(ob, channel, message);

      // Put the message into the history list.
      if (!_channel_history[channel]) {
         _channel_history[channel] = ({ });
      }
      _channel_history[channel] += ({ ({ str, message, time() }) });
      if (sizeof(_channel_history[channel]) > BROADCAST_HISTORY_LENGTH) {
         _channel_history[channel] = _channel_history[channel][1..];
      }
   }
} /* broadcast_to_channel() */

/**
 * This message returns the current history list for the channel.  The
 * array is:<br>
 * ({ ({ person, message }), ... })
 * @param channel the channel to get the history of
 * @return the history of the channel
 * @see broadcast_to_channel()
 */
mixed *query_channel_history(string channel) {
   return _channel_history[channel];
} /* query_channel_history() */

/**
 * This method must only be used for debugging purposes.
 * @param channel the channel which has all these things on it
 * @return the array of objects in the channel
 * @see is_channel()
 */
object *query_channel_members(string channel) {
   return _channels[channel];
} /* query_channel_members() */

/**
 * This method checks to see if the channel exists.
 * @param channel the channel name to check for
 * @return 1 if the channel eixsts, 0 if not
 * @see query_channel_members()
 */
int is_channel(string channel) {
  return !undefinedp(_channels[channel]);
} /* is_channel() */

/** @ignore yes.  THis is definately definately not allowed to be used
 * in code, it is only allow to be used specifically for debugging
 * purposes.
 * @return the nice mapping
 */
mapping query_all_channels() {
   return _channels;
} /* query_all_channels() */

/**
 * This method keeps track of an ever increasing number for a specified
 * channel type.  THis is used in the wizards spell (for instance) to
 * keep track of unique ids for wizard channels.
 * @param channel the name of the channel
 * @return the next number in the series
 */
int query_next_channel_number(string channel) {
   int next_num;

   next_num = ++_channel_ids[channel];
   save_me();
   return next_num;
} /* query_next_channel_number() */

private void save_me() {
   unguarded( (: save_object(SAVE_FILE) :) );
} /* save_me() */

private void load_me() {
   unguarded( (: restore_object(SAVE_FILE, 1) :) );
} /* load_me() */

/** @ignore yes */
mapping query_dynamic_auto_load() {
   return ([ "channels" : _channels,
       "history" : _channel_history ]);
} /* query_dynamic_auto_load() */

void init_dynamic_arg(mapping arg) {
   _channels = arg["channels"];
   if (!_channels) {
      _channels = ([ ]);
   }
   _channel_history = arg["history"];
   if (!_channel_history) {
      _channel_history = ([ ]);
   }
} /* init_dynamic_arg() */