Home | History | Annotate | Line # | Download | only in trek
phaser.c revision 1.1
      1 /*
      2  * Copyright (c) 1980 Regents of the University of California.
      3  * 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 
     34 #ifndef lint
     35 static char sccsid[] = "@(#)phaser.c	5.4 (Berkeley) 6/1/90";
     36 #endif /* not lint */
     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",		(int (*)())1,		0,
     77 	"a",		"utomatic",		0,		0,
     78 	0
     79 };
     80 
     81 struct banks
     82 {
     83 	int	units;
     84 	double	angle;
     85 	double	spread;
     86 };
     87 
     88 
     89 
     90 phaser()
     91 {
     92 	register int		i;
     93 	int			j;
     94 	register struct kling	*k;
     95 	double			dx, dy;
     96 	double			anglefactor, distfactor;
     97 	register struct banks	*b;
     98 	int			manual, flag, extra;
     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 		return(printf("Phasers cannot fire through starbase shields\n"));
    108 	if (damaged(PHASER))
    109 		return (out(PHASER));
    110 	if (Ship.shldup)
    111 		return (printf("Sulu: Captain, we cannot fire through shields.\n"));
    112 	if (Ship.cloaked)
    113 	{
    114 		printf("Sulu: Captain, surely you must realize that we cannot fire\n");
    115 		printf("  phasers with the cloaking device up.\n");
    116 		return;
    117 	}
    118 
    119 	/* decide if we want manual or automatic mode */
    120 	manual = 0;
    121 	if (testnl())
    122 	{
    123 		if (damaged(COMPUTER))
    124 		{
    125 			printf(Device[COMPUTER].name);
    126 			manual++;
    127 		}
    128 		else
    129 			if (damaged(SRSCAN))
    130 			{
    131 				printf(Device[SRSCAN].name);
    132 				manual++;
    133 			}
    134 		if (manual)
    135 			printf(" damaged, manual mode selected\n");
    136 	}
    137 
    138 	if (!manual)
    139 	{
    140 		ptr = getcodpar("Manual or automatic", Matab);
    141 		manual = (int) ptr->value;
    142 	}
    143 	if (!manual && damaged(COMPUTER))
    144 	{
    145 		printf("Computer damaged, manual selected\n");
    146 		skiptonl(0);
    147 		manual++;
    148 	}
    149 
    150 	/* initialize the bank[] array */
    151 	flag = 1;
    152 	for (i = 0; i < NBANKS; i++)
    153 		bank[i].units = 0;
    154 	if (manual)
    155 	{
    156 		/* collect manual mode statistics */
    157 		while (flag)
    158 		{
    159 			printf("%d units available\n", Ship.energy);
    160 			extra = 0;
    161 			flag = 0;
    162 			for (i = 0; i < NBANKS; i++)
    163 			{
    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 				{
    174 					printf("available energy exceeded.  ");
    175 					skiptonl(0);
    176 					flag++;
    177 					break;
    178 				}
    179 				b->units = hit;
    180 				hit = getintpar("course");
    181 				if (hit < 0 || hit > 360)
    182 					return;
    183 				b->angle = hit * 0.0174532925;
    184 				b->spread = getfltpar("spread");
    185 				if (b->spread < 0 || b->spread > 1)
    186 					return;
    187 			}
    188 			Ship.energy -= extra;
    189 		}
    190 		extra = 0;
    191 	}
    192 	else
    193 	{
    194 		/* automatic distribution of power */
    195 		if (Etc.nkling <= 0)
    196 			return (printf("Sulu: But there are no Klingons in this quadrant\n"));
    197 		printf("Phasers locked on target.  ");
    198 		while (flag)
    199 		{
    200 			printf("%d units available\n", Ship.energy);
    201 			hit = getintpar("Units to fire");
    202 			if (hit <= 0)
    203 				return;
    204 			if (hit > Ship.energy)
    205 			{
    206 				printf("available energy exceeded.  ");
    207 				skiptonl(0);
    208 				continue;
    209 			}
    210 			flag = 0;
    211 			Ship.energy -= hit;
    212 			extra = hit;
    213 			n = Etc.nkling;
    214 			if (n > NBANKS)
    215 				n = NBANKS;
    216 			tot = n * (n + 1) / 2;
    217 			for (i = 0; i < n; i++)
    218 			{
    219 				k = &Etc.klingon[i];
    220 				b = &bank[i];
    221 				distfactor = k->dist;
    222 				anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON);
    223 				anglefactor *= GAMMA;
    224 				distfactor = k->power;
    225 				distfactor /= anglefactor;
    226 				hitreqd[i] = distfactor + 0.5;
    227 				dx = Ship.sectx - k->x;
    228 				dy = k->y - Ship.secty;
    229 				b->angle = atan2(dy, dx);
    230 				b->spread = 0.0;
    231 				b->units = ((n - i) / tot) * extra;
    232 #				ifdef xTRACE
    233 				if (Trace)
    234 				{
    235 					printf("b%d hr%d u%d df%.2f af%.2f\n",
    236 						i, hitreqd[i], b->units,
    237 						distfactor, anglefactor);
    238 				}
    239 #				endif
    240 				extra -= b->units;
    241 				hit = b->units - hitreqd[i];
    242 				if (hit > 0)
    243 				{
    244 					extra += hit;
    245 					b->units -= hit;
    246 				}
    247 			}
    248 
    249 			/* give out any extra energy we might have around */
    250 			if (extra > 0)
    251 			{
    252 				for (i = 0; i < n; i++)
    253 				{
    254 					b = &bank[i];
    255 					hit = hitreqd[i] - b->units;
    256 					if (hit <= 0)
    257 						continue;
    258 					if (hit >= extra)
    259 					{
    260 						b->units += extra;
    261 						extra = 0;
    262 						break;
    263 					}
    264 					b->units = hitreqd[i];
    265 					extra -= hit;
    266 				}
    267 				if (extra > 0)
    268 					printf("%d units overkill\n", extra);
    269 			}
    270 		}
    271 	}
    272 
    273 #	ifdef xTRACE
    274 	if (Trace)
    275 	{
    276 		for (i = 0; i < NBANKS; i++)
    277 		{
    278 			b = &bank[i];
    279 			printf("b%d u%d", i, b->units);
    280 			if (b->units > 0)
    281 				printf(" a%.2f s%.2f\n", b->angle, b->spread);
    282 			else
    283 				printf("\n");
    284 		}
    285 	}
    286 #	endif
    287 
    288 	/* actually fire the shots */
    289 	Move.free = 0;
    290 	for (i = 0; i < NBANKS; i++)
    291 	{
    292 		b = &bank[i];
    293 		if (b->units <= 0)
    294 		{
    295 			continue;
    296 		}
    297 		printf("\nPhaser bank %d fires:\n", i);
    298 		n = Etc.nkling;
    299 		k = Etc.klingon;
    300 		for (j = 0; j < n; j++)
    301 		{
    302 			if (b->units <= 0)
    303 				break;
    304 			/*
    305 			** The formula for hit is as follows:
    306 			**
    307 			**  zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)]
    308 			**	/ (dist ** 2 + EPSILON)]
    309 			**	* [cos(delta * sigma) + GAMMA]
    310 			**	* hit
    311 			**
    312 			** where sigma is the spread factor,
    313 			** rho is a random number (0 -> 1),
    314 			** GAMMA is a crud factor for angle (essentially
    315 			**	cruds up the spread factor),
    316 			** delta is the difference in radians between the
    317 			**	angle you are shooting at and the actual
    318 			**	angle of the klingon,
    319 			** ALPHA scales down the significance of sigma,
    320 			** BETA scales down the significance of rho,
    321 			** OMEGA is the magic number which makes everything
    322 			**	up to "* hit" between zero and one,
    323 			** dist is the distance to the klingon
    324 			** hit is the number of units in the bank, and
    325 			** zap is the amount of the actual hit.
    326 			**
    327 			** Everything up through dist squared should maximize
    328 			** at 1.0, so that the distance factor is never
    329 			** greater than one.  Conveniently, cos() is
    330 			** never greater than one, but the same restric-
    331 			** tion applies.
    332 			*/
    333 			distfactor = BETA + franf();
    334 			distfactor *= ALPHA + b->spread;
    335 			distfactor *= OMEGA;
    336 			anglefactor = k->dist;
    337 			distfactor /= anglefactor * anglefactor + EPSILON;
    338 			distfactor *= b->units;
    339 			dx = Ship.sectx - k->x;
    340 			dy = k->y - Ship.secty;
    341 			anglefactor = atan2(dy, dx) - b->angle;
    342 			anglefactor = cos((anglefactor * b->spread) + GAMMA);
    343 			if (anglefactor < 0.0)
    344 			{
    345 				k++;
    346 				continue;
    347 			}
    348 			hit = anglefactor * distfactor + 0.5;
    349 			k->power -= hit;
    350 			printf("%d unit hit on Klingon", hit);
    351 			if (!damaged(SRSCAN))
    352 				printf(" at %d,%d", k->x, k->y);
    353 			printf("\n");
    354 			b->units -= hit;
    355 			if (k->power <= 0)
    356 			{
    357 				killk(k->x, k->y);
    358 				continue;
    359 			}
    360 			k++;
    361 		}
    362 	}
    363 
    364 	/* compute overkill */
    365 	for (i = 0; i < NBANKS; i++)
    366 		extra += bank[i].units;
    367 	if (extra > 0)
    368 		printf("\n%d units expended on empty space\n", extra);
    369 }
    370