Clean up nasty FORTRAN-style if statements.
[super-star-trek.git] / src / moving.c
1 #include <unistd.h>
2 #include "sstlinux.h"
3 #include "sst.h"
4
5 static void getcd(bool, int);
6
7 void imove(bool novapush)
8 /* movement execution for warp, impulse, supernova, and tractor-beam events */
9 {
10     double angle, deltax, deltay, bigger, x, y,
11         finald, stopegy, probf;
12     int n, m, kink, kinks;
13     feature iquad;
14     coord w, final;
15     bool trbeam = false;
16
17     w.x = w.y = 0;
18     if (game.inorbit) {
19         prout(_("Helmsman Sulu- \"Leaving standard orbit.\""));
20         game.inorbit = false;
21     }
22
23     angle = ((15.0 - game.direc) * 0.5235988);
24     deltax = -sin(angle);
25     deltay = cos(angle);
26     if (fabs(deltax) > fabs(deltay))
27         bigger = fabs(deltax);
28     else
29         bigger = fabs(deltay);
30                 
31     deltay /= bigger;
32     deltax /= bigger;
33
34     /* If tractor beam is to occur, don't move full distance */
35     if (game.state.date+game.optime >= scheduled(FTBEAM)) {
36         trbeam = true;
37         game.condition = red;
38         game.dist = game.dist*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1;
39         game.optime = scheduled(FTBEAM) - game.state.date + 1e-5;
40     }
41     /* Move within the quadrant */
42     game.quad[game.sector.x][game.sector.y] = IHDOT;
43     x = game.sector.x;
44     y = game.sector.y;
45     n = 10.0*game.dist*bigger+0.5;
46
47     if (n > 0) {
48         for (m = 1; m <= n; m++) {
49             w.x = (x += deltax) + 0.5;
50             w.y = (y += deltay) + 0.5;
51             if (!VALID_SECTOR(w.x, w.y)) {
52                 /* Leaving quadrant -- allow final enemy attack */
53                 /* Don't do it if being pushed by Nova */
54                 if (game.nenhere != 0 && !novapush) {
55                     newcnd();
56                     for_local_enemies(m) {
57                         finald = distance(w, game.ks[m]);
58                         game.kavgd[m] = 0.5 * (finald + game.kdist[m]);
59                     }
60                     /*
61                      * Stas Sergeev added the condition
62                      * that attacks only happen if Klingons
63                      * are present and your skill is good.
64                      */
65                     if (game.skill > SKILL_GOOD && game.klhere > 0 && !game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova)
66                         attack(false);
67                     if (game.alldone)
68                         return;
69                 }
70                 /* compute final position -- new quadrant and sector */
71                 x = QUADSIZE*(game.quadrant.x-1)+game.sector.x;
72                 y = QUADSIZE*(game.quadrant.y-1)+game.sector.y;
73                 w.x = x+10.0*game.dist*bigger*deltax+0.5;
74                 w.y = y+10.0*game.dist*bigger*deltay+0.5;
75                 /* check for edge of galaxy */
76                 kinks = 0;
77                 do {
78                     kink = 0;
79                     if (w.x <= 0) {
80                         w.x = -w.x + 1;
81                         kink = 1;
82                     }
83                     if (w.y <= 0) {
84                         w.y = -w.y + 1;
85                         kink = 1;
86                     }
87                     if (w.x > GALSIZE*QUADSIZE) {
88                         w.x = (GALSIZE*QUADSIZE*2)+1 - w.x;
89                         kink = 1;
90                     }
91                     if (w.y > GALSIZE*QUADSIZE) {
92                         w.y = (GALSIZE*QUADSIZE*2)+1 - w.y;
93                         kink = 1;
94                     }
95                     if (kink)
96                         kinks = 1;
97                 } while (kink);
98
99                 if (kinks) {
100                     game.nkinks += 1;
101                     if (game.nkinks == 3) {
102                         /* Three strikes -- you're out! */
103                         finish(FNEG3);
104                         return;
105                     }
106                     skip(1);
107                     prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"));
108                     prout(_("AT THE EDGE OF THE GALAXY.  THE THIRD TIME YOU TRY THIS,"));
109                     prout(_("YOU WILL BE DESTROYED."));
110                 }
111                 /* Compute final position in new quadrant */
112                 if (trbeam) return; /* Don't bother if we are to be beamed */
113                 game.quadrant.x = (w.x+(QUADSIZE-1))/QUADSIZE;
114                 game.quadrant.y = (w.y+(QUADSIZE-1))/QUADSIZE;
115                 game.sector.x = w.x - QUADSIZE*(game.quadrant.x-1);
116                 game.sector.y = w.y - QUADSIZE*(game.quadrant.y-1);
117                 skip(1);
118                 prout(_("Entering %s."), cramlc(quadrant, game.quadrant));
119                 game.quad[game.sector.x][game.sector.y] = game.ship;
120                 newqad(false);
121                 if (game.skill>SKILL_NOVICE)
122                     attack(false);  
123                 return;
124             }
125             iquad = game.quad[w.x][w.y];
126             if (iquad != IHDOT) {
127                 /* object encountered in flight path */
128                 stopegy = 50.0*game.dist/game.optime;
129                 game.dist = distance(game.sector, w) / (QUADSIZE * 1.0);
130                 switch (iquad) {
131                 case IHT: /* Ram a Tholian */
132                 case IHK: /* Ram enemy ship */
133                 case IHC:
134                 case IHS:
135                 case IHR:
136                 case IHQUEST:
137                     game.sector = w;
138                     ram(false, iquad, game.sector);
139                     final = game.sector;
140                     break;
141                 case IHBLANK:
142                     skip(1);
143                     prouts(_("***RED ALERT!  RED ALERT!"));
144                     skip(1);
145                     proutn("***");
146                     crmshp();
147                     proutn(_(" pulled into black hole at "));
148                     prout(cramlc(sector, w));
149                     /*
150                      * Getting pulled into a black hole was certain
151                      * death in Almy's original.  Stas Sergeev added a
152                      * possibility that you'll get timewarped instead.
153                      */
154                     n=0;
155                     for (m=0;m<NDEVICES;m++)
156                         if (game.damage[m]>0) 
157                             n++;
158                     probf=pow(1.4,(game.energy+game.shield)/5000.0-1.0)*pow(1.3,1.0/(n+1)-1.0);
159                     if ((game.options & OPTION_BLKHOLE) && Rand()>probf) 
160                         timwrp();
161                     else 
162                         finish(FHOLE);
163                     return;
164                 default:
165                     /* something else */
166                     skip(1);
167                     crmshp();
168                     if (iquad == IHWEB)
169                         proutn(_(" encounters Tholian web at "));
170                     else
171                         proutn(_(" blocked by object at "));
172                     proutn(cramlc(sector, w));
173                     prout(";");
174                     proutn(_("Emergency stop required "));
175                     prout(_("%2d units of energy."), (int)stopegy);
176                     game.energy -= stopegy;
177                     final.x = x-deltax+0.5;
178                     final.y = y-deltay+0.5;
179                     game.sector = final;
180                     if (game.energy <= 0) {
181                         finish(FNRG);
182                         return;
183                     }
184                     break;
185                 }
186                 goto no_quad_change;    /* sorry! */
187             }
188         }
189         game.dist = distance(game.sector, w) / (QUADSIZE * 1.0);
190         game.sector = w;
191     }
192     final = game.sector;
193 no_quad_change:
194     /* No quadrant change -- compute new avg enemy distances */
195     game.quad[game.sector.x][game.sector.y] = game.ship;
196     if (game.nenhere) {
197         for_local_enemies(m) {
198             finald = distance(w, game.ks[m]);
199             game.kavgd[m] = 0.5 * (finald+game.kdist[m]);
200             game.kdist[m] = finald;
201         }
202         sortkl();
203         if (!game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova)
204             attack(false);
205         for_local_enemies(m) game.kavgd[m] = game.kdist[m];
206     }
207     newcnd();
208     drawmaps(0);
209     setwnd(message_window);
210     return;
211 }
212
213 void dock(bool verbose) 
214 /* dock our ship at a starbase */
215 {
216     chew();
217     if (game.condition == docked && verbose) {
218         prout(_("Already docked."));
219         return;
220     }
221     if (game.inorbit) {
222         prout(_("You must first leave standard orbit."));
223         return;
224     }
225     if (!is_valid(game.base) || abs(game.sector.x-game.base.x) > 1 || abs(game.sector.y-game.base.y) > 1) {
226         crmshp();
227         prout(_(" not adjacent to base."));
228         return;
229     }
230     game.condition = docked;
231     if (verbose)
232         prout(_("Docked."));
233     game.ididit = true;
234     if (game.energy < game.inenrg)
235         game.energy = game.inenrg;
236     game.shield = game.inshld;
237     game.torps = game.intorps;
238     game.lsupres = game.inlsr;
239     game.state.crew = FULLCREW;
240     if (!damaged(DRADIO) &&
241         (is_scheduled(FCDBAS) || game.isatb == 1) && !game.iseenit) {
242         /* get attack report from base */
243         prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""));
244         attakreport(false);
245         game.iseenit = true;
246     }
247 }
248
249 /* 
250  * This program originally required input in terms of a (clock)
251  * direction and distance. Somewhere in history, it was changed to
252  * cartesian coordinates. So we need to convert. I think
253  * "manual" input should still be done this way -- it's a real
254  * pain if the computer isn't working! Manual mode is still confusing
255  * because it involves giving x and y motions, yet the coordinates
256  * are always displayed y - x, where +y is downward!
257  */
258
259 static void getcd(bool isprobe, int akey)
260 /* get course and distance */
261 {
262     int irowq=game.quadrant.x, icolq=game.quadrant.y, key=0;
263     double xi, xj, xk, xl;
264     double deltax, deltay;
265     enum {unspecified, manual, automatic} navmode = unspecified;
266     enum {curt, normal, verbose} itemp = curt;
267     coord incr;
268     bool iprompt = false;
269
270     /* Get course direction and distance. If user types bad values, return
271        with DIREC = -1.0. */
272
273     game.direc = -1.0;
274         
275     if (game.landed && !isprobe) {
276         prout(_("Dummy! You can't leave standard orbit until you"));
277         proutn(_("are back aboard the ship."));
278         chew();
279         return;
280     }
281     while (navmode == unspecified) {
282         if (damaged(DNAVSYS)) {
283             if (isprobe)
284                 prout(_("Computer damaged; manual navigation only"));
285             else
286                 prout(_("Computer damaged; manual movement only"));
287             chew();
288             navmode = manual;
289             key = IHEOL;
290             break;
291         }
292         if (isprobe && akey != -1) {
293             /* For probe launch, use pre-scanned value first time */
294             key = akey;
295             akey = -1;
296         }
297         else 
298             key = scan();
299
300         if (key == IHEOL) {
301             proutn(_("Manual or automatic- "));
302             iprompt = true;
303             chew();
304         }
305         else if (key == IHALPHA) {
306             if (isit("manual")) {
307                 navmode = manual;
308                 key = scan();
309                 break;
310             }
311             else if (isit("automatic")) {
312                 navmode = automatic;
313                 key = scan();
314                 break;
315             }
316             else {
317                 huh();
318                 chew();
319                 return;
320             }
321         }
322         else { /* numeric */
323             if (isprobe)
324                 prout(_("(Manual navigation assumed.)"));
325             else
326                 prout(_("(Manual movement assumed.)"));
327             navmode = automatic;
328             break;
329         }
330     }
331
332     if (navmode == automatic) {
333         while (key == IHEOL) {
334             if (isprobe)
335                 proutn(_("Target quadrant or quadrant&sector- "));
336             else
337                 proutn(_("Destination sector or quadrant&sector- "));
338             chew();
339             iprompt = true;
340             key = scan();
341         }
342
343         if (key != IHREAL) {
344             huh();
345             return;
346         }
347         xi = aaitem;
348         key = scan();
349         if (key != IHREAL){
350             huh();
351             return;
352         }
353         xj = aaitem;
354         key = scan();
355         if (key == IHREAL) {
356             /* both quadrant and sector specified */
357             xk = aaitem;
358             key = scan();
359             if (key != IHREAL) {
360                 huh();
361                 return;
362             }
363             xl = aaitem;
364
365             irowq = xi + 0.5;
366             icolq = xj + 0.5;
367             incr.y = xk + 0.5;
368             incr.x = xl + 0.5;
369         }
370         else {
371             if (isprobe) {
372                 /* only quadrant specified -- go to center of dest quad */
373                 irowq = xi + 0.5;
374                 icolq = xj + 0.5;
375                 incr.y = incr.x = 5;
376             }
377             else {
378                 incr.y = xi + 0.5;
379                 incr.x = xj + 0.5;
380             }
381             itemp = normal;
382         }
383         if (!VALID_QUADRANT(icolq,irowq)||!VALID_SECTOR(incr.x,incr.y)) {
384             huh();
385             return;
386         }
387         skip(1);
388         if (!isprobe) {
389             if (itemp > curt) {
390                 if (iprompt) {
391                     prout(_("Helmsman Sulu- \"Course locked in for %s.\""),
392                           cramlc(sector, incr));
393                 }
394             }
395             else
396                 prout(_("Ensign Chekov- \"Course laid in, Captain.\""));
397         }
398         deltax = icolq - game.quadrant.y + 0.1*(incr.x-game.sector.y);
399         deltay = game.quadrant.x - irowq + 0.1*(game.sector.x-incr.y);
400     }
401     else { /* manual */
402         while (key == IHEOL) {
403             proutn(_("X and Y displacements- "));
404             chew();
405             iprompt = true;
406             key = scan();
407         }
408         itemp = verbose;
409         if (key != IHREAL) {
410             huh();
411             return;
412         }
413         deltax = aaitem;
414         key = scan();
415         if (key != IHREAL) {
416             huh();
417             return;
418         }
419         deltay = aaitem;
420     }
421     /* Check for zero movement */
422     if (deltax == 0 && deltay == 0) {
423         chew();
424         return;
425     }
426     if (itemp == verbose && !isprobe) {
427         skip(1);
428         prout(_("Helmsman Sulu- \"Aye, Sir.\""));
429     }
430     game.dist = sqrt(deltax*deltax + deltay*deltay);
431     game.direc = atan2(deltax, deltay)*1.90985932;
432     if (game.direc < 0.0)
433         game.direc += 12.0;
434     chew();
435     return;
436 }
437                 
438
439
440 void impuls(void) 
441 /* move under impulse power */
442 {
443     double power;
444
445     game.ididit = false;
446     if (damaged(DIMPULS)) {
447         chew();
448         skip(1);
449         prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""));
450         return;
451     }
452
453     if (game.energy > 30.0) {
454         getcd(false, 0);
455         if (game.direc == -1.0)
456             return;
457         power = 20.0 + 100.0*game.dist;
458     }
459     else
460         power = 30.0;
461
462     if (power >= game.energy) {
463         /* Insufficient power for trip */
464         skip(1);
465         prout(_("First Officer Spock- \"Captain, the impulse engines"));
466         prout(_("require 20.0 units to engage, plus 100.0 units per"));
467         if (game.energy > 30) {
468             proutn(_("quadrant.  We can go, therefore, a maximum of %d"),
469                    (int)(0.01 * (game.energy-20.0)-0.05));
470             prout(_(" quadrants.\""));
471         }
472         else {
473             prout(_("quadrant.  They are, therefore, useless.\""));
474         }
475         chew();
476         return;
477     }
478     /* Make sure enough time is left for the trip */
479     game.optime = game.dist/0.095;
480     if (game.optime >= game.state.remtime) {
481         prout(_("First Officer Spock- \"Captain, our speed under impulse"));
482         prout(_("power is only 0.95 sectors per stardate. Are you sure"));
483         proutn(_("we dare spend the time?\" "));
484         if (ja() == false)
485             return;
486     }
487     /* Activate impulse engines and pay the cost */
488     imove(false);
489     game.ididit = true;
490     if (game.alldone)
491         return;
492     power = 20.0 + 100.0*game.dist;
493     game.energy -= power;
494     game.optime = game.dist/0.095;
495     if (game.energy <= 0)
496         finish(FNRG);
497     return;
498 }
499
500
501 void warp(bool timewarp)
502 /* move under warp drive */
503 {
504     int iwarp;
505     bool blooey = false, twarp = false;
506     double power;
507
508     if (!timewarp) { /* Not WARPX entry */
509         game.ididit = false;
510         if (game.damage[DWARPEN] > 10.0) {
511             chew();
512             skip(1);
513             prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""));
514             return;
515         }
516         if (damaged(DWARPEN) && game.warpfac > 4.0) {
517             chew();
518             skip(1);
519             prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"));
520             prout(_("  is repaired, I can only give you warp 4.\""));
521             return;
522         }
523                         
524         /* Read in course and distance */
525         getcd(false, 0);
526         if (game.direc == -1.0)
527             return;
528
529         /* Make sure starship has enough energy for the trip */
530         power = (game.dist+0.05)*game.warpfac*game.warpfac*game.warpfac*(game.shldup+1);
531
532
533         if (power >= game.energy) {
534             /* Insufficient power for trip */
535             game.ididit = false;
536             skip(1);
537             prout(_("Engineering to bridge--"));
538             if (!game.shldup || 0.5*power > game.energy) {
539                 iwarp = pow((game.energy/(game.dist+0.05)), 0.333333333);
540                 if (iwarp <= 0) {
541                     prout(_("We can't do it, Captain. We don't have enough energy."));
542                 }
543                 else {
544                     proutn(_("We don't have enough energy, but we could do it at warp %d"), iwarp);
545                     if (game.shldup) {
546                         prout(",");
547                         prout(_("if you'll lower the shields."));
548                     }
549                     else
550                         prout(".");
551                 }
552             }
553             else
554                 prout(_("We haven't the energy to go that far with the shields up."));
555             return;
556         }
557                                                 
558         /* Make sure enough time is left for the trip */
559         game.optime = 10.0*game.dist/game.wfacsq;
560         if (game.optime >= 0.8*game.state.remtime) {
561             skip(1);
562             prout(_("First Officer Spock- \"Captain, I compute that such"));
563             proutn(_("  a trip would require approximately %2.0f"),
564                    100.0*game.optime/game.state.remtime);
565             prout(_(" percent of our"));
566             proutn(_("  remaining time.  Are you sure this is wise?\" "));
567             if (ja() == false) { game.ididit = false; game.optime=0; return;}
568         }
569     }
570     /* Entry WARPX */
571     if (game.warpfac > 6.0) {
572         /* Decide if engine damage will occur */
573         double prob = game.dist*(6.0-game.warpfac)*(6.0-game.warpfac)/66.666666666;
574         if (prob > Rand()) {
575             blooey = true;
576             game.dist = Rand()*game.dist;
577         }
578         /* Decide if time warp will occur */
579         if (0.5*game.dist*pow(7.0,game.warpfac-10.0) > Rand())
580             twarp = true;
581         if (idebug && game.warpfac==10 && !twarp) {
582             blooey = false;
583             proutn("=== Force time warp? ");
584             if (ja() == true)
585                 twarp = true;
586         }
587         if (blooey || twarp) {
588             /* If time warp or engine damage, check path */
589             /* If it is obstructed, don't do warp or damage */
590             double angle = ((15.0-game.direc)*0.5235998);
591             double deltax = -sin(angle);
592             double deltay = cos(angle);
593             double bigger, x, y;
594             int n, l, ix, iy;
595             if (fabs(deltax) > fabs(deltay))
596                 bigger = fabs(deltax);
597             else
598                 bigger = fabs(deltay);
599                         
600             deltax /= bigger;
601             deltay /= bigger;
602             n = 10.0 * game.dist * bigger +0.5;
603             x = game.sector.x;
604             y = game.sector.y;
605             for (l = 1; l <= n; l++) {
606                 x += deltax;
607                 ix = x + 0.5;
608                 y += deltay;
609                 iy = y +0.5;
610                 if (!VALID_SECTOR(ix, iy))
611                     break;
612                 if (game.quad[ix][iy] != IHDOT) {
613                     blooey = false;
614                     twarp = false;
615                 }
616             }
617         }
618     }
619                                 
620
621     /* Activate Warp Engines and pay the cost */
622     imove(false);
623     if (game.alldone)
624         return;
625     game.energy -= game.dist*game.warpfac*game.warpfac*game.warpfac*(game.shldup+1);
626     if (game.energy <= 0)
627         finish(FNRG);
628     game.optime = 10.0*game.dist/game.wfacsq;
629     if (twarp)
630         timwrp();
631     if (blooey) {
632         game.damage[DWARPEN] = game.damfac*(3.0*Rand()+1.0);
633         skip(1);
634         prout(_("Engineering to bridge--"));
635         prout(_("  Scott here.  The warp engines are damaged."));
636         prout(_("  We'll have to reduce speed to warp 4."));
637     }
638     game.ididit = true;
639     return;
640 }
641
642
643
644 void setwrp(void) 
645 /* change the warp factor */
646 {
647     int key;
648     double oldfac;
649         
650     while ((key=scan()) == IHEOL) {
651         chew();
652         proutn(_("Warp factor- "));
653     }
654     chew();
655     if (key != IHREAL) {
656         huh();
657         return;
658     }
659     if (game.damage[DWARPEN] > 10.0) {
660         prout(_("Warp engines inoperative."));
661         return;
662     }
663     if (damaged(DWARPEN) && aaitem > 4.0) {
664         prout(_("Engineer Scott- \"I'm doing my best, Captain,"));
665         prout(_("  but right now we can only go warp 4.\""));
666         return;
667     }
668     if (aaitem > 10.0) {
669         prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""));
670         return;
671     }
672     if (aaitem < 1.0) {
673         prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""));
674         return;
675     }
676     oldfac = game.warpfac;
677     game.warpfac = aaitem;
678     game.wfacsq=game.warpfac*game.warpfac;
679     if (game.warpfac <= oldfac || game.warpfac <= 6.0) {
680         prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\""),
681                (int)game.warpfac);
682         return;
683     }
684     if (game.warpfac < 8.00) {
685         prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""));
686         return;
687     }
688     if (game.warpfac == 10.0) {
689         prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""));
690         return;
691     }
692     prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""));
693     return;
694 }
695
696 void atover(bool igrab) 
697 /* cope with being tossed out of quadrant by supernova or yanked by beam */
698 {
699     double power, distreq;
700
701     chew();
702     /* is captain on planet? */
703     if (game.landed) {
704         if (damaged(DTRANSP)) {
705             finish(FPNOVA);
706             return;
707         }
708         prout(_("Scotty rushes to the transporter controls."));
709         if (game.shldup) {
710             prout(_("But with the shields up it's hopeless."));
711             finish(FPNOVA);
712         }
713         prouts(_("His desperate attempt to rescue you . . ."));
714         if (Rand() <= 0.5) {
715             prout(_("fails."));
716             finish(FPNOVA);
717             return;
718         }
719         prout(_("SUCCEEDS!"));
720         if (game.imine) {
721             game.imine = false;
722             proutn(_("The crystals mined were "));
723             if (Rand() <= 0.25) {
724                 prout(_("lost."));
725             }
726             else {
727                 prout(_("saved."));
728                 game.icrystl = true;
729             }
730         }
731     }
732     if (igrab)
733         return;
734
735     /* Check to see if captain in shuttle craft */
736     if (game.icraft)
737         finish(FSTRACTOR);
738     if (game.alldone)
739         return;
740
741     /* Inform captain of attempt to reach safety */
742     skip(1);
743     do {
744         if (game.justin) {
745             prouts(_("***RED ALERT!  RED ALERT!"));
746             skip(1);
747             proutn(_("The "));
748             crmshp();
749             prout(_(" has stopped in a quadrant containing"));
750             prouts(_("   a supernova."));
751             skip(2);
752         }
753         proutn(_("***Emergency automatic override attempts to hurl "));
754         crmshp();
755         skip(1);
756         prout(_("safely out of quadrant."));
757         if (!damaged(DRADIO))
758             game.state.galaxy[game.quadrant.x][game.quadrant.y].charted = true;
759         /* Try to use warp engines */
760         if (damaged(DWARPEN)) {
761             skip(1);
762             prout(_("Warp engines damaged."));
763             finish(FSNOVAED);
764             return;
765         }
766         game.warpfac = 6.0+2.0*Rand();
767         game.wfacsq = game.warpfac * game.warpfac;
768         prout(_("Warp factor set to %d"), (int)game.warpfac);
769         power = 0.75*game.energy;
770         game.dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1));
771         distreq = 1.4142+Rand();
772         if (distreq < game.dist)
773             game.dist = distreq;
774         game.optime = 10.0*game.dist/game.wfacsq;
775         game.direc = 12.0*Rand();       /* How dumb! */
776         game.justin = false;
777         game.inorbit = false;
778         warp(true);
779         if (!game.justin) {
780             /* This is bad news, we didn't leave quadrant. */
781             if (game.alldone)
782                 return;
783             skip(1);
784             prout(_("Insufficient energy to leave quadrant."));
785             finish(FSNOVAED);
786             return;
787         }
788     } while 
789         /* Repeat if another snova */
790         (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova);
791     if (KLINGREM==0) 
792         finish(FWON); /* Snova killed remaining enemy. */
793 }
794
795 void timwrp() 
796 /* let's do the time warp again */
797 {
798     int l;
799     bool gotit;
800     prout(_("***TIME WARP ENTERED."));
801     if (game.state.snap && Rand() < 0.5) {
802         /* Go back in time */
803         prout(_("You are traveling backwards in time %d stardates."),
804               (int)(game.state.date-game.snapsht.date));
805         game.state = game.snapsht;
806         game.state.snap = false;
807         if (game.state.remcom) {
808             schedule(FTBEAM, expran(game.intime/game.state.remcom));
809             schedule(FBATTAK, expran(0.3*game.intime));
810         }
811         schedule(FSNOVA, expran(0.5*game.intime));
812         /* next snapshot will be sooner */
813         schedule(FSNAP, expran(0.25*game.state.remtime));
814                                 
815         if (game.state.nscrem)
816             schedule(FSCMOVE, 0.2777);      
817         game.isatb = 0;
818         unschedule(FCDBAS);
819         unschedule(FSCDBAS);
820         invalidate(game.battle);
821
822         /* Make sure Galileo is consistant -- Snapshot may have been taken
823            when on planet, which would give us two Galileos! */
824         gotit = false;
825         for (l = 0; l < game.inplan; l++) {
826             if (game.state.plnets[l].known == shuttle_down) {
827                 gotit = true;
828                 if (game.iscraft == onship && game.ship==IHE) {
829                     prout(_("Checkov-  \"Security reports the Galileo has disappeared, Sir!"));
830                     game.iscraft = offship;
831                 }
832             }
833         }
834         /* Likewise, if in the original time the Galileo was abandoned, but
835            was on ship earlier, it would have vanished -- lets restore it */
836         if (game.iscraft == offship && !gotit && game.damage[DSHUTTL] >= 0.0) {
837             prout(_("Checkov-  \"Security reports the Galileo has reappeared in the dock!\""));
838             game.iscraft = onship;
839         }
840         /* 
841          * There used to be code to do the actual reconstrction here,
842          * but the starchart is now part of the snapshotted galaxy state.
843          */
844         prout(_("Spock has reconstructed a correct star chart from memory"));
845     }
846     else {
847         /* Go forward in time */
848         game.optime = -0.5*game.intime*log(Rand());
849         prout(_("You are traveling forward in time %d stardates."), (int)game.optime);
850         /* cheat to make sure no tractor beams occur during time warp */
851         postpone(FTBEAM, game.optime);
852         game.damage[DRADIO] += game.optime;
853     }
854     newqad(false);
855     events();   /* Stas Sergeev added this -- do pending events */
856 }
857
858 void probe(void) 
859 /* launch deep-space probe */
860 {
861     double angle, bigger;
862     int key;
863     /* New code to launch a deep space probe */
864     if (game.nprobes == 0) {
865         chew();
866         skip(1);
867         if (game.ship == IHE) 
868             prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""));
869         else
870             prout(_("Ye Faerie Queene has no deep space probes."));
871         return;
872     }
873     if (damaged(DDSP)) {
874         chew();
875         skip(1);
876         prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""));
877         return;
878     }
879     if (is_scheduled(FDSPROB)) {
880         chew();
881         skip(1);
882         if (damaged(DRADIO) && game.condition != docked) {
883             prout(_("Spock-  \"Records show the previous probe has not yet"));
884             prout(_("   reached its destination.\""));
885         }
886         else
887             prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""));
888         return;
889     }
890     key = scan();
891
892     if (key == IHEOL) {
893         /* slow mode, so let Kirk know how many probes there are left */
894         prout(game.nprobes==1 ? _("%d probe left.") : _("%d probes left."), game.nprobes);
895         proutn(_("Are you sure you want to fire a probe? "));
896         if (ja() == false)
897             return;
898     }
899
900     game.isarmed = false;
901     if (key == IHALPHA && strcmp(citem,"armed") == 0) {
902         game.isarmed = true;
903         key = scan();
904     }
905     else if (key == IHEOL) {
906         proutn(_("Arm NOVAMAX warhead? "));
907         game.isarmed = ja();
908     }
909     getcd(true, key);
910     if (game.direc == -1.0)
911         return;
912     game.nprobes--;
913     angle = ((15.0 - game.direc) * 0.5235988);
914     game.probeinx = -sin(angle);
915     game.probeiny = cos(angle);
916     if (fabs(game.probeinx) > fabs(game.probeiny))
917         bigger = fabs(game.probeinx);
918     else
919         bigger = fabs(game.probeiny);
920                 
921     game.probeiny /= bigger;
922     game.probeinx /= bigger;
923     game.proben = 10.0*game.dist*bigger +0.5;
924     game.probex = game.quadrant.x*QUADSIZE + game.sector.x - 1; // We will use better packing than original
925     game.probey = game.quadrant.y*QUADSIZE + game.sector.y - 1;
926     game.probec = game.quadrant;
927     schedule(FDSPROB, 0.01); // Time to move one sector
928     prout(_("Ensign Chekov-  \"The deep space probe is launched, Captain.\""));
929     game.ididit = true;
930     return;
931 }
932
933 /*
934  *      Here's how the mayday code works:
935  *
936  *      First, the closest starbase is selected.  If there is a
937  *      a starbase in your own quadrant, you are in good shape.
938  *      This distance takes quadrant distances into account only.
939  *
940  *      A magic number is computed based on the distance which acts
941  *      as the probability that you will be rematerialized.  You
942  *      get three tries.
943  *
944  *      When it is determined that you should be able to be remater-
945  *      ialized (i.e., when the probability thing mentioned above
946  *      comes up positive), you are put into that quadrant (anywhere).
947  *      Then, we try to see if there is a spot adjacent to the star-
948  *      base.  If not, you can't be rematerialized!!!  Otherwise,
949  *      it drops you there.  It only tries five times to find a spot
950  *      to drop you.  After that, it's your problem.
951  */
952
953 void mayday(void) 
954 /* yell for help from nearest starbase */
955 {
956     /* There's more than one way to move in this game! */
957     double ddist, xdist, probf;
958     int line = 0, m, ix, iy;
959
960     chew();
961     /* Test for conditions which prevent calling for help */
962     if (game.condition == docked) {
963         prout(_("Lt. Uhura-  \"But Captain, we're already docked.\""));
964         return;
965     }
966     if (damaged(DRADIO)) {
967         prout(_("Subspace radio damaged."));
968         return;
969     }
970     if (game.state.rembase==0) {
971         prout(_("Lt. Uhura-  \"Captain, I'm not getting any response from Starbase.\""));
972         return;
973     }
974     if (game.landed) {
975         proutn(_("You must be aboard the "));
976         crmshp();
977         prout(".");
978         return;
979     }
980     /* OK -- call for help from nearest starbase */
981     game.nhelp++;
982     if (game.base.x!=0) {
983         /* There's one in this quadrant */
984         ddist = distance(game.base, game.sector);
985     }
986     else {
987         ddist = FOREVER;
988         for_starbases(m) {
989             xdist = QUADSIZE * distance(game.state.baseq[m], game.quadrant);
990             if (xdist < ddist) {
991                 ddist = xdist;
992                 line = m;
993             }
994         }
995         /* Since starbase not in quadrant, set up new quadrant */
996         game.quadrant = game.state.baseq[line];
997         newqad(true);
998     }
999     /* dematerialize starship */
1000     game.quad[game.sector.x][game.sector.y]=IHDOT;
1001     proutn(_("Starbase in %s responds--"), cramlc(quadrant, game.quadrant));
1002     crmshp();
1003     prout(_(" dematerializes."));
1004     game.sector.x=0;
1005     for (m = 1; m <= 5; m++) {
1006         ix = game.base.x+3.0*Rand()-1;
1007         iy = game.base.y+3.0*Rand()-1;
1008         if (VALID_SECTOR(ix,iy) && game.quad[ix][iy]==IHDOT) {
1009             /* found one -- finish up */
1010             game.sector.x=ix;
1011             game.sector.y=iy;
1012             break;
1013         }
1014     }
1015     if (!is_valid(game.sector)){
1016         prout(_("You have been lost in space..."));
1017         finish(FMATERIALIZE);
1018         return;
1019     }
1020     /* Give starbase three chances to rematerialize starship */
1021     probf = pow((1.0 - pow(0.98,ddist)), 0.33333333);
1022     for (m = 1; m <= 3; m++) {
1023         switch (m) {
1024         case 1: proutn(_("1st")); break;
1025         case 2: proutn(_("2nd")); break;
1026         case 3: proutn(_("3rd")); break;
1027         }
1028         proutn(_(" attempt to re-materialize "));
1029         crmshp();
1030         switch (m){
1031         case 1: game.quad[ix][iy]=IHMATER0;
1032             break;
1033         case 2: game.quad[ix][iy]=IHMATER1;
1034             break;
1035         case 3: game.quad[ix][iy]=IHMATER2;
1036             break;
1037         }
1038         textcolor(RED);
1039         warble();
1040         if (Rand() > probf)
1041             break;
1042         prout(_("fails."));
1043         delay(500);
1044         textcolor(DEFAULT);
1045     }
1046     if (m > 3) {
1047         game.quad[ix][iy]=IHQUEST;
1048         game.alive = false;
1049         drawmaps(1);
1050         setwnd(message_window);
1051         finish(FMATERIALIZE);
1052         return;
1053     }
1054     game.quad[ix][iy]=game.ship;
1055     textcolor(GREEN);
1056     prout(_("succeeds."));
1057     textcolor(DEFAULT);
1058     dock(false);
1059     skip(1);
1060     prout(_("Lt. Uhura-  \"Captain, we made it!\""));
1061 }
1062
1063 /*
1064 **  Abandon Ship
1065 **
1066 **      The ship is abandoned.  If your current ship is the Faire
1067 **      Queene, or if your shuttlecraft is dead, you're out of
1068 **      luck.  You need the shuttlecraft in order for the captain
1069 **      (that's you!!) to escape.
1070 **
1071 **      Your crew can beam to an inhabited starsystem in the
1072 **      quadrant, if there is one and if the transporter is working.
1073 **      If there is no inhabited starsystem, or if the transporter
1074 **      is out, they are left to die in outer space.
1075 **
1076 **      If there are no starbases left, you are captured by the
1077 **      Klingons, who torture you mercilessly.  However, if there
1078 **      is at least one starbase, you are returned to the
1079 **      Federation in a prisoner of war exchange.  Of course, this
1080 **      can't happen unless you have taken some prisoners.
1081 **
1082 */
1083
1084 void abandn(void) 
1085 /* abandon ship */
1086 {
1087     int nb, l;
1088     struct quadrant *q;
1089
1090     chew();
1091     if (game.condition==docked) {
1092         if (game.ship!=IHE) {
1093             prout(_("You cannot abandon Ye Faerie Queene."));
1094             return;
1095         }
1096     }
1097     else {
1098         /* Must take shuttle craft to exit */
1099         if (game.damage[DSHUTTL]==-1) {
1100             prout(_("Ye Faerie Queene has no shuttle craft."));
1101             return;
1102         }
1103         if (game.damage[DSHUTTL]<0) {
1104             prout(_("Shuttle craft now serving Big Macs."));
1105             return;
1106         }
1107         if (game.damage[DSHUTTL]>0) {
1108             prout(_("Shuttle craft damaged."));
1109             return;
1110         }
1111         if (game.landed) {
1112             prout(_("You must be aboard the ship."));
1113             return;
1114         }
1115         if (game.iscraft != onship) {
1116             prout(_("Shuttle craft not currently available."));
1117             return;
1118         }
1119         /* Print abandon ship messages */
1120         skip(1);
1121         prouts(_("***ABANDON SHIP!  ABANDON SHIP!"));
1122         skip(1);
1123         prouts(_("***ALL HANDS ABANDON SHIP!"));
1124         skip(2);
1125         prout(_("Captain and crew escape in shuttle craft."));
1126         if (game.state.rembase==0) {
1127             /* Oops! no place to go... */
1128             finish(FABANDN);
1129             return;
1130         }
1131         q = &game.state.galaxy[game.quadrant.x][game.quadrant.y];
1132         /* Dispose of crew */
1133         if (!(game.options & OPTION_WORLDS) && !damaged(DTRANSP)) {
1134             prout(_("Remainder of ship's complement beam down"));
1135             prout(_("to nearest habitable planet."));
1136         } else if (q->planet != NOPLANET && !damaged(DTRANSP)) {
1137             prout(_("Remainder of ship's complement beam down"));
1138             prout(_("to %s."), systnames[q->planet]);
1139         } else {
1140             prout(_("Entire crew of %d left to die in outer space."),
1141                     game.state.crew);
1142             game.casual += game.state.crew;
1143             game.abandoned += game.state.crew;
1144         }
1145
1146         /* If at least one base left, give 'em the Faerie Queene */
1147         skip(1);
1148         game.icrystl = false; /* crystals are lost */
1149         game.nprobes = 0; /* No probes */
1150         prout(_("You are captured by Klingons and released to"));
1151         prout(_("the Federation in a prisoner-of-war exchange."));
1152         nb = Rand()*game.state.rembase+1;
1153         /* Set up quadrant and position FQ adjacient to base */
1154         if (!same(game.quadrant, game.state.baseq[nb])) {
1155             game.quadrant = game.state.baseq[nb];
1156             game.sector.x = game.sector.y = 5;
1157             newqad(true);
1158         }
1159         for (;;) {
1160             /* position next to base by trial and error */
1161             game.quad[game.sector.x][game.sector.y] = IHDOT;
1162             for_sectors(l) {
1163                 game.sector.x = 3.0*Rand() - 1.0 + game.base.x;
1164                 game.sector.y = 3.0*Rand() - 1.0 + game.base.y;
1165                 if (VALID_SECTOR(game.sector.x, game.sector.y) &&
1166                     game.quad[game.sector.x][game.sector.y] == IHDOT) break;
1167             }
1168             if (l < QUADSIZE+1) break; /* found a spot */
1169             game.sector.x=QUADSIZE/2;
1170             game.sector.y=QUADSIZE/2;
1171             newqad(true);
1172         }
1173     }
1174     /* Get new commission */
1175     game.quad[game.sector.x][game.sector.y] = game.ship = IHF;
1176     game.state.crew = FULLCREW;
1177     prout(_("Starfleet puts you in command of another ship,"));
1178     prout(_("the Faerie Queene, which is antiquated but,"));
1179     prout(_("still useable."));
1180     if (game.icrystl)
1181         prout(_("The dilithium crystals have been moved."));
1182     game.imine = false;
1183     game.iscraft = offship; /* Galileo disappears */
1184     /* Resupply ship */
1185     game.condition=docked;
1186     for (l = 0; l < NDEVICES; l++) 
1187         game.damage[l] = 0.0;
1188     game.damage[DSHUTTL] = -1;
1189     game.energy = game.inenrg = 3000.0;
1190     game.shield = game.inshld = 1250.0;
1191     game.torps = game.intorps = 6;
1192     game.lsupres=game.inlsr=3.0;
1193     game.shldup=false;
1194     game.warpfac=5.0;
1195     game.wfacsq=25.0;
1196     return;
1197 }