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