Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
3 | * 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 | ||
34 | #ifndef lint | |
35 | static char sccsid[] = "@(#)events.c 5.4 (Berkeley) 6/1/90"; | |
36 | #endif /* not lint */ | |
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 | register 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 | register struct quad *q; | |
61 | register 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 | } |