Home | History | Annotate | Line # | Download | only in trek
phaser.c revision 1.2
      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[] = "from: @(#)phaser.c	5.4 (Berkeley) 6/1/90";*/
     36 static char rcsid[] = "$Id: phaser.c,v 1.2 1993/08/01 18:50:12 mycroft Exp $";
     37 #endif /* not lint */
     38 
     39 # include	"trek.h"
     40 # include	"getpar.h"
     41 
     42 /* factors for phaser hits; see description below */
     43 
     44 # define	ALPHA		3.0		/* spread */
     45 # define	BETA		3.0		/* franf() */
     46 # define	GAMMA		0.30		/* cos(angle) */
     47 # define	EPSILON		150.0		/* dist ** 2 */
     48 # define	OMEGA		10.596		/* overall scaling factor */
     49 
     50 /* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */
     51 
     52 /*
     53 **  Phaser Control
     54 **
     55 **	There are up to NBANKS phaser banks which may be fired
     56 **	simultaneously.  There are two modes, "manual" and
     57 **	"automatic".  In manual mode, you specify exactly which
     58 **	direction you want each bank to be aimed, the number
     59 **	of units to fire, and the spread angle.  In automatic
     60 **	mode, you give only the total number of units to fire.
     61 **
     62 **	The spread is specified as a number between zero and
     63 **	one, with zero being minimum spread and one being maximum
     64 **	spread.  You  will normally want zero spread, unless your
     65 **	short range scanners are out, in which case you probably
     66 **	don't know exactly where the Klingons are.  In that case,
     67 **	you really don't have any choice except to specify a
     68 **	fairly large spread.
     69 **
     70 **	Phasers spread slightly, even if you specify zero spread.
     71 **
     72 **	Uses trace flag 30
     73 */
     74 
     75 struct cvntab	Matab[] =
     76 {
     77 	"m",		"anual",		(int (*)())1,		0,
     78 	"a",		"utomatic",		0,		0,
     79 	0
     80 };
     81 
     82 struct banks
     83 {
     84 	int	units;
     85 	double	angle;
     86 	double	spread;
     87 };
     88 
     89 
     90 
     91 phaser()
     92 {
     93 	register int		i;
     94 	int			j;
     95 	register struct kling	*k;
     96 	double			dx, dy;
     97 	double			anglefactor, distfactor;
     98 	register struct banks	*b;
     99 	int			manual, flag, extra;
    100 	int			hit;
    101 	double			tot;
    102 	int			n;
    103 	int			hitreqd[NBANKS];
    104 	struct banks		bank[NBANKS];
    105 	struct cvntab		*ptr;
    106 
    107 	if (Ship.cond == DOCKED)
    108 		return(printf("Phasers cannot fire through starbase shields\n"));
    109 	if (damaged(PHASER))
    110 		return (out(PHASER));
    111 	if (Ship.shldup)
    112 		return (printf("Sulu: Captain, we cannot fire through shields.\n"));
    113 	if (Ship.cloaked)
    114 	{
    115 		printf("Sulu: Captain, surely you must realize that we cannot fire\n");
    116 		printf("  phasers with the cloaking device up.\n");
    117 		return;
    118 	}
    119 
    120 	/* decide if we want manual or automatic mode */
    121 	manual = 0;
    122 	if (testnl())
    123 	{
    124 		if (damaged(COMPUTER))
    125 		{
    126 			printf(Device[COMPUTER].name);
    127 			manual++;
    128 		}
    129 		else
    130 			if (damaged(SRSCAN))
    131 			{
    132 				printf(Device[SRSCAN].name);
    133 				manual++;
    134 			}
    135 		if (manual)
    136 			printf(" damaged, manual mode selected\n");
    137 	}
    138 
    139 	if (!manual)
    140 	{
    141 		ptr = getcodpar("Manual or automatic", Matab);
    142 		manual = (int) ptr->value;
    143 	}
    144 	if (!manual && damaged(COMPUTER))
    145 	{
    146 		printf("Computer damaged, manual selected\n");
    147 		skiptonl(0);
    148 		manual++;
    149 	}
    150 
    151 	/* initialize the bank[] array */
    152 	flag = 1;
    153 	for (i = 0; i < NBANKS; i++)
    154 		bank[i].units = 0;
    155 	if (manual)
    156 	{
    157 		/* collect manual mode statistics */
    158 		while (flag)
    159 		{
    160 			printf("%d units available\n", Ship.energy);
    161 			extra = 0;
    162 			flag = 0;
    163 			for (i = 0; i < NBANKS; i++)
    164 			{
    165 				b = &bank[i];
    166 				printf("\nBank %d:\n", i);
    167 				hit = getintpar("units");
    168 				if (hit < 0)
    169 					return;
    170 				if (hit == 0)
    171 					break;
    172 				extra += hit;
    173 				if (extra > Ship.energy)
    174 				{
    175 					printf("available energy exceeded.  ");
    176 					skiptonl(0);
    177 					flag++;
    178 					break;
    179 				}
    180 				b->units = hit;
    181 				hit = getintpar("course");
    182 				if (hit < 0 || hit > 360)
    183 					return;
    184 				b->angle = hit * 0.0174532925;
    185 				b->spread = getfltpar("spread");
    186 				if (b->spread < 0 || b->spread > 1)
    187 					return;
    188 			}
    189 			Ship.energy -= extra;
    190 		}
    191 		extra = 0;
    192 	}
    193 	else
    194 	{
    195 		/* automatic distribution of power */
    196 		if (Etc.nkling <= 0)
    197 			return (printf("Sulu: But there are no Klingons in this quadrant\n"));
    198 		printf("Phasers locked on target.  ");
    199 		while (flag)
    200 		{
    201 			printf("%d units available\n", Ship.energy);
    202 			hit = getintpar("Units to fire");
    203 			if (hit <= 0)
    204 				return;
    205 			if (hit > Ship.energy)
    206 			{
    207 				printf("available energy exceeded.  ");
    208 				skiptonl(0);
    209 				continue;
    210 			}
    211 			flag = 0;
    212 			Ship.energy -= hit;
    213 			extra = hit;
    214 			n = Etc.nkling;
    215 			if (n > NBANKS)
    216 				n = NBANKS;
    217 			tot = n * (n + 1) / 2;
    218 			for (i = 0; i < n; i++)
    219 			{
    220 				k = &Etc.klingon[i];
    221 				b = &bank[i];
    222 				distfactor = k->dist;
    223 				anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON);
    224 				anglefactor *= GAMMA;
    225 				distfactor = k->power;
    226 				distfactor /= anglefactor;
    227 				hitreqd[i] = distfactor + 0.5;
    228 				dx = Ship.sectx - k->x;
    229 				dy = k->y - Ship.secty;
    230 				b->angle = atan2(dy, dx);
    231 				b->spread = 0.0;
    232 				b->units = ((n - i) / tot) * extra;
    233 #				ifdef xTRACE
    234 				if (Trace)
    235 				{
    236 					printf("b%d hr%d u%d df%.2f af%.2f\n",
    237 						i, hitreqd[i], b->units,
    238 						distfactor, anglefactor);
    239 				}
    240 #				endif
    241 				extra -= b->units;
    242 				hit = b->units - hitreqd[i];
    243 				if (hit > 0)
    244 				{
    245 					extra += hit;
    246 					b->units -= hit;
    247 				}
    248 			}
    249 
    250 			/* give out any extra energy we might have around */
    251 			if (extra > 0)
    252 			{
    253 				for (i = 0; i < n; i++)
    254 				{
    255 					b = &bank[i];
    256 					hit = hitreqd[i] - b->units;
    257 					if (hit <= 0)
    258 						continue;
    259 					if (hit >= extra)
    260 					{
    261 						b->units += extra;
    262 						extra = 0;
    263 						break;
    264 					}
    265 					b->units = hitreqd[i];
    266 					extra -= hit;
    267 				}
    268 				if (extra > 0)
    269 					printf("%d units overkill\n", extra);
    270 			}
    271 		}
    272 	}
    273 
    274 #	ifdef xTRACE
    275 	if (Trace)
    276 	{
    277 		for (i = 0; i < NBANKS; i++)
    278 		{
    279 			b = &bank[i];
    280 			printf("b%d u%d", i, b->units);
    281 			if (b->units > 0)
    282 				printf(" a%.2f s%.2f\n", b->angle, b->spread);
    283 			else
    284 				printf("\n");
    285 		}
    286 	}
    287 #	endif
    288 
    289 	/* actually fire the shots */
    290 	Move.free = 0;
    291 	for (i = 0; i < NBANKS; i++)
    292 	{
    293 		b = &bank[i];
    294 		if (b->units <= 0)
    295 		{
    296 			continue;
    297 		}
    298 		printf("\nPhaser bank %d fires:\n", i);
    299 		n = Etc.nkling;
    300 		k = Etc.klingon;
    301 		for (j = 0; j < n; j++)
    302 		{
    303 			if (b->units <= 0)
    304 				break;
    305 			/*
    306 			** The formula for hit is as follows:
    307 			**
    308 			**  zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)]
    309 			**	/ (dist ** 2 + EPSILON)]
    310 			**	* [cos(delta * sigma) + GAMMA]
    311 			**	* hit
    312 			**
    313 			** where sigma is the spread factor,
    314 			** rho is a random number (0 -> 1),
    315 			** GAMMA is a crud factor for angle (essentially
    316 			**	cruds up the spread factor),
    317 			** delta is the difference in radians between the
    318 			**	angle you are shooting at and the actual
    319 			**	angle of the klingon,
    320 			** ALPHA scales down the significance of sigma,
    321 			** BETA scales down the significance of rho,
    322 			** OMEGA is the magic number which makes everything
    323 			**	up to "* hit" between zero and one,
    324 			** dist is the distance to the klingon
    325 			** hit is the number of units in the bank, and
    326 			** zap is the amount of the actual hit.
    327 			**
    328 			** Everything up through dist squared should maximize
    329 			** at 1.0, so that the distance factor is never
    330 			** greater than one.  Conveniently, cos() is
    331 			** never greater than one, but the same restric-
    332 			** tion applies.
    333 			*/
    334 			distfactor = BETA + franf();
    335 			distfactor *= ALPHA + b->spread;
    336 			distfactor *= OMEGA;
    337 			anglefactor = k->dist;
    338 			distfactor /= anglefactor * anglefactor + EPSILON;
    339 			distfactor *= b->units;
    340 			dx = Ship.sectx - k->x;
    341 			dy = k->y - Ship.secty;
    342 			anglefactor = atan2(dy, dx) - b->angle;
    343 			anglefactor = cos((anglefactor * b->spread) + GAMMA);
    344 			if (anglefactor < 0.0)
    345 			{
    346 				k++;
    347 				continue;
    348 			}
    349 			hit = anglefactor * distfactor + 0.5;
    350 			k->power -= hit;
    351 			printf("%d unit hit on Klingon", hit);
    352 			if (!damaged(SRSCAN))
    353 				printf(" at %d,%d", k->x, k->y);
    354 			printf("\n");
    355 			b->units -= hit;
    356 			if (k->power <= 0)
    357 			{
    358 				killk(k->x, k->y);
    359 				continue;
    360 			}
    361 			k++;
    362 		}
    363 	}
    364 
    365 	/* compute overkill */
    366 	for (i = 0; i < NBANKS; i++)
    367 		extra += bank[i].units;
    368 	if (extra > 0)
    369 		printf("\n%d units expended on empty space\n", extra);
    370 }
    371