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