home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / games / trek / phaser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-08  |  9.3 KB  |  370 lines

  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, 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. static char sccsid[] = "@(#)phaser.c    5.4 (Berkeley) 6/1/90";
  36. #endif /* not lint */
  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.     register int        i;
  93.     int            j;
  94.     register struct kling    *k;
  95.     double            dx, dy;
  96.     double            anglefactor, distfactor;
  97.     register 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(Device[COMPUTER].name);
  126.             manual++;
  127.         }
  128.         else
  129.             if (damaged(SRSCAN))
  130.             {
  131.                 printf(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 = (int) 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. }
  370.