void 
starttourn(void)
{
    int     i, j;
    struct planet *pl;
    char    s[80];

    opentlog();
    for (i = 0, pl = &planets[i]; i < NUMPLANETS; i++, pl++) {
	for (j = 0; j < MAXTEAM + 1; j++) {
	    pl->pl_tinfo[j].timestamp = 0;
	    /* doesn't work? */
	    pl->pl_hinfo = (PL_TYPE(*pl) == PLSTAR) ? ALLTEAM : pl->pl_owner;
	}
    }
    status->clock = 0;

    explode_everyone(KTOURNSTART, 0);

    tlog_all();


    status2->league++;
    status2->leagueticksleft = MINUTES(configvals->regulation_minutes);

    /* version team names configured time date */
    pmessage(" ", 0, MALL, UMPIRE);
    sprintf(s, "Timer started -- %d minutes remaining",
	    status2->leagueticksleft / MINUTES(1));
    pmessage(s, 0, MALL, UMPIRE);
    pmessage(" ", 0, MALL, UMPIRE);
}
Beispiel #2
0
int getplayer(int from, char *line)
{
  char id;
  char temp[MSG_LEN];
  int what;
  int numargs;

  numargs = sscanf(line,"%s %c", temp, &id);
  id = toupper(id);

  if (numargs==1)
    what = from;
  else if ((id >= '0') && (id <='9'))
    what = id - '0';
  else if ((id >= 'A') && (id <= ('A' + MAXPLAYER - 10)))
    what = id - 'A' + 10;
  else
  {
    pmessage(from, MINDIV, addr_mess(from, MINDIV),
	     "Invalid player number.");
    return -1;
  }
  if (players[what].p_status == PFREE)
  {
    pmessage(from, MINDIV, addr_mess(from, MINDIV),
	     "Player not in the game.");
    return -1;
  }
  return what;
}
void 
udtourny(void)
{
    int     trem;
    char    buf[120];
    if (!status2->league)
	return;

    /* server is configured for league play */

    if (status2->league == 1)
	return;			/* we're still prepping */

    trem = --status2->leagueticksleft;


    switch (status2->league) {
    case 2:			/* the 1-minute pre tourney warm up. */
	if (trem == SECONDS(5))
	    pmessage("5 seconds to tournament start", -1, MALL, UMPIRE);
	else if (trem == SECONDS(2))
	    pmessage("Hold on to your hats.  Everybody dies!", -1, MALL, UMPIRE);
	else if (trem <= 0) {
	    starttourn();
	}
	break;

    case 3:			/* full-on T-mode */

	buf[0] = 0;
	if (trem % MINUTES(20) == 0 ||
	    (trem < MINUTES(20) && 0 == trem % MINUTES(5)) ||
	    (trem < MINUTES(5) && 0 == trem % MINUTES(1))) {
	    sprintf(buf, "There are %d minutes remaining in regulation play",
		    trem / MINUTES(1));
	}
	else if (trem < MINUTES(1) && 0 == trem % SECONDS(10)) {
	    sprintf(buf, "There are %d seconds remaining in regulation play",
		    trem / SECONDS(1));
	}
	if (buf[0])
	    pmessage(buf, -1, MALL, UMPIRE);
	if (trem <= 0)
	    /* maybe go into overtime */
	    endtourn();
	break;
    case 4:
	/* overtime, not implemented */
	break;
    }
}
Beispiel #4
0
void advertise()
{
  int status;
  pid_t result;

  /* do not proceed unless advertising is enabled */
  if (!server_advertise_enable) return;

  /* if forked process jams up, we will simply wait for it to unjam */
  if (pid != 0) {
    result = waitpid(pid, &status, WNOHANG);
    if (result != pid) return;
    pid = 0;
  }

  /* fork a process to handle the task */  
  if ((pid = fork()) != 0) return;

  /* from here on we are executing in the context of the forked process */
  alarm_prevent_inheritance();

  pmessage(0, MALL, "GOD->ALL",
	   "ad: %s", server_advertise_filter);

  exit(0);
}
Beispiel #5
0
void inl_draft_begin()
{
  int h;
  struct player *j;

  status->gameup &= ~GU_INL_DRAFTED;

  context->inl_draft = INL_DRAFT_MOVING_TO_POOL;
  context->inl_pool = 0;
  context->inl_home_pick = 0;
  context->inl_away_pick = 0;

  for (h = 0, j = &players[0]; h < MAXPLAYER; h++, j++) {
    if (inl_draft_ignore(j)) continue;
    j->p_desspeed = 0;
    bay_release(j);
    j->p_flags &= ~(PFREPAIR | PFBOMB | PFORBIT | PFBEAMUP | PFBEAMDOWN |
                    PFCLOAK);
    j->p_flags |= PFSEEN;
    inl_draft_highlight_off(j);
    inl_draft_assign_to_pool(j);
    inl_draft_place(j);
  }

  status->gameup |= GU_INL_DRAFTING;
  pmessage(0, MALL, "GOD->ALL", "The captains have agreed to hold a draft.");
}
Beispiel #6
0
static void inl_draft_pick(struct player *j, struct player *k)
{
  /* TODO: draw a phaser from captain or selector to pick? */
  if (j->p_team != k->p_team) {
    change_team_quietly(j->p_no, k->p_team, j->p_team);
  }

  if (j->p_team == FED) {
    j->p_inl_pick = context->inl_home_pick++;
  }

  if (j->p_team == ROM) {
    j->p_inl_pick = context->inl_away_pick++;
  }

  j->p_inl_draft = INL_DRAFT_MOVING_TO_PICK;

  pmessage(0, MALL, "GOD->ALL", "Selection #%d: %s (%s) drafts %s (%s).",
           context->inl_home_pick + context->inl_away_pick,
           k->p_mapchars, j->p_team == FED ? "HOME" : "AWAY", j->p_mapchars,
           j->p_name);
  /* set rank of player depending on pick position */
  if (status->gameup & GU_INROBOT)
    j->p_stats.st_rank =
      NUMRANKS - (context->inl_home_pick + context->inl_away_pick - 1) / 2 - 2;
}
Beispiel #7
0
void inl_draft_reject(int n)
{
  struct player *j;
  if ((n < 0) || (n > MAXPLAYER)) return;
  j = &players[n];
  switch (j->p_inl_draft) {
  case INL_DRAFT_OFF            : /* not involved */
  case INL_DRAFT_MOVING_TO_POOL : /* in transit to pool */
  case INL_DRAFT_POOLED         : /* in pool of players to be chosen */
    break;
  case INL_DRAFT_CAPTAIN_UP     : /* captain with right to select */
  case INL_DRAFT_CAPTAIN_DOWN   : /* captain without right to select */
    if (me->p_inl_draft == INL_DRAFT_CAPTAIN_UP ||
        me->p_inl_draft == INL_DRAFT_CAPTAIN_DOWN) {
        pmessage(0, MALL, "GOD->ALL",
                 "Captain %s slaps captain %s around with a dead trout.",
                 me->p_mapchars, j->p_mapchars);
    }
    break;
  case INL_DRAFT_MOVING_TO_PICK : /* has been chosen, in transit to team */
  case INL_DRAFT_PICKED         : /* has been chosen by a captain */
    if (me->p_inl_draft == INL_DRAFT_CAPTAIN_UP) {
      /* captain flicks a picked player */
      /* meaning: undo pick */
      /* TODO: sysdef policy default DRAFT_UNPICK=0 */
      /* TODO: verify pick is on same team as captain */
      /* TODO: throw the pick back to the pool */
    }
    break;
  }
}
Beispiel #8
0
/* ARGSUSED */
int do_help(char *comm, struct message *mess, struct command_handler_2 *cmds,
            int cmdnum, int prereqs)
{
  int who;
  int i;
  char *addr;

  who = mess->m_from;
  addr = addr_mess(who,MINDIV); 

  if (cmds[0].command != NULL)
  { 
    for (i=0; cmds[i].command != NULL; i++)
    {
      if ((cmds[i].tag & C_PR_MASK) & ~(prereqs))
	/* Dont meet the prereqs */
	continue;
      if (cmds[i].tag & C_DESC)
	/* Command is just a dummy description */
	pmessage(who,MINDIV,addr, cmds[i].command);
      if (!(cmds[i].desc))
	/* Command has no description
	   (its description has a value of NULL, not "")
	   Use this hack to make a command hidden */
	continue;
      if (!(voting) && (cmds[i].tag & C_PR_VOTE))
	continue;
      else if (cmds[i].tag & (C_VC_TEAM | C_VC_ALL))
      {
	char ch;

	if (cmds[i].tag & C_VC_TEAM)
	  ch = 'T';
	else if (cmds[i].tag & C_VC_ALL)
	  ch = 'M';
	else
	  ch = '?';
	pmessage(who,MINDIV,addr, "|%10s - %c: %s",
		 cmds[i].command, ch, cmds[i].desc);
      }
      else
	pmessage(who,MINDIV,addr, "|%10s - %s",
		 cmds[i].command, cmds[i].desc);
    }
  }
  return 1;
}
int
main(int argc, char **argv)
{
    int     i;
    char    buf[1000];
    int     seconds = 10, part;
    int     c;

    while((c = getopt(argc, argv, "n:")) != -1)
    {
      switch(c)
      {
        case 'n':
	  seconds = atoi(optarg);
	  if(seconds < 0)
	    usage(argv[0]);
	  break;
        default:
	  usage(argv[0]);
          break;
      }
    }

    openmem(0, 0);

    part = seconds % STEP;
    if (part)
	sleep(part);

    for (seconds -= part; seconds > 0; seconds -= STEP) {
	sprintf(buf, "->ALL  ** Attention: The galaxy will be reset in %d seconds.", seconds);
	pmessage(buf, 0, MALL, SERVNAME);
	sleep(STEP);
    }

    sprintf(buf, "%s->ALL  ** Manual galaxy reset **", SERVNAME);
    pmessage(buf, 0, MALL, SERVNAME);

    zap();

    /* *newgalaxy = 1;*/
    status2->newgalaxy = 1;
    exit(0);
}
Beispiel #10
0
sendVersion(void)
{
  char    client_ver[15];

  if (!version_sent)
    {
      version_sent = 1;
      sprintf(client_ver, "@%s.%d", mvers, PATCHLEVEL);

      pmessage(client_ver, me->p_no, MINDIV | MCONFIG);
    }
}
void
sendVersion(void)
{
    static int version_sent = 0;
    char    buf[80];

    if (!version_sent) {
	version_sent = 1;
	sprintf(buf, "@ Paradise %s", CLIENTVERS);
	pmessage(buf, me->p_no, MINDIV | MCONFIG);
    }
}
Beispiel #12
0
void inl_draft_end()
{
  int h;
  struct player *j;

  context->inl_draft = INL_DRAFT_OFF;
  for (h = 0, j = &players[0]; h < MAXPLAYER; h++, j++) {
    j->p_inl_draft = INL_DRAFT_OFF;
    p_heal(j);
  }
  pmessage(0, MALL, "GOD->ALL", "The draft has completed.");
  status->gameup &= ~GU_INL_DRAFTING;
}
void 
endtourn(void)
{
    pmessage(" ", 0, MALL, UMPIRE);
    pmessage("Time is done", 0, MALL, UMPIRE);
    pmessage(" ", 0, MALL, UMPIRE);

    /* print damage assesments */
    endgame_effects(1 << status2->home.index, 1 << status2->away.index, -1);

    scan_for_unexpected_tourny_events();

    tlog_all();

    closetlog();

    /* conquer */

    status2->league = 1;

    /* we should shut the game off here (status->gameup=0) */
}
static void 
advertise_tourney_queue(void)
{
    char    buf[80], addrbuf[10];
    int     count = 0;
    int     i;

    if (status->tourn)
	return;

    for (i = 0; i < MAXPLAYER; i++) {
	if (players[i].p_status == PTQUEUE)
	    count++;
    }

    sprintf(addrbuf, "%s->YOU ", SERVNAME);
    sprintf(buf, "There %s %d player%s on the tournament queue",
	    (count == 1) ? "is" : "are", count, (count == 1) ? "" : "s");
    pmessage (buf, me->p_no, MINDIV, addrbuf);
}
Beispiel #15
0
static int inl_draft_next(struct player *k)
{
  int h;
  struct player *j;

  for (h = 0, j = &players[0]; h < MAXPLAYER; h++, j++) {
    if (j == k) continue;
    if (inl_draft_ignore(j)) continue;
    if (!j->p_inl_captain) continue;
    j->p_inl_draft = INL_DRAFT_CAPTAIN_UP;
    inl_draft_highlight_up(j);
    k->p_inl_draft = INL_DRAFT_CAPTAIN_DOWN;
    inl_draft_highlight_down(k);
    return 1;
  }
  /* TODO: test that a captain who leaves and returns can allow draft
  to continue, test that a replacement captain can take the role */
  pmessage(0, MALL, "GOD->ALL", "Draft stalled, no captain of other team.");
  return 0;
}
Beispiel #16
0
/* animate alive ships during draft */
void inl_draft_update()
{
  int h;
  struct player *j;

  /* tumbling transwarp-like animation for alive ships involved in draft */
  for (h = 0, j = &players[0]; h < MAXPLAYER; h++, j++) {
    int dx, dy;
    if (inl_draft_ignore(j)) continue;
    if (j->p_status != PALIVE) continue;
    /* newly arriving players are forced into the pool */
    if (context->inl_draft == INL_DRAFT_MOVING_TO_POOL &&
        j->p_inl_draft == INL_DRAFT_OFF) {
      pmessage(0, MALL, "GOD->ALL", "%s has joined, and is ready to be drafted", j->p_mapchars);
      inl_draft_assign_to_pool(j);
    }
    inl_draft_place(j);
    dx = j->p_x - j->p_inl_x;
    dy = j->p_y - j->p_inl_y;
    if ((abs(dx) + abs(dy)) > 750) {
      p_x_y_go(j, j->p_x - (dx / 10), j->p_y - (dy / 10));
      j->p_desdir = j->p_dir = (u_char) (j->p_dir + 24);
    } else {
      p_x_y_go(j, j->p_inl_x, j->p_inl_y);
      inl_draft_arrival(j);
    }
  }

  switch (context->inl_draft) {
  case INL_DRAFT_MOVING_TO_POOL:
    if (inl_draft_pool_size() == 0)
      inl_draft_done();
    break;
  case INL_DRAFT_MOVING_TO_HOME:
    if (inl_draft_count_by_state(INL_DRAFT_MOVING_TO_HOME) == 0)
      inl_draft_end();
    break;
  }
}
Beispiel #17
0
dmessage(char *message, unsigned char flags, unsigned char from, unsigned char to)
{
  register int len;
  W_Color color;
  char    timebuf[10];
  LONG    curtime;
  struct tm *tm;
  char    buf[80];
  int     take, destroy, team, kill, killp, killa, bomb, conq;
  struct distress dist;

  take = MTEAM + MTAKE + MVALID;
  destroy = MTEAM + MDEST + MVALID;
  kill = MALL + MKILL + MVALID;
  killp = MALL + MKILLP + MVALID;
  killa = MALL + MKILLA + MVALID;
  bomb = MTEAM + MBOMB + MVALID;
  team = MTEAM + MVALID;
  conq = MALL + MCONQ + MVALID;

  time(&curtime);
  tm = localtime(&curtime);
  sprintf(timebuf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
  len = strlen(message);
  if (from == 255)
    {
      /* From God */
      color = textColor;
    }
  else
    {
      color = playerColor(&(players[from]));
    }
  if (censorMessages)
    if ((flags != kill) && (flags != killp) &&
  (flags != killa) && (flags != bomb) &&
  (flags != take) && (flags != destroy))
      censor(message);

  /* aha! A new type distress/macro call came in. parse it appropriately */
  if (flags == (MTEAM | MDISTR | MVALID))
    {
      HandleGenDistr(message, from, to, &dist);
      len = makedistress(&dist, message, distmacro[dist.distype].macro);

#ifdef BEEPLITE
      if (UseLite)
  rcdlite(&dist);
#endif

      if (len <= 0)
  return;
      flags ^= MDISTR;
    }


  if (niftyNewMessages)
    {
      if (logmess)
  {
    if (logFile != NULL)
      {
        fprintf(logFile, "%s: %s\n", timebuf, message);
        fflush(logFile);
      }
    else
      {
        printf("%s: %s\n", timebuf, message);
      }
  }
      if (!(logmess && logFile == NULL) && flags == conq)
  {
    /* output conquer stuff to stdout in addition to message window */
    fprintf(stdout, "%s\n", message);
    if (instr(message, "kill"))
      {
        fprintf(stdout, "NOTE: The server here does not properly set message flags\n");
        fprintf(stdout, "You should probably pester the server god to update....\n");
      }
  }
      if (flags == (MCONFIG + MINDIV + MVALID))
  {
    if (from == 255)
      CheckFeatures(message);
    return;
  }
      if ((flags == team) || (flags == take) || (flags == destroy))
  {
    W_WriteText(messwt, 0, 0, color, message, len, shipFont(me));
    if ((flags == team) &&
        !strncmp(message + 10, "     ", 5) && (message[15] == 0))
      {
        printf("dmessage:flags==team PIG call from=%d\n", from);
        pmessage(cowid, from, MINDIV);
      }
  }

      else if ((flags == kill) || (flags == killp) ||
         (flags == killa) || (flags == bomb))
  {
    W_WriteText(messwk, 0, 0, color, message, len, 0);
    if (!reportKills)
      return;        /* HW */
  }

      else if (flags & MINDIV)
  {
    W_WriteText(messwi, 0, 0, color, message, len, 0);
    if (!strncmp(message + 10, "     ", 5) && (message[15] == 0))
      {
        printf("dmessage:MINDIV PIG call from=%d\n", from);
        pmessage(cowid, from, MINDIV);
      }
  }
      else
  {          /* if we don't know where *
              * * the message beLONGs by
              * * * this time, stick it
              * in * * the all board... */
    W_WriteText(messwa, 0, 0, color, message, len, 0);
    if (!strncmp(message + 10, "     ", 5) && (message[15] == 0))
      {
        pmessage(cowid, from, MINDIV);
      }
  }
      W_WriteText(reviewWin, 0, 0, color, message, len, 0);

    }
  else
    {

      /* ok, here we have the old kludge nastiness that we can turn on if we
       * * * HAVE to.  yuk, blech, ptooie... */

      if ((strncmp(message, "GOD->ALL", 8) == 0 &&
     (instr(message, "was kill") ||
      instr(message, "killed by"))) ||
    (*message != ' ' && instr(message, "We are being attacked")))
  {
    W_WriteText(messwk, 0, 0, color, message, len, 0);
    if (!reportKills)
      return;
    W_WriteText(reviewWin, 0, 0, color, message, len, 0);
    if (logmess)
      {
        if (logFile != NULL)
    {
      fprintf(logFile, "%s ", timebuf);
      fprintf(logFile, "%s\n", message);
      fflush(logFile);
    }
        else
    {
      printf("%s ", message);
      printf("%s\n", timebuf);
    }
      }
    return;
  }
      switch (flags & (MTEAM | MINDIV | MALL))
  {
  case MTEAM:
    W_WriteText(messwt, 0, 0, color, message, len, 0);
    if (!strncmp(message + 10, "     ", 5) && (message[15] == 0))
      {
        pmessage(cowid, from, MINDIV);
      }
    if (logmess)
      {
        if (logFile != NULL)
    {
      fprintf(logFile, "%s ", timebuf);
      fprintf(logFile, "%s\n", message);
      fflush(logFile);
    }
        else
    {
      printf("%s ", message);
      printf("%s\n", timebuf);
    }
      }
    break;
  case MINDIV:
    if (!(flags & MCONFIG))
      W_WriteText(messwi, 0, 0, color, message, len, 0);
    if (!strncmp(message + 10, "     ", 5) && (message[15] == 0))
      {
        pmessage(cowid, from, MINDIV);
      }
    if (logmess)
      {
        if (logFile != NULL)
    {
      fprintf(logFile, "%s ", timebuf);
      fprintf(logFile, "%s\n", message);
      fflush(logFile);
    }
        else
    {
      printf("%s ", message);
      printf("%s\n", timebuf);
    }
      }
    break;
  default:
    W_WriteText(messwa, 0, 0, color, message, len, 0);
    if (!strncmp(message + 10, "     ", 5) && (message[15] == 0))
      {
        pmessage(cowid, from, MINDIV);
      }
    if (logmess)
      {
        if (logFile != NULL)
    {
      fprintf(logFile, "%s ", timebuf);
      fprintf(logFile, "%s\n", message);
      fflush(logFile);
    }
        else
    {
      printf("%s", message);
      printf("%s\n", timebuf);
    }
      }
    break;
  }
      W_WriteText(reviewWin, 0, 0, color, message, len, 0);
    }
}
Beispiel #18
0
void inl_draft_select(int n)
{
  struct player *j, *k = me;      /* j: pick-ee, k: pick-er */
  if ((n < 0) || (n > MAXPLAYER)) return;
  j = &players[n];
  switch (j->p_inl_draft) {
  case INL_DRAFT_OFF            : /* not involved */
    break;
  case INL_DRAFT_CAPTAIN_UP     : /* captain with right to select */
    break;
  case INL_DRAFT_CAPTAIN_DOWN   : /* captain without right to select */
    if (k->p_inl_draft == INL_DRAFT_CAPTAIN_UP) {
      /* captain fingers fellow captain */
      /* meaning: pass */
      if (inl_draft_next(k)) {
        pmessage(0, MALL, "GOD->ALL", "%s passes this draft pick.",
                 k->p_mapchars);
      }
      /* TODO: this can result in an imbalance */
    }
    break;
  case INL_DRAFT_MOVING_TO_POOL : /* in transit to pool */
  case INL_DRAFT_POOLED         : /* in pool of players to be chosen */
    if (k->p_inl_draft == INL_DRAFT_CAPTAIN_UP) {
      /* captain fingers a pool player */
      /* meaning: pool player is picked, next captain to pick */
      if (!j->p_inl_captain) {
        if (inl_draft_next(k)) {
          inl_draft_pick(j, k);
        }
      }
    } else if (k->p_inl_draft == INL_DRAFT_PICKED_SELECTOR) {
      /* selector fingers a pool player */
      /* meaning: pool player is picked, next captain to pick */
      k = inl_draft_pick_to_captain(me);
      if (k == NULL) {
        pmessage(0, MALL, "GOD->ALL", "Draft error, %s has no captain.",
                 me->p_mapchars);
        return;
      }
      if (k->p_inl_draft != INL_DRAFT_CAPTAIN_UP) {
        pmessage(0, MALL, "GOD->ALL",
                 "Draft error, pick by %s ignored because captain is not up.",
                 me->p_mapchars);
        return;
      }
      if (!j->p_inl_captain) {
        if (inl_draft_next(k)) {
          inl_draft_pick(j, k);
        }
      }
    } else if (k->p_inl_draft == INL_DRAFT_PICKED) {
      /* non-captain pick fingers a pool player */
      /* meaning: team signaling to captain their preference */
      /* TODO: distort pool position according to how many fingerings */
    }
    break;
  case INL_DRAFT_MOVING_TO_PICK : /* has been chosen, in transit to team */
  case INL_DRAFT_PICKED         : /* has been chosen by a captain */
    if (k->p_inl_draft == INL_DRAFT_CAPTAIN_UP ||
        k->p_inl_draft == INL_DRAFT_CAPTAIN_DOWN) {
      /* captain fingers a picked player */
      /* meaning: delegation of pick duty */
      if (j->p_team == k->p_team) {
        j->p_inl_draft = INL_DRAFT_PICKED_SELECTOR;
        god(j->p_no, "Draft selector, your captain has chosen you to pick.");
      }
    }
    break;
  case INL_DRAFT_PICKED_SELECTOR:
    if (k->p_inl_draft == INL_DRAFT_CAPTAIN_UP ||
        k->p_inl_draft == INL_DRAFT_CAPTAIN_DOWN) {
      /* captain fingers a selector */
      /* meaning: cancel delegation of pick duty */
      if (j->p_team == k->p_team) {
        j->p_inl_draft = INL_DRAFT_PICKED;
        god(j->p_no, "Draft selector, your captain has withdrawn your duty to pick.");
      }
    }
    break;
  }
}
Beispiel #19
0
int do_vote(char *comm, struct message *mess, struct command_handler_2 *votes,
            int num)
{
  int what = 0;
  int player = -1;
  register int i;
  register struct player *j;
  int pcount=0;  /* Total players in game */
  int vcount=0;  /* Number who've voted recently */
  int mflag = 0;
  int sendto = 0;
  int who;
  char nv[PV_TOTAL+1];

  who = mess->m_from;

  if (players[who].p_status == POBSERV)
  {
    god(who, "Sorry, observers can't vote");
    return 0;
  }

  if (votes[num].tag & C_PLAYER)
  {
    if ((what = getplayer(who, comm)) < 0)
      return 0;
    player = what;
  }

  what += votes[num].start;

  if (what >= PV_TOTAL) return 0;

  j = &players[who];
  if ((j->voting[what] != 0) && (votes[num].frequency != 0))
  {
    if ( (j->voting[what] + votes[num].frequency) > time(NULL) )
    {
      godf(who,"Sorry, you can only use %s every %1.1f minutes",
           votes[num].command, votes[num].frequency / 60.0);
      return 0;
    }
  }
  j->voting[what] = time(NULL);  /* Enter newest vote */

  if (votes[num].tag & C_VC_TEAM)
  {
    sendto = players[who].p_team;
    mflag = MTEAM;
  }
  else if (votes[num].tag & C_VC_ALL)
  {
    sendto = 0;
    mflag = MALL;
  }
  else
  {
    ERROR(1,("Unrecognized message flag in do_vote() for %s\n",
	     comm));
    return 0;
  }

  if (!strncmp(comm, "EJECT", 5) && (who == player))
  {
      god(who, "Sorry, you can't eject yourself.");
      return 0;
  }

  nv[0] = '\0';
  for (i=0, j = &players[i]; i < MAXPLAYER; i++, j++)
  {
    /*Skip free slots and robots */
    if ( (j->p_status == PFREE) || (j->p_flags & PFROBOT))
      continue;

    /*Also skip players that are not on the same team if team flag is set*/
    if ((votes[num].tag & C_VC_TEAM) && (j->p_team != players[who].p_team))
      continue; 

    /* Also skip observers */
    if (j->p_status == POBSERV)
      continue;

    pcount++;

    /* Did a player vote expire? */
    if ((j->voting[what] > 0)
	&& ((votes[num].expiretime == 0)
	    || (j->voting[what] + votes[num].expiretime > time(NULL))))
    {
      vcount++;
    }
    else
    {
      strcat(nv, j->p_mapchars);
      strcat(nv, " ");
    }
  }
  pmessage(sendto, mflag, addr_mess(sendto,mflag),
	   "%s has voted to %s.  %d player%s (of %d) %s voted.",
	   players[who].p_mapchars, comm, vcount, vcount==1 ? "":"s",
	   pcount, vcount==1 ? "has":"have");

  /* The Votes Passes */
  if ( (vcount >= votes[num].minpass)
      && ( ((pcount < (2*vcount)) && (votes[num].tag & C_VC_ALL))
	  || ((votes[num].tag & C_VC_TEAM) && (pcount/2 + 1 <= vcount)) ))
  {
    pmessage(sendto, mflag, addr_mess(sendto,mflag), 
	     "The motion %s passes", comm);

    /* Reset the Votes for this item since it passed */
    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) 
      j->voting[what] = -1;

    if (votes[num].tag & C_PLAYER)
      (*votes[num].handler)(who, player, mflag, sendto);
    else
      (*votes[num].handler)(who, mflag, sendto);

    return 1;
  }
  else
  {
    /*
    if (votes[num].tag & C_VC_TEAM) 
      i = pcount - vcount - 1;
    else */
      i = pcount/2 + 1 - vcount;

    if (i < (votes[num].minpass - vcount))
      i = votes[num].minpass - vcount;

    pmessage(sendto, mflag, addr_mess(sendto, mflag),
	     "Still need %d more vote%s, from %s", i, (i==1 ? "":"s"), nv);
    return 0;
  }
}