First checkin of experimental event code for the BSDTrek-style Klingons.
[super-star-trek.git] / src / events.c
1 #include "sst.h"
2 #include <math.h>
3
4 void events(void) 
5 {
6     int ictbeam=0, ipage=0, istract=0, line, i=0, j, k, l, ixhold=0, iyhold=0;
7     double fintim = game.state.date + game.optime, datemin, xtime, repair, yank=0;
8     int radio_was_broken;
9
10 #ifdef DEBUG
11     if (game.idebug) prout("EVENTS");
12 #endif
13
14     radio_was_broken = (game.damage[DRADIO] != 0.0);
15
16     for (;;) {
17         /* Select earliest extraneous event, line==0 if no events */
18         line = FSPY;
19         if (game.alldone) return;
20         datemin = fintim;
21         for (l = 1; l < NEVENTS; l++)
22             if (game.future[l] < datemin) {
23                 line = l;
24                 datemin = game.future[l];
25             }
26         xtime = datemin-game.state.date;
27         game.state.date = datemin;
28         /* Decrement Federation resources and recompute remaining time */
29         game.state.remres -= (game.state.remkl+4*game.state.remcom)*xtime;
30         game.state.remtime = game.state.remres/(game.state.remkl+4*game.state.remcom);
31         if (game.state.remtime <=0) {
32             finish(FDEPLETE);
33             return;
34         }
35         /* Is life support adequate? */
36         if (game.damage[DLIFSUP] && game.condit != IHDOCKED) {
37             if (game.lsupres < xtime && game.damage[DLIFSUP] > game.lsupres) {
38                 finish(FLIFESUP);
39                 return;
40             }
41             game.lsupres -= xtime;
42             if (game.damage[DLIFSUP] <= xtime) game.lsupres = game.inlsr;
43         }
44         /* Fix devices */
45         repair = xtime;
46         if (game.condit == IHDOCKED) repair /= game.docfac;
47         /* Don't fix Deathray here */
48         for (l=0; l<NDEVICES; l++)
49             if (game.damage[l] > 0.0 && l != DDRAY)
50                 game.damage[l] -= (game.damage[l]-repair > 0.0 ? repair : game.damage[l]);
51         /* If radio repaired, update star chart and attack reports */
52         if (radio_was_broken && game.damage[DRADIO] == 0.0) {
53             prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"));
54             prout(_("   surveillance reports are coming in."));
55             skip(1);
56             if (game.iseenit==0) {
57                 attakreport(0);
58                 game.iseenit = 1;
59             }
60             rechart();
61             prout(_("   The star chart is now up to date.\""));
62             skip(1);
63         }
64         /* Cause extraneous event LINE to occur */
65         game.optime -= xtime;
66         switch (line) {
67         case FSNOVA: /* Supernova */
68             if (ipage==0) pause_game(1);
69             ipage=1;
70             snova(0,0);
71             game.future[FSNOVA] = game.state.date + expran(0.5*game.intime);
72             if (game.state.galaxy[game.quadx][game.quady].supernova) return;
73             break;
74         case FSPY: /* Check with spy to see if S.C. should tractor beam */
75             if (game.state.nscrem == 0 ||
76                 ictbeam+istract > 0 ||
77                 game.condit==IHDOCKED || game.isatb==1 || game.iscate==1) return;
78             if (game.ientesc ||
79                 (game.energy < 2000 && game.torps < 4 && game.shield < 1250) ||
80                 (game.damage[DPHASER]>0 && (game.damage[DPHOTON]>0 || game.torps < 4)) ||
81                 (game.damage[DSHIELD] > 0 &&
82                  (game.energy < 2500 || game.damage[DPHASER] > 0) &&
83                  (game.torps < 5 || game.damage[DPHOTON] > 0))) {
84                 /* Tractor-beam her! */
85                 istract=1;
86                 yank = square(game.state.isx-game.quadx) + square(game.state.isy-game.quady);
87                 /********* fall through to FTBEAM code ***********/
88             }
89             else return;
90         case FTBEAM: /* Tractor beam */
91             if (line==FTBEAM) {
92                 if (game.state.remcom == 0) {
93                     game.future[FTBEAM] = FOREVER;
94                     break;
95                 }
96                 i = Rand()*game.state.remcom+1.0;
97                 yank = square(game.state.cx[i]-game.quadx) + square(game.state.cy[i]-game.quady);
98                 if (istract || game.condit == IHDOCKED || yank == 0) {
99                     /* Drats! Have to reschedule */
100                     game.future[FTBEAM] = game.state.date + game.optime +
101                         expran(1.5*game.intime/game.state.remcom);
102                     break;
103                 }
104             }
105             /* tractor beaming cases merge here */
106             yank = sqrt(yank);
107             if (ipage==0) pause_game(1);
108             ipage=1;
109             game.optime = (10.0/(7.5*7.5))*yank; /* 7.5 is yank rate (warp 7.5) */
110             ictbeam = 1;
111             skip(1);
112             proutn("***");
113             crmshp();
114             prout(_(" caught in long range tractor beam--"));
115             /* If Kirk & Co. screwing around on planet, handle */
116             atover(1); /* atover(1) is Grab */
117             if (game.alldone) return;
118             if (game.icraft == 1) { /* Caught in Galileo? */
119                 finish(FSTRACTOR);
120                 return;
121             }
122             /* Check to see if shuttle is aboard */
123             if (game.iscraft==0) {
124                 skip(1);
125                 if (Rand() > 0.5) {
126                     prout(_("Galileo, left on the planet surface, is captured"));
127                     prout(_("by aliens and made into a flying McDonald's."));
128                     game.damage[DSHUTTL] = -10;
129                     game.iscraft = -1;
130                 }
131                 else {
132                     prout(_("Galileo, left on the planet surface, is well hidden."));
133                 }
134             }
135             if (line==0) {
136                 game.quadx = game.state.isx;
137                 game.quady = game.state.isy;
138             }
139             else {
140                 game.quadx = game.state.cx[i];
141                 game.quady = game.state.cy[i];
142             }
143             iran(QUADSIZE, &game.sectx, &game.secty);
144             crmshp();
145             proutn(_(" is pulled to "));
146             proutn(cramlc(quadrant, game.quadx, game.quady));
147             proutn(", ");
148             prout(cramlc(sector, game.sectx, game.secty));
149             if (game.resting) {
150                 prout(_("(Remainder of rest/repair period cancelled.)"));
151                 game.resting = 0;
152             }
153             if (game.shldup==0) {
154                 if (game.damage[DSHIELD]==0 && game.shield > 0) {
155                     doshield(2); /* Shldsup */
156                     game.shldchg=0;
157                 }
158                 else prout(_("(Shields not currently useable.)"));
159             }
160             newqad(0);
161             /* Adjust finish time to time of tractor beaming */
162             fintim = game.state.date+game.optime;
163             attack(0);
164             if (game.state.remcom <= 0) game.future[FTBEAM] = FOREVER;
165             else game.future[FTBEAM] = game.state.date+game.optime+expran(1.5*game.intime/game.state.remcom);
166             break;
167         case FSNAP: /* Snapshot of the universe (for time warp) */
168             game.snapsht = game.state;
169             game.state.snap = 1;
170             game.future[FSNAP] = game.state.date + expran(0.5 * game.intime);
171             break;
172         case FBATTAK: /* Commander attacks starbase */
173             if (game.state.remcom==0 || game.state.rembase==0) {
174                 /* no can do */
175                 game.future[FBATTAK] = game.future[FCDBAS] = FOREVER;
176                 break;
177             }
178             i = 0;
179             for_starbases(j) {
180                 for_commanders(k)
181                     if (game.state.baseqx[j]==game.state.cx[k] && game.state.baseqy[j]==game.state.cy[k] &&
182                         (game.state.baseqx[j]!=game.quadx || game.state.baseqy[j]!=game.quady) &&
183                         (game.state.baseqx[j]!=game.state.isx || game.state.baseqy[j]!=game.state.isy)) {
184                         i = 1;
185                         break;
186                     }
187                 if (i == 1) break;
188             }
189             if (j>game.state.rembase) {
190                 /* no match found -- try later */
191                 game.future[FBATTAK] = game.state.date + expran(0.3*game.intime);
192                 game.future[FCDBAS] = FOREVER;
193                 break;
194             }
195             /* commander + starbase combination found -- launch attack */
196             game.batx = game.state.baseqx[j];
197             game.baty = game.state.baseqy[j];
198             game.future[FCDBAS] = game.state.date+1.0+3.0*Rand();
199             if (game.isatb) /* extra time if SC already attacking */
200                 game.future[FCDBAS] += game.future[FSCDBAS]-game.state.date;
201             game.future[FBATTAK] = game.future[FCDBAS] +expran(0.3*game.intime);
202             game.iseenit = 0;
203             if (game.damage[DRADIO] != 0.0 &&
204                 game.condit != IHDOCKED) break; /* No warning :-( */
205             game.iseenit = 1;
206             if (ipage==0) pause_game(1);
207             ipage = 1;
208             skip(1);
209             proutn(_("Lt. Uhura-  \"Captain, the starbase in "));
210             prout(cramlc(quadrant, game.batx, game.baty));
211             prout(_("   reports that it is under attack and that it can"));
212             proutn(_("   hold out only until stardate %d"),
213                    (int)game.future[FCDBAS]);
214             prout(".\"");
215             if (game.resting) {
216                 skip(1);
217                 proutn(_("Mr. Spock-  \"Captain, shall we cancel the rest period?\""));
218                 if (ja()) {
219                     game.resting = 0;
220                     game.optime = 0.0;
221                     return;
222                 }
223             }
224             break;
225         case FSCDBAS: /* Supercommander destroys base */
226             game.future[FSCDBAS] = FOREVER;
227             game.isatb = 2;
228             if (!game.state.galaxy[game.state.isx][game.state.isy].starbase) 
229                 break; /* WAS RETURN! */
230             ixhold = game.batx;
231             iyhold = game.baty;
232             game.batx = game.state.isx;
233             game.baty = game.state.isy;
234         case FCDBAS: /* Commander succeeds in destroying base */
235             if (line==FCDBAS) {
236                 game.future[FCDBAS] = FOREVER;
237                 /* find the lucky pair */
238                 for_commanders(i)
239                     if (game.state.cx[i]==game.batx && game.state.cy[i]==game.baty) 
240                         break;
241                 if (i > game.state.remcom || game.state.rembase == 0 ||
242                     !game.state.galaxy[game.batx][game.baty].starbase) {
243                     /* No action to take after all */
244                     game.batx = game.baty = 0;
245                     break;
246                 }
247             }
248             /* Code merges here for any commander destroying base */
249             /* Not perfect, but will have to do */
250             /* Handle case where base is in same quadrant as starship */
251             if (game.batx==game.quadx && game.baty==game.quady) {
252                 game.state.chart[game.batx][game.baty].starbase = FALSE;
253                 game.quad[game.basex][game.basey]= IHDOT;
254                 game.basex=game.basey=0;
255                 newcnd();
256                 skip(1);
257                 prout(_("Spock-  \"Captain, I believe the starbase has been destroyed.\""));
258             }
259             else if (game.state.rembase != 1 &&
260                      (game.damage[DRADIO] <= 0.0 || game.condit == IHDOCKED)) {
261                 /* Get word via subspace radio */
262                 if (ipage==0) pause_game(1);
263                 ipage = 1;
264                 skip(1);
265                 prout(_("Lt. Uhura-  \"Captain, Starfleet Command reports that"));
266                 proutn(_("   the starbase in "));
267                 proutn(cramlc(quadrant, game.batx, game.baty));
268                 prout(_(" has been destroyed by"));
269                 if (game.isatb==2) prout(_("the Klingon Super-Commander"));
270                 else prout(_("a Klingon Commander"));
271                 game.state.chart[game.batx][game.baty].starbase = FALSE;
272             }
273             /* Remove Starbase from galaxy */
274             game.state.galaxy[game.batx][game.baty].starbase = FALSE;
275             for_starbases(i)
276                 if (game.state.baseqx[i]==game.batx && game.state.baseqy[i]==game.baty) {
277                     game.state.baseqx[i]=game.state.baseqx[game.state.rembase];
278                     game.state.baseqy[i]=game.state.baseqy[game.state.rembase];
279                 }
280             game.state.rembase--;
281             if (game.isatb == 2) {
282                 /* reinstate a commander's base attack */
283                 game.batx = ixhold;
284                 game.baty = iyhold;
285                 game.isatb = 0;
286             }
287             else {
288                 game.batx = game.baty = 0;
289             }
290             break;
291         case FSCMOVE: /* Supercommander moves */
292             game.future[FSCMOVE] = game.state.date+0.2777;
293             if (game.ientesc+istract==0 &&
294                 game.isatb!=1 &&
295                 (game.iscate!=1 || game.justin==1)) scom(&ipage);
296             break;
297         case FDSPROB: /* Move deep space probe */
298             game.future[FDSPROB] = game.state.date + 0.01;
299             game.probex += game.probeinx;
300             game.probey += game.probeiny;
301             i = (int)(game.probex/QUADSIZE +0.05);
302             j = (int)(game.probey/QUADSIZE + 0.05);
303             if (game.probecx != i || game.probecy != j) {
304                 game.probecx = i;
305                 game.probecy = j;
306                 if (!VALID_QUADRANT(i, j) ||
307                     game.state.galaxy[game.probecx][game.probecy].supernova) {
308                     // Left galaxy or ran into supernova
309                     if (game.damage[DRADIO]==0.0 || game.condit == IHDOCKED) {
310                         if (ipage==0) pause_game(1);
311                         ipage = 1;
312                         skip(1);
313                         proutn(_("Lt. Uhura-  \"The deep space probe "));
314                         if (!VALID_QUADRANT(j, i))
315                             proutn(_("has left the galaxy"));
316                         else
317                             proutn(_("is no longer transmitting"));
318                         prout(".\"");
319                     }
320                     game.future[FDSPROB] = FOREVER;
321                     break;
322                 }
323                 if (game.damage[DRADIO]==0.0   || game.condit == IHDOCKED) {
324                     if (ipage==0) pause_game(1);
325                     ipage = 1;
326                     skip(1);
327                     proutn(_("Lt. Uhura-  \"The deep space probe is now in "));
328                     proutn(cramlc(quadrant, game.probecx, game.probecy));
329                     prout(".\"");
330                 }
331             }
332             /* Update star chart if Radio is working or have access to
333                radio. */
334             if (game.damage[DRADIO] == 0.0 || game.condit == IHDOCKED) {
335                 game.state.chart[game.probecx][game.probecy].klingons = game.state.galaxy[game.probecx][game.probecy].klingons;
336                 game.state.chart[game.probecx][game.probecy].starbase = game.state.galaxy[game.probecx][game.probecy].starbase;
337                 game.state.chart[game.probecx][game.probecy].stars = game.state.galaxy[game.probecx][game.probecy].stars;
338                 game.state.galaxy[game.probecx][game.probecy].charted = TRUE;
339             }
340             game.proben--; // One less to travel
341             if (game.proben == 0 && game.isarmed &&
342                 game.state.galaxy[game.probecx][game.probecy].stars) {
343                 /* lets blow the sucker! */
344                 snova(1,0);
345                 game.future[FDSPROB] = FOREVER;
346                 if (game.state.galaxy[game.quadx][game.quady].supernova) 
347                     return;
348             }
349             break;
350 #ifdef EXPERIMENTAL
351         case FDISTR: /* inhabited system issues distress call */
352             /* in BSD Trek this is a straight 1 stardate ahead */ 
353             game.future[FDISTR] =  game.state.date + 1.0 + Rand();
354             /* if we already have too many, throw this one away */
355             if (game.ndistr >= MAXDISTR)
356                 break;
357             /* try a whole bunch of times to find something suitable */
358             for (i = 0; i < 100; i++) {
359                 struct quadrant *q;
360                 iran(GALSIZE, &ix, &iy);
361                 q = &game.state.galaxy[game.quadx][game.quady];
362                 /* need a quadrant which is not the current one,
363                    which has some stars which are inhabited and
364                    not already under attack, which is not
365                    supernova'ed, and which has some Klingons in it */
366                 if (!((ix == game.quadx && iy == game.quady) || q->stars<=0 ||
367                       (q->qsystemname & Q_DISTRESSED) ||
368                       (q->qsystemname & Q_SYSTEM) == 0 || q->klings <= 0))
369                     break;
370             }
371             if (i >= 100)
372                 /* can't seem to find one; ignore this call */
373                 break;
374
375             /* got one!!  Schedule its enslavement */
376             game.ndistr++;
377             e = xsched(E_ENSLV, 1, ix, iy, q->qsystemname);
378             q->qsystemname = (e - Event) | Q_DISTRESSED;
379
380             /* tell the captain about it if we can */
381             if (game.damage[DRADIO] == 0.0)
382             {
383                 printf("\nUhura: Captain, starsystem %s in quadrant %d,%d is under attack\n",
384                        Systemname[e->systemname], ix, iy);
385                 restcancel++;
386             }
387             else
388                 /* if we can't tell him, make it invisible */
389                 e->evcode |= E_HIDDEN;
390             break;
391       case FENSLV:              /* starsystem is enslaved */
392             unschedule(e);
393             /* see if current distress call still active */
394             q = &Quad[e->x][e->y];
395             if (q->klings <= 0)
396             {
397                 /* no Klingons, clean up */
398                 /* restore the system name */
399                 q->qsystemname = e->systemname;
400                 break;
401             }
402
403             /* play stork and schedule the first baby */
404             e = schedule(E_REPRO, Param.eventdly[E_REPRO] * franf(), e->x, e->y, e->systemname);
405
406             /* report the disaster if we can */
407             if (game.damage[DRADIO] == 0.0)
408             {
409                 printf("\nUhura:  We've lost contact with starsystem %s\n",
410                        Systemname[e->systemname]);
411                 printf("  in quadrant %d,%d.\n", e->x, e->y);
412             }
413             else
414                 e->evcode |= E_HIDDEN;
415             break;
416       case FREPRO:              /* Klingon reproduces */
417             /* see if distress call is still active */
418             q = &Quad[e->x][e->y];
419             if (q->klings <= 0)
420             {
421                 unschedule(e);
422                 q->qsystemname = e->systemname;
423                 break;
424             }
425             xresched(e, E_REPRO, 1);
426             /* reproduce one Klingon */
427             ix = e->x;
428             iy = e->y;
429             if (Now.klings == 127)
430                 break;          /* full right now */
431             if (q->klings >= MAXKLQUAD)
432             {
433                 /* this quadrant not ok, pick an adjacent one */
434                 for (i = ix - 1; i <= ix + 1; i++)
435                 {
436                     if (!VALID_QUADRANT(i))
437                         continue;
438                     for (j = iy - 1; j <= iy + 1; j++)
439                     {
440                         if (!VALID_QUADRANT(j))
441                             continue;
442                         q = &Quad[i][j];
443                         /* check for this quad ok (not full & no snova) */
444                         if (q->klings >= MAXKLQUAD || q->stars < 0)
445                             continue;
446                         break;
447                     }
448                     if (j <= iy + 1)
449                         break;
450                 }
451                 if (j > iy + 1)
452                     /* cannot create another yet */
453                     break;
454                 ix = i;
455                 iy = j;
456             }
457             /* deliver the child */
458             game.remkl++;
459             if (ix == game.quadx && iy == game.quady)
460                 newkling(++game.klhere, &ixhold, &iyhold);
461
462             /* recompute time left */
463             game.state.remtime = game.state.remres/(game.state.remkl+4*game.state.remcom);
464             break;
465 #endif /* EXPERIMENTAL */
466         }
467     }
468 }
469
470                                 
471 void wait(void) 
472 {
473     int key;
474     double temp, delay, origTime;
475
476     game.ididit = 0;
477     for (;;) {
478         key = scan();
479         if (key  != IHEOL) break;
480         proutn(_("How long? "));
481     }
482     chew();
483     if (key != IHREAL) {
484         huh();
485         return;
486     }
487     origTime = delay = aaitem;
488     if (delay <= 0.0) return;
489     if (delay >= game.state.remtime || game.nenhere != 0) {
490         proutn(_("Are you sure? "));
491         if (ja() == 0) return;
492     }
493
494     /* Alternate resting periods (events) with attacks */
495
496     game.resting = 1;
497     do {
498         if (delay <= 0) game.resting = 0;
499         if (game.resting == 0) {
500             prout(_("%d stardates left."), (int)game.state.remtime);
501             return;
502         }
503         temp = game.optime = delay;
504
505         if (game.nenhere) {
506             double rtime = 1.0 + Rand();
507             if (rtime < temp) temp = rtime;
508             game.optime = temp;
509         }
510         if (game.optime < delay) attack(0);
511         if (game.alldone) return;
512         events();
513         game.ididit = 1;
514         if (game.alldone) return;
515         delay -= temp;
516         /* Repair Deathray if long rest at starbase */
517         if (origTime-delay >= 9.99 && game.condit == IHDOCKED)
518             game.damage[DDRAY] = 0.0;
519     } while 
520         // leave if quadrant supernovas
521         (!game.state.galaxy[game.quadx][game.quady].supernova);
522
523     game.resting = 0;
524     game.optime = 0;
525 }
526
527 void nova(int ix, int iy) 
528 {
529     static double course[] =
530         {0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5};
531     int bot, top, top2, hits[QUADSIZE+1][3], kount, icx, icy, mm, nn, j;
532     int iquad, iquad1, i, ll, newcx, newcy, ii, jj;
533     if (Rand() < 0.05) {
534         /* Wow! We've supernova'ed */
535         snova(ix, iy);
536         return;
537     }
538
539     /* handle initial nova */
540     game.quad[ix][iy] = IHDOT;
541     crmena(1, IHSTAR, 2, ix, iy);
542     prout(_(" novas."));
543     game.state.galaxy[game.quadx][game.quady].stars--;
544     game.state.starkl++;
545         
546     /* Set up stack to recursively trigger adjacent stars */
547     bot = top = top2 = 1;
548     kount = 0;
549     icx = icy = 0;
550     hits[1][1] = ix;
551     hits[1][2] = iy;
552     while (1) {
553         for (mm = bot; mm <= top; mm++) 
554             for (nn = 1; nn <= 3; nn++)  /* nn,j represents coordinates around current */
555                 for (j = 1; j <= 3; j++) {
556                     if (j==2 && nn== 2) continue;
557                     ii = hits[mm][1]+nn-2;
558                     jj = hits[mm][2]+j-2;
559                     if (!VALID_SECTOR(jj, ii)) continue;
560                     iquad = game.quad[ii][jj];
561                     switch (iquad) {
562                     // case IHDOT:      /* Empty space ends reaction
563                     // case IHQUEST:
564                     // case IHBLANK:
565                     // case IHT:
566                     // case IHWEB:
567                     default:
568                         break;
569                     case IHSTAR: /* Affect another star */
570                         if (Rand() < 0.05) {
571                             /* This star supernovas */
572                             snova(ii,jj);
573                             return;
574                         }
575                         top2++;
576                         hits[top2][1]=ii;
577                         hits[top2][2]=jj;
578                         game.state.galaxy[game.quadx][game.quady].stars -= 1;
579                         game.state.starkl++;
580                         crmena(1, IHSTAR, 2, ii, jj);
581                         prout(_(" novas."));
582                         game.quad[ii][jj] = IHDOT;
583                         break;
584                     case IHP: /* Destroy planet */
585                         game.state.galaxy[game.quadx][game.quady].planet = NULL;
586                         game.state.nplankl++;
587                         crmena(1, IHP, 2, ii, jj);
588                         prout(_(" destroyed."));
589                         DESTROY(&game.state.plnets[game.iplnet]);
590                         game.iplnet = game.plnetx = game.plnety = 0;
591                         if (game.landed == 1) {
592                             finish(FPNOVA);
593                             return;
594                         }
595                         game.quad[ii][jj] = IHDOT;
596                         break;
597                     case IHB: /* Destroy base */
598                         game.state.galaxy[game.quadx][game.quady].starbase = FALSE;
599                         for_starbases(i)
600                             if (game.state.baseqx[i]==game.quadx && game.state.baseqy[i]==game.quady) 
601                                 break;
602                         game.state.baseqx[i] = game.state.baseqx[game.state.rembase];
603                         game.state.baseqy[i] = game.state.baseqy[game.state.rembase];
604                         game.state.rembase--;
605                         game.basex = game.basey = 0;
606                         game.state.basekl++;
607                         newcnd();
608                         crmena(1, IHB, 2, ii, jj);
609                         prout(_(" destroyed."));
610                         game.quad[ii][jj] = IHDOT;
611                         break;
612                     case IHE: /* Buffet ship */
613                     case IHF:
614                         prout(_("***Starship buffeted by nova."));
615                         if (game.shldup) {
616                             if (game.shield >= 2000.0) game.shield -= 2000.0;
617                             else {
618                                 double diff = 2000.0 - game.shield;
619                                 game.energy -= diff;
620                                 game.shield = 0.0;
621                                 game.shldup = 0;
622                                 prout(_("***Shields knocked out."));
623                                 game.damage[DSHIELD] += 0.005*game.damfac*Rand()*diff;
624                             }
625                         }
626                         else game.energy -= 2000.0;
627                         if (game.energy <= 0) {
628                             finish(FNOVA);
629                             return;
630                         }
631                         /* add in course nova contributes to kicking starship*/
632                         icx += game.sectx-hits[mm][1];
633                         icy += game.secty-hits[mm][2];
634                         kount++;
635                         break;
636                     case IHK: /* kill klingon */
637                         deadkl(ii,jj,iquad, ii, jj);
638                         break;
639                     case IHC: /* Damage/destroy big enemies */
640                     case IHS:
641                     case IHR:
642                         for_local_enemies(ll)
643                             if (game.kx[ll]==ii && game.ky[ll]==jj) break;
644                         game.kpower[ll] -= 800.0; /* If firepower is lost, die */
645                         if (game.kpower[ll] <= 0.0) {
646                             deadkl(ii, jj, iquad, ii, jj);
647                             break;
648                         }
649                         newcx = ii + ii - hits[mm][1];
650                         newcy = jj + jj - hits[mm][2];
651                         crmena(1, iquad, 2, ii, jj);
652                         proutn(_(" damaged"));
653                         if (!VALID_SECTOR(newcx, newcy)) {
654                             /* can't leave quadrant */
655                             skip(1);
656                             break;
657                         }
658                         iquad1 = game.quad[newcx][newcy];
659                         if (iquad1 == IHBLANK) {
660                             proutn(_(", blasted into "));
661                             crmena(0, IHBLANK, 2, newcx, newcy);
662                             skip(1);
663                             deadkl(ii, jj, iquad, newcx, newcy);
664                             break;
665                         }
666                         if (iquad1 != IHDOT) {
667                             /* can't move into something else */
668                             skip(1);
669                             break;
670                         }
671                         proutn(_(", buffeted to "));
672                         proutn(cramlc(sector, newcx, newcy));
673                         game.quad[ii][jj] = IHDOT;
674                         game.quad[newcx][newcy] = iquad;
675                         game.kx[ll] = newcx;
676                         game.ky[ll] = newcy;
677                         game.kavgd[ll] = sqrt(square(game.sectx-newcx)+square(game.secty-newcy));
678                         game.kdist[ll] = game.kavgd[ll];
679                         skip(1);
680                         break;
681                     }
682                 }
683         if (top == top2) 
684             break;
685         bot = top + 1;
686         top = top2;
687     }
688     if (kount==0) 
689         return;
690
691     /* Starship affected by nova -- kick it away. */
692     game.dist = kount*0.1;
693     if (icx) icx = (icx < 0 ? -1 : 1);
694     if (icy) icy = (icy < 0 ? -1 : 1);
695     game.direc = course[3*(icx+1)+icy+2];
696     if (game.direc == 0.0) game.dist = 0.0;
697     if (game.dist == 0.0) return;
698     game.optime = 10.0*game.dist/16.0;
699     skip(1);
700     prout(_("Force of nova displaces starship."));
701     game.iattak=2;      /* Eliminates recursion problem */
702     imove();
703     game.optime = 10.0*game.dist/16.0;
704     return;
705 }
706         
707         
708 void snova(int insx, int insy) 
709 {
710     int comdead, nqx=0, nqy=0, nsx, nsy, num=0, kldead, iscdead;
711     int nrmdead, npdead;
712     int incipient=0;
713
714     nsx = insy;
715     nsy = insy;
716
717     if (insy== 0) {
718         if (insx == 1) {
719             /* NOVAMAX being used */
720             nqx = game.probecx;
721             nqy = game.probecy;
722         }
723         else {
724             int stars = 0;
725             /* Scheduled supernova -- select star */
726             /* logic changed here so that we won't favor quadrants in top
727                left of universe */
728             for_quadrants(nqx) {
729                 for_quadrants(nqy) {
730                     stars += game.state.galaxy[nqx][nqy].stars;
731                 }
732             }
733             if (stars == 0) return; /* nothing to supernova exists */
734             num = Rand()*stars + 1;
735             for_quadrants(nqx) {
736                 for_quadrants(nqy) {
737                     num -= game.state.galaxy[nqx][nqy].stars;
738                     if (num <= 0) break;
739                 }
740                 if (num <=0) break;
741             }
742 #ifdef DEBUG
743             if (game.idebug) {
744                 proutn("Super nova here?");
745                 if (ja()==1) {
746                     nqx = game.quadx;
747                     nqy = game.quady;
748                 }
749             }
750 #endif
751         }
752
753         if (nqx != game.quady || nqy != game.quady || game.justin != 0) {
754             /* it isn't here, or we just entered (treat as inroute) */
755             if (game.damage[DRADIO] == 0.0 || game.condit == IHDOCKED) {
756                 skip(1);
757                 prout(_("Message from Starfleet Command       Stardate %.2f"), game.state.date);
758                 prout(_("     Supernova in %s; caution advised."),
759                       cramlc(quadrant, nqx, nqy));
760             }
761         }
762         else {
763             /* we are in the quadrant! */
764             incipient = 1;
765             num = Rand()* game.state.galaxy[nqx][nqy].stars + 1;
766             for_sectors(nsx) {
767                 for_sectors(nsy) {
768                     if (game.quad[nsx][nsy]==IHSTAR) {
769                         num--;
770                         if (num==0) break;
771                     }
772                 }
773                 if (num==0) break;
774             }
775         }
776     }
777     else {
778         incipient = 1;
779     }
780
781     if (incipient) {
782         skip(1);
783         prouts(_("***RED ALERT!  RED ALERT!"));
784         skip(1);
785         prout(_("***Incipient supernova detected at "), cramlc(sector, nsx, nsy));
786         nqx = game.quadx;
787         nqy = game.quady;
788         if (square(nsx-game.sectx) + square(nsy-game.secty) <= 2.1) {
789             proutn(_("Emergency override attempts t"));
790             prouts("***************");
791             skip(1);
792             stars();
793             game.alldone=1;
794         }
795     }
796     /* destroy any Klingons in supernovaed quadrant */
797     kldead = game.state.galaxy[nqx][nqy].klingons;
798     game.state.galaxy[nqx][nqy].klingons = 0;
799     comdead = iscdead = 0;
800     if (nqx==game.state.isx && nqy == game.state.isy) {
801         /* did in the Supercommander! */
802         game.state.nscrem = game.state.isx = game.state.isy = game.isatb = game.iscate = 0;
803         iscdead = 1;
804         game.future[FSCMOVE] = game.future[FSCDBAS] = FOREVER;
805     }
806     if (game.state.remcom) {
807         int maxloop = game.state.remcom, l;
808         for (l = 1; l <= maxloop; l++) {
809             if (game.state.cx[l] == nqx && game.state.cy[l] == nqy) {
810                 game.state.cx[l] = game.state.cx[game.state.remcom];
811                 game.state.cy[l] = game.state.cy[game.state.remcom];
812                 game.state.cx[game.state.remcom] = game.state.cy[game.state.remcom] = 0;
813                 game.state.remcom--;
814                 kldead--;
815                 comdead++;
816                 if (game.state.remcom==0) game.future[FTBEAM] = FOREVER;
817                 break;
818             }
819         }
820     }
821     game.state.remkl -= kldead;
822     /* destroy Romulans and planets in supernovaed quadrant */
823     nrmdead = game.state.galaxy[nqx][nqy].romulans;
824     game.state.galaxy[nqx][nqy].romulans = 0;
825     game.state.nromrem -= nrmdead;
826     npdead = num - nrmdead*10;
827     if (npdead) {
828         int l;
829         for (l = 0; l < game.inplan; l++)
830             if (game.state.plnets[l].x == nqx && game.state.plnets[l].y == nqy) {
831                 DESTROY(&game.state.plnets[l]);
832             }
833     }
834     /* Destroy any base in supernovaed quadrant */
835     if (game.state.rembase) {
836         int maxloop = game.state.rembase, l;
837         for (l = 1; l <= maxloop; l++)
838             if (game.state.baseqx[l]==nqx && game.state.baseqy[l]==nqy) {
839                 game.state.baseqx[l] = game.state.baseqx[game.state.rembase];
840                 game.state.baseqy[l] = game.state.baseqy[game.state.rembase];
841                 game.state.baseqx[game.state.rembase] = game.state.baseqy[game.state.rembase] = 0;
842                 game.state.rembase--;
843                 break;
844             }
845     }
846     /* If starship caused supernova, tally up destruction */
847     if (insx) {
848         game.state.starkl += game.state.galaxy[nqx][nqy].stars;
849         game.state.basekl += game.state.galaxy[nqx][nqy].starbase;
850         game.state.nplankl += npdead;
851     }
852     /* mark supernova in galaxy and in star chart */
853     if ((game.quadx == nqx && game.quady == nqy) ||
854         game.damage[DRADIO] == 0 ||
855         game.condit == IHDOCKED)
856         game.state.galaxy[nqx][nqy].supernova = TRUE;
857     /* If supernova destroys last klingons give special message */
858     if (KLINGREM==0 && (nqx != game.quadx || nqy != game.quady)) {
859         skip(2);
860         if (insx == 0) prout(_("Lucky you!"));
861         proutn(_("A supernova in %s has just destroyed the last Klingons."),
862                cramlc(quadrant, nqx, nqy));
863         finish(FWON);
864         return;
865     }
866     /* if some Klingons remain, continue or die in supernova */
867     if (game.alldone) finish(FSNOVAED);
868     return;
869 }
870                 
871