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