Logo Search packages:      
Sourcecode: acm version File versions  Download package

m61a1.c

/*
 *  acm : an aerial combat simulator for X
 *  Copyright (C) 1991-1997  Riley Rainey
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 dated June, 1991.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program;  if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
 */

#include <math.h>
#include <stdio.h>
#include <string.h>

#include "pm.h"
#ifdef HAVE_DIS
#include "dis.h"
#endif

#define BORE_CROSS_SIZE 7
#define MUZZLE_VELOCITY (3.2808 * 1036.0)
#define TRACER_MOD      10
#define OFFSET_ANGLE    (DEGtoRAD(6.0))         /* the gun points up at this angle */
#define RATE_OF_FIRE    (3000.0 / 60.0)         /* rounds per second */
#define FUZZ            (DEGtoRAD(1.0))         /* distribution due to vibration */

int       select_m61a1(craft *);
int       display_m61a1(craft *, craftType *, viewer *, int *, int *);
int       update_m61a1(craft *);
int       press_m61a1(craft *);
int       release_m61a1(craft *);
extern FILE *acm_fopen(char *name, char *access);
extern int acm_rand PARAMS((void));
void      lcos(craft * c, viewer * u, int *x, int *y);
extern int
          dis_fire_cannon(craft * c, VPoint * pos, VPoint * vel, int quantity, int rate);
int       isCannonHit(double min, craft * c);

int       cdebug = 0;               /* set to 1 to debug cannon fire */

weaponDesc m61a1Desc =
{
      WK_M61A1,
      select_m61a1,                       /* select */
      update_m61a1,                       /* update */
      display_m61a1,                      /* display procedure */
      press_m61a1,                        /* fire */
      release_m61a1,                      /* fire button release */
};

/*
 *  We'll take a running average of our pitch and yaw rates to keep the
 *  aiming reticle from jumping all over the screen.
 */

#define HIST      8

typedef struct {
      double    pitch_hist[HIST];
      double    yaw_hist[HIST];
      int       cur;                      /* current entry in the histories */
      int       count;              /* number of valid entries */
      double    pitch_total;
      double    yaw_total;
} hist_t;

static hist_t history[MAXPLAYERS];

/*
 *  m61a1 selection function
 *
 *  A selection function normally determines whether there are any weapons
 *  of this type on-board.  If so, and the weapon system is functional
 *  (in other words, undamaged) then return 1; otherwise return 0.
 */

int
select_m61a1(craft * c)
{

      hist_t   *p;

      p = &history[c->pIndex];
      p->count = p->cur = 0;
      p->pitch_total = p->yaw_total = 0.0;

/*
 *  The cannon must be located at station zero, for now.  We should
 *  change that.
 */

      if (strcmp(c->station[0].type, "m61a1") == 0 && c->station[0].info > 0) {
            c->station[0].info4 = 0.0;
            return 1;
      }
      else
            return 0;

}

/*
 *  m61a1 display function
 *
 *  Update the HUD display strings associated with this weapon system.
 */

/*ARGSUSED */
int
display_m61a1(craft * c, craftType * w, viewer * u, int *x, int *y)
{

      char      s[16];
      register int tx, ty, m;
      XSegment  seg[2];
      hist_t   *p;

      p = &history[c->pIndex];
      if ((m = p->cur = p->cur + 1) >= HIST)
            m = p->cur = 0;
      if (p->count != HIST)
            (p->count)++;
      else {
            p->pitch_total -= p->pitch_hist[m];
            p->yaw_total -= p->yaw_hist[m];
      }
      p->pitch_hist[m] = c->q;
      p->yaw_hist[m] = c->r;
      p->pitch_total += c->q;
      p->yaw_total += c->r;

      strcpy(c->leftHUD[2], "LCOS");
      sprintf(s, "%.3d M-61A1", c->station[0].info);
      strcpy(c->leftHUD[3], s);
      if (c->station[0].info3)
            strcpy(c->leftHUD[4], "FIRING");
      else
            strcpy(c->leftHUD[4], "");

/*
 *  Draw the boresight cross
 */

      m = (int) ((double) BORE_CROSS_SIZE * u->scaleFactor);

      tx = u->xCenter;
      ty = u->yCenter - (int) (3.0 * 9.0 * u->scaleFactor + 0.5);
      seg[0].x1 = tx - m;
      seg[0].x2 = tx + m;
      seg[0].y1 = seg[0].y2 = ty;
      seg[1].x1 = seg[1].x2 = tx;
      seg[1].y1 = ty - m;
      seg[1].y2 = ty + m;
      VDrawSegments(u->v, seg, 2, (Color) u->v->pixel[HUDPixel]);

/*
 *  Plot the reticle.
 */

      lcos(c, u, x, y);

      return 0;

}

int
press_m61a1(craft * c)
{
      c->station[0].info3 |= 1;
      if (c->station[0].info > 0) {
            playContinuousSound(c, SoundCannonFiring);
      }
      return 0;
}

int
release_m61a1(craft * c)
{
      c->station[0].info3 &= ~1;
      c->station[0].info4 = 0.0;
      stopSound(c, SoundCannonFiring);
      return 0;
}

int
update_m61a1(craft * c)
{

      craft    *m;
      int       i;
      VPoint    tmp, tmp1, mvel;
      double    fuzz, fuzzAngle, phiY, phiZ, tm, mv = MUZZLE_VELOCITY;

      if (c->station[0].info3 == 0)
            return 0;

/*
 *  Got any ammunition ?
 */

      if (c->station[0].info <= 0)
            return -1;

/*
 *  It is possible (especially on today's faster machines) that no rounds
 *  actually left the barrel during this time interval.
 */

      if (c->station[0].info4 > deltaT) {
            if (cdebug) {
                  printf("no rounds interval offset = %.3f, deltaT = %.3f\n",
                           c->station[0].info4, deltaT);
            }
            c->station[0].info4 -= deltaT;
      }
      else {

/*
 *  Allocate a projectile record
 */

            for ((i = 0, m = &mtbl[0]); i < MAXPROJECTILES; (++i, ++m))
                  if (m->type == CT_FREE) {
                        m->type = CT_CANNON;
                        break;
                  }
            if (i == MAXPROJECTILES)
                  return -1;

/*
 *  Determine how far we're fuzzed off the ideal boresight.
 */

            fuzz = ((double) (acm_rand() & 32767) +
                        (double) (acm_rand() & 32767)) / 32767.0 - 1.0;
            fuzz = fuzz * FUZZ;
            fuzzAngle = 2.0 * pi * (double) (acm_rand() & 511) / 511.0;

/*
 *  Determine the initial velocity of the projectile stream.
 */

            phiZ = fuzz * sin(fuzzAngle);
            phiY = fuzz * cos(fuzzAngle);
            tm = mv * cos(OFFSET_ANGLE + phiZ);

            tmp.x = tm * cos(phiY);
            tmp.y = tm * sin(phiY);
            tmp.z = mv * sin(-OFFSET_ANGLE + phiZ);
            VTransform(&tmp, &(c->trihedral), &mvel);

            m->owner = c->pIndex;
            m->createTime = curTime;

            m->gvs_instance = (GVS_OBI) NULL;

            m->curRoll = c->curRoll;
            m->curPitch = c->curPitch;
            m->curHeading = c->curHeading;

            m->Cg = c->Cg;
            m->Cg.x += mvel.x;
            m->Cg.y += mvel.y;
            m->Cg.z += mvel.z;

/*
 *  Determine the initial position.
 */

            VTransform_(&c->cinfo->wStation[0], &c->trihedral, &tmp1);
            VReverseTransform_(&tmp1, &c->XYZtoNED, &tmp);
            m->Sg.x = c->Sg.x + FEETtoMETERS(tmp.x);
            m->Sg.y = c->Sg.y + FEETtoMETERS(tmp.y);
            m->Sg.z = c->Sg.z + FEETtoMETERS(tmp.z);
            m->prevSg = m->Sg;

            DISGeocentricToWorldCoordinates
                  ((dis_world_coordinates *) & m->Sg, &m->w);
            m->prevw = m->w;
            GenerateWorldToLocalMatrix(&m->w, &m->XYZtoNED);

/*
 *  Subtract the number of rounds fired.
 */

            m->offset = c->station[0].info4;
            m->interval = deltaT;
            m->rounds = 1 + (int) (RATE_OF_FIRE * (deltaT - m->offset));
            m->rounds = (m->rounds > c->station[0].info) ?
                  c->station[0].info : m->rounds;
            if (cdebug) {
                  printf("rounds = %d, offset = %.3f sec, interval = %.4f\n",
                           m->rounds, m->offset, m->interval);
            }

/*
 *  Compute time interval until the next round leaves the barrel (in a
 *  subsequent time interval).
 */

            c->station[0].info4 = 1.0 / RATE_OF_FIRE -
                  fmod(deltaT - m->offset, 1.0 / RATE_OF_FIRE);

/*
 *  include tracer information
 */

            m->tracerMod = TRACER_MOD;
            m->tracerVal = c->station[0].info2 % m->tracerMod;
            if (arcadeMode == 0) {
                  c->station[0].info -= m->rounds;
            }
            c->station[0].info2 += m->rounds;

            m->cinfo = lookupCraft("m61a1 cannon");

#ifdef HAVE_DIS
            dis_fire_cannon(c, &m->Sg, &m->Cg, m->rounds, (int) RATE_OF_FIRE);
#endif

      }

      if (c->station[0].info <= 0) {
            stopSound(c, SoundCannonFiring);
      }
      return 0;

}

extern craftType *newCraft(void);

int
placeCannon(Viewport * vp, craft * c, VMatrix * m, VPolygon ** poly, long *cnt)
{

      double    t, startT;
      VPoint    v, s;
      int       i, j, k, n;
      VPoint   *q, tmp;
      VPolygon **p;

/*
 *  Reduce the shell path to a set of parametric equations.
 */

      v.x = c->Sg.x - c->prevSg.x;
      v.y = c->Sg.y - c->prevSg.y;
      v.z = c->Sg.z - c->prevSg.z;

/*
 *  Now add each tracer shell to the view.
 */

      startT = (c->offset + (c->tracerVal / RATE_OF_FIRE)) / c->interval;

      for (t = startT; t <= 1.0; t += TRACER_MOD / (RATE_OF_FIRE * c->interval)) {

            s.x = -v.x * t;
            s.y = -v.y * t;
            s.z = -v.z * t;

/* TODO: check should be based on local altitude */
/* underground? don't plot it */

            if (c->w.z + s.z < 0.0) {
                  continue;
            }

            n = c->cinfo->object->numPolys;
            p = c->cinfo->object->polygon;
            j = *cnt;
            for (i = 0; i < n; ++i) {
                  poly[j] = VCopyPolygon(p[i]);
                  for ((k = 0, q = poly[j]->vertex); k < poly[j]->numVtces; (++k, ++q)) {
                        VTransform(q, m, &tmp);
                        tmp.x += s.x;
                        tmp.y += s.y;
                        tmp.z += s.z;
                        *q = tmp;
                  }
                  VTransformPolygon(poly[j], &vp->eyeSpace);
                  ++j;
            }
            *cnt = j;
      }

      return 0;
}

void
initm61a1(void)
{

      craftType *c;
      FILE     *f;
      dis_entity_type em1 =
      {2, 9, 225, 2, 1, 0, 0};
      dis_entity_type em2 =
      {2, 1, 222, 2, 3, 0, 0};

      wtbl[1] = m61a1Desc;

      c = newCraft();
      c->name = strdup("m61a1 cannon");

      c->entityType = em1;
      c->altEntityType = em2;

      c->placeProc = placeCannon;

      f = acm_fopen("tracer.obv", "r");
      c->object = VReadObject(f);
      fclose(f);

}

int
cannonCalculations(craft * c)
{
      double    dNorth, dEast, dmag;

/*
 *  Kill projectile streams after 10.0 seconds of flight or when
 *  they strike the ground.
 */

      if (curTime - c->createTime > 10.0)
            return 1;

/* TODO */
      if (c->w.z < 0.0) {
            return 1;
      }

      c->prevSg = c->Sg;
      c->prevw = c->w;

      dNorth  = FEETtoMETERS(c->Cg.x * deltaT);
      dEast   = FEETtoMETERS(c->Cg.y * deltaT);
      c->w.z -= FEETtoMETERS(c->Cg.z * deltaT + earth_g * halfDeltaTSquared);

      dmag = sqrt(dNorth * dNorth + dEast * dEast);

      DISUpdateWorldCoordinates(&c->w, dNorth / dmag, dEast / dmag, dmag);
      DISWorldCoordinatesToGeocentric(&c->w,
                                                      (dis_world_coordinates *) & c->Sg);

      c->Cg.z += earth_g * deltaT;

      return 0;

}

/*
 *  plotReticle :  draws the aiming reticle onto the HUD.
 *
 *  An aiming reticle is a circle with an inner arc that clues the
 *  pilot as to the range of the target.  Twelve tic marks are used
 *  to demarcate the range -- each tic represents 1000 feet of
 *  distance.
 */

static struct {
      double    x, y;
} ticTable[12] = {

      {
            0.0, -1.0
      },
      {
            0.5, -0.866
      },
      {
            0.866, -0.5
      },
      {
            1.0, 0.0
      },
      {
            0.866, 0.5
      },
      {
            0.5, 0.866
      },
      {
            0.0, 1.0
      },
      {
            -0.5, 0.866
      },
      {
            -0.866, 0.5
      },
      {
            -1.0, 0.0
      },
      {
            -0.866, -0.5
      },
      {
            -0.5, -0.866
      }
};

/*ARGSUSED */
void
plotReticle(craft * c, viewer * u, int x, int y, int range)
{

#define RETICLE_SIZE    65
#define RANGE_SIZE      59
#define TICK_SIZE (RETICLE_SIZE + 12)

      register int i, size, xt, yt, size1, xt1, yt1, nseg, arc;
      XSegment  seg[16];
      register double rs, rt;

      size = (int) (RETICLE_SIZE * u->scaleFactor);
      if ((size & 1) == 0)
            ++size;                             /* insure it is an odd value */
      xt = x - size / 2;
      yt = y - size / 2;
      rs = size / 2;
      rt = ((TICK_SIZE + 1) / 2) * u->scaleFactor;

      for (i = 0; i < 12; i++) {
            seg[i].x1 = x +
                  (int) (rs * ticTable[i].x + 0.5);
            seg[i].y1 = y +
                  (int) (rs * ticTable[i].y + 0.5);
            seg[i].x2 = x +
                  (int) (rt * ticTable[i].x + 0.5);
            seg[i].y2 = y +
                  (int) (rt * ticTable[i].y + 0.5);
      }

      nseg = 12;
      VDrawArc(u->v, xt, yt, size, size, 0,
                   360 * 64, (Color) (u->v->pixel[HUDPixel]));

      if (range != -1) {
            if (range > 12000)
                  range = 12000;
            arc = -range * 23040 / 12000;
            size1 = (int) (RANGE_SIZE * u->scaleFactor);
            if ((size1 & 1) == 0)
                  ++size1;
            if (size == size1)
                  --size1;
            xt1 = x - size1 / 2;
            yt1 = y - size1 / 2;
            VDrawArc(u->v, xt1, yt1, size1, size1,
                         90 * 64, arc, (Color) (u->v->pixel[HUDPixel]));
      }
      VDrawSegments(u->v, seg, nseg, (Color) (u->v->pixel[HUDPixel]));

}

void
lcos(craft * c, viewer * u, int *x, int *y)
{

/*
 *  How does this LCOS thing work, anyway?
 *
 *  First, let me say that this may or, more probably, may not look
 *  anything like the technique used in a real fighter's gun sighting
 *  system.  Having said that, here's the basic assumptions and steps
 *  used to generate the reticle on the HUD:
 *
 *  1)  Using radar, we know the distance to the target.  Assuming that the
 *      radar is in working order and is locked onto something.
 *
 *  2)  We know the muzzle velocity of the shells we're firing and can
 *      use that value to closely estimate the flight time of the shells
 *      to a target that's a certain distance away (the target).  Call
 *      this value "fTime".
 *
 *  3)  Use the muzzle velocity vector to determine the
 *      relative position (w.r.t. our craft) of a shell "fTime" seconds into
 *      its flight.  Call this vector "pos".
 *
 *  4)  Gravity will accelerate the shells. Use d = 0.5 * g * t ^ 2
 *      to add a distance (along the Z axis that will approximate the
 *      effect of gravity.  Add that to "pos".
 *
 *  5)  We know our pitch and yaw rates.  These rotations will have the
 *      effect of visually "bending" the cannon stream, from the pilot's
 *      perspective.  Use the values to generate a matrix to transform
 *      "pos" by an amount proportional to our "fTime" value.
 *
 *  6)  Convert our "pos" vector to screen x,y coordinates and call
 *      plotReticle.
 */

      double    fTime, range, gm, pitch_rate, yaw_rate;
      VPoint    pos, tmp;
      VPoint    zg, z;
      VMatrix   rotation;
      int       clue;
      hist_t   *hist;

      hist = &history[c->pIndex];

/*  Step 1  */

      if (c->curRadarTarget >= 0)
            range = c->targetDistance;
      else
            range = 2500.0;

/*  Step 2  */

      fTime = range / MUZZLE_VELOCITY;

/*  Step 3  */

      pos.x = fTime * MUZZLE_VELOCITY * cos(OFFSET_ANGLE);
      pos.y = 0.0;
      pos.z = -fTime * MUZZLE_VELOCITY * sin(OFFSET_ANGLE);

/*  Step 4  */

      zg.x = zg.y = 0.0;
      zg.z = 1.0;

      VReverseTransform_(&zg, &c->trihedral, &z);

      gm = 0.5 * earth_g * fTime * fTime;
      pos.x += z.x * gm;
      pos.y += z.y * gm;
      pos.z += z.z * gm;

/*  Step 5  */

      VIdentMatrix(&rotation);

      pitch_rate = hist->pitch_total / (double) hist->count;
      yaw_rate = hist->yaw_total / (double) hist->count;

      if (pitch_rate != 0.0)
            VRotate(&rotation, YRotation, pitch_rate * fTime);
      if (yaw_rate != 0.0)
            VRotate(&rotation, ZRotation, yaw_rate * fTime);

      VTransform(&pos, &rotation, &tmp);

/*  Step 6  */

      *x = (u->v->Middl.x + (int) (tmp.y * u->v->Scale.x / tmp.x)) >> 2;
      *y = (u->v->Middl.y + (int) (tmp.z * u->v->Scale.y / tmp.x)) >> 2;

      if (c->curRadarTarget >= 0)
            clue = (int) c->targetDistance;
      else
            clue = -1;

      plotReticle(c, u, *x, *y, clue);
}

/*
 *  lookForCannonImpacts : Track cannon shells and look for impacts with
 *                         aircraft.  This algorithm tracks each shell's
 *                         flight.
 */

typedef struct _entry {
      double    time;
      double    min;
      VPoint    Sg;
      VPoint    rvel;
      craft    *c;
      struct _entry *next;
} entry;

extern int cdebug;

void
lookForCannonImpacts(craft * m)
{

      craft    *c;
      entry     p[MAXPLAYERS], *list, *q, *r, *rprev;
      VPoint    v, s0, prevSg, Vm, zeroVec = {0, 0, 0};
      double    t, d, roundT, startT, explosion_diameter_meters;
      int       j;

#ifdef HAVE_DIS
      double    worldLocation[3], entityLocation[3];

#endif

      startT = m->offset / m->interval;

      Vm.x = m->Sg.x - m->prevSg.x;
      Vm.y = m->Sg.y - m->prevSg.y;
      Vm.z = m->Sg.z - m->prevSg.z;

      for (roundT = startT; roundT < 1.0; roundT += 1.0 / (RATE_OF_FIRE * m->interval)) {

            prevSg.x = m->prevSg.x - Vm.x * (1.0 - roundT);
            prevSg.y = m->prevSg.y - Vm.y * (1.0 - roundT);
            prevSg.z = m->prevSg.z - Vm.z * (1.0 - roundT);

            list = (entry *) NULL;
            for (c = ptbl, j = 0; j < MAXPLAYERS; ++j, ++c) {

                  if (c->type == CT_FREE || m->owner == c->pIndex)
                        continue;

/*
 * Reduce the relative motion of this object to a the parametric system
 * of equations:
 *              x(t) = vx * t + s0x
 *              y(t) = vy * t + s0y
 *              z(t) = vz * t + s0z
 *
 * We can then compute the time of perigee (closest pass) along with
 * the associated minimum distance.
 */

                  v.x = c->Sg.x - c->prevSg.x - Vm.x;
                  v.y = c->Sg.y - c->prevSg.y - Vm.y;
                  v.z = c->Sg.z - c->prevSg.z - Vm.z;
                  s0.x = c->prevSg.x - prevSg.x;
                  s0.y = c->prevSg.y - prevSg.y;
                  s0.z = c->prevSg.z - prevSg.z;

/*
 * Compute time of minimum distance between the two objects (note that units
 * here are UPDATE_INTERVAL seconds).
 */

                  t = -(v.x * s0.x + v.y * s0.y + v.z * s0.z) /
                        (v.x * v.x + v.y * v.y + v.z * v.z);

                  if (cdebug) {
                        printf("perigee in %g seconds with player %d\n",
                                 t * deltaT, j);
                  }

/*
 *  If the closest pass occurs during this update interval, check for a hit.
 *  We'll build a linked list of all craft that this projectile may strike
 *  during this period, arranged in ascending order by time of "perigee"
 *  (closest pass).  We'll then test for strikes.  If a projectile misses
 *  the first object, then it may have struck subsequent objects in the
 *  list ...
 */

/*
 *  One special case occurs when a target or missile's turn suddenly
 *  changes the perigee time from positive to negative.  If the missile
 *  is within hitting range at t=0 and the time of perigee is negative,
 *  then zap 'em.
 */

                  if (t < 0.0) {
                        d = sqrt(s0.x * s0.x + s0.y * s0.y +
                                     s0.z * s0.z);
                        if (isCannonHit(d, c)) {
                              t = 0.0;
                        }
                  }
                  if (t >= 0.0 && t <= 1.0) {
                        q = &p[j];

                        q->Sg = prevSg;
                        q->Sg.x += Vm.x * t;
                        q->Sg.y += Vm.y * t;
                        q->Sg.z += Vm.z * t;

                        q->rvel = v;

                        if (list == (entry *) NULL) {
                              q->next = list;
                              list = q;
                        }
                        else if (list->time > t) {
                              q->next = list;
                              list = q;
                        }
                        else {
                              for (rprev = list, r = list->next; r != (entry *) NULL;) {
                                    if (r->time > t)
                                          break;
                                    rprev = r;
                                    r = r->next;
                              }
                              if (rprev != list)
                                    rprev->next = q;
                              q->next = r;
                        }
                        q->time = t;
                        q->c = c;
                        q->min = sqrt(pow(v.x * t + s0.x, 2.0) +
                                            pow(v.y * t + s0.y, 2.0) +
                                            pow(v.z * t + s0.z, 2.0));
                        if (cdebug) {
                              printf("perigee %g feet; craft %d.\n",
                                       q->min, j);
                        }
                  }
            }

/*
 *  Now look for cannon hits in the list of perigees.
 */

            for (r = list; r != (entry *) NULL; r = r->next)
                  if (isCannonHit(r->min, r->c)) {
                        newExplosion(&(r->Sg), &zeroVec, 1.0, 2.0, 0.5);
#ifdef HAVE_DIS
                        /* can only damage local player */
                        if (r->c->type != CT_DIS_PLANE)
#endif
                              if (absorbDISDamage(r->c, &m->cinfo->entityType, 0, 0,
                                                            0.0,
                                                            mag(r->rvel),
                                                            &explosion_diameter_meters) == 0) {

                                    killPlayerEx(r->c,
                                       "Your aircraft was destroyed by cannon fire.",
                                                 "No further information is available.");
                              }
#ifdef HAVE_DIS
                        worldLocation[0] = r->Sg.x;
                        worldLocation[1] = r->Sg.y;
                        worldLocation[2] = r->Sg.z;
                        entityLocation[0] = 0.0;
                        entityLocation[1] = 0.0;
                        entityLocation[2] = 0.0;
                        if (disInUse)
                              dis_detonation( &m->cinfo->entityType,
                                                   c->disId, r->c->disId,
                                                   DIS_ID_NONE, worldLocation, entityLocation,
                                                   (double *) &r->rvel );
#endif
                        break;
                  }
      }
}

/*ARGSUSED */
int
isCannonHit(double min, craft * c)
{

      return (min < 3.0) ? 1 : 0;
}

Generated by  Doxygen 1.6.0   Back to index