Mercurial > ~darius > hgwebdir.cgi > paradise_server
diff src/daemonII.c @ 2:2719a89505ba
First entry of Paradise Server 2.9 patch 10 Beta
author | darius |
---|---|
date | Sat, 06 Dec 1997 04:37:01 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/daemonII.c Sat Dec 06 04:37:01 1997 +0000 @@ -0,0 +1,1162 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ +char binary[] = "@(#)daemonII"; + +#define DAEMONII 1 /* to tell daemonII.h we are in this file */ + +#include "config.h" +#include <stdio.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/file.h> +#include <setjmp.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#ifndef ULTRIX +#include <sys/fcntl.h> +#endif +#include <string.h> + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <math.h> +#include <errno.h> + +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "planets.h" +#include "terrain.h" +#include "conquer.h" +#include "daemonII.h" +#include "getship.h" +#include "weapons.h" +#include "player.h" +#include "misc.h" +#include "shmem.h" +#include "path.h" + +#define TellERR(x) fprintf(stderr, "! %s: %s\n", argv0, x) +#define TellERRf(x, y) { \ + sprintf(buf, x, y); \ + fprintf(stderr, "! %s: %s\n", argv0, buf); \ + } +/*--------------------------FUNCTION PROTOTYPES---------------------------*/ +#ifndef FreeBSD +long lseek(); +#endif + +typedef void sig_ret_t; + +void move(); +sig_ret_t reaper(); +sig_ret_t setflag(); +sig_ret_t freemem(); +char *getenv(); +char *twoletters(); +void starttimer(); +void stoptimer(); +void printdaemonIIUsage(); +void check_load(); +void rescue(); +void teamtimers(); +void shipbuild_timers(); +extern void (*r_signal()) (); + +/*------------------------------------------------------------------------*/ + + + + + + + +/*---------------------------MODULE VARIABLES-----------------------------*/ + +int dietime = -1; /* to decide whether the deamon has been */ +/* inactive for one minute. Set to -1 so */ +/* the deamon will not immediately quit */ + +int ticks = 0; /* counting ticks for game timing */ + +jmp_buf env; /* to hold long jump back into main */ + +static int debug = 0; /* set if an arg is passed to main on the + * command line, this var gets set to 1 and + * debuf info is printed. */ + +static int doMove; /* indicates whether it's time to call move() */ + +int plfd; /* for the planet file */ +int glfd; /* for the status file */ + +/* The name of the four teams */ + +/* The verbage to use in sentences such as 'the XXXXX have/has' */ +char *teamVerbage[9] = {"", "has", "have", "", "have", "", "", "", "have"}; + +int tourntimestamp = 0; /* ticks since t-mode started */ + + +/*------------------------------------------------------------------------*/ + + + + + + + + +/*----------------------------------MAIN-----------------------------------*/ +/* + * Well, this is it. The big Kahuna. The main function of daemonII. If an + * arg is passed to main, then debug info is printed. What is passed in does + * not matter. Personally, I am fond of running it with: daemonII fungus. + * But maybe that's just me. Important: An environment variable is read in + * from the user. It is called NETREKDIR. This variable needs to be a path + * to where the '.' (dot) files are to be found. Kurt added this to make + * things a hell of a lot easier. + */ + +int +main(argc, argv) + int argc; + char **argv; +{ + register int i; /* looping var */ + int jjk; /* looping var */ + char buf[255]; /* Temp buffer */ + char *paths; /* to form path with */ + char *ptr; /* get get path env var */ + + int x = 0; /* for delay in debugging messages */ +#ifdef LEAGUE_SUPPORT + int configleague = 0; /* if nonzero, set configvals->league to 1 */ +#endif + int attach = 0; + int nogo = 0; /* for the usage flag/case */ + + argv0 = argv[0]; + + i = 1; + while (argv[i]) + { + if (argv[i][0] == '-') + { + ptr = &argv[i][1]; + while (*ptr) + { + switch (*ptr) + { + case 'l': +#ifdef LEAGUE_SUPPORT + configleague = 1; +#else + TellERR("daemon not compiled with league support."); + TellERR("Edit config.h and reinstall."); + TellERR("Continuing anyway."); +#endif + break; + case 'd': + debug = 1; + break; + case 'a': + attach = 1; + break; + case 'h': + case 'u': /* for old times sake */ + case '-': /* this allows for --help people */ + nogo++; + break; + case 'v': /* version, what the hell */ + fprintf(stderr, "-- NetrekII (Paradise), %s --\n", PARAVERS); + exit(0); + break; + default: + TellERRf("Unknown flag '%c'.", *ptr); + nogo++; + /* fprintf(stderr, "Unknown flag '%c'\n", *ptr); */ + break; + } + ptr++; + } + } +#if 0 /* this is goofy, just use -d */ + else + { + TelLERR("Backward compatibility: activating debugging mode."); + debug = 1; + break; + } +#endif + else + { + TellERRf("Invalid option format '%s'.", argv[i]); + nogo++; + break; + } + i++; + } + + if (nogo) + { + printdaemonIIUsage(argv0); + } + else + { + /* log the PID */ + char *fname; + FILE *fptr; + + fname = build_path("logs/daemonII.pid"); + fptr = fopen(fname, "w+"); + fprintf(fptr, "%d", getpid()); + fclose(fptr); + } + + fprintf(stderr, "Daemon says 'hello!'\n"); /* say hi */ + srand48(getpid()); /* seed random # gen */ + + openmem(attach ? 0 : 2, 0); /* create shared memory */ + + /* my daemonII has been dumping core a lot in readsysdefaults */ + if (!debug) + { /* setup signals if not debugging */ + for (i = 0; i < NSIG; i++) + r_signal(i, freemem); + r_signal(SIGSTOP, SIG_DFL); /* accept SIGSTOP? 3/6/92 TC */ + r_signal(SIGTSTP, SIG_DFL); /* accept SIGTSTP? 3/6/92 TC */ + r_signal(SIGCONT, SIG_DFL); /* accept SIGCONT? 3/6/92 TC */ + } + +#ifdef LEAGUE_SUPPORT + if (configleague && !attach) + { + status2->league = 1; /* configure for league play */ + /* .sysdef will be ignored */ + + /* haven't chosen teams yet */ + status2->home.index = status2->away.index = -1; + + /* haven't chosen captains either */ + status2->home.captain = status2->away.captain = -1; + + /* no names for the team */ + status2->home.name[0] = status2->away.name[0] = 0; + + status2->home.ready = status2->away.ready = 0; + + status2->home.desirepause = status2->away.desirepause = 0; + + /* away has NOT passed team choice */ + status2->awaypassed = 0; + + status2->paused = 0; + + /* clear out the temporary player file */ + paths = build_path(PLAYERFILE); + if (0 != unlink(paths) && errno != ENOENT) + { + perror("zeroing tourney temporary player file"); + } + + status2->home.desired.galaxyreset = status2->away.desired.galaxyreset + = 0; + status2->home.desired.restart = status2->away.desired.restart + = 0; + } +#endif + + if (!attach) + readsysdefaults(); /* go get sysdefaults */ + +#ifdef LEAGUE_SUPPORT + if (configleague && !attach) + { + status2->home.timeouts_left = status2->away.timeouts_left = + configvals->timeouts; + + status2->home.desired.regulation = status2->away.desired.regulation + = configvals->regulation_minutes; + status2->home.desired.overtime = status2->away.desired.overtime + = configvals->overtime_minutes; + status2->home.desired.maxplayers = status2->away.desired.maxplayers + = configvals->playersperteam; + } +#endif + + + if (!attach) + { + for (i = 0; i < MAXPLAYER; i++) + { /* go through all players */ + players[i].p_status = PFREE; /* set slot free */ + players[i].p_no = i; /* set his player number */ + players[i].p_ntspid = 0; + } + status2->nontteamlock = ALLTEAM; + status2->starttourn = 0; + } /* !attach */ + + paths = build_path(PLFILE); + plfd = open(paths, O_RDWR, 0744); /* open planets file */ + if (!attach) + { +#if 1 + gen_planets(); /* generate a new galaxy every time */ + status->time = 0; +#else + if (plfd < 0) + { /* oopen failed? */ + fprintf(stderr, "No planet file. Restarting galaxy\n"); + gen_planets(); /* yup, go to it */ + } + else + { /* try to read in planets */ + if (read(plfd, (char *) planets, sizeof(struct planet) * MAXPLANETS) != + sizeof(struct planet) * MAXPLANETS) + { /* if wrong size */ + fprintf(stderr, "Planet file wrong size. Restarting galaxy\n"); + gen_planets(); /* then regenerate galaxy */ + } + } +#endif + } /* !attach */ + paths = build_path(GLOBAL); + + glfd = open(paths, O_RDWR, 0744); /* try to open file */ + + if (!attach) + { + if (glfd < 0) + { /* if could not open */ + fprintf(stderr, "No global file. Resetting all stats\n"); + memset((char *) status, 0, sizeof(struct status)); + glfd = open(paths, O_RDWR | O_CREAT, 0744); /* try to create file */ + } + else + { + if (read(glfd, (char *) status, sizeof(struct status)) != + sizeof(struct status)) + { /* try to read file */ + fprintf(stderr, "Global file wrong size. Resetting all stats\n"); + memset((char *) status, 0, sizeof(struct status)); + } + } + if (status->time == 0) + { /* do stats need resetting */ + status->dooshes = 1500; /* yup, then reset them */ + status->armsbomb = 4000; /* set them to something other than */ + status->resbomb = 1200; /* zeroes and ones so that the */ + status->planets = 1000; /* globals are not totally whacked */ + status->kills = 1; /* when we first start */ + status->losses = 1; + status->genocides = 10; + status->sbkills = 1200; + status->sblosses = 30; + status->sbtime = 720000; + status->wbkills = 1200; + status->wblosses = 40; + status->wbtime = 360000; + status->jsplanets = 400; + status->jstime = 240000; + status->time = 1; + status->timeprod = 1; + } + + /* wait queue stuff */ + status->wait = 0; /* invocation of the */ + status->count = 0; /* daemon */ + status->request = 0; + + } /* !attach */ + status->active = 0; /* set stats that deal with this */ + status->gameup = 1; + status->nukegame = getpid(); + status->timeprod = 0; + + setjmp(env); /* set the loooong jump */ + + r_signal(SIGCHLD, reaper); /* set reaper and setflag signal */ + r_signal(SIGALRM, setflag); /* handlers */ + + if (!attach) + { + for (i = 0; i <= MAXTEAM; i++) + { /* reset some team vars */ + teams[i].s_surrender = 0; /* reset surrender timers */ + for (jjk = 0; jjk < NUM_TYPES; jjk++) + teams[i].s_turns[jjk] = 0; /* reset all ship construction timers */ + } + } /* !attach */ + + status2->newgalaxy = 0; + for (i = 0; i < MAXPLAYER; i++) + { + galaxyValid[i] = 0; + } + + check_load(); /* check the load on machine */ + + starttimer(); /* start interval timer */ + doMove = 0; + + while (1) + { /* do forever */ + if (!doMove) + pause(); /* wait for signal */ + + if (doMove) + { /* if it's time */ + doMove = 0; /* reset the flag */ + move(); /* then do the update */ + + if (debug) + { /* if in debug mode */ + if (!(++x % 50)) /* print 'mark' as we wait */ + printf("Mark %d\n", x); + } + } + } +} +/*---------------------[ prints the usage of daemonII ]---------------------*/ + +void +printdaemonIIUsage(char *myname) +{ + int x; + char message[][255] = { + "\n\t'%s [options]'\n\n", + "Options:\n", + "\t-h help (this usage message)\n", + "\t-l configures as a League server (usually run by listen)\n", + "\t-d debug\n", + "\t-a attach to a crashed daemon's memory segment\n", + "\nNOTE: %s is designed to be launched by the startup process.\n\n", + "\0" + }; + + fprintf(stderr, "-- NetrekII (Paradise), %s --\n", PARAVERS); + for (x = 0; *message[x] != '\0'; x++) + fprintf(stderr, message[x], myname); + + exit(1); +} + +/*--------------------------[ printdaemonIIUsage ]--------------------------*/ + +/* signal handler for SIGALRM */ +sig_ret_t +setflag() +{ + doMove = 1; +} + +void +starttimer() +{ + struct itimerval udt; + + udt.it_interval.tv_sec = 0; + udt.it_interval.tv_usec = UPDATE; + udt.it_value.tv_sec = 0; + udt.it_value.tv_usec = UPDATE; + setitimer(ITIMER_REAL, &udt, (struct itimerval *) 0); +} + +void +stoptimer() +{ + struct itimerval udt; + + udt.it_interval.tv_sec = 0; + udt.it_interval.tv_usec = 0; + udt.it_value.tv_sec = 0; + udt.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &udt, (struct itimerval *) 0); +} + +#ifdef LEAGUE_SUPPORT +static void +handle_pause_goop() +{ + if (status2->paused) + { + if (!status2->home.desirepause && !status2->away.desirepause) + { + /* countdown to game resumption */ + status2->paused--; + if (status2->paused) + { + if (status2->paused % TICKSPERSEC == 0) + { + char buf[80]; + sprintf(buf, "Game will resume in %d seconds", + status2->paused / TICKSPERSEC); + pmessage(buf, -1, MALL, UMPIRE); + } + } + else + { + pmessage("Let the carnage resume!", -1, MALL, UMPIRE); + } + } + else + { + status2->pausemsgfuse++; + if (status2->pausemsgfuse > SECONDS(15)) + { + status2->pausemsgfuse = 0; + pmessage("Game is PAUSEd. Captains `LEAGUE CONTINUE' to resume play.", + -1, MALL, UMPIRE); + if (!status2->home.desirepause) + pmessage("The home team wishes to CONTINUE the game.", + -1, MALL, UMPIRE); + if (!status2->away.desirepause) + pmessage("The away team wishes to CONTINUE the game.", + -1, MALL, UMPIRE); + } + } + } + else + { + if (!status2->home.desirepause && !status2->away.desirepause) + return; + + status2->pausemsgfuse++; + if (status2->pausemsgfuse > SECONDS(15)) + { + char buf[80]; + status2->pausemsgfuse = 0; + sprintf(buf, "The %s team wishes to PAUSE the game!", + status2->home.desirepause ? "home" : "away"); + pmessage(buf, -1, MALL, UMPIRE); + } + } +} +#endif + +/*---------------------------------MOVE-----------------------------------*/ +/* + * This is the main loop for the program. It is called every 1/10th of a + * second. It decides which functions of the deamon need to be run. + */ + +void +move() +{ + static int oldtourn = 0; /* are we in t-mode or not */ + int i, j; /* looping vars */ + struct planet *pl; + + if (++ticks == dietime) + { /* no player for 1 minute. kill self */ + if (debug) /* do not quit if debug mode */ + fprintf(stderr, "Ho hum. 1 minute, no activity...\n"); + else + { /* quit if not debug mode */ + fprintf(stderr, "Self-destructing the daemon!\n"); + freemem(0); + } + } + + if ((FUSE(300)) && update_sys_defaults()) /* check to load system + * defualts */ + /* This message tells players that new defaults have been */ + /* loaded and the message triggers the ntserv processes */ + /* to check new defaults. */ + pmessage("Loading new server configuration.", 0, MALL, MSERVA); + + if (FUSE(SECONDS(1))) + { + if (tournamentMode()) + { /* are we in tournament mode */ + if (!oldtourn) + { /* is this a new condition */ + if (!status2->starttourn) + { /* fresh t-mode */ + if (configvals->gamestartnuke) + explode_everyone(KTOURNSTART, 20); + } + status2->starttourn = configvals->nottimeout ? configvals->nottimeout : -1; + warmessage(); /* go print war message */ + for (i = 0, pl = &planets[i]; i < NUMPLANETS; i++, pl++) + for (j = 0; j < MAXTEAM + 1; j++) + pl->pl_tinfo[j].timestamp = 0; + status->clock = 0; + tourntimestamp = ticks; /* take a timestamp */ + } + oldtourn = 1; /* record that we have printed warmsg */ + status->tourn = 1; /* set the game status to t-mode */ + status->time++; /* inc time in t-mode */ + } + else + { /* else we are not in t-mode */ + if (oldtourn) + { /* if previously in t-mode */ + tourntimestamp = ticks; /* record t-mode ending */ + peacemessage(); /* send peace message */ + } + else + { + static fuse = 0; + fuse++; + if (fuse > 60 && status2->starttourn > 0) + { + fuse = 0; + status2->starttourn--; + switch (status2->starttourn) + { + case 0: + status2->newgalaxy = 1; + break; + case 1: + case 3: + case 5: + case 15: + { + static char buf[120]; + sprintf(buf, "Warning!! Galaxy will be reset in %d minute%s due to inactivity.", status2->starttourn, (status2->starttourn == 1) ? "" : "s"); + pmessage(buf, 0, MALL, MSERVA); + } + break; + pmessage("Warning!! Galaxy will be reset in one minute due to inactivity.", 0, MALL, MSERVA); + break; + } + } + } + oldtourn = 0; /* set we are not in t-mode */ + status->tourn = 0; /* record in stats */ + } + } + +#if 0 + if (status->nukegame) + { /* if daemon should die then */ + freemem(0); /* nuke shared memory */ + exit(0); /* kill daemon */ + } +#endif + + parse_godmessages(); /* log any messages to god */ + +#ifdef LEAGUE_SUPPORT + handle_pause_goop(); /* print any messages related to pausing the + * game */ +#endif + +#ifdef LEAGUE_SUPPORT + if (!status2->paused) +#endif + { + if (FUSE(PLAYERFUSE)) /* time to update players? */ + udplayers(); + + if (FUSE(TORPFUSE)) /* time to update torps? */ + udtorps(); + if (FUSE(MISSILEFUSE)) /* time to update missiles? */ + udmissiles(); + if (FUSE(PLASMAFUSE)) /* time to update plasma? */ + udplasmatorps(); + if (FUSE(PHASERFUSE)) /* time to update phasers? */ + udphaser(); + + + if (FUSE(CLOAKFUSE)) /* time to update cloaking? */ + udcloak(); + + if (FUSE(TEAMFUSE)) /* time to update team timers? */ + teamtimers(); + + if (FUSE(PLFIGHTFUSE)) /* time to update planets? */ + plfight(); + + if (FUSE(TERRAINFUSE)) /* time to do terrain effects? */ + doTerrainEffects(); + + if (FUSE(BEAMFUSE)) /* time to update beaming */ + beam(); + + if (FUSE(SYNCFUSE)) /* time to save planets? */ + save_planets(); + + + if (FUSE(topgun ? HOSEFUSE2 : HOSEFUSE) +#if !defined(AEDILE) || !defined(IGGY_IN_T) + && status->tourn != 1 /* no Iggy during T-mode */ +#endif +#ifdef LEAGUE_SUPPORT + && status2->league == 0 +#endif + ) /* no Iggy during league games */ + rescue(HUNTERKILLER, 0, -1); /* send in iggy-- no team, no target */ + + if (status->tourn) + { + { + static int spinner = 0; + + for (spinner += configvals->popspeed; spinner >= 100; spinner -= 100) + popplanets(); /* increase population */ + } + + if (FUSE(PLANETFUSE)) /* time to grow resources */ + growplanets(); + + { + /* + * check for revolts. Each planet is checked on average once every + * PLANETFUSE. + */ + static int spinner = 0; + for (spinner += configvals->numplanets; + spinner >= PLANETFUSE; + spinner -= PLANETFUSE) + { + check_revolt(); + } + } + } + /* planet moving */ + if (configvals->planupdspd > 0 && FUSE(4)) + moveplanets(); + + if (FUSE(MINUTEFUSE) && status->tourn) + { + + shipbuild_timers(); + +#ifdef LEAGUE_SUPPORT + if (!status2->league) +#endif + udsurrend(); /* update surrender every minute unless + * playing league */ + + status->clock++; /* increment the timestamp clock */ + + } + /* update the tournament clock, maybe print messages */ +#ifdef LEAGUE_SUPPORT + udtourny(); +#endif + } /* end if !paused */ + + if (FUSE(MINUTEFUSE)) + { + int i, c; + c = 0; + for (i = 0; i < MAXPLAYER; i++) + { + if (players[i].p_status != PFREE) + c++; + } +#ifdef COUNTFILENAME + if (c) + { + char *paths; + FILE *logfile; + paths = build_path(COUNTFILENAME); + logfile = fopen(paths, "a"); + if (logfile) + { + struct tm *tp; + char buf[50]; + time_t cal; + + cal = time(0); + tp = localtime(&cal); + strftime(buf, 50, "%m/%d %H:%M", tp); + + fprintf(logfile, "%s : %2d ", buf, c); + for (i = 0; i < c; i++) + { + putc('*', logfile); + } + putc('\n', logfile); + fclose(logfile); + } + } +#else +#ifdef UFL + { + char *paths; + FILE *logfile; + paths = build_path(LOGFILENAME); + logfile = fopen(paths, "a"); + if (logfile) + { + fprintf(logfile, "Count: %d players\n", c); + fclose(logfile); + } + } +#endif +#endif + } + +#if 0 + /* well, this may cause blocked pipes if too many */ + /* processes, the file said before I hacked it. */ + /* So this is disabled. */ + if (FUSE(CHECKLOADFUSE)) /* time to check load? */ + check_load(); +#endif + + + if (status2->newgalaxy) + { + + /* Disable the game timer. It'll be set again after the longjmp() */ + stoptimer(); + + status2->nontteamlock = ALLTEAM; /* allow all teams again */ + status2->starttourn = 0; /* fresh galaxy */ + + gen_planets(); + + for (i = 0; i < MAXPLAYER; i++) + { + galaxyValid[i] = 0; /* force download of new galaxy map */ + } + longjmp(env, 0); + } +} + + +sig_ret_t +freemem(sig) + int sig; +{ + register int i; + register struct player *j; + + if (sig) + { + fprintf(stderr, "Daemon: Caught signal %d\n", sig); + /* U_STACK_TRACE(); */ + } + + /* Blow players out of the game */ + for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) + { + j->p_status = POUTFIT; + j->p_whydead = KDAEMON; + j->p_ntorp = 0; + j->p_nplasmatorp = 0; + j->p_explode = 600 / PLAYERFUSE; /* ghost buster was leaving players + * in */ + } + /* Kill waiting players */ + status->gameup = 0; /* say goodbye to xsg et. al. 4/10/92 TC */ + status->count = 0; + save_planets(); + sleep(2); + blast_shmem(); + exit(0); +} + + +void +check_load() +{ +#ifndef hpux /* breaks under hpux... it's fixable, though */ + FILE *fp, *popen(); + char buf[100]; + char *s; + float load; + +#if defined(SYSV) || defined(Linux) || defined(FreeBSD) +#if defined(sgi) + fp = popen("/usr/bsd/uptime", "r"); /* sigh. */ +#else + fp = popen("/usr/bin/uptime", "r"); +#endif +#else + fp = popen("/usr/ucb/uptime", "r"); +#endif + if (fp == NULL) + { + /* status->gameup=0; */ + return; + } + fgets(buf, 99, fp); + s = strrchr(buf, ':'); + if (s == NULL) + { + /* status->gameup=0; */ + pclose(fp); + return; + } + if (sscanf(s + 1, " %f", &load) == 1) + { + sprintf(buf, "NetrekII (Paradise), %s", PARAVERS); + pmessage(buf, 0, MALL, MSERVA); + if (load >= configvals->maxload && status->gameup == 1) + { + status->gameup = 0; + sprintf(buf, "The load is %f, this game is going down", load); + pmessage(buf, 0, MALL, MSERVA); + } + else if (load < configvals->maxload && status->gameup == 0) + { + status->gameup = 1; + sprintf(buf, "The load is %f, this game is coming up", load); + pmessage(buf, 0, MALL, MSERVA); + } + else + { + sprintf(buf, "Load check: %-7.2f", load); + buf[strlen(buf) - 1] = '\0'; + pmessage(buf, 0, MALL, MSERVA); + } + } + else + { + /* status->gameup=0; */ + } + r_signal(SIGCHLD, SIG_DFL); + pclose(fp); + r_signal(SIGCHLD, reaper); +#endif +} + +void +ghostmess(victim) + struct player *victim; +{ + char buf[80]; + static float ghostkills = 0.0; + int i, k; + + ghostkills += 1.0 + victim->p_armies * 0.1 + victim->p_kills * 0.1; + sprintf(buf, "%s (%s) was kill %0.2f for the GhostBusters", + victim->p_name, twoletters(victim), + ghostkills); + pmessage(buf, 0, MALL, MSERVA); +#if 1 + if (victim->p_armies > 0) + { + k = 10 * (remap[victim->p_team] - 1); + if (k >= 0 && k <= 30) + for (i = 0; i < 10; i++) + { + if (planets[i + k].pl_owner == victim->p_team) + { + planets[i + k].pl_armies += victim->p_armies; + sprintf(buf, "%s's %d armies placed on %s", + victim->p_name, victim->p_armies, planets[k + i].pl_name); + pmessage(buf, 0, MALL | MGHOST, MSERVA); + break; + } + } + } +#else + if (victim->p_armies > 0) + PlaceLostArmies(victim); /* not working yet */ +#endif +} + +void +saveplayer(victim) + struct player *victim; +{ + int fd; + char *paths; + + if (victim->p_pos < 0) + return; + if (victim->p_stats.st_lastlogin == 0) + return; +#ifndef ROBOTSTATS + if (victim->p_flags & PFROBOT) + return; +#endif + + paths = build_path(PLAYERFILE); + fd = open(paths, O_WRONLY, 0644); + if (fd >= 0) + { + lseek(fd, 32 + victim->p_pos * sizeof(struct statentry), 0); + write(fd, (char *) &victim->p_stats, sizeof(struct stats)); + close(fd); + } +} + + +/* Send in a robot to avenge the aggrieved team */ +/* -1 for HK, -2 for Terminator, -3 for sticky Terminator */ + +/* if team in { FED, ROM, KLI, ORI }, a nonzero target means "fleet" mode */ +/* CRD feature: number (or -1) for starting planet - MAK, 2-Jun-93 */ + +void +rescue(team, target, planet) + int team; + int target; + int planet; +{ + char *arg1, argp[5]; + int pid; + char *paths; /* added 1/18/93 KAO */ + +#ifdef LEAGUE_SUPPORT + if (status2->league) + return; /* no robots during league play */ +#endif + + sprintf(argp, "-S%d", planet); + + if ((pid = fork()) == 0) + { + /* underscore is just a place holder */ + static char termbuf[] = "-Tt_"; + if (!debug) + { + close(0); + close(1); + close(2); + } + r_signal(SIGALRM, SIG_DFL); + paths = build_path(ROBOT); + switch (team) + { + case FED: + arg1 = "-Tf"; + break; + case ROM: + arg1 = "-Tr"; + break; + case KLI: + arg1 = "-Tk"; + break; + case ORI: + arg1 = "-To"; + break; + case HUNTERKILLER: + arg1 = "-Ti"; /* -1 means independent robot */ + if (!debug) + { + execl(paths, "robot", arg1, "-P", argp, 0); + } + else + { + execl(paths, "robot", arg1, "-P", argp, "-d", 0); + } + break; + case TERMINATOR: /* Terminator */ + arg1 = termbuf; + arg1[3] = twoletters(&players[target])[1]; + break; + case STERMINATOR: /* sticky Terminator */ + arg1 = termbuf; + arg1[3] = twoletters(&players[target])[1]; + if (!debug) + execl(paths, "robot", arg1, "-s", argp, 0); + else + execl(paths, "robot", arg1, "-s", argp, "-d", 0); + break; + default: + arg1 = "-Ti"; + break; + } + if (target > 0) /* be fleet 8/28/91 TC */ + execl(paths, "robot", arg1, "-f", argp, 0); + else if (!debug) + { /* Make these fleet, too - MAK, 4-Jun-93 */ + execl(paths, "snake", arg1, argp, 0); + /* execl (paths, "robot", arg1, "-f", argp, 0); */ + } + else + { /* Make these fleet, too - MAK, 4-Jun-93 */ + execl(paths, "snake", arg1, argp, "-d", 0); + /* execl (paths, "snake", arg1, "-f", argp, "-d", 0); */ + } + /* If we get here, we are hosed anyway */ + fprintf(stderr, "Failed to exec robot %s.\n", paths); + exit(1); + } + else + { + if (debug) + { + fprintf(stderr, "Forking robot: pid is %d\n", pid); + } + } +} + +#include <sys/resource.h> + +/* ARGSUSED */ + +/* Don't fear the ... */ + +sig_ret_t +reaper(sig) +{ + static int status; + static int pid; + +#ifndef SVR4 + while ((pid = wait3((union wait *) & status, WNOHANG, (struct rusage *) 0)) > 0) + { +#else /* note: no status info */ + while ((pid = waitpid(0, 0, WNOHANG)) > 0) + { +#endif /* SVR4 */ + if (debug) + { + fprintf(stderr, "Reaping: pid is %d (status: %X)\n", + pid, status); + } + } +} + +unsigned char +getcourse(x, y, xme, yme) + int x, y, xme, yme; +{ + return ((unsigned char) (int) (atan2((double) (x - xme), + (double) (yme - y)) / 3.14159 * 128.)); +} + +int tm_robots[MAXTEAM + 1]; /* To limit the number of robots */ + +void +teamtimers() +{ + register int i; + for (i = 0; i <= MAXTEAM; i++) + { + if (tm_robots[i] > 0) + tm_robots[i]--; + } +} + +void +shipbuild_timers() +{ + int i, t; + + for (i = 0; i <= MAXTEAM; i++)/* go through all teams */ + for (t = 0; t < NUM_TYPES; t++) /* and each ship type */ + if (teams[i].s_turns[t] > 0) /* and if need be, then dec */ + teams[i].s_turns[t]--; /* the construction timer */ +} + + +#undef D