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