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