1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)phaser.c 5.1 (Berkeley) 1/29/86"; 9: #endif not lint 10: 11: # include "trek.h" 12: # include "getpar.h" 13: 14: /* factors for phaser hits; see description below */ 15: 16: # define ALPHA 3.0 /* spread */ 17: # define BETA 3.0 /* franf() */ 18: # define GAMMA 0.30 /* cos(angle) */ 19: # define EPSILON 150.0 /* dist ** 2 */ 20: # define OMEGA 10.596 /* overall scaling factor */ 21: 22: /* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */ 23: 24: /* 25: ** Phaser Control 26: ** 27: ** There are up to NBANKS phaser banks which may be fired 28: ** simultaneously. There are two modes, "manual" and 29: ** "automatic". In manual mode, you specify exactly which 30: ** direction you want each bank to be aimed, the number 31: ** of units to fire, and the spread angle. In automatic 32: ** mode, you give only the total number of units to fire. 33: ** 34: ** The spread is specified as a number between zero and 35: ** one, with zero being minimum spread and one being maximum 36: ** spread. You will normally want zero spread, unless your 37: ** short range scanners are out, in which case you probably 38: ** don't know exactly where the Klingons are. In that case, 39: ** you really don't have any choice except to specify a 40: ** fairly large spread. 41: ** 42: ** Phasers spread slightly, even if you specify zero spread. 43: ** 44: ** Uses trace flag 30 45: */ 46: 47: struct cvntab Matab[] = 48: { 49: "m", "anual", (int (*)())1, 0, 50: "a", "utomatic", 0, 0, 51: 0 52: }; 53: 54: struct banks 55: { 56: int units; 57: double angle; 58: double spread; 59: }; 60: 61: 62: 63: phaser() 64: { 65: register int i; 66: int j; 67: register struct kling *k; 68: double dx, dy; 69: double anglefactor, distfactor; 70: register struct banks *b; 71: int manual, flag, extra; 72: int hit; 73: double tot; 74: int n; 75: int hitreqd[NBANKS]; 76: struct banks bank[NBANKS]; 77: struct cvntab *ptr; 78: 79: if (Ship.cond == DOCKED) 80: return(printf("Phasers cannot fire through starbase shields\n")); 81: if (damaged(PHASER)) 82: return (out(PHASER)); 83: if (Ship.shldup) 84: return (printf("Sulu: Captain, we cannot fire through shields.\n")); 85: if (Ship.cloaked) 86: { 87: printf("Sulu: Captain, surely you must realize that we cannot fire\n"); 88: printf(" phasers with the cloaking device up.\n"); 89: return; 90: } 91: 92: /* decide if we want manual or automatic mode */ 93: manual = 0; 94: if (testnl()) 95: { 96: if (damaged(COMPUTER)) 97: { 98: printf(Device[COMPUTER].name); 99: manual++; 100: } 101: else 102: if (damaged(SRSCAN)) 103: { 104: printf(Device[SRSCAN].name); 105: manual++; 106: } 107: if (manual) 108: printf(" damaged, manual mode selected\n"); 109: } 110: 111: if (!manual) 112: { 113: ptr = getcodpar("Manual or automatic", Matab); 114: manual = (int) ptr->value; 115: } 116: if (!manual && damaged(COMPUTER)) 117: { 118: printf("Computer damaged, manual selected\n"); 119: skiptonl(0); 120: manual++; 121: } 122: 123: /* initialize the bank[] array */ 124: flag = 1; 125: for (i = 0; i < NBANKS; i++) 126: bank[i].units = 0; 127: if (manual) 128: { 129: /* collect manual mode statistics */ 130: while (flag) 131: { 132: printf("%d units available\n", Ship.energy); 133: extra = 0; 134: flag = 0; 135: for (i = 0; i < NBANKS; i++) 136: { 137: b = &bank[i]; 138: printf("\nBank %d:\n", i); 139: hit = getintpar("units"); 140: if (hit < 0) 141: return; 142: if (hit == 0) 143: break; 144: extra += hit; 145: if (extra > Ship.energy) 146: { 147: printf("available energy exceeded. "); 148: skiptonl(0); 149: flag++; 150: break; 151: } 152: b->units = hit; 153: hit = getintpar("course"); 154: if (hit < 0 || hit > 360) 155: return; 156: b->angle = hit * 0.0174532925; 157: b->spread = getfltpar("spread"); 158: if (b->spread < 0 || b->spread > 1) 159: return; 160: } 161: Ship.energy -= extra; 162: } 163: extra = 0; 164: } 165: else 166: { 167: /* automatic distribution of power */ 168: if (Etc.nkling <= 0) 169: return (printf("Sulu: But there are no Klingons in this quadrant\n")); 170: printf("Phasers locked on target. "); 171: while (flag) 172: { 173: printf("%d units available\n", Ship.energy); 174: hit = getintpar("Units to fire"); 175: if (hit <= 0) 176: return; 177: if (hit > Ship.energy) 178: { 179: printf("available energy exceeded. "); 180: skiptonl(0); 181: continue; 182: } 183: flag = 0; 184: Ship.energy -= hit; 185: extra = hit; 186: n = Etc.nkling; 187: if (n > NBANKS) 188: n = NBANKS; 189: tot = n * (n + 1) / 2; 190: for (i = 0; i < n; i++) 191: { 192: k = &Etc.klingon[i]; 193: b = &bank[i]; 194: distfactor = k->dist; 195: anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON); 196: anglefactor *= GAMMA; 197: distfactor = k->power; 198: distfactor /= anglefactor; 199: hitreqd[i] = distfactor + 0.5; 200: dx = Ship.sectx - k->x; 201: dy = k->y - Ship.secty; 202: b->angle = atan2(dy, dx); 203: b->spread = 0.0; 204: b->units = ((n - i) / tot) * extra; 205: # ifdef xTRACE 206: if (Trace) 207: { 208: printf("b%d hr%d u%d df%.2f af%.2f\n", 209: i, hitreqd[i], b->units, 210: distfactor, anglefactor); 211: } 212: # endif 213: extra -= b->units; 214: hit = b->units - hitreqd[i]; 215: if (hit > 0) 216: { 217: extra += hit; 218: b->units -= hit; 219: } 220: } 221: 222: /* give out any extra energy we might have around */ 223: if (extra > 0) 224: { 225: for (i = 0; i < n; i++) 226: { 227: b = &bank[i]; 228: hit = hitreqd[i] - b->units; 229: if (hit <= 0) 230: continue; 231: if (hit >= extra) 232: { 233: b->units += extra; 234: extra = 0; 235: break; 236: } 237: b->units = hitreqd[i]; 238: extra -= hit; 239: } 240: if (extra > 0) 241: printf("%d units overkill\n", extra); 242: } 243: } 244: } 245: 246: # ifdef xTRACE 247: if (Trace) 248: { 249: for (i = 0; i < NBANKS; i++) 250: { 251: b = &bank[i]; 252: printf("b%d u%d", i, b->units); 253: if (b->units > 0) 254: printf(" a%.2f s%.2f\n", b->angle, b->spread); 255: else 256: printf("\n"); 257: } 258: } 259: # endif 260: 261: /* actually fire the shots */ 262: Move.free = 0; 263: for (i = 0; i < NBANKS; i++) 264: { 265: b = &bank[i]; 266: if (b->units <= 0) 267: { 268: continue; 269: } 270: printf("\nPhaser bank %d fires:\n", i); 271: n = Etc.nkling; 272: k = Etc.klingon; 273: for (j = 0; j < n; j++) 274: { 275: if (b->units <= 0) 276: break; 277: /* 278: ** The formula for hit is as follows: 279: ** 280: ** zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)] 281: ** / (dist ** 2 + EPSILON)] 282: ** * [cos(delta * sigma) + GAMMA] 283: ** * hit 284: ** 285: ** where sigma is the spread factor, 286: ** rho is a random number (0 -> 1), 287: ** GAMMA is a crud factor for angle (essentially 288: ** cruds up the spread factor), 289: ** delta is the difference in radians between the 290: ** angle you are shooting at and the actual 291: ** angle of the klingon, 292: ** ALPHA scales down the significance of sigma, 293: ** BETA scales down the significance of rho, 294: ** OMEGA is the magic number which makes everything 295: ** up to "* hit" between zero and one, 296: ** dist is the distance to the klingon 297: ** hit is the number of units in the bank, and 298: ** zap is the amount of the actual hit. 299: ** 300: ** Everything up through dist squared should maximize 301: ** at 1.0, so that the distance factor is never 302: ** greater than one. Conveniently, cos() is 303: ** never greater than one, but the same restric- 304: ** tion applies. 305: */ 306: distfactor = BETA + franf(); 307: distfactor *= ALPHA + b->spread; 308: distfactor *= OMEGA; 309: anglefactor = k->dist; 310: distfactor /= anglefactor * anglefactor + EPSILON; 311: distfactor *= b->units; 312: dx = Ship.sectx - k->x; 313: dy = k->y - Ship.secty; 314: anglefactor = atan2(dy, dx) - b->angle; 315: anglefactor = cos((anglefactor * b->spread) + GAMMA); 316: if (anglefactor < 0.0) 317: { 318: k++; 319: continue; 320: } 321: hit = anglefactor * distfactor + 0.5; 322: k->power -= hit; 323: printf("%d unit hit on Klingon", hit); 324: if (!damaged(SRSCAN)) 325: printf(" at %d,%d", k->x, k->y); 326: printf("\n"); 327: b->units -= hit; 328: if (k->power <= 0) 329: { 330: killk(k->x, k->y); 331: continue; 332: } 333: k++; 334: } 335: } 336: 337: /* compute overkill */ 338: for (i = 0; i < NBANKS; i++) 339: extra += bank[i].units; 340: if (extra > 0) 341: printf("\n%d units expended on empty space\n", extra); 342: }