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