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