#include <stdio.h>
#include <dos.h>
#include <math.h>
#include <string.h>
#include <malloc.h>
#include "3dproj.h"
#include "3ddefs.h"
#include "3dprep.h"
#include "3dvarse.h"

void  speedup_ship(int f)
{
  o[f].speed++;
  o[f].sx=o[f].sx+(o[f].dx[0]*velconst)/(220);
  o[f].sy=o[f].sy+(o[f].dy[0]*velconst)/(220);
  o[f].sz=o[f].sz+(o[f].dz[0]*velconst)/(220);
}

void  slowdown_ship(int f)
{
  o[f].speed--;
  o[f].sx=o[f].sx-(o[f].dx[0]*velconst)/(220);
  o[f].sy=o[f].sy-(o[f].dy[0]*velconst)/(220);
  o[f].sz=o[f].sz-(o[f].dz[0]*velconst)/(220);
}

void  doesitmatter(int f)
{
  if (matter[f]==2 && o[f].type>-1 && enemy==0) completedcount++;
  if (matter[f]==1 && o[f].type==-1) completedcount++;
  if (matter[f]==2 && o[f].type==-1) notcompleted=1;
  if (matter[f]==0) completedcount++;
  if ((matter[f]==2 || matter[f]==3) && (o[f].type>-1) && (o[f].shields<10) ) critical=1;
}

void  aimship(float dx,float dy,float dz,float accuracy,int fireflag,int f)
{
  float xdir,ydir,zdir,fx,fy;
  calculate_ship_angles(dx,dy,dz, o[f].dx[0],o[f].dy[0],o[f].dz[0], &fx,&fy);
  xdir=ydir=zdir=0;
  if((difficulty==2 || difficulty==3) && o[f].side!=o[0].side && norand==0) accuracy=accuracy*4;
  if (fy<-accuracy)
  {
    o[f].rsy=1; o[f].rsz=-0.1; ydir=1; zdir=-0.1;
  }
  if (fy>accuracy)
  {
    o[f].rsy=-1; o[f].rsz=0.1; ydir=-1; zdir=0.1;
  }
  if (fx<-accuracy)
  {
    o[f].rsx=-1; xdir=-1;
  }
  if (fx>accuracy)
  {
    o[f].rsx=1; xdir=1;
  }
  if (xdir==0 && ydir==0 && zdir==0)
  {
    o[f].currentrevs=o[f].currentrevs*0.5;
    if (o[f].currentrevs<0.09)
    {
      o[f].currentrevs=0;
      o[f].rsx=o[f].rsy=o[f].rsz=0;
    }
  }
  else if (o[f].currentrevs<o[f].toprevs) o[f].currentrevs=o[f].currentrevs+0.1;
  if (fireflag==1) openfire(fx,fy,f);
  o[f].rsx=o[f].rsx*o[f].currentrevs;
  o[f].rsy=o[f].rsy*o[f].currentrevs;
  o[f].rsz=o[f].rsz*o[f].currentrevs;
  spinobject(f,o[f].cx,o[f].cy,o[f].cz,o[f].rsx,o[f].rsy,o[f].rsz,0);
}

void  openfire(float fx, float fy, int f)
{
  int g,createtype,d;
  int soundtype;
  float fx2,fy2,dx,dy,dz,distance2,t;

  if (o[f].target>-1 && (fx>-0.27 && fx<0.27 && fy>-0.27 && fy<0.27))
  {
    if ((frame1==1)&&(o[f].crashzones==0)) for (g=0; g<ships; g++) if ( o[g].side==o[f].side && g!=f && o[g].type>-1)
    {
      dx=o[g].cx-o[f].cx;
      dy=o[g].cy-o[f].cy;
      dz=o[g].cz-o[f].cz;
      distance2=pythag3d(dx,dy,dz);
      calculate_ship_angles(dx,dy,dz, o[f].dx[0],o[f].dy[0],o[f].dz[0], &fx2,&fy2);
      if (fx2>-0.1 && fx2<0.1 && fy2>-0.1 && fy2<0.1 && distance2<3500)
      {
        o[f].doing=1;
        o[f].frame1=210;
      } // End evade friendly ships so that you won't shoot them (unless you are a cap ship with crashzones; then you don't give a shit)
    }
    dx=o[o[f].target].cx-o[f].cx;
    dy=o[o[f].target].cy-o[f].cy;
    dz=o[o[f].target].cz-o[f].cz;
    distance2=pythag3d(dx,dy,dz);
    for (g=0; g<o[f].guns; g++) // Gun selection logic
    {
      o[f].g[g].selected=0;
      t=0.07;
      d=0.6;
      if (o[f].g[g].type>ION && o[f].g[g].type<MISSILE && o[f].crashzones>0) t=0.2;
      if ((((apirandom(100)>95 || norand==1) || !(o[f].g[g].type>=BOMB && o[f].g[g].type<=MISSILE))
      && ((o[f].g[g].type>ION && o[f].g[g].type<MISSILE && o[o[f].target].crashzones>0) ||
          (
          (o[f].g[g].type==LASER && ((g==1 && o[f].g[0].type==LASER && o[f].g[0].fireframe>3) || g==0 ))
          || o[f].g[g].type==BEAM || o[f].g[g].type==ION || o[f].g[g].type==TURBOLASER || o[f].g[g].type==ALIENBEAM || (o[f].g[g].type==ALIENTORP && distance2>1000) || o[f].g[g].type==CHAINGUN) ||
          ((o[f].g[g].type==MISSILE && o[o[f].target].crashzones==0 && (((o[o[f].target].shields<30 || o[o[f].target].armour<30) && distance2<1000) || distance2>5000) && (o[f].armour<o[f].maxarmour/2 || o[f].g[g].left>1)))))
          && (fx>-t && fx<t && fy>-t && fy<t))
          o[f].g[g].selected=1;
      soundtype=-1;
      if (o[o[f].target].doing<DIEING && o[f].g[g].selected==1 && distance2<gunrange[o[f].g[g].type] && o[f].g[g].left>0 && (o[f].g[g].fireframe==0 || (o[f].g[g].type==ION && o[f].g[g].fireframe<ioncharge && frame2==0) || (o[f].g[g].type==CHAINGUN) ))
      {
        if (o[f].target==0) incoming=2;
        if (o[f].g[g].type!=CHAINGUN)
        {
          switch (o[f].g[g].type)
          {
            case LASER: d=-.9; if(o[f].side==1 || o[f].side==6) createtype=1; else createtype=2; soundtype=LASER; break;
            case BEAM:
            case ALIENBEAM:
              soundtype=5;
              if (o[f].g[g].type==ALIENBEAM) createtype=4;
              else createtype=3; // Beam
              if(o[f].side!=5)
              {
                createobject(createtype, (o[f].cx + o[f].dx[0] * 0.3) + (o[f].dx[2] * -o[f].g[g].fireflag * o[f].g[g].gun ) + (o[f].dx[0] * o[f].g[g].gunz ) + (o[f].dx[1] * o[f].g[g].guny) ,
                (o[f].cy + o[f].dy[0] * 0.3) + (o[f].dy[2] * -o[f].g[g].fireflag * o[f].g[g].gun ) + (o[f].dy[0] * o[f].g[g].gunz ) + (o[f].dy[1] * o[f].g[g].guny ),
                (o[f].cz + o[f].dz[0] * 0.3) + (o[f].dz[2] * -o[f].g[g].fireflag * o[f].g[g].gun ) + (o[f].dz[0] * o[f].g[g].gunz ) + (o[f].dz[1] * o[f].g[g].guny )
                ,o[f].dx[0]*gunvelocity[o[f].g[g].type],o[f].dy[0]*gunvelocity[o[f].g[g].type],o[f].dz[0]*gunvelocity[o[f].g[g].type],o[f].side,f);
              }
              else
              {
                createobject(createtype, (o[f].cx + o[f].dx[0] * 0.3) + (o[f].dx[2] * -o[f].g[g].fireflag * o[f].g[g].gun ) + (o[f].dx[0] * o[f].g[g].gunz ) + (o[f].dx[1] * o[f].g[g].guny) ,
                (o[f].cy + o[f].dy[0] * 0.3) + (o[f].dy[2] * -o[f].g[g].fireflag * o[f].g[g].gun ) + (o[f].dy[0] * o[f].g[g].gunz ) + (o[f].dy[1] * o[f].g[g].guny ),
                (o[f].cz + o[f].dz[0] * 0.3) + (o[f].dz[2] * -o[f].g[g].fireflag * o[f].g[g].gun ) + (o[f].dz[0] * o[f].g[g].gunz ) + (o[f].dz[1] * o[f].g[g].guny )
                ,o[f].dx[0]*gunvelocity[o[f].g[g].type],o[f].dy[0]*gunvelocity[o[f].g[g].type],o[f].dz[0]*gunvelocity[o[f].g[g].type],2,f);
              }
              if ((fx>-0.035)&&(fx<0.035)&&(fy>-0.035)&&(fy<0.035)&&(o[f].target>-1))
              {
                if (createtype==3) damageship(o[f].target , gunpower[BEAM]);
                else if (createtype==4) damageship(o[f].target , gunpower[ALIENBEAM]);
                if (o[o[f].target].crashzones==0)
                {
                  o[o[f].target].sparking=1;
                  o[o[f].target].sparkx=o[f].sx;
                  o[o[f].target].sparky=o[f].sy;
                  if (o[f].sz>0) o[o[f].target].sparkz=0.9;
                  else o[o[f].target].sparkz=1.1;
                }
              }
              break;
            case ION: createtype=5; soundtype=3; break;
            case BOMB: createtype=6; soundtype=BOMB; if (o[f].target==0) addcomputer("INCOMING BOMB!",-1);break;
            case NUKE: createtype=7; soundtype=BOMB; if (o[f].target==0) addcomputer("INCOMING NUKE!",-1);break;
            case TORP: createtype=8; soundtype=BOMB; if (o[f].target==0) addcomputer("INCOMING TORP!",-1);break;
            case MISSILE: createtype=9; soundtype=MISSILE; if (o[f].target==0) {addcomputer("INCOMING",-1); addcomputer("MISSILE!",213);playtricia(3);  }break;
            case ALIENTORP: createtype=12; soundtype=6; if (o[f].target==0) addcomputer("INCOMING FIRE!",-1);break;
            case TURBOLASER: d=-.9; createtype=11; soundtype=8; break;
          }
          createobject(createtype,
            (o[f].cx + o[f].dx[0] * d) + (o[f].dx[2] * o[f].g[g].fireflag * o[f].g[g].gun ) + (o[f].dx[0] * o[f].g[g].gunz ) + (o[f].dx[1] * o[f].g[g].guny ),
            (o[f].cy + o[f].dy[0] * d) + (o[f].dy[2] * o[f].g[g].fireflag * o[f].g[g].gun ) + (o[f].dy[0] * o[f].g[g].gunz ) + (o[f].dy[1] * o[f].g[g].guny ),
            (o[f].cz + o[f].dz[0] * d) + (o[f].dz[2] * o[f].g[g].fireflag * o[f].g[g].gun ) + (o[f].dz[0] * o[f].g[g].gunz ) + (o[f].dz[1] * o[f].g[g].guny ),
            o[f].dx[0]*gunvelocity[o[f].g[g].type],o[f].dy[0]*gunvelocity[o[f].g[g].type],o[f].dz[0]*gunvelocity[o[f].g[g].type],o[f].target,f);
          if (o[f].g[g].fireframe==0) o[f].g[g].fireframe=1;
          if(o[f].g[g].type!=LASER && o[f].g[g].type!=BEAM && o[f].g[g].type!=ION && o[f].g[g].type!=TURBOLASER && o[f].g[g].type!=ALIENBEAM) o[f].g[g].left--;
          else o[f].g[g].fireflag=-o[f].g[g].fireflag;
          if(soundblaster==1 && o[f].g[g].type<9) playsoundeffect(soundtype,distance);
          if(soundtype>-1 && soundblaster==1 && sound1[soundtype]!=NULL) playsoundeffect(soundtype,distance);
        } // End of not chaingun
        else // CHAINGUN
        {
          if (o[f].g[g].fireframe<30) o[f].g[g].fireframe++;
          else if (o[f].g[g].fireframe>30) o[f].g[g].fireframe=30;
          {
            if (frame2==0 && o[f].g[g].left>0)
            {
              o[f].g[g].left--;
              soundtype=2;
              if(soundtype>-1 && soundblaster==1 && sound1[soundtype]!=NULL) playsoundeffect(soundtype,distance);
              createobject(13,
                (o[f].cx + o[f].dx[0] * 0.3) + (o[f].dx[2] * o[f].g[g].gun ) + (o[f].dx[0] * o[f].g[g].gunz ) + (o[f].dx[1] * o[f].g[g].guny ),
                (o[f].cy + o[f].dy[0] * 0.3) + (o[f].dy[2] * o[f].g[g].gun ) + (o[f].dy[0] * o[f].g[g].gunz ) + (o[f].dy[1] * o[f].g[g].guny ),
                (o[f].cz + o[f].dz[0] * 0.3) + (o[f].dz[2] * o[f].g[g].gun ) + (o[f].dz[0] * o[f].g[g].gunz ) + (o[f].dz[1] * o[f].g[g].guny ),
                o[f].dx[0]*gunvelocity[o[f].g[g].type],o[f].dy[0]*gunvelocity[o[f].g[g].type],o[f].dz[0]*gunvelocity[o[f].g[g].type],o[f].target,f);
              createobject(13,
                (o[f].cx + o[f].dx[0] * 0.3) + (o[f].dx[2] * -o[f].g[g].gun ) + (o[f].dx[0] * o[f].g[g].gunz ) + (o[f].dx[1] * o[f].g[g].guny ),
                (o[f].cy + o[f].dy[0] * 0.3) + (o[f].dy[2] * -o[f].g[g].gun ) + (o[f].dy[0] * o[f].g[g].gunz ) + (o[f].dy[1] * o[f].g[g].guny ),
                (o[f].cz + o[f].dz[0] * 0.3) + (o[f].dz[2] * -o[f].g[g].gun ) + (o[f].dz[0] * o[f].g[g].gunz ) + (o[f].dz[1] * o[f].g[g].guny ),
                o[f].dx[0]*gunvelocity[o[f].g[g].type],o[f].dy[0]*gunvelocity[o[f].g[g].type],o[f].dz[0]*gunvelocity[o[f].g[g].type],o[f].target,f);
            }
          }
        } // End of chaingun
      } // End of ok to fire
      if (o[f].g[g].type==CHAINGUN && o[f].g[g].selected==0 && o[f].g[g].fireframe>0) o[f].g[g].fireframe-=2;
    } // End of gun loop
  } // End open fire
}

void  check(int f)
{
  int g,h;
  float distance1,distance2;
  float fx2,fy2,fz2;
  float fx,fy,fz;
  for (g=0; g<ships; g++)
  {
    if (o[g].type>-1 && g!=f)
    {
    // UM THIS DOES NOT WORK FOR LANDING EITHER ! JASON WE NEED YOU
      if (o[g].crashzones>0 && o[f].doing!=10 && (f!=o[g].mother && (
          o[g].doing!=BOARDING && o[g].doing!=BOARDED &&
          o[f].doing!=BOARDING && o[f].doing!=BOARDED &&
          o[f].doing!=LAUNCHING && o[g].doing!=LAUNCHING &&
          o[f].type!=TYPE_NONSENTIENT)))
      {
        if ((o[f].cx < o[g].cx+600) && (o[f].cx > o[g].cx-600) &&
        (o[f].cy < o[g].cy+600) && (o[f].cy > o[g].cy-600) &&
        (o[f].cz < o[g].cz+600) && (o[f].cz > o[g].cz-600) &&
         o[g].doing!=WITHDRAWING && o[g].wingleader!=f && f>0 && o[f].type!=0 && o[f].type!=4 && o[f].type!=5 && o[f].doing<=3)
        {
          o[f].doing=WITHDRAWING;
          o[f].frame1=10;
        }
        fx=(o[g].cx+(0.01*((o[g].dx[2]*o[g].c[0].x)+(o[g].dx[0]*o[g].c[0].z)+(o[g].dx[1]*o[g].c[0].y)))) - (o[f].cx+o[f].sx);
        fy=(o[g].cy+(0.01*((o[g].dy[2]*o[g].c[0].x)+(o[g].dy[0]*o[g].c[0].z)+(o[g].dy[1]*o[g].c[0].y)))) - (o[f].cy+o[f].sy);
        fz=(o[g].cz+(0.01*((o[g].dz[2]*o[g].c[0].x)+(o[g].dz[0]*o[g].c[0].z)+(o[g].dz[1]*o[g].c[0].y)))) - (o[f].cz+o[f].sz);
        distance1=pythag3d(fx,fy,fz);
        if (distance1<o[g].c[0].size)
        {
          for (h=1; h<o[g].crashzones; h++)
          {
            fx2=(o[g].cx+(0.01*((o[g].dx[2]*o[g].c[h].x)+(o[g].dx[0]*o[g].c[h].z)+(o[g].dx[1]*o[g].c[h].y)))) - (o[f].cx+o[f].sx) ;
            fy2=(o[g].cy+(0.01*((o[g].dy[2]*o[g].c[h].x)+(o[g].dy[0]*o[g].c[h].z)+(o[g].dy[1]*o[g].c[h].y)))) - (o[f].cy+o[f].sy) ;
            fz2=(o[g].cz+(0.01*((o[g].dz[2]*o[g].c[h].x)+(o[g].dz[0]*o[g].c[h].z)+(o[g].dz[1]*o[g].c[h].y)))) - (o[f].cz+o[f].sz) ;
            distance2=pythag3d(fx2,fy2,fz2);
            if (distance2<o[g].c[h].size)
            {
              createexplosion(complexity, o[f].cx, o[f].cy, o[f].cz, 20,20,20 );
              o[f].speed=0;
              o[f].sx=0;
              o[f].sy=0;
              o[f].sz=0;
              if (f==0 && o[0].type>-1 && norand==0)
              {
                o[0].rsx=frame1-5;
                o[0].rsy=-frame1+5;
                if (o[0].doing==ENTERING_HYPERSPACE)
                {
                  o[0].doing=ATTACKING;
                  o[0].cz=0;
                }
              }
// Major hack here.  We need to find the better bit...
              if(o[f].doing!=ENTERING_HYPERSPACE &&
                 o[g].doing!=ENTERING_HYPERSPACE &&
                 o[f].doing!=LEAVING_HYPERSPACE &&
                 o[g].doing!=LEAVING_HYPERSPACE &&
                 o[f].doing!=BOARDED && o[g].doing!=BOARDED)
              {
                damageship(f,gunpower[MISSILE]);
                damageship(g,gunpower[MISSILE]);
              }

            }
          }
        }
      }
      else if (o[g].type>-1 && o[f].doing<=10 &&
          o[f].doing!=LAUNCHING && o[g].doing!=LAUNCHING
      )
      {
        if ((o[f].cx < o[g].cx+60) && (o[f].cx > o[g].cx-60) &&
        (o[f].cy < o[g].cy+60) && (o[f].cy > o[g].cy-60) &&
        (o[f].cz < o[g].cz+60) && (o[f].cz > o[g].cz-60) &&
         o[g].doing!=WITHDRAWING && o[g].wingleader!=f && f>0 && o[f].type!=4 && o[f].type!=5 && o[f].crashzones==0)
        {
          o[f].doing=WITHDRAWING;
          o[f].frame1=80;
        }
        if ((o[f].cx < o[g].cx+30) && (o[f].cx > o[g].cx-30) &&
            (o[f].cy < o[g].cy+30) && (o[f].cy > o[g].cy-30) &&
            (o[f].cz < o[g].cz+30) && (o[f].cz > o[g].cz-30) )
        {
          if (f==0 && o[0].type>-1 && norand==0)
          {
            o[0].rsx=frame1-5;
            o[0].rsy=-frame1+5;
            if (o[0].doing==ENTERING_HYPERSPACE) o[0].doing=ATTACKING;
          }
          damageship( f , gunpower[MISSILE]/5 );
          createexplosion(complexity, o[f].cx, o[f].cy, o[f].cz, 20,20,20 );
          damageship( g , gunpower[MISSILE]/5 );
        } // End of projectile HIT
      } // End of normal hit
    }
  } // end of g
}

void  checkshields(int f)
{
  int xold,yold,zold,g,var1;
  float dx,dy,dz,amount;
  char s1[120];
  if (o[f].type==36 || o[f].type==37 || o[f].type==38 || o[f].doing==DIEING) return; // Asteroids have no need for shields
  if (o[f].shields<15 && f>0 && o[f].stubborn==0 && o[f].crashzones==0)
  {
    xold=yold=zold=0;
    for (g=0; g<ships; g++)
    {
      if (o[g].side!=o[f].side && o[g].doing!=10 && o[g].crashzones==0 && (apirandom(10)>5 || norand==1)) // Possible target reassignation
      {
        dx=o[f].cx-o[g].cx;
        dy=o[f].cy-o[g].cx;
        dz=o[f].cz-o[g].cx;
        if ((xold==0 && yold==0 && zold==0) || (pythag3d(xold,yold,zold)>pythag3d(dx,dy,dz)))
        {
          xold=dx;
          yold=dy;
          zold=dz;
          if (o[g].target==f && o[g].side!=o[f].side && o[g].side>0) o[f].target=g;
        } // End of target selected
      } // End of possible target choose
    } // End of go through ships
  }
  if (o[f].shields<o[f].maxshields && o[f].armour>5)
  {
    if(o[f].crashzones==0) amount=0.5;
    else amount=1;
    if (frame2==0) o[f].shields+=amount;
    if (o[f].shields<15 && f>0 && o[f].type>0 && o[f].type!=TYPE_AMBUSH
    && o[f].type!=TYPE_NONSENTIENT && o[f].type!=TYPE_CONVOY
    && o[f].type!=TYPE_DUMBCONVOY)
    {
      if ((o[f].stubborn!=2 && o[f].doing==EVADING && o[f].frame2==0) // DO A TYPE
       || ((o[f].doing!=EVADING && o[f].crashzones==0)) )
      {
        o[f].doing=EVADING;
        if (norand==0) xold=apirandom(100);
        else xold=1;
        if (norand==0 || f!=0)
        {
          if (xold<25) o[f].rsx=-1;
          else if (xold<50) o[f].rsy=-1;
          else if (xold<75) o[f].rsx=1;
          else if (xold<99) o[f].rsy=1;
        }
        o[f].rsx=(o[f].rsx)*o[f].toprevs;
        o[f].rsy=(o[f].rsy)*o[f].toprevs;
        o[f].rsz=(o[f].rsz)*o[f].toprevs;
        o[f].frame1=0;
        o[f].frame2=0;
      }
      if (o[f].doing!=2 && c[currentcomm].type!=2 && o[f].side==o[0].side && f>0)
      {
        var1=apirandom(5);
        sprintf(s1,"%s REQUESTING ASSISTANCE", shapedata[o[f].shape].type);
        if (o[f].side==2)
        {
          switch(var1)
          {
            case 1:
              sprintf(s1,"%s UNDER ATTACK",
                shapedata[o[f].shape].type);
            break;
            case 2:
              sprintf(s1,"%s NEEDING HELP",
                shapedata[o[f].shape].type);
            break;
            case 3:
              sprintf(s1,"%s SUFFERING DAMAGE",
                shapedata[o[f].shape].type);
            break;
            case 4:
              sprintf(s1,"%s UNDER ATTACK",
                shapedata[o[f].shape].type);
            break;
          }
        }
        else if (o[f].side==1)
        {
          switch(var1)
          {
            case 1:
              sprintf(s1,"GET THIS GUY OFF ME");
            break;
            case 2:
              sprintf(s1,"%s IS UNDER ATTACK",
              shapedata[o[f].shape].type);
            break;
            case 3:
              sprintf(s1,"%s SUFFERING DAMAGE",
                shapedata[o[f].shape].type);
            break;
            case 4:
              sprintf(s1,"IM HIT");
            break;
          }
        }                           
        if (commtimer>10 || commtimer==0) createcomm(f,2,o[f].side,s1);
      }
    } // Run awwaay
  } // End of shield recharge
}

void damageship(int gg, int amount)
{
  float spare;
  if(o[gg].doing>=10) return;
//  if (o[gg].shape==36 || o[gg].shape==37 || o[gg].shape==38) return;
  if (o[gg].crashzones==0) // Play shield hit
  {
    spare=(pythag3d(o[gg].cx,o[gg].cy,o[gg].cz)-pythag3d(viewx,viewy,viewz));
    if (spare<0) spare=-spare;
    playsoundeffect(11,spare);
  }
  o[gg].shields-=amount;

  if (o[gg].shields<0)
  {
    o[gg].armour+=o[gg].shields;
    o[gg].shields=0;
    o[gg].smoking=10;
    if (o[gg].armour<0 && o[gg].doing!=10)
    {
      createexplosion(complexity, o[gg].cx, o[gg].cy, o[gg].cz, 20,20,20 );
      addcomputer(shapedata[o[gg].shape].type,o[gg].side);
      addcomputer("DESTROYED.",o[gg].side);
      if(gg==o[0].target) playtricia(10);
      else if(o[gg].side==o[0].side)
      {
        if(o[gg].crashzones>0) playtricia(16);
        else playtricia(18);
      }
      else if(o[gg].side!=o[0].side)
      {
        if(o[gg].crashzones>0) playtricia(15);
        else playtricia(17);
      }
      o[gg].armour=0;
      o[gg].doing=10;
      if (frame1>6) o[gg].frame1=1;     // Normal death
      else if (frame1>8) o[gg].frame1=-100; // Long death
      else frame1=70; //Short death
      o[gg].frame3=0;
      if (o[gg].shape==90 || o[gg].shape==91 || o[gg].shape==92 || o[gg].shape==93)
      {
        o[gg].frame1=-apirandom(100);
        if (o[gg].frame1>-1) o[gg].frame1=-1;
        o[gg].rsx=0;
        o[gg].rsy=0;
        o[gg].rsz=0;
      }
      else if (o[gg].crashzones>0 && (norand==0 || gg!=0)) // A big ship
      {
        o[gg].frame1=-apirandom(100);
        if (o[gg].frame1>-1) o[gg].frame1=-1;
        o[gg].rsx=(float)saferandom(5)/20;
        o[gg].rsy=(float)saferandom(5)/20;
        o[gg].rsz=(float)saferandom(5)/20;
      }
      else if (norand==0 || gg!=0) // A little ship
      {
        if (frame1==0) // Dead pilot; follow current heading and course.
        {
          o[gg].frame3=1;
          o[gg].rsx=(float)saferandom(9);
          o[gg].rsy=(float)saferandom(9);
          o[gg].rsz=(float)saferandom(9);
        } // End of dead pilot
        else // Broken machine. Cartwheel apirandomly
        {
          o[gg].sx+=(float)saferandom(5);
          o[gg].sy+=(float)saferandom(5);
          o[gg].sz+=(float)saferandom(5);
          o[gg].rsx=(float)saferandom(9);
          o[gg].rsy=(float)saferandom(9);
          o[gg].rsz=(float)saferandom(9);
        } // End of cartwheel apirandomly
      }
      o[gg].wingleader=-1;
      o[gg].target=-1;
    } // End of death
  } // End of reduction in shields
  if (gg==0 && norand==0) // OUCH! YOUR HIT!!!
  {
    if (o[0].crashzones==0 && view<4)
    {
      dddFillScreen(134); // This used to be 2
      judx=saferandom(50);
      judy=saferandom(50);
    }
    if (o[0].doing==10)
    {
      o[0].rsx+=(float)saferandom(21)/10;
      o[0].rsy+=(float)saferandom(21)/10;
      o[0].rsz+=(float)saferandom(21)/10;
    }
  } // End of YOUR hit!
}

void  drawturrets(int f)
{
  int g,h;
  float xold,yold,zold;
  float fx,fy;
  float dx,dy,dz;
  float fy2;
  float xdir,ydir,spare;
  float distance2=0;
  for (g=0; g<o[f].turrets; g++)
  {
    if (o[f].t[g].target>-1) if((o[o[f].t[g].target].type==-1 || o[o[f].t[g].target].doing>=10)) o[f].t[g].target=-1;
    if (o[f].t[g].target==-1) // No target. Scan for one.
    {
      xold=yold=zold=1;
      for (h=0; h<ships; h++)
      {
        if (o[h].type>-1 && o[g].doing<=10 && o[h].side>0 && o[h].side!=o[f].side && o[h].doing!=10 /*&& (o[h].shape>9 && o[h].shape<29)*/ && (apirandom(10)>5 || norand==1) )
        {
          dx=o[h].cx-o[f].cx;
          dy=o[h].cy-o[f].cy;
          dz=o[h].cz-o[f].cz;
          if ( (xold==1 && yold==1 && zold==1) || (pythag3d(xold,yold,zold)>pythag3d(dx,dy,dz)))
          {
            xold=dx;
            yold=dy;
            zold=dz;
            o[f].t[g].target=h; // I want this man.
          }
        }
      }
    } // End of no target
    xdir=ydir=0;
    if (o[f].t[g].deadframe>0)
    {
      o[f].t[g].deadframe--;
      if (flames==ON)
      {
        if (frame2==0) createobject(10, apirandom(30)-15+o[f].cx+o[f].t[g].cx-(o[f].sx*4),apirandom(30)-15+o[f].cy+o[f].t[g].cy-(o[f].sy*4),apirandom(30)-15+o[f].cz+o[f].t[g].cz-(o[f].sz*4) ,-o[f].t[g].dx[1]/(25+saferandom(10)),-o[f].t[g].dy[1]/(25+saferandom(10)),-o[f].t[g].dz[1]/(25+saferandom(10)),0,-1 );
      } // End of smoke
    }
    else if (o[f].t[g].target>-1 && o[o[f].t[g].target].type>-1) // Oooh! Beer!
    {
      if (o[f].t[g].target==0 && incoming!=2) incoming=3; // Oh shag.
      dx=o[o[f].t[g].target].cx-(o[f].cx+o[f].t[g].cx);
      dy=o[o[f].t[g].target].cy-(o[f].cy+o[f].t[g].cy);
      dz=o[o[f].t[g].target].cz-(o[f].cz+o[f].t[g].cz);
      distance2=pythag3d(dx,dy,dz);
      xdir=ydir=0;
      calculate_ship_angles(dx,dy,dz, o[f].t[g].sx,o[f].t[g].sy,o[f].t[g].sz, &fx,&fy);
      if (o[f].t[g].type!=2) // All turrets move pretty quickly . . .
      {
        if (fy<-0.06) ydir=1;
        if (fy>0.06) ydir=-1;
        if (fx<-0.06) xdir=-1;
        if (fx>0.06) xdir=1;
      }
      else // Except for the beam of death, lest you die all the time.
      {
        if (fy<-0.01) ydir=0.07;
        else if (fy>0.01) ydir=-0.07;
        else if (fy<-0.001) ydir=0.03;
        else if (fy>0.001) ydir=-0.03;
        if (fx<-0.01) xdir=-0.07;
        else if (fx>0.01) xdir=0.07;
        else if (fx<-0.001) xdir=-0.03;
        else if (fx>0.001) xdir=0.03;
      }
      spare=(( sqrt( (pow(o[f].t[g].dx[1],2)) + (pow(o[f].t[g].dy[1],2)) + (pow(o[f].t[g].dz[1],2)) ) ) *
      ( sqrt( (pow(dx,2)) + (pow(dy,2)) + (pow(dz,2)) ) ) ) ;
      if ((spare>-0.001)&&(spare<0.001)) spare=0.001;
      fy2=acos(((o[f].t[g].dx[1]*dx)+(o[f].t[g].dy[1]*dy)+(o[f].t[g].dz[1]*dz))/spare);
      if (fy2<1.92)
      {
        o[f].t[g].target=-1;
        xdir=ydir=0;
      }
      else if (o[o[f].t[g].target].type==-1 || o[o[f].t[g].target].doing==10) o[f].t[g].target=-1;
      if (o[f].t[g].target>-1)
      {
        if (o[f].t[g].type==2 && fy2>1.62 && fx>-0.6 && fx<0.6 && fy>-0.6 && fy<0.6 && distance2<10000)
        {
          if (o[f].t[g].target==0) incoming=2;
          createobject(3,(o[f].cx + o[f].t[g].cx - o[f].t[g].sx * 3.0),
                         (o[f].cy + o[f].t[g].cy - o[f].t[g].sy * 3.0),
                         (o[f].cz + o[f].t[g].cz - o[f].t[g].sz * 3.0),
                         o[f].t[g].sx/1.2 , o[f].t[g].sy/1.2 , o[f].t[g].sz/1.2 , o[f].side,f );
          if (soundblaster==1) playsoundeffect(5, distance);
          if (fx>-0.03 && fx<0.03 && fy>-0.03 && fy<0.03)
          {
            if(o[o[f].t[g].target].crashzones==0)
            {
              o[o[f].t[g].target].sparking=1;
              o[o[f].t[g].target].sparkx=o[f].t[g].sx;
              o[o[f].t[g].target].sparky=o[f].t[g].sy;
              if (o[f].t[g].sz>0) o[o[f].t[g].target].sparkz=0.99;
              else o[o[f].t[g].target].sparkz=1.01;
            }
            damageship(o[f].t[g].target , gunpower[BEAM]);
          }
        }
        if (fx>-0.1 && fx<0.1 && fy>-0.1 && fy<0.1) // Laser, Turbo laser and Ion Chunk turret
        {
          if (o[f].t[g].target==0) incoming=2;
          if (o[f].t[g].type==1 && distance2<3500 && o[f].t[g].fireframe==0) // Laser turret
          {
            if (soundblaster==1) playsoundeffect(1, distance);
              createobject(o[f].side, (o[f].cx + o[f].t[g].cx - o[f].t[g].sx * 1.7),
                          (o[f].cy + o[f].t[g].cy - o[f].t[g].sy * 1.7),
                          (o[f].cz + o[f].t[g].cz - o[f].t[g].sz * 1.7),
                           o[f].t[g].sx/1.2 , o[f].t[g].sy/1.2 , o[f].t[g].sz/1.2,0,f);
              o[f].t[g].fireframe=1;
          }
          if (o[f].t[g].type==8 && distance2<3500 && o[f].t[g].fireframe==0) // Turbolaser
          {
            if (soundblaster==1) playsoundeffect(8, distance);
              createobject(11, (o[f].cx + o[f].t[g].cx - o[f].t[g].sx * 1.7),
                               (o[f].cy + o[f].t[g].cy - o[f].t[g].sy * 1.7),
                               (o[f].cz + o[f].t[g].cz - o[f].t[g].sz * 1.7),
                                o[f].t[g].sx/1.2 , o[f].t[g].sy/1.2 , o[f].t[g].sz/1.2,0,f);
            o[f].t[g].fireframe=1;
          }
          if (o[f].t[g].type==3 && o[f].t[g].fireframe<ioncharge && distance2<3500 && frame2==0)
          {
            if (soundblaster==1 && frame2==0) playsoundeffect(3, distance);
            createobject(5, (o[f].cx + o[f].t[g].cx - o[f].t[g].sx * 1.2),
                            (o[f].cy + o[f].t[g].cy - o[f].t[g].sy * 1.2),
                            (o[f].cz + o[f].t[g].cz - o[f].t[g].sz * 1.2),
                             o[f].t[g].sx/2 , o[f].t[g].sy/2 , o[f].t[g].sz/2,0,f);
            if (o[f].t[g].fireframe==0) o[f].t[g].fireframe=1;
          }
        } // End of target locked
        if (distance2 >3500 && (o[f].t[g].type==1 || o[f].t[g].type==3 || o[f].t[g].type==8)) o[f].t[g].target=-1;
        else if (distance2 >20000 && o[f].t[g].type==2) o[f].t[g].target=-1;
      }
      if (o[f].t[g].target>-1) rotatesummat(&o[f].t[g].sx,&o[f].t[g].sy,&o[f].t[g].sz,xdir,ydir,0 );
    }
    if (o[f].t[g].fireframe>0)
    {
      o[f].t[g].fireframe++;
      if (o[f].t[g].type==1 && o[f].t[g].fireframe>gunrate[LASER]) o[f].t[g].fireframe=0;
      if (o[f].t[g].type==3 && o[f].t[g].fireframe>gunrate[ION]) o[f].t[g].fireframe=0;
      if (o[f].t[g].type==8 && o[f].t[g].fireframe>gunrate[TURBOLASER]) o[f].t[g].fireframe=0;
    }
  }
}

void  killoff(int f)
{
  float xold,yold,zold;
  int tempx,g;
  if (o[f].crashzones==0)
  {
    createexplosion(complexity*3, o[f].cx, o[f].cy, o[f].cz, 20,20,20 );
    for (g=0; g<complexity*2; g++)
    {
      xold=apirandom(31)-15;
      yold=apirandom(31)-15;
      zold=apirandom(31)-15;
      if ((xold>-1) && (xold<1)) xold=1;
      if ((yold>-1) && (yold<1)) yold=1;
      if ((zold>-1) && (zold<1)) zold=1;
      if (g<complexity/2)
        createobject(25, o[f].cx,o[f].cy,o[f].cz ,o[f].sx-(xold/3),o[f].sy+(yold/3),o[f].sz+(zold/3) ,0,-1);
      else if (g<complexity)
        createobject(23, o[f].cx,o[f].cy,o[f].cz ,o[f].sx-(xold/2),o[f].sy-(yold/2),o[f].sz-(zold/2) ,0,-1);
      else
        createobject(22, o[f].cx,o[f].cy,o[f].cz ,o[f].sx-(xold/2.5),o[f].sy-(yold/2.5),o[f].sz-(zold/2.5),0,-1 );
    }
    tempx=24;
    if ((o[f].shape==12)||(o[f].shape==17)||(o[f].shape==18)) tempx=26;
    else if ((o[f].shape>12)&&(o[f].shape<16)) tempx=27;
    for (g=0; g<2; g++)
    {
      xold=apirandom(21)-10;
      yold=apirandom(21)-10;
      zold=apirandom(21)-10;
      if ((xold>-1) && (xold<1)) xold=1;
      if ((yold>-1) && (yold<1)) yold=1;
      if ((zold>-1) && (zold<1)) zold=1;
      createobject(tempx, o[f].cx,o[f].cy,o[f].cz ,o[f].sx+(xold/5),o[f].sy+(yold/5),o[f].sz+(zold/5),0 ,-1);
    }
  }
  if(dpt[f]==1 && o[f].dpt==1) dpt[f]=0;
  free_memory_for_ship(f);
}

void calculateheight(int f)
{
  int g,h;
  float x,y,z;
  if(ground==0 || o[f].shape==90 || o[f].shape==91 || o[f].shape==92 || o[f].shape==93 || o[f].shape==98 || o[f].shape==99 || o[f].shape==100) return;
  h=0;
  for(g=0;g<9;g++)
  {
    x=gr[g].cx-o[f].cx;
    y=gr[g].cy-o[f].cy;
    z=gr[g].cz-o[f].cz;
    rotatesummat(&x,&y,&z , (-gr[g].rx/655.35),(gr[g].ry/655.35),(-gr[g].rz/655.35));
    h=h+y;
  }
  h=40+y; // 400!
  if(f==0) height=h;
  else // Not you; then an AI. These chaps should avoid the ground.
  {
    if((h<200 || (o[f].crashzones>0 && h<400))
      && (pythag3d(gr[4].cx-o[f].cx , gr[4].cy-o[f].cy , gr[4].cz-o[f].cz) <
      pythag3d(gr[4].cx-(o[f].cx+o[f].dx[0]) , gr[4].cy-(o[f].cy+o[f].dy[0]) , gr[4].cz-(o[f].cz+o[f].dz[0]) )
      && o[f].doing!=DIEING && (o[f].type==1 || o[f].type==2 || o[f].type==3 )))
    {
      if (o[f].doing!=EVADING && o[f].doing<10)
      {
        o[f].doing=EVADING;
        o[f].frame1=0;
        o[f].frame2=0;
      }
      o[f].rsx=o[f].rsy=o[f].rsz=0;
      aimship(gr[4].cx-gr[4].dx[1]*1000,
              gr[4].cy-gr[4].dy[1]*1000,
              gr[4].cz-gr[4].dz[1]*1000,0.1,0,f);
    }
  }
  if (h<0)
  {
    if (o[f].doing!=DIEING) damageship(f,4000);
//    o[f].frame1=81;
//    o[f].doing=DIEING;
    o[f].sx=o[f].sy=o[f].sz=0;
    o[f].rsx=o[f].rsy=o[f].rsz=0;
    if(f==0) o[f].speed=0;
  }
}

void projectiles(void)
{
  int f,g,h;                            // Three counter variables
//  float xold;                   // Calculation variables
  float fx,fy,fz;
  float fx2,fy2,fz2;
  float xdir;
  float distance1;    // Three distance counters
  float distance4,distance5;
  float x,y,z;
  int projectile_hit,projectile_boom,ease;
  char s1[80];
  no_projectiles=0;
  for (f=0; f<shapes-10; f++)
  {
    if (p[f].type>-1)
    {
      if (o[0].doing==ENTERING_HYPERSPACE && o[0].frame1<0) p[f].cz+=o[0].frame1*100;
      no_projectiles++;
      projectile_boom=-1; // It has not exploded.
      distance1=pythag3d(p[f].cx,p[f].cy,p[f].cz)-pythag3d(viewx,viewy,viewz);
      if (distance1<0) distance1=-distance1;
      if (debrisremoval==ON && old_time>minspeed && removal<1) // Remove a piece of crap
      {
        if (p[f].type==110 || p[f].type==120 || p[f].type==121 || p[f].type==122)
        {
          p[f].type=-1;
          removal++;
        }
      }
      // This one is a projectile WEAPON !
      if(p[f].type==100 || p[f].type==102 || p[f].type==103 || p[f].type==104 || p[f].type==105 || p[f].type==106 || p[f].type==111 || p[f].type==112 || p[f].type==113)
      {
        p[f].frame1++;
        if (p[f].type==100 && p[f].frame1>20) p[f].type=-1; // Laser
        if (p[f].type==111 && p[f].frame1>20) p[f].type=-1; // Turbo Laser
        if (p[f].type==102 && p[f].frame1>60) p[f].type=-1; // Ion Chunk
        if (p[f].type==112 && p[f].frame1>120) p[f].type=-1; // Alien Torpedo
        if (p[f].type==113 && p[f].frame1>30) p[f].type=-1; // Chaingun round
        if (p[f].type==105 || p[f].type==106 || p[f].type==104 || p[f].type==103 || p[f].type==112) // Homing weapon
        {
          if (flames==1 && p[f].type==106 && apirandom(10)>4) createobject(102, p[f].cx,p[f].cy,p[f].cz, -p[f].sx,-p[f].sy,-p[f].sz, 0,-1); // Missiles Burn.
          /* This is moved from the bottom, cos if target is -1, nowt to do is there?? */
          if (p[f].target>-1 && o[p[f].target].type==-1 /* || hyperspace */) p[f].target=-1;
          if (p[f].target==0 && incoming!=2) incoming=1;
          if (p[f].target>-1 && o[p[f].target].type>-1) //if ship exists, home  in on the fucker.
          {
            if(p[f].target==0) incoming=4; // Set it to INCOMING MISSILE
            if(o[0].target==p[f].target && p[f].owner==0 && o[o[0].target].turrets>0)
            {
              calculate_ship_angles((o[p[f].target].cx+o[o[0].target].t[targetturret].cx)-p[f].cx ,
                                    (o[p[f].target].cy+o[o[0].target].t[targetturret].cy)-p[f].cy ,
                                    (o[p[f].target].cz+o[o[0].target].t[targetturret].cz)-p[f].cz ,
                                     p[f].dx[0],p[f].dy[0],p[f].dz[0],&fx,&fy);
            }
            else
              calculate_ship_angles(o[p[f].target].cx-p[f].cx , o[p[f].target].cy-p[f].cy , o[p[f].target].cz-p[f].cz , p[f].dx[0],p[f].dy[0],p[f].dz[0],&fx,&fy);
            xdir=0;
            if (fy<-0.04)
            {
              p[f].rsy=1; p[f].rsz=-0.1;
              xdir=1;
            }
            if (fy>0.04)
            {
              p[f].rsy=-1; p[f].rsz=0.1;
              xdir=1;
            }
            if (fx<-0.04)
            {
              p[f].rsx=-1;
              xdir=1;
            }
            if (fx>0.04)
            {
              p[f].rsx=1;
              xdir=1;
            }
            if (xdir==0 && p[f].currentrevs!=0)
            {
              p[f].currentrevs=p[f].currentrevs/2;
              if (p[f].currentrevs<0.09)
              {
                p[f].currentrevs=0;
                p[f].rsx=p[f].rsy=p[f].rsz=0;
              }
            }
            else if (p[f].currentrevs<p[f].toprevs) p[f].currentrevs=p[f].currentrevs+0.1;
            p[f].rsx=p[f].rsx*p[f].currentrevs;
            p[f].rsy=p[f].rsy*p[f].currentrevs;
            p[f].rsz=p[f].rsz*p[f].currentrevs;
            spinprojectile(f, p[f].cx,p[f].cy,p[f].cz, p[f].rsx,p[f].rsy,p[f].rsz ,0 );
          }
          if ((p[f].type==105 || p[f].type==104 || p[f].type==103) && p[f].frame1>800) // Torp, Bomb, Nuke
          {
            p[f].type=-1;
            projectile_boom=4;
          }
          if (p[f].type==106) //missile missile
          {    /* added this test below HERE cos target might be dead */
            if(p[f].target>-1 && o[p[f].target].type>-1 && o[p[f].target].shields<10 && o[p[f].target].crashzones==0 && o[p[f].target].doing<DIEING)
            {
              o[p[f].target].doing=EVADING;
              o[p[f].target].frame1=40;
              if (norand==0) h=apirandom(100);
              else h=0;
              if (h<25) o[f].rsx=-1;
              else if (h<50) o[f].rsy=-1;
              else if (h<75) o[f].rsx=1;
              else if (h<99) o[f].rsy=1;
              o[f].rsx=(o[f].rsx)*o[f].toprevs;
              o[f].rsy=(o[f].rsy)*o[f].toprevs;
              o[f].rsz=(o[f].rsz)*o[f].toprevs;
            }
            // Jase moved this to after the last if, cos this kills off the missile... dunno if it caused a crash
            if(p[f].frame1>200) // Missile
            {
              p[f].type=-1;
              projectile_boom=1;
            }
          }
        } // End of homing weapons

        if(p[f].type>-1) //Added by jase cos might be causing a problem as p[f].type=-1 is in above code!!!
        {
          projectile_hit=-1;
          for (g=0; g<ships; g++) if(p[f].owner!=g && o[g].type>-1) //THis is so you don't get blown up by your own weaponry!!
          {
            if (o[g].crashzones>0)
            {
              fx=(o[g].cx+(0.01*((o[g].dx[2]*o[g].c[0].x)+(o[g].dx[0]*o[g].c[0].z)+(o[g].dx[1]*o[g].c[0].y))))-(p[f].cx+p[f].sx);
              fy=(o[g].cy+(0.01*((o[g].dy[2]*o[g].c[0].x)+(o[g].dy[0]*o[g].c[0].z)+(o[g].dy[1]*o[g].c[0].y))))-(p[f].cy+p[f].sy);
              fz=(o[g].cz+(0.01*((o[g].dz[2]*o[g].c[0].x)+(o[g].dz[0]*o[g].c[0].z)+(o[g].dz[1]*o[g].c[0].y))))-(p[f].cz+p[f].sz);
              distance4=pythag3d(fx,fy,fz);
              if(distance4<o[g].c[0].size) // If the projectile is within the crashzones boundary, then . . .
              {
                for(h=1; h<o[g].crashzones; h++) // Look to see if it is hitting an actual crashzoned part of the ship.
                {
                  fx2=(o[g].cx+(0.01*((o[g].dx[2]*o[g].c[h].x)+(o[g].dx[0]*o[g].c[h].z)+(o[g].dx[1]*o[g].c[h].y))))-(p[f].cx+p[f].sx); // More curves than Pamela Anderson. Ho fucking ho.
                  fy2=(o[g].cy+(0.01*((o[g].dy[2]*o[g].c[h].x)+(o[g].dy[0]*o[g].c[h].z)+(o[g].dy[1]*o[g].c[h].y))))-(p[f].cy+p[f].sy);
                  fz2=(o[g].cz+(0.01*((o[g].dz[2]*o[g].c[h].x)+(o[g].dz[0]*o[g].c[h].z)+(o[g].dz[1]*o[g].c[h].y))))-(p[f].cz+p[f].sz);
                  distance5=pythag3d(fx2,fy2,fz2);
                  if (distance5<o[g].c[h].size) // We have a collision.
                  {
                    projectile_hit=g;
                    break;
                  }
                }
              }
            }
            else
            {
              if ((p[f].cx < o[g].cx+70) && (p[f].cx > o[g].cx-70) &&
                  (p[f].cy < o[g].cy+70) && (p[f].cy > o[g].cy-70) &&
                  (p[f].cz < o[g].cz+70) && (p[f].cz > o[g].cz-70)) // A projectile hit!
              {
                projectile_hit=g;
                if(o[g].doing!=DIEING) o[g].sparking=1;
                o[g].sparkx=p[f].rx;
                o[g].sparky=p[f].ry;
                if (p[f].sz>0) o[g].sparkz=0.9;
                else o[g].sparkz=1.1;
              }
            } // END OF CRASH DETECTION
            if (projectile_hit>-1)
            {
              for(h=0;h<o[g].turrets;h++)
              {
                if( p[f].cx > o[g].cx + o[g].t[h].cx-70 &&
                    p[f].cx < o[g].cx + o[g].t[h].cx+70 &&
                    p[f].cy > o[g].cy + o[g].t[h].cy-70 &&
                    p[f].cy < o[g].cy + o[g].t[h].cy+70 &&
                    p[f].cz > o[g].cz + o[g].t[h].cz-70 &&
                    p[f].cz < o[g].cz + o[g].t[h].cz+70 && o[g].t[h].deadframe==0)
                {
                  o[g].t[h].hits++;
                  if (p[f].type==105 || p[f].type==104 || p[f].type==103 || p[f].type==106) o[g].t[h].hits=31;
                  if(o[g].t[h].hits>30)
                  {
                    o[g].t[h].hits=0;
                    o[g].t[h].damage++;
                    o[g].t[h].deadframe=500;
                    if(o[g].t[h].damage>10) o[g].t[h].deadframe=o[g].t[h].damage*100;
                    createexplosion(complexity,o[g].cx+o[g].t[h].cx,o[g].cy+o[g].t[h].cy,o[g].cz+o[g].t[h].cz,20,20,20);
                  }
                }
              } // End of h
            }
          } // End of g
          if(projectile_hit>-1 && o[projectile_hit].type>-1)
          {
            if ((p[f].type==103 || p[f].type==104 || p[f].type==105 || p[f].type==106 || p[f].type==112) || (p[f].type==113 && apirandom(10)>7)) projectile_boom=1;
            if (o[projectile_hit].doing<10)
            {
              if(p[f].owner==0 && (difficulty==1 || difficulty==3)) ease=4;
              else ease=1;
              if (p[f].type==100) damageship(projectile_hit,gunpower[LASER]*ease);
              if (p[f].type==102) damageship(projectile_hit,gunpower[ION]*ease);
              if (p[f].type==103) damageship(projectile_hit,gunpower[BOMB]);
              if (p[f].type==104) damageship(projectile_hit,gunpower[NUKE]);
              if (p[f].type==105) damageship(projectile_hit,gunpower[TORP]);
              if (p[f].type==106) damageship(projectile_hit,gunpower[MISSILE]);
              if (p[f].type==111) damageship(projectile_hit,gunpower[TURBOLASER]*ease);
              if (p[f].type==112) damageship(projectile_hit,gunpower[ALIENTORP]);
              if (p[f].type==113) damageship(projectile_hit,gunpower[CHAINGUN]*ease);
              if (o[projectile_hit].doing==10) pilot.kills++;
              if (p[f].owner==0 && o[projectile_hit].side==o[p[f].owner].side)
              { // He's on your side, dumbass!
                pilot.inmisfriendlyhits++;
                if(pilot.inmisfriendlyhits<10 && frame1<2)
                {
                  var1=apirandom(5);
                  sprintf(s1,"WATCH YOUR FIRE" );
                  switch(var1)
                  {
                    case 1:
                      sprintf(s1,"IM UNDER FRIENDLY ATTACK");
                    break;
                    case 2:
                      sprintf(s1,"%s UNDER FRIENDLY FIRE", shapedata[o[projectile_hit].shape].type);
                    break;
                    case 3:
                      sprintf(s1,"STOP SHOOTING ME");
                    break;
                    case 4:
                      sprintf(s1,"YOU IDIOT");
                    break;
                  }
                  if (commtimer>10 || commtimer==0) createcomm(projectile_hit,2,o[projectile_hit].side,s1);
                }
              } // end of Ship you hit being on your side, dumbass
              if(pilot.inmisfriendlyhits>=10 && o[0].side!=6)
              {
                createcomm(projectile_hit,2,o[projectile_hit].side,"YOU ARE HEREBY EXPELLED FROM OUR FORCES");
                if (o[0].side==1) o[0].side=6;
                else o[0].side=7;
                for(g=1; g<ships; g++)
                {
                  if(o[g].wingleader==0)
                  {
                    o[g].wingleader=-1;
                    createcomm(g,2,o[g].side,"BREAKING FORMATION FROM TRAITOR");
                  }
                }
              }
            } //          }
            p[f].type=-1;
          } // end of damage ship
        } //end of jases: if(p[f].type>-1)
        if (projectile_boom>-1 && distance1<effectsrenderdist)
          createexplosion(complexity*projectile_boom,p[f].cx,p[f].cy,p[f].cz,20,20,20);
      } // End if its a damaging projectile.
      if (p[f].type == 120) // The yellow spark
      {
        p[f].frame1++; if (p[f].frame1>40 || no_projectiles>270) p[f].type=-1;
      }
      if (p[f].type == 121) // The red spark
      {
        p[f].frame1++; if (p[f].frame1>60 || no_projectiles>270) p[f].type=-1;
      }
      if (p[f].type == 122 || no_projectiles>270) // Wreckage
      {
        spinprojectile(f, p[f].cx,p[f].cy,p[f].cz, p[f].rsx,p[f].rsy,p[f].rsz ,1 );
        if (distance1>effectsrenderdist) p[f].type=-1;
      }
      if (p[f].type==200 || p[f].type==201 || p[f].type==202) // Explosions
      {
        p[f].rx=viewrx;
        p[f].ry=viewry;
        p[f].rz=viewrz;
        p[f].frame2++;
        if (p[f].frame2>7 || distance1>effectsrenderdist || no_projectiles>270) p[f].type=-1;
      }
      if(ground>0 && (p[f].type==121 || p[f].type==122 || p[f].type==120))
      {
        p[f].sx+=gr[4].dx[1]/1000;
        p[f].sy+=gr[4].dy[1]/1000;
        p[f].sz+=gr[4].dz[1]/1000;
      }
      p[f].cz+=(p[f].sz-o[0].speed)*velconst;
      p[f].cx+=(p[f].sx*velconst);
      p[f].cy+=(p[f].sy*velconst);
      spinprojectile(f, 0,0,0, o[0].rsx,o[0].rsy,o[0].rsz,0);
      if (p[f].type==110) // The smoke
      {
        p[f].frame1++; if (p[f].frame1>40 || no_projectiles>270) p[f].type=-1;
        p[f].rx=viewrx;
        p[f].ry=viewry;
        p[f].rz=viewrz+(p[f].frame1*100*(150-f));
      }
      if (flames==1 && apirandom(10)>4 && p[f].type==122 && (p[f].shape==47 || p[f].shape==48))
      {
        createobject(102, p[f].cx,p[f].cy,p[f].cz, -p[f].sx,-p[f].sy,-p[f].sz, 0,-1);
        if(apirandom(100)>92) // Ka BOOOM!
        {
          if(p[f].shape==47) createexplosion(complexity,p[f].cx,p[f].cy,p[f].cz,20,20,20);
          p[f].type=-1;
        }                                  
      }
      if (p[f].type==105) // No idea. Sommet.
      {
        p[f].rx=viewrx;
        p[f].ry=p[f].frame1*1000;
        p[f].rz=p[f].frame1*1000;
      }
      if (p[f].type==251) // torus piece.
      {
        p[f].rx=viewrx;
        p[f].ry=viewry;
        p[f].rz=viewrz;
        p[f].frame1++;
        if (p[f].frame1>7) p[f].type=-1;
      }
      if (p[f].type==252) // torus piece.
      {
        p[f].frame1+=2;
        if (p[f].frame1>62) p[f].type=-1;
      }
      x=p[f].cx;
      y=p[f].cy;
      z=p[f].cz;
      if (distance1<effectsrenderdist && p[f].type>-1)
      {
        if (p[f].type==200 || p[f].type==201 || p[f].type==202) // Explosions
        {
          if (p[f].frame2==1) apiprojectile(DRW_SIMPLE,p[f].object, 0, x,y,z , p[f].rx,p[f].ry,p[f].rz);
          else if (p[f].frame2==2) apiprojectile(DRW_SIMPLE,p[f].object, 1, x,y,z, p[f].rx,p[f].ry,p[f].rz);
          else if (p[f].frame2==3) apiprojectile(DRW_SIMPLE,p[f].object, 2, x,y,z, p[f].rx,p[f].ry,p[f].rz);
          else if (p[f].frame2==4) apiprojectile(DRW_SIMPLE,p[f].object, 3, x,y,z, p[f].rx,p[f].ry,p[f].rz);
          else if (p[f].frame2==5) apiprojectile(DRW_SIMPLE,p[f].object, 4, x,y,z, p[f].rx,p[f].ry,p[f].rz);
          else if (p[f].frame2==6) apiprojectile(DRW_SIMPLE,p[f].object, 5, x,y,z, p[f].rx,p[f].ry,p[f].rz);
          else apiprojectile(DRW_SIMPLE,p[f].object, 6, x,y,z , p[f].rx,p[f].ry,p[f].rz);
          if(lightsourcing==ON)// Insert the light from the explosion! How cool is that?
          {
            if(p[f].shape==62) dddSetLightIntensity(p[f].farobject,(7-p[f].frame2)*5 ); // big boom
            if(p[f].shape==63) dddSetLightIntensity(p[f].farobject,(7-p[f].frame2)*10 ); // bigger boom
            if(p[f].shape==64) dddSetLightIntensity(p[f].farobject,(7-p[f].frame2)*2 ); //  little flame
            if(p[f].shape==78) dddSetLightIntensity(p[f].farobject,(7-p[f].frame2)*20 ); // biggest boom
            apiprojectile(DRAWFULL,p[f].farobject,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);
          }
        }
        else if (p[f].type==251) // Capship blue flame.
          apiprojectile(DRW_SIMPLE,p[f].object,p[f].frame1, x,y,z, p[f].rx,p[f].ry,p[f].rz);
        else if (p[f].type==252 && distance1>1500) // Capship blue tours thng.
          apiprojectile(DRW_SIMPLE,p[f].object,p[f].frame1/2, x,y,z, p[f].rx,p[f].ry,p[f].rz);
        else if (p[f].type==252 && distance1<1500) {}// Capship blue tours thng. TOO CLOASE SO DONT DRAW
        else if ((p[f].type==121 || p[f].type==120) && distance1>3000) // Sparks
          apiprojectile(DRW_SIMPLE,p[f].farobject,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);
        else if (p[f].type==102 && distance1>2000) // Ion Chunks in dot mode.
          apiprojectile(DRW_SIMPLE,p[f].farobject,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);
        else if ((p[f].type==105 || p[f].type==113) && distance1>4000) // Torpedo in dot mode
          apiprojectile(DRW_SIMPLE,p[f].farobject,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);

        else if (p[f].type==100 && distance1>800) // Lasers in line mode
          apiprojectile(DRW_SIMPLE,p[f].farobject,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);
        else if (p[f].type==111 && distance1>800) // Turbolaser in line mode
          apiprojectile(DRW_SIMPLE,p[f].farobject,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);

        else if (p[f].type==110 && distance1<2000) // Smoke!
          apiprojectile(DRW_SIMPLE,p[f].object,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);
        else if (p[f].type==122 && p[f].shape>=43 && p[f].shape<=46) // Wreckage projectiles
          apiprojectile(DRAWMOST,p[f].object,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);
        else if (p[f].type==122) // Wreckage projectiles
          apishape(DRAWFULL,p[f].object,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);
        else // Normal projectiles
          apiprojectile(DRW_SIMPLE,p[f].object,0, x,y,z, p[f].rx,p[f].ry,p[f].rz);
        if (longlaser==ON && p[f].type==100 && p[f].frame1>2) // Long lasers
          apiprojectile(DRW_SIMPLE,p[f].farobject,0, (p[f].cx-p[f].sx*2.7),(p[f].cy-p[f].sy*2.7),(p[f].cz-p[f].sz*2.7) , p[f].rx,p[f].ry,p[f].rz);
      }
      if (p[f].type==101) // Beam weaponry
      {
//        if (p[f].target==1) apiprojectile(DRW_SIMPLE,p[f].object,apirandom(2), p[f].cx,p[f].cy,p[f].cz, p[f].rx,p[f].ry,p[f].rz);
//        else apiprojectile(DRW_SIMPLE,p[f].object,2+apirandom(2), p[f].cx,p[f].cy,p[f].cz, p[f].rx,p[f].ry,p[f].rz);
        if (p[f].target==1) apiprojectile(DRW_SIMPLE,p[f].object,apirandom(2), p[f].cx,p[f].cy,p[f].cz, p[f].rx,p[f].ry,frame1*6553);
        else apiprojectile(DRW_SIMPLE,p[f].object,2+apirandom(2), p[f].cx,p[f].cy,p[f].cz, p[f].rx,p[f].ry,frame1*6553);
        p[f].frame1++;
        if(p[f].frame1>1) p[f].type=-1;
      }
      if (p[f].type==250)
      {
        p[f].frame1--;
        if (p[f].frame1<0) p[f].type=-1;
      }
    } // End of existing projectile
    if (ce[f].time>-1  && ce[f].time==missiontime && frame1==0) // Do the COMM events too.
    {
      if (ce[f].from>-1 && o[ce[f].from].type>-1)
      createcomm(ce[f].from, 1 ,ce[f].side, ce[f].msg);
      if (ce[f].from==-1) createcomm(ce[f].from,0,ce[f].side,ce[f].msg);
    }
  } // End for for loop
  for (f=shapes-10; f<shapes; f++) // Bit of a BLATENT hack here.
  {
    if (ce[f].time>-1  && ce[f].time==missiontime && frame1==0) //oh dear. more fucking comm events. hacktastic dude.
    {
      if (ce[f].from>-1 && o[ce[f].from].type>-1)
      createcomm(ce[f].from, 1 ,ce[f].side, ce[f].msg);
      if (ce[f].from==-1) createcomm(ce[f].from,0,ce[f].side,ce[f].msg);
    }
  }
}


