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