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