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