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: pinkfish $
 * $Id: voting_room.c,v 1.9 2001/10/16 16:53:06 ceres Exp pinkfish $
 *
 */

#include <board.h>

#define DEFAULT_VOTE_DURATION (2600*24*7)

/**
 * Generalised voting room intended to be inherited into rooms in the mud that
 * will setup the parameters and settings for votes.
 * <p>
 * The room does not inherantly support player initiated votes, however it is
 * a fairly simple matter to add this to your own room and have your room add
 * votes when players initiate them.
 *
 * @author Ceres
 */

/**
 *  This class stores the essential information about a vote. It is only used
 *  internally to the voting room.
 * @element type used to setup vote types
 * @element desc the description of the vote
 */
class vote {
  string type;                  /* used to setup vote types */
  string desc;                  /* description of the vote */
  string *choices;              /* options in the vote */
  mixed *votes;
  int ending;                   /* when the vote ends */
  string *voted;                /* people who've voted */
}

/**
 *  This class stores the essential information about an election during the
 *  setup phase. It is only used internally to the voting room.
 */
class election {
  mixed *candidates;            /* who are the candidates */
  int closes;                   /* when does acceptance of nominees close */
}

private int vote_counter;               /* Used to give each vote a unique number */

private mapping votes;                  /* the votes themselves */
private mapping elections;              /* the elections being setup */

private nosave string _vote_file;        /* Controls which vote file to use */
private nosave mixed _vote_cond;
private nosave mixed _comp_action;       /* Completion action */
private nosave int _vote_duration;       /* The normal duration for a vote */
private nosave int _open_voting;         /* Make who voted for what known */
private nosave int _no_elections;
private nosave string _proxy;            /* A proxy room to use for votes. */

private nosave mixed _stand_cond;
private nosave mixed _second_cond;

private nosave mixed _election_announcement; /* The board, person and subject */

int list_votes();
int cast_vote( string words, int num );
int stand_for_election(string position);
int second_candidate(string who, string position);
int list_elections();
int do_create_vote(string choices);

/**
 * @ignore
 */
void create() {
  seteuid("Room");
  votes = ([ ]);
  elections = ([ ]);
}

/**
 * @ignore
 */
void init() {
   // commands for votes
   add_command("vote", "<string> on <number>", (: cast_vote($4[0], $4[1]) :) );
   add_command("list", "votes", (: list_votes :));
   add_command("votes", "", (: list_votes :));

   // commands for elections
   if (!_no_elections) {
      add_command( "stand", "[for] <string>", (: stand_for_election($4[0]) :));
      add_command( "second", "<string> [for] <string>",
                   (: second_candidate($4[0], $4[1]) :) );
      add_command("list", "elections", (: list_elections :));
      add_command("elections", "", (: list_elections :));
   }
} /* init() */

/**
 * This method is used to return the current votes.  This can be overridden
 * in higher functions to get the votes from somewhere else if nessessary.
 * @return the votes
 */
protected mapping query_our_votes() {
   if (_proxy) {
      return _proxy->query_votes();
   }
   if (votes) {
      return votes;
   }
   return ([ ]);
} /* query_our_votes() */

/**
 * This method adds in a vote.
 * @param id the id of the vote
 * @param data the vote data
 */
protected void add_our_vote(int id, class vote data) {
   if (!votes) {
      votes = ([ ]);
   }
   votes[id] = data;
} /* add_our_vote() */

/**
 * This method is used to return the current elections.  This can be
 * overridden in hgiher inherits to control things better.
 * @return the elections
 */
protected mapping query_our_elections() {
   if (_proxy) {
      return _proxy->query_elections();
   }
   if (elections) {
      return elections;
   }
   return ([ ]);
} /* query_our_elections() */

/**
 * This method adds in a election.
 * @param name the name of the election to add
 * @param data the election data
 */
protected void add_our_election(string name, class election data) {
   if (!elections) {
      elections = ([ ]);
   }
   elections[name] = data;
} /* add_our_election() */

/**
 * This is the init() which should be called as well as the default
 * init() if you wish to have player added votes.
 */
void init_add_vote() {
   add_command( "add", "vote with <string'choices'>",
               (: do_create_vote($4[0]) :));
} /* init_add_vote() */

/**
 * This setups all the stuff that  needs to be setup after the room has
 * been loaded.  Makes all the callouts for the right amount of time
 * and so on.
 */
void setup_after_load() {
  int i;
  string election;
  int *vote_ids;

  if (_proxy) {
    return ;
  }
  vote_ids = m_indices( query_our_votes() );

  for ( i = 0; i < sizeof( vote_ids ); i++ ) {
    if ( query_our_votes()[ vote_ids[ i ] ]->ending < time() ) {
      call_out( "end_vote", 10 * ( i + 1 ), vote_ids[ i ] );
    } else {
      call_out( "end_vote", query_our_votes()[ vote_ids[ i ] ]->ending - time(),
                vote_ids[ i ] );
    }
  }

  foreach(election in keys(query_our_elections())) {
    if(query_our_elections()[election]->closes < time()) {
      call_out( "start_election_vote", 30 * random(5), election);
    } else {
      call_out( "start_election_vote", query_our_elections()[election]->closes - time(),
                election);
    }
  }
} /* setup_after_load() */

/**
 * This method is called by the inheriting object to determine which save file
 * to use for votes.
 *
 * @param str The name of the file you want the voting info saved to
 * (without the .o)
 */
void set_save_file(string file) {
  
  _vote_file = file;
  if( file_size( _vote_file + ".o" ) > 0 ) {
    unguarded( (: restore_object, _vote_file :) );
    setup_after_load();
  } else {
    elections = ([ ]);
    votes = ([ ]);
  }
}

/**
 * This method returns the save file currently used for the room.
 * @return the current save file
 */
string query_save_file() { return _vote_file; }

/**
 * Private function to save the rooms data file.
 */
protected void save_room() {
   if (_vote_file) {
      unguarded( (: save_object, _vote_file :) );
   }
}

/**
 * This method sets up a proxy for the room.  A proxy is somewhere else
 * to get all the voting information from.
 * @param proxy the proxy tpo setup
 */
void set_proxy(string proxy) {
   _proxy = proxy;
} /* set_proxy() */

/**
 * This method sets the room to not allow elections and disable all the
 * election commands.
 * @param no_elections the flag
 */
void set_no_elections(int no_elections) {
   _no_elections = no_elections;
} /* set_no_elections() */

/**
 * This function setups if the votes should be open or not.  If a vote is
 * open then you know who voted for each thing.
 * @param open 1 for an open system 0 for closed
 */
void set_open_voting(int open) {
   _open_voting = open;
} /* set_open_voting() */

/**
 * This function queries if the votes should be open or not.  If a vote is
 * open then you know who voted for each thing.
 * @return 1 for an open system 0 for closed
 */
int query_open_voting(int open) {
   return _open_voting;
} /* set_open_voting() */

/**
 * This function defines a function to be called to determine if a player
 * is eligible to vote.
 *
 * @param cond This will usually be a mixed array of an object and a function.
 * It could also be a function pointer.
 *
 * Your function should return 1 if the player is eligible to vote or 0 if
 * they are not.
 */
void set_vote_conditions(mixed cond) { _vote_cond = cond; }

/**
 * This function defines a function to be called when the vote is complete.
 * Typically your function will post the vote results somewhere or somesuch.
 * The parameters passedinto the function are:<br>
 * ( string type, string description, string* choices, mapping votes, string* voted) <br>
 *
 * @param cond This will usually be a mixed array of an object and a function.
 * It could also be a function pointer.
 */
void set_completion_action(mixed cond) { _comp_action = cond; }

/**
 * This function is used to set the normal vote and election duration. It can
 * be overridden when calling add_vote. If it is not set and no duration is
 * given in add_vote then the default value of DEFAULT_VOTE_DURATION is used.
 *
 * @param duraction The number of seconds the vote should be open.
 *
 * @see add_vote()
 */
void set_vote_duration(int duration) { _vote_duration = duration; }

/**
 * This function is used to returns the normal vote and election duration.
 * If it is not set and no duration is
 * given in add_vote then the default value of DEFAULT_VOTE_DURATION is used.
 *
 * @param duraction The number of seconds the vote should be open.
 *
 * @see add_vote()
 */
int query_vote_duration() {
   if (!_vote_duration) {
      return DEFAULT_VOTE_DURATION;
   }
   return _vote_duration;
}

/**
 * This function defines a function to be called to determine if a player
 * is eligible to stand for election to a position.
 *
 * @param cond This will usually be a mixed array of an object and a function.
 * It could also be a function pointer.
 *
 * Your function should return 1 if the player is eligible to stand or 0 if
 * they are not.
 */
void set_stand_conditions(mixed cond) { _stand_cond = cond; }

/**
 * This function defines a function to be called to determine if a player
 * is eligible to second a canditate for election.
 *
 * @param cond This will usually be a mixed array of an object and a function.
 * It could also be a function pointer.
 *
 * Your function should return 1 if the player is eligible to second or 0 if
 * they are not.
 */
void set_second_conditions(mixed cond) { _second_cond = cond; }

/**
 * This function defines the board, person and subject for announcements
 * of elections.
 *
 * @param board This is the board to post to.
 * @param person This is who to post as.
 * @param subject This is the subject line to use.
 * @param prefix The text to preceed the message.  The default is
 *               "All eligible persons are requested to vote for the position "
 *               "of "
 * @param suffix The text to follow the message.
 */
void set_election_announcement(string board, string person, string subject,
                               string prefix, string suffix) {
  _election_announcement = ({ board, person, subject, prefix, suffix });
}

/**
 * This function is called when a player votes. The syntax is
 * "vote <choice> on <vote>".
 *
 * @see set_vote_conditions()
 */
int cast_vote( string which_str, int vote_id ) {
  string pname;
  int which, ok;
  class vote this_vote;
 
  if (_proxy) {
     return _proxy->cast_vote(which_str, vote_id);
  }
 
  if ( undefinedp(query_our_votes()[vote_id])) {
    add_failed_mess("There is no vote " + vote_id + ".\n");
    return 0;
  }

  this_vote = query_our_votes()[vote_id];
  which = member_array(which_str, this_vote->choices);
  if (which == -1) {
    if(strlen(which_str) > 1) {
      add_failed_mess("There is no choice " + which_str + " for vote id " +
           vote_id + ".\n");
      return 0;
    }

     which = upper_case( which_str )[ 0 ] - 65;
  }
  if(which < 0 || which > sizeof(this_vote->choices) -1) {
    add_failed_mess("There is no choice " + which_str + " for vote id " +
                           vote_id + ".\n");
    return 0;
  }
  
  ok = 1;
  if (functionp(_vote_cond)) {
    ok = evaluate(_vote_cond, this_player(), this_vote->desc);
  }
  if(arrayp(_vote_cond)) {
    ok = call_other(_vote_cond[0], _vote_cond[1], this_player(), this_vote->desc);
  }

  if(!intp(ok)) {
    ok = 0;
  }

  if(!ok) {
    add_failed_mess("Sorry, but you are not allowed to vote on this "
                       "subject.\n");
    return 0;
  }

  pname = this_player()->query_name();
  if(member_array(pname, this_vote->voted) != -1) {
    add_succeeded_mess(({"You have already voted on this subject.\n", ""}));
    return 1;
  }

  this_vote->voted += ({ pname });
  if (_open_voting) {
     this_vote->votes[which] += ({ pname });
  } else {
     if (arrayp(this_vote->votes[which])) {
        this_vote->votes[which] = sizeof(this_vote->votes[which]);
     }
     this_vote->votes[which]++;
  }
  save_room();
 
  add_succeeded_mess(({ "You cast your vote for "+which_str + " on " +
                        vote_id+".\n",
                        "$N casts a vote.\n" }));
  
  return 1;
} /* cast_vote() */

/**
 * This function is called when a player types 'list'. It lists the currently
 * open votes.
 */
int list_votes() {
  int i, j, *vote_ids;
  string text;
  class vote this_vote;
  
  if ( !m_sizeof( query_our_votes() ) ) {
    write( "There are no votes in progress.\n" );
    return 1;
  }
  
  vote_ids = m_indices( query_our_votes() );
  if ( sizeof( vote_ids ) > 1 )
    write( "The following votes are in progress:\n" );
  else
    write( "The following vote is in progress:\n" );
  text = "";

  for ( i = 0; i < sizeof( vote_ids ); i++ ) {
    this_vote = query_our_votes()[vote_ids[i]];
    text += "  "+ vote_ids[i] + ". " + this_vote->desc +"\n Choices are :\n";

    for(j=0; j<sizeof(this_vote->choices); j++) {
      text += sprintf("    %c. %s\n", 'A'+j, this_vote->choices[j]);
    }
    text += " Voting closes at "+ ctime( this_vote->ending ) +".\n\n";
  }
  
  this_player()->more_string(sprintf( "%-=*s",
                                      (int)this_player()->query_cols(),
                                      text ));
  return 1;
}

/**
 * This function is called to add a vote to the system.
 *
 * @param type Freeform string giving the type of vote. This is typically used
 * by your completion function so that it can perform different actions for
 * different types of votes.
 *
 * @param description The description of the vote as shown to the player.
 *
 * @param choices An array of vote options eg. ({"Yes", "No" })
 *
 * @param ending An integer time of when the vote should be terminated.
 *
 * @see set_completion_action()
 */
void add_vote(string type, string description, string *choices, int ending) {
  class vote new_vote;
  
  if (_proxy) {
     return _proxy->add_vote(type, description, choices, ending);
  }
  vote_counter++;
  
  new_vote = new(class vote);
  new_vote->type = type;
  new_vote->desc = description;
  new_vote->choices = choices;
  if (_open_voting) {
    new_vote->votes = allocate(sizeof(choices), (: ({ }) :));
  } else {
    new_vote->votes = allocate(sizeof(choices));
  }
  if(ending) {
    new_vote->ending = ending;
  } else if(_vote_duration) {
    new_vote->ending = (_vote_duration + time());
  } else {
    new_vote->ending = (DEFAULT_VOTE_DURATION + time());
  }
  new_vote->voted = ({ });

  add_our_vote(vote_counter, new_vote);
  //query_our_votes()[ vote_counter ] = new_vote;

  call_out( "end_vote", new_vote->ending - time(), vote_counter );

  save_room();
}

/**
 * @ignore
 */
mapping query_votes() { return query_our_votes() + ([ ]); }

/**
 * @ignore
 */
mapping query_elections() { return query_our_elections() + ([ ]); }

/**
 * This function is called to terminate a vote. It calls your completion
 * action.
 *
 * @see set_completion_action()
 */
void end_vote( int which ) {
  if ( !query_our_votes()[ which ] ) {
      return;
  }

  if(functionp(_comp_action)) {
      evaluate(_comp_action, query_our_votes()[which]->type, query_our_votes()[which]->desc,
               query_our_votes()[which]->choices, query_our_votes()[which]->votes,
               query_our_votes()[which]->voted);
  } else if(arrayp(_comp_action)) {
    call_other(_comp_action[0], _comp_action[1], query_our_votes()[which]->type,
               query_our_votes()[which]->desc, query_our_votes()[which]->choices, query_our_votes()[which]->votes,
               query_our_votes()[which]->voted);
  }

  map_delete(query_our_votes(), which);

  save_room();
}

/**
 * This function is provided for convenience to make it easy for your vote
 * end function to post to a board.
 *
 * @param board The name of the board to post to.
 * @param name The name of the person to post as.
 * @param subject The subject line to use.
 * @param message The message to post.
 */
void make_announcement(string board, string name, string subject,
                       string message ) {
  BOARD_HAND->add_message(board, name, subject,
                          sprintf( "%-=*s", 64, message));
}

/**
 * This function is used to initiate an election.
 * It sets up the election class and adds it to the mapping.
 *
 * @param position The name of the position the election is for.
 */
void initiate_election(string position) {
  class election tmp;

  if (_proxy) {
     return _proxy->initiate_election(position);
  }
  if(query_our_elections()[position])
    return;

  tmp = new(class election);
  tmp->candidates = ({});
  if(_vote_duration) {
    tmp->closes = time() + _vote_duration;
  } else {
    tmp->closes = time() + DEFAULT_VOTE_DURATION;
  }

  add_our_election(position, tmp);

  call_out("start_election_vote", tmp->closes + 60, position);
  
  save_room();
} /* initiate_election() */

/**
 * This method determines if there is already an election of the
 * specified type in progress.
 * @param position the name of the election in progress
 * @return 1 if there is an election in progress
 */
int query_election_in_progress(string position) {
   if (classp(query_our_elections()[position])) {
       return 1;
   }
   return 0;
} /* query_election_in_progress() */

/**
 * This function is used by players to stand for election. The syntax is:
 * "stand for <position>".
 *
 * @see set_stand_conditions()
 */
int stand_for_election(string position) {
  int ok, i;
  
  if (_proxy) {
     return _proxy->stand_for_election(position);
  }
  // check if they're eligible.
  ok = 1;
  if(functionp(_stand_cond)) {
    ok = evaluate(_stand_cond, this_player(), position);
  } else if(arrayp(_stand_cond)) {
    ok = call_other(_stand_cond[0], _stand_cond[1], this_player(), position);
  }

  if(!intp(ok))
    ok = 0;

  if(!ok) {
    add_succeeded_mess(({ "Sorry, but you are not allowed to stand for this "
                            "election.\n", ""}));
    return 1;
  }

  // check if there is an election for this position.
  if(!query_our_elections()[position]) {
    add_succeeded_mess(({"There is no election in progress for the post of " +
                    position + ".\n", ""}));
    return 1;
  }

  // check if they're already a candidate for this position.
  for(i=0; i<sizeof(query_our_elections()[position]->candidates); i++) {
    if(query_our_elections()[position]->candidates[i][0] == this_player()->query_name()) {
      add_succeeded_mess(({"You are already standing in this "
                             "election.\n", ""}));
      return 1;
    }
  }
    
  // add them to the list of candidates.
  query_our_elections()[position]->candidates += ({({ this_player()->query_name(), "" })});
  save_room();
  add_succeeded_mess(({"You have been added to the list of candidates for "
                         "the position of " + position + ".  You must now "
                         "find someone to second your candidacy.\n",
                         "$N stands for election.\n"}));
  return 1;
}

/**
 * This function is used by players to second candidates for election. If a
 * candidates isn't seconded he/she won't be in the election. The syntax is:
 * "second <player> for <position>".
 *
 * @see set_second_conditions()
 */
int second_candidate(string who, string position) {
  mixed *candidates;
  int i, found, ok;
  
  if (_proxy) {
     return _proxy->second_candidate(who, position);
  }
  // check if they're eligible.
  ok = 1;
  if(functionp(_second_cond)) {
    ok = evaluate(_second_cond, this_player(), position);
  } else if(arrayp(_second_cond)) {
    ok = call_other(_second_cond[0], _second_cond[1], this_player(), position);
  }

  if(!intp(ok))
    ok = 0;

  if(!ok) {
    add_succeeded_mess(({"Sorry, but you are not allowed to second candidates "
                           "in this election.\n", ""}));
    return 1;
  }

  // check the position is up for election
  if(!query_our_elections()[position]) {
    add_succeeded_mess(({"There is no election in progress for " + position +
                           ".\n", ""}));
    return 1;
  }

  // check the candidate is standing
  candidates = (query_our_elections()[position])->candidates;
  for(i=0; i< sizeof(candidates); i++) {
    if(candidates[i][0] == who)
      found = i+1;
  }

  if(!found) {
    add_succeeded_mess(({who + " is not standing for the position of " +
                           position + ".\n", ""}));
    return 1;
  }

  if(this_player()->query_name() == who) {
    add_succeeded_mess(({"You cannot second yourself.\n", ""}));
    return 1;
  }

  if(candidates[found-1][1] != "") {
    add_succeeded_mess(({candidates[found-1][0] +
                           " has already been seconded by " +
                           candidates[found-1][1] + ".\n", ""}));
    return 1;
  }
  
  // mark the candidate as seconded (supported).
  candidates[found-1][1] = this_player()->query_name();

  save_room();
  
  add_succeeded_mess(({candidates[found-1][0] +
                         " has been seconded in the election for "+
                         position+".\n", ""}));
  return 1;
}

/**
 * Once the candidacy phase is over this function starts the election vote
 * itself by taking all eligible candidates, setting them as choices in the
 * election and then posting an announcemment.
 */
void start_election_vote(string post) {
  string str, *choices;
  int i;
  
  if(!query_our_elections()[post])
    return;


  if(_election_announcement[3])
    str = _election_announcement[3];
  else
    str = "All eligible persons are requested to vote for the position of ";
  
  str += post + "\n\nThe candidates are:\n";
  
  choices = ({ });
  for(i=0; i<sizeof(query_our_elections()[post]->candidates); i++) {
    if(query_our_elections()[post]->candidates[i][1] != "") {
      str += sprintf("  %s seconded by %s.\n", 
                     query_our_elections()[post]->candidates[i][0],
                     query_our_elections()[post]->candidates[i][1]);
      choices += ({ query_our_elections()[post]->candidates[i][0] });
    }
  }

  if(!sizeof(choices)) {
    str = "In the election for the position of " + post +
      " no candidate stood for election therefore the election "
      "is null and void.\n";
  } else if(sizeof(choices) < 2) {
    str = "In the election for the position of " + post +
      " only one candidate stood for election therefore the election "
      "is null and void.\n";
  } else {

    if(_election_announcement[4])
      str += _election_announcement[4];

    add_vote("election", "Election for the post of " + post + "\n", choices,
             0);
  }
  
  make_announcement(_election_announcement[0], _election_announcement[1],
                    _election_announcement[2], str);

  map_delete(query_our_elections(), post);
  save_room();
}

/**
 * This function is called when a player types 'elections'. It lists the
 * elections currently accepting candidates.
 */
int list_elections() {
  class election this_election;
  string *posts, text;
  int i, j;
  
  if ( !m_sizeof( query_our_elections() ) ) {
    write( "There are no elections in progress.\n" );
    return 1;
  }
  
  posts = m_indices( query_our_elections() );
  if ( sizeof( posts ) > 1 )
    write( "The following elections are in progress:\n" );
  else
    write( "The following election is in progress:\n" );
  text = "";

  for ( i = 0; i < sizeof( posts ); i++ ) {
    this_election = query_our_elections()[posts[i]];
    text += "  Election to the post of "+ posts[i] + ".\n";

    if(!sizeof(this_election->candidates)) {
      text += "  No candidates have declared yet.\n";
    } else {
      text += "    Current candidates are :\n";
      
      for(j=0; j<sizeof(this_election->candidates); j++) {
        if(this_election->candidates[j][1] != "")
          text += sprintf("    %c. %s seconded by %s.\n", 'A'+j,
                          this_election->candidates[j][0],
                          this_election->candidates[j][1]);
        else
          text += sprintf("    %c. %s not yet seconded.\n", 'A'+j,
                          this_election->candidates[j][0]);
          
      }
    }
    text += " Candidacies must be declared by "+
      ctime( this_election->closes ) +".\n\n";
  }
  
  this_player()->more_string(sprintf( "%-=*s",
                                      (int)this_player()->query_cols(),
                                      text ));
  return 1;
}

/** @ignore yes */
string strip_spaces(string str) {
   if (!strlen(str)) {
      return str;
   }
   while (str[0] == ' ') {
      str = str[1..];
   }
   if (!strlen(str)) {
      return str;
   }
   while (str[<1] == ' ') {
      str = str[0..<2];
   }
   return str;
} /* strip_spaces() */

/**
 * This is an option function which can be defined in upper level inherits.
 * It allows the players to create their own votes with their own choices.
 */
int do_create_vote(string choices) {
   string* bits;

   bits = map(explode(choices, ","), (: strip_spaces($1) :)) - ({ "" });
   write("Choices: " + query_multiple_short(bits) + ".\n");
   write("What description would you like for your vote?\n");
   this_player()->do_edit("", "create_vote_desc", this_object(), 0, bits);
   add_succeeded_mess(({ "", "$N starts to create a new vote.\n" }));
   return 1;
} /* do_create_vote() */

/** @ignore yes */
void create_vote_desc(string str, string* choices) {
   if (!str) {
      write("Aborting.\n");
      return ;
   }
   write("Are you sure you wish to create a vote with a description of:\n" +
         str + "\nWith vote choices of " + query_multiple_short(choices) +
         ".\n");
   write("Please answer yes or no: ");
   input_to("create_vote_desc_confirm", 0, str, choices);
} /* create_vote_desc() */

/** @ignore yes */
void create_vote_desc_confirm(string str, string desc, string* choices) {
   str = lower_case(str);
   if (!strlen(str) ||
       (str[0] != 'y' && str[0] != 'n' && str[0] != 'q')) {
      write("Please answer yes or no: ");
      input_to("create_vote_desc_confirm", 0, str, choices);
   }

   if (str[0] == 'q' || str[0] == 'n') {
      write("Ok, quitting.\n");
      return ;
   }

   //
   // Now we add the vote.
   //
   add_vote("freeform", desc, choices, 0);
   write("Added in the vote.\n");
} /* create_vote_desc_confirm() */

/**
 * This is an administrative function to allow the removal/cancellation
 * of an election.
 * @param election The name of the election to be cancelled
 * @return Returns 1 for success, 0 for failure.
 */
int delete_election(string election) {
  if(!query_our_elections()[election])
    return 0;
  map_delete(query_our_elections(), election);
  save_room();
  return 1;
}

/**
 * This is an administrative function to allow the removal/cancellation
 * of a vote.
 * @param vote_id The id number of the vote to be cancelled.
 * @return Returns 1 for success, 0 for failure.
 */
int delete_vote(int vote_id) {
  if(!query_our_votes()[vote_id])
    return 0;
  
  map_delete(query_our_votes(), vote_id);
  save_room();
  return 1;
}