Expand PMF_FN_* macros.
[netbsd-mini2440.git] / games / trek / phaser.c
blobc3e8d1e8d6531646c3a215477fc245e73080e9b0
1 /* $NetBSD: phaser.c,v 1.14 2009/05/24 22:55:03 dholland Exp $ */
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
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.14 2009/05/24 22:55:03 dholland Exp $");
38 #endif
39 #endif /* not lint */
41 #include <stdio.h>
42 #include <math.h>
43 #include "trek.h"
44 #include "getpar.h"
46 /* factors for phaser hits; see description below */
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 */
54 /* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */
57 ** Phaser Control
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.
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.
74 ** Phasers spread slightly, even if you specify zero spread.
76 ** Uses trace flag 30
79 static struct cvntab Matab[] = {
80 { "m", "anual", (cmdfun) 1, 0 },
81 { "a", "utomatic", (cmdfun) 0, 0 },
82 { NULL, NULL, NULL, 0 }
85 struct banks {
86 int units;
87 double angle;
88 double spread;
93 /*ARGSUSED*/
94 void
95 phaser(int v __unused)
97 int i;
98 int j;
99 struct kling *k;
100 double dx, dy;
101 double anglefactor, distfactor;
102 struct banks *b;
103 int manual, flag, extra = 0;
104 int hit;
105 double tot;
106 int n;
107 int hitreqd[NBANKS];
108 struct banks bank[NBANKS];
109 const struct cvntab *ptr;
111 if (Ship.cond == DOCKED) {
112 printf("Phasers cannot fire through starbase shields\n");
113 return;
115 if (damaged(PHASER)) {
116 out(PHASER);
117 return;
119 if (Ship.shldup) {
120 printf("Sulu: Captain, we cannot fire through shields.\n");
121 return;
123 if (Ship.cloaked) {
124 printf("Sulu: Captain, surely you must realize that we cannot "
125 "fire\n");
126 printf(" phasers with the cloaking device up.\n");
127 return;
130 /* decide if we want manual or automatic mode */
131 manual = 0;
132 if (testnl()) {
133 if (damaged(COMPUTER)) {
134 printf("%s", Device[COMPUTER].name);
135 manual++;
136 } else if (damaged(SRSCAN)) {
137 printf("%s", Device[SRSCAN].name);
138 manual++;
140 if (manual)
141 printf(" damaged, manual mode selected\n");
144 if (!manual) {
145 ptr = getcodpar("Manual or automatic", Matab);
146 manual = (long) ptr->value;
148 if (!manual && damaged(COMPUTER)) {
149 printf("Computer damaged, manual selected\n");
150 skiptonl(0);
151 manual++;
154 /* initialize the bank[] array */
155 flag = 1;
156 for (i = 0; i < NBANKS; i++)
157 bank[i].units = 0;
158 if (manual) {
159 /* collect manual mode statistics */
160 while (flag) {
161 printf("%d units available\n", Ship.energy);
162 extra = 0;
163 flag = 0;
164 for (i = 0; i < NBANKS; i++) {
165 b = &bank[i];
166 printf("\nBank %d:\n", i);
167 hit = getintpar("units");
168 if (hit < 0)
169 return;
170 if (hit == 0)
171 break;
172 extra += hit;
173 if (extra > Ship.energy) {
174 printf("available energy exceeded. ");
175 skiptonl(0);
176 flag++;
177 break;
179 b->units = hit;
180 hit = getintpar("course");
181 if (hit < 0 || hit > 360)
182 return;
183 b->angle = hit * 0.0174532925;
184 b->spread = getfltpar("spread");
185 if (b->spread < 0 || b->spread > 1)
186 return;
188 Ship.energy -= extra;
190 extra = 0;
191 } else {
192 /* automatic distribution of power */
193 if (Etc.nkling <= 0) {
194 printf("Sulu: But there are no Klingons in this "
195 "quadrant\n");
196 return;
198 printf("Phasers locked on target. ");
199 while (flag) {
200 printf("%d units available\n", Ship.energy);
201 hit = getintpar("Units to fire");
202 if (hit <= 0)
203 return;
204 if (hit > Ship.energy) {
205 printf("available energy exceeded. ");
206 skiptonl(0);
207 continue;
209 flag = 0;
210 Ship.energy -= hit;
211 extra = hit;
212 n = Etc.nkling;
213 if (n > NBANKS)
214 n = NBANKS;
215 tot = n * (n + 1) / 2;
216 for (i = 0; i < n; i++) {
217 k = &Etc.klingon[i];
218 b = &bank[i];
219 distfactor = k->dist;
220 anglefactor = ALPHA * BETA * OMEGA /
221 (distfactor * distfactor + EPSILON);
222 anglefactor *= GAMMA;
223 distfactor = k->power;
224 distfactor /= anglefactor;
225 hitreqd[i] = distfactor + 0.5;
226 dx = Ship.sectx - k->x;
227 dy = k->y - Ship.secty;
228 b->angle = atan2(dy, dx);
229 b->spread = 0.0;
230 b->units = ((n - i) / tot) * extra;
231 #ifdef xTRACE
232 if (Trace) {
233 printf("b%d hr%d u%d df%.2f af%.2f\n",
234 i, hitreqd[i], b->units,
235 distfactor, anglefactor);
237 #endif
238 extra -= b->units;
239 hit = b->units - hitreqd[i];
240 if (hit > 0) {
241 extra += hit;
242 b->units -= hit;
246 /* give out any extra energy we might have around */
247 if (extra > 0) {
248 for (i = 0; i < n; i++) {
249 b = &bank[i];
250 hit = hitreqd[i] - b->units;
251 if (hit <= 0)
252 continue;
253 if (hit >= extra) {
254 b->units += extra;
255 extra = 0;
256 break;
258 b->units = hitreqd[i];
259 extra -= hit;
261 if (extra > 0)
262 printf("%d units overkill\n", extra);
267 #ifdef xTRACE
268 if (Trace) {
269 for (i = 0; i < NBANKS; i++) {
270 b = &bank[i];
271 printf("b%d u%d", i, b->units);
272 if (b->units > 0)
273 printf(" a%.2f s%.2f\n", b->angle, b->spread);
274 else
275 printf("\n");
278 #endif
280 /* actually fire the shots */
281 Move.free = 0;
282 for (i = 0; i < NBANKS; i++) {
283 b = &bank[i];
284 if (b->units <= 0) {
285 continue;
287 printf("\nPhaser bank %d fires:\n", i);
288 n = Etc.nkling;
289 k = Etc.klingon;
290 for (j = 0; j < n; j++) {
291 if (b->units <= 0)
292 break;
294 ** The formula for hit is as follows:
296 ** zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)]
297 ** / (dist ** 2 + EPSILON)]
298 ** * [cos(delta * sigma) + GAMMA]
299 ** * hit
301 ** where sigma is the spread factor,
302 ** rho is a random number (0 -> 1),
303 ** GAMMA is a crud factor for angle (essentially
304 ** cruds up the spread factor),
305 ** delta is the difference in radians between the
306 ** angle you are shooting at and the actual
307 ** angle of the klingon,
308 ** ALPHA scales down the significance of sigma,
309 ** BETA scales down the significance of rho,
310 ** OMEGA is the magic number which makes everything
311 ** up to "* hit" between zero and one,
312 ** dist is the distance to the klingon
313 ** hit is the number of units in the bank, and
314 ** zap is the amount of the actual hit.
316 ** Everything up through dist squared should maximize
317 ** at 1.0, so that the distance factor is never
318 ** greater than one. Conveniently, cos() is
319 ** never greater than one, but the same restric-
320 ** tion applies.
322 distfactor = BETA + franf();
323 distfactor *= ALPHA + b->spread;
324 distfactor *= OMEGA;
325 anglefactor = k->dist;
326 distfactor /= anglefactor * anglefactor + EPSILON;
327 distfactor *= b->units;
328 dx = Ship.sectx - k->x;
329 dy = k->y - Ship.secty;
330 anglefactor = atan2(dy, dx) - b->angle;
331 anglefactor = cos((anglefactor * b->spread) + GAMMA);
332 if (anglefactor < 0.0) {
333 k++;
334 continue;
336 hit = anglefactor * distfactor + 0.5;
337 k->power -= hit;
338 printf("%d unit hit on Klingon", hit);
339 if (!damaged(SRSCAN))
340 printf(" at %d,%d", k->x, k->y);
341 printf("\n");
342 b->units -= hit;
343 if (k->power <= 0) {
344 killk(k->x, k->y);
345 continue;
347 k++;
351 /* compute overkill */
352 for (i = 0; i < NBANKS; i++)
353 extra += bank[i].units;
354 if (extra > 0)
355 printf("\n%d units expended on empty space\n", extra);