xref: /dragonfly/games/trek/events.c (revision 4318c66eac379e15105fe145d406dfef81b795f6)
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
events(int timewarp)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 }
475