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