Explicitly mention in RETURN VALUES that socket() sets
[dragonfly.git] / games / trek / phaser.c
1 /*
2  * Copyright (c) 1980, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)phaser.c 8.1 (Berkeley) 5/31/93
34  * $FreeBSD: src/games/trek/phaser.c,v 1.5.2.1 2000/07/20 10:35:07 kris Exp $
35  * $DragonFly: src/games/trek/phaser.c,v 1.2 2003/06/17 04:25:25 dillon Exp $
36  */
37
38 # include       "trek.h"
39 # include       "getpar.h"
40
41 /* factors for phaser hits; see description below */
42
43 # define        ALPHA           3.0             /* spread */
44 # define        BETA            3.0             /* franf() */
45 # define        GAMMA           0.30            /* cos(angle) */
46 # define        EPSILON         150.0           /* dist ** 2 */
47 # define        OMEGA           10.596          /* overall scaling factor */
48
49 /* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */
50
51 /*
52 **  Phaser Control
53 **
54 **      There are up to NBANKS phaser banks which may be fired
55 **      simultaneously.  There are two modes, "manual" and
56 **      "automatic".  In manual mode, you specify exactly which
57 **      direction you want each bank to be aimed, the number
58 **      of units to fire, and the spread angle.  In automatic
59 **      mode, you give only the total number of units to fire.
60 **
61 **      The spread is specified as a number between zero and
62 **      one, with zero being minimum spread and one being maximum
63 **      spread.  You  will normally want zero spread, unless your
64 **      short range scanners are out, in which case you probably
65 **      don't know exactly where the Klingons are.  In that case,
66 **      you really don't have any choice except to specify a
67 **      fairly large spread.
68 **
69 **      Phasers spread slightly, even if you specify zero spread.
70 **
71 **      Uses trace flag 30
72 */
73
74 struct cvntab   Matab[] =
75 {
76         "m",            "anual",                (int (*)())1,           0,
77         "a",            "utomatic",             0,              0,
78         0
79 };
80
81 struct banks
82 {
83         int     units;
84         double  angle;
85         double  spread;
86 };
87
88
89
90 phaser()
91 {
92         int             i;
93         int                     j;
94         struct kling    *k;
95         double                  dx, dy;
96         double                  anglefactor, distfactor;
97         struct banks    *b;
98         int                     manual, flag, extra;
99         int                     hit;
100         double                  tot;
101         int                     n;
102         int                     hitreqd[NBANKS];
103         struct banks            bank[NBANKS];
104         struct cvntab           *ptr;
105
106         if (Ship.cond == DOCKED)
107                 return(printf("Phasers cannot fire through starbase shields\n"));
108         if (damaged(PHASER))
109                 return (out(PHASER));
110         if (Ship.shldup)
111                 return (printf("Sulu: Captain, we cannot fire through shields.\n"));
112         if (Ship.cloaked)
113         {
114                 printf("Sulu: Captain, surely you must realize that we cannot fire\n");
115                 printf("  phasers with the cloaking device up.\n");
116                 return;
117         }
118
119         /* decide if we want manual or automatic mode */
120         manual = 0;
121         if (testnl())
122         {
123                 if (damaged(COMPUTER))
124                 {
125                         printf("%s", Device[COMPUTER].name);
126                         manual++;
127                 }
128                 else
129                         if (damaged(SRSCAN))
130                         {
131                                 printf("%s", Device[SRSCAN].name);
132                                 manual++;
133                         }
134                 if (manual)
135                         printf(" damaged, manual mode selected\n");
136         }
137
138         if (!manual)
139         {
140                 ptr = getcodpar("Manual or automatic", Matab);
141                 manual = (long) ptr->value;
142         }
143         if (!manual && damaged(COMPUTER))
144         {
145                 printf("Computer damaged, manual selected\n");
146                 skiptonl(0);
147                 manual++;
148         }
149
150         /* initialize the bank[] array */
151         flag = 1;
152         for (i = 0; i < NBANKS; i++)
153                 bank[i].units = 0;
154         if (manual)
155         {
156                 /* collect manual mode statistics */
157                 while (flag)
158                 {
159                         printf("%d units available\n", Ship.energy);
160                         extra = 0;
161                         flag = 0;
162                         for (i = 0; i < NBANKS; i++)
163                         {
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                                 {
174                                         printf("available energy exceeded.  ");
175                                         skiptonl(0);
176                                         flag++;
177                                         break;
178                                 }
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;
187                         }
188                         Ship.energy -= extra;
189                 }
190                 extra = 0;
191         }
192         else
193         {
194                 /* automatic distribution of power */
195                 if (Etc.nkling <= 0)
196                         return (printf("Sulu: But there are no Klingons in this quadrant\n"));
197                 printf("Phasers locked on target.  ");
198                 while (flag)
199                 {
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                         {
206                                 printf("available energy exceeded.  ");
207                                 skiptonl(0);
208                                 continue;
209                         }
210                         flag = 0;
211                         Ship.energy -= hit;
212                         extra = hit;
213                         n = Etc.nkling;
214                         if (n > NBANKS)
215                                 n = NBANKS;
216                         tot = n * (n + 1) / 2;
217                         for (i = 0; i < n; i++)
218                         {
219                                 k = &Etc.klingon[i];
220                                 b = &bank[i];
221                                 distfactor = k->dist;
222                                 anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON);
223                                 anglefactor *= GAMMA;
224                                 distfactor = k->power;
225                                 distfactor /= anglefactor;
226                                 hitreqd[i] = distfactor + 0.5;
227                                 dx = Ship.sectx - k->x;
228                                 dy = k->y - Ship.secty;
229                                 b->angle = atan2(dy, dx);
230                                 b->spread = 0.0;
231                                 b->units = ((n - i) / tot) * extra;
232 #                               ifdef xTRACE
233                                 if (Trace)
234                                 {
235                                         printf("b%d hr%d u%d df%.2f af%.2f\n",
236                                                 i, hitreqd[i], b->units,
237                                                 distfactor, anglefactor);
238                                 }
239 #                               endif
240                                 extra -= b->units;
241                                 hit = b->units - hitreqd[i];
242                                 if (hit > 0)
243                                 {
244                                         extra += hit;
245                                         b->units -= hit;
246                                 }
247                         }
248
249                         /* give out any extra energy we might have around */
250                         if (extra > 0)
251                         {
252                                 for (i = 0; i < n; i++)
253                                 {
254                                         b = &bank[i];
255                                         hit = hitreqd[i] - b->units;
256                                         if (hit <= 0)
257                                                 continue;
258                                         if (hit >= extra)
259                                         {
260                                                 b->units += extra;
261                                                 extra = 0;
262                                                 break;
263                                         }
264                                         b->units = hitreqd[i];
265                                         extra -= hit;
266                                 }
267                                 if (extra > 0)
268                                         printf("%d units overkill\n", extra);
269                         }
270                 }
271         }
272
273 #       ifdef xTRACE
274         if (Trace)
275         {
276                 for (i = 0; i < NBANKS; i++)
277                 {
278                         b = &bank[i];
279                         printf("b%d u%d", i, b->units);
280                         if (b->units > 0)
281                                 printf(" a%.2f s%.2f\n", b->angle, b->spread);
282                         else
283                                 printf("\n");
284                 }
285         }
286 #       endif
287
288         /* actually fire the shots */
289         Move.free = 0;
290         for (i = 0; i < NBANKS; i++)
291         {
292                 b = &bank[i];
293                 if (b->units <= 0)
294                 {
295                         continue;
296                 }
297                 printf("\nPhaser bank %d fires:\n", i);
298                 n = Etc.nkling;
299                 k = Etc.klingon;
300                 for (j = 0; j < n; j++)
301                 {
302                         if (b->units <= 0)
303                                 break;
304                         /*
305                         ** The formula for hit is as follows:
306                         **
307                         **  zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)]
308                         **      / (dist ** 2 + EPSILON)]
309                         **      * [cos(delta * sigma) + GAMMA]
310                         **      * hit
311                         **
312                         ** where sigma is the spread factor,
313                         ** rho is a random number (0 -> 1),
314                         ** GAMMA is a crud factor for angle (essentially
315                         **      cruds up the spread factor),
316                         ** delta is the difference in radians between the
317                         **      angle you are shooting at and the actual
318                         **      angle of the klingon,
319                         ** ALPHA scales down the significance of sigma,
320                         ** BETA scales down the significance of rho,
321                         ** OMEGA is the magic number which makes everything
322                         **      up to "* hit" between zero and one,
323                         ** dist is the distance to the klingon
324                         ** hit is the number of units in the bank, and
325                         ** zap is the amount of the actual hit.
326                         **
327                         ** Everything up through dist squared should maximize
328                         ** at 1.0, so that the distance factor is never
329                         ** greater than one.  Conveniently, cos() is
330                         ** never greater than one, but the same restric-
331                         ** tion applies.
332                         */
333                         distfactor = BETA + franf();
334                         distfactor *= ALPHA + b->spread;
335                         distfactor *= OMEGA;
336                         anglefactor = k->dist;
337                         distfactor /= anglefactor * anglefactor + EPSILON;
338                         distfactor *= b->units;
339                         dx = Ship.sectx - k->x;
340                         dy = k->y - Ship.secty;
341                         anglefactor = atan2(dy, dx) - b->angle;
342                         anglefactor = cos((anglefactor * b->spread) + GAMMA);
343                         if (anglefactor < 0.0)
344                         {
345                                 k++;
346                                 continue;
347                         }
348                         hit = anglefactor * distfactor + 0.5;
349                         k->power -= hit;
350                         printf("%d unit hit on Klingon", hit);
351                         if (!damaged(SRSCAN))
352                                 printf(" at %d,%d", k->x, k->y);
353                         printf("\n");
354                         b->units -= hit;
355                         if (k->power <= 0)
356                         {
357                                 killk(k->x, k->y);
358                                 continue;
359                         }
360                         k++;
361                 }
362         }
363
364         /* compute overkill */
365         for (i = 0; i < NBANKS; i++)
366                 extra += bank[i].units;
367         if (extra > 0)
368                 printf("\n%d units expended on empty space\n", extra);
369 }