|
|
researchv10 Norman
/* atc: simulate an air traffic controller at work */
#define NRAND 1
#define die nrand
#include <stdio.h>
#include <sys/ttyio.h>
#include <sys/param.h>
#include <sys/timeb.h>
#include <ctype.h>
#include <signal.h>
#include <pwd.h>
#include "ahdr.h"
#define SYNTAX "Usage: atc [-s=<seed>] [-a=<airspace>] [-t=<time>]\n"
/* size of terminal capability buffer */
#define TCSIZE 1024
int cmdx; /* command located using same cursor positioning as screen */
int cmdy; /* usually will be at 24 lines down */
char screen[MAXWIDTH][MAXHEIGHT]; /* contents of screen when no planes */
char *flowfile = 0; /* no default flow patterns */
char *airfile = AIRFILE;
char *airspace = {"Apple1"}; /* default airspace is as on Apple */
char *protofile = 0; /* no default protocol file */
FILE *proto; /* stays open all the time if protocol */
char *moviefile = 0; /* if in movie mode, here's the file */
FILE *movie; /* and the file descriptor */
int nextmovie; /* next time for a moviefile command */
char *mcommand; /* next movie command */
int width,height; /* these values set in the airspace file */
char *bigname = 0; /* megastatistics file */
FILE *bigstatsfile; /* megastatistics stream */
struct flow fpath[MAXPATHS];
int maxflow;
int npaths;
int nentry = 0; /* number of entries into the board */
struct pstruct entry[EMAX];
int nairport = 0;
struct pstruct airport[AMAX];
int nnavaid = 0;
struct pstruct navaid[NMAX];
int nplanes = PMAX;
struct astruct plane[PMAX];
int initseed,seed,game_time,initgame_time,last_update;
time_t start_time; /* real time in seconds that game started */
time_t get_time();
struct passwd *getpwuid();
FILE *popen();
#define BUFSIZE 80 /* buffer for message */
int remain;
int bound = 0; /* number of boundary errors */
int system = 0; /* system errors */
int crash = 0; /* crashed - out of fuel */
int fuel = 0; /* out of fuel on runway - tow truck */
int goaround = 0; /* missed an approach */
int icmds = 0; /* number of cmds issued (including deferred) */
int cmds = 0; /* number of cmds actually executed */
int fuelused = 0;
int inaptot=0,outaptot=0; /* denominators for random entries/exits */
int inawtot=0,outawtot=0; /* for airports and airways */
char tcbuf[TCSIZE];
char cmbuf[100]; /* buffer for cursor motion strings */
char clbuf[100]; /* clear screen sequence */
int rubout = 0;
catchint(n)
int n;
{
rubout = 1;
signal (n, catchint);
}
struct sgttyb tty_setting;
short tty_flags;
main(argc,argv)
int argc;
char **argv;
{ register char *arg;
char *ttype;
char *getenv();
ttype = getenv("TERM");
if (ttype == NULL || *ttype == '\0' || tgetent (tcbuf, ttype) <= 0) {
fprintf (stderr, "cannot determine terminal type\n");
exit (1);
}
/* get cursor motion and clear screen code into cmbuf and clbuf */
{
char *p;
p = cmbuf;
tgetstr ("cm", &p);
p = clbuf;
tgetstr ("cl", &p);
}
ioctl(0, TIOCGETP, &tty_setting);
tty_flags = tty_setting.sg_flags;
seed = 0;
for (arg = *++argv; --argc; arg = *++argv) /* read args 1 at a time */
{ if (arg[0] == '-')
switch(arg[1])
{ case 's':
if (arg[2] != '=') err(SYNTAX);
seed = atoi(&arg[3]);
break;
case 'S':
if (arg[2] != '=') err(SYNTAX);
bigname = &arg[3];
break;
case 'a':
if (arg[2] != '=') err(SYNTAX);
airspace = &arg[3];
break;
case 'u':
if (arg[2] != '=') err(SYNTAX);
airfile = &arg[3];
break;
case 't':
if (arg[2] != '=') err(SYNTAX);
initgame_time = game_time = 59 + 60 * atoi(&arg[3]);
break;
case 'f':
if (arg[2] != '=') err(SYNTAX);
flowfile = &arg[3];
break;
case 'p': /* run a protocol */
if (arg[2] != '=') err(SYNTAX);
protofile = &arg[3];
break;
case 'm': /* movie mode */
if (arg[2] != '=') err(SYNTAX);
moviefile = &arg[3];
break;
default :
err("Bad arg: %s\n",arg);
}
}
init(); /* set up flight plans, initialize screen */
while (command()); /* get commands from user */
done(1);
exit(0);
}
#define CMDSIZE 40
int inter; /* non-zero if an alarm went off */
intp() /* process interrupt from alarm */
{ inter++;
}
command()
{ time_t now;
char cmd[CMDSIZE];
char *c,utype,*d;
int i,j;
for (utype = i = *(c=cmd) = 0; utype != RETURN; )
{
if (moviefile) game_time--; /* 1 sec at a time? */
else
{ now = get_time();
game_time = initgame_time - (now - start_time);
}
if (remain == 0) return(0);
if (game_time < 0)
{ report(OUTOFTIME,0,0);
return(0);
}
if (i == 0) /* preserve partial command */
{ cursor(cmdx,cmdy);
printf("<%.2d> COMMAND: ",game_time/60);
}
if (last_update - game_time >= UPDATE)
{ update();
if (c != cmd) {BEEP;} /* cmd may be obsolete */
}
while (moviefile && game_time <= nextmovie)
{ if (bigname) pcmd(bigstatsfile,mcommand);
if (protofile) pcmd(proto,mcommand);
i = parse(mcommand);
if (!i) return i;
getmcmd();
}
if (moviefile) continue; /* no longer accept inputs */
cursor(cmdx+7,cmdy);
for (j=0; j<i; j++) putchar(cmd[j]);
signal(SIGALRM,intp);/* catch the alarm if it goes off */
inter = 0; /* set to >0 if the alarm goes off */
if (rubout) return 0; /* user really wants to quit */
alarm(TIMEOUT); /* read for TIMEOUT sec unless he types */
utype = getchar() & 0177;
alarm(0);
if (inter > 0) continue; /* didn't type anything */
delmsg(cmdx,cmdy-1); /* erase previous echo if he types */
cursor(cmdx+7,cmdy);
if (i != 2 || (*(c-1) != '*' && *(c-1) != ':'))
if (*cmd != '!' || i == 0) /* don't shift CDL filename */
if (*cmd != '@'|| i == 0) /* don't shift location descrip */
if (utype >= 'a' && utype <= 'z')
utype = utype - 'a' + 'A';
if (utype == INSMODE) utype = RETURN;
if ((*c++ = utype) != RETURN)
{ if (++i >= CMDSIZE) c--;
else
switch(utype) /* echo something reasonable */
{
#ifdef ANNARBOR
case MIPAGE:/* check cursor controls */
putchar(*--c = 'N');
putchar(*++c = 'W');
c++; i++;
break;
case HOME:
putchar(*--c = 'N');
c++;
break;
case PLPAGE:
putchar(*--c = 'N');
putchar(*++c = 'E');
c++; i++;
break;
case MISRCH:
putchar(*--c = 'W');
c++;
break;
case UPARROW:
putchar(*--c = '0');
c++;
break;
case PLSRCH:
putchar(*--c = 'E');
c++;
break;
case LEFTARROW:
putchar(*--c = 'S');
putchar(*++c = 'W');
c++; i++;
break;
case DOWNARROW:
putchar(*--c = 'S');
c++;
break;
case RIGHTARROW:
putchar(*--c = 'S');
putchar(*++c = 'E');
c++; i++;
break;
case ':': /* like a * */
putchar('*');
break;
#endif
case BS:
if (i<=0) break;
if (i==1) { i = 0; break; }
putchar(BS);
c--; c--; i--; i--;
break;
default: putchar(utype); break;
}
}
}
*c = 0;
if (bigname) pcmd(bigstatsfile,cmd);
if (protofile) pcmd(proto,cmd);
return(parse(cmd));
}
pcmd(file,cmd) /* protocol a command */
FILE *file;
char *cmd;
{ register char *s;
if (file == proto)
fprintf(file,"%5d: ",game_time);
else fprintf(file,"%5d: ",initgame_time - game_time);
for (s = cmd; *s && *s != RETURN; s++) fputc(*s,file);
fputc('\n',file);
}
parse(cmd) /* command is terminated by RETURN */
register char *cmd;
{ time_t now;
register int i;
register struct astruct *pl;
char dest;
char *fullcmd;
char ubuf[10];
fullcmd = cmd;
switch(*cmd) /* parse 1 letter at a time */
{ case ' ': /* time advance */
sprintf (ubuf, "%d", UPDATE);
echo("%s\" - ROGER",ubuf);
now = get_time();
start_time = last_update - UPDATE - 1 - initgame_time + now;
break;
case '$':
return(0);
case '!': /* read a file of clearance directive lists */
readcdl(++cmd);
break;
case '@': /* get a monitoring command */
getmon(++cmd);
break;
default: /* should be airplane id */
/* ASSUMPTION HERE: aircraft are A-Z */
if (*cmd < 'A' || *cmd > 'Z')
{ echo("%s - UNABLE",fullcmd);
BEEP;
break;
}
for (pl = &plane[i=0]; i < nplanes; i++,pl++)
if (pl->a_id == *cmd) break;
if (i == nplanes)
{ echo("%s - NOT ACTIVE",fullcmd);
BEEP;
break;
}
if (cmd[1] == '?') /* o.k. to cancel plans */
{ if (pl->a_active != ACTIVE &&
pl->a_active != WAITING)
{ echo("%s - NOT ACTIVE",fullcmd);
BEEP;
break;
}
}
else if (cmd[1] == RETURN) /* info request only */
{ if (pl->a_active != ACTIVE &&
pl->a_active != APPROACHING &&
pl->a_active != WAITING)
{ echo("%s - NOT ACTIVE",fullcmd);
BEEP;
break;
}
}
else
{ if (pl->a_active != ACTIVE && pl->a_active != WAITING)
{ echo("%s - NOT ACTIVE",fullcmd);
BEEP;
break;
}
if (pl->a_active==ACTIVE && pl->a_nextz == 0 && cmd[1]!=RETURN)
{ echo("%s - LANDING",fullcmd);
BEEP;
break;
}
}
switch(*++cmd) /* parse second char */
{ case RETURN: /* info request */
strip(pl,cmdy+1,VERBOSE);
break;
case 'A': /* change altitude */
if (*++cmd < '0' || *cmd > '5')
{ echo("%s - UNABLE",fullcmd);
BEEP;
}
else
{ pl->a_nextz = *cmd - '0';
echo("%s - ROGER",fullcmd);
cmds++;
icmds++;
}
break;
case 'H': /* hold at beacon */
pl->a_hold = 1;
pl->a_clear = 0;
echo("%s - ROGER",fullcmd);
cmds++;
icmds++;
break;
case 'L': /* left turn */
rdturn(pl,'L',++cmd,fullcmd);
break;
case 'R': /* right turn */
rdturn(pl,'R',++cmd,fullcmd);
break;
case 'T': /* shortest turn */
rdturn(pl,'T',++cmd,fullcmd);
break;
case '*': /* clearance at navaid */
case ':':
dest = *++cmd;
for (i=0; i<nentry; i++) /* vector to entry? */
if (dest == entry[i].p_sym) break;
if (pl->a_hold == 1) pl->a_hold = 0;
if (i<nentry)
{ echo("%s - ROGER",fullcmd);
pl->a_clear = dest;
cmds++;
icmds++;
break;
}
for (i=0; i<nairport; i++)
if (dest == airport[i].p_sym) break;
if (i<nairport)
{ echo("%s - ROGER",fullcmd);
pl->a_clear = dest;
cmds++;
icmds++;
break;
}
echo("%s - UNABLE",fullcmd);
BEEP;
break;
case '?': /* delete delayed commands */
ddelay(pl);
echo("%s - ROGER",fullcmd);
cmds++;
icmds++;
break;
default: /* airport id? - maybe cursor motions? */
echo("%s - UNABLE",fullcmd);
BEEP;
break;
}
}
return(1);
}
getmon(cmd) /* get monitor command from command line */
register char *cmd;
{ int x,y;
register char *start;
start = cmd;
if (getloc(cmd,&x,&y) == 0) /* where did you say? */
{ echo("%s - BAD LOC SPEC",cmd);
BEEP;
return;
}
while (*cmd) /* pick up each command that happens here */
{ while (*cmd && *cmd != ',') cmd++;
if (*cmd == 0) return; /* read last command */
putlist(start,x,y,++cmd); /* put the next command on a list */
}
}
ddelay(pl) /* delete any delayed commands from this plane's list */
struct astruct *pl;
{ struct list *l,*next;
if (pl->a_plan == 0) return;
for (l = pl->a_plan; l; l = next)
{ next = l->l_next;
free(l);
}
pl->a_plan = 0;
}
putlist(start,x,y,cmd) /* put some commands on the list for a plane */
char *start;
int x,y;
char *cmd;
{ register struct list *l;
register struct astruct *p;
register char *c,*d;
int i;
d = cmd;
for (i = 0; cmd[i] != ',' && cmd[i] != 0 && cmd[i] != RETURN; i++)
if (i != 2 || (cmd[i-1] != '*' && cmd[i-1] != ':'))
if (cmd[i] >= 'a' && cmd[i] <= 'z') cmd[i] += 'A' - 'a';
for (p = &plane[i = 0]; i < nplanes; i++,p++)
if (p->a_id == *cmd) break;
if (i == nplanes)
{ echo("BAD PLANE SPEC: %s",cmd);
BEEP;
return;
}
l = p->a_plan; /* go to the CDL for this plane */
if (p->a_plan == 0)
l = p->a_plan = (struct list *) malloc(sizeof (struct list));
else
{ for (l = p->a_plan; l->l_next != 0; l = l->l_next); /* eol */
l->l_next = (struct list *) malloc(sizeof (struct list));
l = l->l_next;
}
l->l_next = 0;
l->l_x = x;
l->l_y = y;
c = l->l_cmd;
while (*cmd != ',' && *cmd != 0 && *cmd != RETURN)
*c++ = *cmd++;
*c++ = RETURN;
*c = 0;
for (c = d; *c; c++) if (*c == RETURN) *c = 0; /* return damages dspla*/
echo("%s - WILCO",d);
icmds++;
/* copy the verbatim direction used by the guy */
for (c = start, d = l->l_loc; *c != ','; *d++ = *c++);
*d = 0;
}
getloc(cmd,px,py) /* get location description from a monitor command */
char *cmd;
int *px,*py;
{ register char l,*m; /* location */
register int i;
register struct pstruct *p;
int dx,dy;
char buf[300];
l = *(m = cmd);
p = 0;
for (i = 0; i < nentry; i++)
if (entry[i].p_sym == l) p = &entry[i];
for (i = 0; i < nairport; i++)
if (airport[i].p_sym == l) p = &airport[i];
for (i = 0; i < nnavaid; i++)
if (navaid[i].p_sym == l) p = &navaid[i];
if (p == 0) return 0;
*px = p->p_x;
*py = p->p_y;
m++;
while (*m != ',') /* read through the other directions */
{ dx = dy = 0;
switch(*m) /* NSEW */
{ case 'n': dy = -1; break;
case 's': dy = 1; break;
case 'e': dx = 1; break;
case 'w': dx = -1; break;
default:
sprintf(buf,"Got %c instead of n,s,e,w",*m);
msg(cmdx,cmdy+3,buf);
return 0;
}
if (*++m == 'w') { dx = -1; m++;} /* NW or SW */
else if (*m == 'e') { dx = 1; m++;} /* NE or SE */
if (*m < '0' || *m > '9')
{ sprintf(buf,"Got %c instead of digit",*m);
msg(cmdx,cmdy+3,buf);
return 0;
}
for (i = 0; *m >= '0' && *m <= '9'; m++)
i = 10 * i + *m - '0';
*px += i * dx;
*py += i * dy;
}
return 1;
}
readcdl(fname) /* fname points at CDL filename, \r-terminated */
char *fname;
{ FILE *cdlfile;
char *p;
while (*fname == ' ') fname++; /* skip initial blanks */
for (p = fname; *p && *p != RETURN; p++); /* remove newline */
*p = 0;
if ((cdlfile = fopen(fname,"r")) == NULL)
{ echo("Cannot open %s",fname);
return;
}
echo("Reading CDL file...",0);
fclose(cdlfile);
}
rdturn(pl,dir,cmd,fullcmd)
struct astruct *pl;
char dir;
char *cmd,*fullcmd;
{ int i,ok,newx,newy,turncount;
if (pl->a_nextz == 0)
{ echo("%s - WRONG WAY",fullcmd);
BEEP;
return;
}
ok = 1; /* check whether this is a legal command */
newx = newy = 0;
for (i=0; i<2; i++) /* look at next 2 chars */
switch(cmd[i])
{ case RETURN:
if (i == 0)
{ echo("%s - WHICH WAY?",fullcmd);
BEEP;
return;
}
break;
case '0':
if (i == 1) /* can't be second char */
{ ok = 0;
break;
}
pl->a_dxnew = 0;
pl->a_dynew = 0;
pl->a_turn = 0;
pl->a_clear = 0;
pl->a_hold = 0;
echo("%s - ROGER",fullcmd);
cmds++;
icmds++;
return;
case 'N':
newy = -1;
break;
case 'S':
newy = 1;
break;
case 'E':
newx = 1;
break;
case 'W':
newx = -1;
break;
default: /* numbers (e.g.) no longer acceptable */
ok = 0;
break;
}
if (ok)
{ echo("%s - ROGER",fullcmd);
cmds++;
icmds++;
pl->a_turn = dir; /* will replace 'T' with 'L' or 'R' */
pl->a_dxnew = newx; pl->a_dynew = newy;
pl->a_hold = pl->a_clear = 0;
if (dir == 'T')
{ newx = pl->a_dx; /* start with this direction */
newy = pl->a_dy; /* and turn until done */
for (turncount = 1; turncount < 9; turncount++)
if (turn(&newx,&newy,'L',pl->a_dxnew,pl->a_dynew))
break;
if (turncount <= 4) pl->a_turn = 'L';
else pl->a_turn = 'R';
}
}
else
{ echo("%s - UNABLE",fullcmd);
BEEP;
}
}
echo(format,cmd)
char *format,*cmd;
{ char *c;
char mbuf[BUFSIZE];
for (c=cmd; *c; c++) if (*c == RETURN) *c = 0;
sprintf(mbuf,format,cmd);
msg(cmdx,cmdy-1,mbuf);
}
int parity = 0; /* props move every other update */
update()
{ parity = 1 - parity;
last_update -= UPDATE; /* must average out to every UPDATE secs */
moveplanes();
printplans();
if (bigname) activity();
}
activity() /* number of active planes to megastats file */
{ register int i,active,waiting,approaching,planned;
struct astruct *p;
for (i=active=waiting=approaching=planned=0; i < nplanes; i++)
{ p = &plane[i];
switch(p->a_active)
{ case ACTIVE:
active++;
break;
case WAITING:
waiting++;
break;
case APPROACHING:
approaching++;
break;
}
if (p->a_plan && p->a_active != DONE) planned++;
}
fprintf(bigstatsfile,"%5d: %d active, %d approaching, %d waiting. ",
initgame_time - game_time, active,approaching,waiting);
fprintf(bigstatsfile,"%d planned.\n",planned);
for (i = 0; i < nplanes; i++)
{ int a;
p = &plane[i];
a = p->a_active;
if (a == ACTIVE || a == APPROACHING || a == WAITING)
{ p->a_load += active;
p->a_ticks++;
p->a_planned += planned;
}
if (a == APPROACHING || a == WAITING)
{ p->a_aprev += active;
p->a_prev++;
p->a_pprev += planned;
p->a_pplanned = (p->a_plan? YES : NO);
}
}
}
moveplanes()
{ register struct astruct *pl;
register int i,j;
register int nextx,nexty;
int ax,ay,oldx,oldy;
struct pstruct *dst;
for (pl = &plane[i = 0]; i < PMAX; i++, pl++)
{ if (parity && pl->a_type == PROP)
{ pl->a_lastz = pl->a_z;
if (pl->a_active == LANDING) pl->a_active = DONE;
continue;
}
switch(pl->a_active)
{ case INACTIVE:
if (initgame_time - game_time + FPTHRESH>= pl->a_stime
&& !pl->a_sair)
pl->a_active = APPROACHING;
case APPROACHING:
if (initgame_time - game_time>= pl->a_stime)
{ pl->a_active = ACTIVE;
if (pl->a_sair) pl->a_active = WAITING;
nextx = pl->a_x;
nexty = pl->a_y;
}
break;
case LANDING: /* to allow for conflicts */
pl->a_active = DONE;
break;
case ACTIVE:
pl->a_dist++; /* increment distance traveled */
nextx = pl->a_x + pl->a_dx;
nexty = pl->a_y + pl->a_dy;
if (nextx < 0 || nexty < 0 ||
nextx >= width || nexty >= height)
{ leavescreen(pl);
break;
}
/* turning? */
if (pl->a_turn) /* turn 1 tick in right direction */
if (turn(&pl->a_dx,&pl->a_dy,
pl->a_turn,pl->a_dxnew,pl->a_dynew))
pl->a_turn = pl->a_dxnew = pl->a_dynew = 0;
if (pl->a_dair) /* landing? */
{ dst = &airport[pl->a_dest];
ax = dst->p_x;
ay = dst->p_y;
if (ax == nextx && ay == nexty)
if (pl->a_z == 0 &&
pl->a_dx == dst->p_dx &&
pl->a_dy == dst->p_dy)
{ pl->a_active = LANDING; /* landed */
erase(pl->a_x,pl->a_y);
pl->a_x = nextx;
pl->a_y = nexty;
remain--;
}
else if (pl->a_nextz == 0) /* flyby */
{ pl->a_nextz = 1; /* down too late*/
goaround++;
report(GOAROUND,pl);
}
}
/* changing altitude? */
if (pl->a_z > pl->a_nextz)
pl->a_lastz = pl->a_z--;
else if (pl->a_z < pl->a_nextz)
pl->a_lastz = pl->a_z++;
else pl->a_lastz = pl->a_z;
/* out of fuel? */
if (--pl->a_fuel <= 0)
{ crash++;
report(CRASH,pl);
pl->a_active = DONE;
remain--;
erase(pl->a_x,pl->a_y);
}
if (pl->a_type == JET) fuelused += 5;
else fuelused += 1;
break;
case WAITING: /* waiting for takeoff */
if (--pl->a_fuel <= 0) /* out of fuel on ground? */
{ fuel++;
if (bigname) freport(pl);
report(FUEL,pl);
pl->a_active = DONE;
remain--;
}
if (pl->a_nextz != 0)
{ pl->a_z++; /* take off */
pl->a_active = ACTIVE;
pl->a_dist++;
}
nextx = pl->a_x + pl->a_dx;
nexty = pl->a_y + pl->a_dy;
/* turning? */
if (pl->a_turn) /* turn 1 tick in right direction */
if (turn(&pl->a_dx,&pl->a_dy,
pl->a_turn,pl->a_dxnew,pl->a_dynew))
pl->a_turn = pl->a_dxnew = pl->a_dynew = 0;
if (pl->a_type == JET) fuelused += 5;
else fuelused += 1;
break;
case DONE: /* off the screen */
break;
}
if (pl->a_active != ACTIVE) continue;
oldx = pl->a_x;
oldy = pl->a_y;
pl->a_x = nextx;
pl->a_y = nexty;
cursor(nextx,nexty);
printf("%c%c",pl->a_id,(pl->a_z>9? '^' : pl->a_z+'0'));
erase(oldx,oldy);
if (pl->a_hold || pl->a_clear)
for (j = 0; j < nnavaid; j++) /* at a navaid? */
if (screen[nextx][nexty] == navaid[j].p_sym)
{ donavaid(pl); /* right navaid? */
break;
}
}
conflict();
delays(); /* execute any applicable delayed commands */
}
freport(pl) /* report to big stats file about tow truck */
struct astruct *pl;
{
fprintf(bigstatsfile,"%5d: %c out of fuel on runway.\n",
initgame_time - game_time,pl->a_id);
}
delays() /* execute any applicable delayed actions */
{ register struct astruct *p;
register int i;
register struct list *l,*last;
/* for each plane, if it is active and if it has a command pending,
* and if it is at the right place for the command, then execute it.
*/
for (i = 0; i < PMAX; i++)
{ p = &plane[i];
if (p->a_active != ACTIVE) continue;
if (p->a_plan == 0) continue;
last = 0;
for (l = p->a_plan; l; )
{ if (p->a_x != l->l_x || p->a_y != l->l_y)
{
last = l;
l = l->l_next;
}
else /* it matched */
{
parse(l->l_cmd); /* execute the command */
/* now delete the command from the list */
if (last == 0) /* it was the first one */
{ p->a_plan = l->l_next;
free(l);
l = p->a_plan;
/* last stays at 0 */
}
else
{ last->l_next = l->l_next;
free(l);
l = last->l_next;
/* last stays where it was */
}
}
}
}
}
donavaid(pl) /* take appropriate action at navaid */
struct astruct *pl; /* the plane has either been vectored or told to hold */
{ register struct pstruct *d;
register int i;
if (pl->a_hold)
{ pl->a_hold = 2; /* will be holding now */
pl->a_turn = 'L'; /* and turning continuously to the left */
pl->a_dxnew = pl->a_dx; /* until it reaches this heading agn*/
pl->a_dynew = pl->a_dy;
}
if (pl->a_clear)
{ pl->a_turn = pl->a_dxnew = pl->a_dynew = pl->a_hold = 0;
/* see what we're vectoring to */
for (d = &entry[i=0]; i < nentry; i++,d++)
if (d->p_sym == pl->a_clear) break;
if (i != nentry) /* yes, it was a navaid */
{ pl->a_dx = -d->p_dx; /* opposite of entry heading*/
pl->a_dy = -d->p_dy;
pl->a_clear = 0;
return;
}
for (d = &airport[i=0]; i < nairport; i++,d++)
if (d->p_sym == pl->a_clear) break;
if (i == nairport) return; /* program bug - cleared to ?? */
pl->a_dx = d->p_dx; /* assume landing heading for airport */
pl->a_dy = d->p_dy;
pl->a_clear = 0;
if (pl->a_hold == 1)
pl->a_hold = pl->a_dxnew = pl->a_dynew = 0;
else if (pl->a_hold == 0)
pl->a_dxnew = pl->a_dynew = 0;
return;
}
}
turn(newx,newy,direc,dx,dy) /* messy - enumeration of all cases */
int *newx,*newy; /* returned values of new heading */
char direc;
int dx,dy;
{ int x,y;
x = *newx;
y = *newy;
switch(direc)
{ case 'L': /* cases would be more efficient, but this is clearer*/
if (x== -1 && y== -1) {*newx= -1; *newy= 0; break;}
if (x== -1 && y== 0) {*newx= -1; *newy= 1; break;}
if (x== -1 && y== 1) {*newx= 0; *newy= 1; break;}
if (x== 0 && y== -1) {*newx= -1; *newy= -1; break;}
if (x== 0 && y== 1) {*newx= 1; *newy= 1; break;}
if (x== 1 && y== -1) {*newx= 0; *newy= -1; break;}
if (x== 1 && y== 0) {*newx= 1; *newy= -1; break;}
if (x== 1 && y== 1) {*newx= 1; *newy= 0; break;}
break;
case 'R':
if (x== -1 && y== -1) {*newx= 0; *newy= -1; break;}
if (x== -1 && y== 0) {*newx= -1; *newy= -1; break;}
if (x== -1 && y== 1) {*newx= -1; *newy= 0; break;}
if (x== 0 && y== -1) {*newx= 1; *newy= -1; break;}
if (x== 0 && y== 1) {*newx= -1; *newy= 1; break;}
if (x== 1 && y== -1) {*newx= 1; *newy= 0; break;}
if (x== 1 && y== 0) {*newx= 1; *newy= 1; break;}
if (x== 1 && y== 1) {*newx= 0; *newy= 1; break;}
break;
}
if (*newx == dx && *newy == dy) return(1); /* finished turn */
else return(0);
}
report(error,plane1,plane2)
int error;
struct astruct *plane1,*plane2;
{ char mbuf[BUFSIZE];
int i;
putchar(BELL);
switch(error)
{ case FUEL:
sprintf(mbuf,"Tow truck called for %c (%c)",
plane1->a_id,airport[plane1->a_start].p_sym);
break;
case CRASH:
sprintf(mbuf,"PLANE %c OUT OF GAS",plane1->a_id);
break;
case BOUND:
sprintf(mbuf,"Boundary error - %c",plane1->a_id);
break;
case SYSTEM:
sprintf(mbuf,"%c AND %c: SYSTEM ERROR",
plane1->a_id, plane2->a_id);
break;
case GOAROUND:
sprintf(mbuf,"%c missed approach",plane1->a_id);
break;
case OUTOFTIME:
sprintf(mbuf,"Out of time: %d remain",remain);
break;
}
msg(cmdx,cmdy+2,mbuf);
}
leavescreen(pl)
struct astruct *pl;
{ struct pstruct *e;
pl->a_active = DONE;
pl->a_dist++;
erase(pl->a_x,pl->a_y);
remain--;
e = &entry[pl->a_dest];
if (pl->a_z == 5 && !pl->a_dair && /* leaving at non-airport, 5K' */
screen[pl->a_x][pl->a_y] == e->p_sym && /* right exit */
pl->a_dx == -e->p_dx && pl->a_dy == -e->p_dy && /* right direc */
pl->a_turn == 0) /* and not turning */
return(0);
bound++;
if (bigname)
{ fprintf(bigstatsfile,"%5d: Boundary error - plane %c ",
initgame_time - game_time,pl->a_id);
fprintf(bigstatsfile,"left at %d000' ",pl->a_z);
if (pl->a_nextz > pl->a_z)
fprintf(bigstatsfile,"climbing to %d000'",pl->a_nextz);
if (pl->a_nextz < pl->a_z)
fprintf(bigstatsfile,"descending to %d000'",pl->a_nextz);
fprintf(bigstatsfile,
"\n\tPosition: (%d,%d) Bearing: ",pl->a_x,pl->a_y);
if (pl->a_dy < 0) fprintf(bigstatsfile,"N");
else if (pl->a_dy > 0) fprintf(bigstatsfile,"S");
if (pl->a_dx > 0) fprintf(bigstatsfile,"E");
else if (pl->a_dx < 0) fprintf(bigstatsfile,"W");
if (pl->a_turn)
{ fprintf(bigstatsfile," turning %c to ",pl->a_turn);
if (pl->a_dynew < 0) fprintf(bigstatsfile,"N");
else if (pl->a_dynew > 0) fprintf(bigstatsfile,"S");
if (pl->a_dxnew > 0) fprintf(bigstatsfile,"E");
else if (pl->a_dxnew < 0) fprintf(bigstatsfile,"W");
}
fprintf(bigstatsfile,".\n");
}
report(BOUND,pl);
return(0);
}
conflict() /* check each pair of planes for problems */
{ register struct astruct *q,*p;
register int i,j,k;
register int miss;
for (p = &plane[k=1]; k < nplanes; k++,p++)
{ if (p->a_active != ACTIVE && p->a_active != LANDING) continue;
for (q = &plane[i=0]; i < k; i++,q++)
{ if (q->a_active != ACTIVE) continue;
if (q->a_z != p->a_z && q->a_z != p->a_lastz &&
q->a_lastz != p->a_z && q->a_lastz != p->a_lastz)
continue;
miss = abs(q->a_x - p->a_x);
j = abs(q->a_y - p->a_y);
if (j>miss) miss=j;
if (miss < 3) /* too close - system error */
{ system++;
if (bigname) bigsyserr(p,q);
report(SYSTEM,p,q);
break;
}
}
}
}
bigsyserr(p,q) /* spew sys err info into the big stats file */
struct astruct *p,*q;
{
fprintf(bigstatsfile,
"%5d: System error between %c (%d,%d,%d000) and %c (%d,%d,%d000)\n",
initgame_time - game_time,p->a_id,p->a_x,p->a_y,p->a_z,
q->a_id,q->a_x,q->a_y,q->a_z);
}
erase(x,y)
int x,y;
{ register struct astruct *p;
register int i;
if (x<0 || y < 0) return;
if (x>=width || y>=height) return;
cursor(x,y);
printf("%c ",screen[x][y]);
for (p = &plane[i=0]; i < nplanes; i++,p++)
if (p->a_active == ACTIVE && x == p->a_x && y == p->a_y)
{ cursor(x,y);
printf("%c%c",p->a_id,(p->a_z>9?'^':p->a_z+'0'));
}
}
int msglen[MAXHEIGHT]; /* length of message string on this row */
init()
{ int i,j;
char c,mbuf[BUFSIZE];
int pcompare();
FILE *statfile;
struct passwd *pw;
time_t now;
char *p,*ct;
extern char *ctime();
int nearlies;
if ((statfile = fopen(STATSFILE,"a")) != NULL)
{ pw = getpwuid(getuid());
now = get_time();
ct = ctime(&now);
for (p= &ct[4]; p <= &ct[16]; p++) fputc(*p,statfile);
fprintf(statfile,"%8s\n",pw->pw_name);
fclose(statfile);
}
/* go into raw mode, no echo */
if (!moviefile)
{ ioctl(0, TIOCGETP, &tty_setting);
tty_flags = tty_setting.sg_flags;
#ifdef CBREAK
tty_setting.sg_flags |= CBREAK;
tty_setting.sg_flags &= ~CRMOD;
#else
tty_setting.sg_flags |= RAW;
#endif
tty_setting.sg_flags &= ~ECHO;
ioctl(0, TIOCSETP, &tty_setting);
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
signal (SIGINT, catchint);
if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
signal (SIGQUIT, catchint);
}
for (i = 0; i < MAXHEIGHT; i++)
msglen[i] = 0;
for (i=0; i<MAXWIDTH; i++) for (j=0; j<MAXHEIGHT; j++)
screen[i][j] = '.';
if (moviefile)
{ if ((movie = fopen(moviefile,"r")) == NULL)
err("Cannot open %s for reading.\n",moviefile);
minit(); /* initialize from movie file */
}
if (seed == 0) seed = get_time();
initseed = seed;
#ifdef vax
srand(seed);
#else
srandom(seed); /* initialize random number generator */
#endif
clearscreen();
readspace();
cmdx = width; /* start command just to right of display */
cmdy = height-4; /* and a ways from the bottom */
display(); /* initial display */
for (i=0; i<nairport; i++)
{ sprintf(mbuf,"%c : %c%c",
screen[airport[i].p_x][airport[i].p_y],
(j = airport[i].p_dy) == 1 ? 'S' : j == -1 ? 'N' : ' ',
(j = airport[i].p_dx) == 1 ? 'E' : j == -1 ? 'W' : ' ');
msg(cmdx,cmdy-2-i,mbuf);
}
cdltop.c_next = 0; /* initially no clearance directive lists */
cdltop.c_list = 0;
while (game_time < 16*60 || game_time > 99*60+59) /*get time from user */
{ char buf[100];
char *p;
cursor(cmdx,cmdy);
printf("< >");
cursor(cmdx,cmdy);
/* move the cursor one space to the right */
p = buf;
tgetstr ("nd", &p);
fwrite (buf, sizeof (*buf), p-buf, stdout);
game_time = getdigit()*10; /* get the time as 2 digits */
game_time += getdigit();
initgame_time = game_time = game_time*60+59;
}
if (protofile) /* keeping a protocol of the whole game */
{ if ((proto = fopen(protofile,"w")) == NULL)
err("Cannot open %s for writing.\n",protofile);
protostats(proto);
}
if (bigname) /* megastatistics requested */
{ if ((bigstatsfile = fopen(bigname,"w")) == NULL)
err("Cannot open %s for writing.\n",bigname);
protostats(bigstatsfile);
if (protofile)
fprintf(bigstatsfile,"Protocol from %s\n",protofile);
}
last_update = initgame_time+UPDATE; /* force early update */
if (moviefile) last_update += OFFSET;
for (i=nearlies=0; i<nplanes; i++) /* construct 26 flight plans */
{ plane[i].a_id = 'A'+i;
flightplan(&plane[i],0);
if (plane[i].a_stime < FPTHRESH) nearlies++;
}
for (i=nearlies; i < NEARLY; i++) /* ensure 2 or so planes in 1st minute */
flightplan(&plane[die(nplanes)],1);
qsort(plane,nplanes,sizeof (struct astruct),pcompare);
remain = nplanes;
if (bigname)
for (i = 0; i < nplanes; i++)
strip(&plane[i],-1,TERSE);
for (i=0; i<nairport; i++) /* erase the approaches */
delmsg(cmdx,cmdy-2-i);
start_time = get_time();
}
protostats(proto) /* bunch of statistics for protocols and stuff */
FILE *proto;
{ char wd[100]; /* result of a "pwd" command */
FILE *pwd;
char *s,*t,*u;
int c;
if ((pwd = popen("pwd","r")) == NULL)
err("Cannot open a pipe to pwd.\n");
for (s = wd; (c = getc(pwd)) != EOF;)
if (c != '\n') *s++ = c;
t = s; /* here's where to put the filename */
*s = 0;
fclose(pwd);
if (*airfile != '/') /* relative airspace file */
{ s = t;
*s++ = '/';
for (u = airfile; *s++ = *u++; );
fprintf(proto,"Airspace file: %s\n",wd);
}
else fprintf(proto,"Airspace file: %s\n",airfile);
fprintf(proto,"Airspace: %s\n",airspace);
if (flowfile)
{ if (*flowfile != '/') /* relative flowfile */
{ s = t;
*s++ = '/';
for (u = flowfile; *s++ = *u++; );
fprintf(proto,"Flow file: %s\n",wd);
}
else fprintf(proto,"Flow file: %s\n",flowfile);
}
else fprintf(proto,"Flow file: \n");
fprintf(proto,"Seed: %d\n",seed);
fprintf(proto,"Time: %d seconds\n",game_time);
}
minit() /* initialize the game from a protocol file */
{ /* the file is open on stream "movie" */
char buffer[80];
static char airfilebuf[80];
static char airbuf[80];
static char flowbuf[80];
char *s,*t;
if (fgets(buffer,80,movie) == 0) /* airspace file line */
err("Unexpected EOF on movie file.\n");
for (s = buffer; *s != ':' && *s; s++); /* scan to colon */
if (*s == 0) err("Bad airspace file line.\n");
s++; s++; /* skip colon and space */
for (t = airfilebuf; (*t++ = *s++) != '\n';); /* copy airspace file */
*--t = 0;
airfile = airfilebuf; /* and dummy the pointer */
if (fgets(buffer,80,movie) == 0) /* airspace line */
err("Unexpected EOF on movie file.\n");
for (s = buffer; *s != ':' && *s; s++); /* scan to colon */
if (*s == 0) err("Bad airspace line.\n");
s++; s++; /* skip colon and space */
for (t = airbuf; (*t++ = *s++) != '\n';); /* copy airspace name */
*--t = 0;
airspace = airbuf; /* and dummy the pointer */
if (fgets(buffer,80,movie) == 0) /* flowfile line */
err("Unexpected EOF on movie file.\n");
for (s = buffer; *s != ':' && *s; s++); /* scan to colon */
if (*s == 0) err("Bad flowfile line.\n");
s++; s++; /* skip colon and space */
if (*s == '\n') flowfile = 0;
else
{ for (t = flowbuf; (*t++ = *s++) != '\n';); /* copy flowfile */
*--t = 0;
flowfile = flowbuf; /* and dummy the pointer */
}
if (fgets(buffer,80,movie) == 0) /* seed */
err("Unexpected EOF on movie file.\n");
for (s = buffer; *s != ':' && *s; s++); /* scan to colon */
if (*s == 0) err("Bad seed line.\n");
s++; s++; /* skip colon and space */
seed = atoi(s);
if (fgets(buffer,80,movie) == 0) /* time line */
err("Unexpected EOF on movie file.\n");
for (s = buffer; *s != ':' && *s; s++); /* scan to colon */
if (*s == 0) err("Bad time line.\n");
s++; s++; /* skip colon and space */
initgame_time = game_time = atoi(s);
getmcmd(); /* get the first command from movie mode */
}
getmcmd() /* read a command and store time and command */
{ static char buff[80];
char *s;
if (fgets(buff,80,movie) == 0)
{ mcommand = "";
nextmovie = -20;
fclose(movie);
return;
}
for (s = buff; *s == ' '; s++); /* skip initial blanks */
nextmovie = atoi(s);
while (*s++ != ' '); /* skip to the command */
mcommand = s; /* and save it in a global */
for (; *s; s++) if (*s == '\n') *s = RETURN;
}
pcompare(p1,p2) /* compare start times for sorting the plane list */
struct astruct *p1,*p2;
{ if ((p1)->a_stime < (p2)->a_stime) return(-1);
else if ((p1)->a_stime == (p2)->a_stime) return(0);
else return(1);
}
printplans() /* flight plans for active and near-active planes */
{ register int ctr; /* can only keep cmdy-2 planes on the screen */
register struct astruct *p;
register int i;
for (i = ctr = 0, p = &plane[0]; i < nplanes && ctr < cmdy - 2; i++,p++)
if (p->a_active == APPROACHING || p->a_active == WAITING)
strip(p,ctr++,TERSE);
delmsg(cmdx,ctr++); /* blank line between approaching and active*/
for (p = &plane[i=0]; i < nplanes && ctr < cmdy - 2; i++,p++)
if (p->a_active == ACTIVE)
strip(p,ctr++,TERSE);
while (ctr < cmdy - 2) delmsg(cmdx,ctr++); /* delete any msg on line*/
}
strip(p,y,outstyle) /* display flight strip for this plane on cmd row y */
register struct astruct *p;
int y,outstyle;
{ char mbuf[80]; /* plan message to appear */
int pfuel;
struct list *l;
char *s;
if (p->a_active == WAITING) sprintf(mbuf," ");
else if (p->a_active == APPROACHING)
sprintf(mbuf,"%d ",
(p->a_stime - initgame_time + game_time + 14) / 15);
else mbuf[0] = 0;
sprintf(&mbuf[strlen(mbuf)],"%c%c %c->%c ",
p->a_id,
(p->a_type? 'j': 'p'),
screen[p->a_x][p->a_y],
(p->a_dair? airport[p->a_dest].p_sym :
entry[p->a_dest].p_sym));
sprintf(&mbuf[strlen(mbuf)],"%d%c%c ",
p->a_z,
(p->a_nextz > p->a_z ? '^' :
p->a_nextz < p->a_z ? 'v' : ' '),
(p->a_nextz != p->a_z ? p->a_nextz + '0' : ' '));
if (p->a_dy>0) sprintf(&mbuf[strlen(mbuf)],"S");
else if (p->a_dy<0) sprintf(&mbuf[strlen(mbuf)],"N");
if (p->a_dx>0) sprintf(&mbuf[strlen(mbuf)],"E");
else if (p->a_dx<0) sprintf(&mbuf[strlen(mbuf)],"W");
if (p->a_dy == 0) sprintf(&mbuf[strlen(mbuf)]," ");
switch(p->a_hold)
{ case 2: sprintf(&mbuf[strlen(mbuf)]," h "); break;
case 1: sprintf(&mbuf[strlen(mbuf)]," * "); break;
case 0: sprintf(&mbuf[strlen(mbuf)]," %c ",p->a_turn-'A'+'a');
break;
}
if (p->a_clear)
sprintf(&mbuf[strlen(mbuf)],"* %c",p->a_clear);
if (p->a_dynew>0) sprintf(&mbuf[strlen(mbuf)],"S");
else if (p->a_dynew<0) sprintf(&mbuf[strlen(mbuf)],"N");
if (p->a_dxnew>0) sprintf(&mbuf[strlen(mbuf)],"E");
else if (p->a_dxnew<0) sprintf(&mbuf[strlen(mbuf)],"W");
if (p->a_dynew == 0) sprintf(&mbuf[strlen(mbuf)]," ");
pfuel = (p->a_type == JET? p->a_fuel/4 : p->a_fuel/2);
sprintf(&mbuf[strlen(mbuf)]," %c",pfuel>=10?'+':pfuel+'0');
if (p->a_plan)
sprintf(&mbuf[strlen(mbuf)]," P");
if (y < 0) /* flight strip to file, not screen */
{ if (bigname)
{ int st;
st = p->a_stime;
if (p->a_type == JET)
{ st = st / 15;
st = st * 15;
}
else
{ st = (st + 45) / 30;
st = (st * 30) - 15;
}
if (st < FIRST_TIME) st = FIRST_TIME;
fprintf(bigstatsfile,"%5d: ",st);
fprintf(bigstatsfile,"%s\n",mbuf);
}
}
else
{ msg(cmdx,y,mbuf); /* display the string */
if (outstyle == VERBOSE && p->a_plan)
{ for (l = p->a_plan; l; l = l->l_next)
{ sprintf(mbuf,"%s %s",l->l_loc,l->l_cmd);
for (s = mbuf; *s; s++) if (*s == RETURN) *s = 0;
msg(cmdx,++y,mbuf);
}
}
while (++y < MAXHEIGHT && msglen[y]) msg(cmdx,y,"");/* clr old plans*/
}
}
msg(x,y,string) /* put up a message at cursor position x,y */
int x,y;
char *string;
{ int i,l;
cursor(x,y);
printf("%s",string);
l = strlen(string);
for (i=l; i<msglen[y]; i++) putchar(' ');
msglen[y] = l;
}
delmsg(x,y) /* delete any message starting at cursor posn x,y */
int x,y;
{ int i;
if (msglen[y] <= 0) return;
cursor(x,y);
for (i=0; i<msglen[y]; i++) putchar(' ');
msglen[y] = 0;
}
flightplan(p,early)
struct astruct *p;
int early; /* 1 if this plane should be rescheduled for early arrival */
{ int i,r,cum;
struct astruct *q;
struct pstruct *loc;
p->a_type = die(2);
/* starting time: no planes in last 15 minutes; pretend interval
* extends negatively from 0 by FUDGE seconds to make it more likely
* that there will be planes available soon. On the other hand, no
* plane can come on for the first FIRST_TIME seconds.
*/
p->a_stime = die(FUDGE + game_time - 15*60) - FUDGE;
if (early) p->a_stime = die(FPTHRESH);
if (p->a_stime <FIRST_TIME) p->a_stime = FIRST_TIME;
if (flowfile) /* flows have been specified */
{ r = die(maxflow);
for (i = cum = 0; i < npaths; i++)
{ cum += fpath[i].f_freq;
if (cum >= r) break;
}
if (i >= npaths) i = 0; /* shouldn't ever do this */
p->a_sair = fpath[i].f_fair;
p->a_dair = fpath[i].f_tair;
p->a_hold = (p->a_dair && !p->a_sair? 1 : 0);
p->a_start = fpath[i].f_from;
p->a_dest = fpath[i].f_to;
if (p->a_sair) loc = &airport[p->a_start];
else loc = &entry[p->a_start];
}
else
{ p->a_sair = (die(inaptot+inawtot) <= inaptot? 1 : 0);
p->a_dair = (die(outaptot+outawtot) <= outaptot? 1 : 0);
p->a_hold = (p->a_dair? 1 : 0);
if (p->a_sair)
{ p->a_start =pick(die(inaptot),&airport[0],nairport,1);
loc = &airport[p->a_start];
p->a_hold = 0;
if (p->a_dair) p->a_dest = pick(die(inaptot),
&airport[0],nairport,0);
else p->a_dest = pick(die(inawtot),
&entry[0],nentry,0);
}
else
{ p->a_start = pick(die(inawtot),&entry[0],nentry,0);
loc = &entry[p->a_start];
if (p->a_dair) p->a_dest = pick(die(inaptot),
&airport[0],nairport,0);
else do p->a_dest = pick(die(inawtot),
&entry[0],nentry,0);
while (p->a_dest == p->a_start);
}
}
p->a_active = INACTIVE;
p->a_z = (p->a_sair? 0 : 6);
if (!p->a_sair) /* separate planes by 1000' altitude */
for (q = &plane[0]; q != &plane[PMAX]; q++)
{ if (q == p && !early) break;
if (q == p) continue;
if (p->a_start == q->a_start)
if (abs(q->a_stime - p->a_stime) < SAFETY)
if (q->a_z >= p->a_z)
p->a_z = q->a_z + 1;
}
if (flowfile && p->a_z < NALT)
{ p->a_opt = fpath[i].f_dist[p->a_z];
p->a_cmds = fpath[i].f_cmds;
}
p->a_prev = p->a_pprev = p->a_aprev = 0;
p->a_x = loc->p_x;
p->a_y = loc->p_y;
p->a_dx = loc->p_dx;
p->a_dy = loc->p_dy;
p->a_dxnew = p->a_dynew = 0;
p->a_lastz = p->a_nextz = p->a_z;
p->a_turn = 0;
p->a_fuel = (p->a_type == JET ? JETFUEL : PROPFUEL);
p->a_clear = 0; /* not cleared for any approach */
p->a_plan = 0; /* no monitor points on the flight plan */
p->a_load = p->a_ticks = p->a_planned = p->a_dist = 0;
}
pick(draw,point,num,in)
int draw;
struct pstruct *point;
int num,in;
{ register int i,cum;
for (i = cum = 0; i<num; i++,point++)
{ if (in) cum += point->p_inprop;
else cum += point->p_outprop;
if (cum >= draw) return(i);
}
return(0); /* should never get here */
}
#if !NRAND
die(n) /* throw an n-sided die (sides 0 thru n-1) */
int n;
{ int r;
#ifdef vax
r = rand() >> 10; /* rightmost bits are not very random */
#else
r = random(); /* rightmost bits are not very random */
#endif
return(r % n); /* enough resolution to make this o.k. */
}
#endif
getdigit() /* keep reading chars from terminal until get a digit */
{ int c; /* returns digit - '0' */
do {
if (rubout) return 9;
c = getchar() & 0177;
} while (c < '0' || c > '9');
putchar(c);
return(c-'0');
}
time_t
get_time() /* returns time in seconds since 1970 */
{
time_t t;
time(&t);
return(t); /* seconds since 1970 */
}
display() /* put up initial screen */
{ int i,j;
for (j=0; j<height; j++)
{ cursor(0,j); /* general enough to extend to graphics */
for (i=0; i<width; i++)
{ putchar(screen[i][j]);
putchar(' ');
}
}
}
cursor(x,y) /* move to location x,y on WIDTHxHEIGHT screen */
char x,y; /* this is in terms of screen, i.e. with x's 2 chars wide */
{
poscur(2*x,y);
}
poscur(x,y) /* position cursor at this absolute location on screen */
char x,y;
{
char *tgoto();
printf ("%s", tgoto (cmbuf, x, y));
}
clearscreen()
{
printf ("%s", clbuf);
}
char *
plural(n) /* returns "s" unless n=1 */
int n;
{ static char s[2] = "s";
if (n != 1) return(s);
else return("");
}
done(flag) /* clean up */
int flag;
{ FILE *statfile;
struct passwd *pw;
time_t now;
char *c,*ct;
extern char *ctime();
if (!moviefile)
{ tty_setting.sg_flags = tty_flags;/* put terminal back the way it was*/
ioctl(0, TIOCSETP, &tty_setting);
}
if (flag) cursor(LEFT,height+1);
if ((statfile = fopen(STATSFILE,"a")) != NULL)
{ pw = getpwuid(getuid());
now = get_time();
ct = ctime(&now);
for (c= &ct[4]; c <= &ct[16]; c++) fputc(*c,statfile);
if (!flag) fprintf(statfile,"%8s: aborted\n",pw->pw_name);
else
{ fprintf(statfile,"%8s: %2d %3d %2d %2d %3d %5d %3d %2d",
pw->pw_name,crash,system,fuel,bound,goaround,
fuelused,cmds,remain);
fprintf(statfile,". %d %2d %s\n",
initseed,initgame_time/60,airspace);
fclose(statfile);
}
}
if (!flag) return;
ttystats(stdout);
if (bigname)
{ int i;
float load,ticks,plans,route,d,stripped;
for (i = 0; i < nplanes; i++)
{ load = plane[i].a_load;
ticks = plane[i].a_ticks;
plans = plane[i].a_planned;
route = plane[i].a_opt;
stripped = plane[i].a_prev;
d = plane[i].a_dist;
fprintf(bigstatsfile,
"%c: %2d tks, %2d/%2d=%1.2f, %d, %.2f a/tk, %.2f p/tk, %.2f a/ptk, %.2f p/ptk, %c, %s\n",
plane[i].a_id,plane[i].a_ticks,
plane[i].a_dist,
plane[i].a_opt,
d/route,
plane[i].a_cmds,
load/ticks,
plans/ticks,
plane[i].a_aprev/stripped,
plane[i].a_pprev/stripped,
plane[i].a_sair? 'W' : 'A',
plane[i].a_pplanned? "+P" : "-P"
);
}
}
if (bigname) ttystats(bigstatsfile);
if (protofile) fclose(proto);
if (bigname) fclose(bigstatsfile);
}
ttystats(file)
FILE *file;
{ char *eol;
if (file == bigstatsfile) eol = "\n";
else {
clearscreen();
eol = "\n\r";
}
if (crash) fprintf(file,"%d plane%s out of fuel, crashed%s",
crash,plural(crash),eol);
if (system) fprintf(file,"%d system error%s%s",
system,plural(system),eol);
if (fuel) fprintf(file,"%d tow truck%s called%s",
fuel,plural(fuel),eol);
if (bound) fprintf(file,"%d boundary error%s%s",
bound,plural(bound),eol);
if (goaround) fprintf(file,"%d go-around%s%s",
goaround,plural(goaround),eol);
if (crash+system+fuel+bound+remain == 0)
{ fprintf(file,"GREAT JOB!! Have you considered a career in ATC?\n");
fprintf(file,"Now try %d minutes...\n",initgame_time/60-5);
}
fprintf(file,"Fuel used: %d\n",fuelused);
fprintf(file,"Commands issued (including deferred): %d\n",icmds);
fprintf(file,"Commands executed: %d\n",cmds);
fprintf(file,"Airspace: %s; seed: %d; time=%d; %d remaining.%s",
airspace,initseed,initgame_time/60,remain,eol);
if (file == bigstatsfile) fprintf(file,"\f");
}
err(msg,arg1,arg2)
char *msg;
{ fprintf(stderr,msg,arg1,arg2);
done(0);
exit(1);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.