[net.sources.games] Small visual trek game

Doug@ecn-aa.UUCP (09/07/85)

#
#	Here's a simple visual Star Trek game that I recently wrote.
#	It's pretty much the same as other Star Trek games,  but the
#	visual aspect makes it a bit more entertaining.
#
#	This version seems to work OK here at purdue-ecn (4.2,4.3bsd).  It
#	should work on other Unix OS's with little or no changes.
#	It will work on CP/M if you have the Aztec C compiler and
#	64K of ram.  It will work on the IBM PC & compatibles with 
#	minor changes.
#
#	Send flames to /dev/null.  Please mail be a copy of any major
#	enhancements/modifications that you make.
#
#	You are free to distribute copies to anyone who wants the game,
#	as long as you don't sell it.
#
#					dug patrick
#					ihnp4!pur-ee!dug
#
#------------------------------------------------------------------------
echo x - main.c
cat >main.c << '!EOF!'
/*
 *	main.c
 *
 *	visual star trek
 *
 *	BASIC version written by Tom Goerz and debugged by Dug Patrick
 *		22-Dec-79, 13-Nov-80
 *	C version written by Dug Patrick
 *		05-Aug-84, 11-Mar-85
 *
 */

#include "vtrek.h"

char playership[] = " ? ";
int rolines = 0;

main()
{
	int cmd, ch;
	char str[44];

#ifdef AZTEC
	int errortrap();
	Sysvec[FLT_FAULT] = errortrap;
#endif

	instructions();
	initvars();
	terminit();
	replot();

	sprintf(str, "You have %.1f stardates to save the", lastdate - stardate);
	readout(ADDLINE, str);
	readout(ADDLINE, "Federation from the Klingon invasion.");

	setcondition();

	while (numkling > 0) {
	    switch (cmd = getcmd()) {

	    case 'H' :		/* hyper-space */
		hyperspace();
		break;

	    case 'S' :		/* short range scan */
		srs();
		break;

	    case 'L' :		/* long range scan */
		lrs();
		break;

	    case 'P' :		/* fire phasers */
		phasers();
		break;

	    case 'T' :		/* fire photon torpedo */
		torpedo();
		break;

	    case 'U' :		/* change shield level */
		defense();
		break;    

	    case 'R' :		/* replot screen */
		replot();
		continue;

	    case 'Q' :		/* move using impulse engines */
	    case 'W' :
	    case 'E' :
	    case 'A' :
	    case 'D' :
	    case 'Z' :
	    case 'X' :
	    case 'C' :
		impulse(cmd);
		break;

	    case 'K' :		/* kill - commit suicide */
		prompt("Quit ? ");
		ch = getch();
		if (Toupper(ch) == 'Y')
		    die();
		break;

	    case 'F' :		/* fix devices */
		repdevices();
		break;

	    case 03 :		/* exit without warning */
	    case 04 :
		die();
		break;

	    case '?' :		/* help */
		help();
		break;

	    default :		/* illegal command */
		readout(ADDLINE, "Type '?' for help.");
		break;
	    }

	    fixdev(REL, RND, 5);
	    setcondition();
	    klingmove();

	    if ((stardate += 0.1) > lastdate)
		timeout();
	    plt_stat(ELEMENT, STARDATE);
	    plt_num(INFO);

	    if (energy <= 0 && shields <= 0)
		dead();
	}

	win();
}

#ifdef AZTEC
errortrap(errcode, addr)
int errcode, addr;
{
}
#endif
!EOF!
echo x - makefile
cat >makefile << '!EOF!'
OBJS=main.o plot.o sub1.o sub2.o termio.o

a.out:	$(OBJS)
	$(CC) $(OBJS) -lm -ltermlib

.c.o:
	cc -O -c $*.c

$(OBJS): vtrek.h
!EOF!
echo x - plot.c
cat >plot.c << '!EOF!'
/* plot.c -- plot routines for visual star trek */

#include "vtrek.h"

/* replot screen */
replot()
{
	cls();
	plt_stat(ALL);
	plt_srs(ALL);
	plt_dam(ALL);
	plt_gal(ALL);
	moveyx(12, 18);
	printf("READOUT");
	moveyx(13, 18);
	printf("-------");
	plt_num(ALL);
}

/* plot status (upper left) */
plt_stat(op, item)
int op, item;
{
	static char *text[9] = {
	    "      Status", "      ------", "Stardate     :",
	    "Condition    :", "Quadrant     :", "Sector       :",
	    "Energy       :", "Photon torps :", "Shields      :"
	};
	static char *ctext[4] = {
	    "Green", "Yellow", "Red", "Docked"
	};
	int i, high, low;

	if (op & TEXT)
	    for (i = 0; i < 9; i++) {
		moveyx(i + 2, 1);
		printf("%s", text[i]);
	    }

	if (op & (INFO | ELEMENT)) {
	    if (op & INFO) {
		low = STARDATE;
		high = SHIELDS;
	    }
	    else {
		low = item;
		high = item;
	    }

	    for (i = low; i <= high; i++) {
		switch (i) {
		case STARDATE :
		    moveyx(4, 16);
		    printf("%-.1f", stardate);
		    break;
		case CONDITION :
		    moveyx(5, 16);
		    printf("%-6s", ctext[condition]);
		    break;
		case QUADRANT :
		    moveyx(6, 16);
		    printf("[%d,%d]", xquad + 1, yquad + 1);
		    break;
		case SECTOR :
		    moveyx(7, 16);
		    printf("[%d,%d]", xsect + 1, ysect + 1);
		    break;
		case ENERGY :
		    moveyx(8, 16);
		    printf("%-4d", energy);
		    break;
		case TORPS :
		    moveyx(9, 16);
		    printf("%-2d", torps);
		    break;
		case SHIELDS :
		    moveyx(10, 16);
		    printf("%-4d", shields);
		    break;
		}
	    }
	}
}

/* plot short range scan */
plt_srs(op, xs, ys)
int op, xs, ys;
{
	static char *htext = "-1--2--3--4--5--6--7--8-";
	static char *stext[6] = {
	    "   ", "<K>", "<S>", " * ", "???", " + "
	};
	int i, j;

	if (op & TEXT) {
	    moveyx(1, 28);
	    printf("%s", htext);
	    for (i = 1; i < 9; i++) {
		moveyx(i + 1, 27);
		printf("%d", i);
		moveyx(i + 1, 52);
		printf("%d", i);
	    }
	    moveyx(10, 28);
	    printf("%s", htext);
	}

	strcpy(stext[PLAYER], playership);

	if (op & INFO) {
	    for (i = 0; i < 8; i++) {
		moveyx(i + 2, 28);
		for (j = 0; j < 8; j++)
		    printf("%s", stext[(damage[SRS] <= 0) ? EMPTY : quadrant[j][i]]);
	    }
	}
	else if (op & ELEMENT) {
	    moveyx(ys + 2, 28 + 3 * xs);
	    printf("%s", stext[(damage[SRS] <= 0) ? EMPTY : quadrant[xs][ys]]);
	}
}

/* plot damage info */
plt_dam(op, item)
int op, item;
{
	static char *text[10] = {
	    "    Damage Report", "    -------------",
	    "Warp engines    :", "S.R. sensors    :", "L.R. sensors    :",
	    "Phaser control  :", "Damage control  :", "Defense control :",
	    "Computer        :", "Photon tubes    :"
	};
	int i;

	if (op & TEXT)
	    for (i = 0; i < 10; i++) {
		moveyx(i + 1, 56);
		printf("%s", text[i]);
	    }

	if (op & INFO)
	    for (i = 0; i < 8; i++) {
		moveyx(i + 3, 74);
		if (damage[DAMAGE] <= 0)
		    printf("    ");
		else
		    printf("%4d", damage[i]);
	    }
	else if (op & ELEMENT) {
	    moveyx(item + 3, 74);
	    if (damage[DAMAGE] <= 0)
		printf("    ");
	    else
		printf("%4d", damage[item]);
	}
}

/* plot galaxy map */
plt_gal(op, xq, yq)
int op, xq, yq;
{
	static char *htext = "-1- -2- -3- -4- -5- -6- -7- -8-";
	int i, j, fedquad;

	if (op & TEXT) {
	    moveyx(13, 47);
	    printf("%s", htext);
	    for (i = 1; i < 9; i++) {
		moveyx(i + 13, 45);
		printf("%d:", i);
		for (j = 0; j < 7; j++) {
		    moveyx(i + 13, 50 + (j << 2));
		    putch(':');
		}
		moveyx(i + 13, 78);
		printf(":%d", i);
	    }
	    moveyx(22, 47);
	    printf("%s", htext);
	}

	if (op & INFO) {
	    for (i = 0; i < 8; i++)
		for (j = 0; j < 8; j++) {
		    moveyx(i + 14, 47 + (j << 2));
		    if (damage[COMPUTER] <= 0 || !galaxy[j][i].known)
			printf("   ");
		    else
			printf("%01d%01d%01d", galaxy[j][i].nkling, galaxy[j][i].nbase,
			    galaxy[j][i].nstar);
		}
	    moveyx(yquad + 14, 46 + (xquad << 2));
	    putch('[');
	    moveyx(yquad + 14, 50 + (xquad << 2));
	    putch(']');
	}
	else if (op & ELEMENT) {
	    moveyx(yq + 14, 46 + (xq << 2));
	    fedquad = (xq == xquad && yq == yquad);
	    putch(fedquad ? '[' : ':');
	    if (damage[COMPUTER] <= 0)
		printf("   ");
	    else
		printf("%01d%01d%01d", galaxy[xq][yq].nkling, galaxy[xq][yq].nbase, galaxy[xq][yq].nstar);
	    putch(fedquad ? ']' : ':');
	}
}

/* plot number of star bases & klingons */
plt_num(op)
int op;
{
	float kf;

	if (op & TEXT) {
	    moveyx(23, 47);
	    printf("Base stars = ");
	    moveyx(23, 63);
	    printf("Klingons = ");
	    moveyx(24, 54);
	    printf("Kill Factor = ");
	}

	if (op & INFO) {
	    moveyx(23, 59);
	    printf(" %d", numbases);
	    moveyx(23, 73);
	    printf(" %d/%d  ", numkling, begkling);
	    moveyx(24, 68);
	    if (begdate != stardate)
		kf = (begkling - numkling) / (stardate - begdate);
	    else
		kf = 0.0;
	    printf("%5.3f  ", kf);
	}
}

/* change readout */
readout(op, str)
int op;
char *str;
{
	int i, j;

	switch (op) {

	case CLEAR :		/* clear readout */
	    for (i = 14; i <= 13 + rolines; i++) {
		moveyx(i, 1);
		for (j = 0; j < 44; j++)
		    putch(' ');
	    }
	    rolines = 0;
	    break;

	case ADDLINE :		/* add line to readout */
	    if (rolines >= 10)
		readout(CLEAR, NULL);
	    moveyx(14 + rolines, 1);
	    printf("%-.44s", str);
	    rolines++;
	    break;
	}
}
!EOF!
echo x - sub1.c
cat >sub1.c << '!EOF!'
/* sub1.c -- subroutines for visual star trek */

#include "vtrek.h"

/* print short help information */
help()
{
	if (rolines > 5)
	    readout(CLEAR, NULL);
	readout(ADDLINE, "Directions = Q,W,E,A,D,Z,X,C");
	readout(ADDLINE, "H = Hyper-space      S = Short range scan");
	readout(ADDLINE, "L = Long range scan  P = Fire phasers");
	readout(ADDLINE, "T = Fire torpedo     U = Defense control");
	readout(ADDLINE, "R = Redraw screen    F = Fix devices");
}

/* get command character */
getcmd()
{
	int ch, i;
	char str[40];

	sprintf(str, "Command %s ? ", captain);
	prompt(str);

	ch = getch();

	return Toupper(ch);
}

/* give option to see instructions */
instructions()
{
	FILE *fp;
	char line[80];
	int n, ch;

	printf("Instructions ? ");

	/* This would seem to be a silly place to randomize,  but this */
	/* location made things a bit easier for the CPM version. */
#ifdef AZTEC
	/* if randomize is available then use it instead of this: */
	while (!chready())
	    rnd(1);
#else
	randomize();
#endif

	if (fgets(line, 80, stdin) == NULL)
	    vexit(0);
	ch = Toupper(line[0]);
	if (ch == 'Y') {
	    if ((fp = fopen(VTREKINS, "r")) == NULL)
		printf("Error: Missing instruction file\n");
	    else {
		terminit();
		for (;;) {
		    for (n = 0; n < 22; n++) {
			if (fgets(line, 80, fp) == NULL)
			    break;
			printf("%s", line);
#ifdef UNIX
			putchar('\r');
#endif
		    }
		    if (n < 22)
			break;
		    printf("--More--");
		    getch();
		    printf("\r        \r");
		}
		fclose(fp);
		termreset();
	    }
	}
}

/* get captain's name and ship's name */
getnames()
{
	int ch, tmp;

	printf("Your name captain ? ");
	if (fgets(captain, 11, stdin) == NULL)
	    vexit(1);
	if (captain[tmp = strlen(captain) - 1] == '\n')
	    captain[tmp] = '\0';
	else
	    while (getchar() != '\n');
	if (*captain == '\0')
	    strcpy(captain, "Duncel");

	printf("Your ship's name captain ? ");
	if (fgets(shipname, 11, stdin) == NULL)
	    vexit(1);
	if (shipname[tmp = strlen(shipname) - 1] == '\n')
	    shipname[tmp] = '\0';
	else
	    while (getchar() != '\n');
	if (*shipname == '\0')
	    strcpy(shipname, "Fruit");
}

/* get skill level */
getskill()
{
	char level[10];

	printf("Skill level (0-5, 0=easy, 5=hard) ? ");
	if (fgets(level, 10, stdin) == NULL)
	    vexit(1);
	if (isdigit(level[0]))
	    skill = level[0] - '0';
	else
	    skill = 3;
}

/* initialize galaxy */
initgal()
{
	int i, j, k, r, n;

	numkling = 0;

	for (i = 0; i < 8; i++) {
	    for (j = 0; j < 8; j++) {
		if ((r = rnd(100)) < 10)
		    k = 3;
		else if (r < 20)
		    k = 2;
		else if (r < 30)
		    k = 1;
		else
		    k = 0;
		numkling += k;
		galaxy[i][j].nkling = k;
		galaxy[i][j].nstar = rnd(8) + 1;
		galaxy[i][j].nbase = 0;
		galaxy[i][j].known = 0;
	    }
	}

	numbases = rnd(3) + 2;

	for (n = 0; n < numbases; n++) {
	    for (;;) {
		if (galaxy[i = rnd(7)][j = rnd(7)].nbase == 0) {
		    galaxy[i][j].nbase = 1;
		    break;
		}
	    }
	}
}

/* initialize variables */
initvars()
{
	int i;

	getnames();
	getskill();
	initgal();

	numkmove = skill;
	begkling = numkling;
	xquad = rnd(7);
	yquad = rnd(7);
	old_xsect = (xsect = rnd(7));
	old_ysect = (ysect = rnd(7));
	shields = 0;
	energy = 3000;
	stardate = 2000.0;
	begdate = stardate;
	lastdate = stardate + (float)numkling;
	torps = 10;
	playership[1] = *shipname;
	condition = YELLOW;

	for (i = 0; i < 8; i++)
	    damage[i] = 100;
	
	old_xquad = -1;
	old_yquad = -1;
	setpos();
}

/* set new position -- check for outside galaxy, set up new quadrant */
setpos()
{
	int dam = 0, i, j, n, dev, status = 0;
	static int notfirstcall = 0;

	if (xsect > 7) {
	    xsect = 0;
	    xquad++;
	}
	else if (xsect < 0) {
	    xsect = 7;
	    xquad--;
	}

	if (ysect > 7) {
	    ysect = 0;
	    yquad++;
	}
	else if (ysect < 0) {
	    ysect = 7;
	    yquad--;
	}

	if (xquad > 7) {
	    dam = 1;
	    xquad = 7;
	    xsect = 7;
	}
	else if (xquad < 0) {
	    dam = 1;
	    xquad = 0;
	    xsect = 0;
	}

	if (yquad > 7) {
	    dam = 1;
	    yquad = 7;
	    ysect = 7;
	}
	else if (yquad < 0) {
	    dam = 1;
	    yquad = 0;
	    ysect = 0;
	}

	if (dam) {
	    readout(ADDLINE, "You encounter a force field.");
	    shields -= rnd(20) + 90;
	    plt_stat(ELEMENT, SHIELDS);
	    status = DAMAGE;
	    if (shields < 0)
		die();
	}

	if (xquad != old_xquad || yquad != old_yquad) {
	    galaxy[xquad][yquad].known = 1;
	    if (notfirstcall) {
		plt_gal(ELEMENT, old_xquad, old_yquad);
	        plt_gal(ELEMENT, xquad, yquad);
	    }

	    for (i = 0; i < 8; i++)
		for (j = 0; j < 8; j++)
		    quadrant[i][j] = EMPTY;

	    quadrant[xsect][ysect] = PLAYER;

	    for (n = 0; n < galaxy[xquad][yquad].nkling; n++) {
		for (;;) {
		    if (quadrant[i = rnd(7)][j = rnd(7)] == EMPTY) {
			quadrant[i][j] = KLINGON;
			break;
		    }
		}
		klingon[n].xs = i;
		klingon[n].ys = j;
		klingon[n].sh = 200;
	    }

	    for (; n < 3; n++)
		klingon[n].xs = klingon[n].ys = klingon[n].sh = -1;

	    for (n = 0; n < galaxy[xquad][yquad].nbase; n++)
		for (;;) {
		    if (quadrant[i = rnd(7)][j = rnd(7)] == EMPTY) {
			quadrant[i][j] = STARBASE;
			base_xsect = i;
			base_ysect = j;
			break;
		    }
		}

	    for (n = 0; n < galaxy[xquad][yquad].nstar; n++)
		for (;;) {
		    if (quadrant[i = rnd(7)][j = rnd(7)] == EMPTY) {
			quadrant[i][j] = STAR;
			break;
		    }
		}

	    old_xquad = xquad;
	    old_yquad = yquad;
	    if (notfirstcall) {
	        plt_srs(INFO);
	        plt_stat(ELEMENT, CONDITION);
	        plt_stat(ELEMENT, QUADRANT);
	        plt_gal(ELEMENT, xquad, yquad);
	    }
	}
	else {
	    switch (quadrant[xsect][ysect]) {

	    case KLINGON:
		dam = rnd(20) + 90;
		if (damkling(xsect, ysect, dam) != DEAD) {
		    xsect = old_xsect;
		    ysect = old_ysect;
		}
		dam >>= 1;
		if ((shields -= dam) < 0)
		    die();
		fixdev(REL, RND, -dam);
		plt_stat(ELEMENT, SHIELDS);
		break;

	    case STAR:
		readout(ADDLINE, "There's a star in the way, Duncel!");
		if (damage[SRS] > 0)
		    strcpy(captain, "Duncel");
		xsect = old_xsect;
		ysect = old_ysect;
		break;

	    case STARBASE:
		xsect = old_xsect;
		ysect = old_ysect;
		readout(ADDLINE, "There's a star base in the way!");
		break;
	    }

	    status = quadrant[xsect][ysect];
	    quadrant[old_xsect][old_ysect] = EMPTY;
	    quadrant[xsect][ysect] = PLAYER;
	    plt_srs(ELEMENT, old_xsect, old_ysect);
	    plt_srs(ELEMENT, xsect, ysect);
	}
	old_xsect = xsect;
	old_ysect = ysect;
	if (notfirstcall)
	    plt_stat(ELEMENT, SECTOR);
	notfirstcall = 1;

	return status;
}

/* "So this is it.  We're going to die." -- Arthur Dent */
die()
{
	char str[10];

	plt_stat(ELEMENT, SHIELDS);
	prompt("(Press RETURN)");
	while (getch() != '\r')
	    ;
	cls();
	moveyx(11, 21);
	printf("Your ship the %s has been destroyed.", shipname);
	moveyx(12, 21);
	printf("The Federation will be conquered.\n\n\n\r");
	vexit(0);
}

win()
{
	char str[10];

	readout(ADDLINE, "Congratulations!");
	prompt("(Press RETURN)");
	while (getch() != '\r')
	    ;
	cls();
	moveyx(11, 16);
	printf("The last of the Klingon battle cruisers have been\n");
	printf("%15sdestroyed.  You alone have saved the Federation.  You\n", "");
	printf("%15sare promoted to Admiral %s !!!\n\n\n\r", "", captain);
	vexit(0);
}

/* random (?) number generator */
rnd(max)
int max;
{
#ifdef AZTEC
	static long iy = 0x86A186A1;

	iy *= 125;
	iy &= 0x7FFFFFFF;
	iy %= 0xAAAAAAAd;

	return (int)((iy >> 8) % max);
#else
	return (int)(rand() % max);
#endif
}

#ifdef UNIX
/* randomize */
randomize()
{
	srand(time(0));
}
#endif

/* impulse drive -- move one sector */
impulse(dir)
int dir;
{
	int dx, dy, status;

	if (energy <= 0) {
	    readout(ADDLINE, "Insufficient energy for command.");
	    return ERROR;
	}

	if (checkdir(dir, &dx, &dy) != ERROR) {
	    xsect += dx;
	    ysect += dy;
	}

	energy--;
	status = setpos();
	plt_stat(ELEMENT, ENERGY);

	return status;
}

/* defense -- set shield level */
defense()
{
	int i;

	if (damage[DEFENSE] <= 0)
	    readout(ADDLINE, "Defense control is damaged.");
	else {
	    energy += shields;
	    for (;;) {	
	        prompt("Shield level ? ");
	        if ((shields = getnum()) >= 0 && shields <= energy) {
	            energy -= shields;
		    break;
		}
	    }
	    if (shields > 0) {
		playership[0] = '(';
		playership[2] = ')';
	    }
	    else {
		playership[0] = ' ';
		playership[2] = ' ';
	    }
	    plt_srs(ELEMENT, xsect, ysect);
	    plt_stat(ELEMENT, SHIELDS);
	    plt_stat(ELEMENT, ENERGY);
	}
}

/* get a number */
getnum()
{
	int num = 0, ch;

	while ((ch = getch()) != '\r') {
	    putch(ch);
	    if (isdigit(ch))
		num = num * 10 + ch - '0';
	    else if (ch == '\b') {
		num = num / 10;
		putch(' ');
		putch('\b');
	    }
	    else
		break;
	}

	return num;
}

/* damage a klingon */
damkling(xs, ys, dam)
int xs, ys, dam;
{
	char str[40];
	int k;

	if ((k = findkling(xs, ys)) == ERROR)
	    readout(ADDLINE, "damkling: error");
	else {
	    if (dam != AUTOKILL) {
	        sprintf(str, "You did %d to the Klingon.", dam);
	        readout(ADDLINE, str);
	    }

	    if ((klingon[k].sh -= dam) < 0) {
		readout(ADDLINE, "Klingon destroyed.");
		klingon[k].xs = klingon[k].ys = -1;
		quadrant[xs][ys] = EMPTY;
		plt_srs(ELEMENT, xs, ys);
		numkling--;
		plt_num(INFO);
		galaxy[xquad][yquad].nkling--;
		plt_gal(ELEMENT, xquad, yquad);

		return DEAD;
	    }
	}

	return ALIVE;
}

/* fix/damage a device */
fixdev(type, dev, value)
int type;	/* ABSolution fix or RELative fix */
int dev;	/* device (if RND then pick a damaged device) */
int value;	/* new device value for ABS, amount to add for REL */
{
	int i, old_dam;

	if (dev == RND) {
	    dev = rnd(8);
	    if (value > 0 && damage[dev] >= 100) {
		for (i = 0; i < 8; i++) {
		    if (++dev > 7)
			dev = 0;
		    if (damage[dev] < 100)
			break;
		}
	    }
	}

	old_dam = damage[dev];

	if (type == ABS)
	    damage[dev] = value;
	else
	    damage[dev] += value;

	if (damage[dev] > 100)
	    damage[dev] = 100;

	plt_dam(ELEMENT, dev);

	/* see if device changed from fixed <==> broken */
	if ((old_dam <= 0 && damage[dev] > 0) || (old_dam > 0 && damage[dev] <= 0)) {
	    switch (dev) {
	    case SRS :
	        plt_srs(INFO);
	        break;
	    case DAMAGE :
	        plt_dam(INFO);
	        break;
	    case COMPUTER :
	        plt_gal(INFO);
	        break;
	    }
	}
}

/* print a prompt in the upper left hand corner */
prompt(str)
char *str;
{
	int i;

	moveyx(1, 1);
	for (i = 0; i < 26; i++)
	    putch(' ');
	moveyx(1, 1);
	printf("%-.26s", str);
}

/* check a direction for validity and return delta-x and delta-y */
checkdir(dir, dx, dy)
int dir, *dx, *dy;
{
	static struct {
	    int d, x, y;
	} dirs[8] = {
	    {'Q', -1, -1}, {'W', 0, -1}, {'E', 1, -1}, {'D', 1, 0},
	    {'C', 1, 1}, {'X', 0, 1}, {'Z', -1, 1}, {'A', -1, 0}
	};
	int i;

	for (i = 0; i < 8; i++)
	    if (dirs[i].d == dir) {
		*dx = dirs[i].x;
		*dy = dirs[i].y;
		return 0;
	    }

	return ERROR;
}

/* hyperspace drive */
hyperspace()
{
	int i, dir, dx, dy, w, tmp, savex, savey;

	if (damage[WARP] <= 0)
	    readout(ADDLINE, "Warp engines are damaged.");
	else {
	    prompt("Direction ? ");
	    if (islower(dir = getch()))
		dir = toupper(dir);
	    if (checkdir(dir, &dx, &dy) == ERROR) {
		readout(ADDLINE, "Illegal direction.");
		return;
	    }

	    prompt("Warp ? ");
	    putch(w = getch());
	    if (isdigit(w)) {
		w -= '0';
	        if (w <= 0)
		    return;
	        savex = xsect;
	        savey = ysect;
	        while ((tmp = xsect + dx) >= 0 && tmp <= 7 && (tmp = ysect + dy) >= 0 && tmp <= 7) {
		    if (impulse(dir))
		        return;
	        }
	        if (energy < 20 * w)
		    readout(ADDLINE, "Insufficient energy for command.");
	        else {
	            xquad += w * dx;
	            yquad += w * dy;
	            energy -= 20 * w;
		    stardate += (double)(w) / 5.0;
	            xsect = savex;
	            ysect = savey;
	            setpos();
	            plt_stat(ELEMENT, ENERGY);
	        }
	    }
	    else if (w == '.' && isdigit(w = getch())) {
		putch(w);
		w -= '0';
		stardate += (double)(w) / 50.0;
		for (; w > 0; w--)
		    if (impulse(dir))
			break;
	    }
	    else
		readout(ADDLINE, "Illegal warp factor.");
	}
}

/* long range scan */
lrs()
{
	int x, y;
	char str[20];

	if (damage[LRS] <= 0)
	    readout(ADDLINE, "Long range sensors are damaged.");
	else {
	    if (rolines > 3)
		readout(CLEAR, NULL);

	    for (y = yquad - 1; y <= yquad + 1; y++) {
		readout(ADDLINE, "+---+---+---+");
		strcpy(str, "|");
		for (x = xquad - 1; x <= xquad + 1; x++) {
		    if (x < 0 || x > 7 || y < 0 || y > 7)
			strcat(str, "XXX");
		    else {
			if (damage[COMPUTER] > 0)
			    galaxy[x][y].known = 1;
			sprintf(str + strlen(str), "%d%d%d", galaxy[x][y].nkling,
			galaxy[x][y].nbase, galaxy[x][y].nstar);
			plt_gal(ELEMENT, x, y);
		    }
		    strcat(str, "|");
		}
		str[13] = '\0';
		readout(ADDLINE, str);
	    }

	    readout(ADDLINE, "+---+---+---+");
	    plt_gal(ELEMENT, xquad, yquad);
	}
}

/* short range scan */
srs()
{
	int k, dx, dy;
	double dir, dist;
	char str[40];

	if (damage[SRS] <= 0)
	    readout(ADDLINE, "Short range sensors are damaged.");
	else {
	    if (rolines > 6)
		readout(CLEAR, NULL);
	    readout(ADDLINE, "Sector  Direction  Distance");
	    for (k = 0; k < 3; k++) {
		if (klingon[k].sh >= 0) {
		    if (damage[COMPUTER] <= 0)
			sprintf(str, "[%d,%d]", klingon[k].xs+1, klingon[k].ys+1);
		    else {
			dx = klingon[k].xs - xsect;
			dy = klingon[k].ys - ysect;
			dist = sqrt((double)(dx*dx) + (double)(dy*dy));
			if (dx) {
			    dir = atan2(-(double)dy, (double)dx) * 180.0 / PI;
			    if (dir < 0.0)
				dir += 360.0;
			}
			else if (dy > 0)
			    dir = 270.0;
			else
			    dir = 90.0;
			sprintf(str, "[%d,%d]     %5.1f      %4.1f", klingon[k].xs+1,
			klingon[k].ys+1, dir, dist);
		    }
		    readout(ADDLINE, str);
		}
	    }
	}
}

findkling(x, y)
int x, y;
{
	int i;

	for (i = 0; i < 3; i++)
	    if (x == klingon[i].xs && y == klingon[i].ys)
		return i;

	return ERROR;
}
!EOF!
echo x - sub2.c
cat >sub2.c << '!EOF!'
/* sub2.c -- subroutines for visual star trek */

#include "vtrek.h"

/* klingon movement and firing */
klingmove()
{
	int k, dx, dy, dam, kx, ky, nx, ny, i, j;
	int minj, mind, d, sk;
	static int dirx[9] = {1, 1, 0, -1, -1, -1, 0, 1, 0};
	static int diry[9] = {0, 1, 1, 1, 0, -1, -1, -1, 0};
	double dist;
	char str[40];

	for (k = 0; k < 3; k++) {
	    if (klingon[k].sh < 0)
		continue;
	    kx = klingon[k].xs;
	    ky = klingon[k].ys;

	    /* movement */
	    if (rnd(100) < 30 + skill * 5) {
		for (i = 0; i < numkmove; i++) {
		    mind = 999;
		    minj = -1;
		    for (j = 0; j < 9; j++) {
			nx = kx + dirx[j];
			ny = ky + diry[j];
			if (nx < 0 || nx > 7 || ny < 0 || ny > 7)
			    continue;
			if (quadrant[nx][ny] != EMPTY)
			    continue;
			dx = xsect - nx;
			dy = ysect - ny;
			d = dx * dx + dy * dy;
			if (d < mind) {
			    mind = d;
			    minj = j;
			}
		    }

		    if (minj < 0)
			break;

		    nx = kx + dirx[minj];
		    ny = ky + diry[minj];
		    quadrant[kx][ky] = EMPTY;
		    quadrant[nx][ny] = KLINGON;
		    plt_srs(ELEMENT, nx, ny);
		    plt_srs(ELEMENT, kx, ky);
		    kx = nx;
		    ky = ny;
		}
		klingon[k].xs = kx;
		klingon[k].ys = ky;
	    }

	    /* fire disrupters */
	    dx = kx - xsect;
	    dy = ky - ysect;
	    dist = sqrt((double)(dx * dx) + (double)(dy * dy));
	    dam = (rnd(100) + 100 + skill * 20) / dist;
	    if (damage[SRS] > 0)
	        sprintf(str, "Klingon at [%d,%d] hits with %d units.", kx+1,
		ky+1, dam);
	    else
		sprintf(str, "Klingon hits with %d units.", dam);
	    readout(ADDLINE, str);
	    if (condition == DOCKED)
		readout(ADDLINE, "Starbase shields protect you!");
	    else {
		if ((shields -= dam) < 0)
		    die();
		sk = skill * 250;
		if (shields <= 500 + sk)
		    fixdev(REL, RND, -dam / 2);
		else if (shields < 1500 + sk)
		    fixdev(REL, RND, -(1500 + sk - shields) * dam / 2000);
	    }
	}

	plt_stat(ELEMENT, SHIELDS);
}

/* fire phasers */
phasers()
{
	int dam, k, dx, dy, e, kx, ky;
	char str[40];
	double dist;

	if (damage[PHASER] < 0)
	    readout(ADDLINE, "Phasers are damaged.");
	else {
	    for (k = 0; k < 3; k++) {
		if (klingon[k].sh < 0)
		    continue;
		kx = klingon[k].xs;
		ky = klingon[k].ys;

		if (damage[SRS] > 0) {
		    sprintf(str, "Units aimed at [%d,%d] : ", kx + 1, ky + 1);
		    prompt(str);
		}
		else
		    prompt("Units aimed at [?,?] : ");
		e = getnum();
		dx = kx - xsect;
		dy = ky - ysect;
		dist = sqrt((double)(dx * dx) + (double)(dy * dy));
		dam = e / dist;

		if (energy < e)
		    readout(ADDLINE, "Insufficient energy for command.");
		else {
		    energy -= e;
		    damkling(kx, ky, dam);
		    plt_stat(ELEMENT, ENERGY);
		}
	    }
	}
}

/* set condition */
setcondition()
{
	int dx, dy, i, oldcond;
	int plotgal, plotsrs;

	oldcond = condition;

	if (galaxy[xquad][yquad].nkling)
	    condition = RED;
	else if (shields < 100) {
	    condition = YELLOW;
	    if (oldcond != DOCKED)
	        readout(ADDLINE, "Captain, shields are dangerously low.");
	}
	else
	    condition = GREEN;

	if (galaxy[xquad][yquad].nbase) {
	    dx = xsect - base_xsect;
	    dy = ysect - base_ysect;
	    if (abs(dx) <= 1 && abs(dy) <= 1) {
		condition = DOCKED;
		if (oldcond != DOCKED) {
		    energy = 3000;
		    torps = 10;
		    shields = 0;
		    plotsrs = damage[SRS] <= 0;
		    plotgal = damage[COMPUTER] <= 0;
		    for (i = 0; i < 8; i++)
		        damage[i] = 100;
		    readout(ADDLINE, "Shields lowered for docking.");
		    playership[0] = playership[2] = ' ';
		    plt_srs(ELEMENT, xsect, ysect);
		    plt_stat(INFO);
		    plt_dam(INFO);
		    if (plotsrs)
			plt_srs(INFO);
		    if (plotgal)
		        plt_gal(INFO);
		    oldcond = DOCKED;
		}
	    }
	}

	if (oldcond != condition)
	    plt_stat(ELEMENT, CONDITION);
}

/* move torp to a sector and see if it hit */
mvtorp(x, y)
int x, y;
{
	int ch, status = ALIVE;
	char str[40];

	ch = quadrant[x][y];
	quadrant[x][y] = TBLAST;
	plt_srs(ELEMENT, x, y);

	switch (ch) {
	case EMPTY :
	    break;
	case KLINGON :
	    damkling(x, y, AUTOKILL);
	    status = DEAD;
	    break;
	case STARBASE :
	    readout(ADDLINE, "Starbase destroyed.");
	    galaxy[xquad][yquad].nbase--;
	    numbases--;
	    plt_num(INFO);
	    status = DEAD;
	    break;
	case STAR :
	    sprintf(str, "Star at [%d,%d] has gone supernova.", x + 1, y + 1);
	    readout(ADDLINE, str);
	    galaxy[xquad][yquad].nstar--;
	    status = DEAD;
	    break;
	}

	if (status == DEAD)
	    ch = EMPTY;
	quadrant[x][y] = ch;
	plt_srs(ELEMENT, x, y);

	return status;
}

/* fire a torpedo */
torpedo()
{
	int dir, i, ch, x, y;
	int dx, dy;
	double th;
	static char dirstr[] = "DEWQAZXC";

	if (damage[TUBES] < 0)
	    readout(ADDLINE, "Photon torpedo tubes are damaged.");
	else if (torps < 1)
	    readout(ADDLINE, "You're out of photon torpedos!");
	else {
	    torps--;
	    plt_stat(ELEMENT, TORPS);
	    prompt("Direction ? ");
	    dir = getch();
	    if (isdigit(dir)) {
		putch(dir);
		dir -= '0';
		while ((ch = getch()) != '\r') {
		    putch(ch);
		    if (isdigit(ch))
			dir = dir * 10 + ch - '0';
		    else
			break;
		}
	    }
	    else {
		ch = Toupper(dir);
		dir = 0;
		for (i = 0; i < 8; i++) {
		    if (ch == dirstr[i])
			break;
		    dir += 45;
		}
		if (i >= 8) {
		    readout(ADDLINE, "Illegal direction.");
		    return;
		}
	    }

	    th = dir / 180.0 * PI;
	    if (dir >= 315 || dir <= 45 || (dir >= 135 && dir <= 225)) {
		dx = (dir >= 315 || dir <= 45) ? 1 : -1;
		for (x = xsect + dx; x >= 0 && x <= 7; x += dx) {
		    y = ysect - (x - xsect) * tan(th) + 0.5;
		    if (y < 0 || y > 7)
			break;
		    if (mvtorp(x, y) == DEAD) {
			break;
		    }
		}
	    }
	    else {
		th -= PI / 2.0;
		dy = (dir >= 45 && dir <= 135) ? -1 : 1;
		for (y = ysect + dy; y >= 0 && y <= 7; y += dy) {
		    x = xsect + (y - ysect) * tan(th) + 0.5;
		    if (x < 0 || x > 7)
			break;
		    if (mvtorp(x, y) == DEAD)
			break;
		}
	    }
	}
}

/* repair devices somewhat */
repdevices()
{
	int i;

	for (i = 0; i < 8; i++)
	    fixdev(REL, i, 5);
}

/* out of star dates */
timeout()
{
	char str[44];

	readout(CLEAR);
	readout(ADDLINE, "You have run out of stardates an there");
	sprintf(str, "are still %d Klingons left.  Some captain you", numkling);
	readout(ADDLINE, str);
	readout(ADDLINE, "are.");
	die();
}

/* out of energy */
dead()
{
	readout(CLEAR);
	readout(ADDLINE, "Your ship is dead in space.  Eventually,");
	readout(ADDLINE, "Klingons show up and relieve you of your");
	readout(ADDLINE, "task . . .");
	die();
}

/* reset terminal and exit program */
vexit(status)
{
	termreset();
	exit(status);
}
!EOF!
echo x - termio.c
cat >termio.c << '!EOF!'
/* terminal I/O */

#include "vtrek.h"

#ifdef AZTEC

/* These constants are at the beginning so they will be easy to find with */
/* DDT.  They will be a 0103 and 0107 if this file is loaded first. */
char cm[4] = "\033=";		/* cursor movement string */
char cl[4] = "\032";		/* clear screen string */

#else /* UNIX */
#include <sgtty.h>

static int saveflags;
static char cl[5], cm[20], bp[1024], name[20];
char PC, BC[5], UP[5];
#endif

/* initialize the termimal mode */
terminit()
{
#ifdef UNIX
	struct sgttyb tty;
	char *p, *getenv();

	if (p = getenv("TERM"))
	    strcpy(name, p);
	else {
	    fprintf(stderr, "TERM not set\n");
	    exit(1);
	}
	if (tgetent(bp, name) != 1) {
	    fprintf(stderr, "Can't get termcap entry\n");
	    exit(1);
	}
	p = cm;
	tgetstr("cm", &p);
	p = cl;
	tgetstr("cl", &p);
	p = UP;
	tgetstr("up", &p);
	p = BC;
	tgetstr("bc", &p);
	gtty(0, &tty);
	saveflags = tty.sg_flags;
	tty.sg_flags |= RAW;
	tty.sg_flags &= ~(ECHO | XTABS);
	stty(0, &tty);
#endif
}

/* reset the terminal mode */
termreset()
{
#ifdef UNIX
	struct sgttyb tty;

	gtty(0, &tty);
	tty.sg_flags = saveflags;
	stty(0, &tty);
#endif
}

/* get a character from the terminal */
getch()
{
#ifdef AZTEC
	int ch;
	while ((ch = CPM(6, 0xff)) == 0)
	    ;
	return ch;
#else /* UNIX */
	return getchar() & 0177;
#endif
}

/* write a character */
putch(ch)
int ch;
{
#ifdef AZTEC
	CPM(6, ch);
#else /* UNIX */
	putchar(ch);
#endif
}

#ifdef AZTEC
/* see if a character is ready to be read */
chready()
{
	return CPM(11, 0);
}
#endif

/* move cursor */
moveyx(ypos,xpos)
int ypos,xpos;
{
#ifdef AZTEC
	printf("%s%c%c", cm, ypos+31, xpos+31);
#else /* UNIX */
	fputs(tgoto(cm, xpos - 1, ypos - 1), stdout);
#endif
}

/* clear screen */
cls()
{
	fputs(cl, stdout);
}
!EOF!
echo x - vtrek.doc
cat >vtrek.doc << '!EOF!'




                <<< Instructions for Star Trek >>>

           The galaxy is divided into a 8 X 8 quadrant grid, and
        each quadrant is further divided into a 8 X 8 sector grid.
           You will be assigned a starting point somewhere in the
        galaxy. Your mission : To seek out and destroy the fleet of
        Klingon warships which are menacing the Federation of Planets.

           You will have the following commands available to you as
        captain :

                'D','E','W','Q','A','Z','X','C' , the keys around the
                      'S' on the keyboard control your direction. When
                      you are asked for the direction, type one of these.

                                Q  W  E
                                 \ | /
                                  \|/
                               A --S-- D
                                  /|\
                                 / | \
                                Z  X  C

                'H' , Hyper-space , used when you want to travel a
                      large distance. The direction is set by typing
                      one of the keys around the 'S'. The warp factor
                      can be a number from 0-8.

                'S' , Short range scan , tells you the direction and
                      the distance that the Klingons are from you.
                      Anytime that your Short range sensors are working,
                      you will have a display of your quadrant on the
                      screen. The following symbols are used on the
                      display :

                                <K> - Klingon
                                <S> - Star Base (refuel/repair/re-arm here)
                                 *  - star
                                 ?  or (?) - you (? is the 1st letter of your
                                             ship name.)

                'L'   Long range scan.  Shows conditions in space for
                      one quadrant on each side of you (your in the
                      middle of the scan). The scan prints out up to
                      three digits for each quadrant.  The one's digit
                      is the number of stars, then tens digit is the
                      number of star bases, and the hundred's digit is
                      the number of Kilngons.

                      EXAMPLE : 207 , 2 Klingons, 0 star bases, 7 stars

                'P'   Fire phasers.  Allows you to destroy the Klingon
                      warships by zapping them with suitable amounts of
                      energy.

                'T'   Fire photon torpedo's.  Torpedo course is selected
                      by typing one of the keys around the 'S'. If the
                      torpedo hits the Klingon, he will be destroyed.

                'U'   Defense control.  Allows you to raise or lower your
                      shields. The power to your shields drops as you are
                      hit. If you are hit with your shields all the way
                      down (0), you WILL be destroyed. When your shields
                      up you will have paretheses around your ship.

		'F'   Fix devices.  This allows you to repair damaged devices
		      at a faster pace than normally.

                'R'   Redraw the screen.

           Impulse power can be used by typing one of the direction
        keys around the 'S'. This moves you the same distance as 
        Hyper-space with a warp of 0.1.
           In the upper right of the screen is a damage report. If
        something is damaged it will have a negative number beside it.
        If an item is damaged, you won't be able to use it.

!EOF!
echo x - vtrek.h
cat >vtrek.h << '!EOF!'
/* vtrek.h -- header file for visual star trek */

#undef AZTEC				/* Aztec C */
#define UNIX				/* Unix */

#ifdef AZTEC
#include "libc.h"
#include "math.h"
#endif
#ifdef UNIX
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#endif

#define VTREKINS	"vtrek.doc"	/* instructions */
#define ERROR		-1
#define PI		3.1415926
#define Toupper(x)	(islower(x) ? toupper(x) : x)
#define abs(x)		(x < 0 ? -x : x)

/* used for damaging klingon */
#define AUTOKILL	9999

/* used for fixing/damaging devices */
#define ABS		0		/* absolute fix */
#define REL		1		/* relative fix */
#define RND		-1		/* pick a random device */

/* status of a ship */
#define ALIVE		0		/* ship is still here */
#define DEAD		1		/* ship has been destroyed */

/* used for replot calls */
#define TEXT		1		/* replot text portion */
#define INFO		2		/* replot information portion */
#define ELEMENT		4		/* replot individual element */
#define ALL		(TEXT | INFO)	/* replot all */

/* legal condition values */
#define GREEN		0		/* everything OK */
#define YELLOW		1		/* reason to be cautious */
#define RED		2		/* eminent danger */
#define DOCKED		3		/* docked at base (no danger) */

/* legal quadrant values (used in s.r.s) */
#define EMPTY		0		/* sector is empty */
#define KLINGON		1		/* sector contains klingon */
#define STARBASE	2		/* sector contains star base */
#define STAR		3		/* sector contains star */
#define PLAYER		4		/* sector contains player */
#define TBLAST		5		/* torpedo */

/* legal damage control indices */
#define WARP		0		/* warp drive */
#define SRS		1		/* short range sensors */
#define LRS		2		/* long range sensors */
#define PHASER		3		/* phaser control */
#define DAMAGE		4		/* damage control */
#define DEFENSE		5		/* defense control (shields) */
#define COMPUTER	6		/* computer (galaxy map, calculations) */
#define TUBES		7		/* torpedo tubes */

/* legal status items */
#define STARDATE	0
#define CONDITION	1
#define QUADRANT	2
#define SECTOR		3
#define ENERGY		4
#define TORPS		5
#define SHIELDS		6

/* used for readout calls */
#define CLEAR		0		/* clear readout */
#define ADDLINE		1		/* add line to readout */

/* sructure used to store quandrant information */
typedef struct {
	char nkling;	/* number of klingons in quadrant */
	char nbase;	/* number of bases in quadrant */
	char nstar;	/* number of stars in quadrant */
	char known;	/* tells if info is known to player */
} QUADINFO;

/* structure used to store klingon information */
struct {
	int xs, ys;	/* sector coordinates */
	int sh;		/* shield level */
} klingon[3];

QUADINFO galaxy[8][8];	/* galaxy */
int numbases;		/* number of bases in galaxy */
int numkling;		/* number of klingons in galaxy */
int begkling;		/* beginning number of klingons */
int condition;		/* current condition (GREEN,YELLOW,RED,DOCKED) */
int xquad, yquad;	/* current quadrant */
int xsect, ysect;	/* current sector */
int old_xquad, old_yquad; /* quadrant before last movement */
int old_xsect, old_ysect; /* sector before last movement */
int energy;		/* energy level */
int shields;		/* shield level */
int torps;		/* number of torps left */
int quadrant[8][8];	/* current quadrant picture (EMPTY,KLINGON,STARBASE,STAR,PLAYER) */
extern int rolines;	/* number of lines used in current readout */
int damage[8];		/* % effectiveness of devices, normal range is 0-100 */
			/* if < 0 then device is damaged beyond use */
extern char playership[]; /* image of player's ship for s.r.s */
char captain[11];	/* captain's name */
char shipname[11];	/* ship's name */
float stardate;		/* current star date */
float lastdate;		/* last star date before federation is conquered */
float begdate;		/* beginning star date */
int base_xsect, base_ysect; /* starbase sector, if one is present */
int numkmove;		/* number of klingon moves allowed */
int skill;		/* skill level */
!EOF!
exit 0