Partial merge of I/O management.
[super-star-trek.git] / moving.c
1 #include "conio.h"
2 #include "sstlinux.h"
3 #include <unistd.h>
4 #include "sst.h"
5
6 static void getcd(int, int);
7
8 void imove(void) {
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 = 0;
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 (ix < 1 || ix > 10 || iy < 1 || iy > 10) {
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 > 3.
60                                          */
61                                         if (skill > 3 && klhere > 0 && game.state.galaxy[quadx][quady] != 1000)
62                                             attack(0);
63                                         if (alldone) return;
64                                 }
65                                 /* compute final position -- new quadrant and sector */
66                                 x = 10*(quadx-1)+sectx;
67                                 y = 10*(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 > 80) {
83                                                 ix = 161 - ix;
84                                                 kink = 1;
85                                         }
86                                         if (iy > 80) {
87                                                 iy = 161 - 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+9)/10;
107                                 quady = (iy+9)/10;
108                                 sectx = ix - 10*(quadx-1);
109                                 secty = iy - 10*(quady-1);
110                                 proutn("\n\rEntering %s.",
111                                       cramlc(quadrant, quadx, quady));
112                                 game.quad[sectx][secty] = ship;
113                                 newqad(0);
114                                 if (skill>1) 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 
146                                                  * hole was certain death in
147                                                  * Almy's original.  Stas 
148                                                  * Sergeev added a possibility
149                                                  * that you'll get timewarped
150                                                  * instead.
151                                                  */
152                                                 n=0;
153                                                 for (l=1;l<=NDEVICES+1;l++)
154                                                     if (game.damage[l]>0) n++;
155                                                 probf=pow(1.4,(energy+shield)/5000.0-1.0)*
156                                                        pow(1.3,1.0/(n+1)-1.0);
157                                                 if (Rand()>probf) 
158                                                     timwrp();
159                                                 else 
160                                                     finish(FHOLE);
161                                                 return;
162                                         default:
163                                                 /* something else */
164                                                 skip(1);
165                                                 crmshp();
166                                                 if (iquad == IHWEB)
167                                                         proutn(" encounters Tholian web at ");
168                                                 else
169                                                         proutn(" blocked by object at ");
170                                                 proutn(cramlc(sector, ix,iy));
171                                                 prout(";");
172                                                 proutn("Emergency stop required ");
173                                                 prout("%2d units of energy.", (int)stopegy);
174                                                 energy -= stopegy;
175                                                 finalx = x-deltax+0.5;
176                                                 sectx = finalx;
177                                                 finaly = y-deltay+0.5;
178                                                 secty = finaly;
179                                                 if (energy <= 0) {
180                                                         finish(FNRG);
181                                                         return;
182                                                 }
183                                                 break;
184                                 }
185                                 goto label100;  /* sorry! */
186                         }
187                 }
188                 dist = 0.1*sqrt((sectx-ix)*(double)(sectx-ix) +
189                                                 (secty-iy)*(double)(secty-iy));
190                 sectx = ix;
191                 secty = iy;
192         }
193         finalx = sectx;
194         finaly = secty;
195 label100:
196         /* No quadrant change -- compute new avg enemy distances */
197         game.quad[sectx][secty] = ship;
198         if (nenhere) {
199                 for (l = 1; l <= nenhere; l++) {
200                         finald = sqrt((ix-game.kx[l])*(double)(ix-game.kx[l]) +
201                                                   (iy-game.ky[l])*(double)(iy-game.ky[l]));
202                         game.kavgd[l] = 0.5 * (finald+game.kdist[l]);
203                         game.kdist[l] = finald;
204                 }
205                 sortkl();
206                 if (game.state.galaxy[quadx][quady] != 1000 && iattak == 0)
207                         attack(0);
208                 for (l = 1 ; l <= nenhere; l++) game.kavgd[l] = game.kdist[l];
209         }
210         newcnd();
211         iattak = 0;
212         drawmaps(0);
213         return;
214 }
215
216 void dock(int l) {
217         chew();
218         if (condit == IHDOCKED && l) {
219                 prout("Already docked.");
220                 return;
221         }
222         if (inorbit) {
223                 prout("You must first leave standard orbit.");
224                 return;
225         }
226         if (basex==0 || abs(sectx-basex) > 1 || abs(secty-basey) > 1) {
227                 crmshp();
228                 prout(" not adjacent to base.");
229                 return;
230         }
231         condit = IHDOCKED;
232         if (l) prout("Docked.");
233         ididit=1;
234         if (energy < inenrg) energy = inenrg;
235         shield = inshld;
236         torps = intorps;
237         lsupres = inlsr;
238         if (stdamtim != 1e30 &&
239                 (game.future[FCDBAS] < 1e30 || isatb == 1) && iseenit == 0) {
240                 /* get attack report from base */
241                 prout("Lt. Uhura- \"Captain, an important message from the starbase:\"");
242                 attakreport(0);
243                 iseenit = 1;
244         }
245 }
246
247 static void getcd(int isprobe, int akey) {
248         /* This program originally required input in terms of a (clock)
249            direction and distance. Somewhere in history, it was changed to
250            cartesian coordinates. So we need to convert. I think
251            "manual" input should still be done this way -- it's a real
252            pain if the computer isn't working! Manual mode is still confusing
253            because it involves giving x and y motions, yet the coordinates
254            are always displayed y - x, where +y is downward! */
255
256         
257         int irowq=quadx, icolq=quady, irows, icols, itemp=0, iprompt=0, key=0;
258         double xi, xj, xk, xl;
259         double deltax, deltay;
260         int automatic = -1;
261
262         /* Get course direction and distance. If user types bad values, return
263            with DIREC = -1.0. */
264
265         direc = -1.0;
266         
267         if (landed == 1 && !isprobe) {
268                 prout("Dummy! You can't leave standard orbit until you");
269                 proutn("are back abourt the ");
270                 crmshp();
271                 prout(".");
272                 chew();
273                 return;
274         }
275         while (automatic == -1) {
276                 if (game.damage[DCOMPTR]) {
277                         if (isprobe)
278                                 prout("Computer damaged; manual navigation only");
279                         else
280                                 prout("Computer damaged; manual movement only");
281                         chew();
282                         automatic = 0;
283                         key = IHEOL;
284                         break;
285                 }
286                 if (isprobe && akey != -1) {
287                         /* For probe launch, use pre-scaned value first time */
288                         key = akey;
289                         akey = -1;
290                 }
291                 else 
292                         key = scan();
293
294                 if (key == IHEOL) {
295                         proutn("Manual or automatic- ");
296                         iprompt = 1;
297                         chew();
298                 }
299                 else if (key == IHALPHA) {
300                         if (isit("manual")) {
301                                 automatic =0;
302                                 key = scan();
303                                 break;
304                         }
305                         else if (isit("automatic")) {
306                                 automatic = 1;
307                                 key = scan();
308                                 break;
309                         }
310                         else {
311                                 huh();
312                                 chew();
313                                 return;
314                         }
315                 }
316                 else { /* numeric */
317                         if (isprobe)
318                                 prout("(Manual navigation assumed.)");
319                         else
320                                 prout("(Manual movement assumed.)");
321                         automatic = 0;
322                         break;
323                 }
324         }
325
326         if (automatic) {
327                 while (key == IHEOL) {
328                         if (isprobe)
329                                 proutn("Target quadrant or quadrant&sector- ");
330                         else
331                                 proutn("Destination sector or quadrant&sector- ");
332                         chew();
333                         iprompt = 1;
334                         key = scan();
335                 }
336
337                 if (key != IHREAL) {
338                         huh();
339                         return;
340                 }
341                 xi = aaitem;
342                 key = scan();
343                 if (key != IHREAL){
344                         huh();
345                         return;
346                 }
347                 xj = aaitem;
348                 key = scan();
349                 if (key == IHREAL) {
350                         /* both quadrant and sector specified */
351                         xk = aaitem;
352                         key = scan();
353                         if (key != IHREAL) {
354                                 huh();
355                                 return;
356                         }
357                         xl = aaitem;
358
359                         irowq = xi + 0.5;
360                         icolq = xj + 0.5;
361                         irows = xk + 0.5;
362                         icols = xl + 0.5;
363                 }
364                 else {
365                         if (isprobe) {
366                                 /* only quadrant specified -- go to center of dest quad */
367                                 irowq = xi + 0.5;
368                                 icolq = xj + 0.5;
369                                 irows = icols = 5;
370                         }
371                         else {
372                                 irows = xi + 0.5;
373                                 icols = xj + 0.5;
374                         }
375                         itemp = 1;
376                 }
377                 if (irowq<1 || irowq > 8 || icolq<1 || icolq > 8 ||
378                         irows<1 || irows > 10 || icols<1 || icols > 10) {
379                                 huh();
380                                 return;
381                         }
382                 skip(1);
383                 if (!isprobe) {
384                         if (itemp) {
385                                 if (iprompt) {
386                                         prout("Helmsman Sulu- \"Course locked in for %s.\"",
387                                                 cramlc(sector, irows, icols));
388                                 }
389                         }
390                         else prout("Ensign Chekov- \"Course laid in, Captain.\"");
391                 }
392                 deltax = icolq - quady + 0.1*(icols-secty);
393                 deltay = quadx - irowq + 0.1*(sectx-irows);
394         }
395         else { /* manual */
396                 while (key == IHEOL) {
397                         proutn("X and Y displacements- ");
398                         chew();
399                         iprompt = 1;
400                         key = scan();
401                 }
402                 itemp = 2;
403                 if (key != IHREAL) {
404                         huh();
405                         return;
406                 }
407                 deltax = aaitem;
408                 key = scan();
409                 if (key != IHREAL) {
410                         huh();
411                         return;
412                 }
413                 deltay = aaitem;
414         }
415         /* Check for zero movement */
416         if (deltax == 0 && deltay == 0) {
417                 chew();
418                 return;
419         }
420         if (itemp == 2 && !isprobe) {
421                 skip(1);
422                 prout("Helmsman Sulu- \"Aye, Sir.\"");
423         }
424         dist = sqrt(deltax*deltax + deltay*deltay);
425         direc = atan2(deltax, deltay)*1.90985932;
426         if (direc < 0.0) direc += 12.0;
427         chew();
428         return;
429
430 }
431                 
432
433
434 void impuls(void) {
435         double power;
436
437         ididit = 0;
438         if (game.damage[DIMPULS]) {
439                 chew();
440                 skip(1);
441                 prout("Engineer Scott- \"The impulse engines are damaged, Sir.\"");
442                 return;
443         }
444
445         if (energy > 30.0) {
446                 getcd(FALSE, 0);
447                 if (direc == -1.0) return;
448                 power = 20.0 + 100.0*dist;
449         }
450         else
451                 power = 30.0;
452
453         if (power >= energy) {
454                 /* Insufficient power for trip */
455                 skip(1);
456                 prout("First Officer Spock- \"Captain, the impulse engines");
457                 prout("require 20.0 units to engage, plus 100.0 units per");
458                 if (energy > 30) {
459                         proutn("quadrant.  We can go, therefore, a maximum of %d", 
460                                (int)(0.01 * (energy-20.0)-0.05));
461                         prout(" quadrants.\"");
462                 }
463                 else {
464                         prout("quadrant.  They are, therefore, useless.\"");
465                 }
466                 chew();
467                 return;
468         }
469         /* Make sure enough time is left for the trip */
470         Time = dist/0.095;
471         if (Time >= game.state.remtime) {
472                 prout("First Officer Spock- \"Captain, our speed under impulse");
473                 prout("power is only 0.95 sectors per stardate. Are you sure");
474                 proutn("we dare spend the time?\" ");
475                 if (ja() == 0) return;
476         }
477         /* Activate impulse engines and pay the cost */
478         imove();
479         ididit = 1;
480         if (alldone) return;
481         power = 20.0 + 100.0*dist;
482         energy -= power;
483         Time = dist/0.095;
484         if (energy <= 0) finish(FNRG);
485         return;
486 }
487
488
489 void warp(int i) {
490         int blooey=0, twarp=0, iwarp;
491         double power;
492
493         if (i!=2) { /* Not WARPX entry */
494                 ididit = 0;
495                 if (game.damage[DWARPEN] > 10.0) {
496                         chew();
497                         skip(1);
498                         prout("Engineer Scott- \"The impulse engines are damaged, Sir.\"");
499                         return;
500                 }
501                 if (game.damage[DWARPEN] > 0.0 && warpfac > 4.0) {
502                         chew();
503                         skip(1);
504                         prout("Engineer Scott- \"Sorry, Captain. Until this damage");
505                         prout("  is repaired, I can only give you warp 4.\"");
506                         return;
507                 }
508                         
509                 /* Read in course and distance */
510                 getcd(FALSE, 0);
511                 if (direc == -1.0) return;
512
513                 /* Make sure starship has enough energy for the trip */
514                 power = (dist+0.05)*warpfac*warpfac*warpfac*(shldup+1);
515
516
517                 if (power >= energy) {
518                         /* Insufficient power for trip */
519                         ididit = 0;
520                         skip(1);
521                         prout("Engineering to bridge--");
522                         if (shldup==0 || 0.5*power > energy) {
523                                 iwarp = pow((energy/(dist+0.05)), 0.333333333);
524                                 if (iwarp <= 0) {
525                                         prout("We can't do it, Captain. We haven't the energy.");
526                                 }
527                                 else {
528                                         proutn("We haven't the energy, but we could do it at warp %d", iwarp);
529                                         if (shldup) {
530                                                 prout(",");
531                                                 prout("if you'll lower the shields.");
532                                         }
533                                         else
534                                                 prout(".");
535                                 }
536                         }
537                         else
538                                 prout("We haven't the energy to go that far with the shields up.");
539                         return;
540                 }
541                                                 
542                 /* Make sure enough time is left for the trip */
543                 Time = 10.0*dist/wfacsq;
544                 if (Time >= 0.8*game.state.remtime) {
545                         skip(1);
546                         prout("First Officer Spock- \"Captain, I compute that such");
547                         proutn("  a trip would require approximately %2.0f",
548                                 100.0*Time/game.state.remtime);
549                         prout(" percent of our");
550                         proutn("  remaining time.  Are you sure this is wise?\" ");
551                         if (ja() == 0) { ididit = 0; Time=0; return;}
552                 }
553         }
554         /* Entry WARPX */
555         if (warpfac > 6.0) {
556                 /* Decide if engine damage will occur */
557                 double prob = dist*(6.0-warpfac)*(6.0-warpfac)/66.666666666;
558                 if (prob > Rand()) {
559                         blooey = 1;
560                         dist = Rand()*dist;
561                 }
562                 /* Decide if time warp will occur */
563                 if (0.5*dist*pow(7.0,warpfac-10.0) > Rand()) twarp=1;
564 #ifdef DEBUG
565                 if (idebug &&warpfac==10 && twarp==0) {
566                         blooey=0;
567                         proutn("Force time warp? ");
568                         if (ja()==1) twarp=1;
569                 }
570 #endif
571                 if (blooey || twarp) {
572                         /* If time warp or engine damage, check path */
573                         /* If it is obstructed, don't do warp or damage */
574                         double angle = ((15.0-direc)*0.5235998);
575                         double deltax = -sin(angle);
576                         double deltay = cos(angle);
577                         double bigger, x, y;
578                         int n, l, ix, iy;
579                         if (fabs(deltax) > fabs(deltay))
580                                 bigger = fabs(deltax);
581                         else
582                                 bigger = fabs(deltay);
583                         
584                         deltax /= bigger;
585                         deltay /= bigger;
586                         n = 10.0 * dist * bigger +0.5;
587                         x = sectx;
588                         y = secty;
589                         for (l = 1; l <= n; l++) {
590                                 x += deltax;
591                                 ix = x + 0.5;
592                                 if (ix < 1 || ix > 10) break;
593                                 y += deltay;
594                                 iy = y +0.5;
595                                 if (iy < 1 || iy > 10) break;
596                                 if (game.quad[ix][iy] != IHDOT) {
597                                         blooey = 0;
598                                         twarp = 0;
599                                 }
600                         }
601                 }
602         }
603                                 
604
605         /* Activate Warp Engines and pay the cost */
606         imove();
607         if (alldone) return;
608         energy -= dist*warpfac*warpfac*warpfac*(shldup+1);
609         if (energy <= 0) finish(FNRG);
610         Time = 10.0*dist/wfacsq;
611         if (twarp) timwrp();
612         if (blooey) {
613                 game.damage[DWARPEN] = damfac*(3.0*Rand()+1.0);
614                 skip(1);
615                 prout("Engineering to bridge--");
616                 prout("  Scott here.  The warp engines are damaged.");
617                 prout("  We'll have to reduce speed to warp 4.");
618         }
619         ididit = 1;
620         return;
621 }
622
623
624
625 void setwrp(void) {
626         int key;
627         double oldfac;
628         
629         while ((key=scan()) == IHEOL) {
630                 chew();
631                 proutn("Warp factor- ");
632         }
633         chew();
634         if (key != IHREAL) {
635                 huh();
636                 return;
637         }
638         if (game.damage[DWARPEN] > 10.0) {
639                 prout("Warp engines inoperative.");
640                 return;
641         }
642         if (game.damage[DWARPEN] > 0.0 && aaitem > 4.0) {
643                 prout("Engineer Scott- \"I'm doing my best, Captain,\n"
644                           "  but right now we can only go warp 4.\"");
645                 return;
646         }
647         if (aaitem > 10.0) {
648                 prout("Helmsman Sulu- \"Our top speed is warp 10, Captain.\"");
649                 return;
650         }
651         if (aaitem < 1.0) {
652                 prout("Helmsman Sulu- \"We can't go below warp 1, Captain.\"");
653                 return;
654         }
655         oldfac = warpfac;
656         warpfac = aaitem;
657         wfacsq=warpfac*warpfac;
658         if (warpfac <= oldfac || warpfac <= 6.0) {
659                 proutn("Helmsman Sulu- \"Warp factor %d, Captain.\"", 
660                         (int)warpfac);
661                 return;
662         }
663         if (warpfac < 8.00) {
664                 prout("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\"");
665                 return;
666         }
667         if (warpfac == 10.0) {
668                 prout("Engineer Scott- \"Aye, Captain, we'll try it.\"");
669                 return;
670         }
671         prout("Engineer Scott- \"Aye, Captain, but our engines may not take it.\"");
672         return;
673 }
674
675 void atover(int igrab) {
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                 game.starch[quadx][quady] = game.damage[DRADIO] > 0.0 ? game.state.galaxy[quadx][quady]+1000:1;
732
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                 /* Repeat if another snova */
761         } while (game.state.galaxy[quadx][quady] == 1000);
762         if (game.state.remkl==0) finish(FWON); /* Snova killed remaining enemy. */
763 }
764
765 void timwrp() {
766         int l, ll, gotit;
767         prout("***TIME WARP ENTERED.");
768         if (game.state.snap && Rand() < 0.5) {
769                 /* Go back in time */
770                 prout("You are traveling backwards in time %d stardates.",
771                       (int)(game.state.date-game.snapsht.date));
772                 game.state = game.snapsht;
773                 game.state.snap = 0;
774                 if (game.state.remcom) {
775                         game.future[FTBEAM] = game.state.date + expran(intime/game.state.remcom);
776                         game.future[FBATTAK] = game.state.date + expran(0.3*intime);
777                 }
778                 game.future[FSNOVA] = game.state.date + expran(0.5*intime);
779                 game.future[FSNAP] = game.state.date +expran(0.25*game.state.remtime); /* next snapshot will
780                                                                                                            be sooner */
781                 if (game.state.nscrem) game.future[FSCMOVE] = 0.2777;
782                 isatb = 0;
783                 game.future[FCDBAS] = game.future[FSCDBAS] = 1e30;
784                 batx = baty = 0;
785
786                 /* Make sure Galileo is consistant -- Snapshot may have been taken
787                    when on planet, which would give us two Galileos! */
788                 gotit = 0;
789                 for (l = 0; l < inplan; l++) {
790                         if (game.state.plnets[l].known == shuttle_down) {
791                                 gotit = 1;
792                                 if (iscraft==1 && ship==IHE) {
793                                         prout("Checkov-  \"Security reports the Galileo has disappeared, Sir!");
794                                         iscraft = 0;
795                                 }
796                         }
797                 }
798                 /* Likewise, if in the original time the Galileo was abandoned, but
799                    was on ship earlier, it would have vanished -- lets restore it */
800                 if (iscraft==0 && gotit==0 && game.damage[DSHUTTL] >= 0.0) {
801                         prout("Checkov-  \"Security reports the Galileo has reappeared in the dock!\"");
802                         iscraft = 1;
803                 }
804
805                 /* Revert star chart to earlier era, if it was known then*/
806                 if (game.damage[DRADIO]==0.0 || stdamtim > game.state.date) {
807                         for (l = 1; l <= 8; l++)
808                                 for (ll = 1; ll <= 8; ll++)
809                                         if (game.starch[l][ll] > 1)
810                                                 game.starch[l][ll]=game.damage[DRADIO]>0.0 ? game.state.galaxy[l][ll]+1000 :1;
811                         prout("Spock has reconstructed a correct star chart from memory");
812                         if (game.damage[DRADIO] > 0.0) stdamtim = game.state.date;
813                 }
814         }
815         else {
816                 /* Go forward in time */
817                 Time = -0.5*intime*log(Rand());
818                 prout("You are traveling forward in time %d stardates.", (int)Time);
819                 /* cheat to make sure no tractor beams occur during time warp */
820                 game.future[FTBEAM] += Time;
821                 game.damage[DRADIO] += Time;
822         }
823         newqad(0);
824         events();       /* Stas Sergeev added this -- do pending events */
825 }
826
827 void probe(void) {
828         double angle, bigger;
829         int key;
830         /* New code to launch a deep space probe */
831         if (nprobes == 0) {
832                 chew();
833                 skip(1);
834                 if (ship == IHE) 
835                         prout("Engineer Scott- \"We have no more deep space probes, Sir.\"");
836                 else
837                         prout("Ye Faerie Queene has no deep space probes.");
838                 return;
839         }
840         if (game.damage[DDSP] != 0.0) {
841                 chew();
842                 skip(1);
843                 prout("Engineer Scott- \"The probe launcher is damaged, Sir.\"");
844                 return;
845         }
846         if (game.future[FDSPROB] != 1e30) {
847                 chew();
848                 skip(1);
849                 if (game.damage[DRADIO] != 0 && condit != IHDOCKED) {
850                         prout("Spock-  \"Records show the previous probe has not yet");
851                         prout("   reached its destination.\"");
852                 }
853                 else
854                         prout("Uhura- \"The previous probe is still reporting data, Sir.\"");
855                 return;
856         }
857         key = scan();
858
859         if (key == IHEOL) {
860                 /* slow mode, so let Kirk know how many probes there are left */
861                 prout(nprobes==1 ? "%d probe left." : "%d probes left.", nprobes);
862                 proutn("Are you sure you want to fire a probe? ");
863                 if (ja()==0) return;
864         }
865
866         isarmed = FALSE;
867         if (key == IHALPHA && strcmp(citem,"armed") == 0) {
868                 isarmed = TRUE;
869                 key = scan();
870         }
871         else if (key == IHEOL) {
872                 proutn("Arm NOVAMAX warhead? ");
873                 isarmed = ja();
874         }
875         getcd(TRUE, key);
876         if (direc == -1.0) return;
877         nprobes--;
878                 angle = ((15.0 - direc) * 0.5235988);
879         probeinx = -sin(angle);
880         probeiny = cos(angle);
881         if (fabs(probeinx) > fabs(probeiny))
882                 bigger = fabs(probeinx);
883         else
884                 bigger = fabs(probeiny);
885                 
886         probeiny /= bigger;
887         probeinx /= bigger;
888         proben = 10.0*dist*bigger +0.5;
889         probex = quadx*10 + sectx - 1;  // We will use better packing than original
890         probey = quady*10 + secty - 1;
891         probecx = quadx;
892         probecy = quady;
893         game.future[FDSPROB] = game.state.date + 0.01; // Time to move one sector
894         prout("Ensign Chekov-  \"The deep space probe is launched, Captain.\"");
895         ididit = 1;
896         return;
897 }
898
899 void help(void) {
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 (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         /* 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(LIGHTGRAY);
991         }
992         if (l > 3) {
993                 finish(FMATERIALIZE);
994                 return;
995         }
996         game.quad[ix][iy]=ship;
997         textcolor(WHITE);
998         prout("succeeds.");
999         textcolor(LIGHTGRAY);
1000         dock(0);
1001         skip(1);
1002         prout("Lt. Uhura-  \"Captain, we made it!\"");
1003 }