xref: /original-bsd/games/trek/events.c (revision e8c4bdd9)
18e739251Sdist /*
2*e8c4bdd9Sbostic  * Copyright (c) 1980, 1993
3*e8c4bdd9Sbostic  *	The Regents of the University of California.  All rights reserved.
4afcc7e22Sbostic  *
589363ea9Sbostic  * %sccs.include.redist.c%
68e739251Sdist  */
78e739251Sdist 
8d6722163Smckusick #ifndef lint
9*e8c4bdd9Sbostic static char sccsid[] = "@(#)events.c	8.1 (Berkeley) 05/31/93";
10afcc7e22Sbostic #endif /* not lint */
11d6722163Smckusick 
12d6722163Smckusick # include	"trek.h"
13d6722163Smckusick 
14d6722163Smckusick /*
15d6722163Smckusick **  CAUSE TIME TO ELAPSE
16d6722163Smckusick **
17d6722163Smckusick **	This routine does a hell of a lot.  It elapses time, eats up
18d6722163Smckusick **	energy, regenerates energy, processes any events that occur,
19d6722163Smckusick **	and so on.
20d6722163Smckusick */
21d6722163Smckusick 
22d6722163Smckusick 
events(warp)23d6722163Smckusick events(warp)
24d6722163Smckusick int	warp;		/* set if called in a time warp */
25d6722163Smckusick {
26d6722163Smckusick 	register int		i;
27d6722163Smckusick 	int			j;
28d6722163Smckusick 	struct kling		*k;
29d6722163Smckusick 	double			rtime;
30d6722163Smckusick 	double			xdate;
31d6722163Smckusick 	double			idate;
32d40d07f4Slayer 	struct event		*ev, *xsched(), *schedule();
33d6722163Smckusick 	int			ix, iy;
34d6722163Smckusick 	register struct quad	*q;
35d6722163Smckusick 	register struct event	*e;
36d6722163Smckusick 	int			evnum;
37d6722163Smckusick 	int			restcancel;
38d6722163Smckusick 
39d6722163Smckusick 	/* if nothing happened, just allow for any Klingons killed */
40d6722163Smckusick 	if (Move.time <= 0.0)
41d6722163Smckusick 	{
42d6722163Smckusick 		Now.time = Now.resource / Now.klings;
43d6722163Smckusick 		return (0);
44d6722163Smckusick 	}
45d6722163Smckusick 
46d6722163Smckusick 	/* indicate that the cloaking device is now working */
47d6722163Smckusick 	Ship.cloakgood = 1;
48d6722163Smckusick 
49d6722163Smckusick 	/* idate is the initial date */
50d6722163Smckusick 	idate = Now.date;
51d6722163Smckusick 
52d6722163Smckusick 	/* schedule attacks if resting too long */
53d6722163Smckusick 	if (Move.time > 0.5 && Move.resting)
54d6722163Smckusick 		schedule(E_ATTACK, 0.5, 0, 0, 0);
55d6722163Smckusick 
56d6722163Smckusick 	/* scan the event list */
57d6722163Smckusick 	while (1)
58d6722163Smckusick 	{
59d6722163Smckusick 		restcancel = 0;
60d6722163Smckusick 		evnum = -1;
61d6722163Smckusick 		/* xdate is the date of the current event */
62d6722163Smckusick 		xdate = idate + Move.time;
63d6722163Smckusick 
64d6722163Smckusick 		/* find the first event that has happened */
65d6722163Smckusick 		for (i = 0; i < MAXEVENTS; i++)
66d6722163Smckusick 		{
67d6722163Smckusick 			e = &Event[i];
68d6722163Smckusick 			if (e->evcode == 0 || (e->evcode & E_GHOST))
69d6722163Smckusick 				continue;
70d6722163Smckusick 			if (e->date < xdate)
71d6722163Smckusick 			{
72d6722163Smckusick 				xdate = e->date;
73d6722163Smckusick 				ev = e;
74d6722163Smckusick 				evnum = i;
75d6722163Smckusick 			}
76d6722163Smckusick 		}
77d6722163Smckusick 		e = ev;
78d6722163Smckusick 
79d6722163Smckusick 		/* find the time between events */
80d6722163Smckusick 		rtime = xdate - Now.date;
81d6722163Smckusick 
82d6722163Smckusick 		/* decrement the magic "Federation Resources" pseudo-variable */
83d40d07f4Slayer 		Now.resource -= Now.klings * rtime;
84d6722163Smckusick 		/* and recompute the time left */
85d6722163Smckusick 		Now.time = Now.resource / Now.klings;
86d6722163Smckusick 
87d6722163Smckusick 		/* move us up to the next date */
88d6722163Smckusick 		Now.date = xdate;
89d6722163Smckusick 
90d6722163Smckusick 		/* check for out of time */
91d6722163Smckusick 		if (Now.time <= 0.0)
92d6722163Smckusick 			lose(L_NOTIME);
93d6722163Smckusick #		ifdef xTRACE
94d6722163Smckusick 		if (evnum >= 0 && Trace)
95d6722163Smckusick 			printf("xdate = %.2f, evcode %d params %d %d %d\n",
96d6722163Smckusick 				xdate, e->evcode, e->x, e->y, e->systemname);
97d6722163Smckusick #		endif
98d6722163Smckusick 
99d6722163Smckusick 		/* if evnum < 0, no events occurred  */
100d6722163Smckusick 		if (evnum < 0)
101d6722163Smckusick 			break;
102d6722163Smckusick 
103d6722163Smckusick 		/* otherwise one did.  Find out what it is */
104d6722163Smckusick 		switch (e->evcode & E_EVENT)
105d6722163Smckusick 		{
106d6722163Smckusick 
107d6722163Smckusick 		  case E_SNOVA:			/* supernova */
108d6722163Smckusick 			/* cause the supernova to happen */
109d6722163Smckusick 			snova(-1);
110d6722163Smckusick 			/* and schedule the next one */
111d6722163Smckusick 			xresched(e, E_SNOVA, 1);
112d6722163Smckusick 			break;
113d6722163Smckusick 
114d6722163Smckusick 		  case E_LRTB:			/* long range tractor beam */
115d6722163Smckusick 			/* schedule the next one */
116d6722163Smckusick 			xresched(e, E_LRTB, Now.klings);
117d6722163Smckusick 			/* LRTB cannot occur if we are docked */
118d6722163Smckusick 			if (Ship.cond != DOCKED)
119d6722163Smckusick 			{
120d6722163Smckusick 				/* pick a new quadrant */
121d6722163Smckusick 				i = ranf(Now.klings) + 1;
122d6722163Smckusick 				for (ix = 0; ix < NQUADS; ix++)
123d6722163Smckusick 				{
124d6722163Smckusick 					for (iy = 0; iy < NQUADS; iy++)
125d6722163Smckusick 					{
126d6722163Smckusick 						q = &Quad[ix][iy];
127d6722163Smckusick 						if (q->stars >= 0)
128d40d07f4Slayer 							if ((i -= q->klings) <= 0)
129d6722163Smckusick 								break;
130d6722163Smckusick 					}
131d6722163Smckusick 					if (i <= 0)
132d6722163Smckusick 						break;
133d6722163Smckusick 				}
134d6722163Smckusick 
135d6722163Smckusick 				/* test for LRTB to same quadrant */
136d6722163Smckusick 				if (Ship.quadx == ix && Ship.quady == iy)
137d6722163Smckusick 					break;
138d6722163Smckusick 
139d6722163Smckusick 				/* nope, dump him in the new quadrant */
140d6722163Smckusick 				Ship.quadx = ix;
141d6722163Smckusick 				Ship.quady = iy;
142d6722163Smckusick 				printf("\n%s caught in long range tractor beam\n", Ship.shipname);
143d6722163Smckusick 				printf("*** Pulled to quadrant %d,%d\n", Ship.quadx, Ship.quady);
144d6722163Smckusick 				Ship.sectx = ranf(NSECTS);
145d6722163Smckusick 				Ship.secty = ranf(NSECTS);
146d6722163Smckusick 				initquad(0);
147d6722163Smckusick 				/* truncate the move time */
148d6722163Smckusick 				Move.time = xdate - idate;
149d6722163Smckusick 			}
150d6722163Smckusick 			break;
151d6722163Smckusick 
152d6722163Smckusick 		  case E_KATSB:			/* Klingon attacks starbase */
153d6722163Smckusick 			/* if out of bases, forget it */
154d6722163Smckusick 			if (Now.bases <= 0)
155d6722163Smckusick 			{
156d6722163Smckusick 				unschedule(e);
157d6722163Smckusick 				break;
158d6722163Smckusick 			}
159d6722163Smckusick 
160d6722163Smckusick 			/* check for starbase and Klingons in same quadrant */
161d6722163Smckusick 			for (i = 0; i < Now.bases; i++)
162d6722163Smckusick 			{
163d6722163Smckusick 				ix = Now.base[i].x;
164d6722163Smckusick 				iy = Now.base[i].y;
165d6722163Smckusick 				/* see if a Klingon exists in this quadrant */
166d6722163Smckusick 				q = &Quad[ix][iy];
167d6722163Smckusick 				if (q->klings <= 0)
168d6722163Smckusick 					continue;
169d6722163Smckusick 
170d6722163Smckusick 				/* see if already distressed */
171d6722163Smckusick 				for (j = 0; j < MAXEVENTS; j++)
172d6722163Smckusick 				{
173d6722163Smckusick 					e = &Event[j];
174d6722163Smckusick 					if ((e->evcode & E_EVENT) != E_KDESB)
175d6722163Smckusick 						continue;
176d6722163Smckusick 					if (e->x == ix && e->y == iy)
177d6722163Smckusick 						break;
178d6722163Smckusick 				}
179d6722163Smckusick 				if (j < MAXEVENTS)
180d6722163Smckusick 					continue;
181d6722163Smckusick 
182d6722163Smckusick 				/* got a potential attack */
183d6722163Smckusick 				break;
184d6722163Smckusick 			}
185d6722163Smckusick 			e = ev;
186d6722163Smckusick 			if (i >= Now.bases)
187d6722163Smckusick 			{
188d6722163Smckusick 				/* not now; wait a while and see if some Klingons move in */
189d6722163Smckusick 				reschedule(e, 0.5 + 3.0 * franf());
190d6722163Smckusick 				break;
191d6722163Smckusick 			}
192d6722163Smckusick 			/* schedule a new attack, and a destruction of the base */
193d6722163Smckusick 			xresched(e, E_KATSB, 1);
194d6722163Smckusick 			e = xsched(E_KDESB, 1, ix, iy, 0);
195d6722163Smckusick 
196d6722163Smckusick 			/* report it if we can */
197d6722163Smckusick 			if (!damaged(SSRADIO))
198d6722163Smckusick 			{
199d6722163Smckusick 				printf("\nUhura:  Captain, we have recieved a distress signal\n");
200d6722163Smckusick 				printf("  from the starbase in quadrant %d,%d.\n",
201d6722163Smckusick 					ix, iy);
202d6722163Smckusick 				restcancel++;
203d6722163Smckusick 			}
204d6722163Smckusick 			else
205d6722163Smckusick 				/* SSRADIO out, make it so we can't see the distress call */
206d6722163Smckusick 				/* but it's still there!!! */
207d40d07f4Slayer 				e->evcode |= E_HIDDEN;
208d6722163Smckusick 			break;
209d6722163Smckusick 
210d6722163Smckusick 		  case E_KDESB:			/* Klingon destroys starbase */
211d6722163Smckusick 			unschedule(e);
212d6722163Smckusick 			q = &Quad[e->x][e->y];
213d6722163Smckusick 			/* if the base has mysteriously gone away, or if the Klingon
214d6722163Smckusick 			   got tired and went home, ignore this event */
215d6722163Smckusick 			if (q->bases <=0 || q->klings <= 0)
216d6722163Smckusick 				break;
217d6722163Smckusick 			/* are we in the same quadrant? */
218d6722163Smckusick 			if (e->x == Ship.quadx && e->y == Ship.quady)
219d6722163Smckusick 			{
220d6722163Smckusick 				/* yep, kill one in this quadrant */
221d6722163Smckusick 				printf("\nSpock: ");
222d6722163Smckusick 				killb(Ship.quadx, Ship.quady);
223d6722163Smckusick 			}
224d6722163Smckusick 			else
225d6722163Smckusick 				/* kill one in some other quadrant */
226d6722163Smckusick 				killb(e->x, e->y);
227d6722163Smckusick 			break;
228d6722163Smckusick 
229d6722163Smckusick 		  case E_ISSUE:		/* issue a distress call */
230d6722163Smckusick 			xresched(e, E_ISSUE, 1);
231d6722163Smckusick 			/* if we already have too many, throw this one away */
232d6722163Smckusick 			if (Ship.distressed >= MAXDISTR)
233d6722163Smckusick 				break;
234d6722163Smckusick 			/* try a whole bunch of times to find something suitable */
235d6722163Smckusick 			for (i = 0; i < 100; i++)
236d6722163Smckusick 			{
237d6722163Smckusick 				ix = ranf(NQUADS);
238d6722163Smckusick 				iy = ranf(NQUADS);
239d6722163Smckusick 				q = &Quad[ix][iy];
240d6722163Smckusick 				/* need a quadrant which is not the current one,
241d6722163Smckusick 				   which has some stars which are inhabited and
242d6722163Smckusick 				   not already under attack, which is not
243d6722163Smckusick 				   supernova'ed, and which has some Klingons in it */
244d6722163Smckusick 				if (!((ix == Ship.quadx && iy == Ship.quady) || q->stars < 0 ||
245d40d07f4Slayer 				    (q->qsystemname & Q_DISTRESSED) ||
246d40d07f4Slayer 				    (q->qsystemname & Q_SYSTEM) == 0 || q->klings <= 0))
247d6722163Smckusick 					break;
248d6722163Smckusick 			}
249d6722163Smckusick 			if (i >= 100)
250d6722163Smckusick 				/* can't seem to find one; ignore this call */
251d6722163Smckusick 				break;
252d6722163Smckusick 
253d6722163Smckusick 			/* got one!!  Schedule its enslavement */
254d40d07f4Slayer 			Ship.distressed++;
255d40d07f4Slayer 			e = xsched(E_ENSLV, 1, ix, iy, q->qsystemname);
256d40d07f4Slayer 			q->qsystemname = (e - Event) | Q_DISTRESSED;
257d6722163Smckusick 
258d6722163Smckusick 			/* tell the captain about it if we can */
259d6722163Smckusick 			if (!damaged(SSRADIO))
260d6722163Smckusick 			{
261d6722163Smckusick 				printf("\nUhura: Captain, starsystem %s in quadrant %d,%d is under attack\n",
262d6722163Smckusick 					Systemname[e->systemname], ix, iy);
263d6722163Smckusick 				restcancel++;
264d6722163Smckusick 			}
265d6722163Smckusick 			else
266d6722163Smckusick 				/* if we can't tell him, make it invisible */
267d40d07f4Slayer 				e->evcode |= E_HIDDEN;
268d6722163Smckusick 			break;
269d6722163Smckusick 
270d6722163Smckusick 		  case E_ENSLV:		/* starsystem is enslaved */
271d6722163Smckusick 			unschedule(e);
272d6722163Smckusick 			/* see if current distress call still active */
273d6722163Smckusick 			q = &Quad[e->x][e->y];
274d6722163Smckusick 			if (q->klings <= 0)
275d6722163Smckusick 			{
276d6722163Smckusick 				/* no Klingons, clean up */
277d6722163Smckusick 				/* restore the system name */
278d40d07f4Slayer 				q->qsystemname = e->systemname;
279d6722163Smckusick 				break;
280d6722163Smckusick 			}
281d6722163Smckusick 
282d6722163Smckusick 			/* play stork and schedule the first baby */
283d6722163Smckusick 			e = schedule(E_REPRO, Param.eventdly[E_REPRO] * franf(), e->x, e->y, e->systemname);
284d6722163Smckusick 
285d6722163Smckusick 			/* report the disaster if we can */
286d6722163Smckusick 			if (!damaged(SSRADIO))
287d6722163Smckusick 			{
288d6722163Smckusick 				printf("\nUhura:  We've lost contact with starsystem %s\n",
289d6722163Smckusick 					Systemname[e->systemname]);
290d6722163Smckusick 				printf("  in quadrant %d,%d.\n",
291d6722163Smckusick 					e->x, e->y);
292d6722163Smckusick 			}
293d6722163Smckusick 			else
294d40d07f4Slayer 				e->evcode |= E_HIDDEN;
295d6722163Smckusick 			break;
296d6722163Smckusick 
297d6722163Smckusick 		  case E_REPRO:		/* Klingon reproduces */
298d6722163Smckusick 			/* see if distress call is still active */
299d6722163Smckusick 			q = &Quad[e->x][e->y];
300d6722163Smckusick 			if (q->klings <= 0)
301d6722163Smckusick 			{
302d6722163Smckusick 				unschedule(e);
303d40d07f4Slayer 				q->qsystemname = e->systemname;
304d6722163Smckusick 				break;
305d6722163Smckusick 			}
306d6722163Smckusick 			xresched(e, E_REPRO, 1);
307d6722163Smckusick 			/* reproduce one Klingon */
308d6722163Smckusick 			ix = e->x;
309d6722163Smckusick 			iy = e->y;
310d6722163Smckusick 			if (Now.klings == 127)
311d6722163Smckusick 				break;		/* full right now */
312d6722163Smckusick 			if (q->klings >= MAXKLQUAD)
313d6722163Smckusick 			{
314d6722163Smckusick 				/* this quadrant not ok, pick an adjacent one */
315d6722163Smckusick 				for (i = ix - 1; i <= ix + 1; i++)
316d6722163Smckusick 				{
317d6722163Smckusick 					if (i < 0 || i >= NQUADS)
318d6722163Smckusick 						continue;
319d6722163Smckusick 					for (j = iy - 1; j <= iy + 1; j++)
320d6722163Smckusick 					{
321d6722163Smckusick 						if (j < 0 || j >= NQUADS)
322d6722163Smckusick 							continue;
323d6722163Smckusick 						q = &Quad[i][j];
324d6722163Smckusick 						/* check for this quad ok (not full & no snova) */
325d6722163Smckusick 						if (q->klings >= MAXKLQUAD || q->stars < 0)
326d6722163Smckusick 							continue;
327d6722163Smckusick 						break;
328d6722163Smckusick 					}
329d6722163Smckusick 					if (j <= iy + 1)
330d6722163Smckusick 						break;
331d6722163Smckusick 				}
332d6722163Smckusick 				if (j > iy + 1)
333d6722163Smckusick 					/* cannot create another yet */
334d6722163Smckusick 					break;
335d6722163Smckusick 				ix = i;
336d6722163Smckusick 				iy = j;
337d6722163Smckusick 			}
338d6722163Smckusick 			/* deliver the child */
339d40d07f4Slayer 			q->klings++;
340d40d07f4Slayer 			Now.klings++;
341d6722163Smckusick 			if (ix == Ship.quadx && iy == Ship.quady)
342d6722163Smckusick 			{
343d6722163Smckusick 				/* we must position Klingon */
344d6722163Smckusick 				sector(&ix, &iy);
345d6722163Smckusick 				Sect[ix][iy] = KLINGON;
346d6722163Smckusick 				k = &Etc.klingon[Etc.nkling++];
347d6722163Smckusick 				k->x = ix;
348d6722163Smckusick 				k->y = iy;
349d6722163Smckusick 				k->power = Param.klingpwr;
350d6722163Smckusick 				k->srndreq = 0;
351d6722163Smckusick 				compkldist(Etc.klingon[0].dist == Etc.klingon[0].avgdist ? 0 : 1);
352d6722163Smckusick 			}
353d6722163Smckusick 
354d6722163Smckusick 			/* recompute time left */
355d6722163Smckusick 			Now.time = Now.resource / Now.klings;
356d6722163Smckusick 			break;
357d6722163Smckusick 
358d6722163Smckusick 		  case E_SNAP:		/* take a snapshot of the galaxy */
359d6722163Smckusick 			xresched(e, E_SNAP, 1);
360d40d07f4Slayer 			i = (int) Etc.snapshot;
361d40d07f4Slayer 			i = bmove(Quad, i, sizeof (Quad));
362d40d07f4Slayer 			i = bmove(Event, i, sizeof (Event));
36377a26eb8Smckusick 			i = bmove(&Now, i, sizeof (Now));
364d6722163Smckusick 			Game.snap = 1;
365d6722163Smckusick 			break;
366d6722163Smckusick 
367d6722163Smckusick 		  case E_ATTACK:	/* Klingons attack during rest period */
368d6722163Smckusick 			if (!Move.resting)
369d6722163Smckusick 			{
370d6722163Smckusick 				unschedule(e);
371d6722163Smckusick 				break;
372d6722163Smckusick 			}
373d6722163Smckusick 			attack(1);
374d6722163Smckusick 			reschedule(e, 0.5);
375d6722163Smckusick 			break;
376d6722163Smckusick 
377d6722163Smckusick 		  case E_FIXDV:
378d6722163Smckusick 			i = e->systemname;
379d6722163Smckusick 			unschedule(e);
380d6722163Smckusick 
381d6722163Smckusick 			/* de-damage the device */
382d6722163Smckusick 			printf("%s reports repair work on the %s finished.\n",
383d6722163Smckusick 				Device[i].person, Device[i].name);
384d6722163Smckusick 
385d6722163Smckusick 			/* handle special processing upon fix */
386d6722163Smckusick 			switch (i)
387d6722163Smckusick 			{
388d6722163Smckusick 
389d6722163Smckusick 			  case LIFESUP:
390d6722163Smckusick 				Ship.reserves = Param.reserves;
391d6722163Smckusick 				break;
392d6722163Smckusick 
393d6722163Smckusick 			  case SINS:
394d6722163Smckusick 				if (Ship.cond == DOCKED)
395d6722163Smckusick 					break;
396d6722163Smckusick 				printf("Spock has tried to recalibrate your Space Internal Navigation System,\n");
397d6722163Smckusick 				printf("  but he has no standard base to calibrate to.  Suggest you get\n");
398d6722163Smckusick 				printf("  to a starbase immediately so that you can properly recalibrate.\n");
399d6722163Smckusick 				Ship.sinsbad = 1;
400d6722163Smckusick 				break;
401d6722163Smckusick 
402d6722163Smckusick 			  case SSRADIO:
403d6722163Smckusick 				restcancel = dumpssradio();
404d6722163Smckusick 				break;
405d6722163Smckusick 			}
406d6722163Smckusick 			break;
407d6722163Smckusick 
408d6722163Smckusick 		  default:
409d6722163Smckusick 			break;
410d6722163Smckusick 		}
411d6722163Smckusick 
412d6722163Smckusick 		if (restcancel && Move.resting && getynpar("Spock: Shall we cancel our rest period"))
413d6722163Smckusick 			Move.time = xdate - idate;
414d6722163Smckusick 
415d6722163Smckusick 	}
416d6722163Smckusick 
417d6722163Smckusick 	/* unschedule an attack during a rest period */
418d6722163Smckusick 	if (e = Now.eventptr[E_ATTACK])
419d6722163Smckusick 		unschedule(e);
420d6722163Smckusick 
421d6722163Smckusick 	if (!warp)
422d6722163Smckusick 	{
423d6722163Smckusick 		/* eat up energy if cloaked */
424d6722163Smckusick 		if (Ship.cloaked)
425d40d07f4Slayer 			Ship.energy -= Param.cloakenergy * Move.time;
426d6722163Smckusick 
427d6722163Smckusick 		/* regenerate resources */
428d6722163Smckusick 		rtime = 1.0 - exp(-Param.regenfac * Move.time);
429d40d07f4Slayer 		Ship.shield += (Param.shield - Ship.shield) * rtime;
430d40d07f4Slayer 		Ship.energy += (Param.energy - Ship.energy) * rtime;
431d6722163Smckusick 
432d6722163Smckusick 		/* decrement life support reserves */
433d6722163Smckusick 		if (damaged(LIFESUP) && Ship.cond != DOCKED)
434d40d07f4Slayer 			Ship.reserves -= Move.time;
435d6722163Smckusick 	}
436d6722163Smckusick 	return (0);
437d6722163Smckusick }
438