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