Home | History | Annotate | Line # | Download | only in trek
phaser.c revision 1.4
      1 /*	$NetBSD: phaser.c,v 1.4 1995/04/24 12:26:02 cgd 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. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #ifndef lint
     37 #if 0
     38 static char sccsid[] = "@(#)phaser.c	8.1 (Berkeley) 5/31/93";
     39 #else
     40 static char rcsid[] = "$NetBSD: phaser.c,v 1.4 1995/04/24 12:26:02 cgd Exp $";
     41 #endif
     42 #endif /* not lint */
     43 
     44 # include	"trek.h"
     45 # include	"getpar.h"
     46 
     47 /* factors for phaser hits; see description below */
     48 
     49 # define	ALPHA		3.0		/* spread */
     50 # define	BETA		3.0		/* franf() */
     51 # define	GAMMA		0.30		/* cos(angle) */
     52 # define	EPSILON		150.0		/* dist ** 2 */
     53 # define	OMEGA		10.596		/* overall scaling factor */
     54 
     55 /* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */
     56 
     57 /*
     58 **  Phaser Control
     59 **
     60 **	There are up to NBANKS phaser banks which may be fired
     61 **	simultaneously.  There are two modes, "manual" and
     62 **	"automatic".  In manual mode, you specify exactly which
     63 **	direction you want each bank to be aimed, the number
     64 **	of units to fire, and the spread angle.  In automatic
     65 **	mode, you give only the total number of units to fire.
     66 **
     67 **	The spread is specified as a number between zero and
     68 **	one, with zero being minimum spread and one being maximum
     69 **	spread.  You  will normally want zero spread, unless your
     70 **	short range scanners are out, in which case you probably
     71 **	don't know exactly where the Klingons are.  In that case,
     72 **	you really don't have any choice except to specify a
     73 **	fairly large spread.
     74 **
     75 **	Phasers spread slightly, even if you specify zero spread.
     76 **
     77 **	Uses trace flag 30
     78 */
     79 
     80 struct cvntab	Matab[] =
     81 {
     82 	"m",		"anual",		(int (*)())1,		0,
     83 	"a",		"utomatic",		0,		0,
     84 	0
     85 };
     86 
     87 struct banks
     88 {
     89 	int	units;
     90 	double	angle;
     91 	double	spread;
     92 };
     93 
     94 
     95 
     96 phaser()
     97 {
     98 	register int		i;
     99 	int			j;
    100 	register struct kling	*k;
    101 	double			dx, dy;
    102 	double			anglefactor, distfactor;
    103 	register struct banks	*b;
    104 	int			manual, flag, extra;
    105 	int			hit;
    106 	double			tot;
    107 	int			n;
    108 	int			hitreqd[NBANKS];
    109 	struct banks		bank[NBANKS];
    110 	struct cvntab		*ptr;
    111 
    112 	if (Ship.cond == DOCKED)
    113 		return(printf("Phasers cannot fire through starbase shields\n"));
    114 	if (damaged(PHASER))
    115 		return (out(PHASER));
    116 	if (Ship.shldup)
    117 		return (printf("Sulu: Captain, we cannot fire through shields.\n"));
    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(Device[COMPUTER].name);
    132 			manual++;
    133 		}
    134 		else
    135 			if (damaged(SRSCAN))
    136 			{
    137 				printf(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 			return (printf("Sulu: But there are no Klingons in this quadrant\n"));
    203 		printf("Phasers locked on target.  ");
    204 		while (flag)
    205 		{
    206 			printf("%d units available\n", Ship.energy);
    207 			hit = getintpar("Units to fire");
    208 			if (hit <= 0)
    209 				return;
    210 			if (hit > Ship.energy)
    211 			{
    212 				printf("available energy exceeded.  ");
    213 				skiptonl(0);
    214 				continue;
    215 			}
    216 			flag = 0;
    217 			Ship.energy -= hit;
    218 			extra = hit;
    219 			n = Etc.nkling;
    220 			if (n > NBANKS)
    221 				n = NBANKS;
    222 			tot = n * (n + 1) / 2;
    223 			for (i = 0; i < n; i++)
    224 			{
    225 				k = &Etc.klingon[i];
    226 				b = &bank[i];
    227 				distfactor = k->dist;
    228 				anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON);
    229 				anglefactor *= GAMMA;
    230 				distfactor = k->power;
    231 				distfactor /= anglefactor;
    232 				hitreqd[i] = distfactor + 0.5;
    233 				dx = Ship.sectx - k->x;
    234 				dy = k->y - Ship.secty;
    235 				b->angle = atan2(dy, dx);
    236 				b->spread = 0.0;
    237 				b->units = ((n - i) / tot) * extra;
    238 #				ifdef xTRACE
    239 				if (Trace)
    240 				{
    241 					printf("b%d hr%d u%d df%.2f af%.2f\n",
    242 						i, hitreqd[i], b->units,
    243 						distfactor, anglefactor);
    244 				}
    245 #				endif
    246 				extra -= b->units;
    247 				hit = b->units - hitreqd[i];
    248 				if (hit > 0)
    249 				{
    250 					extra += hit;
    251 					b->units -= hit;
    252 				}
    253 			}
    254 
    255 			/* give out any extra energy we might have around */
    256 			if (extra > 0)
    257 			{
    258 				for (i = 0; i < n; i++)
    259 				{
    260 					b = &bank[i];
    261 					hit = hitreqd[i] - b->units;
    262 					if (hit <= 0)
    263 						continue;
    264 					if (hit >= extra)
    265 					{
    266 						b->units += extra;
    267 						extra = 0;
    268 						break;
    269 					}
    270 					b->units = hitreqd[i];
    271 					extra -= hit;
    272 				}
    273 				if (extra > 0)
    274 					printf("%d units overkill\n", extra);
    275 			}
    276 		}
    277 	}
    278 
    279 #	ifdef xTRACE
    280 	if (Trace)
    281 	{
    282 		for (i = 0; i < NBANKS; i++)
    283 		{
    284 			b = &bank[i];
    285 			printf("b%d u%d", i, b->units);
    286 			if (b->units > 0)
    287 				printf(" a%.2f s%.2f\n", b->angle, b->spread);
    288 			else
    289 				printf("\n");
    290 		}
    291 	}
    292 #	endif
    293 
    294 	/* actually fire the shots */
    295 	Move.free = 0;
    296 	for (i = 0; i < NBANKS; i++)
    297 	{
    298 		b = &bank[i];
    299 		if (b->units <= 0)
    300 		{
    301 			continue;
    302 		}
    303 		printf("\nPhaser bank %d fires:\n", i);
    304 		n = Etc.nkling;
    305 		k = Etc.klingon;
    306 		for (j = 0; j < n; j++)
    307 		{
    308 			if (b->units <= 0)
    309 				break;
    310 			/*
    311 			** The formula for hit is as follows:
    312 			**
    313 			**  zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)]
    314 			**	/ (dist ** 2 + EPSILON)]
    315 			**	* [cos(delta * sigma) + GAMMA]
    316 			**	* hit
    317 			**
    318 			** where sigma is the spread factor,
    319 			** rho is a random number (0 -> 1),
    320 			** GAMMA is a crud factor for angle (essentially
    321 			**	cruds up the spread factor),
    322 			** delta is the difference in radians between the
    323 			**	angle you are shooting at and the actual
    324 			**	angle of the klingon,
    325 			** ALPHA scales down the significance of sigma,
    326 			** BETA scales down the significance of rho,
    327 			** OMEGA is the magic number which makes everything
    328 			**	up to "* hit" between zero and one,
    329 			** dist is the distance to the klingon
    330 			** hit is the number of units in the bank, and
    331 			** zap is the amount of the actual hit.
    332 			**
    333 			** Everything up through dist squared should maximize
    334 			** at 1.0, so that the distance factor is never
    335 			** greater than one.  Conveniently, cos() is
    336 			** never greater than one, but the same restric-
    337 			** tion applies.
    338 			*/
    339 			distfactor = BETA + franf();
    340 			distfactor *= ALPHA + b->spread;
    341 			distfactor *= OMEGA;
    342 			anglefactor = k->dist;
    343 			distfactor /= anglefactor * anglefactor + EPSILON;
    344 			distfactor *= b->units;
    345 			dx = Ship.sectx - k->x;
    346 			dy = k->y - Ship.secty;
    347 			anglefactor = atan2(dy, dx) - b->angle;
    348 			anglefactor = cos((anglefactor * b->spread) + GAMMA);
    349 			if (anglefactor < 0.0)
    350 			{
    351 				k++;
    352 				continue;
    353 			}
    354 			hit = anglefactor * distfactor + 0.5;
    355 			k->power -= hit;
    356 			printf("%d unit hit on Klingon", hit);
    357 			if (!damaged(SRSCAN))
    358 				printf(" at %d,%d", k->x, k->y);
    359 			printf("\n");
    360 			b->units -= hit;
    361 			if (k->power <= 0)
    362 			{
    363 				killk(k->x, k->y);
    364 				continue;
    365 			}
    366 			k++;
    367 		}
    368 	}
    369 
    370 	/* compute overkill */
    371 	for (i = 0; i < NBANKS; i++)
    372 		extra += bank[i].units;
    373 	if (extra > 0)
    374 		printf("\n%d units expended on empty space\n", extra);
    375 }
    376