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