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 <broadcaster.h>
#include <command.h>
#include <group_handler.h>

// Magic numbers for messages.
#define BROADCASTER_NAME     0
#define MESSAGE              1
#define DATA                 0
#define TIME                 1
#define TO_BROADCASTER       0
#define TO_OTHERS            1

inherit "/std/effect_shadow";

int _time_joined;
string _group, _parsed_prefix;
object _player, *_assisting, *_assisters, *_preparing_to_attack;

int add_assister( object member );
int remove_assister( object member );
void rebuild_parsed_prefix();

/** @ignore yes */
object attach_to_player( object p, int i ) {

   _player = p;
   _time_joined = time();

   _assisting = ({ });
   _assisters = ({ });
   _preparing_to_attack = ({ });

   return ::attach_to_player( p, i );

} /* attach_to_player() */

/** @ignore yes */
void event_quit( object me ) {
    object tmp;

    tmp = _player; // Store it locally.
    GROUP->remove_member( _group, _player );
    tmp->event_quit( me );

} /* event_quit() */

/** @ignore yes */
string query_group() { return _group; }

// This function is called always when a player receives
// membership to a group.  Whether it's a completely new
// group, or the new name of a renamed group.
void group_membership_added( string group ) {
    _group = group;
    rebuild_parsed_prefix();
} /* group_membership_added() */

/** @ignore yes */
void group_membership_removed() { remove_this_effect(); }

/** @ignore yes */
void rebuild_parsed_prefix() {

   string channel_name;

   tell_creator( _player, "[DEBUG]: Rebuilding channel prefix.\n");

   if( sizeof( _group ) <= GROUP_CHANNEL_MAX_CHARS ||
       GROUP_CHANNEL_MAX_CHARS <= 3 ) {
       channel_name = _group;
   } else {
       channel_name = _group[ 0..( GROUP_CHANNEL_MAX_CHARS - 4 ) ];
       channel_name += "...";
   }

   _parsed_prefix = GROUP_NOTIFY_PREFIX;
   _parsed_prefix = replace( _parsed_prefix,
      ({
         "$channel$", channel_name,
         "$colour$", _player->colour_event( GROUP_COLOUR_EVENT, "" )
      }) );

} /* rebuild_parsed_prefix() */

/** @ignore yes */
string query_parsed_prefix() { return _parsed_prefix; }

// Group members are visible to the group's leader.
int query_visible( object looker ) {
   string looker_group;

   // Safe guard for creators.
   if( _player->query_invis() && !looker->query_property("test character") )
       return _player->query_visible( looker );

   looker_group = looker->query_group();

   // If I'm a member of the looker's group, and he's using a group
   // command, then I'm visible to him.
   if( looker != _player && query_verb() == "group" &&
       GROUP->is_member( looker_group, _player ) )
       return 1;

   // Else return default.
   return _player->query_visible( looker );

} /* query_visible() */

void set_my_colours( string event, string colour ) {
   _player->set_my_colours( event, colour );
   if( event == GROUP_COLOUR_EVENT )
       rebuild_parsed_prefix();
} /* set_my_colours() */

int attack_by( object attacker ) {
   object assists_me;
   int delay;
   int retval;

   retval = player->attack_by( attacker );

   if( !retval )
       return retval;

   _assisters -= ({ 0 });

   foreach( assists_me in _assisters ) {
      // He's already fighting the attacker.
      if( member_array( attacker, assists_me->query_attacker_list() ) != -1 )
          continue;

      // He's not in my group.
      if( !GROUP->is_member( _group, assists_me ) ) {
          remove_assister( assists_me );
          continue;
      }

      // He's not in the same room.
      if( ENV( assists_me ) != ENV( _player ) )
          continue;

      if( pk_check( assists_me, attacker ) )
          continue;

      delay = 16 - sqrt( assists_me->query_skill_bonus("general.perception") );
      delay -= random( 3 );

      if( delay < 1 )
          delay = 1;

      delay = delay * sizeof( assists_me->query_assisting() );

      tell_creator( assists_me, "(DEBUG) Moving in to assist %s "
         "fighting %s in %i seconds.\n", _player->query_cap_name(),
         file_name( attacker ), delay );

      assists_me->commence_assist( _player, attacker, delay );

   }

   return retval;

} /* attack_by() */

void commence_assist( object person_to_help, object target_to_attack,
                      int delay ) {

   if( member_array( target_to_attack, _preparing_to_attack ) != -1 )
       return;

   _preparing_to_attack += ({ target_to_attack });

   call_out("assist_member", delay, target_to_attack, person_to_help );

} /* commence_assist() */

void assist_member( object attacker, object assisting ) {
   object *my_attacker_list, *his_attacker_list;

   _preparing_to_attack -= ({ attacker, 0 });

   if( !assisting || !attacker )
       return;

   my_attacker_list = _player->query_attacker_list();
   his_attacker_list = assisting->query_attacker_list();

   // I'm already fighting this guy, or at least
   // preparing to fight.
   if( member_array( attacker, my_attacker_list ) != -1 )
       return;

   // He's no longer fighting this guy.
   if( member_array( attacker, his_attacker_list ) == -1 )
       return;

   if( attacker == _player || assisting == _player ||
       ENV( attacker ) != ENV( _player ) )
       return;

    // We're not assisting them any more.
    if( member_array( assisting, _assisting ) == -1 )
        return;

   if( _player->attack_ob( attacker ) ) {
       if( !sizeof( my_attacker_list | _preparing_to_attack ) ) {
           _player->add_message("Noting the intentions of "+
               attacker->the_short()+", you move in to assist "+
               assisting->the_short()+".\n", ({ }) );
           return;
       }

       _player->add_message("You note the intentions of "+
           attacker->the_short()+" and prepare to attack "+
           attacker->HIM+" as well.\n", ({ }) );
   }

} /* assist_member() */

int add_assister( object member ) {
   _assisters -= ({ 0 });
   if( member_array( member, _assisters ) != -1 )
       return 0;
   _assisters += ({ member });
   member->add_assisting( _player );
   return 1;
} /* add_assister() */

void add_assisting( object member ) {
   _assisting -= ({ 0 });
   if( member_array( member, _assisting ) != -1 )
       return;
   _assisting += ({ member });
} /* add_assisting() */

int remove_assister( object member ) {
   _assisters -= ({ 0 });
   if( member_array( member, _assisters ) == -1 )
       return 0;
   _assisters -= ({ member });
   member->remove_assisting( _player );
   return 1;
} /* remove_assister() */

void remove_assisting( object member ) {
   _assisting -= ({ 0 });
   _assisting -= ({ member });
} /* remove_assisting() */

object *query_assisting() {
   _assisting -= ({ 0 });
   return _assisting;
} /* query_assisting() */

object *query_assisters() {
   _assisters -= ({ 0 });
   return _assisters;
} /* query_assisters() */

void event_channel_message( object broadcaster, string channel, mixed data ) {
   mixed message;
   string msg, colour;

   message = data[ 0 ];

   if( channel != "group_"+_group ) {
       call_out( (: remove_this_effect() :), 1 );
       return;
   }

   if( !GROUP->is_member( _group, _player ) ) {
       call_out( (: remove_this_effect() :), 1 );
       return;
   }

   colour = _player->colour_event( GROUP_COLOUR_EVENT, "" );

   msg = "";

   if( stringp( message ) ) {
       msg += message;
   } else if( arrayp( message ) ) {
       if( broadcaster == _player ) {
           if( message[ TO_BROADCASTER ] ) {
               msg += message[ TO_BROADCASTER ];
           } else {
               return;
           }
       } else if( message[ TO_OTHERS ] ) {
           msg += message[ TO_OTHERS ];
       } else {
           return;
       }
   }

   msg += "\n";
   msg = replace( msg, ({ "%^RESET%^", ( "%^RESET%^" + colour ),
                          "\n", "%^RESET%^\n"}) );

   msg = _parsed_prefix + colour + msg;

   tell_object( _player, msg );

} /* event_channel_message() */

void display_group_history() {
   int indent_a, indent_b;
   mixed *bit, *history;
   string whole, message, prefix, suffix;

   /* This is a convoluted function because of the hack-job I
    * did with the message structure.  Basically, this is
    * what one message consists of:
    *    bit =
    *    ({
    *       [0] broadcaster's name (capitalized),
    *       [1] ({
    *             [0] either array: ({ msg_to_broadcaster, msg_to_rest }) or
    *               msg_to_all,
    *             [1] time() when the broadcast was made
    *           })
    *    })
    */

   if( !GROUP->is_member( _group, _player ) ) {
       call_out( (: remove_this_effect() :), 0 );
       return;
   }

   history = BROADCASTER->query_channel_history( "group_" + _group );

   if( !sizeof( history ) ) {
       tell_object( this_player(), "Nothing has been said on your "
           "group's channel.\n" );
       return;
   }

   if( TP != _player ) {
       tell_object( TP, "Shame on you.\n");
       return;
   }

   prefix = _parsed_prefix;

   // This is a bit of a hack, but I don't feel like rewriting
   // the messaging system.  And it's not that ugly.
   sscanf( GROUP_NOTIFY_PREFIX, "$I$+%d,+%d=", indent_a, indent_b );
   suffix = "$I$-" + indent_a + ",-" + indent_b + "=\n";

   whole = "";

   foreach( bit in history ) {
      if( bit[ MESSAGE ][ TIME ] < _time_joined ) {
          // The message was broadcasted before this member
          // joined the group.  We skip it.
          continue;
      }

      // message = "** " + ctime( bit[ MESSAGE ][ TIME ] ) + " **:\n";
      message = ctime(bit[MESSAGE][TIME])[11..18];
      message += prefix;

      if( bit[ MESSAGE ][ DATA ] && stringp( bit[ MESSAGE ][ DATA ] ) ) {
          // The message is general to everyone.
          message += bit[ MESSAGE ][ DATA ];
          message += "$I$-5,-0=\n";
          whole += message;
          continue;
      }

      if( !arrayp( bit[ MESSAGE ][ DATA ] ) ) {
          // Something's gone wrong.
          continue;
      }

      // The message is an array divided to two parts: the first
      // element is the message the broadcaster received ("You..."),
      // the second is what everyone else received.
      if( bit[ BROADCASTER_NAME ] &&
          lower_case( bit[ BROADCASTER_NAME ] ) == _player->query_name() ) {
          // The broadcaster is the person listening.
          if( bit[ MESSAGE ][ DATA ][ TO_BROADCASTER ] ) {
              // We give him msg_to_broadcaster, the first.
              message += bit[ MESSAGE ][ DATA ][ TO_BROADCASTER ];
          }
      } else if( bit[ MESSAGE ][ DATA ][ TO_OTHERS ] ) {
          // The broadcaster is someone else.  We give him msg_to_rest.
          message += bit[ MESSAGE ][ DATA ][ TO_OTHERS ];
      }

      whole += message + suffix;

   }

   tell_object( TP, whole );

} /* display_channel_history() */

varargs int adjust_xp( int original_xp, int shared ) {
   int plvl, olvl, xp, share;
   object other, *others;

   if( original_xp < 0 || !shared )
       return ( int )player->adjust_xp( original_xp );

   others = GROUP->members_of( _group );

   if( !sizeof( others ) ) {
       call_out( (: remove_this_effect() :), 1 );
       return ( int )player->adjust_xp( original_xp );
   }

   if( sizeof( others ) == 1 )
       return ( int )player->adjust_xp( original_xp );

   // the more people in the team the smaller the shared Xp.
   xp = ( original_xp * 2 ) / sizeof(others);

   plvl = (int)player->query_level() / 2;

   foreach( other in others - ({ _player }) ) {
       if( !objectp( other ) )
           continue;

       if( ENV( other ) != ENV( _player ) )
           continue;

       olvl = (int)other->query_level();

       if( olvl <= plvl && plvl ) {
           share = ( xp * ( 1 + ( 99 * olvl ) / plvl ) ) / 100;
       } else {
           share = xp;
       }

       tell_creator( _player, "%s's share: %i\n", other->query_name(),
           share );

       other->adjust_xp( share, 0 );

   }

   tell_creator( _player, "%s's share: %i\n", _player->query_name(),
      original_xp );

   return ( int )player->adjust_xp( original_xp );

} /* adjust_xp() */

/**
 * This bit coded completely by Ceres.  Or was it Deutha?  In
 * any case, thanks to them.
 */
varargs int add_skill_level( string skill, int lvl, mixed exp ) {
   int diff_0, diff_1, diff, width_0, width, ret;
   object other, *others;

   ret = _player->add_skill_level( skill, lvl, exp );

   if( !ret ) {
        // If they didn't actually get an advance due to hitting a limit or
        // whatever then don't give their team an advance either.
       return ret;
   }

   // Not sharing already shared TMs, TMs from contemplate, skill
   // level advancements from 'advance', perception and points TMs.
   if( objectp( exp ) && base_name( exp ) == base_name( TO ) ||
       ( PO && file_name( PO ) == CONTEMPLATE ) || lvl != 1 ||
       intp( exp ) || skill == "general.perception" ||
       ( skill[ <7.. ] == ".points" ) )
       return ret;

   if( !_group ) {
       // Something's messed up.
       call_out( (: remove_this_effect() :), 1 );
       return ret;
   }

   others = (object *)GROUP->members_of( _group );
   others -= ({ 0 });

   if( !sizeof( others ) ) {
       // Something's REALLY messed up.
       call_out( (: remove_this_effect() :), 1 );
       return ret;
   }

   others -= ({ _player });

   if( !sizeof( others ) ) {
       // He's soloing.
       return ret;
   }

   diff_0 = (int)_player->query_skill_bonus( skill );
   diff_1 = (int)_player->query_skill( skill );
   width_0 = (int)_player->stat_modify( 25 * 25, skill );

   foreach ( other in others ) {
      if( !objectp( other ) )
          continue;

      if( ENV( other ) != ENV( _player ) )
          continue;

      if( diff_0 - (int)other->query_skill_bonus( skill ) >
          diff_1 - (int)other->query_skill( skill ) ) {
          diff = diff_0 - (int)other->query_skill_bonus( skill );
      } else {
          diff = diff_1 - (int)other->query_skill( skill );
      }

      width = (int)other->stat_modify( width_0, skill );

      if( random( width + diff * diff +
          sqrt( other->query_skill( skill ) ) ) < ( width / 2 ) &&
          other->add_skill_level( skill, lvl, TO ) ) {
          tell_object( other, "%^YELLOW%^By watching "+
              (string)_player->the_short()+", you feel you have learnt "
              "something.%^RESET%^\n");
      }
   }

   return 1;

} /* add_skill_level() */