Get rid of all DOS-generated CRs.
[super-star-trek.git] / battle.c
1 #ifdef SERGEEV
2 #include <conio.h>
3 #include <unistd.h>
4 #include "sstlinux.h"
5 #endif /* SERGEEV */
6 #include "sst.h"
7
8 void doshield(int i) {
9         int key;
10         enum {NONE, SHUP, SHDN, NRG} action = NONE;
11
12         ididit = 0;
13
14         if (i == 2) action = SHUP;
15         else {
16                 key = scan();
17                 if (key == IHALPHA) {
18                         if (isit("transfer"))
19                                 action = NRG;
20                         else {
21                                 chew();
22                                 if (game.damage[DSHIELD]) {
23                                         prout("Shields damaged and down.");
24                                         return;
25                                 }
26                                 if (isit("up"))
27                                         action = SHUP;
28                                 else if (isit("down"))
29                                         action = SHDN;
30                         }
31                 }
32                 if (action==NONE) {
33                         proutn("Do you wish to change shield energy? ");
34                         if (ja()) {
35                                 proutn("Energy to transfer to shields- ");
36                                 action = NRG;
37                         }
38                         else if (game.damage[DSHIELD]) {
39                                 prout("Shields damaged and down.");
40                                 return;
41                         }
42                         else if (shldup) {
43                                 proutn("Shields are up. Do you want them down? ");
44                                 if (ja()) action = SHDN;
45                                 else {
46                                         chew();
47                                         return;
48                                 }
49                         }
50                         else {
51                                 proutn("Shields are down. Do you want them up? ");
52                                 if (ja()) action = SHUP;
53                                 else {
54                                         chew();
55                                         return;
56                                 }
57                         }
58                 }
59         }
60         switch (action) {
61                 case SHUP: /* raise shields */
62                         if (shldup) {
63                                 prout("Shields already up.");
64                                 return;
65                         }
66                         shldup = 1;
67                         shldchg = 1;
68                         if (condit != IHDOCKED) energy -= 50.0;
69                         prout("Shields raised.");
70                         if (energy <= 0) {
71                                 skip(1);
72                                 prout("Shields raising uses up last of energy.");
73                                 finish(FNRG);
74                                 return;
75                         }
76                         ididit=1;
77                         return;
78                 case SHDN:
79                         if (shldup==0) {
80                                 prout("Shields already down.");
81                                 return;
82                         }
83                         shldup=0;
84                         shldchg=1;
85                         prout("Shields lowered.");
86                         ididit=1;
87                         return;
88                 case NRG:
89                         while (scan() != IHREAL) {
90                                 chew();
91                                 proutn("Energy to transfer to shields- ");
92                         }
93                         chew();
94                         if (aaitem==0) return;
95                         if (aaitem > energy) {
96                                 prout("Insufficient ship energy.");
97                                 return;
98                         }
99                         ididit = 1;
100                         if (shield+aaitem >= inshld) {
101                                 prout("Shield energy maximized.");
102                                 if (shield+aaitem > inshld) {
103                                         prout("Excess energy requested returned to ship energy");
104                                 }
105                                 energy -= inshld-shield;
106                                 shield = inshld;
107                                 return;
108                         }
109                         if (aaitem < 0.0 && energy-aaitem > inenrg) {
110                                 /* Prevent shield drain loophole */
111                                 skip(1);
112                                 prout("Engineering to bridge--");
113                                 prout("  Scott here. Power circuit problem, Captain.");
114                                 prout("  I can't drain the shields.");
115                                 ididit = 0;
116                                 return;
117                         }
118                         if (shield+aaitem < 0) {
119                                 prout("All shield energy transferred to ship.");
120                                 energy += shield;
121                                 shield = 0.0;
122                                 return;
123                         }
124                         proutn("Scotty- \"");
125                         if (aaitem > 0)
126                                 prout("Transferring energy to shields.\"");
127                         else
128                                 prout("Draining energy from shields.\"");
129                         shield += aaitem;
130                         energy -= aaitem;
131                         return;
132                 case NONE:;     /* avoid gcc warning */
133         }
134 }
135
136 void ram(int ibumpd, int ienm, int ix, int iy) {
137         double type = 1.0, extradm;
138         int icas, l;
139         
140         prouts("***RED ALERT!  RED ALERT!");
141         skip(1);
142         prout("***COLLISION IMMINENT.");
143         skip(2);
144         proutn("***");
145         crmshp();
146         switch (ienm) {
147                 case IHR: type = 1.5; break;
148                 case IHC: type = 2.0; break;
149                 case IHS: type = 2.5; break;
150                 case IHT: type = 0.5; break;
151                 case IHQUEST: type = 4.0; break;
152         }
153         proutn(ibumpd ? " rammed by " : " rams ");
154         crmena(0, ienm, 2, ix, iy);
155         if (ibumpd) proutn(" (original position)");
156         skip(1);
157         deadkl(ix, iy, ienm, sectx, secty);
158         proutn("***");
159         crmshp();
160         prout(" heavily damaged.");
161         icas = 10.0+20.0*Rand();
162         prout("***Sickbay reports %d casualties", icas);
163         casual += icas;
164         for (l=1; l <= NDEVICES; l++) {
165                 if (l == DDRAY) continue; // Don't damage deathray 
166                 if (game.damage[l] < 0) continue;
167                 extradm = (10.0*type*Rand()+1.0)*damfac;
168                 game.damage[l] += Time + extradm; /* Damage for at least time of travel! */
169         }
170         shldup = 0;
171         if (game.state.remkl) {
172                 pause_game(2);
173                 dreprt();
174         }
175         else finish(FWON);
176         return;
177 }
178
179 void torpedo(double course, double r, int inx, int iny, double *hit, int wait) {
180         int l, iquad=0, ix=0, iy=0, jx=0, jy=0, shoved=0, ll;
181 #ifdef SERGEEV
182         int crx,cry;
183         
184 #endif /* SERGEEV */
185         double ac=course + 0.25*r;
186         double angle = (15.0-ac)*0.5235988;
187         double bullseye = (15.0 - course)*0.5235988;
188         double deltax=-sin(angle), deltay=cos(angle), x=inx, y=iny, bigger;
189         double ang, temp, xx, yy, kp, h1;
190
191         bigger = fabs(deltax);
192         if (fabs(deltay) > bigger) bigger = fabs(deltay);
193         deltax /= bigger;
194         deltay /= bigger;
195 #ifdef SERGEEV
196         crx=wherex();
197         cry=wherey();
198         if (game.damage[DSRSENS]==0 || condit==IHDOCKED) setwnd(1);
199         else setwnd(4);
200 #endif /* SERGEEV */
201         /* Loop to move a single torpedo */
202         for (l=1; l <= 15; l++) {
203                 x += deltax;
204                 ix = x + 0.5;
205                 if (ix < 1 || ix > 10) break;
206                 y += deltay;
207                 iy = y + 0.5;
208                 if (iy < 1 || iy > 10) break;
209 #ifndef SERGEEV
210                 if (l==4 || l==9) skip(1);
211                 proutn("%d - %d   ", (int)x, (int)y);
212                 iquad=game.quad[ix][iy];
213 #else
214                 iquad=game.quad[ix][iy];
215                 if (game.damage[DSRSENS]==0 || condit==IHDOCKED){
216                    drawmaps(2);
217                    delay((wait!=1)*400);
218                    wait=1;
219                    gotoxy(iy*2+3,ix+2);
220                    if ((game.quad[ix][iy]==IHDOT)||(game.quad[ix][iy]==IHBLANK)){
221                       game.quad[ix][iy]='+';
222                       drawmaps(2);
223                       game.quad[ix][iy]=iquad;
224                       sound(l*10);
225                       delay(100);
226                       nosound();
227                    }
228                    else {
229                         game.quad[ix][iy]|=128;
230                         drawmaps(2);
231                         game.quad[ix][iy]=iquad;
232                         _setcursortype(_NOCURSOR);
233                         sound(500);
234                         delay(1000);
235                         nosound();
236                         lowvideo();
237                         _setcursortype(_NORMALCURSOR);
238                    }
239                 }
240                 else {
241                   proutn("%d - %d   ", (int)x, (int)y);
242                 }
243 #endif /* SERGEEV */
244                 if (iquad==IHDOT) continue;
245                 /* hit something */
246 #ifndef SERGEEV
247                 skip(1);
248 #else
249                 setwnd(4);
250                 gotoxy(crx,cry);
251 #endif
252                 switch(iquad) {
253                         case IHE: /* Hit our ship */
254                         case IHF:
255                                 skip(1);
256                                 proutn("Torpedo hits ");
257                                 crmshp();
258                                 prout(".");
259                                 *hit = 700.0 + 100.0*Rand() -
260                                            1000.0*sqrt(square(ix-inx)+square(iy-iny))*
261                                            fabs(sin(bullseye-angle));
262                                 *hit = fabs(*hit);
263 #ifndef SERGEEV
264                                 newcnd(); /* undock */
265 #endif /* SERGEEV */
266                                 /* We may be displaced. */
267                                 if (landed==1 || condit==IHDOCKED) return; /* Cheat if on a planet */
268                                 ang = angle + 2.5*(Rand()-0.5);
269                                 temp = fabs(sin(ang));
270                                 if (fabs(cos(ang)) > temp) temp = fabs(cos(ang));
271                                 xx = -sin(ang)/temp;
272                                 yy = cos(ang)/temp;
273                                 jx=ix+xx+0.5;
274                                 jy=iy+yy+0.5;
275                                 if (jx<1 || jx>10 || jy<1 ||jy > 10) return;
276                                 if (game.quad[jx][jy]==IHBLANK) {
277                                         finish(FHOLE);
278                                         return;
279                                 }
280                                 if (game.quad[jx][jy]!=IHDOT) {
281                                         /* can't move into object */
282                                         return;
283                                 }
284                                 sectx = jx;
285                                 secty = jy;
286                                 crmshp();
287                                 shoved = 1;
288                                 break;
289                                           
290                         case IHC: /* Hit a commander */
291                         case IHS:
292                                 if (Rand() <= 0.05) {
293                                         crmena(1, iquad, 2, ix, iy);
294                                         prout(" uses anti-photon device;");
295                                         prout("   torpedo neutralized.");
296                                         return;
297                                 }
298                         case IHR: /* Hit a regular enemy */
299                         case IHK:
300                                 /* find the enemy */
301                                 for (ll=1; ll <= nenhere; ll++)
302                                         if (ix==game.kx[ll] && iy==game.ky[ll]) break;
303                                 kp = fabs(game.kpower[ll]);
304                                 h1 = 700.0 + 100.0*Rand() -
305                                          1000.0*sqrt(square(ix-inx)+square(iy-iny))*
306                                          fabs(sin(bullseye-angle));
307                                 h1 = fabs(h1);
308                                 if (kp < h1) h1 = kp;
309                                 game.kpower[ll] -= (game.kpower[ll]<0 ? -h1 : h1);
310                                 if (game.kpower[ll] == 0) {
311                                         deadkl(ix, iy, iquad, ix, iy);
312                                         return;
313                                 }
314                                 crmena(1, iquad, 2, ix, iy);
315                                 /* If enemy damaged but not destroyed, try to displace */
316                                 ang = angle + 2.5*(Rand()-0.5);
317                                 temp = fabs(sin(ang));
318                                 if (fabs(cos(ang)) > temp) temp = fabs(cos(ang));
319                                 xx = -sin(ang)/temp;
320                                 yy = cos(ang)/temp;
321                                 jx=ix+xx+0.5;
322                                 jy=iy+yy+0.5;
323                                 if (jx<1 || jx>10 || jy<1 ||jy > 10) {
324                                         prout(" damaged but not destroyed.");
325                                         return;
326                                 }
327                                 if (game.quad[jx][jy]==IHBLANK) {
328                                         prout(" buffeted into black hole.");
329                                         deadkl(ix, iy, iquad, jx, jy);
330                                         return;
331                                 }
332                                 if (game.quad[jx][jy]!=IHDOT) {
333                                         /* can't move into object */
334                                         prout(" damaged but not destroyed.");
335                                         return;
336                                 }
337                                 proutn(" damaged--");
338                                 game.kx[ll] = jx;
339                                 game.ky[ll] = jy;
340                                 shoved = 1;
341                                 break;
342                         case IHB: /* Hit a base */
343                                 skip(1);
344                                 prout("***STARBASE DESTROYED..");
345                                 if (game.starch[quadx][quady] < 0) game.starch[quadx][quady] = 0;
346                                 for (ll=1; ll<=game.state.rembase; ll++) {
347                                         if (game.state.baseqx[ll]==quadx && game.state.baseqy[ll]==quady) {
348                                                 game.state.baseqx[ll]=game.state.baseqx[game.state.rembase];
349                                                 game.state.baseqy[ll]=game.state.baseqy[game.state.rembase];
350                                                 break;
351                                         }
352                                 }
353                                 game.quad[ix][iy]=IHDOT;
354                                 game.state.rembase--;
355                                 basex=basey=0;
356                                 game.state.galaxy[quadx][quady] -= 10;
357                                 game.state.basekl++;
358                                 newcnd();
359                                 return;
360                         case IHP: /* Hit a planet */
361                                 crmena(1, iquad, 2, ix, iy);
362                                 prout(" destroyed.");
363                                 game.state.nplankl++;
364                                 game.state.newstuf[quadx][quady] -= 1;
365                                 DESTROY(&game.state.plnets[iplnet]);
366                                 iplnet = 0;
367                                 plnetx = plnety = 0;
368                                 game.quad[ix][iy] = IHDOT;
369                                 if (landed==1) {
370                                         /* captain parishes on planet */
371                                         finish(FDPLANET);
372                                 }
373                                 return;
374                         case IHSTAR: /* Hit a star */
375                                 if (Rand() > 0.10) {
376                                         nova(ix, iy);
377                                         return;
378                                 }
379                                 crmena(1, IHSTAR, 2, ix, iy);
380                                 prout(" unaffected by photon blast.");
381                                 return;
382                         case IHQUEST: /* Hit a thingy */
383                             if (Rand()>0.7) {   // Used to be certain death 
384                                 skip(1);
385                                 prouts("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!");
386                                 skip(1);
387                                 prouts("    HACK!     HACK!    HACK!        *CHOKE!*  ");
388                                 skip(1);
389                                 proutn("Mr. Spock-");
390                                 prouts("  \"Fascinating!\"");
391                                 skip(1);
392                                 deadkl(ix, iy, iquad, ix, iy);
393                             } else {
394                                 /*
395                                  * Stas Sergeev added the possibility that
396                                  * you can shove the Thingy.
397                                  */
398                                 iqengry=1;
399                                 shoved=1;
400                             }
401                             return;
402                         case IHBLANK: /* Black hole */
403                                 skip(1);
404                                 crmena(1, IHBLANK, 2, ix, iy);
405                                 prout(" swallows torpedo.");
406                                 return;
407                         case IHWEB: /* hit the web */
408                                 skip(1);
409                                 prout("***Torpedo absorbed by Tholian web.");
410                                 return;
411                         case IHT:  /* Hit a Tholian */
412                                 h1 = 700.0 + 100.0*Rand() -
413                                          1000.0*sqrt(square(ix-inx)+square(iy-iny))*
414                                          fabs(sin(bullseye-angle));
415                                 h1 = fabs(h1);
416                                 if (h1 >= 600) {
417 #ifndef SERGEEV
418                                         prout(" destroyed.");
419 #endif /* SERGEEV */
420                                         game.quad[ix][iy] = IHDOT;
421                                         ithere = 0;
422                                         ithx = ithy = 0;
423 #ifdef SERGEEV
424                                         deadkl(ix, iy, iquad, ix, iy);
425 #endif /* SERGEEV */
426                                         return;
427                                 }
428                                 skip(1);
429                                 crmena(1, IHT, 2, ix, iy);
430                                 if (Rand() > 0.05) {
431                                         prout(" survives photon blast.");
432                                         return;
433                                 }
434                                 prout(" disappears.");
435                                 game.quad[ix][iy] = IHWEB;
436                                 ithere = ithx = ithy = 0;
437                                 nenhere--;
438                                 {
439                                         int dum, my;
440                                         dropin(IHBLANK, &dum, &my);
441                                 }
442                                 return;
443                                         
444                         default: /* Problem! */
445                                 skip(1);
446                                 proutn("Don't know how to handle collision with ");
447                                 crmena(1, iquad, 2, ix, iy);
448                                 skip(1);
449                                 return;
450                 }
451                 break;
452         }
453 #ifdef SERGEEV
454         if(curwnd!=4) {
455             setwnd(4);
456             gotoxy(crx,cry);
457         }
458 #endif /* SERGEEV */
459         if (shoved) {
460                 game.quad[jx][jy]=iquad;
461                 game.quad[ix][iy]=IHDOT;
462                 prout(" displaced by blast to %s ", cramlc(sector, jx, jy));
463                 for (ll=1; ll<=nenhere; ll++)
464                         game.kdist[ll] = game.kavgd[ll] = sqrt(square(sectx-game.kx[ll])+square(secty-game.ky[ll]));
465                 sortkl();
466                 return;
467         }
468 #ifndef SERGEEV
469         skip(1);
470 #endif /* SERGEEV */
471         prout("Torpedo missed.");
472         return;
473 }
474
475 static void fry(double hit) {
476         double ncrit, extradm;
477         int ktr=1, l, ll, j, cdam[NDEVICES+1];
478
479         /* a critical hit occured */
480         if (hit < (275.0-25.0*skill)*(1.0+0.5*Rand())) return;
481
482         ncrit = 1.0 + hit/(500.0+100.0*Rand());
483         proutn("***CRITICAL HIT--");
484         /* Select devices and cause damage */
485         for (l = 1; l <= ncrit && l <= NDEVICES; l++) {
486                 do {
487                         j = NDEVICES*Rand()+1.0;
488                         /* Cheat to prevent shuttle damage unless on ship */
489                 } while (game.damage[j] < 0.0 || (j == DSHUTTL && iscraft != 1) ||
490                                  j == DDRAY);
491                 cdam[l] = j;
492                 extradm = (hit*damfac)/(ncrit*(75.0+25.0*Rand()));
493                 game.damage[j] += extradm;
494                 if (l > 1) {
495                         for (ll=2; ll<=l && j != cdam[ll-1]; ll++) ;
496                         if (ll<=l) continue;
497                         ktr += 1;
498                         if (ktr==3) skip(1);
499                         proutn(" and ");
500                 }
501                 proutn(device[j]);
502         }
503         prout(" damaged.");
504         if (game.damage[DSHIELD] && shldup) {
505                 prout("***Shields knocked down.");
506                 shldup=0;
507         }
508 }
509
510 void attack(int k) {
511         /* k == 0 forces use of phasers in an attack */
512         int percent, ihurt=0, l, i=0, jx, jy, iquad, itflag;
513         int atackd = 0, attempt = 0;
514         double hit;
515         double pfac, dustfac, hitmax=0.0, hittot=0.0, chgfac=1.0, r;
516
517         iattak = 1;
518         if (alldone) return;
519 #ifdef DEBUG
520         if (idebug) prout("ATTACK!");
521 #endif
522
523         if (ithere) movetho();
524
525         if (neutz) { /* The one chance not to be attacked */
526                 neutz = 0;
527                 return;
528         }
529         if ((((comhere || ishere) && (justin == 0)) || skill == 5)&&(k!=0)) movcom();
530         if (nenhere==0 || (nenhere==1 && iqhere && iqengry==0)) return;
531         pfac = 1.0/inshld;
532         if (shldchg == 1) chgfac = 0.25+0.5*Rand();
533         skip(1);
534         if (skill <= 2) i = 2;
535         for (l=1; l <= nenhere; l++) {
536                 if (game.kpower[l] < 0) continue;       /* too weak to attack */
537                 /* compute hit strength and diminsh shield power */
538                 r = Rand();
539                 /* Increase chance of photon torpedos if docked or enemy energy low */
540                 if (condit == IHDOCKED) r *= 0.25;
541                 if (game.kpower[l] < 500) r *= 0.25; 
542                 jx = game.kx[l];
543                 jy = game.ky[l];
544                 iquad = game.quad[jx][jy];
545                 if (iquad==IHT || (iquad==IHQUEST && !iqengry)) continue;
546                 itflag = (iquad == IHK && r > 0.0005) || k == 0 ||
547                         (iquad==IHC && r > 0.015) ||
548                         (iquad==IHR && r > 0.3) ||
549                         (iquad==IHS && r > 0.07) ||
550                         (iquad==IHQUEST && r > 0.05);
551                 if (itflag) {
552                         /* Enemy uses phasers */
553                         if (condit == IHDOCKED) continue; /* Don't waste the effort! */
554                         attempt = 1; /* Attempt to attack */
555                         dustfac = 0.8+0.05*Rand();
556                         hit = game.kpower[l]*pow(dustfac,game.kavgd[l]);
557                         game.kpower[l] *= 0.75;
558                 }
559                 else { /* Enemy used photon torpedo */
560                         double course = 1.90985*atan2((double)secty-jy, (double)jx-sectx);
561                         hit = 0;
562                         proutn("***TORPEDO INCOMING");
563                         if (game.damage[DSRSENS] <= 0.0) {
564                                 proutn(" From ");
565                                 crmena(0, iquad, i, jx, jy);
566                         }
567                         attempt = 1;
568                         prout("  ");
569                         r = (Rand()+Rand())*0.5 -0.5;
570                         r += 0.002*game.kpower[l]*r;
571                         torpedo(course, r, jx, jy, &hit, 0);
572                         if (game.state.remkl==0) finish(FWON); /* Klingons did themselves in! */
573                         if (game.state.galaxy[quadx][quady] == 1000 ||
574                                 alldone) return; /* Supernova or finished */
575                         if (hit == 0) continue;
576                 }
577                 if (shldup != 0 || shldchg != 0 || condit==IHDOCKED) {
578                         /* shields will take hits */
579                         double absorb, hitsh, propor = pfac*shield*(condit==IHDOCKED ? 2.1 : 1.0);
580                         if(propor < 0.1) propor = 0.1;
581                         hitsh = propor*chgfac*hit+1.0;
582                         atackd=1;
583                         absorb = 0.8*hitsh;
584                         if (absorb > shield) absorb = shield;
585                         shield -= absorb;
586                         hit -= hitsh;
587                         if (condit==IHDOCKED) dock(0);
588                         if (propor > 0.1 && hit < 0.005*energy) continue;
589                 }
590                 /* It's a hit -- print out hit size */
591                 atackd = 1; /* We weren't going to check casualties, etc. if
592                                shields were down for some strange reason. This
593                                            doesn't make any sense, so I've fixed it */
594                 ihurt = 1;
595                 proutn("%d unit hit", (int)hit);
596                 if ((game.damage[DSRSENS] > 0 && itflag) || skill <= 2) {
597                         proutn(" on the ");
598                         crmshp();
599                 }
600                 if (game.damage[DSRSENS] <= 0.0 && itflag) {
601                         proutn(" from ");
602                         crmena(0, iquad, i, jx, jy);
603                 }
604                 skip(1);
605                 /* Decide if hit is critical */
606                 if (hit > hitmax) hitmax = hit;
607                 hittot += hit;
608                 fry(hit);
609                 prout("Hit %g energy %g", hit, energy);
610                 energy -= hit;
611                 if (condit==IHDOCKED) dock(0);
612         }
613         if (energy <= 0) {
614                 /* Returning home upon your shield, not with it... */
615                 finish(FBATTLE);
616                 return;
617         }
618         if (attempt == 0 && condit == IHDOCKED)
619                 prout("***Enemies decide against attacking your ship.");
620         if (atackd == 0) return;
621         percent = 100.0*pfac*shield+0.5;
622         if (ihurt==0) {
623                 /* Shields fully protect ship */
624                 proutn("Enemy attack reduces shield strength to ");
625         }
626         else {
627                 /* Print message if starship suffered hit(s) */
628                 skip(1);
629                 proutn("Energy left %2d    shields ", (int)energy);
630                 if (shldup) proutn("up ");
631                 else if (game.damage[DSHIELD] == 0) proutn("down ");
632                 else proutn("damaged, ");
633         }
634         prout("%d%%,   torpedoes left %d", percent, torps);
635         /* Check if anyone was hurt */
636         if (hitmax >= 200 || hittot >= 500) {
637                 int icas= hittot*Rand()*0.015;
638                 if (icas >= 2) {
639                         skip(1);
640                         prout("Mc Coy-  \"Sickbay to bridge.  We suffered %d casualties", icas);
641                         prout("   in that last attack.\"");
642                         casual += icas;
643                 }
644         }
645         /* After attack, reset average distance to enemies */
646         for (l = 1; l <= nenhere; l++)
647                 game.kavgd[l] = game.kdist[l];
648         sortkl();
649         return;
650 }
651                 
652 void deadkl(int ix, int iy, int type, int ixx, int iyy) {
653         /* Added ixx and iyy allow enemy to "move" before dying */
654
655         int i,j;
656
657 #ifdef SERGEEV  
658         skip(1);
659 #endif /* SERGEEV */
660         crmena(1, type, 2, ixx, iyy);
661         /* Decide what kind of enemy it is and update approriately */
662         if (type == IHR) {
663                 /* chalk up a Romulan */
664                 game.state.newstuf[quadx][quady] -= 10;
665                 irhere--;
666                 game.state.nromkl++;
667                 game.state.nromrem--;
668         }
669         else if (type == IHT) {
670                 /* Killed a Tholian */
671                 ithere = 0;
672         }
673         else if (type == IHQUEST) {
674                 /* Killed a Thingy */
675              iqhere=iqengry=thingx=thingy=0;
676         }
677         else {
678                 /* Some type of a Klingon */
679                 game.state.galaxy[quadx][quady] -= 100;
680                 klhere--;
681                 game.state.remkl--;
682                 switch (type) {
683                         case IHC:
684                                 comhere = 0;
685                                 for (i=1; i<=game.state.remcom; i++)
686                                         if (game.state.cx[i]==quadx && game.state.cy[i]==quady) break;
687                                 game.state.cx[i] = game.state.cx[game.state.remcom];
688                                 game.state.cy[i] = game.state.cy[game.state.remcom];
689                                 game.state.cx[game.state.remcom] = 0;
690                                 game.state.cy[game.state.remcom] = 0;
691                                 game.state.remcom--;
692                                 game.future[FTBEAM] = 1e30;
693                                 if (game.state.remcom != 0)
694                                         game.future[FTBEAM] = game.state.date + expran(1.0*incom/game.state.remcom);
695                                 game.state.killc++;
696                                 break;
697                         case IHK:
698                                 game.state.killk++;
699                                 break;
700                         case IHS:
701                                 game.state.nscrem = ishere = game.state.isx = game.state.isy = isatb = iscate = 0;
702                                 game.state.nsckill = 1;
703                                 game.future[FSCMOVE] = game.future[FSCDBAS] = 1e30;
704                                 break;
705                 }
706         }
707
708         /* For each kind of enemy, finish message to player */
709         prout(" destroyed.");
710         game.quad[ix][iy] = IHDOT;
711         if (game.state.remkl==0) return;
712
713         game.state.remtime = game.state.remres/(game.state.remkl + 4*game.state.remcom);
714
715         /* Remove enemy ship from arrays describing local conditions */
716         if (game.future[FCDBAS] < 1e30 && batx==quadx && baty==quady && type==IHC)
717             game.future[FCDBAS] = 1e30;
718         for (i=1; i<=nenhere; i++)
719                 if (game.kx[i]==ix && game.ky[i]==iy) break;
720         nenhere--;
721         if (i <= nenhere)  {
722                 for (j=i; j<=nenhere; j++) {
723                         game.kx[j] = game.kx[j+1];
724                         game.ky[j] = game.ky[j+1];
725                         game.kpower[j] = game.kpower[j+1];
726                         game.kavgd[j] = game.kdist[j] = game.kdist[j+1];
727                 }
728         }
729         game.kx[nenhere+1] = 0;
730         game.ky[nenhere+1] = 0;
731         game.kdist[nenhere+1] = 0;
732         game.kavgd[nenhere+1] = 0;
733         game.kpower[nenhere+1] = 0;
734         return;
735 }
736
737 static int targetcheck(double x, double y, double *course) {
738         double deltx, delty;
739         /* Return TRUE if target is invalid */
740         if (x < 1.0 || x > 10.0 || y < 1.0 || y > 10.0) {
741                 huh();
742                 return 1;
743         }
744         deltx = 0.1*(y - secty);
745         delty = 0.1*(sectx - x);
746         if (deltx==0 && delty== 0) {
747                 skip(1);
748                 prout("Spock-  \"Bridge to sickbay.  Dr. McCoy,");
749                 prout("  I recommend an immediate review of");
750                 prout("  the Captain's psychological profile.\"");
751                 chew();
752                 return 1;
753         }
754         *course = 1.90985932*atan2(deltx, delty);
755         return 0;
756 }
757
758 void photon(void) {
759         double targ[4][3], course[4];
760         double r, dummy;
761         int key, n, i, osuabor;
762
763         ididit = 0;
764
765         if (game.damage[DPHOTON]) {
766                 prout("Photon tubes damaged.");
767                 chew();
768                 return;
769         }
770         if (torps == 0) {
771                 prout("No torpedoes left.");
772                 chew();
773                 return;
774         }
775         key = scan();
776         for (;;) {
777                 if (key == IHALPHA) {
778                         huh();
779                         return;
780                 }
781                 else if (key == IHEOL) {
782                         prout("%d torpedoes left.", torps);
783                         proutn("Number of torpedoes to fire- ");
784                         key = scan();
785                 }
786                 else /* key == IHREAL */ {
787                         n = aaitem + 0.5;
788                         if (n <= 0) { /* abort command */
789                                 chew();
790                                 return;
791                         }
792                         if (n > 3) {
793                                 chew();
794                                 prout("Maximum of 3 torpedoes per burst.");
795                                 key = IHEOL;
796                                 return;
797                         }
798                         if (n <= torps) break;
799                         chew();
800                         key = IHEOL;
801                 }
802         }
803         for (i = 1; i <= n; i++) {
804                 key = scan();
805                 if (i==1 && key == IHEOL) {
806                         break;  /* we will try prompting */
807                 }
808                 if (i==2 && key == IHEOL) {
809                         /* direct all torpedoes at one target */
810                         while (i <= n) {
811                                 targ[i][1] = targ[1][1];
812                                 targ[i][2] = targ[1][2];
813                                 course[i] = course[1];
814                                 i++;
815                         }
816                         break;
817                 }
818                 if (key != IHREAL) {
819                         huh();
820                         return;
821                 }
822                 targ[i][1] = aaitem;
823                 key = scan();
824                 if (key != IHREAL) {
825                         huh();
826                         return;
827                 }
828                 targ[i][2] = aaitem;
829                 if (targetcheck(targ[i][1], targ[i][2], &course[i])) return;
830         }
831         chew();
832         if (i == 1 && key == IHEOL) {
833                 /* prompt for each one */
834                 for (i = 1; i <= n; i++) {
835                     proutn("Target sector for torpedo number %d- ", i);
836                         key = scan();
837                         if (key != IHREAL) {
838                                 huh();
839                                 return;
840                         }
841                         targ[i][1] = aaitem;
842                         key = scan();
843                         if (key != IHREAL) {
844                                 huh();
845                                 return;
846                         }
847                         targ[i][2] = aaitem;
848                         chew();
849                         if (targetcheck(targ[i][1], targ[i][2], &course[i])) return;
850                 }
851         }
852         ididit = 1;
853         /* Loop for moving <n> torpedoes */
854         osuabor = 0;
855         for (i = 1; i <= n && !osuabor; i++) {
856                 if (condit != IHDOCKED) torps--;
857                 r = (Rand()+Rand())*0.5 -0.5;
858                 if (fabs(r) >= 0.47) {
859                         /* misfire! */
860                         r = (Rand()+1.2) * r;
861                         if (n>1) {
862                             prouts("***TORPEDO NUMBER %d MISFIRES", i);
863                         }
864                         else prouts("***TORPEDO MISFIRES.");
865                         skip(1);
866                         if (i < n)
867                                 prout("  Remainder of burst aborted.");
868                         osuabor=1;
869                         if (Rand() <= 0.2) {
870                                 prout("***Photon tubes damaged by misfire.");
871                                 game.damage[DPHOTON] = damfac*(1.0+2.0*Rand());
872                                 break;
873                         }
874                 }
875                 if (shldup || condit == IHDOCKED) r *= 1.0 + 0.0001*shield;
876 #ifndef SERGEEV
877                 if (n != 1) {
878                         skip(1);
879                         proutn("Track for torpedo number %d-  ", i);
880                 }
881                 else {
882                         skip(1);
883                         proutn("Torpedo track- ");
884                 }
885 #endif /* SERGEEV */
886                 torpedo(course[i], r, sectx, secty, &dummy, i);
887                 if (alldone || game.state.galaxy[quadx][quady]==1000) return;
888         }
889         if (game.state.remkl==0) finish(FWON);
890 }
891
892         
893
894 static void overheat(double rpow) {
895         if (rpow > 1500) {
896                 double chekbrn = (rpow-1500.)*0.00038;
897                 if (Rand() <= chekbrn) {
898                         prout("Weapons officer Sulu-  \"Phasers overheated, sir.\"");
899                         game.damage[DPHASER] = damfac*(1.0 + Rand()) * (1.0+chekbrn);
900                 }
901         }
902 }
903
904 static int checkshctrl(double rpow) {
905         double hit;
906         int icas;
907         
908         skip(1);
909         if (Rand() < .998) {
910                 prout("Shields lowered.");
911                 return 0;
912         }
913         /* Something bad has happened */
914         prouts("***RED ALERT!  RED ALERT!");
915         skip(2);
916         hit = rpow*shield/inshld;
917         energy -= rpow+hit*0.8;
918         shield -= hit*0.2;
919         if (energy <= 0.0) {
920                 prouts("Sulu-  \"Captain! Shield malf***********************\"");
921                 skip(1);
922                 stars();
923                 finish(FPHASER);
924                 return 1;
925         }
926         prouts("Sulu-  \"Captain! Shield malfunction! Phaser fire contained!\"");
927         skip(2);
928         prout("Lt. Uhura-  \"Sir, all decks reporting damage.\"");
929         icas = hit*Rand()*0.012;
930         skip(1);
931         fry(0.8*hit);
932         if (icas) {
933                 skip(1);
934                 prout("McCoy to bridge- \"Severe radiation burns, Jim.");
935                 prout("  %d casualties so far.\"", icas);
936                 casual -= icas;
937         }
938         skip(1);
939         prout("Phaser energy dispersed by shields.");
940         prout("Enemy unaffected.");
941         overheat(rpow);
942         return 1;
943 }
944         
945
946 void phasers(void) {
947         double hits[21], rpow=0, extra, powrem, over, temp;
948         int kz = 0, k=1, i, irec=0; /* Cheating inhibitor */
949         int ifast=0, no=0, ipoop=1, msgflag = 1;
950         enum {NOTSET, MANUAL, FORCEMAN, AUTOMATIC} automode = NOTSET;
951         int key=0;
952
953         skip(1);
954         /* SR sensors and Computer */
955         if (game.damage[DSRSENS]+game.damage[DCOMPTR] > 0) ipoop = 0;
956         if (condit == IHDOCKED) {
957                 prout("Phasers can't be fired through base shields.");
958                 chew();
959                 return;
960         }
961         if (game.damage[DPHASER] != 0) {
962                 prout("Phaser control damaged.");
963                 chew();
964                 return;
965         }
966         if (shldup) {
967                 if (game.damage[DSHCTRL]) {
968                         prout("High speed shield control damaged.");
969                         chew();
970                         return;
971                 }
972                 if (energy <= 200.0) {
973                         prout("Insufficient energy to activate high-speed shield control.");
974                         chew();
975                         return;
976                 }
977                 prout("Weapons Officer Sulu-  \"High-speed shield control enabled, sir.\"");
978                 ifast = 1;
979                 
980         }
981         /* Original code so convoluted, I re-did it all */
982         while (automode==NOTSET) {
983                 key=scan();
984                 if (key == IHALPHA) {
985                         if (isit("manual")) {
986                                 if (nenhere==0) {
987                                         prout("There is no enemy present to select.");
988                                         chew();
989                                         key = IHEOL;
990                                         automode=AUTOMATIC;
991                                 }
992                                 else {
993                                         automode = MANUAL;
994                                         key = scan();
995                                 }
996                         }
997                         else if (isit("automatic")) {
998                                 if ((!ipoop) && nenhere != 0) {
999                                         automode = FORCEMAN;
1000                                 }
1001                                 else {
1002                                         if (nenhere==0)
1003                                                 prout("Energy will be expended into space.");
1004                                         automode = AUTOMATIC;
1005                                         key = scan();
1006                                 }
1007                         }
1008                         else if (isit("no")) {
1009                                 no = 1;
1010                         }
1011                         else {
1012                                 huh();
1013                                 return;
1014                         }
1015                 }
1016                 else if (key == IHREAL) {
1017                         if (nenhere==0) {
1018                                 prout("Energy will be expended into space.");
1019                                 automode = AUTOMATIC;
1020                         }
1021                         else if (!ipoop)
1022                                 automode = FORCEMAN;
1023                         else
1024                                 automode = AUTOMATIC;
1025                 }
1026                 else {
1027                         /* IHEOL */
1028                         if (nenhere==0) {
1029                                 prout("Energy will be expended into space.");
1030                                 automode = AUTOMATIC;
1031                         }
1032                         else if (!ipoop)
1033                                 automode = FORCEMAN;
1034                         else 
1035                         proutn("Manual or automatic? ");
1036                 }
1037         }
1038                                 
1039         switch (automode) {
1040                 case AUTOMATIC:
1041                         if (key == IHALPHA && isit("no")) {
1042                                 no = 1;
1043                                 key = scan();
1044                         }
1045                         if (key != IHREAL && nenhere != 0) {
1046                                 prout("Phasers locked on target. Energy available: %.2f",
1047                                     ifast?energy-200.0:energy,1,2);
1048                         }
1049                         irec=0;
1050                         do {
1051                                         chew();
1052                                         if (!kz) for (i = 1; i <= nenhere; i++)
1053                                                      irec+=fabs(game.kpower[i])/(PHASEFAC*pow(0.90,game.kdist[i]))*
1054                                                      (1.01+0.05*Rand()) + 1.0;
1055                                         kz=1;
1056                                         proutn("(%d) units required. ", irec);
1057                                         chew();
1058                                         proutn("Units to fire= ");
1059                                         key = scan();
1060                                         if (key!=IHREAL) return;
1061                                         rpow = aaitem;
1062                                         if (rpow > (ifast?energy-200:energy)) {
1063                                             proutn("Energy available= %.2f",
1064                                             ifast?energy-200:energy);
1065                                         skip(1);
1066                                         key = IHEOL;
1067                                 }
1068                         } while (rpow > (ifast?energy-200:energy));
1069                         if (rpow<=0) {
1070                                 /* chicken out */
1071                                 chew();
1072                                 return;
1073                         }
1074                         if ((key=scan()) == IHALPHA && isit("no")) {
1075                                 no = 1;
1076                         }
1077                         if (ifast) {
1078                                 energy -= 200; /* Go and do it! */
1079                                 if (checkshctrl(rpow)) return;
1080                         }
1081                         chew();
1082                         energy -= rpow;
1083                         extra = rpow;
1084                         if (nenhere) {
1085                                 extra = 0.0;
1086                                 powrem = rpow;
1087                                 for (i = 1; i <= nenhere; i++) {
1088                                         hits[i] = 0.0;
1089                                         if (powrem <= 0) continue;
1090                                         hits[i] = fabs(game.kpower[i])/(PHASEFAC*pow(0.90,game.kdist[i]));
1091                                         over = (0.01 + 0.05*Rand())*hits[i];
1092                                         temp = powrem;
1093                                         powrem -= hits[i] + over;
1094                                         if (powrem <= 0 && temp < hits[i]) hits[i] = temp;
1095                                         if (powrem <= 0) over = 0.0;
1096                                         extra += over;
1097                                 }
1098                                 if (powrem > 0.0) extra += powrem;
1099                                 hittem(hits);
1100                                 ididit=1;
1101                         }
1102                         if (extra > 0 && alldone == 0) {
1103                                 if (ithere) {
1104                                         proutn("*** Tholian web absorbs ");
1105                                         if (nenhere>0) proutn("excess ");
1106                                         prout("phaser energy.");
1107                                 }
1108                                 else {
1109                                         prout("%d expended on empty space.", (int)extra);
1110                                 }
1111                         }
1112                         break;
1113
1114                 case FORCEMAN:
1115                         chew();
1116                         key = IHEOL;
1117                         if (game.damage[DCOMPTR]!=0)
1118                                 prout("Battle comuter damaged, manual file only.");
1119                         else {
1120                                 skip(1);
1121                                 prouts("---WORKING---");
1122                                 skip(1);
1123                                 prout("Short-range-sensors-damaged");
1124                                 prout("Insufficient-data-for-automatic-phaser-fire");
1125                                 prout("Manual-fire-must-be-used");
1126                                 skip(1);
1127                         }
1128                 case MANUAL:
1129                         rpow = 0.0;
1130                         for (k = 1; k <= nenhere;) {
1131                                 int ii = game.kx[k], jj = game.ky[k];
1132                                 int ienm = game.quad[ii][jj];
1133                                 if (msgflag) {
1134                                         proutn("Energy available= %.2f",
1135                                                energy-.006-(ifast?200:0));
1136                                         skip(1);
1137                                         msgflag = 0;
1138                                         rpow = 0.0;
1139                                 }
1140                                 if (game.damage[DSRSENS] && !(abs(sectx-ii) < 2 && abs(secty-jj) < 2) &&
1141                                         (ienm == IHC || ienm == IHS)) {
1142                                         cramen(ienm);
1143                                         prout(" can't be located without short range scan.");
1144                                         chew();
1145                                         key = IHEOL;
1146                                         hits[k] = 0; /* prevent overflow -- thanks to Alexei Voitenko */
1147                                         k++;
1148                                         continue;
1149                                 }
1150                                 if (key == IHEOL) {
1151                                         chew();
1152                                         if (ipoop && k > kz)
1153                                                 irec=(fabs(game.kpower[k])/(PHASEFAC*pow(0.9,game.kdist[k])))*
1154                                                                  (1.01+0.05*Rand()) + 1.0;
1155                                         kz = k;
1156                                         proutn("(");
1157                                         if (game.damage[DCOMPTR]==0) proutn("%d", irec);
1158                                         else proutn("??");
1159                                         proutn(")  ");
1160                                         proutn("units to fire at ");
1161                                         crmena(0, ienm, 2, ii, jj);
1162                                         proutn("-  ");
1163                                         key = scan();
1164                                 }
1165                                 if (key == IHALPHA && isit("no")) {
1166                                         no = 1;
1167                                         key = scan();
1168                                         continue;
1169                                         }
1170                                 if (key == IHALPHA) {
1171                                         huh();
1172                                         return;
1173                                 }
1174                                 if (key == IHEOL) {
1175                                         if (k==1) { /* Let me say I'm baffled by this */
1176                                                 msgflag = 1;
1177                                         }
1178                                         continue;
1179                                 }
1180                                 if (aaitem < 0) {
1181                                         /* abort out */
1182                                         chew();
1183                                         return;
1184                                 }
1185                                 hits[k] = aaitem;
1186                                 rpow += aaitem;
1187                                 /* If total requested is too much, inform and start over */
1188                                 
1189                                 if (rpow > (ifast?energy-200:energy)) {
1190                                         prout("Available energy exceeded -- try again.");
1191                                         chew();
1192                                         return;
1193                                 }
1194                                 key = scan(); /* scan for next value */
1195                                 k++;
1196                         }
1197                         if (rpow == 0.0) {
1198                                 /* zero energy -- abort */
1199                                 chew();
1200                                 return;
1201                         }
1202                         if (key == IHALPHA && isit("no")) {
1203                                 no = 1;
1204                         }
1205                         energy -= rpow;
1206                         chew();
1207                         if (ifast) {
1208                                 energy -= 200.0;
1209                                 if (checkshctrl(rpow)) return;
1210                         }
1211                         hittem(hits);
1212                         ididit=1;
1213                 case NOTSET:;   /* avoid gcc warning */
1214         }
1215         /* Say shield raised or malfunction, if necessary */
1216         if (alldone) return;
1217         if (ifast) {
1218                 skip(1);
1219                 if (no == 0) {
1220                         if (Rand() >= 0.99) {
1221                                 prout("Sulu-  \"Sir, the high-speed shield control has malfunctioned . . .");
1222                                 prouts("         CLICK   CLICK   POP  . . .");
1223                                 prout(" No  response, sir!");
1224                                 shldup = 0;
1225                         }
1226                         else
1227                                 prout("Shields raised.");
1228                 }
1229                 else
1230                         shldup = 0;
1231         }
1232         overheat(rpow);
1233 }
1234
1235 void hittem(double *hits) {
1236         double kp, kpow, wham, hit, dustfac, kpini;
1237 #ifdef SERGEEV
1238         int cx, cy;
1239 #endif /* SERGEEV */
1240         int nenhr2=nenhere, k=1, kk=1, ii, jj, ienm;
1241
1242         skip(1);
1243
1244         for (; k <= nenhr2; k++, kk++) {
1245                 if ((wham = hits[k])==0) continue;
1246                 dustfac = 0.9 + 0.01*Rand();
1247                 hit = wham*pow(dustfac,game.kdist[kk]);
1248                 kpini = game.kpower[kk];
1249                 kp = fabs(kpini);
1250                 if (PHASEFAC*hit < kp) kp = PHASEFAC*hit;
1251                 game.kpower[kk] -= (game.kpower[kk] < 0 ? -kp: kp);
1252                 kpow = game.kpower[kk];
1253                 ii = game.kx[kk];
1254                 jj = game.ky[kk];
1255                 if (hit > 0.005) {
1256 #ifdef SERGEEV
1257                         if (game.damage[DSRSENS]==0){
1258                            crx=wherex();
1259                            cry=wherey();
1260                            setwnd(1);
1261                            drawmaps(2);
1262                            gotoxy(jj*2+3,ii+2);
1263                            highvideo();
1264                            proutn("%c", game.quad[ii][jj]);
1265                            gotoxy(wherex()-1,wherey());
1266                            sound(500);
1267                            delay(1000);
1268                            nosound();
1269                            lowvideo();
1270                            proutn("%c", game.quad[ii][jj]);
1271                            setwnd(4);
1272                            gotoxy(crx,cry);
1273                            _setcursortype(_NORMALCURSOR);
1274                            delay(500);
1275                         }
1276 #endif /* SERGEEV */
1277                         proutn("%d unit hit on ", (int)hit);
1278                 }
1279                 else
1280                         proutn("Very small hit on ");
1281                 ienm = game.quad[ii][jj];
1282                 if (ienm==IHQUEST) iqengry=1;
1283                 crmena(0,ienm,2,ii,jj);
1284                 skip(1);
1285                 if (kpow == 0) {
1286                         deadkl(ii, jj, ienm, ii, jj);
1287                         if (game.state.remkl==0) finish(FWON);
1288                         if (alldone) return;
1289                         kk--; /* don't do the increment */
1290                 }
1291                 else /* decide whether or not to emasculate klingon */
1292                         if (kpow > 0 && Rand() >= 0.9 &&
1293                                 kpow <= ((0.4 + 0.4*Rand())*kpini)) {
1294                                 prout("***Mr. Spock-  \"Captain, the vessel at ",
1295                                         cramlc(sector,ii,jj));
1296                                 prout("   has just lost its firepower.\"");
1297                                 game.kpower[kk] = -kpow;
1298                         }
1299         }
1300         return;
1301 }
1302