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