[net.sources] new "fly" command for empire: source

mr-frog@sdcsvax.UUCP (05/16/84)

<>

Following is the source to a re-written "fly" command
for the game Empire.  See the net.games.emp article on
this subject for more information.


Dave Pare

[ucbvax | dcdwest]!sdcsvax!mr-frog

"A megaton of prevention..."
(Keith Laumer)




--------------------------- cut here -------------------------
echo x - FLY_ME
cat >FLY_ME << 'FunkyStuff'
How to install the new fly.c

You've probably already extracted all the stuff from the net posting
if you are reading this.  So your first step is already done.

1)	Unpack fly.c, the info page, and this document:
		% sh filename
	where "filename" is the name of the news article (remove header, please)
	Do not move it to the main empire source directory yet.

2)	Compile the new version of fly:
		% cc -O -c fly.c
	I've only tested fly on a VAX 750 under 4.2 BSD,
	so if you're running some wierd machine the cc may fail.

3)	Extract the old version (in case you want to save it) from
	empcom.a using ar:
		% ar x empsub.a fly.o
	This will create a "fly.o" binary in the current directory.
	Move this to somewhere safe if you want to keep it.

4)	Move the new fly.o into the empire source directory, (the file
	you compiled in step 2) and put it into empcom.a:
		% ar r empsub.a fly.o

5)	Update the library:
		% ranlib empsub.a

6)	Re-compile empire:
		% touch empdis.o ; make BIN/csh

7)	Move the fly info page to the INFO directory.  If you have the
	empire manual pre-nroffed, you'll have to format it first.

Now you can go run a bombing mission on someone's capitol.  Have fun.


Dave Pare

[ucbvax | dcdwest]!sdcsvax!mr-frog

FunkyStuff
echo x - fly
cat >fly << 'FunkyStuff'
.TH Command FLY
.SY "fly <SECT | SHIP> <SECT | none> <SECT | SHIP> planes"
.s1
The "fly" command represents one complete mission for one
or several planes, taking off from one place, attacking a target,
and (perhaps) landing in another place.
.s1
The arguments represent the ship/sector you take off from, your target
sector, the ship/sector you want to land on, and the number of
planes in the mission, respectively.
If the target sector is a harbor, the program will ask you if you
wish to bomb a ship, or a land target.
If your target sector is sea, then the program will assume you wish
to bomb a ship.
If you make an error, the program will assume that you wish your pilots
to dump the bombs in the land (or ocean) sector, and then return to base.
.s1
If the target sector is within range, but the landing sector is farther
away than the round-trip range of your plane, then the program will ask
if you would like to perform a kamakazi mission.
If your response is yes, the pilots will go off, bomb the target,
and die soon afterwards.
In order to make up for their rather expensive nature,
kamakazi missions are noticeably more effective than are normal
bombing missions.
.s1
If you type "none" instead of a target sector, the program will
execute a "transport" mission instead, carrying no bombs, and
moving directly to the "return-to" sector.
This mission still costs oil and mobility, and has a side-effect
of transporting military to the destination sector.
.s1
Planes can only take off and land from either an airport,
or an aircraft carrier.
Any other sector or ship will not be able to either recieve or
launch planes.
.s1
If not specified on the command line, the program requests information
as to the number of planes on the mission.
Each plane needs one fuel unit, one military (for crew), and 1/2 mobility
unit (rounded up) upon take-off.
If you don't have enough of any one commodity, then the program will let
you know, and tell you how many planes are available.
.s1
If the "return-to" sector would be filled to overflowing (i.e. greater
than 999 for a sector, and greater than 40 planes for a carrier) by
the landing of planes there, the mission will be scrubbed.
.s1
When you bomb, the damage done depends on your tech level.
The damage done by each bomb is tech factor * 15,
with modifications as to ship armor and the target's tech level.
.s1
When you bomb other sectors or ships owned by other countries,
their guns will fire at your attacking planes before any bombs have
been dropped, with varying chances of hitting.
Fortresses, capitals and airfields all fire on "foreign" aircraft
(assuming they have the guns & shells).
The greater their tech level in relation to yours, the better chance
they'll have of hitting your planes.
A maximum of 14 shots can be fired from any given land sector,
and from 1 to 4 shots from each ship in the sector, depending on
the ship type.
For instance, a heavy cruiser has 3 AA shots, a patrol boat has 1, and
a battleship has 4.
FunkyStuff
echo x - fly.c
cat >fly.c << 'FunkyStuff'
/*
 * fly.c
 *
 * Version 1.0
 *
 * Dave Pare
 * UCSD Phonetics Lab
 *
 * May 1984
 */


#define NULL 0

#define D_DCHRSTR
#define D_FILES
#define D_MCHRSTR
#define D_NATSTAT
#define D_NATSTR
#define D_NEWSVERBS
#define D_SCTSTR
#define D_SECTDES
#define D_SHPSTR
#define D_SHIPTYP
#define D_UPDATE
#define D_VTYPES
#include "../empdef.h"


/*
 * fly <SECT/SHIP> <SHIP | SECT> <return-to-sect/ship> #planes
 *        from        target             base
 */

fly() {
	extern	int mapdist();
	extern	char *fmt();
	extern	char *getstarg();
	extern	char *getstring();
	extern	float tfact();
	extern	short sx, sy;
	extern	short cnum;
	extern	struct sctstr sect;
	extern	struct dchrstr dchr[];
	extern	struct mchrstr mchr[];
	struct	shpstr ship;
	float	armor;
	char	*bp;
	int	i;
	int	tmp;
	int	peaceful = 0;
	int	kamakazi = 0;
	int	range_to_target;
	int	range_to_base;
	int	plane_range;
	int	victim;
	int	fromx, fromy, fromship;
	int	basex, basey, baseship;
	int	targx, targy, targship;
	int	mission, hopeful;
	int	planes;
	int	military;
	int	damage;
	int	shells;
	int	fuel;
	int	mobility;

	fromship = -1;
	targship = -1;
	baseship = -1;
	plane_range = (tfact(cnum, 1.0) * 32);
	pr(fmt("max range: %d\n", plane_range));
	bp = getstarg(argp[1], "from? ");
	if (bp == NULL || *bp == NULL)
		return R_OK;
	if (index(bp, ',')) {
		/*
		 * get the sector to launch from
		 */
		i = getsno(bp);
		if (i == -1)
			return R_OK;
		fromx = sx;
		fromy = sy;
		if (getmysect(fromx, fromy, UP_OWN) == -1)
			return R_OK;
		if (sect.sct_type != SCT_AIRPT) {
			pr("That's not an airport!\n");
			return R_OK;
		}
		bp = (char *) &sect;
		mobility = sect.sct_mobil;
	} else {
		/*
		 * get the ship to launch from
		 */
		fromship = atoi(bp);
		if (fromship < 0) {
			pr("must be a positive value!\n");
			return R_OK;
		}
		if (getmyship(fromship, &ship) == -1)
			return R_OK;
		if (ship.shp_type != SHP_A) {
			pr("That's not an aircraft carrier!\n");
			return R_OK;
		}
		bp = (char *) &ship;
		fromx = ship.shp_x;
		fromy = ship.shp_y;
		mobility = ship.shp_mobil;
	}
	/*
	 * make sure all the needed supplies are there
	 * note that "shells" aren't needed because of
	 * the "transport" mission possibility
	 */
	if (mobility <= 0) {
		pr("There's no mobility there.\n");
		return R_OK;
	}
	planes = getvar(V_PLANE, bp);
	if (planes == 0) {
		pr("There aren't any planes there!\n");
		return R_OK;
	}
	fuel = getvar(V_OIL, bp);
	if (fuel == 0) {
		pr("You need fuel (oil) to fly!\n");
		return R_OK;
	}
	shells = getvar(V_SHELL, bp);
	military = getvar(V_MILIT, bp);
	if (military == 0) {
		pr("There's no crew for the planes!\n");
		return R_OK;
	}
	/*
	 * target must be a sector, or a "none"
	 */
	bp = getstarg(argp[2], "target sector? ");
	if (bp == NULL || *bp == NULL)
		return R_OK;
	if (strcmp(bp, "none") == 0) {
		range_to_target = 0;
		peaceful++;
		targx = fromx;
		targy = fromy;
	} else if (getsno(bp) == -1)
		return R_OK;
	else {
		targx = sx;
		targy = sy;
		if ((targx + targy) % 2) {
			pr("That's inbetween sectors!\n");
			return R_OK;
		}
		range_to_target = mapdist(fromx, fromy, targx, targy);
		if (range_to_target > plane_range) {
			pr("But sir, the planes won't make it that far!\n");
			return R_OK;
		}
	}
	/*
	 * return-to can either be a ship or a sector
	 */
	bp = getstarg(argp[3], "return-to? ");
	if (bp == NULL || *bp == NULL)
		return R_OK;
	if (index(bp, ',') == 0) {
		/*
		 * get the ship to land on
		 * make sure it's an aircraft carrier
		 */
		baseship = atoi(bp);
		if (getship(baseship, &ship) == -1) {
			pr(fmt("No such ship %s\n", baseship));
			return R_OK;
		}
		if (ship.shp_own != cnum) {
			pr("That's not your ship!\n");
			return R_OK;
		}
		if (ship.shp_type != SHP_A) {
			pr("That'll be hard to land on!\n");
			return R_OK;
		}
		basex = ship.shp_x;
		basey = ship.shp_y;
	} else {
		/*
		 * get the sector to land on
		 * make sure it's an airport
		 */
		i = getsno(bp);
		if (i == -1)
			return R_OK;
		basex = sx;
		basey = sy;
		if ((basex + basey) % 2) {
			pr("That's inbetween sectors!\n");
			return R_OK;
		}
		if (getmysect(basex, basey, UP_OWN) == -1)
			return R_OK;
		if (sect.sct_type != SCT_AIRPT) {
			pr("That's not an airport!\n");
			return R_OK;
		}
	}
	/*
	 * check round-trip range; kamakazi if max plane range
	 * isn't quite up to the journey
	 */
	range_to_base = mapdist(basex, basey, targx, targy);
	if (range_to_target + range_to_base > plane_range) {
		if (peaceful) {
			pr("The planes won't make it that far, sir!\n");
			return R_OK;
		}
		bp = getstring("Kamakazi mission, sir? ");
		if (bp == NULL || (*bp != 'y' && *bp != 'Y')) {
			pr("Mission scrubbed.\n");
			return R_OK;
		}
		kamakazi++;
	}
	bp = getstarg(argp[4], "# of planes to fly? ");
	if (bp == NULL || *bp == NULL)
		return R_OK;
	hopeful = mission = atoi(bp);
	if (mission <= 0)
		return R_OK;
	/*
	 * we use 1 fuel per plane, 1 military (crew) per plane,
	 * 1/2 mobility unit per plane, and 1 shell per plane
	 */
	mission = min(planes, mission);
	mission = min(fuel, mission);
	mission = min(mobility*2, mission);
	if (!peaceful)
		mission = min(shells, mission);
	mission = min(military, mission);
	/*
	 * all this muck checks to make sure that the
	 * planes and military can fit on the return-to sector
	 */
	if (baseship < 0 && basex != fromx && basey != fromy) {
		getsect(basex, basey, UP_NONE);
		if (getvar(V_PLANE, &sect) + mission > 999) {
			pr("Base sector cannot hold that many planes\n");
			return R_OK;
		}
		if (peaceful && getvar(V_MILIT, &sect) + mission > 999) {
			pr("Base sector cannot hold that many military\n");
			return R_OK;
		}
	} else if (baseship != fromship) {
		getship(baseship, &ship, UP_NONE);
		if (getvar(V_PLANE, &ship) + mission > getvar(V_PLANE, &mchr[ship.shp_type])) {
			pr("Base ship cannot hold that many planes\n");
			return R_OK;
		}
		if (peaceful && getvar(V_MILIT, &ship) + mission > getvar(V_MILIT, &mchr[ship.shp_type])) {
			pr("Base ship cannot hold that many military\n");
			return R_OK;
		}
	}
	if (!mission) {
		pr("We could not equip any planes for the mission.\n");
		return R_OK;
	}
	/*
	 * if we couldn't satisfy (for whatever reason) the request
	 * fully, tell him.
	 */
	if (mission != hopeful) {
		pr(fmt("We can only equip %d planes.\n",mission));
		bp = getstring("Shall we launch it, sir? ");
		if (bp == NULL || (*bp != 'y' && *bp == 'Y')) {
			pr("Scrubbing the mission.\n");
			return R_OK;
		}
	}
	/*
	 * subtract mobility from the sector or ship in question
	 * and prepare to update the sector goodies
	 */
	if (fromship >= 0) {
		getship(fromship, &ship, UP_OWN);
		ship.shp_mobil = ship.shp_mobil - (int) (mission/2.0 + .5);
		bp = (char *) &ship;
	} else {
		getsect(fromx, fromy, UP_OWN);
		sect.sct_mobil = sect.sct_mobil - (int) (mission/2.0 + .5);
		bp = (char *) &sect;
	}
	putvar(V_PLANE, planes - mission, bp, 0);
	putvar(V_OIL, fuel - mission, bp, 0);
	if (!peaceful)
		putvar(V_SHELL, shells - mission, bp, 0);
	putvar(V_MILIT, military - mission, bp, 0);
	/*
	 * update the "from" sector or ship.  The commodities
	 * are now gone.  If the unfortunate player hits delete,
	 * he loses the mission
	 */
	if (fromship >= 0)
		putship(fromship, &ship);
	else
		putsect(fromx, fromy);
	getsect(targx, targy, UP_GOD);
	/*
	 * if it's a peaceful mission, jump around all the
	 * bombing code
	 */
	if (peaceful)
		goto cargo;
	/*
	 * maybe I should make this more inexact?
	 */
	if (sect.sct_type != SCT_WATER) {
		pr(fmt("Raiding a %d%% %s.\n"), sect.sct_effic,
			dchr[sect.sct_type].d_name);
	}
	victim = sect.sct_own;
	/*
	 * shoot at the incoming planes from ships and the target sector
	 */
	mission = fireflak(cnum, targx, targy, mission);
	/*
	 * if targx,targy is a water sector (harbor or water), look
	 * down the ship list and print all of them out.
	 * then ask which ship we're supposed to bomb
	 */
	if (sect.sct_type == SCT_HARBR || sect.sct_type == SCT_WATER) {
		getnat(cnum);
		targship = -1;
		for (i=0; getship(i, &ship, UP_GOD) >= 0; i++) {
			if (ship.shp_x != targx || ship.shp_y != targy)
				continue;
			if (ship.shp_own == 0)
				continue;
			getnat(ship.shp_own);
			pr(fmt("#%d %d%% %s %s\n", i, ship.shp_effic,
				nat.nat_cnam, mchr[ship.shp_type].m_name));
		}
		if (sect.sct_type == SCT_HARBR)
			bp = getstring("Bomb land or ship? ");
		if (sect.sct_type == SCT_WATER ||
			(sect.sct_type == SCT_HARBR && *bp == 's')) {
			bp = getstring("Ship number? ");
			if (bp == NULL || *bp == NULL || *bp == '\n')
				targship = -1;
			else
				targship = atoi(bp);
			if (targship >= 0) {
				if (getship(targship, &ship, UP_GOD) == -1) {
					pr("We can't see that ship, sir.\n");
					targship = -1;
				} else if (ship.shp_x != sect.sct_x ||
						ship.shp_y != sect.sct_y) {
					pr("We can't see that ship, sir.\n");
					targship = -1;
				}
				if (targship >= 0)
					victim = ship.shp_own;
			}
		}
	}
	/*
	 * let the bombs drop (if there are any planes left)
	 */
	if (mission)
		pr("Bombs away!\n");
	if (targship >= 0)
		armor = tfact(ship.shp_own,1.0)*mchr[ship.shp_type].m_armor;
	damage = tfact(cnum, 1.0) * 15;
	for (i=1; i<=mission; i++) {
		tmp = damage;
		if (sect.sct_type == SCT_SANCT) {
			pr(fmt("BOUNCE! off of %d,%d\n", targx, targy));
			/* Mr. Frog was here */
			continue;
		} else
			pr("BLAMMO!");
		/*
		 * just make it so the kamakazi's never miss, and
		 * double the chance of a direct hit
		 */
		switch ((rand() % (8 - kamakazi)) - kamakazi) {
			case -1:
			case 0:
				pr(" direct hit on ");
				tmp *= 2;
				break;
			case 1:
			case 2:
				pr(" hit on ");
				break;
			case 3:
			case 4:
			case 5:
				pr(" near miss on ");
				tmp /= 2;
				break;
			case 6:
			case 7:
				pr(" complete miss on ");
				tmp = 0;
				break;
		}
		if (targship < 0) {
			sectdamage(targx, targy, tmp);
			pr(fmt("%d,%d for %d%% damage\n",targx,targy,tmp));
		} else {
			tmp = tmp * (63.0 / armor);
			shipdamage(&ship, tmp);
			pr(fmt("ship #%d for %d%% damage\n", targship, tmp));
		}
	}
	pr("\n");
	/*
	 * now tell the victim what happened
	 */
	getnat(cnum);
	if (targship >= 0) {
		putship(targship, &ship);
		cvt_xy(cnum, victim, &targx, &targy);
		bp = fmt("Ship #%d at %d,%d was bombed %d times by %s planes!",
			targship, targx, targy, mission, nat.nat_cnam);
		wu(0, victim, bp);
		nreport(cnum, N_SHP_BOMB, victim, i);
	} else {
		putsect(targx, targy);
		cvt_xy(cnum, victim, &targx, &targy);
		bp = fmt("Sector %d,%d was bombed %d times by %s planes!",
			targx, targy, mission, nat.nat_cnam);
		wu(0, victim, bp);
		nreport(cnum, N_SCT_BOMB, victim, i);
	}
	if (kamakazi)
		return R_OK;
cargo:
	/*
	 * subtract mobility (for landing) from the base sector
	 */
	if (baseship >= 0) {
		getship(baseship, &ship, UP_OWN);
		ship.shp_mobil = ship.shp_mobil - (mission/2.0 + .5);
		bp = (char *) &ship;
	} else {
		getsect(basex, basey, UP_OWN);
		sect.sct_mobil = sect.sct_mobil - (mission/2.0 + .5);
		bp = (char *) &sect;
	}
	/*
	 * add the surviving planes and military to the base sector
	 *
	 * note the MAXSCTV argument to putvar -- this is needed
	 * because putvar() may need to make an additional slot
	 * for the planes/military if there were no planes/military
	 * there previously.
	 */
	putvar(V_MILIT, getvar(V_MILIT, bp) + mission, bp, MAXSCTV);
	putvar(V_PLANE, getvar(V_PLANE, bp) + mission, bp, MAXSCTV);
	if (baseship >= 0)
		putship(baseship, &ship);
	else
		putsect(basex, basey);
	pr(fmt("Welcome home!  (%d planes landed)\n", mission));
}


/*
 * fireflak()
 *
 * who: whose planes are they?
 * x,y: coords the planes are flying above
 * planes: how many planes are there?
 *
 * fires flak at planes over a given sector, and also fires
 * from any ships that happen to be in the area
 *
 * return: number of planes after flak has been fired
 */

int fireflak(who, x, y, planes)
int who;
int x,y;
int planes;
{
	extern	float tfact();
	extern	char *fmt();
	extern	struct natstr nat;
	register int i, j;
	float	tech, planetech, roll;
	char	*bp;
	int	type;
	int	shootdown[32];
	int	own;
	int	theirx, theiry;
	int	guns;
	int	shells;
	int	fire;
	int	shotdown = 0;

	/*
	 * get target sector, tech factor, set up misc vars.
	 */
	for (i=0; i<32; i++)
		shootdown[i] = 0;
	getsect(x, y, UP_GOD);
	type = sect.sct_type;
	own = sect.sct_own;
	planetech = tfact(who, 1.0);
	tech = tfact(own, 1.0);
	roll = tech - (planetech - tech) - .10;
	/*
	 * give the underdeveloped slobs an 8% chance minimum
	 */
	if (roll < .08)
		roll = .08;
	fire = 0;
	if (own != 0 && (type == SCT_FORTR || type == SCT_AIRPT ||
			type == SCT_CAPIT)) {
		/*
		 * allow a maximum of (guns * techfact) guns to fire
		 * ex: tfact: .80, guns: 10.  guns firing: 10
		 */
		guns = getvar(V_GUN, &sect);
		shells = getvar(V_SHELL, &sect);
		fire = min(guns, 14);
		fire = min(fire, shells) * tech;
		if (fire > 0) {
			/*
			 * fire AA guns at the planes, one BOOM per gun
			 */
			for (i=0; i<fire && planes; i++) {
				pr("BOOM! ");
				if (chance(roll)) {
					pr("(crash)...we've been hit!\n");
					planes--;
					shootdown[sect.sct_own]++;
					shotdown++;
				}
			}
			/*
			 * subtract shells fired from the sector
			 */
			putvar(V_SHELL, shells - i, &sect, 0);
			putsect(x, y);
		}
	}
	/*
	 * if it's a water sector, or a harbor sector, we get to fire
	 * guns from ships in the sector (goodie, goodie)
	 */
	if (sect.sct_type == SCT_WATER || sect.sct_type == SCT_HARBR) {
		/*
		 * while there are planes left to shoot at...
		 */
		for (i=0; planes>0 && getship(i, &ship, UP_GOD) != -1; i++) {
			if (ship.shp_x != x || ship.shp_y != y)
				continue;
			if (ship.shp_own == 0 || ship.shp_own == who)
				continue;
			/*
			 * make sure the ship has guns and shells
			 * (like we did in the sector AA above)
			 */
			guns = getvar(V_GUN, &ship);
			if (!guns)
				continue;
			shells = getvar(V_SHELL, &ship);
			if (!shells)
				continue;
			/*
			 * let the ship fire up to it's gun-limit
			 * (i.e. 4 for a BB, 3 for a HC, etc)
			 */
			fire = min(guns, mchr[ship.shp_type].m_glim);
			fire = min(fire, shells);
			if (!fire)
				continue;
			/*
			 * may be faster to figure all this out
			 * beforehand and put it in a big array...
			 * then again, maybve not
			 */
			tech = tfact(ship.shp_own, 1.0);
			roll = tech - (planetech - tech) - .10;
			if (roll < .08)
				roll = .08;
			/*
			 * again, one BOOM per fire
			 */
			for (j=0; j<fire && planes; j++) {
				pr("BOOM! ");
				if (!chance(roll))
					continue;
				pr("(crash)...we've been hit!\n");
				planes--;
				shootdown[ship.shp_own]++;
				shotdown++;
			}
			/*
			 * subtract the number fired from the ship
			 */
			putvar(V_SHELL, shells - j, &sect, 0);
			putship(i, &ship);
		}
	}
	getnat(who);
	if (!shotdown)
		return planes;
	/*
	 * now tell the various countries about the
	 * downing of planes, and report it to the news
	 */
	for (i=0; i<32; i++) {
		if (!shootdown[i])
			continue;
		theirx = x;
		theiry = y;
		cvt_xy(who, i, &theirx, &theiry);
		bp = fmt("AA batteries shot down %d %s planes over %d,%d\n",
			shootdown[i], nat.nat_cnam, theirx, theiry);
		wu(0, i, bp);
		nreport(i, N_FLAK, who, shootdown[i]);
	}
	return planes;
}


/*
 * convert the x,y coords from one country to another
 */

cvt_xy(from, to, x, y)
short from;
short to;
int *x, *y;
{
	int	xwrap();
	int	ywrap();
	extern	short capxof[];
	extern	short capyof[];
	extern	short maxnoc;

	if (to < 0 || to > maxnoc || from < 0 || from > maxnoc) {
		pr("bad country number!\n");
		exit(1);
	}
	*x = xwrap(capxof[from] - capxof[to] + *x);
	*y = ywrap(capyof[from] - capyof[to] + *y);
}
FunkyStuff