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