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