Vanilla Netrek Server Development Archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[VANILLA-L:466] INL Robot server mods - part 1
*** ntserv/commands.c.orig Tue Dec 26 05:15:04 1995
--- ntserv/commands.c Thu Feb 22 14:35:51 1996
***************
*** 122,127 ****
--- 122,129 ----
extern int do_pause();
extern int do_free();
extern int do_gametime();
+ extern int do_timeout();
+ extern int do_confine();
#else /* OTHER stuff */
***************
*** 174,180 ****
*/
struct command_handler commands[] = {
! { NULL, NULL, NULL}, /* record 0 */
{ "HELP",
0,
"Show this help information",
--- 176,182 ----
*/
struct command_handler commands[] = {
! { NULL, 0, NULL, NULL}, /* record 0 */
{ "HELP",
0,
"Show this help information",
***************
*** 305,310 ****
--- 307,316 ----
C_CAPTAIN,
"Change your side to Orion.",
do_pickside }, /* ORI */
+ { "PASS",
+ C_CAPTAIN,
+ "Pass the first choice of sides to the home team.",
+ do_pickside }, /* PASS */
{ "PAUSE",
C_CAPTAIN,
"Requests a pause.",
***************
*** 317,322 ****
--- 323,332 ----
C_CAPTAIN,
"Requests that the game continues.",
do_pause }, /* CONTINUE */
+ { "TOUT",
+ C_CAPTAIN,
+ "Call a timeout.",
+ do_timeout }, /* TIMEOUT */
{ "FREE",
C_CAPTAIN | C_PLAYER,
"Frees a slot. Ex: 'FREE 0'",
***************
*** 325,330 ****
--- 335,344 ----
C_CAPTAIN,
"Shows the game time or sets it. Ex: 'GAMETIME 30 10'",
do_gametime }, /* GAMETIME */
+ { "CONFINE",
+ C_CAPTAIN,
+ "Confine teams from other races cores.",
+ do_confine }, /* CONFINE */
#else
{ "SBSTATS",
C_PLAYER,
***************
*** 1126,1132 ****
pcount++;
if (i==who) {
! if (j->voting[what] != 0) {
if (j->voting[what] < time(NULL) + votes[num].frequency) {
bounce(who,"Sorry, you can only use %s every %1.1f minutes",
votes[num].type, votes[num].frequency / 60.0);
--- 1140,1146 ----
pcount++;
if (i==who) {
! if ((j->voting[what] != 0) && (votes[num].frequency != 0)) {
if (j->voting[what] < time(NULL) + votes[num].frequency) {
bounce(who,"Sorry, you can only use %s every %1.1f minutes",
votes[num].type, votes[num].frequency / 60.0);
*** ntserv/death.c.orig Mon Jul 18 14:45:06 1994
--- ntserv/death.c Thu Feb 22 14:35:51 1996
***************
*** 41,46 ****
--- 41,47 ----
case KTORP:
case KTORP2:
case KPLASMA:
+ case KPLASMA2:
case KPHASER:
case KPLANET:
case KSHIP:
*** ntserv/gencmds.c.orig Thu Feb 22 23:24:27 1996
--- ntserv/gencmds.c Thu Feb 22 23:41:32 1996
***************
*** 0 ****
--- 1,373 ----
+ /*
+ * gencmds.c
+ */
+
+ /*
+ Command interface routines general to ntserv/daemon/robot code. This
+ is a replacement for the spagetti compile method used previously in
+ commands.c . Instead of compiling this file several times with modified
+ defines, the generalized routines found here can be linked into other
+ executables.
+ */
+
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <string.h>
+ #include <time.h>
+ #include <signal.h>
+ #include "defs.h"
+ #include "struct.h"
+ #include "data.h"
+ #include "gencmds.h"
+
+ char *
+ addr_mess(who, type)
+ int who, type;
+ {
+ static char addrbuf[10];
+ char* team_names[MAXTEAM+1] = { "", "FED", "ROM", "", "KLI",
+ "", "", "", "ORI" };
+
+ if (type == MALL)
+ sprintf(addrbuf,"%s->ALL", myname);
+ else if (type == MTEAM)
+ sprintf(addrbuf,"%s->%3s", myname, team_names[who]);
+ else /* Assume MINDIV */
+ sprintf(addrbuf, "%s->%2s", myname, players[who].p_mapchars);
+
+ return (addrbuf);
+ }
+
+ /* Check a command list to see if a message is a command */
+ int
+ check_2_command(mess, cmds, prereqs)
+ struct message *mess;
+ struct command_handler_2 *cmds;
+ int prereqs;
+ {
+ int i, j, len;
+ char *comm;
+ FILE *glog;
+
+ if (!(mess->m_flags & MINDIV)) return 0; /* double-check */
+
+ len = strlen(mess->m_data);
+
+ /* Check if a null command ( First 8 characters are XXX->XXX ) */
+ if (len <= 8)
+ return 0;
+
+ for (i = 8; i < len && isspace(mess->m_data[i]); i++) ; /* skip header/space */
+
+ comm = strdup(&mess->m_data[i]);
+
+ len = strlen(comm);
+
+ /* Convert first word in msg to uppercase */
+ for (i=0; (i < len && !isspace(comm[i])); i++)
+ {
+ comm[i] = toupper(comm[i]);
+ }
+
+ for (i=0; cmds[i].command != NULL; i++)
+ {
+ /* Dont check dummy descriptions.. */
+ if (cmds[i].tag & C_DESC)
+ continue;
+ if ((cmds[i].tag & C_PR_MASK) & ~(prereqs))
+ /* Dont meet the prereqs */
+ continue;
+ if (strncmp(cmds[i].command, comm, strlen(cmds[i].command)) == 0)
+ {
+
+ /* Record vote in GodLog if C_GLOG is set */
+ if (cmds[i].tag & C_GLOG )
+ {
+ if (!(glog = fopen(GodLog,"a")) ) /* Log votes for God to see */
+ perror(GodLog);
+ else
+ {
+ time_t t = time(NULL);
+ char tbuf[40];
+ struct tm *tmv = localtime(&t);
+
+ #ifdef STRFTIME
+ sprintf(tbuf, "%02d/%02d %d/%d", tmv->tm_hour,tmv->tm_min,
+ tmv->tm_mday,tmv->tm_mon);
+ #else
+ strftime(tbuf, 39, "%R %D", tmv);
+ #endif
+ fprintf(glog, "VOTE: %s %s@%s \"%s\"\n", tbuf,
+ players[mess->m_from].p_login,
+ players[mess->m_from].p_monitor, comm);
+ fclose(glog);
+ }
+ }
+
+ /* assume C_NAME */
+ #ifdef nodef
+ if (!(cmds[i].tag & C_NAME))
+ {
+ for (j=i; j < strlen(upper); j++)
+ upper[j] = toupper(upper[j]);
+ }
+ #endif
+
+ #ifdef VOTING
+ if (cmds[i].tag & (C_VC_ALL | C_VC_TEAM))
+ {
+ if (do_vote(comm, mess, cmds, i))
+ {
+ if ( cmds[i].tag & C_GLOG )
+ if (!(glog = fopen(GodLog,"a")) ) /* Log pass for God to see */
+ perror(GodLog);
+ else
+ {
+ fprintf(glog, "VOTE: The motion %s passes\n", comm);
+ fclose(glog);
+ }
+ }
+ }
+ else
+ #endif
+ {
+ if (cmds[i].tag & C_PLAYER)
+ {
+ int who;
+
+ /* This is really not that usefull - If the calling
+ function needs a player field, it should check it
+ on it's own. I include it here for compatibility */
+ who = getplayer(mess->m_from, comm);
+ if (who >= 0)
+ (*cmds[i].handler)(comm, mess, who, cmds, i, prereqs);
+ else
+ {
+ free(comm);
+ return 0;
+ }
+ }
+ else
+ (*cmds[i].handler)(comm, mess, cmds, i, prereqs);
+ }
+ free(comm);
+ return 1;
+ }
+ }
+ free(comm);
+ return 0;
+ }
+
+ int
+ getplayer(from, line)
+ 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;
+ }
+
+ #ifdef VOTING
+ int
+ do_vote(comm, mess, votes, num)
+ 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;
+
+ who = mess->m_from;
+
+ #ifdef OBSERVERS
+ if (players[who].p_status == POBSERV)
+ {
+ bounce(who, "Sorry, Observers can't vote");
+ return 0;
+ }
+ #endif
+
+ 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] < time(NULL) + votes[num].frequency)
+ {
+ bounce(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;
+ }
+
+ 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;
+
+ #ifdef OBSERVERS
+ /* Also skip observers */
+ if (j->p_status == POBSERV)
+ continue;
+ #endif
+
+ pcount++;
+
+ /* Did a player vote expire? */
+ if ((j->voting[what] > 0)
+ && ((votes[num].expiretime == 0)
+ || (j->voting[what] + votes[num].expiretime > time(NULL))))
+ vcount++;
+ }
+ 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-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 %s", i, (i==1 ? " ":"s"), comm);
+ return 0;
+ }
+ }
+ #endif /* VOTING */
+
+ /* ARGSUSED */
+ int
+ do_help(comm, mess, cmds, cmdnum, prereqs)
+ char *comm;
+ struct message *mess;
+ struct command_handler_2 *cmds;
+ int cmdnum;
+ {
+ 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);
+ #ifdef VOTING
+ 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);
+ }
+ #endif /* VOTING */
+ else
+ pmessage(who,MINDIV,addr, "|%10s - %s",
+ cmds[i].command, cmds[i].desc);
+ }
+ }
+ }
*** ntserv/ntscmds.c.orig Thu Feb 22 23:24:39 1996
--- ntserv/ntscmds.c Thu Feb 22 23:26:53 1996
***************
*** 0 ****
--- 1,935 ----
+ /*
+ * ntscmds.c
+ */
+
+ /*
+ Command interface routines general to ntserv processes. This
+ is a replacement for the spagetti compile method used previously in
+ commands.c . This file contains the defines, and code for performing
+ general commands issued to the server.
+ It doesn't contain the PUCK/DOG/INL and general command checking
+ routines that used to be grouped together in commands.c
+ */
+
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <string.h>
+ #include <time.h>
+ #include <signal.h>
+ #include "defs.h"
+ #include "struct.h"
+ #include "data.h"
+ #include "gencmds.h"
+
+ #define ALLOW_EJECT
+
+ #if defined (ALLOW_EJECT)
+ int do_player_eject();
+ #endif
+
+ #if defined (AUTO_INL)
+ int do_start_inl();
+ #endif
+
+ #if defined (AUTO_PRACTICE)
+ int do_start_basep();
+ #endif
+
+ #if defined(AUTO_HOCKEY)
+ int do_start_puck();
+ #endif
+
+ #if defined(AUTO_DOGFIGHT)
+ int do_start_mars();
+ #endif
+
+ #if defined (TRIPLE_PLANET_MAYHEM)
+ char *teamNames[9] = {" ", "Federation", "Romulans", " ", "Klingons",
+ " ", " ", " ", "Orions"};
+ int do_balance();
+ int do_triple_planet_mayhem();
+ #endif
+
+ const char myname[] = {"GOD"};
+
+ int do_sbstats_query();
+ int do_time_msg();
+ int do_queue_msg();
+
+ #ifdef GENO_COUNT
+ int do_genos_query();
+ #endif
+
+ int do_client_query();
+ int do_ping_query();
+ int do_stats_query();
+ #ifdef RSA
+ int bounceRSAClientType();
+ #endif
+ int bouncePingStats();
+ int bounceSessionStats();
+ int bounceSBStats();
+
+ /********* COMMANDS LIST ********
+ Note: - The commands *must* be in upper case. All commands are converted
+ to upper case before be checked.
+ - Votes are entered in the Voting list.
+ The first field is the command, the second is a description string
+ (up to 50 chars.), lastly is the function to call.
+ */
+
+ static struct command_handler_2 nts_commands[] =
+ {
+ { "Possible commands are:", C_DESC },
+ { "HELP",
+ 0,
+ "Show this help information",
+ do_help }, /* HELP */
+ { "CLIENT",
+ C_PLAYER,
+ "Show a user's client. Ex: 'CLIENT 0'",
+ do_client_query }, /* CLIENT */
+ { "PING",
+ C_PLAYER,
+ "Show client's ping (lag). Ex: 'PING 0'",
+ do_ping_query }, /* PING */
+ { "STATS",
+ C_PLAYER,
+ "Show player's stats during t-mode. Ex: 'STATS 0'",
+ do_stats_query }, /* STATS */
+ #ifdef ALLOW_PAUSE
+ { "PAUSE",
+ 0,
+ "Pause the game",
+ game_pause },
+ { "UNPAUSE",
+ 0,
+ "Resume the game",
+ game_resume },
+ #endif
+ { "SBSTATS",
+ C_PLAYER,
+ "Show player's starbase stats. Ex: 'SBSTATS 0'",
+ do_sbstats_query }, /* SBSTATS */
+ /***** Vanilla commands */
+ { "TIME",
+ 0,
+ "Show time left on Genocide timer.",
+ do_time_msg }, /* TIME */
+ { "QUEUE",
+ 0,
+ "Show how many people are on the queue.",
+ do_queue_msg }, /* QUEUE */
+ #ifdef GENO_COUNT
+ { "GENOS",
+ C_PLAYER,
+ "Show player's winning genocides. Ex: 'GENOS 0'",
+ do_genos_query }, /* GENOS */
+ #endif
+ #ifdef VOTING
+
+ { "The following votes can be used: (M=Majority, T=Team vote)", C_DESC },
+ { "Ejection Votes are recorded for the god to review.", C_DESC },
+ #if defined(ALLOW_EJECT)
+ { "EJECT",
+ C_VC_TEAM | C_GLOG | C_PLAYER,
+ "To eject a player. Ex: 'EJECT 0'",
+ do_player_eject, /* EJECT */
+ 2, 0, 120, 30},
+ #endif
+ #if defined(TRIPLE_PLANET_MAYHEM)
+ { "TRIPLE",
+ C_VC_ALL | C_GLOG,
+ "Start triple planet mayhem by vote",
+ do_triple_planet_mayhem,
+ 2, 22, 0},
+ { "BALANCE",
+ C_VC_ALL | C_GLOG,
+ "Request team randomise & balance",
+ do_balance,
+ 4, 23, 0 },
+ #endif
+ #if defined(AUTO_INL)
+ { "INL",
+ C_VC_ALL | C_GLOG,
+ "Start game under INL rules.",
+ do_start_inl,
+ 1, 20, 0 },
+ #endif
+ #if defined(AUTO_PRACTICE)
+ { "PRACTICE",
+ C_VC_ALL,
+ "Start basepractice by majority vote.",
+ do_start_basep,
+ 1, 20, 0 },
+ #endif
+ #if defined(AUTO_HOCKEY)
+ { "HOCKEY",
+ C_VC_ALL | C_GLOG,
+ "Start hockey by majority vote.",
+ do_start_puck,
+ 1, 20, 0 },
+ #endif
+ #if defined(AUTO_DOGFIGHT)
+ { "DOGFIGHT",
+ C_VC_ALL | C_GLOG,
+ "Start dogfight tournament by majority vote.",
+ do_start_mars,
+ 1, 20, 0 },
+ #endif
+ #endif /* VOTING */
+
+ { NULL }
+ };
+
+ int
+ check_command(mess)
+ struct message *mess;
+ {
+ return check_2_command(mess, nts_commands, 0);
+ }
+
+ #if defined (ALLOW_EJECT)
+ do_player_eject(who,player,mflags, sendto)
+ int who, player, mflags, sendto;
+ {
+ register struct player *j;
+
+ j = &players[player];
+
+ if (j->p_status == PFREE){
+ pmessage(sendto, mflags, addr_mess(who,MTEAM),
+ "That player is not in the game");
+ return;
+ }
+ if (j->p_flags & PFROBOT) {
+ pmessage(sendto, mflags, addr_mess(players[who].p_team,MTEAM),
+ "You cannot eject a robot, twinks!");
+ return;
+ }
+ if (j->p_team != players[who].p_team){
+ pmessage(players[who].p_team, MTEAM,
+ addr_mess(players[who].p_team,MTEAM),
+ "You can only eject your own teammates, twinks!");
+ return;
+ }
+
+ pmessage(0, MALL, addr_mess(who,MALL),
+ " %2s has been ejected by the players", j->p_mapchars);
+
+ #if defined (DOG)
+ reset_player(j->p_no);
+ dont_score(j->p_no);
+ #endif
+
+ eject_player(j->p_no);
+ }
+
+ eject_player(who)
+ int who;
+ {
+ struct player* j;
+
+ j = &players[who];
+ j->p_ship.s_type = STARBASE;
+ j->p_whydead=KQUIT;
+ j->p_explode=10;
+ j->p_status=PEXPLODE;
+ j->p_whodead=me->p_no;
+ }
+ #endif /* ALLOW_EJECT */
+
+ #if defined(AUTO_PRACTICE)
+ int do_start_basep(who, mflags, sendto)
+ int who, mflags,sendto;
+ {
+ if (vfork() == 0) {
+ (void) SIGNAL(SIGALRM,SIG_DFL);
+ execl(Basep, "basep", 0);
+ perror(Basep);
+ }
+ }
+ #endif
+
+ #if defined(AUTO_INL)
+ int do_start_inl(who, mflags, sendto)
+ int who, mflags, sendto;
+ {
+ if (vfork() == 0) {
+ (void) SIGNAL(SIGALRM,SIG_DFL);
+ execl(Inl, "inl", 0);
+ perror(Inl);
+ }
+ }
+ #endif
+
+ #if defined(AUTO_HOCKEY)
+ int do_start_puck(who, mflags, sendto)
+ int who, mflags, sendto;
+ {
+ if (vfork() == 0) {
+ (void) SIGNAL(SIGALRM,SIG_DFL);
+ execl(Puck, "puck", 0);
+ perror(Puck);
+ }
+ }
+ #endif
+
+ #if defined(AUTO_DOGFIGHT)
+ int do_start_mars(who, mflags, sendto)
+ int who, mflags, sendto;
+ {
+ if (vfork() == 0) {
+ (void) SIGNAL(SIGALRM,SIG_DFL);
+ execl(Mars, "mars", 0);
+ perror(Mars);
+ }
+ }
+ #endif
+
+ /*** QUERIES ***/
+ send_query(which,who,from)
+ char which;
+ int who, from;
+ {
+ pmessage2(who, MINDIV, " ", from, "%c", which);
+ }
+
+ /* ARGSUSED */
+ do_client_query(comm,mess,who)
+ char *comm;
+ struct message *mess;
+ int who;
+ {
+ #ifdef RSA
+ send_query('#', who, mess->m_from);
+ #endif
+ }
+
+ /* ARGSUSED */
+ do_ping_query(comm,mess,who)
+ char *comm;
+ struct message *mess;
+ int who;
+ {
+ send_query('!', who, mess->m_from);
+ }
+
+ /* ARGSUSED */
+ do_stats_query(comm,mess,who)
+ char *comm;
+ struct message *mess;
+ int who;
+ {
+ send_query('?', who, mess->m_from);
+ }
+
+ #ifdef RSA
+ int bounceRSAClientType(from)
+ int from;
+ {
+ bounce(from,"Client: %s", RSA_client_type);
+
+ return 1;
+ }
+ #endif
+
+ int
+ bounceSessionStats(from)
+ int from;
+ {
+ float sessionBombing, sessionPlanets,
+ sessionOffense, sessionDefense;
+ int deltaArmies, deltaPlanets,
+ deltaKills, deltaLosses,
+ deltaTicks;
+ deltaPlanets = me->p_stats.st_tplanets - startTplanets;
+ deltaArmies = me->p_stats.st_tarmsbomb - startTarms;
+ deltaKills = me->p_stats.st_tkills - startTkills;
+ deltaLosses = me->p_stats.st_tlosses - startTlosses;
+ deltaTicks = me->p_stats.st_tticks - startTticks;
+
+
+ if (deltaTicks == 0) {
+ bounce(from,
+ "Session stats are only available during t-mode.");
+ return 1; /* non t-mode */
+ }
+
+ sessionPlanets = (double ) deltaPlanets * status->timeprod /
+ ((double) deltaTicks * status->planets);
+
+ sessionBombing = (double) deltaArmies * status->timeprod /
+ ((double) deltaTicks * status->armsbomb);
+
+ sessionOffense = (double) deltaKills * status->timeprod /
+ ((double) deltaTicks * status->kills);
+
+ sessionDefense = (double) deltaTicks * status->losses /
+ (deltaLosses!=0 ? (deltaLosses * status->timeprod) : (status->timeprod));
+
+ bounce(from,
+ "%2s stats: %d planets and %d armies. %d wins/%d losses. %5.2f hours.",
+ me->p_mapchars,
+ deltaPlanets,
+ deltaArmies,
+ deltaKills,
+ deltaLosses,
+ (float) deltaTicks/36000.0);
+ bounce(from,
+ "Ratings: Pla: %5.2f Bom: %5.2f Off: %5.2f Def: %5.2f Ratio: %4.2f",
+ sessionPlanets,
+ sessionBombing,
+ sessionOffense,
+ sessionDefense,
+ (float) deltaKills /
+ (float) ((deltaLosses == 0) ? 1 : deltaLosses));
+ return 1;
+ }
+
+ int
+ bounceSBStats(from)
+ int from;
+ {
+ float sessionRatio, sessionKPH, sessionDPH,
+ overallKPH, overallDPH, overallRatio;
+ int deltaKills, deltaLosses,
+ deltaTicks;
+
+ deltaKills = me->p_stats.st_sbkills - startSBkills;
+ deltaLosses = me->p_stats.st_sblosses - startSBlosses;
+ deltaTicks = me->p_stats.st_sbticks - startSBticks;
+ overallRatio = (float) (me->p_stats.st_sblosses==0) ?
+ (float) me->p_stats.st_sbkills :
+ (float) me->p_stats.st_sbkills / (float) me->p_stats.st_sblosses;
+
+ /* if (deltaTicks == 0) {
+ bounce(from,
+ "No SB time yet this session.");
+ return 0;
+ } */
+
+ if (deltaTicks != 0) {
+ sessionKPH = (float) deltaKills * 36000.0 / (float) deltaTicks;
+ sessionDPH = (float) deltaLosses * 36000.0 / (float) deltaTicks;
+ } else {
+ sessionKPH = sessionDPH = 0.0;
+ }
+
+ sessionRatio = (float) (deltaLosses==0) ? (float) deltaKills :
+ (float) deltaKills / (float) deltaLosses;
+
+ if (me->p_stats.st_sbticks != 0) {
+ overallKPH = (float) me->p_stats.st_sbkills * 36000.0 /
+ (float) me->p_stats.st_sbticks;
+ overallDPH = (float) me->p_stats.st_sblosses * 36000.0 /
+ (float) me->p_stats.st_sbticks;
+ } else {
+ overallKPH = overallDPH = 0.0;
+ }
+
+ bounce(from,
+ "%2s overall SB stats: %d wins/%d losses. %5.2f hours. Ratio: %5.2f",
+ me->p_mapchars,
+ me->p_stats.st_sbkills,
+ me->p_stats.st_sblosses,
+ (float) me->p_stats.st_sbticks/36000.0,
+ overallRatio);
+
+ if (deltaTicks)
+ bounce(from,
+ "%2s session SB stats: %d wins/%d losses. %5.2f hours. Ratio: %5.2f",
+ me->p_mapchars,
+ deltaKills,
+ deltaLosses,
+ (float) deltaTicks/36000.0,
+ sessionRatio);
+ bounce(from,
+ "Kills/Hour: %5.2f (%5.2f total), Deaths/Hour: %4.2f (%4.2f total)",
+ sessionKPH,
+ overallKPH,
+ sessionDPH,
+ overallDPH);
+ return 1;
+ }
+
+
+ #ifdef PING
+ int bouncePingStats(from)
+ int from;
+ {
+ if(me->p_avrt == -1){
+ /* client doesn't support it or server not pinging */
+ bounce(from,"No PING stats available for %c%c",
+ me->p_mapchars[0], me->p_mapchars[1]);
+ }
+ else{
+ bounce(from,
+ "%c%c PING stats: Average: %d ms, Stdv: %d ms, Loss: %d%%/%d%% s->c/c->s",
+ me->p_mapchars[0], me->p_mapchars[1],
+ me->p_avrt,
+ me->p_stdv,
+ me->p_pkls_s_c,
+ me->p_pkls_c_s);
+ }
+ return 1;
+ }
+ #endif
+
+
+ /* ARGSUSED */
+ do_sbstats_query(comm,mess,who)
+ char *comm;
+ struct message *mess;
+ int who;
+ {
+ send_query('^', who, mess->m_from);
+ }
+
+ #ifdef GENO_COUNT
+ do_genos_query(comm,mess,who)
+ char *comm;
+ struct message *mess;
+ int who;
+ {
+ char *addr;
+
+ addr = addr_mess(mess->m_from,MINDIV);
+ pmessage(mess->m_from, MINDIV, addr, "%s has won the game %d times.",
+ players[who].p_name,players[who].p_stats.st_genos);
+ }
+ #endif
+
+
+ /* ARGSUSED */
+ do_time_msg(comm,mess)
+ char *comm;
+ struct message *mess;
+ {
+ char *teamNames[9] = {" ", "Federation", "Romulans", " ", "Klingons",
+ " ", " ", " ", "Orions"};
+ int who;
+ int t;
+ char *addr;
+
+ who = mess->m_from;
+ addr = addr_mess(who,MINDIV);
+
+ for (t=0;((t<=MAXTEAM)&&(teams[t].s_surrender==0));t++);
+
+ if (t>MAXTEAM) {
+ pmessage(who, MINDIV, addr, "No one is considering surrender now. Go take some planets.");
+ } else {
+ pmessage(who, MINDIV, addr, "The %s have %d minutes left before they surrender.", teamNames[t],teams[t].s_surrender);
+ }
+ }
+
+ /*
+ * Give information about the waitqueue status
+ */
+
+ /* ARGSUSED */
+ do_queue_msg(comm,mess)
+ char *comm;
+ struct message *mess;
+ {
+ int who;
+ char *addr;
+ int i;
+
+ who = mess->m_from;
+ addr = addr_mess(who,MINDIV);
+
+ for (i=0; i < MAXQUEUE; i++) {
+ /* Only report open queues that have the report flag set. */
+ if (!(queues[i].q_flags & QU_OPEN)) continue;
+ if (!(queues[i].q_flags & QU_REPORT)) continue;
+
+ if (queues[i].count>0 )
+ pmessage(who, MINDIV, addr, "Approximate %s queue size: %d",
+ queues[i].q_name, queues[i].count);
+ else
+ pmessage(who, MINDIV, addr, "There is no one on the %s queue.",
+ queues[i].q_name);
+ }
+ }
+
+ #ifdef TRIPLE_PLANET_MAYHEM
+ /*
+ ** 16-Jul-1994 James Cameron
+ **
+ ** Balances teams according to player statistics.
+ ** Intended for use with Triple Planet Mayhem
+ */
+
+ /*
+ ** Tell all that player will be moved
+ */
+ static void
+ moveallmsg ( int p_no, int ours, int theirs )
+ {
+ struct player *k = &players[p_no];
+ pmessage(0, MALL, addr_mess(myname, MALL),
+ "Balance: %16s (%c%c) is to join the %s",
+ k->p_name, teamlet[k->p_team], shipnos[p_no], teamNames[ours] );
+ }
+
+ /*
+ ** Move a player to the specified team, if they are not yet there.
+ ** Make them peaceful with the new team, and hostile/at war with the
+ ** other team.
+ */
+ static void
+ move(int p_no, int ours, int theirs)
+ {
+ struct player *k = &players[p_no];
+
+ if ( k->p_team != ours ) {
+ pmessage(k->p_no, MINDIV, addr_mess(k->p_no,MINDIV),
+ "%s: please SWAP SIDES to the %s", k->p_name, teamNames[ours] );
+ }
+ else {
+ pmessage(k->p_no, MINDIV, addr_mess(k->p_no,MINDIV),
+ "%s: please remain with the %s", k->p_name, teamNames[ours] );
+ }
+
+ printf("Balance: %16s (%s) is to join the %s\n",
+ k->p_name, k->p_mapchars, teamNames[ours]);
+
+ k->p_hostile |= theirs;
+ k->p_swar |= theirs;
+ k->p_hostile &= ~ours;
+ k->p_swar &= ~ours;
+ k->p_war = (k->p_hostile | k->p_swar);
+ k->p_team = ours;
+ sprintf(k->p_mapchars, "%c%c", teamlet[k->p_team], shipnos[p_no]);
+ sprintf(k->p_longname, "%s (%s)", k->p_name, k->p_mapchars);
+
+ k->p_status = PEXPLODE;
+ k->p_whydead = KPROVIDENCE; /* should be KTOURNSTART? */
+ if (k->p_ship.s_type = STARBASE)
+ k->p_explode = 2 * SBEXPVIEWS;
+ else
+ k->p_explode = 10;
+ k->p_ntorp = 0;
+ k->p_nplasmatorp = 0;
+ k->p_hostile = (FED | ROM | ORI | KLI);
+ k->p_war = (k->p_hostile | k->p_swar);
+ }
+
+ /*
+ ** Return two team masks corresponding to the teams of the first two
+ ** teams found in the player list.
+ */
+ static void sides ( int *one, int *two )
+ {
+ struct player *k;
+ int i;
+ int unseen;
+
+ unseen = (FED | ROM | ORI | KLI);
+ *one = 0;
+ *two = 0;
+ k = &players[0];
+ for(i=0;i<MAXPLAYER;i++)
+ {
+ if ( (k->p_status != PFREE) && (!(k->p_flags & PFROBOT)))
+ {
+ if ( ( unseen & k->p_team ) != 0 )
+ {
+ if ( *one == 0 )
+ {
+ *one = k->p_team;
+ unseen &= ~k->p_team;
+ k++;
+ continue;
+ }
+ *two = k->p_team;
+ return;
+ }
+ }
+ k++;
+ }
+ }
+
+ /*
+ ** Calculate a player value
+ */
+ static int value ( struct player *k )
+ {
+ return
+ (int)
+ (
+ (float)
+ (
+ bombingRating(k) +
+ planetRating(k) +
+ offenseRating(k)
+ ) * 100.0
+ );
+ }
+
+ /*
+ ** Balance the teams
+ **
+ ** Uses an exhaustive algorithm (I'm exhausted!) to find the best combination
+ ** of the current players that balances the teams in terms of statistics.
+ ** The algorithm will support only the number of players that fits into the
+ ** number of bits in an int.
+ **
+ ** If there are multiple "best" combinations, then the combination
+ ** involving the least number of team swaps will be chosen.
+ */
+ int do_balance(void)
+ {
+ int i, j; /* miscellaneous counters */
+ int records; /* number of players in game */
+ int one; /* team number one mask */
+ int two; /* team number two mask */
+
+ struct player *k; /* pointer to current player */
+
+ struct item
+ {
+ int p_no; /* player number */
+ int p_value; /* calculated player value */
+ int p_team; /* team player on previously */
+ } list[MAXPLAYER]; /* working array */
+
+ struct
+ {
+ int combination; /* combination number */
+ int value; /* team balance difference */
+ int one; /* team one total value */
+ int two; /* team two total value */
+ int swaps; /* number of swaps involved */
+ } best; /* best team combination */
+
+ /* which teams are playing? give up if only one found */
+ sides ( &one, &two );
+ if ( two == 0 )
+ {
+ pmessage ( 0, MALL, addr_mess(myname,MALL),
+ "Can't balance only one team!" );
+ pmessage ( 0, MALL, addr_mess(myname,MALL),
+ "Please could somebody move to another team, then all vote again?" );
+ return;
+ }
+
+ /* initialise best to worst case */
+ best.combination = -1;
+ best.value = 1<<30;
+ best.one = 0;
+ best.two = 0;
+ best.swaps = 1<<30;
+
+ /* reset working array */
+ for(i=0;i<MAXPLAYER;i++)
+ {
+ list[i].p_no = 0;
+ list[i].p_value = 0;
+ }
+
+ /* insert players in working array */
+ records = 0;
+ k = &players[0];
+ for(i=0;i<MAXPLAYER;i++)
+ {
+ if ( (k->p_status != PFREE) && (!(k->p_flags & PFROBOT)))
+ {
+ list[records].p_no = k->p_no;
+ list[records].p_value = value ( k );
+ list[records].p_team = k->p_team;
+ records++;
+ }
+ k++;
+ }
+
+ /* randomise the working array; may cause different team mixes */
+ for(i=0;i<records;i++)
+ {
+ int a, b;
+ struct item swapper;
+
+ a = random() % records;
+ b = random() % records;
+
+ swapper = list[a];
+ list[a] = list[b];
+ list[b] = swapper;
+ }
+
+ /* loop for every _possible_ combination to find the best */
+ for(i=0;i<(1<<records);i++)
+ {
+ int difference; /* difference in team total */
+ int value_a, value_b; /* total stats per team */
+ int count_a, count_b; /* total count of players on team */
+ int swaps; /* number of swaps involved */
+
+ /* if this a shadow combination already considered, ignore it */
+ /* if ( ( i ^ ( ( 1<<records ) - 1 ) ) < i ) continue; */
+ /* disabled - it will interfere with swap minimisation goal */
+
+ /* is this combination an equal number of players each side? */
+ count_a = 0;
+ count_b = 0;
+
+ for(j=0;j<records;j++)
+ if((1<<j)&i)
+ count_a++;
+ else
+ count_b++;
+
+ /* skip this combination if teams are significantly unequal */
+ if ( abs ( count_a - count_b ) > 1 ) continue;
+
+ /* reset team total for attempt */
+ value_a = 0;
+ value_b = 0;
+
+ /* calculate team total stats */
+ for(j=0;j<records;j++)
+ if((1<<j)&i)
+ value_a += list[j].p_value;
+ else
+ value_b += list[j].p_value;
+
+ /* calculate number of swaps this combination produces */
+ swaps = 0;
+ for(j=0;j<records;j++)
+ if((1<<j)&i)
+ {
+ if ( list[j].p_team != one ) swaps++;
+ }
+ else
+ {
+ if ( list[j].p_team != two ) swaps++;
+ }
+
+ /* calculate difference in team total stats */
+ difference = abs ( value_a - value_b );
+
+ /* if this combo is better than the previous one we had,
+ or the combo is the same and the number of swaps is lower... */
+ if ( ( difference < best.value )
+ || ( ( difference == best.value )
+ && ( swaps < best.swaps ) ) )
+ {
+ /* remember it */
+ best.value = difference;
+ best.combination = i;
+ best.one = value_a;
+ best.two = value_b;
+ best.swaps = swaps;
+ }
+ }
+
+ /* announce movements intended */
+ for(j=0;j<records;j++)
+ if ( (1<<j)&best.combination )
+ moveallmsg ( list[j].p_no, one, two );
+
+ for(j=0;j<records;j++)
+ if ( !((1<<j)&best.combination) )
+ moveallmsg ( list[j].p_no, two, one );
+
+ /* move players to their teams */
+ for(j=0;j<records;j++)
+ if ( (1<<j)&best.combination )
+ move ( list[j].p_no, one, two );
+ else
+ move ( list[j].p_no, two, one );
+
+ /* advise all of resultant team mix difference */
+ pmessage ( 0, MALL, addr_mess(myname,MALL),
+ "The %s total rating will be %.2f",
+ teamNames[one],
+ (float) ( best.one / 100.0 ) );
+
+ pmessage ( 0, MALL, addr_mess(myname,MALL),
+ "The %s total rating will be %.2f",
+ teamNames[two],
+ (float) ( best.two / 100.0 ) );
+
+ }
+
+ int do_triple_planet_mayhem(void)
+ {
+ int i;
+
+ struct player* j;
+
+ /* balance the teams */
+ do_balance();
+
+ /* move all planets off the galaxy */
+ for (i=0; i<MAXPLANETS; i++)
+ {
+ planets[i].pl_flags = 0;
+ planets[i].pl_owner = 0;
+ planets[i].pl_x = -10000;
+ planets[i].pl_y = -10000;
+ planets[i].pl_info = 0;
+ planets[i].pl_armies = 0;
+ strcpy ( planets[i].pl_name, "" );
+ }
+
+ /* disable Klingon and Orion teams; stop people from joining them */
+ planets[20].pl_couptime = 999999; /* no Klingons */
+ planets[30].pl_couptime = 999999; /* no Orions */
+
+ /* initialise earth */
+ i = 0;
+ planets[i].pl_flags |= FED | PLHOME | PLCORE | PLAGRI | PLFUEL | PLREPAIR;
+ planets[i].pl_x = 40000;
+ planets[i].pl_y = 65000;
+ planets[i].pl_armies = 40;
+ planets[i].pl_info = FED;
+ planets[i].pl_owner = FED;
+ strcpy ( planets[i].pl_name, "Earth" );
+
+ /* initialise romulus */
+ i = 10;
+ planets[i].pl_flags |= ROM | PLHOME | PLCORE | PLAGRI | PLFUEL | PLREPAIR;
+ planets[i].pl_x = 40000;
+ planets[i].pl_y = 35000;
+ planets[i].pl_armies = 40;
+ planets[i].pl_info = ROM;
+ planets[i].pl_owner = ROM;
+ strcpy ( planets[i].pl_name, "Romulus" );
+
+ /* initialise indi */
+ i = 18;
+ planets[i].pl_flags |= PLFUEL | PLREPAIR;
+ planets[i].pl_flags &= ~PLAGRI;
+ planets[i].pl_x = 15980;
+ planets[i].pl_y = 50000;
+ planets[i].pl_armies = 4;
+ planets[i].pl_info &= ~ALLTEAM;
+ strcpy ( planets[i].pl_name, "Indi" );
+
+ /* fix all planet name lengths */
+ for (i=0; i<MAXPLANETS; i++)
+ {
+ planets[i].pl_namelen = strlen(planets[i].pl_name);
+ }
+
+ /* advise players */
+ {
+ char *list[] =
+ {
+ "Galaxy reset for triple planet mayhem!",
+ "Rule 1: they take Indi, they win,",
+ "Rule 2: they take your home planet, they win,",
+ "Rule 3: you can't bomb Indi,",
+ "Rule 4: you may bomb their home planet, and;",
+ "Rule 5: all planets are FUEL & REPAIR, home planets are AGRI.",
+ ""
+ };
+
+ for ( i=0; strlen(list[i])!=0; i++ )
+ pmessage ( 0, MALL, addr_mess(myname,MALL), list[i] );
+ }
+ }
+ #endif /* TRIPLE_PLANET_MAYHEM */
--
------------------------------------------------------------------------
| Kevin O'Connor "BTW, IMHO we need a FAQ for 'RTFM', | **
| koconnor@acsu.buffalo.edu 'IMHO', 'IMO', 'FAQ', 'BTW', etc. !" | **
------------------------------------------------------------------------ **
*************************************************************************