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