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