Resync code and docs.
[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_local_enemies(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                     skip(1);
101                     prout("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER");
102                     prout("AT THE EDGE OF THE GALAXY.  THE THIRD TIME YOU TRY THIS,");
103                     prout("YOU WILL BE DESTROYED.");
104                 }
105                 /* Compute final position in new quadrant */
106                 if (trbeam) return; /* Don't bother if we are to be beamed */
107                 quadx = (ix+(QUADSIZE-1))/QUADSIZE;
108                 quady = (iy+(QUADSIZE-1))/QUADSIZE;
109                 sectx = ix - QUADSIZE*(quadx-1);
110                 secty = iy - QUADSIZE*(quady-1);
111                 skip(1);
112                 prout("Entering %s.",
113                       cramlc(quadrant, quadx, quady));
114                 game.quad[sectx][secty] = ship;
115                 newqad(0);
116                 if (skill>SKILL_NOVICE) attack(0);
117                 return;
118             }
119             iquad = game.quad[ix][iy];
120             if (iquad != IHDOT) {
121                 /* object encountered in flight path */
122                 stopegy = 50.0*dist/Time;
123                 dist=0.1*sqrt((sectx-ix)*(double)(sectx-ix) +
124                               (secty-iy)*(double)(secty-iy));
125                 switch (iquad) {
126                 case IHT: /* Ram a Tholian */
127                 case IHK: /* Ram enemy ship */
128                 case IHC:
129                 case IHS:
130                 case IHR:
131                 case IHQUEST:
132                     sectx = ix;
133                     secty = iy;
134                     ram(0, iquad, sectx, secty);
135                     finalx = sectx;
136                     finaly = secty;
137                     break;
138                 case IHBLANK:
139                     skip(1);
140                     prouts("***RED ALERT!  RED ALERT!");
141                     skip(1);
142                     proutn("***");
143                     crmshp();
144                     proutn(" pulled into black hole at ");
145                     prout(cramlc(sector, ix, iy));
146                     /*
147                      * Getting pulled into a black hole was certain
148                      * death in Almy's original.  Stas Sergeev added a
149                      * possibility that you'll get timewarped instead.
150                      */
151                     n=0;
152                     for (l=0;l<NDEVICES;l++)
153                         if (game.damage[l]>0) 
154                             n++;
155                     probf=pow(1.4,(energy+shield)/5000.0-1.0)*pow(1.3,1.0/(n+1)-1.0);
156                     if (Rand()>probf) 
157                         timwrp();
158                     else 
159                         finish(FHOLE);
160                     return;
161                 default:
162                     /* something else */
163                     skip(1);
164                     crmshp();
165                     if (iquad == IHWEB)
166                         proutn(" encounters Tholian web at ");
167                     else
168                         proutn(" blocked by object at ");
169                     proutn(cramlc(sector, ix,iy));
170                     prout(";");
171                     proutn("Emergency stop required ");
172                     prout("%2d units of energy.", (int)stopegy);
173                     energy -= stopegy;
174                     finalx = x-deltax+0.5;
175                     sectx = finalx;
176                     finaly = y-deltay+0.5;
177                     secty = finaly;
178                     if (energy <= 0) {
179                         finish(FNRG);
180                         return;
181                     }
182                     break;
183                 }
184                 goto no_quad_change;    /* sorry! */
185             }
186         }
187         dist = 0.1*sqrt((sectx-ix)*(double)(sectx-ix) +
188                         (secty-iy)*(double)(secty-iy));
189         sectx = ix;
190         secty = iy;
191     }
192     finalx = sectx;
193     finaly = secty;
194 no_quad_change:
195     /* No quadrant change -- compute new avg enemy distances */
196     game.quad[sectx][secty] = ship;
197     if (nenhere) {
198         for_local_enemies(l) {
199             finald = sqrt((ix-game.kx[l])*(double)(ix-game.kx[l]) +
200                           (iy-game.ky[l])*(double)(iy-game.ky[l]));
201             game.kavgd[l] = 0.5 * (finald+game.kdist[l]);
202             game.kdist[l] = finald;
203         }
204         sortkl();
205         if (!game.state.galaxy[quadx][quady].supernova && iattak == 0)
206             attack(0);
207         for_local_enemies(l) game.kavgd[l] = game.kdist[l];
208     }
209     newcnd();
210     iattak = 0;
211     drawmaps(0);
212     return;
213 }
214
215 void dock(int l) 
216 {
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 (game.damage[DRADIO] == 0.0 &&
239         (game.future[FCDBAS] < FOREVER || 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 aboard 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 (!VALID_QUADRANT(icolq,irowq)||!VALID_SECTOR(icols,irows)) {
378                     huh();
379                     return;
380                 }
381                 skip(1);
382                 if (!isprobe) {
383                         if (itemp) {
384                                 if (iprompt) {
385                                         prout("Helmsman Sulu- \"Course locked in for %s.\"",
386                                                 cramlc(sector, irows, icols));
387                                 }
388                         }
389                         else prout("Ensign Chekov- \"Course laid in, Captain.\"");
390                 }
391                 deltax = icolq - quady + 0.1*(icols-secty);
392                 deltay = quadx - irowq + 0.1*(sectx-irows);
393         }
394         else { /* manual */
395                 while (key == IHEOL) {
396                         proutn("X and Y displacements- ");
397                         chew();
398                         iprompt = 1;
399                         key = scan();
400                 }
401                 itemp = 2;
402                 if (key != IHREAL) {
403                         huh();
404                         return;
405                 }
406                 deltax = aaitem;
407                 key = scan();
408                 if (key != IHREAL) {
409                         huh();
410                         return;
411                 }
412                 deltay = aaitem;
413         }
414         /* Check for zero movement */
415         if (deltax == 0 && deltay == 0) {
416                 chew();
417                 return;
418         }
419         if (itemp == 2 && !isprobe) {
420                 skip(1);
421                 prout("Helmsman Sulu- \"Aye, Sir.\"");
422         }
423         dist = sqrt(deltax*deltax + deltay*deltay);
424         direc = atan2(deltax, deltay)*1.90985932;
425         if (direc < 0.0) direc += 12.0;
426         chew();
427         return;
428
429 }
430                 
431
432
433 void impuls(void) 
434 {
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 {
491     int blooey=0, twarp=0, iwarp;
492     double power;
493
494     if (i!=2) { /* Not WARPX entry */
495         ididit = 0;
496         if (game.damage[DWARPEN] > 10.0) {
497             chew();
498             skip(1);
499             prout("Engineer Scott- \"The impulse engines are damaged, Sir.\"");
500             return;
501         }
502         if (game.damage[DWARPEN] > 0.0 && warpfac > 4.0) {
503             chew();
504             skip(1);
505             prout("Engineer Scott- \"Sorry, Captain. Until this damage");
506             prout("  is repaired, I can only give you warp 4.\"");
507             return;
508         }
509                         
510         /* Read in course and distance */
511         getcd(FALSE, 0);
512         if (direc == -1.0) return;
513
514         /* Make sure starship has enough energy for the trip */
515         power = (dist+0.05)*warpfac*warpfac*warpfac*(shldup+1);
516
517
518         if (power >= energy) {
519             /* Insufficient power for trip */
520             ididit = 0;
521             skip(1);
522             prout("Engineering to bridge--");
523             if (shldup==0 || 0.5*power > energy) {
524                 iwarp = pow((energy/(dist+0.05)), 0.333333333);
525                 if (iwarp <= 0) {
526                     prout("We can't do it, Captain. We haven't the energy.");
527                 }
528                 else {
529                     proutn("We haven't the energy, but we could do it at warp %d", iwarp);
530                     if (shldup) {
531                         prout(",");
532                         prout("if you'll lower the shields.");
533                     }
534                     else
535                         prout(".");
536                 }
537             }
538             else
539                 prout("We haven't the energy to go that far with the shields up.");
540             return;
541         }
542                                                 
543         /* Make sure enough time is left for the trip */
544         Time = 10.0*dist/wfacsq;
545         if (Time >= 0.8*game.state.remtime) {
546             skip(1);
547             prout("First Officer Spock- \"Captain, I compute that such");
548             proutn("  a trip would require approximately %2.0f",
549                    100.0*Time/game.state.remtime);
550             prout(" percent of our");
551             proutn("  remaining time.  Are you sure this is wise?\" ");
552             if (ja() == 0) { ididit = 0; Time=0; return;}
553         }
554     }
555     /* Entry WARPX */
556     if (warpfac > 6.0) {
557         /* Decide if engine damage will occur */
558         double prob = dist*(6.0-warpfac)*(6.0-warpfac)/66.666666666;
559         if (prob > Rand()) {
560             blooey = 1;
561             dist = Rand()*dist;
562         }
563         /* Decide if time warp will occur */
564         if (0.5*dist*pow(7.0,warpfac-10.0) > Rand()) twarp=1;
565 #ifdef DEBUG
566         if (idebug &&warpfac==10 && twarp==0) {
567             blooey=0;
568             proutn("Force time warp? ");
569             if (ja()==1) twarp=1;
570         }
571 #endif
572         if (blooey || twarp) {
573             /* If time warp or engine damage, check path */
574             /* If it is obstructed, don't do warp or damage */
575             double angle = ((15.0-direc)*0.5235998);
576             double deltax = -sin(angle);
577             double deltay = cos(angle);
578             double bigger, x, y;
579             int n, l, ix, iy;
580             if (fabs(deltax) > fabs(deltay))
581                 bigger = fabs(deltax);
582             else
583                 bigger = fabs(deltay);
584                         
585             deltax /= bigger;
586             deltay /= bigger;
587             n = 10.0 * dist * bigger +0.5;
588             x = sectx;
589             y = secty;
590             for (l = 1; l <= n; l++) {
591                 x += deltax;
592                 ix = x + 0.5;
593                 y += deltay;
594                 iy = y +0.5;
595                 if (!VALID_SECTOR(ix, iy)) 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 {
627     int key;
628     double oldfac;
629         
630     while ((key=scan()) == IHEOL) {
631         chew();
632         proutn("Warp factor- ");
633     }
634     chew();
635     if (key != IHREAL) {
636         huh();
637         return;
638     }
639     if (game.damage[DWARPEN] > 10.0) {
640         prout("Warp engines inoperative.");
641         return;
642     }
643     if (game.damage[DWARPEN] > 0.0 && aaitem > 4.0) {
644         prout("Engineer Scott- \"I'm doing my best, Captain,");
645         prout("  but right now we can only go warp 4.\"");
646         return;
647     }
648     if (aaitem > 10.0) {
649         prout("Helmsman Sulu- \"Our top speed is warp 10, Captain.\"");
650         return;
651     }
652     if (aaitem < 1.0) {
653         prout("Helmsman Sulu- \"We can't go below warp 1, Captain.\"");
654         return;
655     }
656     oldfac = warpfac;
657     warpfac = aaitem;
658     wfacsq=warpfac*warpfac;
659     if (warpfac <= oldfac || warpfac <= 6.0) {
660         proutn("Helmsman Sulu- \"Warp factor %d, Captain.\"", 
661                (int)warpfac);
662         return;
663     }
664     if (warpfac < 8.00) {
665         prout("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\"");
666         return;
667     }
668     if (warpfac == 10.0) {
669         prout("Engineer Scott- \"Aye, Captain, we'll try it.\"");
670         return;
671     }
672     prout("Engineer Scott- \"Aye, Captain, but our engines may not take it.\"");
673     return;
674 }
675
676 void atover(int igrab) 
677 {
678     double power, distreq;
679
680     chew();
681     /* is captain on planet? */
682     if (landed==1) {
683         if (game.damage[DTRANSP]) {
684             finish(FPNOVA);
685             return;
686         }
687         prout("Scotty rushes to the transporter controls.");
688         if (shldup) {
689             prout("But with the shields up it's hopeless.");
690             finish(FPNOVA);
691         }
692         prouts("His desperate attempt to rescue you . . .");
693         if (Rand() <= 0.5) {
694             prout("fails.");
695             finish(FPNOVA);
696             return;
697         }
698         prout("SUCCEEDS!");
699         if (imine) {
700             imine = 0;
701             proutn("The crystals mined were ");
702             if (Rand() <= 0.25) {
703                 prout("lost.");
704             }
705             else {
706                 prout("saved.");
707                 icrystl = 1;
708             }
709         }
710     }
711     if (igrab) return;
712
713     /* Check to see if captain in shuttle craft */
714     if (icraft) finish(FSTRACTOR);
715     if (alldone) return;
716
717     /* Inform captain of attempt to reach safety */
718     skip(1);
719     do {
720         if (justin) {
721             prouts("***RED ALERT!  READ ALERT!");
722             skip(1);
723             proutn("The ");
724             crmshp();
725             prout(" has stopped in a quadrant containing");
726             prouts("   a supernova.");
727             skip(2);
728         }
729         proutn("***Emergency automatic override attempts to hurl ");
730         crmshp();
731         skip(1);
732         prout("safely out of quadrant.");
733         if (game.damage[DRADIO] == 0.0)
734             game.state.galaxy[quadx][quady].charted = TRUE;
735         /* Try to use warp engines */
736         if (game.damage[DWARPEN]) {
737             skip(1);
738             prout("Warp engines damaged.");
739             finish(FSNOVAED);
740             return;
741         }
742         warpfac = 6.0+2.0*Rand();
743         wfacsq = warpfac * warpfac;
744         prout("Warp factor set to %d", (int)warpfac);
745         power = 0.75*energy;
746         dist = power/(warpfac*warpfac*warpfac*(shldup+1));
747         distreq = 1.4142+Rand();
748         if (distreq < dist) dist = distreq;
749         Time = 10.0*dist/wfacsq;
750         direc = 12.0*Rand();    /* How dumb! */
751         justin = 0;
752         inorbit = 0;
753         warp(2);
754         if (justin == 0) {
755             /* This is bad news, we didn't leave quadrant. */
756             if (alldone) return;
757             skip(1);
758             prout("Insufficient energy to leave quadrant.");
759             finish(FSNOVAED);
760             return;
761         }
762     } while 
763         /* Repeat if another snova */
764         (game.state.galaxy[quadx][quady].supernova);
765     if (game.state.remkl==0) 
766         finish(FWON); /* Snova killed remaining enemy. */
767 }
768
769 void timwrp() 
770 {
771     int l, gotit;
772     prout("***TIME WARP ENTERED.");
773     if (game.state.snap && Rand() < 0.5) {
774         /* Go back in time */
775         prout("You are traveling backwards in time %d stardates.",
776               (int)(game.state.date-game.snapsht.date));
777         game.state = game.snapsht;
778         game.state.snap = 0;
779         if (game.state.remcom) {
780             game.future[FTBEAM] = game.state.date + expran(intime/game.state.remcom);
781             game.future[FBATTAK] = game.state.date + expran(0.3*intime);
782         }
783         game.future[FSNOVA] = game.state.date + expran(0.5*intime);
784         game.future[FSNAP] = game.state.date +expran(0.25*game.state.remtime); /* next snapshot will
785                                                                                   be sooner */
786         if (game.state.nscrem) game.future[FSCMOVE] = 0.2777;
787         isatb = 0;
788         game.future[FCDBAS] = game.future[FSCDBAS] = FOREVER;
789         batx = baty = 0;
790
791         /* Make sure Galileo is consistant -- Snapshot may have been taken
792            when on planet, which would give us two Galileos! */
793         gotit = 0;
794         for (l = 0; l < inplan; l++) {
795             if (game.state.plnets[l].known == shuttle_down) {
796                 gotit = 1;
797                 if (iscraft==1 && ship==IHE) {
798                     prout("Checkov-  \"Security reports the Galileo has disappeared, Sir!");
799                     iscraft = 0;
800                 }
801             }
802         }
803         /* Likewise, if in the original time the Galileo was abandoned, but
804            was on ship earlier, it would have vanished -- lets restore it */
805         if (iscraft==0 && gotit==0 && game.damage[DSHUTTL] >= 0.0) {
806             prout("Checkov-  \"Security reports the Galileo has reappeared in the dock!\"");
807             iscraft = 1;
808         }
809         /* 
810          * There used to be code to do the actual reconstrction here,
811          * but the starchart is now part of the snapshotted galaxy state.
812          */
813         prout("Spock has reconstructed a correct star chart from memory");
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 {
829     double angle, bigger;
830     int key;
831     /* New code to launch a deep space probe */
832     if (nprobes == 0) {
833         chew();
834         skip(1);
835         if (ship == IHE) 
836             prout("Engineer Scott- \"We have no more deep space probes, Sir.\"");
837         else
838             prout("Ye Faerie Queene has no deep space probes.");
839         return;
840     }
841     if (game.damage[DDSP] != 0.0) {
842         chew();
843         skip(1);
844         prout("Engineer Scott- \"The probe launcher is damaged, Sir.\"");
845         return;
846     }
847     if (game.future[FDSPROB] != FOREVER) {
848         chew();
849         skip(1);
850         if (game.damage[DRADIO] != 0 && condit != IHDOCKED) {
851             prout("Spock-  \"Records show the previous probe has not yet");
852             prout("   reached its destination.\"");
853         }
854         else
855             prout("Uhura- \"The previous probe is still reporting data, Sir.\"");
856         return;
857     }
858     key = scan();
859
860     if (key == IHEOL) {
861         /* slow mode, so let Kirk know how many probes there are left */
862         prout(nprobes==1 ? "%d probe left." : "%d probes left.", nprobes);
863         proutn("Are you sure you want to fire a probe? ");
864         if (ja()==0) return;
865     }
866
867     isarmed = FALSE;
868     if (key == IHALPHA && strcmp(citem,"armed") == 0) {
869         isarmed = TRUE;
870         key = scan();
871     }
872     else if (key == IHEOL) {
873         proutn("Arm NOVAMAX warhead? ");
874         isarmed = ja();
875     }
876     getcd(TRUE, key);
877     if (direc == -1.0) return;
878     nprobes--;
879     angle = ((15.0 - direc) * 0.5235988);
880     probeinx = -sin(angle);
881     probeiny = cos(angle);
882     if (fabs(probeinx) > fabs(probeiny))
883         bigger = fabs(probeinx);
884     else
885         bigger = fabs(probeiny);
886                 
887     probeiny /= bigger;
888     probeinx /= bigger;
889     proben = 10.0*dist*bigger +0.5;
890     probex = quadx*QUADSIZE + sectx - 1;        // We will use better packing than original
891     probey = quady*QUADSIZE + secty - 1;
892     probecx = quadx;
893     probecy = quady;
894     game.future[FDSPROB] = game.state.date + 0.01; // Time to move one sector
895     prout("Ensign Chekov-  \"The deep space probe is launched, Captain.\"");
896     ididit = 1;
897     return;
898 }
899
900 void help(void) 
901 {
902     /* There's more than one way to move in this game! */
903     double ddist, xdist, probf;
904     int line = 0, l, ix, iy;
905
906     chew();
907     /* Test for conditions which prevent calling for help */
908     if (condit == IHDOCKED) {
909         prout("Lt. Uhura-  \"But Captain, we're already docked.\"");
910         return;
911     }
912     if (game.damage[DRADIO] != 0) {
913         prout("Subspace radio damaged.");
914         return;
915     }
916     if (game.state.rembase==0) {
917         prout("Lt. Uhura-  \"Captain, I'm not getting any response from Starbase.\"");
918         return;
919     }
920     if (landed == 1) {
921         proutn("You must be aboard the ");
922         crmshp();
923         prout(".");
924         return;
925     }
926     /* OK -- call for help from nearest starbase */
927     nhelp++;
928     if (basex!=0) {
929         /* There's one in this quadrant */
930         ddist = sqrt(square(basex-sectx)+square(basey-secty));
931     }
932     else {
933         ddist = FOREVER;
934         for_starbases(l) {
935             xdist=10.0*sqrt(square(game.state.baseqx[l]-quadx)+square(game.state.baseqy[l]-quady));
936             if (xdist < ddist) {
937                 ddist = xdist;
938                 line = l;
939             }
940         }
941         /* Since starbase not in quadrant, set up new quadrant */
942         quadx = game.state.baseqx[line];
943         quady = game.state.baseqy[line];
944         newqad(1);
945     }
946     /* dematerialize starship */
947     game.quad[sectx][secty]=IHDOT;
948     proutn("Starbase in %s responds--", cramlc(quadrant, quadx, quady));
949     proutn("");
950     crmshp();
951     prout(" dematerializes.");
952     sectx=0;
953     for (l = 1; l <= 5; l++) {
954         ix = basex+3.0*Rand()-1;
955         iy = basey+3.0*Rand()-1;
956         if (VALID_SECTOR(ix,iy) && game.quad[ix][iy]==IHDOT) {
957             /* found one -- finish up */
958             sectx=ix;
959             secty=iy;
960             break;
961         }
962     }
963     if (sectx==0){
964         prout("You have been lost in space...");
965         finish(FMATERIALIZE);
966         return;
967     }
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         switch (l){
979         case 1: game.quad[ix][iy]=IHMATER0;
980             break;
981         case 2: game.quad[ix][iy]=IHMATER1;
982             break;
983         case 3: game.quad[ix][iy]=IHMATER2;
984             break;
985         }
986         textcolor(RED);
987         warble();
988         if (Rand() > probf) break;
989         prout("fails.");
990         delay(500);
991         textcolor(DEFAULT);
992     }
993     if (l > 3) {
994         game.quad[ix][iy]=IHQUEST;
995         alive = 0;
996         drawmaps(1);
997         setwnd(message_window);
998         finish(FMATERIALIZE);
999         return;
1000     }
1001     game.quad[ix][iy]=ship;
1002     textcolor(GREEN);
1003     prout("succeeds.");
1004     textcolor(DEFAULT);
1005     dock(0);
1006     skip(1);
1007     prout("Lt. Uhura-  \"Captain, we made it!\"");
1008 }