xref: /csrg-svn/games/trek/events.c (revision 60857)
121278Sdist /*
2*60857Sbostic  * Copyright (c) 1980, 1993
3*60857Sbostic  *	The Regents of the University of California.  All rights reserved.
434205Sbostic  *
542605Sbostic  * %sccs.include.redist.c%
621278Sdist  */
721278Sdist 
811672Smckusick #ifndef lint
9*60857Sbostic static char sccsid[] = "@(#)events.c	8.1 (Berkeley) 05/31/93";
1034205Sbostic #endif /* not lint */
1111672Smckusick 
1211672Smckusick # include	"trek.h"
1311672Smckusick 
1411672Smckusick /*
1511672Smckusick **  CAUSE TIME TO ELAPSE
1611672Smckusick **
1711672Smckusick **	This routine does a hell of a lot.  It elapses time, eats up
1811672Smckusick **	energy, regenerates energy, processes any events that occur,
1911672Smckusick **	and so on.
2011672Smckusick */
2111672Smckusick 
2211672Smckusick 
events(warp)2311672Smckusick events(warp)
2411672Smckusick int	warp;		/* set if called in a time warp */
2511672Smckusick {
2611672Smckusick 	register int		i;
2711672Smckusick 	int			j;
2811672Smckusick 	struct kling		*k;
2911672Smckusick 	double			rtime;
3011672Smckusick 	double			xdate;
3111672Smckusick 	double			idate;
3212737Slayer 	struct event		*ev, *xsched(), *schedule();
3311672Smckusick 	int			ix, iy;
3411672Smckusick 	register struct quad	*q;
3511672Smckusick 	register struct event	*e;
3611672Smckusick 	int			evnum;
3711672Smckusick 	int			restcancel;
3811672Smckusick 
3911672Smckusick 	/* if nothing happened, just allow for any Klingons killed */
4011672Smckusick 	if (Move.time <= 0.0)
4111672Smckusick 	{
4211672Smckusick 		Now.time = Now.resource / Now.klings;
4311672Smckusick 		return (0);
4411672Smckusick 	}
4511672Smckusick 
4611672Smckusick 	/* indicate that the cloaking device is now working */
4711672Smckusick 	Ship.cloakgood = 1;
4811672Smckusick 
4911672Smckusick 	/* idate is the initial date */
5011672Smckusick 	idate = Now.date;
5111672Smckusick 
5211672Smckusick 	/* schedule attacks if resting too long */
5311672Smckusick 	if (Move.time > 0.5 && Move.resting)
5411672Smckusick 		schedule(E_ATTACK, 0.5, 0, 0, 0);
5511672Smckusick 
5611672Smckusick 	/* scan the event list */
5711672Smckusick 	while (1)
5811672Smckusick 	{
5911672Smckusick 		restcancel = 0;
6011672Smckusick 		evnum = -1;
6111672Smckusick 		/* xdate is the date of the current event */
6211672Smckusick 		xdate = idate + Move.time;
6311672Smckusick 
6411672Smckusick 		/* find the first event that has happened */
6511672Smckusick 		for (i = 0; i < MAXEVENTS; i++)
6611672Smckusick 		{
6711672Smckusick 			e = &Event[i];
6811672Smckusick 			if (e->evcode == 0 || (e->evcode & E_GHOST))
6911672Smckusick 				continue;
7011672Smckusick 			if (e->date < xdate)
7111672Smckusick 			{
7211672Smckusick 				xdate = e->date;
7311672Smckusick 				ev = e;
7411672Smckusick 				evnum = i;
7511672Smckusick 			}
7611672Smckusick 		}
7711672Smckusick 		e = ev;
7811672Smckusick 
7911672Smckusick 		/* find the time between events */
8011672Smckusick 		rtime = xdate - Now.date;
8111672Smckusick 
8211672Smckusick 		/* decrement the magic "Federation Resources" pseudo-variable */
8312737Slayer 		Now.resource -= Now.klings * rtime;
8411672Smckusick 		/* and recompute the time left */
8511672Smckusick 		Now.time = Now.resource / Now.klings;
8611672Smckusick 
8711672Smckusick 		/* move us up to the next date */
8811672Smckusick 		Now.date = xdate;
8911672Smckusick 
9011672Smckusick 		/* check for out of time */
9111672Smckusick 		if (Now.time <= 0.0)
9211672Smckusick 			lose(L_NOTIME);
9311672Smckusick #		ifdef xTRACE
9411672Smckusick 		if (evnum >= 0 && Trace)
9511672Smckusick 			printf("xdate = %.2f, evcode %d params %d %d %d\n",
9611672Smckusick 				xdate, e->evcode, e->x, e->y, e->systemname);
9711672Smckusick #		endif
9811672Smckusick 
9911672Smckusick 		/* if evnum < 0, no events occurred  */
10011672Smckusick 		if (evnum < 0)
10111672Smckusick 			break;
10211672Smckusick 
10311672Smckusick 		/* otherwise one did.  Find out what it is */
10411672Smckusick 		switch (e->evcode & E_EVENT)
10511672Smckusick 		{
10611672Smckusick 
10711672Smckusick 		  case E_SNOVA:			/* supernova */
10811672Smckusick 			/* cause the supernova to happen */
10911672Smckusick 			snova(-1);
11011672Smckusick 			/* and schedule the next one */
11111672Smckusick 			xresched(e, E_SNOVA, 1);
11211672Smckusick 			break;
11311672Smckusick 
11411672Smckusick 		  case E_LRTB:			/* long range tractor beam */
11511672Smckusick 			/* schedule the next one */
11611672Smckusick 			xresched(e, E_LRTB, Now.klings);
11711672Smckusick 			/* LRTB cannot occur if we are docked */
11811672Smckusick 			if (Ship.cond != DOCKED)
11911672Smckusick 			{
12011672Smckusick 				/* pick a new quadrant */
12111672Smckusick 				i = ranf(Now.klings) + 1;
12211672Smckusick 				for (ix = 0; ix < NQUADS; ix++)
12311672Smckusick 				{
12411672Smckusick 					for (iy = 0; iy < NQUADS; iy++)
12511672Smckusick 					{
12611672Smckusick 						q = &Quad[ix][iy];
12711672Smckusick 						if (q->stars >= 0)
12812737Slayer 							if ((i -= q->klings) <= 0)
12911672Smckusick 								break;
13011672Smckusick 					}
13111672Smckusick 					if (i <= 0)
13211672Smckusick 						break;
13311672Smckusick 				}
13411672Smckusick 
13511672Smckusick 				/* test for LRTB to same quadrant */
13611672Smckusick 				if (Ship.quadx == ix && Ship.quady == iy)
13711672Smckusick 					break;
13811672Smckusick 
13911672Smckusick 				/* nope, dump him in the new quadrant */
14011672Smckusick 				Ship.quadx = ix;
14111672Smckusick 				Ship.quady = iy;
14211672Smckusick 				printf("\n%s caught in long range tractor beam\n", Ship.shipname);
14311672Smckusick 				printf("*** Pulled to quadrant %d,%d\n", Ship.quadx, Ship.quady);
14411672Smckusick 				Ship.sectx = ranf(NSECTS);
14511672Smckusick 				Ship.secty = ranf(NSECTS);
14611672Smckusick 				initquad(0);
14711672Smckusick 				/* truncate the move time */
14811672Smckusick 				Move.time = xdate - idate;
14911672Smckusick 			}
15011672Smckusick 			break;
15111672Smckusick 
15211672Smckusick 		  case E_KATSB:			/* Klingon attacks starbase */
15311672Smckusick 			/* if out of bases, forget it */
15411672Smckusick 			if (Now.bases <= 0)
15511672Smckusick 			{
15611672Smckusick 				unschedule(e);
15711672Smckusick 				break;
15811672Smckusick 			}
15911672Smckusick 
16011672Smckusick 			/* check for starbase and Klingons in same quadrant */
16111672Smckusick 			for (i = 0; i < Now.bases; i++)
16211672Smckusick 			{
16311672Smckusick 				ix = Now.base[i].x;
16411672Smckusick 				iy = Now.base[i].y;
16511672Smckusick 				/* see if a Klingon exists in this quadrant */
16611672Smckusick 				q = &Quad[ix][iy];
16711672Smckusick 				if (q->klings <= 0)
16811672Smckusick 					continue;
16911672Smckusick 
17011672Smckusick 				/* see if already distressed */
17111672Smckusick 				for (j = 0; j < MAXEVENTS; j++)
17211672Smckusick 				{
17311672Smckusick 					e = &Event[j];
17411672Smckusick 					if ((e->evcode & E_EVENT) != E_KDESB)
17511672Smckusick 						continue;
17611672Smckusick 					if (e->x == ix && e->y == iy)
17711672Smckusick 						break;
17811672Smckusick 				}
17911672Smckusick 				if (j < MAXEVENTS)
18011672Smckusick 					continue;
18111672Smckusick 
18211672Smckusick 				/* got a potential attack */
18311672Smckusick 				break;
18411672Smckusick 			}
18511672Smckusick 			e = ev;
18611672Smckusick 			if (i >= Now.bases)
18711672Smckusick 			{
18811672Smckusick 				/* not now; wait a while and see if some Klingons move in */
18911672Smckusick 				reschedule(e, 0.5 + 3.0 * franf());
19011672Smckusick 				break;
19111672Smckusick 			}
19211672Smckusick 			/* schedule a new attack, and a destruction of the base */
19311672Smckusick 			xresched(e, E_KATSB, 1);
19411672Smckusick 			e = xsched(E_KDESB, 1, ix, iy, 0);
19511672Smckusick 
19611672Smckusick 			/* report it if we can */
19711672Smckusick 			if (!damaged(SSRADIO))
19811672Smckusick 			{
19911672Smckusick 				printf("\nUhura:  Captain, we have recieved a distress signal\n");
20011672Smckusick 				printf("  from the starbase in quadrant %d,%d.\n",
20111672Smckusick 					ix, iy);
20211672Smckusick 				restcancel++;
20311672Smckusick 			}
20411672Smckusick 			else
20511672Smckusick 				/* SSRADIO out, make it so we can't see the distress call */
20611672Smckusick 				/* but it's still there!!! */
20712737Slayer 				e->evcode |= E_HIDDEN;
20811672Smckusick 			break;
20911672Smckusick 
21011672Smckusick 		  case E_KDESB:			/* Klingon destroys starbase */
21111672Smckusick 			unschedule(e);
21211672Smckusick 			q = &Quad[e->x][e->y];
21311672Smckusick 			/* if the base has mysteriously gone away, or if the Klingon
21411672Smckusick 			   got tired and went home, ignore this event */
21511672Smckusick 			if (q->bases <=0 || q->klings <= 0)
21611672Smckusick 				break;
21711672Smckusick 			/* are we in the same quadrant? */
21811672Smckusick 			if (e->x == Ship.quadx && e->y == Ship.quady)
21911672Smckusick 			{
22011672Smckusick 				/* yep, kill one in this quadrant */
22111672Smckusick 				printf("\nSpock: ");
22211672Smckusick 				killb(Ship.quadx, Ship.quady);
22311672Smckusick 			}
22411672Smckusick 			else
22511672Smckusick 				/* kill one in some other quadrant */
22611672Smckusick 				killb(e->x, e->y);
22711672Smckusick 			break;
22811672Smckusick 
22911672Smckusick 		  case E_ISSUE:		/* issue a distress call */
23011672Smckusick 			xresched(e, E_ISSUE, 1);
23111672Smckusick 			/* if we already have too many, throw this one away */
23211672Smckusick 			if (Ship.distressed >= MAXDISTR)
23311672Smckusick 				break;
23411672Smckusick 			/* try a whole bunch of times to find something suitable */
23511672Smckusick 			for (i = 0; i < 100; i++)
23611672Smckusick 			{
23711672Smckusick 				ix = ranf(NQUADS);
23811672Smckusick 				iy = ranf(NQUADS);
23911672Smckusick 				q = &Quad[ix][iy];
24011672Smckusick 				/* need a quadrant which is not the current one,
24111672Smckusick 				   which has some stars which are inhabited and
24211672Smckusick 				   not already under attack, which is not
24311672Smckusick 				   supernova'ed, and which has some Klingons in it */
24411672Smckusick 				if (!((ix == Ship.quadx && iy == Ship.quady) || q->stars < 0 ||
24512737Slayer 				    (q->qsystemname & Q_DISTRESSED) ||
24612737Slayer 				    (q->qsystemname & Q_SYSTEM) == 0 || q->klings <= 0))
24711672Smckusick 					break;
24811672Smckusick 			}
24911672Smckusick 			if (i >= 100)
25011672Smckusick 				/* can't seem to find one; ignore this call */
25111672Smckusick 				break;
25211672Smckusick 
25311672Smckusick 			/* got one!!  Schedule its enslavement */
25412737Slayer 			Ship.distressed++;
25512737Slayer 			e = xsched(E_ENSLV, 1, ix, iy, q->qsystemname);
25612737Slayer 			q->qsystemname = (e - Event) | Q_DISTRESSED;
25711672Smckusick 
25811672Smckusick 			/* tell the captain about it if we can */
25911672Smckusick 			if (!damaged(SSRADIO))
26011672Smckusick 			{
26111672Smckusick 				printf("\nUhura: Captain, starsystem %s in quadrant %d,%d is under attack\n",
26211672Smckusick 					Systemname[e->systemname], ix, iy);
26311672Smckusick 				restcancel++;
26411672Smckusick 			}
26511672Smckusick 			else
26611672Smckusick 				/* if we can't tell him, make it invisible */
26712737Slayer 				e->evcode |= E_HIDDEN;
26811672Smckusick 			break;
26911672Smckusick 
27011672Smckusick 		  case E_ENSLV:		/* starsystem is enslaved */
27111672Smckusick 			unschedule(e);
27211672Smckusick 			/* see if current distress call still active */
27311672Smckusick 			q = &Quad[e->x][e->y];
27411672Smckusick 			if (q->klings <= 0)
27511672Smckusick 			{
27611672Smckusick 				/* no Klingons, clean up */
27711672Smckusick 				/* restore the system name */
27812737Slayer 				q->qsystemname = e->systemname;
27911672Smckusick 				break;
28011672Smckusick 			}
28111672Smckusick 
28211672Smckusick 			/* play stork and schedule the first baby */
28311672Smckusick 			e = schedule(E_REPRO, Param.eventdly[E_REPRO] * franf(), e->x, e->y, e->systemname);
28411672Smckusick 
28511672Smckusick 			/* report the disaster if we can */
28611672Smckusick 			if (!damaged(SSRADIO))
28711672Smckusick 			{
28811672Smckusick 				printf("\nUhura:  We've lost contact with starsystem %s\n",
28911672Smckusick 					Systemname[e->systemname]);
29011672Smckusick 				printf("  in quadrant %d,%d.\n",
29111672Smckusick 					e->x, e->y);
29211672Smckusick 			}
29311672Smckusick 			else
29412737Slayer 				e->evcode |= E_HIDDEN;
29511672Smckusick 			break;
29611672Smckusick 
29711672Smckusick 		  case E_REPRO:		/* Klingon reproduces */
29811672Smckusick 			/* see if distress call is still active */
29911672Smckusick 			q = &Quad[e->x][e->y];
30011672Smckusick 			if (q->klings <= 0)
30111672Smckusick 			{
30211672Smckusick 				unschedule(e);
30312737Slayer 				q->qsystemname = e->systemname;
30411672Smckusick 				break;
30511672Smckusick 			}
30611672Smckusick 			xresched(e, E_REPRO, 1);
30711672Smckusick 			/* reproduce one Klingon */
30811672Smckusick 			ix = e->x;
30911672Smckusick 			iy = e->y;
31011672Smckusick 			if (Now.klings == 127)
31111672Smckusick 				break;		/* full right now */
31211672Smckusick 			if (q->klings >= MAXKLQUAD)
31311672Smckusick 			{
31411672Smckusick 				/* this quadrant not ok, pick an adjacent one */
31511672Smckusick 				for (i = ix - 1; i <= ix + 1; i++)
31611672Smckusick 				{
31711672Smckusick 					if (i < 0 || i >= NQUADS)
31811672Smckusick 						continue;
31911672Smckusick 					for (j = iy - 1; j <= iy + 1; j++)
32011672Smckusick 					{
32111672Smckusick 						if (j < 0 || j >= NQUADS)
32211672Smckusick 							continue;
32311672Smckusick 						q = &Quad[i][j];
32411672Smckusick 						/* check for this quad ok (not full & no snova) */
32511672Smckusick 						if (q->klings >= MAXKLQUAD || q->stars < 0)
32611672Smckusick 							continue;
32711672Smckusick 						break;
32811672Smckusick 					}
32911672Smckusick 					if (j <= iy + 1)
33011672Smckusick 						break;
33111672Smckusick 				}
33211672Smckusick 				if (j > iy + 1)
33311672Smckusick 					/* cannot create another yet */
33411672Smckusick 					break;
33511672Smckusick 				ix = i;
33611672Smckusick 				iy = j;
33711672Smckusick 			}
33811672Smckusick 			/* deliver the child */
33912737Slayer 			q->klings++;
34012737Slayer 			Now.klings++;
34111672Smckusick 			if (ix == Ship.quadx && iy == Ship.quady)
34211672Smckusick 			{
34311672Smckusick 				/* we must position Klingon */
34411672Smckusick 				sector(&ix, &iy);
34511672Smckusick 				Sect[ix][iy] = KLINGON;
34611672Smckusick 				k = &Etc.klingon[Etc.nkling++];
34711672Smckusick 				k->x = ix;
34811672Smckusick 				k->y = iy;
34911672Smckusick 				k->power = Param.klingpwr;
35011672Smckusick 				k->srndreq = 0;
35111672Smckusick 				compkldist(Etc.klingon[0].dist == Etc.klingon[0].avgdist ? 0 : 1);
35211672Smckusick 			}
35311672Smckusick 
35411672Smckusick 			/* recompute time left */
35511672Smckusick 			Now.time = Now.resource / Now.klings;
35611672Smckusick 			break;
35711672Smckusick 
35811672Smckusick 		  case E_SNAP:		/* take a snapshot of the galaxy */
35911672Smckusick 			xresched(e, E_SNAP, 1);
36012737Slayer 			i = (int) Etc.snapshot;
36112737Slayer 			i = bmove(Quad, i, sizeof (Quad));
36212737Slayer 			i = bmove(Event, i, sizeof (Event));
36316249Smckusick 			i = bmove(&Now, i, sizeof (Now));
36411672Smckusick 			Game.snap = 1;
36511672Smckusick 			break;
36611672Smckusick 
36711672Smckusick 		  case E_ATTACK:	/* Klingons attack during rest period */
36811672Smckusick 			if (!Move.resting)
36911672Smckusick 			{
37011672Smckusick 				unschedule(e);
37111672Smckusick 				break;
37211672Smckusick 			}
37311672Smckusick 			attack(1);
37411672Smckusick 			reschedule(e, 0.5);
37511672Smckusick 			break;
37611672Smckusick 
37711672Smckusick 		  case E_FIXDV:
37811672Smckusick 			i = e->systemname;
37911672Smckusick 			unschedule(e);
38011672Smckusick 
38111672Smckusick 			/* de-damage the device */
38211672Smckusick 			printf("%s reports repair work on the %s finished.\n",
38311672Smckusick 				Device[i].person, Device[i].name);
38411672Smckusick 
38511672Smckusick 			/* handle special processing upon fix */
38611672Smckusick 			switch (i)
38711672Smckusick 			{
38811672Smckusick 
38911672Smckusick 			  case LIFESUP:
39011672Smckusick 				Ship.reserves = Param.reserves;
39111672Smckusick 				break;
39211672Smckusick 
39311672Smckusick 			  case SINS:
39411672Smckusick 				if (Ship.cond == DOCKED)
39511672Smckusick 					break;
39611672Smckusick 				printf("Spock has tried to recalibrate your Space Internal Navigation System,\n");
39711672Smckusick 				printf("  but he has no standard base to calibrate to.  Suggest you get\n");
39811672Smckusick 				printf("  to a starbase immediately so that you can properly recalibrate.\n");
39911672Smckusick 				Ship.sinsbad = 1;
40011672Smckusick 				break;
40111672Smckusick 
40211672Smckusick 			  case SSRADIO:
40311672Smckusick 				restcancel = dumpssradio();
40411672Smckusick 				break;
40511672Smckusick 			}
40611672Smckusick 			break;
40711672Smckusick 
40811672Smckusick 		  default:
40911672Smckusick 			break;
41011672Smckusick 		}
41111672Smckusick 
41211672Smckusick 		if (restcancel && Move.resting && getynpar("Spock: Shall we cancel our rest period"))
41311672Smckusick 			Move.time = xdate - idate;
41411672Smckusick 
41511672Smckusick 	}
41611672Smckusick 
41711672Smckusick 	/* unschedule an attack during a rest period */
41811672Smckusick 	if (e = Now.eventptr[E_ATTACK])
41911672Smckusick 		unschedule(e);
42011672Smckusick 
42111672Smckusick 	if (!warp)
42211672Smckusick 	{
42311672Smckusick 		/* eat up energy if cloaked */
42411672Smckusick 		if (Ship.cloaked)
42512737Slayer 			Ship.energy -= Param.cloakenergy * Move.time;
42611672Smckusick 
42711672Smckusick 		/* regenerate resources */
42811672Smckusick 		rtime = 1.0 - exp(-Param.regenfac * Move.time);
42912737Slayer 		Ship.shield += (Param.shield - Ship.shield) * rtime;
43012737Slayer 		Ship.energy += (Param.energy - Ship.energy) * rtime;
43111672Smckusick 
43211672Smckusick 		/* decrement life support reserves */
43311672Smckusick 		if (damaged(LIFESUP) && Ship.cond != DOCKED)
43412737Slayer 			Ship.reserves -= Move.time;
43511672Smckusick 	}
43611672Smckusick 	return (0);
43711672Smckusick }
438