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