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