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