1 /* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)phaser.c 8.1 (Berkeley) 5/31/93 34 * $FreeBSD: src/games/trek/phaser.c,v 1.5.2.1 2000/07/20 10:35:07 kris Exp $ 35 * $DragonFly: src/games/trek/phaser.c,v 1.3 2006/09/07 21:19:44 pavalos Exp $ 36 */ 37 38 # include "trek.h" 39 # include "getpar.h" 40 41 /* factors for phaser hits; see description below */ 42 43 # define ALPHA 3.0 /* spread */ 44 # define BETA 3.0 /* franf() */ 45 # define GAMMA 0.30 /* cos(angle) */ 46 # define EPSILON 150.0 /* dist ** 2 */ 47 # define OMEGA 10.596 /* overall scaling factor */ 48 49 /* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */ 50 51 /* 52 ** Phaser Control 53 ** 54 ** There are up to NBANKS phaser banks which may be fired 55 ** simultaneously. There are two modes, "manual" and 56 ** "automatic". In manual mode, you specify exactly which 57 ** direction you want each bank to be aimed, the number 58 ** of units to fire, and the spread angle. In automatic 59 ** mode, you give only the total number of units to fire. 60 ** 61 ** The spread is specified as a number between zero and 62 ** one, with zero being minimum spread and one being maximum 63 ** spread. You will normally want zero spread, unless your 64 ** short range scanners are out, in which case you probably 65 ** don't know exactly where the Klingons are. In that case, 66 ** you really don't have any choice except to specify a 67 ** fairly large spread. 68 ** 69 ** Phasers spread slightly, even if you specify zero spread. 70 ** 71 ** Uses trace flag 30 72 */ 73 74 struct cvntab Matab[] = 75 { 76 { "m", "anual", (void (*)(int))1, 0 }, 77 { "a", "utomatic", (void (*)(int))0, 0 }, 78 { NULL, NULL, NULL, 0 } 79 }; 80 81 struct banks 82 { 83 int units; 84 double angle; 85 double spread; 86 }; 87 88 89 void 90 phaser(__unused int unused) 91 { 92 int i; 93 int j; 94 struct kling *k; 95 double dx, dy; 96 double anglefactor, distfactor; 97 struct banks *b; 98 int manual, flag, extra = 0; 99 int hit; 100 double tot; 101 int n; 102 int hitreqd[NBANKS]; 103 struct banks bank[NBANKS]; 104 struct cvntab *ptr; 105 106 if (Ship.cond == DOCKED) { 107 printf("Phasers cannot fire through starbase shields\n"); 108 return; 109 } 110 if (damaged(PHASER)) { 111 out(PHASER); 112 return; 113 } 114 if (Ship.shldup) { 115 printf("Sulu: Captain, we cannot fire through shields.\n"); 116 return; 117 } 118 if (Ship.cloaked) 119 { 120 printf("Sulu: Captain, surely you must realize that we cannot fire\n"); 121 printf(" phasers with the cloaking device up.\n"); 122 return; 123 } 124 125 /* decide if we want manual or automatic mode */ 126 manual = 0; 127 if (testnl()) 128 { 129 if (damaged(COMPUTER)) 130 { 131 printf("%s", Device[COMPUTER].name); 132 manual++; 133 } 134 else 135 if (damaged(SRSCAN)) 136 { 137 printf("%s", Device[SRSCAN].name); 138 manual++; 139 } 140 if (manual) 141 printf(" damaged, manual mode selected\n"); 142 } 143 144 if (!manual) 145 { 146 ptr = getcodpar("Manual or automatic", Matab); 147 manual = (long) ptr->value; 148 } 149 if (!manual && damaged(COMPUTER)) 150 { 151 printf("Computer damaged, manual selected\n"); 152 skiptonl(0); 153 manual++; 154 } 155 156 /* initialize the bank[] array */ 157 flag = 1; 158 for (i = 0; i < NBANKS; i++) 159 bank[i].units = 0; 160 if (manual) 161 { 162 /* collect manual mode statistics */ 163 while (flag) 164 { 165 printf("%d units available\n", Ship.energy); 166 extra = 0; 167 flag = 0; 168 for (i = 0; i < NBANKS; i++) 169 { 170 b = &bank[i]; 171 printf("\nBank %d:\n", i); 172 hit = getintpar("units"); 173 if (hit < 0) 174 return; 175 if (hit == 0) 176 break; 177 extra += hit; 178 if (extra > Ship.energy) 179 { 180 printf("available energy exceeded. "); 181 skiptonl(0); 182 flag++; 183 break; 184 } 185 b->units = hit; 186 hit = getintpar("course"); 187 if (hit < 0 || hit > 360) 188 return; 189 b->angle = hit * 0.0174532925; 190 b->spread = getfltpar("spread"); 191 if (b->spread < 0 || b->spread > 1) 192 return; 193 } 194 Ship.energy -= extra; 195 } 196 extra = 0; 197 } 198 else 199 { 200 /* automatic distribution of power */ 201 if (Etc.nkling <= 0) { 202 printf("Sulu: But there are no Klingons in this quadrant\n"); 203 return; 204 } 205 printf("Phasers locked on target. "); 206 while (flag) 207 { 208 printf("%d units available\n", Ship.energy); 209 hit = getintpar("Units to fire"); 210 if (hit <= 0) 211 return; 212 if (hit > Ship.energy) 213 { 214 printf("available energy exceeded. "); 215 skiptonl(0); 216 continue; 217 } 218 flag = 0; 219 Ship.energy -= hit; 220 extra = hit; 221 n = Etc.nkling; 222 if (n > NBANKS) 223 n = NBANKS; 224 tot = n * (n + 1) / 2; 225 for (i = 0; i < n; i++) 226 { 227 k = &Etc.klingon[i]; 228 b = &bank[i]; 229 distfactor = k->dist; 230 anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON); 231 anglefactor *= GAMMA; 232 distfactor = k->power; 233 distfactor /= anglefactor; 234 hitreqd[i] = distfactor + 0.5; 235 dx = Ship.sectx - k->x; 236 dy = k->y - Ship.secty; 237 b->angle = atan2(dy, dx); 238 b->spread = 0.0; 239 b->units = ((n - i) / tot) * extra; 240 # ifdef xTRACE 241 if (Trace) 242 { 243 printf("b%d hr%d u%d df%.2f af%.2f\n", 244 i, hitreqd[i], b->units, 245 distfactor, anglefactor); 246 } 247 # endif 248 extra -= b->units; 249 hit = b->units - hitreqd[i]; 250 if (hit > 0) 251 { 252 extra += hit; 253 b->units -= hit; 254 } 255 } 256 257 /* give out any extra energy we might have around */ 258 if (extra > 0) 259 { 260 for (i = 0; i < n; i++) 261 { 262 b = &bank[i]; 263 hit = hitreqd[i] - b->units; 264 if (hit <= 0) 265 continue; 266 if (hit >= extra) 267 { 268 b->units += extra; 269 extra = 0; 270 break; 271 } 272 b->units = hitreqd[i]; 273 extra -= hit; 274 } 275 if (extra > 0) 276 printf("%d units overkill\n", extra); 277 } 278 } 279 } 280 281 # ifdef xTRACE 282 if (Trace) 283 { 284 for (i = 0; i < NBANKS; i++) 285 { 286 b = &bank[i]; 287 printf("b%d u%d", i, b->units); 288 if (b->units > 0) 289 printf(" a%.2f s%.2f\n", b->angle, b->spread); 290 else 291 printf("\n"); 292 } 293 } 294 # endif 295 296 /* actually fire the shots */ 297 Move.free = 0; 298 for (i = 0; i < NBANKS; i++) 299 { 300 b = &bank[i]; 301 if (b->units <= 0) 302 { 303 continue; 304 } 305 printf("\nPhaser bank %d fires:\n", i); 306 n = Etc.nkling; 307 k = Etc.klingon; 308 for (j = 0; j < n; j++) 309 { 310 if (b->units <= 0) 311 break; 312 /* 313 ** The formula for hit is as follows: 314 ** 315 ** zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)] 316 ** / (dist ** 2 + EPSILON)] 317 ** * [cos(delta * sigma) + GAMMA] 318 ** * hit 319 ** 320 ** where sigma is the spread factor, 321 ** rho is a random number (0 -> 1), 322 ** GAMMA is a crud factor for angle (essentially 323 ** cruds up the spread factor), 324 ** delta is the difference in radians between the 325 ** angle you are shooting at and the actual 326 ** angle of the klingon, 327 ** ALPHA scales down the significance of sigma, 328 ** BETA scales down the significance of rho, 329 ** OMEGA is the magic number which makes everything 330 ** up to "* hit" between zero and one, 331 ** dist is the distance to the klingon 332 ** hit is the number of units in the bank, and 333 ** zap is the amount of the actual hit. 334 ** 335 ** Everything up through dist squared should maximize 336 ** at 1.0, so that the distance factor is never 337 ** greater than one. Conveniently, cos() is 338 ** never greater than one, but the same restric- 339 ** tion applies. 340 */ 341 distfactor = BETA + franf(); 342 distfactor *= ALPHA + b->spread; 343 distfactor *= OMEGA; 344 anglefactor = k->dist; 345 distfactor /= anglefactor * anglefactor + EPSILON; 346 distfactor *= b->units; 347 dx = Ship.sectx - k->x; 348 dy = k->y - Ship.secty; 349 anglefactor = atan2(dy, dx) - b->angle; 350 anglefactor = cos((anglefactor * b->spread) + GAMMA); 351 if (anglefactor < 0.0) 352 { 353 k++; 354 continue; 355 } 356 hit = anglefactor * distfactor + 0.5; 357 k->power -= hit; 358 printf("%d unit hit on Klingon", hit); 359 if (!damaged(SRSCAN)) 360 printf(" at %d,%d", k->x, k->y); 361 printf("\n"); 362 b->units -= hit; 363 if (k->power <= 0) 364 { 365 killk(k->x, k->y); 366 continue; 367 } 368 k++; 369 } 370 } 371 372 /* compute overkill */ 373 for (i = 0; i < NBANKS; i++) 374 extra += bank[i].units; 375 if (extra > 0) 376 printf("\n%d units expended on empty space\n", extra); 377 } 378