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/
#include <group_handler.h>
#include <function.h>
#include <player.h>

// Define IN_TESTING below if you want to restrict the usage of
// these commands only to creators, playtesters and test
// characters.

#undef IN_TESTING

// Define IN_STRICT_TESTING in addition to IN_TESTING if
// you wish only creators to be able to use the commands.

#undef IN_STRICT_TESTING

mixed *_patterns;
mapping _sub_commands;

class sub_command {
   // The verb is the key of the _sub_commands mapping.
   string file_name;         // Where the sub-command file is located
   mixed *data;         // This contains alternating elements of
                        // (string)command patterns and (function)
                        // function pointers to the command.
}


#if defined( IN_TESTING ) || defined( IN_STRICT_TESTING )
int allowed_to_use( object user );
#endif

void rehash_group_sub_commands();
void make_patterns_array();
mixed *query_patterns();

int group_command_control( string verb, mixed *indirect_obs,
   string dir_match, string indir_match, mixed *args, string pattern );

int do_help( string on_what );


void create() {
   rehash_group_sub_commands();
   make_patterns_array();
} /* create() */


/* This function reads the GROUP_SUB_CMDS_DIR for files matching
 * GROUP_SUB_CMDS_FILE_WILDCARD, loads them one by one, and extracts
 * information from them if they respond to the group sub command
 * signature function.
 */
void rehash_group_sub_commands() {

   mixed *files;                         // An array of the files in the dir.
   object cmd_object;                    // The active object being used.
   string dir, verb, file, pattern;      // Stuff to be extracted and shuffled
                                         // around.
   
   // flush the sub commands
   _sub_commands = ([ ]);
   
   dir = GROUP_SUB_CMDS_DIR;
   dir += GROUP_SUB_CMDS_FILE_WILDCARD;
   
   // read the group sub-command directory for command files
   files = get_dir( dir );
   
   // if there were no files found, stop
   if( !sizeof( files ) ) {
      return;
   }
   
   // iterate through the files and add data to the mapping
   foreach( file in files ) {

      // remove the file extension
      sscanf( file, "%s.%*s", file );
      
      // load the file or find it if it's already loaded
      cmd_object = load_object( ( GROUP_SUB_CMDS_DIR + file ) );
      
      if( !cmd_object ) {
         // can't be loaded.  Probably broken, so let's skip it.
         continue;
      }

      // if the file isn't a group sub-command file
      if( !cmd_object->query_group_sub_command_amount() ) {
         continue;
      }
      
      // find all verbs the command has declared and
      // iterate through them
      foreach( verb in cmd_object->query_group_sub_command_verbs() ) {

         // if this is an entirely new verb and not just an additional
         // pattern
         if( !_sub_commands[ verb ] ) {         
            // assign a new entry for it
            _sub_commands += ([ verb : new( class sub_command ) ]);
         }
         
         _sub_commands[ verb ]->data = ( mixed * )({ });
         _sub_commands[ verb ]->file_name = ( string )file_name( cmd_object );
         
         // fetch all the patterns for that verb
         foreach( pattern in
            cmd_object->query_group_sub_command_patterns( verb ) ) {
            
            // add the pattern and the corresponding command function to
            // the entry
            _sub_commands[ verb ]->data +=
               ({
               pattern,
               cmd_object->query_group_sub_command_function( verb, pattern )
               });

         }  // foreach pattern
      }  // foreach verb
   } // foreach file

} /* rehash_group_sub_commands() */


int group_command_control( string verb, mixed *indirect_obs,
   string dir_match, string indir_match, mixed *args, string pattern ) {
   
   int count, size;
   string cmd_pattern, mangled_pattern, group;
   function cmd_fun;
   object cmd_object;
   class sub_command info;

#if defined( IN_TESTING ) || defined( IN_STRICT_TESTING )
   if( !allowed_to_use( this_player() ) ) {
      return 0;
   }
#endif

   info = _sub_commands[ verb ];
   
   if( !info ) {
      printf( "ERROR: Command information for \"" + verb + "\""
         " not found.\n" );
      return 0;   
   }
   
   // find the right version of the command (there can be different
   // patterns for the same verb)

   if( pattern != verb ) {
      // means the command takes arguments -- let's get rid
      // of the verb name from the front
      sscanf( pattern, verb + " %s", mangled_pattern );
   }
   else {
      // means the command takes no arguments
      mangled_pattern = "";
   }
   
   size = sizeof( info->data );   

   for( count = 0; count < size; count += 2 ) {
      if( mangled_pattern == info->data[ count ] ) {
         // we now have a match on the verb and the pattern wanted.
         cmd_pattern = info->data[ count ];
         cmd_fun     = info->data[ count + 1 ];
         break;
      }
   }
   
   if( !cmd_pattern || !cmd_fun ) {
      printf( "ERROR: Correct version of \"" + verb + "\" not found.\n" );
      tell_creator( this_player(), "DEBUG: Verb: %s, pattern: %s\n",
         verb, pattern );
      return 0;
   }
   
   if( !cmd_object = load_object( info->file_name ) ) {
      // object's probably broken
      printf( "ERROR: Cannot load command \"" + verb + "\"!\n" );
      tell_creator( this_player(), "DEBUG: File name: %s\n", info->file_name );
      return 0;
   }   

   // if the command function's pointer has been destructed.. This happens
   // when the command object is unloaded after a period of unuse.
   if( functionp( cmd_fun ) & FP_OWNER_DESTED ) {   
      // try to re-acquire the pointer and update the entry as well
      info->data[ count + 1 ] = cmd_fun =
         cmd_object->query_group_sub_command_function( verb, cmd_pattern );         
   }
   
   // if the pointer couldn't be re-acquired
   if( !cmd_fun || !functionp( cmd_fun ) ) {
      printf( "ERROR: Could not find command function for verb " +
         "\"" + verb + "\".\n" );
      return 0;   
   }

   group = this_player()->query_group();
   
   // Check if the command requires this_player() to be a member of
   // a group.
   if( cmd_object->query_membership_required( verb, cmd_pattern ) > 0 ) {
      if( !group ) {
         return notify_fail( "You must be a member of a group in order "
            "to use this command.\n" );
      }
   }
   
   // Check if the command requires the command user to be the leader
   // of the group.
   if( cmd_object->query_leadership_required( verb, cmd_pattern ) > 0 ) {
      if( GROUP->leader_of( group ) != this_player() ) {
         return notify_fail( "Only the leader of a group can use this "
            "command.\n" );
      }
   }
   
   // Call the command function on it and return what it returned
   
   // The parameters for it are identical to a normal add_command(),
   // with the exception of an additional one which designates the
   // command user's current group, if any.
   
   return evaluate( cmd_fun, indirect_obs, dir_match, indir_match,
      args, pattern, group );

} /* group_command_control() */


int do_help( string on_what ) {
   
   int top_left;
   string help, message;
   object command;
   
   on_what = lower_case( on_what );

#if defined( IN_TESTING ) || defined( IN_STRICT_TESTING )
   if( !allowed_to_use( this_player() ) ) {
      return 0;
   }
#endif

   if( on_what == "help" ) {
      // "group help help"
      return notify_fail( "To get help on a command, use \"group help <sub-"
         "command>\".  That is, if you wanted to get help on the command "
         "\"group create <name>\", you would type \"group help create\".\n" );
   }
   
   // such a sub-command doesn't exist
   if( !_sub_commands[ on_what ] ) {
      return notify_fail( "There is no sub-command called \"" + on_what +
         "\".\n" );
   }

   command = load_object( _sub_commands[ on_what ]->file_name );
   
   if( !command ) {
      tell_creator( this_player(), "Alleged file name: %s\n",
         _sub_commands[ on_what ]->file_name );
      return notify_fail( "ERROR: Cannot find or load sub-command "
         "\"" + on_what + "\".\n" );
   }
   
   help = command->query_help_string_for( on_what );
   
   if( !help ) {
      return notify_fail( "No help found for sub-command \"" + on_what +
         "\".\n" );
   }
   
   top_left = this_player()->query_cols();
   
   message = sprintf(
      "\n%' '|*s\n"
      "%' '-=*s\n",
      top_left, "Help on sub-command \"" + on_what + "\":\n",
      top_left, help );
   
   this_player()->more_string( message );
   
   return 1;
   
} /* do_help() */


/* This function parses all defined group subcommand classes into
 * a form that the parser understands.  I.e. one that can be
 * returned with query_patterns()
 */
void make_patterns_array() {

   int count, size;
   string verb, pattern;
   class sub_command command;

   // flush the patterns
   _patterns = ({ });

   // Establish a separate command for the help thingie.
   _patterns += ({
      "help <word'sub-command'>", (: do_help( $4[ 0 ] ) :) });
      
   // iterate through the commands   
   foreach( verb, command in _sub_commands ) {

      // get the verb and the pattern from the command
      // and stick them into a pattern entry to the
      // group command controller.
   
      size = sizeof( command->data );
      
      // multiple patterns for one verb?  Certainly possible.
      for( count = 0; count < size; count += 2 ) {

         // these checks are to ensure things' not breaking
         // if a verb doesn't take any arguments

         if( sizeof( command->data[ count ] ) ) {
            pattern = verb + " " + command->data[ count  ];
         }
         else {
            pattern = verb;
         }
      
         _patterns += ({
            pattern, (: group_command_control( $( verb ), $1, $2, $3, $4,
               $5 ) :) });
      }   
   }
} /* make_patterns_array() */


mixed *query_patterns() {
   return _patterns;   
} /* query_patterns() */


#if defined( IN_TESTING ) || defined( IN_STRICT_TESTING )
int allowed_to_use( object user ) {
#endif

#ifdef IN_STICT_TESTING
   if( !user->query_creator() ) {
      tell_object( user, "You are not allowed to use this feature at this "
         "time.\n" );
      return 0;
   }
#endif

#ifdef IN_TESTING
   if( !PLAYTESTER_HAND->query_tester( user ) ) {
      tell_object( user, "You are not allowed to use this feature at this "
         "time.\n" );
      return 0;
   }
#endif

#if defined( IN_TESTING ) || defined( IN_STRICT_TESTING )
   return 1;
} /* allowed_to_use() */
#endif


// Debug.
mapping dump_info() { return _sub_commands; }
mixed *dump_patterns() { return _patterns; }