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