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