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