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