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