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