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