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