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/
/**
 * The base chunk for doing multiplayer board games.
 * @author Pinkfish
 * @started Thu Dec  7 01:27:46 PST 2000
 */
private inherit "/std/basic/auto_load";

#define LOAD_TAG "multiplayer base"

class player_info {
   int number;
   string cap_name;
   string name;
   mixed data;
}

private mapping _players;
private string _winner;
private string* _ids_when_started;
private string _current_player;
private int _minimum_needed;
private int _maximum_allowed;
private int _can_join_as_new;
private int _game_started;

string* query_currently_playing_ids();
void delete_gone_players();
string find_player_id_of_person(object person);

void create() {
   _players = ([ ]);
   _ids_when_started = ({ });
} /* create() */

/**
 * This method should be defined in the top level, it should also
 * call this method to setup stuff as needed when a game starts.
 */
void reset_game() {
//   renumber_players();
} /* reset_game() */

/**
 * This method should be called when a game starts.
 * @return 1 if started, 0 if not enough players
 */
int start_game() {
   delete_gone_players();
   if (sizeof(query_currently_playing_ids()) < _minimum_needed) {
      return 0;
   }
   _winner = 0;
   _game_started = 1;
   _ids_when_started = query_currently_playing_ids();
   //
   // Pick one of these guys to start with.
   //
   _current_player = _ids_when_started[random(sizeof(_ids_when_started))];
   return 1;
} /* start_game() */

/**
 * This method is called when the game ends to set the winner.
 * @param winner the winner
 */
void finish_game(string winner) {
   _winner = winner;
   _game_started = 0;
} /* finish_game() */

/**
 * This method returns the current winner of the game.
 * @return the winner of the game
 */
string query_winner() {
   return _winner;
} /* query_winner() */

/**
 * This method checks to see if the game has started.
 * @return 1 if it has, 0 if it has not
 */
int is_game_started() {
   return _game_started;
} /* is_game_started() */

/**
 * This method checks to see if you can join as a new player, or only
 * occupy the slots from the start of the game.
 * @return 1 if you can join as new
 */
int can_join_as_new_player() {
   return _can_join_as_new;
} /* can_join_as_new_player() */

/**
 * This method sets the flag to allow you to make the game allow players
 * to join after they have started the game.
 * @param join 1 if they can join after the game has started
 */
void set_can_join_as_new_player(int join) {
   _can_join_as_new = join;
} /* set_can_join_as_new_player() */

/**
 * This method checks to see if the person is here.
 * @param person the person to check
 * @return 1 if they are, 0 if not
 */
int is_person_playing(string id) {
   if (_players[id]->name) {
      if (find_player(_players[id]->name) &&
          is_in_me_or_environment(this_object(),
                                  find_player(_players[id]->name)) &&
          interactive(find_player(_players[id]->name))) {
         return 1;
      }
   }
   return 0;
} /* is_person_player() */

/**
 * This method checks to see if the player is player.
 * @return 1 if they are playing, 0 if not
 */
int is_playing(object ob) {
   string id;

   id = find_player_id_of_person(ob);
   return id != 0;
} /* is_playing() */

/**
 * This method checks to see if the object is the current player or not.
 * @return 1 if they are, 0 if not
 */
int is_current_player(object ob) {
   string id;

   id = find_player_id_of_person(ob);
   return id == _current_player;
} /* is_current_player() */

/**
 * This method lets the person join the game.
 * @param id the id of the person to add
 * @param person the person to join
 * @return 1 on success, 0 on failure
 */
int add_person_to_game(string id, object person) {
   class player_info info;

   if (is_person_playing(id)) {
      return 0;
   }
   info = _players[id];
   //info->player_num = _current_player_num++;
   info->name = person->query_name();
   info->cap_name = person->query_cap_name();
   return 1;
} /* add_person_to_game() */

/**
 * This method removes a person from the game.
 * @param person the person to remove
 * @return 1 on success, 0 on failure
 */
int remove_person_object_from_game(object person) {
   class player_info info;
   string id;

   foreach (id, info in _players) {
      if (find_player(info->name) == person) {
         info->name = 0;
         info->cap_name = 0;
         return 1;
      }
   }
   return 0;
} /* remove_person_object_from_game() */

/**
 * This method removes a person from the game.
 * @param id the id to remove
 * @return 1 on success, 0 on failure
 */
int remove_person_id_from_game(string id) {
   if (_players[id]->name) {
      _players[id]->name = 0;
      return 1;
   }
   return 0;
} /* remove_person_object_from_game() */

/**
 * This method randomises the numbers  of the players.
 */
void randomise_player_numbers() {
   string* ids;
   int num;
   int pos;

   ids = keys(_players);
   num = 0;
   while (sizeof(ids)) {
      pos = random(sizeof(ids));
      _players[ids[pos]]->number = num;
      ids = ids[0..pos-1] + ids[pos+1..];
      num++;
   }
} /* randomise_player_nambers() */

/**
 * This method adds a type of allowed player.
 * @param id the id to be allowed
 * @param number the start player number
 */
void add_player_id_type(string id, int number) {
   _players[id] = new(class player_info);
   _players[id]->number = number;
} /* add_player_id_type() */

/**
 * This method removes a player id type.
 * @param id the id to remove
 */
void remove_player_id_type(string id) {
   map_delete(_players, id);
} /* remove_player_id_type() */

/**
 * This method figures out the info structure from the number of the player.
 * @param number the number to lookup
 * @return the info structure, 0 if not found
 */
class player_info find_player_info_from_number(int num) {
   class player_info info;
   string id;

   foreach (id, info in _players) {
      if (info->number == num) {
         return info;
      }
   }
   return 0;
} /* find_player_info_from_number() */

/**
 * This method figures out the id from the number of the player.
 * @param number the number to lookup
 * @return the id, 0 if not found
 */
string find_player_id_from_number(int num) {
   class player_info info;
   string id;

   foreach (id, info in _players) {
      if (info->number == num) {
         return id;
      }
   }
   return 0;
} /* find_player_info_from_number() */

/**
 * This method returns all the ids for the players.
 * @return the ids for the player
 */
string* query_player_ids() {
   return keys(_players);
} /* query_player_ids() */

/**
 * This method returns the list of ids who are current playing.
 * @return the list of currently playing ids
 */
string* query_currently_playing_ids() {
   return filter(keys(_players), (: _players[$1]->name :));
} /* query_currently_playing_ids() */

/**
 * This method returns the list of ids of people who started playing the
 * game.
 * @return the list of people who started playing the game
 */
string* query_started_player_ids() {
   return _ids_when_started;
} /* query_started_player_ids() */

/**
 * This method returns the players cap name from the player id.
 * @param id the id to look up from
 * @return the players cap name
 */
string query_player_cap_name(string id) {
   if (_players[id]->name) {
      return _players[id]->cap_name;
   }
   return "No one";
} /* query_player_cap_name() */

/**
 * This method returns the player object from the player id.
 * @param id the id for the player
 * @return the player object
 */
object query_player_object(string id) {
   return find_player(_players[id]->name);
} /* query_player_object() */

/**
 * This method nips through the list of players and checks to see if they
 * are in the room or not.  If they are not it deletes them from the array.
 * Useful for start games or cleanups.
 */
void delete_gone_players() {
   string id;
   class player_info info;

   foreach (id, info in _players) {
      if (info->name) {
         if (!find_player(info->name) ||
             !is_in_me_or_environment(this_object(), find_player(info->name))) {
            info->name = 0;
         }
      }
   }
} /* delete_gone_players() */

/**
 * This method sets the minimum number of players needed to play the
 * game.
 * @param minimum the minimum needed
 */
void set_minimum_needed(int minimun) {
   _minimum_needed = minimun;
} /* set_minimum_needed() */

/**
 * This method checks to see if the minimum requirements for starting the
 * game have been met.
 * @return 1 on success, 0 on failure
 */
int can_start_game() {
   if (sizeof(query_currently_playing_ids()) > _minimum_needed) {
      return 1;
   }
   return 0;
} /* can_start_game() */

/**
 * This method finds the next player to the specified one.
 * @param id the id of the player to find, 0 means current player
 * @return the next id
 */
string find_next_player(string id) {
   class player_info info;
   int start;
   int cur;
   string new_id;

   if (!id) {
      id = _current_player;
   }

   start = _players[id]->number;
   cur = start;
   do {
      cur = (cur + 1) % sizeof(_players);
      new_id = find_player_id_from_number(cur);
      info = _players[new_id];
   } while (((_can_join_as_new && !info->name) ||
            (!_can_join_as_new &&
                member_array(new_id, _ids_when_started) == -1)) &&
            cur != start);
   return new_id;
} /* find_next_player() */

/**
 * This method finds the previous player to the specified one.
 * @param id the id of the player to find, 0 means current player
 * @return the previous id
 */
string find_previous_player(string id) {
   class player_info info;
   int start;
   string new_id;
   int cur;

   if (!id) {
      id = _current_player;
   }

   start = _players[id]->number;
   cur = start;
   do {
      cur = (cur - 1 + sizeof(_players)) % sizeof(_players);
      new_id = find_player_id_from_number(cur);
      info = _players[new_id];
   } while (((_can_join_as_new && !info->name) ||
            (!_can_join_as_new &&
               member_array(new_id, _ids_when_started) == -1)) &&
            cur != start);
   return new_id;
} /* find_previous_player() */

/**
 * This method increments the player number to the next available player.
 */
void increment_current_player() {
   _current_player = find_next_player(_current_player);
} /* increment_current_player() */

/**
 * This method finds the id of the person from their object.
 * @param person the person to find
 * @return the id of the person
 */
string find_player_id_of_person(object person) {
   class player_info info;
   string id;

   foreach (id, info in _players) {
      if (find_player(info->name) == person) {
         return id;
      }
   }
   return 0;
} /* find_id_of_person() */

/**
 * This method finds the id of the current player.
 * @return the id of the current player
 */
string query_current_player() {
   if (!_current_player) {
      _current_player = find_player_id_from_number(0);
   }
   return _current_player;
} /* query_current_player() */

/**
 * This method finds the specified person and sets the current player
 * number to them.
 * @param person the person to find
 * @return the id the of the person, 0 on failure
 */
string set_current_player(string id) {
   _current_player = id;
} /* set_current_player() */

/**
 * This method tells the specified player the message.
 * @param id the id to tell the message to
 * @param message the message to send
 */
void tell_player(string id, string message) {
   object player;

   player = find_player(_players[id]->name);
   if (player) {
      tell_object(player, message);
   }
} /* tell_player() */

/**
 * THis method tells a message to the current player.
 * @param message the message to send
 */
void tell_current_player(string message) {
   tell_player(_current_player, message);
} /* tell_current_player() */

/**
 * This method tells everyone playing the game something.
 * @param message the message to send to everyone
 * @param exclude the ids to optionaly exclude
 */
varargs void tell_all_players(string message, string* exclude) {
   class player_info info;
   string id;

   if (!exclude) {
      exclude = ({ });
   }
   foreach (id, info in _players) {
      if (member_array(id, exclude) == -1) {
         tell_player(id, message);
      }
   }
} /* tell_all_players() */

/**
 * This method gets the extra data associated with the player id.
 * @param id the id to look up the data for
 * @return the extra data
 */
mixed query_player_data(string id) {
   return _players[id]->data;
} /* query_player_data() */

/**
 * This method sets the extra data associated with the player id.
 * @param id the id to set the data for
 * @param data the data to set
 */
void set_player_data(string id, mixed data) {
   _players[id]->data = data;
} /* set_player_data() */

/**
 * This method is called when an id joins the game.  This method should 
 * be overridden in higher up objects to handle special events.
 * @param id the id of the person joining
 */
void multiplayer_someone_joins(string id) {
} /* multiplayer_someone_joins() */

/**
 * This method is called when an id resigns from the game.  This method should 
 * be overridden in higher up objects to handle special events.
 * @param id the id of the person joining
 */
void multiplayer_someone_resigns(string id) {
} /* multiplayer_someone_resigns() */

/**
 * This method scrambles the array.
 * @return the array shuffled
 */
mixed* shuffle_array(mixed *arr) {
   int i;
   int pos;
   mixed* new_arr;

   for (i = 0; i < 2; i++) {
      new_arr = ({ });
      while (sizeof(arr)) {
         pos = random(sizeof(arr));
         new_arr += arr[pos..pos];
         arr = arr[0..pos - 1] + arr[pos + 1..];
      }
      arr = new_arr;
   }
   return arr;
} /* shuffle_array() */

/**
 * This method is the one that does the joining.
 * @param id the id they wish to join as
 * @return 1 on success, 0 on failure
 */
int do_join(string id) {
   if (is_person_playing(id)) {
      add_failed_mess("Someone is already playing " + id + " on $D.\n");
      return 0;
   }

   if (is_playing(this_player())) {
      add_failed_mess("You are already playing on $D.\n");
      return 0;
   }

   if (is_game_started() &&
       !can_join_as_new_player() &&
       member_array(id, query_started_player_ids()) == -1) {
      add_failed_mess("You can only take over one of the spots vacated by "
                      "someone else.\n");
      return 0;
   }

   if (add_person_to_game(id, this_player())) {
      add_succeeded_mess("$N $V as " + id + " on $D.\n");
      multiplayer_someone_joins(id);
      return 1;
   }

   add_failed_mess("Some weird error joining game on $D.\n");
   return 0;
} /* do_join() */

/**
 * This method is the one that does the resignation from the game.
 * @return 1 on success, 0 on failure
 */
int do_resign() {
   string id;

   id = find_player_id_of_person(this_player());
   if (remove_person_object_from_game(this_player())) {
      add_succeeded_mess("$N $V from game on $D.\n");
      multiplayer_someone_resigns(id);
      return 1;
   }
   add_failed_mess("You are not playing on $D to resign.\n");
   return 0;
} /* do_resign() */

/** @ignore yes */
void init() {
   string ids;

   ids = implode(keys(_players), "|");
   add_command("join", "[game] [as] {" + ids + "} on <direct:object>",
                (: do_join($4[0]) :));
   add_command("resign", "[from] [game] on <direct:object>",
               (: do_resign() :));
} /* init() */

/** @ignore yes */
mapping query_dynamic_auto_load(mapping map) {
   if (!map) {
      return 0;
   }
   add_auto_load_value(map, LOAD_TAG, "players", _players);
   add_auto_load_value(map, LOAD_TAG, "current player", _current_player);
   add_auto_load_value(map, LOAD_TAG, "started ids", _ids_when_started);
   add_auto_load_value(map, LOAD_TAG, "winner", _winner);
   add_auto_load_value(map, LOAD_TAG, "game started", _game_started);
   return map;
} /* query_dynamic_auto_load() */

/** @ignore yes */
void init_dynamic_arg(mapping map, object player) {
   if (!map) {
      return ;
   }
   _players = query_auto_load_value(map, LOAD_TAG, "players");
   _current_player = query_auto_load_value(map, LOAD_TAG, "current player");
   _ids_when_started = query_auto_load_value(map, LOAD_TAG, "started ids");
   _winner = query_auto_load_value(map, LOAD_TAG, "winner");
   _game_started = query_auto_load_value(map, LOAD_TAG, "game started");
} /* init_dynamic_arg() */