]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - trek/phaser.c
KNF: fix formatting of preprocessor directives
[bsdgames-darwin.git] / trek / phaser.c
1 /* $NetBSD: phaser.c,v 1.12 2009/05/24 20:39:43 dholland Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)phaser.c 8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: phaser.c,v 1.12 2009/05/24 20:39:43 dholland Exp $");
38 #endif
39 #endif /* not lint */
40
41 #include <stdio.h>
42 #include <math.h>
43 #include "trek.h"
44 #include "getpar.h"
45
46 /* factors for phaser hits; see description below */
47
48 #define ALPHA 3.0 /* spread */
49 #define BETA 3.0 /* franf() */
50 #define GAMMA 0.30 /* cos(angle) */
51 #define EPSILON 150.0 /* dist ** 2 */
52 #define OMEGA 10.596 /* overall scaling factor */
53
54 /* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */
55
56 /*
57 ** Phaser Control
58 **
59 ** There are up to NBANKS phaser banks which may be fired
60 ** simultaneously. There are two modes, "manual" and
61 ** "automatic". In manual mode, you specify exactly which
62 ** direction you want each bank to be aimed, the number
63 ** of units to fire, and the spread angle. In automatic
64 ** mode, you give only the total number of units to fire.
65 **
66 ** The spread is specified as a number between zero and
67 ** one, with zero being minimum spread and one being maximum
68 ** spread. You will normally want zero spread, unless your
69 ** short range scanners are out, in which case you probably
70 ** don't know exactly where the Klingons are. In that case,
71 ** you really don't have any choice except to specify a
72 ** fairly large spread.
73 **
74 ** Phasers spread slightly, even if you specify zero spread.
75 **
76 ** Uses trace flag 30
77 */
78
79 struct cvntab Matab[] =
80 {
81 { "m", "anual", (cmdfun) 1, 0 },
82 { "a", "utomatic", (cmdfun) 0, 0 },
83 { NULL, NULL, NULL, 0 }
84 };
85
86 struct banks
87 {
88 int units;
89 double angle;
90 double spread;
91 };
92
93
94
95 /*ARGSUSED*/
96 void
97 phaser(int v __unused)
98 {
99 int i;
100 int j;
101 struct kling *k;
102 double dx, dy;
103 double anglefactor, distfactor;
104 struct banks *b;
105 int manual, flag, extra = 0;
106 int hit;
107 double tot;
108 int n;
109 int hitreqd[NBANKS];
110 struct banks bank[NBANKS];
111 const struct cvntab *ptr;
112
113 if (Ship.cond == DOCKED) {
114 printf("Phasers cannot fire through starbase shields\n");
115 return;
116 }
117 if (damaged(PHASER)) {
118 out(PHASER);
119 return;
120 }
121 if (Ship.shldup) {
122 printf("Sulu: Captain, we cannot fire through shields.\n");
123 return;
124 }
125 if (Ship.cloaked)
126 {
127 printf("Sulu: Captain, surely you must realize that we cannot fire\n");
128 printf(" phasers with the cloaking device up.\n");
129 return;
130 }
131
132 /* decide if we want manual or automatic mode */
133 manual = 0;
134 if (testnl())
135 {
136 if (damaged(COMPUTER))
137 {
138 printf("%s", Device[COMPUTER].name);
139 manual++;
140 }
141 else
142 if (damaged(SRSCAN))
143 {
144 printf("%s", Device[SRSCAN].name);
145 manual++;
146 }
147 if (manual)
148 printf(" damaged, manual mode selected\n");
149 }
150
151 if (!manual)
152 {
153 ptr = getcodpar("Manual or automatic", Matab);
154 manual = (long) ptr->value;
155 }
156 if (!manual && damaged(COMPUTER))
157 {
158 printf("Computer damaged, manual selected\n");
159 skiptonl(0);
160 manual++;
161 }
162
163 /* initialize the bank[] array */
164 flag = 1;
165 for (i = 0; i < NBANKS; i++)
166 bank[i].units = 0;
167 if (manual)
168 {
169 /* collect manual mode statistics */
170 while (flag)
171 {
172 printf("%d units available\n", Ship.energy);
173 extra = 0;
174 flag = 0;
175 for (i = 0; i < NBANKS; i++)
176 {
177 b = &bank[i];
178 printf("\nBank %d:\n", i);
179 hit = getintpar("units");
180 if (hit < 0)
181 return;
182 if (hit == 0)
183 break;
184 extra += hit;
185 if (extra > Ship.energy)
186 {
187 printf("available energy exceeded. ");
188 skiptonl(0);
189 flag++;
190 break;
191 }
192 b->units = hit;
193 hit = getintpar("course");
194 if (hit < 0 || hit > 360)
195 return;
196 b->angle = hit * 0.0174532925;
197 b->spread = getfltpar("spread");
198 if (b->spread < 0 || b->spread > 1)
199 return;
200 }
201 Ship.energy -= extra;
202 }
203 extra = 0;
204 }
205 else
206 {
207 /* automatic distribution of power */
208 if (Etc.nkling <= 0) {
209 printf("Sulu: But there are no Klingons in this quadrant\n");
210 return;
211 }
212 printf("Phasers locked on target. ");
213 while (flag)
214 {
215 printf("%d units available\n", Ship.energy);
216 hit = getintpar("Units to fire");
217 if (hit <= 0)
218 return;
219 if (hit > Ship.energy)
220 {
221 printf("available energy exceeded. ");
222 skiptonl(0);
223 continue;
224 }
225 flag = 0;
226 Ship.energy -= hit;
227 extra = hit;
228 n = Etc.nkling;
229 if (n > NBANKS)
230 n = NBANKS;
231 tot = n * (n + 1) / 2;
232 for (i = 0; i < n; i++)
233 {
234 k = &Etc.klingon[i];
235 b = &bank[i];
236 distfactor = k->dist;
237 anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON);
238 anglefactor *= GAMMA;
239 distfactor = k->power;
240 distfactor /= anglefactor;
241 hitreqd[i] = distfactor + 0.5;
242 dx = Ship.sectx - k->x;
243 dy = k->y - Ship.secty;
244 b->angle = atan2(dy, dx);
245 b->spread = 0.0;
246 b->units = ((n - i) / tot) * extra;
247 #ifdef xTRACE
248 if (Trace)
249 {
250 printf("b%d hr%d u%d df%.2f af%.2f\n",
251 i, hitreqd[i], b->units,
252 distfactor, anglefactor);
253 }
254 #endif
255 extra -= b->units;
256 hit = b->units - hitreqd[i];
257 if (hit > 0)
258 {
259 extra += hit;
260 b->units -= hit;
261 }
262 }
263
264 /* give out any extra energy we might have around */
265 if (extra > 0)
266 {
267 for (i = 0; i < n; i++)
268 {
269 b = &bank[i];
270 hit = hitreqd[i] - b->units;
271 if (hit <= 0)
272 continue;
273 if (hit >= extra)
274 {
275 b->units += extra;
276 extra = 0;
277 break;
278 }
279 b->units = hitreqd[i];
280 extra -= hit;
281 }
282 if (extra > 0)
283 printf("%d units overkill\n", extra);
284 }
285 }
286 }
287
288 #ifdef xTRACE
289 if (Trace)
290 {
291 for (i = 0; i < NBANKS; i++)
292 {
293 b = &bank[i];
294 printf("b%d u%d", i, b->units);
295 if (b->units > 0)
296 printf(" a%.2f s%.2f\n", b->angle, b->spread);
297 else
298 printf("\n");
299 }
300 }
301 #endif
302
303 /* actually fire the shots */
304 Move.free = 0;
305 for (i = 0; i < NBANKS; i++)
306 {
307 b = &bank[i];
308 if (b->units <= 0)
309 {
310 continue;
311 }
312 printf("\nPhaser bank %d fires:\n", i);
313 n = Etc.nkling;
314 k = Etc.klingon;
315 for (j = 0; j < n; j++)
316 {
317 if (b->units <= 0)
318 break;
319 /*
320 ** The formula for hit is as follows:
321 **
322 ** zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)]
323 ** / (dist ** 2 + EPSILON)]
324 ** * [cos(delta * sigma) + GAMMA]
325 ** * hit
326 **
327 ** where sigma is the spread factor,
328 ** rho is a random number (0 -> 1),
329 ** GAMMA is a crud factor for angle (essentially
330 ** cruds up the spread factor),
331 ** delta is the difference in radians between the
332 ** angle you are shooting at and the actual
333 ** angle of the klingon,
334 ** ALPHA scales down the significance of sigma,
335 ** BETA scales down the significance of rho,
336 ** OMEGA is the magic number which makes everything
337 ** up to "* hit" between zero and one,
338 ** dist is the distance to the klingon
339 ** hit is the number of units in the bank, and
340 ** zap is the amount of the actual hit.
341 **
342 ** Everything up through dist squared should maximize
343 ** at 1.0, so that the distance factor is never
344 ** greater than one. Conveniently, cos() is
345 ** never greater than one, but the same restric-
346 ** tion applies.
347 */
348 distfactor = BETA + franf();
349 distfactor *= ALPHA + b->spread;
350 distfactor *= OMEGA;
351 anglefactor = k->dist;
352 distfactor /= anglefactor * anglefactor + EPSILON;
353 distfactor *= b->units;
354 dx = Ship.sectx - k->x;
355 dy = k->y - Ship.secty;
356 anglefactor = atan2(dy, dx) - b->angle;
357 anglefactor = cos((anglefactor * b->spread) + GAMMA);
358 if (anglefactor < 0.0)
359 {
360 k++;
361 continue;
362 }
363 hit = anglefactor * distfactor + 0.5;
364 k->power -= hit;
365 printf("%d unit hit on Klingon", hit);
366 if (!damaged(SRSCAN))
367 printf(" at %d,%d", k->x, k->y);
368 printf("\n");
369 b->units -= hit;
370 if (k->power <= 0)
371 {
372 killk(k->x, k->y);
373 continue;
374 }
375 k++;
376 }
377 }
378
379 /* compute overkill */
380 for (i = 0; i < NBANKS; i++)
381 extra += bank[i].units;
382 if (extra > 0)
383 printf("\n%d units expended on empty space\n", extra);
384 }