|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)phaser.c 5.4 (Berkeley) 6/1/90";
22: #endif /* not lint */
23:
24: # include "trek.h"
25: # include "getpar.h"
26:
27: /* factors for phaser hits; see description below */
28:
29: # define ALPHA 3.0 /* spread */
30: # define BETA 3.0 /* franf() */
31: # define GAMMA 0.30 /* cos(angle) */
32: # define EPSILON 150.0 /* dist ** 2 */
33: # define OMEGA 10.596 /* overall scaling factor */
34:
35: /* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */
36:
37: /*
38: ** Phaser Control
39: **
40: ** There are up to NBANKS phaser banks which may be fired
41: ** simultaneously. There are two modes, "manual" and
42: ** "automatic". In manual mode, you specify exactly which
43: ** direction you want each bank to be aimed, the number
44: ** of units to fire, and the spread angle. In automatic
45: ** mode, you give only the total number of units to fire.
46: **
47: ** The spread is specified as a number between zero and
48: ** one, with zero being minimum spread and one being maximum
49: ** spread. You will normally want zero spread, unless your
50: ** short range scanners are out, in which case you probably
51: ** don't know exactly where the Klingons are. In that case,
52: ** you really don't have any choice except to specify a
53: ** fairly large spread.
54: **
55: ** Phasers spread slightly, even if you specify zero spread.
56: **
57: ** Uses trace flag 30
58: */
59:
60: struct cvntab Matab[] =
61: {
62: "m", "anual", (int (*)())1, 0,
63: "a", "utomatic", 0, 0,
64: 0
65: };
66:
67: struct banks
68: {
69: int units;
70: double angle;
71: double spread;
72: };
73:
74:
75:
76: phaser()
77: {
78: register int i;
79: int j;
80: register struct kling *k;
81: double dx, dy;
82: double anglefactor, distfactor;
83: register struct banks *b;
84: int manual, flag, extra;
85: int hit;
86: double tot;
87: int n;
88: int hitreqd[NBANKS];
89: struct banks bank[NBANKS];
90: struct cvntab *ptr;
91:
92: if (Ship.cond == DOCKED)
93: return(printf("Phasers cannot fire through starbase shields\n"));
94: if (damaged(PHASER))
95: return (out(PHASER));
96: if (Ship.shldup)
97: return (printf("Sulu: Captain, we cannot fire through shields.\n"));
98: if (Ship.cloaked)
99: {
100: printf("Sulu: Captain, surely you must realize that we cannot fire\n");
101: printf(" phasers with the cloaking device up.\n");
102: return;
103: }
104:
105: /* decide if we want manual or automatic mode */
106: manual = 0;
107: if (testnl())
108: {
109: if (damaged(COMPUTER))
110: {
111: printf(Device[COMPUTER].name);
112: manual++;
113: }
114: else
115: if (damaged(SRSCAN))
116: {
117: printf(Device[SRSCAN].name);
118: manual++;
119: }
120: if (manual)
121: printf(" damaged, manual mode selected\n");
122: }
123:
124: if (!manual)
125: {
126: ptr = getcodpar("Manual or automatic", Matab);
127: manual = (int) ptr->value;
128: }
129: if (!manual && damaged(COMPUTER))
130: {
131: printf("Computer damaged, manual selected\n");
132: skiptonl(0);
133: manual++;
134: }
135:
136: /* initialize the bank[] array */
137: flag = 1;
138: for (i = 0; i < NBANKS; i++)
139: bank[i].units = 0;
140: if (manual)
141: {
142: /* collect manual mode statistics */
143: while (flag)
144: {
145: printf("%d units available\n", Ship.energy);
146: extra = 0;
147: flag = 0;
148: for (i = 0; i < NBANKS; i++)
149: {
150: b = &bank[i];
151: printf("\nBank %d:\n", i);
152: hit = getintpar("units");
153: if (hit < 0)
154: return;
155: if (hit == 0)
156: break;
157: extra += hit;
158: if (extra > Ship.energy)
159: {
160: printf("available energy exceeded. ");
161: skiptonl(0);
162: flag++;
163: break;
164: }
165: b->units = hit;
166: hit = getintpar("course");
167: if (hit < 0 || hit > 360)
168: return;
169: b->angle = hit * 0.0174532925;
170: b->spread = getfltpar("spread");
171: if (b->spread < 0 || b->spread > 1)
172: return;
173: }
174: Ship.energy -= extra;
175: }
176: extra = 0;
177: }
178: else
179: {
180: /* automatic distribution of power */
181: if (Etc.nkling <= 0)
182: return (printf("Sulu: But there are no Klingons in this quadrant\n"));
183: printf("Phasers locked on target. ");
184: while (flag)
185: {
186: printf("%d units available\n", Ship.energy);
187: hit = getintpar("Units to fire");
188: if (hit <= 0)
189: return;
190: if (hit > Ship.energy)
191: {
192: printf("available energy exceeded. ");
193: skiptonl(0);
194: continue;
195: }
196: flag = 0;
197: Ship.energy -= hit;
198: extra = hit;
199: n = Etc.nkling;
200: if (n > NBANKS)
201: n = NBANKS;
202: tot = n * (n + 1) / 2;
203: for (i = 0; i < n; i++)
204: {
205: k = &Etc.klingon[i];
206: b = &bank[i];
207: distfactor = k->dist;
208: anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON);
209: anglefactor *= GAMMA;
210: distfactor = k->power;
211: distfactor /= anglefactor;
212: hitreqd[i] = distfactor + 0.5;
213: dx = Ship.sectx - k->x;
214: dy = k->y - Ship.secty;
215: b->angle = atan2(dy, dx);
216: b->spread = 0.0;
217: b->units = ((n - i) / tot) * extra;
218: # ifdef xTRACE
219: if (Trace)
220: {
221: printf("b%d hr%d u%d df%.2f af%.2f\n",
222: i, hitreqd[i], b->units,
223: distfactor, anglefactor);
224: }
225: # endif
226: extra -= b->units;
227: hit = b->units - hitreqd[i];
228: if (hit > 0)
229: {
230: extra += hit;
231: b->units -= hit;
232: }
233: }
234:
235: /* give out any extra energy we might have around */
236: if (extra > 0)
237: {
238: for (i = 0; i < n; i++)
239: {
240: b = &bank[i];
241: hit = hitreqd[i] - b->units;
242: if (hit <= 0)
243: continue;
244: if (hit >= extra)
245: {
246: b->units += extra;
247: extra = 0;
248: break;
249: }
250: b->units = hitreqd[i];
251: extra -= hit;
252: }
253: if (extra > 0)
254: printf("%d units overkill\n", extra);
255: }
256: }
257: }
258:
259: # ifdef xTRACE
260: if (Trace)
261: {
262: for (i = 0; i < NBANKS; i++)
263: {
264: b = &bank[i];
265: printf("b%d u%d", i, b->units);
266: if (b->units > 0)
267: printf(" a%.2f s%.2f\n", b->angle, b->spread);
268: else
269: printf("\n");
270: }
271: }
272: # endif
273:
274: /* actually fire the shots */
275: Move.free = 0;
276: for (i = 0; i < NBANKS; i++)
277: {
278: b = &bank[i];
279: if (b->units <= 0)
280: {
281: continue;
282: }
283: printf("\nPhaser bank %d fires:\n", i);
284: n = Etc.nkling;
285: k = Etc.klingon;
286: for (j = 0; j < n; j++)
287: {
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: {
331: k++;
332: continue;
333: }
334: hit = anglefactor * distfactor + 0.5;
335: k->power -= hit;
336: printf("%d unit hit on Klingon", hit);
337: if (!damaged(SRSCAN))
338: printf(" at %d,%d", k->x, k->y);
339: printf("\n");
340: b->units -= hit;
341: if (k->power <= 0)
342: {
343: killk(k->x, k->y);
344: continue;
345: }
346: k++;
347: }
348: }
349:
350: /* compute overkill */
351: for (i = 0; i < NBANKS; i++)
352: extra += bank[i].units;
353: if (extra > 0)
354: printf("\n%d units expended on empty space\n", extra);
355: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.