Get rid of some macros that block mechanical translation.
[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 = automatic;
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 impulse 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         if (!damaged(DRADIO))
763             game.state.galaxy[game.quadrant.x][game.quadrant.y].charted = true;
764         /* Try to use warp engines */
765         if (damaged(DWARPEN)) {
766             skip(1);
767             prout(_("Warp engines damaged."));
768             finish(FSNOVAED);
769             return;
770         }
771         game.warpfac = 6.0+2.0*Rand();
772         game.wfacsq = game.warpfac * game.warpfac;
773         prout(_("Warp factor set to %d"), (int)game.warpfac);
774         power = 0.75*game.energy;
775         game.dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1));
776         distreq = 1.4142+Rand();
777         if (distreq < game.dist)
778             game.dist = distreq;
779         game.optime = 10.0*game.dist/game.wfacsq;
780         game.direc = 12.0*Rand();       /* How dumb! */
781         game.justin = false;
782         game.inorbit = false;
783         warp(true);
784         if (!game.justin) {
785             /* This is bad news, we didn't leave quadrant. */
786             if (game.alldone)
787                 return;
788             skip(1);
789             prout(_("Insufficient energy to leave quadrant."));
790             finish(FSNOVAED);
791             return;
792         }
793     } while 
794         /* Repeat if another snova */
795         (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova);
796     if ((game.state.remkl + game.state.remcom + game.state.nscrem)==0) 
797         finish(FWON); /* Snova killed remaining enemy. */
798 }
799
800 void timwrp() 
801 /* let's do the time warp again */
802 {
803     int l;
804     bool gotit;
805     prout(_("***TIME WARP ENTERED."));
806     if (game.state.snap && Rand() < 0.5) {
807         /* Go back in time */
808         prout(_("You are traveling backwards in time %d stardates."),
809               (int)(game.state.date-game.snapsht.date));
810         game.state = game.snapsht;
811         game.state.snap = false;
812         if (game.state.remcom) {
813             schedule(FTBEAM, expran(game.intime/game.state.remcom));
814             schedule(FBATTAK, expran(0.3*game.intime));
815         }
816         schedule(FSNOVA, expran(0.5*game.intime));
817         /* next snapshot will be sooner */
818         schedule(FSNAP, expran(0.25*game.state.remtime));
819                                 
820         if (game.state.nscrem)
821             schedule(FSCMOVE, 0.2777);      
822         game.isatb = 0;
823         unschedule(FCDBAS);
824         unschedule(FSCDBAS);
825         invalidate(game.battle);
826
827         /* Make sure Galileo is consistant -- Snapshot may have been taken
828            when on planet, which would give us two Galileos! */
829         gotit = false;
830         for (l = 0; l < game.inplan; l++) {
831             if (game.state.planets[l].known == shuttle_down) {
832                 gotit = true;
833                 if (game.iscraft == onship && game.ship==IHE) {
834                     prout(_("Checkov-  \"Security reports the Galileo has disappeared, Sir!"));
835                     game.iscraft = offship;
836                 }
837             }
838         }
839         // Likewise, if in the original time the Galileo was abandoned, but
840         // was on ship earlier, it would have vanished -- let's restore it.
841         if (game.iscraft == offship && !gotit && game.damage[DSHUTTL] >= 0.0) {
842             prout(_("Checkov-  \"Security reports the Galileo has reappeared in the dock!\""));
843             game.iscraft = onship;
844         }
845         /* 
846          * There used to be code to do the actual reconstrction here,
847          * but the starchart is now part of the snapshotted galaxy state.
848          */
849         prout(_("Spock has reconstructed a correct star chart from memory"));
850     }
851     else {
852         /* Go forward in time */
853         game.optime = -0.5*game.intime*log(Rand());
854         prout(_("You are traveling forward in time %d stardates."), (int)game.optime);
855         /* cheat to make sure no tractor beams occur during time warp */
856         postpone(FTBEAM, game.optime);
857         game.damage[DRADIO] += game.optime;
858     }
859     newqad(false);
860     events();   /* Stas Sergeev added this -- do pending events */
861 }
862
863 void probe(void) 
864 /* launch deep-space probe */
865 {
866     double angle, bigger;
867     int key;
868     /* New code to launch a deep space probe */
869     if (game.nprobes == 0) {
870         chew();
871         skip(1);
872         if (game.ship == IHE) 
873             prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""));
874         else
875             prout(_("Ye Faerie Queene has no deep space probes."));
876         return;
877     }
878     if (damaged(DDSP)) {
879         chew();
880         skip(1);
881         prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""));
882         return;
883     }
884     if (is_scheduled(FDSPROB)) {
885         chew();
886         skip(1);
887         if (damaged(DRADIO) && game.condition != docked) {
888             prout(_("Spock-  \"Records show the previous probe has not yet"));
889             prout(_("   reached its destination.\""));
890         }
891         else
892             prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""));
893         return;
894     }
895     key = scan();
896
897     if (key == IHEOL) {
898         /* slow mode, so let Kirk know how many probes there are left */
899         prout(game.nprobes==1 ? _("%d probe left.") : _("%d probes left."), game.nprobes);
900         proutn(_("Are you sure you want to fire a probe? "));
901         if (ja() == false)
902             return;
903     }
904
905     game.isarmed = false;
906     if (key == IHALPHA && strcmp(citem,"armed") == 0) {
907         game.isarmed = true;
908         key = scan();
909     }
910     else if (key == IHEOL) {
911         proutn(_("Arm NOVAMAX warhead? "));
912         game.isarmed = ja();
913     }
914     getcd(true, key);
915     if (game.direc == -1.0)
916         return;
917     game.nprobes--;
918     angle = ((15.0 - game.direc) * 0.5235988);
919     game.probeinx = -sin(angle);
920     game.probeiny = cos(angle);
921     if (fabs(game.probeinx) > fabs(game.probeiny))
922         bigger = fabs(game.probeinx);
923     else
924         bigger = fabs(game.probeiny);
925                 
926     game.probeiny /= bigger;
927     game.probeinx /= bigger;
928     game.proben = 10.0*game.dist*bigger +0.5;
929     game.probex = game.quadrant.x*QUADSIZE + game.sector.x - 1; // We will use better packing than original
930     game.probey = game.quadrant.y*QUADSIZE + game.sector.y - 1;
931     game.probec = game.quadrant;
932     schedule(FDSPROB, 0.01); // Time to move one sector
933     prout(_("Ensign Chekov-  \"The deep space probe is launched, Captain.\""));
934     game.ididit = true;
935     return;
936 }
937
938 /*
939  *      Here's how the mayday code works:
940  *
941  *      First, the closest starbase is selected.  If there is a
942  *      a starbase in your own quadrant, you are in good shape.
943  *      This distance takes quadrant distances into account only.
944  *
945  *      A magic number is computed based on the distance which acts
946  *      as the probability that you will be rematerialized.  You
947  *      get three tries.
948  *
949  *      When it is determined that you should be able to be remater-
950  *      ialized (i.e., when the probability thing mentioned above
951  *      comes up positive), you are put into that quadrant (anywhere).
952  *      Then, we try to see if there is a spot adjacent to the star-
953  *      base.  If not, you can't be rematerialized!!!  Otherwise,
954  *      it drops you there.  It only tries five times to find a spot
955  *      to drop you.  After that, it's your problem.
956  */
957
958 void mayday(void) 
959 /* yell for help from nearest starbase */
960 {
961     /* There's more than one way to move in this game! */
962     double ddist, xdist, probf;
963     int line = 0, m, ix, iy;
964
965     chew();
966     /* Test for conditions which prevent calling for help */
967     if (game.condition == docked) {
968         prout(_("Lt. Uhura-  \"But Captain, we're already docked.\""));
969         return;
970     }
971     if (damaged(DRADIO)) {
972         prout(_("Subspace radio damaged."));
973         return;
974     }
975     if (game.state.rembase==0) {
976         prout(_("Lt. Uhura-  \"Captain, I'm not getting any response from Starbase.\""));
977         return;
978     }
979     if (game.landed) {
980         proutn(_("You must be aboard the "));
981         crmshp();
982         prout(".");
983         return;
984     }
985     /* OK -- call for help from nearest starbase */
986     game.nhelp++;
987     if (game.base.x!=0) {
988         /* There's one in this quadrant */
989         ddist = distance(game.base, game.sector);
990     }
991     else {
992         ddist = FOREVER;
993         for (m = 1; m <= game.state.rembase; m++) {
994             xdist = QUADSIZE * distance(game.state.baseq[m], game.quadrant);
995             if (xdist < ddist) {
996                 ddist = xdist;
997                 line = m;
998             }
999         }
1000         /* Since starbase not in quadrant, set up new quadrant */
1001         game.quadrant = game.state.baseq[line];
1002         newqad(true);
1003     }
1004     /* dematerialize starship */
1005     game.quad[game.sector.x][game.sector.y]=IHDOT;
1006     proutn(_("Starbase in %s responds--"), cramlc(quadrant, game.quadrant));
1007     crmshp();
1008     prout(_(" dematerializes."));
1009     game.sector.x=0;
1010     for (m = 1; m <= 5; m++) {
1011         ix = game.base.x+3.0*Rand()-1;
1012         iy = game.base.y+3.0*Rand()-1;
1013         if (VALID_SECTOR(ix,iy) && game.quad[ix][iy]==IHDOT) {
1014             /* found one -- finish up */
1015             game.sector.x=ix;
1016             game.sector.y=iy;
1017             break;
1018         }
1019     }
1020     if (!is_valid(game.sector)){
1021         prout(_("You have been lost in space..."));
1022         finish(FMATERIALIZE);
1023         return;
1024     }
1025     /* Give starbase three chances to rematerialize starship */
1026     probf = pow((1.0 - pow(0.98,ddist)), 0.33333333);
1027     for (m = 1; m <= 3; m++) {
1028         switch (m) {
1029         case 1: proutn(_("1st")); break;
1030         case 2: proutn(_("2nd")); break;
1031         case 3: proutn(_("3rd")); break;
1032         }
1033         proutn(_(" attempt to re-materialize "));
1034         crmshp();
1035         switch (m){
1036         case 1: game.quad[ix][iy]=IHMATER0;
1037             break;
1038         case 2: game.quad[ix][iy]=IHMATER1;
1039             break;
1040         case 3: game.quad[ix][iy]=IHMATER2;
1041             break;
1042         }
1043         textcolor(RED);
1044         warble();
1045         if (Rand() > probf)
1046             break;
1047         prout(_("fails."));
1048         delay(500);
1049         textcolor(DEFAULT);
1050     }
1051     if (m > 3) {
1052         game.quad[ix][iy]=IHQUEST;
1053         game.alive = false;
1054         drawmaps(1);
1055         setwnd(message_window);
1056         finish(FMATERIALIZE);
1057         return;
1058     }
1059     game.quad[ix][iy]=game.ship;
1060     textcolor(GREEN);
1061     prout(_("succeeds."));
1062     textcolor(DEFAULT);
1063     dock(false);
1064     skip(1);
1065     prout(_("Lt. Uhura-  \"Captain, we made it!\""));
1066 }
1067
1068 /*
1069  *  Abandon Ship
1070  *
1071  *      The ship is abandoned.  If your current ship is the Faire
1072  *      Queene, or if your shuttlecraft is dead, you're out of
1073  *      luck.  You need the shuttlecraft in order for the captain
1074  *      (that's you!!) to escape.
1075  *
1076  *      Your crew can beam to an inhabited starsystem in the
1077  *      quadrant, if there is one and if the transporter is working.
1078  *      If there is no inhabited starsystem, or if the transporter
1079  *      is out, they are left to die in outer space.
1080  *
1081  *      If there are no starbases left, you are captured by the
1082  *      Klingons, who torture you mercilessly.  However, if there
1083  *      is at least one starbase, you are returned to the
1084  *      Federation in a prisoner of war exchange.  Of course, this
1085  *      can't happen unless you have taken some prisoners.
1086  *
1087  */
1088
1089 void abandon(void) 
1090 /* abandon ship */
1091 {
1092     int nb, l;
1093     struct quadrant *q;
1094
1095     chew();
1096     if (game.condition==docked) {
1097         if (game.ship!=IHE) {
1098             prout(_("You cannot abandon Ye Faerie Queene."));
1099             return;
1100         }
1101     }
1102     else {
1103         /* Must take shuttle craft to exit */
1104         if (game.damage[DSHUTTL]==-1) {
1105             prout(_("Ye Faerie Queene has no shuttle craft."));
1106             return;
1107         }
1108         if (game.damage[DSHUTTL]<0) {
1109             prout(_("Shuttle craft now serving Big Macs."));
1110             return;
1111         }
1112         if (game.damage[DSHUTTL]>0) {
1113             prout(_("Shuttle craft damaged."));
1114             return;
1115         }
1116         if (game.landed) {
1117             prout(_("You must be aboard the ship."));
1118             return;
1119         }
1120         if (game.iscraft != onship) {
1121             prout(_("Shuttle craft not currently available."));
1122             return;
1123         }
1124         /* Print abandon ship messages */
1125         skip(1);
1126         prouts(_("***ABANDON SHIP!  ABANDON SHIP!"));
1127         skip(1);
1128         prouts(_("***ALL HANDS ABANDON SHIP!"));
1129         skip(2);
1130         prout(_("Captain and crew escape in shuttle craft."));
1131         if (game.state.rembase==0) {
1132             /* Oops! no place to go... */
1133             finish(FABANDN);
1134             return;
1135         }
1136         q = &game.state.galaxy[game.quadrant.x][game.quadrant.y];
1137         /* Dispose of crew */
1138         if (!(game.options & OPTION_WORLDS) && !damaged(DTRANSP)) {
1139             prout(_("Remainder of ship's complement beam down"));
1140             prout(_("to nearest habitable planet."));
1141         } else if (q->planet != NOPLANET && !damaged(DTRANSP)) {
1142             prout(_("Remainder of ship's complement beam down"));
1143             prout(_("to %s."), systnames[q->planet]);
1144         } else {
1145             prout(_("Entire crew of %d left to die in outer space."),
1146                     game.state.crew);
1147             game.casual += game.state.crew;
1148             game.abandoned += game.state.crew;
1149         }
1150
1151         /* If at least one base left, give 'em the Faerie Queene */
1152         skip(1);
1153         game.icrystl = false; /* crystals are lost */
1154         game.nprobes = 0; /* No probes */
1155         prout(_("You are captured by Klingons and released to"));
1156         prout(_("the Federation in a prisoner-of-war exchange."));
1157         nb = Rand()*game.state.rembase+1;
1158         /* Set up quadrant and position FQ adjacient to base */
1159         if (!same(game.quadrant, game.state.baseq[nb])) {
1160             game.quadrant = game.state.baseq[nb];
1161             game.sector.x = game.sector.y = 5;
1162             newqad(true);
1163         }
1164         for (;;) {
1165             /* position next to base by trial and error */
1166             game.quad[game.sector.x][game.sector.y] = IHDOT;
1167             for (l = 1; l <= QUADSIZE; l++) {
1168                 game.sector.x = 3.0*Rand() - 1.0 + game.base.x;
1169                 game.sector.y = 3.0*Rand() - 1.0 + game.base.y;
1170                 if (VALID_SECTOR(game.sector.x, game.sector.y) &&
1171                     game.quad[game.sector.x][game.sector.y] == IHDOT) break;
1172             }
1173             if (l < QUADSIZE+1)
1174                 break; /* found a spot */
1175             game.sector.x=QUADSIZE/2;
1176             game.sector.y=QUADSIZE/2;
1177             newqad(true);
1178         }
1179     }
1180     /* Get new commission */
1181     game.quad[game.sector.x][game.sector.y] = game.ship = IHF;
1182     game.state.crew = FULLCREW;
1183     prout(_("Starfleet puts you in command of another ship,"));
1184     prout(_("the Faerie Queene, which is antiquated but,"));
1185     prout(_("still useable."));
1186     if (game.icrystl)
1187         prout(_("The dilithium crystals have been moved."));
1188     game.imine = false;
1189     game.iscraft = offship; /* Galileo disappears */
1190     /* Resupply ship */
1191     game.condition=docked;
1192     for (l = 0; l < NDEVICES; l++) 
1193         game.damage[l] = 0.0;
1194     game.damage[DSHUTTL] = -1;
1195     game.energy = game.inenrg = 3000.0;
1196     game.shield = game.inshld = 1250.0;
1197     game.torps = game.intorps = 6;
1198     game.lsupres=game.inlsr=3.0;
1199     game.shldup=false;
1200     game.warpfac=5.0;
1201     game.wfacsq=25.0;
1202     return;
1203 }