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