phaser.c revision 1.13 1 /* $NetBSD: phaser.c,v 1.13 2009/05/24 21:44:56 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.13 2009/05/24 21:44:56 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 { "m", "anual", (cmdfun) 1, 0 },
81 { "a", "utomatic", (cmdfun) 0, 0 },
82 { NULL, NULL, NULL, 0 }
83 };
84
85 struct banks {
86 int units;
87 double angle;
88 double spread;
89 };
90
91
92
93 /*ARGSUSED*/
94 void
95 phaser(int v __unused)
96 {
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;
110
111 if (Ship.cond == DOCKED) {
112 printf("Phasers cannot fire through starbase shields\n");
113 return;
114 }
115 if (damaged(PHASER)) {
116 out(PHASER);
117 return;
118 }
119 if (Ship.shldup) {
120 printf("Sulu: Captain, we cannot fire through shields.\n");
121 return;
122 }
123 if (Ship.cloaked) {
124 printf("Sulu: Captain, surely you must realize that we cannot fire\n");
125 printf(" phasers with the cloaking device up.\n");
126 return;
127 }
128
129 /* decide if we want manual or automatic mode */
130 manual = 0;
131 if (testnl()) {
132 if (damaged(COMPUTER)) {
133 printf("%s", Device[COMPUTER].name);
134 manual++;
135 } else if (damaged(SRSCAN)) {
136 printf("%s", Device[SRSCAN].name);
137 manual++;
138 }
139 if (manual)
140 printf(" damaged, manual mode selected\n");
141 }
142
143 if (!manual) {
144 ptr = getcodpar("Manual or automatic", Matab);
145 manual = (long) ptr->value;
146 }
147 if (!manual && damaged(COMPUTER)) {
148 printf("Computer damaged, manual selected\n");
149 skiptonl(0);
150 manual++;
151 }
152
153 /* initialize the bank[] array */
154 flag = 1;
155 for (i = 0; i < NBANKS; i++)
156 bank[i].units = 0;
157 if (manual) {
158 /* collect manual mode statistics */
159 while (flag) {
160 printf("%d units available\n", Ship.energy);
161 extra = 0;
162 flag = 0;
163 for (i = 0; i < NBANKS; i++) {
164 b = &bank[i];
165 printf("\nBank %d:\n", i);
166 hit = getintpar("units");
167 if (hit < 0)
168 return;
169 if (hit == 0)
170 break;
171 extra += hit;
172 if (extra > Ship.energy) {
173 printf("available energy exceeded. ");
174 skiptonl(0);
175 flag++;
176 break;
177 }
178 b->units = hit;
179 hit = getintpar("course");
180 if (hit < 0 || hit > 360)
181 return;
182 b->angle = hit * 0.0174532925;
183 b->spread = getfltpar("spread");
184 if (b->spread < 0 || b->spread > 1)
185 return;
186 }
187 Ship.energy -= extra;
188 }
189 extra = 0;
190 } else {
191 /* automatic distribution of power */
192 if (Etc.nkling <= 0) {
193 printf("Sulu: But there are no Klingons in this quadrant\n");
194 return;
195 }
196 printf("Phasers locked on target. ");
197 while (flag) {
198 printf("%d units available\n", Ship.energy);
199 hit = getintpar("Units to fire");
200 if (hit <= 0)
201 return;
202 if (hit > Ship.energy) {
203 printf("available energy exceeded. ");
204 skiptonl(0);
205 continue;
206 }
207 flag = 0;
208 Ship.energy -= hit;
209 extra = hit;
210 n = Etc.nkling;
211 if (n > NBANKS)
212 n = NBANKS;
213 tot = n * (n + 1) / 2;
214 for (i = 0; i < n; i++) {
215 k = &Etc.klingon[i];
216 b = &bank[i];
217 distfactor = k->dist;
218 anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON);
219 anglefactor *= GAMMA;
220 distfactor = k->power;
221 distfactor /= anglefactor;
222 hitreqd[i] = distfactor + 0.5;
223 dx = Ship.sectx - k->x;
224 dy = k->y - Ship.secty;
225 b->angle = atan2(dy, dx);
226 b->spread = 0.0;
227 b->units = ((n - i) / tot) * extra;
228 #ifdef xTRACE
229 if (Trace) {
230 printf("b%d hr%d u%d df%.2f af%.2f\n",
231 i, hitreqd[i], b->units,
232 distfactor, anglefactor);
233 }
234 #endif
235 extra -= b->units;
236 hit = b->units - hitreqd[i];
237 if (hit > 0) {
238 extra += hit;
239 b->units -= hit;
240 }
241 }
242
243 /* give out any extra energy we might have around */
244 if (extra > 0) {
245 for (i = 0; i < n; i++) {
246 b = &bank[i];
247 hit = hitreqd[i] - b->units;
248 if (hit <= 0)
249 continue;
250 if (hit >= extra) {
251 b->units += extra;
252 extra = 0;
253 break;
254 }
255 b->units = hitreqd[i];
256 extra -= hit;
257 }
258 if (extra > 0)
259 printf("%d units overkill\n", extra);
260 }
261 }
262 }
263
264 #ifdef xTRACE
265 if (Trace) {
266 for (i = 0; i < NBANKS; i++) {
267 b = &bank[i];
268 printf("b%d u%d", i, b->units);
269 if (b->units > 0)
270 printf(" a%.2f s%.2f\n", b->angle, b->spread);
271 else
272 printf("\n");
273 }
274 }
275 #endif
276
277 /* actually fire the shots */
278 Move.free = 0;
279 for (i = 0; i < NBANKS; i++) {
280 b = &bank[i];
281 if (b->units <= 0) {
282 continue;
283 }
284 printf("\nPhaser bank %d fires:\n", i);
285 n = Etc.nkling;
286 k = Etc.klingon;
287 for (j = 0; j < n; j++) {
288 if (b->units <= 0)
289 break;
290 /*
291 ** The formula for hit is as follows:
292 **
293 ** zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)]
294 ** / (dist ** 2 + EPSILON)]
295 ** * [cos(delta * sigma) + GAMMA]
296 ** * hit
297 **
298 ** where sigma is the spread factor,
299 ** rho is a random number (0 -> 1),
300 ** GAMMA is a crud factor for angle (essentially
301 ** cruds up the spread factor),
302 ** delta is the difference in radians between the
303 ** angle you are shooting at and the actual
304 ** angle of the klingon,
305 ** ALPHA scales down the significance of sigma,
306 ** BETA scales down the significance of rho,
307 ** OMEGA is the magic number which makes everything
308 ** up to "* hit" between zero and one,
309 ** dist is the distance to the klingon
310 ** hit is the number of units in the bank, and
311 ** zap is the amount of the actual hit.
312 **
313 ** Everything up through dist squared should maximize
314 ** at 1.0, so that the distance factor is never
315 ** greater than one. Conveniently, cos() is
316 ** never greater than one, but the same restric-
317 ** tion applies.
318 */
319 distfactor = BETA + franf();
320 distfactor *= ALPHA + b->spread;
321 distfactor *= OMEGA;
322 anglefactor = k->dist;
323 distfactor /= anglefactor * anglefactor + EPSILON;
324 distfactor *= b->units;
325 dx = Ship.sectx - k->x;
326 dy = k->y - Ship.secty;
327 anglefactor = atan2(dy, dx) - b->angle;
328 anglefactor = cos((anglefactor * b->spread) + GAMMA);
329 if (anglefactor < 0.0) {
330 k++;
331 continue;
332 }
333 hit = anglefactor * distfactor + 0.5;
334 k->power -= hit;
335 printf("%d unit hit on Klingon", hit);
336 if (!damaged(SRSCAN))
337 printf(" at %d,%d", k->x, k->y);
338 printf("\n");
339 b->units -= hit;
340 if (k->power <= 0) {
341 killk(k->x, k->y);
342 continue;
343 }
344 k++;
345 }
346 }
347
348 /* compute overkill */
349 for (i = 0; i < NBANKS; i++)
350 extra += bank[i].units;
351 if (extra > 0)
352 printf("\n%d units expended on empty space\n", extra);
353 }
354