#include <stdio.h>
#include <dos.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <malloc.h>
#include <conio.h>
#include <stdlib.h>
#include "3dproj.h"
#include "3dmain.h"
#include "3ddefs.h"
#include "3dprep.h"
#include "3dvars.h"

void main(int argc, char *argv[] )
{
  char s1[80];
  int f,i,controlflag,knownarg,loadit=0,temp,topspeed=0,depend=0;
  int leapoutflag=0,mustload,temptermflag,runit;
  printf("%s",version);
  printf("%s",notice);

  if(demo!=2) for (i=1; i<argc; i++)
  {
    knownarg=0;
    argv[i] = strupr(argv[i]);
    if(strcmp(argv[i],"DEBUG")==0) { debug=1; knownarg=1; }
    if(strcmp(argv[i],"TEST")==0) { debug=2; knownarg=1; }
    if(strcmp(argv[i],"NOSOUND")==0) { thereisnosound=1; knownarg=1;}
    if(strcmp(argv[i],"FAST")==0) { topspeed=1; knownarg=1;}
    if(strcmp(argv[i],"DEPEND")==0) { depend=1; knownarg=1;}
    if(strcmp(argv[i],"DEMO")==0) { demo=2; knownarg=1;}
    if(strcmp(argv[i],"QUIET")==0) { quiet=1; knownarg=1;}
    if(strcmp(argv[i],"?")==0 || strcmp(argv[i],"HELP")==0)
    {
      printf("\nDEBUG\t: Full debug mode\n");
      printf("TEST\t: Test mode\n");
      printf("NOSOUND\t: Disable sound\n");
      printf("FAST\t: Increase ship speed\n");
      printf("DEMO\t: Put into demo mode\n");
      printf("START\t: Demo start belt campaign\n");
      printf("DEPEND\t: Disable dependant ships\n");
      printf("QUIET\t: Disable cutscenes\n");
      return;
    }
    if(knownarg==0)
    {
      sprintf(s1,argv[i]);
      loadit=1;
    }
  }

  allocate_memory_for_everything();
  initialise_data();

  if(debug>0 && demo!=2)
  {
    reset();
    tempmodsong=modsong[0];
    for(i=0;i<49;i++) dpt[i]=1;
    apiclearcliparea();
    apigameprint3(1,140,90,"DEBUG MODE");
    if(depend==1) for(i=0;i<49;i++) dpt[i]=0;
    else if(loadit==0) load("DEMO1");
    else load(s1);
    prepareyourguns();
    if(topspeed==1) o[0].speed=40;
    game(); //Sets terminateflag and missioncompleted
  }

  pilot.side=0;
  while(pilot.side!=-1)
  {
    reset();
    newside(); // Decides the side your playing for and initialises the campaign
    reset();
    leapoutflag=0;
    if((pilot.side==1 || pilot.side==2) && leapoutflag==0)
    {
      controlflag=0;
      while(controlflag!=-1 && pilot.campaign<numcampaigns && leapoutflag==0)
      {
        newcampaign();
        controlflag=-2;
        while(controlflag!=-1 && leapoutflag==0)
        {
          f=complete();
          if(f==1)
          {
            leapoutflag=1;
            controlflag=-1;
          }
          switch(controlflag)
          {
            case -2:
              newcampaign();
              load(missionname[actualmission]);
              loadwindowships();
              controlflag=0;
              break;
            case 0:
              controlflag=roomlounge();
              if(controlflag==-1)
              {
                leapoutflag=1;
              }
              break;
            case 1:
              controlflag=roomquarters();
              break;
            case 2:
              controlflag=roombriefing();
              break;
            case 3:
              controlflag=database();
              break;
            case 4:
              controlflag=indepth();
              break;
            case 5:
              controlflag=briefing();
              break;
            case 6:
              switch(startflag)
              {
                case HYPERSPACEIN: //break;
                case TAKEOFF:
                  if(quiet==0 || actualmission==f) launch();
                  if(quiet==0 || actualmission==f) launching();
                  break;
              }
              controlflag=7;
              break;
            case 7:
              if(actualmission==0) mustload=0;
              else mustload=1;
              successflag=0;
              for(f=0;f<nummissions;f++)
              {
                terminateflag=0;
                view=0;
                missiontime=0;
                if((f>actualmission && missiontype[f]==MISSION_SUCCESS && successflag==1)
                 ||(f>actualmission && missiontype[f]==MISSION_FAILURE && successflag!=1)
                 ||(f<=actualmission)) runit=1;
                else runit=0;
                if((temptermflag==DEAD || temptermflag==ABORTED) && f>actualmission) runit=0;
                if(mustload==1 && runit==1)
                {
                  reset();
                  if(quiet==0 || actualmission==f) load(missionname[f]);
                }
                mustload=1;
                if(music==1)
                {
                  if (missiontune[f]==0) tempmodsong=modsong[0];
                  if (missiontune[f]==1) tempmodsong=modsong[1];
                  if (missiontune[f]==2) tempmodsong=modsong[2];
                  if (missiontune[f]==3) tempmodsong=modsong[3];
                }
                if((quiet==0 || actualmission==f) && runit==1) prepareyourguns();
                if((quiet==0 || actualmission==f) && runit==1) game(); //Sets terminateflag and missioncompleted
                if(f==actualmission)
                {
                  temptermflag=terminateflag;
                  if(missioncompleted==COMPLETED) successflag=1;
                  else successflag=-1;
                }
              }
              if(quiet==0 && actualmission<f)
              {
                reset();
                load(missionname[actualmission]);
              }
              terminateflag=temptermflag;
              controlflag=8;
              if(missioncompleted==ABORTED)
              {
                controlflag=-2;
                break; //Aborting mission...
              }
              break;
            case 8:
             controlflag=11;
              switch(terminateflag)
              {
                case HYPERSPACED:
                  if(quiet==0) landing();
                  if(quiet==0) land();
                  pilot.mission++;
                  savepilot();
                  break;
                case DOCKED:
                  if(quiet==0) landing();
                  if(quiet==0) land();
                  pilot.mission++;
                  savepilot();
                  break;
                case DEAD:
                  leapoutflag=1;
                  pilot.deaths++;
                  savepilot();
                break;
                case ABORTED:
                  pilot.restarts++;
                  savepilot();
                  controlflag=-2;
                break;
              }
              break;
            case 9: // pilot info
              controlflag=pilotinfo();
              break;
            case 10: // Awaken PILOT
              temp=awakenpilot();
              loadwindowships();
              controlflag=1;
              break;
            case 11:
              roomdebriefing();
              controlflag=-2;
              break;
          } //ENd of switch
        } // End of loop through missions in a campaign
      } // End of loop through campaigns
    } // end of if side==1 || side==2
  } // End of while not quitting
  deinitialise_data();
  free_memory_for_everything();
  printf("%s",version);
  printf("%s",notice);
}

void game(void)
{
  int f,g,h;
  char s1[120];                         // A buffer string
  float xold,yold,zold;                 // Calculation variables
  float tx,ty,tz;
  float dx,dy,dz;
  float fx2,fy2,fz2;
  float x,y,z,rx,ry,rz,jx,jy;
  float xdir,ydir,zdir;
  float distance2; // distance counters
  float closestcapshipdistance,closestfighterdistance;
/*
  createship( 0,0,10, 0,0,0, 0,0,0,0,0,0,0,0,0,  0,-1,0, 100,100,100,0,"YOU",1,-1, 49,0);
  createship( 1,1,79, -3000,0,1800, 0,25,0,0,0,0,0,0,0,  0,-1,0, 100,100,100,0,"K-NAW 1",1,-1, 49,0);
  createship( 2,1,79, -3000,0,2800, 0,25,0,0,0,0,0,0,0,  0,-1,0, 100,100,100,0,"K-NAW 2",1,-1, 49,0);
  createship( 3,1,79, -3000,0,3800, 0,25,0,0,0,0,0,0,0,  0,-1,0, 100,100,100,0,"K-NAW 3",1,-1, 49,0);
  createship( 46,0,20, 0,-1000,3000, 0,25,0,0,0,0,0,0,0,  0,-1,0, 100,100,100,0,"PICKET 9734A",1,-1, 49,0);
  createship( 47,0,26, 0,-500,4000, 0,25,0,0,0,0,0,0,0,  0,-1,0, 100,100,100,0,"THE FURY",1,-1, 49,0);f
  createship( 48,0,22, 0,1000,3000, 0,25,0,0,0,0,0,0,0,  0,-1,0, 100,100,100,0,"THE BLACK SWAN",1,-1, 49,0);
  o[1].doing=PREPARINGTOBOARD;
  o[1].mother=48;
  o[2].doing=PREPARINGTOBOARD;
  o[2].mother=47;
  o[3].doing=PREPARINGTOBOARD;
  o[3].mother=46;
  finishtime=400;
*/
  createdebrisfield();

  camera=dddCreateCamera(96000,100*ar,100*ar);
  ccamera=dddCreateCamera(96000,100,100);

  if(music==1 && norand==0)
  {
    mod_data=tempmodsong;
    ModCommand(v_play);
  }

  playtricia(9);

  while(terminateflag==0) // The main program loop
  {
    if (key[_N] && debug!=0) // Change mission
    {
      reset();
      missionchoice();
    }
    if ((key[_Q] && (key[_R_CTRL] || key[_L_CTRL])) || ((o[0].doing==DIEING || norand==1 || debug>0) && (key[_ESC] || (key[_RETURN] && norand==1))))
    {
      terminateflag=ABORTED;
      if(o[0].doing==DIEING) terminateflag=DEAD;
      while(key[_ESC] || key[_Q]) {}
      if (norand==1) missiontime=finishtime+1;
    }
    if(missiontime>finishtime && norand==1) terminateflag=CUTSCENEOVER;

    /********* CHANGE FRAME VARIABLES **********/
    jjjtimer_start(0);
    frame1++; if (frame1>9) frame1=0;
    frame2++; if (frame2>2) frame2=0;
    frame3++; if (frame3>1000) frame3=0;
    if(tricia>0)
    {
      tricia++;
      if(tricia>17) tricia=0;
    }

    if(o[0].type>-1 && o[0].doing!=DIEING)
    {
      if(o[0].shields<o[0].maxshields/2) playtricia(1);
      if(o[0].armour<o[0].maxarmour/3 && o[0].shields<o[0].maxshields/2) playtricia(2);
    }

    if (frame1==0)
    {
      missiontime++;
      incoming=0; // Incoming fire flag
    }

    if (frame2==0)
    {
      for (g=0; g<12; g++) playing[g]=0; // Reset sound playing flags
    }
    if (frame1==0) playing[12]=0;


    if (targetframe>0) // Check the buttonpressing counter
    {
      targetframe++;
      if (targetframe>30) targetframe=0;
    }
    for(f=0;f<20;f++) if(triciaplaying[f]>0) triciaplaying[f]++;
    if(triciaplaying[1]>360) triciaplaying[1]=0;
    if(triciaplaying[2]>360) triciaplaying[2]=0;
    if(triciaplaying[3]>5) triciaplaying[3]=0;
    if(triciaplaying[4]>60) triciaplaying[4]=0;
    if(triciaplaying[5]>20000) triciaplaying[5]=0;
    if(triciaplaying[6]>20000) triciaplaying[6]=0;
    if(triciaplaying[7]>100) triciaplaying[7]=0;
    if(triciaplaying[8]>100) triciaplaying[8]=0;
    if(triciaplaying[9]>20000) triciaplaying[9]=0;
    if(triciaplaying[10]>10) triciaplaying[10]=0;
//    if(triciaplaying[11]>10) triciaplaying[11]=0;
//    if(triciaplaying[12]>10) triciaplaying[12]=0;
    if(triciaplaying[13]>25) triciaplaying[13]=0;
    if(triciaplaying[14]>25) triciaplaying[14]=0;
    if(triciaplaying[15]>10) triciaplaying[15]=0;
    if(triciaplaying[16]>10) triciaplaying[16]=0;
    if(triciaplaying[17]>10) triciaplaying[17]=0;
    if(triciaplaying[18]>10) triciaplaying[18]=0;
    if(triciaplaying[19]>60) triciaplaying[19]=0;

    /********* SORT YOU OUT ***********/
    for (g=0; g<o[0].guns; g++) if (o[0].g[g].fireframe>0) // Refire rate
    {
      o[0].g[g].fireframe++;
      if(o[0].g[g].fireframe>gunrate[ o[0].g[g].type ]) o[0].g[g].fireframe=0;
    }
    if ((o[0].turrets>0)&&(o[0].doing!=DIEING)) drawturrets(0);
    if (norand==0) check(0);
    /********* SET THE VIEW *********/
    apisetviewpos(0,0,0);
    viewx=0; viewy=0; viewz=0;
    viewrx=0; viewry=0; viewrz=0;
    switch (view)
    {
      case 0:
        apisetviewangles(0,0,0);
        if (o[0].crashzones!=0 && o[0].guns>0)
        apisetviewpos(viewx=0,viewy=0,(viewz=o[0].g[0].gunz*120));
        break;
      case 1:
        apisetviewangles(0,(viewry=32676),0);
        break;
      case 2:
        apisetviewangles(0,(viewry=16384),0);
        break;
      case 3:
        apisetviewangles(0,(viewry=-16384),0);
        break;
      case 4:
        apisetviewangles(0,0,(viewrz=o[0].rsz*1600));
        if (o[0].crashzones==0)
        apisetviewpos((viewx=o[0].rsy*30),
        (viewy=-10+o[0].rsx*30),
        (viewz=-200-(o[0].speed*10)));
        else
        apisetviewpos((viewx=o[0].rsy*30),
        (viewy=-10+o[0].rsx*30),
        (viewz=-4000));
        break;
      case 5:
        apisetviewangles(0,(viewry=32767),(viewrz=o[0].rsz*1600));
        if (o[0].crashzones==0) apisetviewpos((viewx=o[0].rsy*30),(viewy=-10+o[0].rsx*30),(viewz=200+(o[0].speed*10)));
        else apisetviewpos((viewx=o[0].rsy*30),(viewy=-10+o[0].rsx*30),(viewz=4000));
        break;
      case 6:
        apisetviewangles(0,0,(viewrz=o[0].rsz*1600));
        apisetviewpos((viewx=o[0].rsy*30),
        (viewy=-10+o[0].rsx*30),
        (viewz=-(200+o[0].frame3*10)  ));
        if(o[0].doing==10 && ground==0)
        {
          if (key[_C_DOWN] && o[0].rsx<1) o[0].rsx+=0.05;
          if (key[_C_UP] && o[0].rsx>-1) o[0].rsx-=0.05;
          if (key[_C_LEFT] && o[0].rsy>-1) o[0].rsy-=0.05;
          if (key[_C_RIGHT] && o[0].rsy<1) o[0].rsy+=0.05;
          if (key[_C_PGUP])
          {
            for(f=0;f<9;f++) gr[f].cz-=100;
            for(f=1; f<ships; f++) if(o[f].type>-1) o[f].cz-=100;
            for(f=0; f<shapes-10; f++) if(p[f].type>-1) p[f].cz-=100;
          }
          if (key[_C_PGDN])
          {
            for(f=0;f<9;f++) gr[f].cz+=100;
            for(f=1; f<ships; f++) if(o[f].type>-1) o[f].cz+=100;
            for(f=0; f<shapes-10; f++) if(p[f].type>-1) p[f].cz+=100;
          }
        }

        break;
      case 7:
        apisetviewangles((viewrx=-16387),0,0);
        apisetviewpos(0,(viewy=-6000),0);
        break;
      case 8:
        apisetviewangles((viewrx=o[o[0].target].rx),
                         (viewry=o[o[0].target].ry),
                         (viewrz=o[o[0].target].rz));
        if(o[o[0].target].crashzones==0) g=10;
        else g=2;
        apisetviewpos((viewx=o[o[0].target].cx-o[o[0].target].dx[0]*(g*shapedata[o[o[0].target].shape].scale)),
          (viewy=o[o[0].target].cy-o[o[0].target].dy[0]*(g*shapedata[o[o[0].target].shape].scale)),
          (viewz=o[o[0].target].cz-o[o[0].target].dz[0]*(g*shapedata[o[o[0].target].shape].scale)));
        break;
      case 9:
        apisetviewangles((viewrx=32767+o[o[0].target].rx),
                         (viewry=+o[o[0].target].ry),
                         (viewrz=-(32767+o[o[0].target].rz)));
        if(o[o[0].target].crashzones==0) g=10;
        else g=2;
        apisetviewpos((viewx=o[o[0].target].cx+o[o[0].target].dx[0]*(g*shapedata[o[o[0].target].shape].scale)),
          (viewy=o[o[0].target].cy+o[o[0].target].dy[0]*(g*shapedata[o[o[0].target].shape].scale)),
          (viewz=o[o[0].target].cz+o[o[0].target].dz[0]*(g*shapedata[o[o[0].target].shape].scale)));
        break;
    }

    /********* SETUP THE SCREEN **********/

    apiclearcliparea();
    apiclearobjects();
    dddSelectCamera(camera);

    drawstarfield(o[0].rsx,o[0].rsy,o[0].rsz);
    drawplanets();
    if(ground>0)drawground();

    apidrawobjects();
    apiclearobjects();
    dddSelectCamera(camera);

    checkshields(0);
    removal=0;
    missioncompleted=0;
    notcompleted=0;
    completedcount=0;
    critical=0;
    closestcapshipdistance=0;
    closestfighterdistance=0;
    doesitmatter(0);

    if (norand==0) you();
    waypoints();
    drawdebrisfield();

    for(f=1;f<ships;f++)
    {

      if (oe[f].no>-1) if (oe[f].time>-1 && oe[f].time==missiontime && frame1==0 && o[oe[f].no].type>-1)
      {
        if (oe[f].type>-1 && o[oe[f].no].doing!=10)
        {
          o[oe[f].no].type=oe[f].type;
          o[oe[f].no].frame1=1;
          o[oe[f].no].target=-1;
          o[oe[f].no].rsx=o[oe[f].no].rsy=o[oe[f].no].rsz=0;
        }
        if (oe[f].doing>-1 && o[oe[f].no].doing!=10)
        {
          o[oe[f].no].doing=oe[f].doing;
          o[oe[f].no].frame1=1;
          o[oe[f].no].target=-1;
        }
        if (oe[f].side>-1)
        {
          o[oe[f].no].side=oe[f].side;
          o[oe[f].no].target=-1;
          for (g=1; g<ships; g++) if (o[g].type<-1 && o[g].target==oe[f].no) o[g].target=-1;
        }
        if (o[oe[f].no].target>-1 && oe[f].target>-1 && o[o[oe[f].no].target].type>-1) o[oe[f].no].target=oe[f].target;
        if (oe[f].topspeed>-1) o[oe[f].no].topspeed=oe[f].topspeed;
        if (oe[f].toprevs>-1)     o[oe[f].no].toprevs=oe[f].toprevs;
        if (oe[f].shields>-1)     o[oe[f].no].shields=oe[f].shields;
        if (oe[f].maxshields>-1)  o[oe[f].no].maxshields=oe[f].maxshields;
        if (oe[f].armour>-1)      o[oe[f].no].armour=oe[f].armour;
        if (oe[f].maxarmour>-1)   o[oe[f].no].maxarmour=oe[f].maxarmour;
        if (oe[f].stubborn>-1)    o[oe[f].no].stubborn=oe[f].stubborn;
        if (oe[f].destination>-1) o[oe[f].no].destination=oe[f].destination;
        if (oe[f].rank>-1)        o[oe[f].no].rank=oe[f].rank;
        if (oe[f].wingleader>-1)  o[oe[f].no].wingleader=oe[f].wingleader;
        if (oe[f].wingtype>-1)    o[oe[f].no].wingtype=oe[f].wingtype;
        // The following do exist, but arn't initialised for some odd fucker of a reason.
        // You WILL cause crashes by enabling them without rewriting large chunks of the
        // fucking mission editor code. Sod that, I thought, Rem the soddists out.
/*
        if (oe[f].wingx>-1)       o[oe[f].no].wingx=oe[f].wingx;
        if (oe[f].wingy>-1)       o[oe[f].no].wingy=oe[f].wingy;
        if (oe[f].wingz>-1)       o[oe[f].no].wingz=oe[f].wingz;
*/
      }
      // CREATE CREATE OBJECTS
      if (co[f].time>-1)
      {
        if (o[0].doing==ENTERING_HYPERSPACE && o[0].frame1<0) co[f].cz+=o[0].frame1*100;
        spincreateobjects(f,0,0,0,o[0].rsx,o[0].rsy,o[0].rsz);
//        if ((co[f].time<=missiontime+2) && (co[f].time>missiontime) && (o[co[f].no].type==-1) && co[f].createtype==0 )
//          for (g=0; g<10; g++) apiinsertobject(DRW_MOBILE,8,Semaphores, co[f].cx + saferandom(200), co[f].cy + saferandom(200), co[f].cz + saferandom(200), apirandom(6553)*10,apirandom(6553)*10,apirandom(6553)*10);

// COULD BE A PROBLEM HERE IN CREATEING OBJECTS USING THE DEPENDANCE PART

        if (co[f].time==missiontime && frame1==0 && o[co[f].no].type==-1 &&  (co[f].dpt==0 || (co[f].dpt==1 && dpt[co[f].no]==1)) )
        {

          if(co[f].createtype==0)
          {
            xdir=0;
            ydir=angle(co[f].dx[0],co[f].dz[0]);
            if (co[f].dz[0]<=0 && co[f].dx[0]>=0) ydir+=PI;
            if (co[f].dz[0]<=0 && co[f].dx[0]<0) ydir-=PI;
            zdir=angle(co[f].dy[0],co[f].dx[0]);
            createship( co[f].no,co[f].type,co[f].shape,
              co[f].cx,co[f].cy,co[f].cz,
              xdir*16, -ydir*16, zdir*16,
              co[f].rsx,co[f].rsy , co[f].rsz ,co[f].sx,co[f].sy,co[f].sz,
              co[f].stubborn, co[f].wingleader, co[f].wingtype,
              co[f].wingx,co[f].wingy,co[f].wingz,
              co[f].destination, co[f].name, co[f].rank , co[f].target,co[f].mother,co[f].motherhangerzone );
            createexplosion(complexity*3, co[f].cx, co[f].cy, co[f].cz, 20,20,20 );
            o[co[f].no].doing = LEAVING_HYPERSPACE; // hyperspace exit
            o[co[f].no].frame1 = 80;   // miles away. 80
            o[co[f].no].sx = co[f].dx[0];
            o[co[f].no].sy = co[f].dy[0];
            o[co[f].no].sz = co[f].dz[0];
            complatest=0;
            addcomputer( o[co[f].no].name,o[co[f].no].side );
            addcomputer( "HAS ARRIVED.",o[co[f].no].side );
            if(o[co[f].no].side==o[0].side) playtricia(13);
            else playtricia(14);
          }
          else if(co[f].createtype==1 && co[f].mother>-1 && o[co[f].mother].type>-1 && o[co[f].mother].hangerzones>0 && co[f].motherhangerzone<=o[co[f].mother].hangerzones)
          {
              xdir=0;
              ydir=angle(o[co[f].mother].h[co[f].motherhangerzone].dx[0],o[co[f].mother].h[co[f].motherhangerzone].dz[0]);
              if (o[co[f].mother].h[co[f].motherhangerzone].dz[0]>=0 && o[co[f].mother].h[co[f].motherhangerzone].dx[0]<=0) ydir+=PI;
              if (o[co[f].mother].h[co[f].motherhangerzone].dz[0]>=0 && o[co[f].mother].h[co[f].motherhangerzone].dx[0]>0) ydir-=PI;
              zdir=angle(o[co[f].mother].h[co[f].motherhangerzone].dy[0],o[co[f].mother].h[co[f].motherhangerzone].dx[0]);
              createship( co[f].no,co[f].type,co[f].shape,
                o[co[f].mother].cx+(o[co[f].mother].h[co[f].motherhangerzone].cx),
                o[co[f].mother].cy+(o[co[f].mother].h[co[f].motherhangerzone].cy),
                o[co[f].mother].cz+(o[co[f].mother].h[co[f].motherhangerzone].cz),
                xdir*16, -ydir*16, zdir*16,
                co[f].rsx,co[f].rsy , co[f].rsz, 0,0,10,
                co[f].stubborn, co[f].wingleader, co[f].wingtype,
                co[f].wingx,co[f].wingy,co[f].wingz,
                co[f].destination, co[f].name, co[f].rank , co[f].target,co[f].mother,co[f].motherhangerzone );
              o[co[f].no].speed=10;
              o[co[f].no].frame1=1;
              o[co[f].no].doing=LAUNCHING;
              complatest=0;
              addcomputer( o[co[f].no].name,o[co[f].no].side );
              addcomputer( "HAS LAUNCHED.",o[co[f].no].side );
          }
        } // end of time
      } // end of existing.
      doesitmatter(f);
      if (o[f].type>-1)
      {
        if(o[f].doing==LAUNCHING)
        {
          o[f].frame1++;
          if(o[f].frame1>20) o[f].doing=ATTACKING;
        }
        if (o[f].type!=TYPE_NONSENTIENT) calculateheight(f);
        if (o[0].doing==ENTERING_HYPERSPACE && o[0].frame1<0) o[f].cz+=o[0].frame1*100;
        if (o[f].doing<DIEING) for (g=0; g<o[f].guns; g++)
        {
          if (o[f].g[g].fireframe>0)
          {
            o[f].g[g].fireframe++;
            if(o[f].g[g].fireframe>gunrate[ o[f].g[g].type ])  o[f].g[g].fireframe=0;
          }
        }
        distance=(pythag3d(o[f].cx,o[f].cy,o[f].cz)-pythag3d(viewx,viewy,viewz));
        if (distance<0) distance=-distance;

        if(o[f].turrets>0 && o[f].doing <DIEING && o[f].type>0 && o[f].type!=4) drawturrets(f);
        switch(o[f].type)
        {
          case TYPE_NONSENTIENT:
          case TYPE_DUMBCONVOY:
          {
            if (o[f].crashzones>0 && (closestcapshipdistance==0 || distance<closestcapshipdistance) && o[f].doing<10) closestcapshipdistance=distance;
            if (o[f].crashzones==0 && (closestfighterdistance==0 || distance<closestfighterdistance) && o[f].doing<10) closestfighterdistance=distance;
            if (o[f].type==TYPE_DUMBCONVOY && o[f].armour<o[f].maxarmour/2) // Panic! Your nearly dead!
            {
              sprintf(s1,"%s BREAKING FORMATION!", shapedata[o[f].shape].type);
              if (commtimer>10 || commtimer==0) createcomm(f,2,o[f].side,s1);
              o[f].sx=o[f].sy=o[f].sz=0; o[f].speed=0;
              if (o[f].guns==0) o[f].type=TYPE_BROADSIDE;
              else o[f].type=TYPE_NORMAL;
            }
          }
          case TYPE_DERELICT:
          {
            spinobject(f,o[f].cx,o[f].cy,o[f].cz,o[f].rsx,o[f].rsy,-o[f].rsz,1);
            checkshields(f);
            break;
          } // End of shape is nothing much
          case TYPE_AMBUSH:
          {
            spinobject(f, o[f].cx,o[f].cy,o[f].cz, o[f].rsx,o[f].rsy, -o[f].rsz ,0 );
            checkshields(f);
            for (g=0; g<ships; g++) if ((o[g].type>-1)&&(o[g].side!=o[f].side))
            {
              tx=o[g].cx-o[f].cx;
              ty=o[g].cy-o[f].cy;
              tz=o[g].cz-o[f].cz;
              if(pythag3d(tx,ty,tz)<2000||o[f].shields<o[f].maxshields/2) o[f].type=1;
            }
            break;
          }
          case TYPE_NORMAL:
          case TYPE_APPROXIMATE:
          case TYPE_BROADSIDE:
          case TYPE_CONVOY:
          {
            if (o[f].crashzones>0 && (closestcapshipdistance==0 || distance<closestcapshipdistance) && o[f].doing<10) closestcapshipdistance=distance;
            if (o[f].crashzones==0 && (closestfighterdistance==0 || distance<closestfighterdistance) && o[f].doing<10) closestfighterdistance=distance;
            if(o[f].doing<DIEING)
            {
              if(o[f].crashzones>0 && o[f].target>-1 && o[f].wingleader==-1)
              if(o[o[f].target].crashzones==0 ) for (g=0; g<ships; g++)
                if (o[g].crashzones>0 && f!=g && o[g].type>-1 && o[f].side!=o[g].side && o[g].side>0 && o[g].doing<DIEING && o[g].shape!=99 && o[g].shape!=100) o[f].target=g;
              if (o[f].target==-1 && o[f].doing<APPROACHING || o[f].type==TYPE_CONVOY) // No target.
              {
                if (o[f].type==TYPE_CONVOY && o[f].armour<o[f].maxarmour/2) // Panic! Your nearly dead!
                {
                  sprintf(s1,"%s BREAKING FORMATION!", shapedata[o[f].shape].type);
                  if (commtimer>10 || commtimer==0) createcomm(f,2,o[f].side,s1);
                  o[f].sx=o[f].sy=o[f].sz=0; o[f].speed=0;
                  if (o[f].guns==0) o[f].type=TYPE_BROADSIDE;
                  else o[f].type=TYPE_NORMAL;
                }
                if(o[f].wingleader==-1) // Must have no wingleader to do this
                {
                  distance2=pythag3d(w[o[f].destination].x-o[f].cx,w[o[f].destination].y-o[f].cy,w[o[f].destination].z-o[f].cz);
                  if((o[f].speed<=o[f].topspeed/2 || (o[f].type==TYPE_CONVOY && o[f].speed<=o[f].topspeed)) && distance2>500) speedup_ship(f);
                  else if ( (o[f].speed>0) ) slowdown_ship(f);
                  aimship(w[o[f].destination].x-o[f].cx,w[o[f].destination].y-o[f].cy,w[o[f].destination].z-o[f].cz,0.04,0,f);
                }
                xold=yold=zold=0;
                for(g=0;g<ships; g++)
                {
                  if(o[g].side>0 && o[g].side!=o[f].side && o[g].shape!=99 && o[g].shape!=100 && /*o[g].shape>9 && o[g].shape<29 && */ o[g].type>-1 && o[g].doing<DIEING && ((apirandom(9)>4 || norand==1) || o[f].crashzones>0))
                  {
                    // Possible target
                    dx=o[g].cx-o[f].cx;
                    dy=o[g].cy-o[f].cy;
                    dz=o[g].cz-o[f].cz;
                    if((xold==0 && yold==0 && zold==0) || (pythag3d(xold,yold,zold)>pythag3d(dx,dy,dz)))
                    {
                      // Select target
                      xold=dx;
                      yold=dy;
                      zold=dz;
                      if((o[f].wingtype==2 && g==o[o[f].wingleader].target) ||
                      (o[g].target==o[f].wingleader) ||
                      (o[f].wingleader==-1 || o[f].wingtype==1 || o[f].wingtype==3 || o[f].wingtype==4))
                      {
                        o[f].target=g;
                        if (o[f].crashzones>0 && o[g].crashzones>0 && o[f].wingtype==0)
                        break; // This bit makes cap ships go after cap ships.
                      }
                    } // End of target selected
                  } // End of possible target choose
                } // End of go through ships
              } // End of no target
              distance2=0;
              if(o[f].wingleader>-1 && o[f].target>-1)
              {
                distance2=pythag3d(o[o[f].target].cx-o[f].cx,o[o[f].target].cy-o[f].cy,o[o[f].target].cz-o[f].cz);
                if(o[f].wingtype==3 || o[f].wingtype==4) distance2=0;
                if(o[f].wingtype==5) distance2=10000;
                if(o[o[f].target].type==-1) o[f].target=-1;
              }
              if(o[f].wingleader>-1 && (o[f].target==-1 || distance2>4000) && o[f].doing<APPROACHING)
              {
                if(o[o[f].wingleader].type==-1 || o[o[f].wingleader].doing>=DIEING) o[f].wingleader=-1;
                else // Form on the wingleader
                {
                  dx=-o[f].cx+o[o[f].wingleader].cx+(0.01*((o[o[f].wingleader].dx[2]*o[f].wingx)+(o[o[f].wingleader].dx[0]*o[f].wingz)+(o[o[f].wingleader].dx[1]*o[f].wingy)));
                  dy=-o[f].cy+o[o[f].wingleader].cy+(0.01*((o[o[f].wingleader].dy[2]*o[f].wingx)+(o[o[f].wingleader].dy[0]*o[f].wingz)+(o[o[f].wingleader].dy[1]*o[f].wingy)));
                  dz=-o[f].cz+o[o[f].wingleader].cz+(0.01*((o[o[f].wingleader].dz[2]*o[f].wingx)+(o[o[f].wingleader].dz[0]*o[f].wingz)+(o[o[f].wingleader].dz[1]*o[f].wingy)));
                  distance2=pythag3d(dx,dy,dz);
                  if(o[f].speed<=o[f].topspeed && (o[f].speed<o[o[f].wingleader].speed || distance2>500)) speedup_ship(f);
                  else if (o[f].speed>0 && o[f].speed>o[o[f].wingleader].speed) slowdown_ship(f);
                  aimship(dx,dy,dz,0.1,0,f);
                } // end of wingleader exists.
              } // end of ship thinks it has a wingleader.
              else if (o[f].target>-1 && o[f].doing<APPROACHING)         // A target
              {
                if (o[f].target==0 && incoming!=2) incoming=1;
                if (o[f].target>-1)
                {
                  if (o[o[f].target].type==-1 || o[o[f].target].doing>10) o[f].target=-1;
                }
                // This bit creates comm chatter for ships with targets destroyed
                if (o[f].target>-1 && o[o[f].target].doing==DIEING && o[f].side<=2)
                {
                  var1=apirandom(5);
                  sprintf(s1,"%s REPORTING %s DESTROYED",
                    shapedata[o[f].shape].type,
                    shapedata[o[o[f].target].shape].type);
                  if (c[currentcomm].type!=2 && o[f].side==2)
                  {
                    switch(var1)
                    {
                      case 2:
                        sprintf(s1,"%s REPORTING DESTRUCTION OF %s",
                          shapedata[o[f].shape].type,
                          o[o[f].target].name);
                        break;
                      case 3:
                        sprintf(s1,"%s DESTROYED BY %s",
                          shapedata[o[o[f].target].shape].type,
                          shapedata[o[f].shape].type);
                        break;
                      case 4:
                        sprintf(s1,"%s HAS BEEN DESTROYED",
                          o[o[f].target].name);
                        break;
                    }
                  }
                  else if (c[currentcomm].type!=2 && o[f].side==1)
                  {
                    switch(var1)
                    {
                      case 1:
                        sprintf(s1,"%s HERE, ONE LESS %s!",
                          shapedata[o[f].shape].type,
                          shapedata[o[o[f].target].shape].type);
                        break;
                      case 2:
                        sprintf(s1,"HAVE SOME OF THAT %s",
                          o[o[f].target].name);
                        break;
                      case 3:
                        sprintf(s1,"SCRATCH ONE %s",
                          shapedata[o[o[f].target].shape].type);
                        break;
                      case 4:
                        sprintf(s1,"%s HAS BEEN DESTROYED",
                          o[o[f].target].name);
                        break;
                    }
                  }
                  if (c[currentcomm].type!=2 && (commtimer>10 || commtimer==0)) createcomm(f,1,o[f].side,s1);
                }
                if (o[f].target>-1) // This bit makes the ship match speeds with his target
                {
                  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);
                  if(o[f].speed<=o[f].topspeed && (o[f].speed<o[o[f].target].speed || o[o[f].target].crashzones>0 || o[o[f].target].speed==0 || o[f].doing==ATTACKING || o[f].doing==WITHDRAWING || distance2>3500)) speedup_ship(f);
                  else if(o[f].speed>2 && o[f].speed>o[o[f].target].speed) slowdown_ship(f);
                } // end of has target
                xdir=ydir=zdir=0;
                if (o[f].doing==ATTACKING) // Normal attack procedures...
                {
                  switch(o[f].type)
                  {
                    case 1: aimship(dx,dy,dz,0.04,1,f); break;
                    case 2: aimship(dx,dy,dz,0.2,1,f); break;
                    case 3: aimship(dx,dy,dz,0.8,1,f); break;
                  }
                  if (o[f].target>-1
                  && ((distance2<450 && o[o[f].target].crashzones==0)
                  || (distance2 <1400 && o[o[f].target].crashzones>0)
                  || (distance2 <2500 && o[o[f].target].shape==86)
                  || (o[f].crashzones>0 && o[o[f].target].crashzones>0 && distance2<1800)
                  || (o[f].shape==71 && distance2<1800)
                  || ((o[o[f].target].shape==90 || o[o[f].target].shape==91 || o[o[f].target].shape==92) && distance2<2500) )
                  ) // Too close
                  {
// alien might be a bit dogey...
                    if (o[o[f].target].shape==71) o[f].frame1=-150;
                    else if (o[o[f].target].crashzones>0) o[f].frame1=1;
                    else if (o[o[f].target].crashzones==0) o[f].frame1=150;
                    o[f].doing=WITHDRAWING;
                  } // End initiate withdraw
                } // End normal attack
                if (o[f].doing==WITHDRAWING && o[f].target>-1) // Withdrawing
                {
                  aimship(o[f].cx-o[o[f].target].cx,o[f].cx-o[o[f].target].cy,o[f].cx-o[o[f].target].cz,0.04,0,f);
                  o[f].frame1++;
                  if (o[f].frame1>220+(norand==0?apirandom(50):0)) // Initiate normal procedures
                  {
                    o[f].frame1=0;
                    o[f].doing=ATTACKING;
                  }
                } // End Withdrawing
              } // End of ship has target
              if (o[f].doing==EVADING) // Evasive manouvers
              {
                if(o[f].speed<=o[f].topspeed) speedup_ship(f);
                o[f].frame1++;
                o[f].frame2++; if (o[f].frame2>30) o[f].frame2=0;
                if (o[f].frame1>100)
                {
                  o[f].frame1=0;
                  o[f].doing=ATTACKING;
                  o[f].rsx=o[f].rsy=o[f].rsz=0;
                }
                spinobject(f, o[f].cx,o[f].cy,o[f].cz, o[f].rsx,o[f].rsy,o[f].rsz ,0 );
              } // End of evasive manouvers
              if ((o[f].doing==APPROACHING || o[f].doing==LININGUP || o[f].doing==LANDING ||
                   o[f].doing==PREPARINGTOBOARD || o[f].doing==BOARDING || o[f].doing==BOARDED)
                   && o[f].mother>-1 && o[o[f].mother].type>-1)
              {
                if (o[f].mother>0 && (o[o[f].mother].type==-1 || o[o[f].mother].doing>=DIEING)) o[f].mother=-1;
                if (o[f].mother<0)
                {
                  if (o[f].guns>0) o[f].doing=ATTACKING; // Boarding craft go into convoy
                  else o[f].type=TYPE_CONVOY;
                }
                if (o[f].mother>0)
                {
                  switch (o[f].doing)
                  {
                    case APPROACHING:
                      dx=-o[f].cx+o[o[f].mother].cx+(o[o[f].mother].h[o[f].motherhangerzone].cx+(20*o[o[f].mother].h[o[f].motherhangerzone].dx[1]));
                      dy=-o[f].cy+o[o[f].mother].cy+(o[o[f].mother].h[o[f].motherhangerzone].cy+(20*o[o[f].mother].h[o[f].motherhangerzone].dy[1]));
                      dz=-o[f].cz+o[o[f].mother].cz+(o[o[f].mother].h[o[f].motherhangerzone].cz+(20*o[o[f].mother].h[o[f].motherhangerzone].dz[1]));
                    break;
                    case LININGUP:
                    case PREPARINGTOBOARD:
                      dx=-o[f].cx+o[o[f].mother].cx+(o[o[f].mother].h[o[f].motherhangerzone].cx+(20*-o[o[f].mother].h[o[f].motherhangerzone].dx[0]));
                      dy=-o[f].cy+o[o[f].mother].cy+(o[o[f].mother].h[o[f].motherhangerzone].cy+(20*-o[o[f].mother].h[o[f].motherhangerzone].dy[0]));
                      dz=-o[f].cz+o[o[f].mother].cz+(o[o[f].mother].h[o[f].motherhangerzone].cz+(20*-o[o[f].mother].h[o[f].motherhangerzone].dz[0]));
                    break;
                    case LANDING:
                    case BOARDING:
                      dx=-o[f].cx+o[o[f].mother].cx+(o[o[f].mother].h[o[f].motherhangerzone].cx);
                      dy=-o[f].cy+o[o[f].mother].cy+(o[o[f].mother].h[o[f].motherhangerzone].cy);
                      dz=-o[f].cz+o[o[f].mother].cz+(o[o[f].mother].h[o[f].motherhangerzone].cz);
                    break;
                    case BOARDED:
                      o[f].cx=o[o[f].mother].cx+(o[o[f].mother].h[o[f].motherhangerzone].cx-o[o[f].mother].h[o[f].motherhangerzone].dx[0]*0.4);
                      o[f].cy=o[o[f].mother].cy+(o[o[f].mother].h[o[f].motherhangerzone].cy-o[o[f].mother].h[o[f].motherhangerzone].dy[0]*0.4);
                      o[f].cz=o[o[f].mother].cz+(o[o[f].mother].h[o[f].motherhangerzone].cz-o[o[f].mother].h[o[f].motherhangerzone].dz[0]*0.4);
                      o[f].dx[0]=o[o[f].mother].h[o[f].motherhangerzone].dx[0];
                      o[f].dy[0]=o[o[f].mother].h[o[f].motherhangerzone].dy[0];
                      o[f].dz[0]=o[o[f].mother].h[o[f].motherhangerzone].dz[0];
                      o[f].dx[1]=o[o[f].mother].h[o[f].motherhangerzone].dx[1];
                      o[f].dy[1]=o[o[f].mother].h[o[f].motherhangerzone].dy[1];
                      o[f].dz[1]=o[o[f].mother].h[o[f].motherhangerzone].dz[1];
                      o[f].dx[2]=o[o[f].mother].h[o[f].motherhangerzone].dx[2];
                      o[f].dy[2]=o[o[f].mother].h[o[f].motherhangerzone].dy[2];
                      o[f].dz[2]=o[o[f].mother].h[o[f].motherhangerzone].dz[2];
                      if (o[f].frame1<=100*shapedata[o[o[f].mother].shape].scale) o[f].frame1++;
                      if (o[f].frame1==100*shapedata[o[o[f].mother].shape].scale)
                      {
// rape class ships wingtype; slave targeter==convoy
                        o[o[f].mother].side=o[f].side;
                        if (o[f].wingtype==1) o[o[f].mother].type=TYPE_BROADSIDE;
                        else if (o[f].wingtype==2) o[o[f].mother].type=TYPE_CONVOY;
                        else if (o[f].wingtype==3) o[o[f].mother].type=TYPE_AMBUSH;
                        else if (o[f].wingtype==4) o[o[f].mother].doing=DIEING;
                        else o[o[f].mother].type=TYPE_NORMAL;
                        complatest=1;
                        addcomputer( shapedata[o[o[f].mother].shape].type , o[f].side );
                        addcomputer( "CAPTURED." , o[f].side);
                        for(g=0;g<ships;g++)
                        {
// Coult this cause a crash then?
                          if(o[g].target==o[f].mother) o[g].target=-1;
                        }
                      }
                    break;
                  }
                  distance2=pythag3d(dx,dy,dz);
                  if(o[f].speed<=o[f].topspeed && o[f].doing!=LANDING && o[f].doing!=BOARDING && o[f].doing!=BOARDED) speedup_ship(f);
                  else if ((o[f].speed>3 && distance2>500 && distance2<700) || (o[f].speed>1 && distance2<300) ) slowdown_ship(f);
                  if (distance2<300)
                  {
                    if(o[f].doing<LANDING || (o[f].doing<BOARDING && o[f].doing>LANDING)) o[f].doing++;
                    else
                    {
                      if(distance2<30 && o[f].doing==LANDING)
                      {
                        complatest=0;
                        addcomputer( shapedata[o[f].shape].type, o[f].side );
                        addcomputer( "HAS DOCKED." , o[f].side);
                        matter[f]=0;
                        free_memory_for_ship(f);
                      }
                    }
                    if(distance2<70 && o[f].doing==BOARDING)
                    {
                      complatest=0;
                      addcomputer( shapedata[o[o[f].mother].shape].type , o[f].side);
                      addcomputer( "BOARDED." , o[f].side);
                      o[f].doing=BOARDED;
                      o[f].sx=o[f].sy=o[f].sz=0; o[f].speed=0;
                      o[f].frame1=1;
                    }
                  }
                  if(o[f].doing!=BOARDED)
                  {
                    if (distance2>1000) aimship(dx,dy,dz,0.1,0,f);
                    else aimship(dx,dy,dz,0.05,0,f);
                  }
                } // End of mother ship exists
              }
              checkshields(f);
            } // End of ship is not dead
            if (flames==ON && o[f].smoking>0 || (o[f].crashzones>0 && o[f].armour<20))
            {
              if(frame2==0 && o[f].crashzones==0 && o[f].doing!=DIEING) createobject(10, apirandom(30)-15+o[f].cx-(o[f].sx*4),apirandom(30)-15+o[f].cy-(o[f].sy*4),apirandom(30)-15+o[f].cz-(o[f].sz*4) ,o[f].sx/2,o[f].sy/2,o[f].sz/2,0,-1 );
              else if(frame2==0 && o[f].crashzones>0)
              {
                if((o[f].doing==DIEING && o[f].frame1<67) || o[f].doing!=DIEING) for(g=1;g<10;g++)
                {
                  h=1+((o[f].crashzones-1)/g);
                  fx2=o[f].cx+((0.01*( (o[f].dx[2]*o[f].c[h].x)+(o[f].dx[0]*o[f].c[h].z)+(o[f].dx[1]*o[f].c[h].y)+o[f].c[h].size)) );
                  fy2=o[f].cy+((0.01*( (o[f].dy[2]*o[f].c[h].x)+(o[f].dy[0]*o[f].c[h].z)+(o[f].dy[1]*o[f].c[h].y)+o[f].c[h].size)) );
                  fz2=o[f].cz+((0.01*( (o[f].dz[2]*o[f].c[h].x)+(o[f].dz[0]*o[f].c[h].z)+(o[f].dz[1]*o[f].c[h].y)+o[f].c[h].size)) );
                  createobject(10, fx2,fy2,fz2 ,-o[f].dx[0]/40,-o[f].dy[0]/40,-o[f].dz[0]/40,0,-1 );
                }
              }
              if (o[f].armour>10) o[f].smoking--;
            } // End of smoke
            if (o[f].target>0 && o[o[f].target].doing>=DIEING) o[f].target=-1;
          } //End of type 1 2 3 case
        } //End of switch
        if (o[f].doing==DIEING)
        {
          o[f].frame1++;
          if(debug==1 && key[_R_CTRL] && o[f].frame1<70) o[f].frame1=70;
          if (o[f].frame3==0) xold=1;
          else xold=0;
          if (o[f].type!=0) spinobject(f, o[f].cx,o[f].cy,o[f].cz, o[f].rsx,o[f].rsy,o[f].rsz ,xold);
          if (o[f].shape==36 || o[f].shape==37 || o[f].shape==38) o[f].frame1=81; // Asteroids.
          if (o[f].frame1>80)
          {
            killoff(f);
            if ((o[f].shape==36 || o[f].shape==37 || o[f].shape==38) && distance<effectsrenderdist)
              createexplosion(1+complexity*2 , o[f].cx, o[f].cy, o[f].cz ,30,30,30 );
          }
          if (o[f].crashzones==0 && apirandom(10)>4 && distance<effectsrenderdist)
            createobject(100, o[f].cx,o[f].cy,o[f].cz, -o[f].sx,-o[f].sy,-o[f].sz, 0,-1);
        } // End of death
        if  (o[f].crashzones>0 && distance<effectsrenderdist && o[f].doing==DIEING)
        {
          g=1+apirandom(o[f].crashzones-1);
          x=y=z=50;
          rx=apirandom(100); ry=apirandom(100); rz=apirandom(100);
          rotatesummat(&x,&y,&z,rx,ry,rz);
          fx2=o[f].cx+((0.01*( (o[f].dx[2]*o[f].c[g].x)+(o[f].dx[0]*o[f].c[g].z)+(o[f].dx[1]*o[f].c[g].y)+o[f].c[g].size*x)) );
          fy2=o[f].cy+((0.01*( (o[f].dy[2]*o[f].c[g].x)+(o[f].dy[0]*o[f].c[g].z)+(o[f].dy[1]*o[f].c[g].y)+o[f].c[g].size*y)) );
          fz2=o[f].cz+((0.01*( (o[f].dz[2]*o[f].c[g].x)+(o[f].dz[0]*o[f].c[g].z)+(o[f].dz[1]*o[f].c[g].y)+o[f].c[g].size*z)) );
          if (apirandom(10)>7) createexplosion(2 , fx2, fy2, fz2 ,30,30,30 );
          if (apirandom(10)>7) createobject(101, fx2,fy2,fz2, 0,0,0, 0,-1);
          if(o[f].frame1==76)
          {
            createobject(201, o[f].cx,o[f].cy,o[f].cz, 0,0,0 ,0,-1);
            if (o[f].shape==25 || o[f].shape==26 || o[f].shape==23 || o[f].shape==24 || o[f].shape==27 || o[f].shape==28)
            {
              createobject(201, o[f].cx+o[f].dx[0]*10,o[f].cy+o[f].dy[0]*10,o[f].cz+o[f].dz[0]*10, 0,0,0 ,0,-1);
              createobject(201, o[f].cx-o[f].dx[0]*10,o[f].cy-o[f].dy[0]*10,o[f].cz-o[f].dz[0]*10, 0,0,0 ,0,-1);
            }
            createtorus(75, o[f].cx,o[f].cy,o[f].cz,0,0,0 );
          }
        } // End of chunky capship death
        if (o[f].type>-1) check(f); // Check its shields if alive; WAS && o[f].doing!=DIEING
        o[f].cz+=-(o[0].speed*velconst)+(o[f].sz*velconst); // Move the ship
        o[f].cx+=o[f].sx*velconst;
        o[f].cy+=o[f].sy*velconst;
        spinobject(f, 0,0,0, o[0].rsx,o[0].rsy,o[0].rsz,0);
        // 8k is chosen as you simply CANT see them beyond that!
        attached(f); // draw things like radar and flames
        if (smalldetails!=OFF && distance<6000 && o[f].turrets>0) for (g=0; g<o[f].turrets; g++)
        {
          apismallshape(DRAWFULL,o[f].t[g].object,o[f].t[g].type,
            o[f].cx+o[f].t[g].cx ,o[f].cy+o[f].t[g].cy ,o[f].cz+o[f].t[g].cz,
            o[f].t[g].rx,o[f].t[g].ry,o[f].t[g].rz );
          apismallshape(DRAWFULL,o[f].t[g].gun,o[f].t[g].type,
            o[f].cx+o[f].t[g].cx ,o[f].cy+o[f].t[g].cy ,o[f].cz+o[f].t[g].cz-2,
            o[f].t[g].srx,o[f].t[g].sry,o[f].t[g].srz );
        }  // End of turrets
        if (smalldetails!=OFF && distance<6000 && o[f].hangerzones>0) for (g=0; g<o[f].hangerzones; g++)
        {
          if (o[f].h[g].type==1) apishape(DRAWFULL,o[f].h[g].object,1,
            o[f].cx+o[f].h[g].cx ,o[f].cy+o[f].h[g].cy ,o[f].cz+o[f].h[g].cz,
            o[f].h[g].rx,o[f].h[g].ry,o[f].h[g].rz );
        }  // End of hangers
        if (o[f].type!=-1 && distance<renderdist)
        {
          if (o[f].crashzones>0 || (o[f].crashzones==0 && distance<6000)) // cap ships or small fighters at close range
            {
              if((o[f].shape==99 || o[f].shape==100) && ground>0)
                apiground(DRAWFULL,o[f].object, o[f].cx,o[f].cy,o[f].cz, o[f].rx,o[f].ry,o[f].rz);
              else
                apishape(DRAWFULL,o[f].object,0, o[f].cx,o[f].cy,o[f].cz, o[f].rx,o[f].ry,o[f].rz);
//              apishape(DRAWFULL,o[f].object,0, o[f].cx,o[f].cy,o[f].cz, o[f].rx,o[f].ry,o[f].rz);
            }
          else // small fighters far away.
            apishape(DRW_SIMPLE,o[f].farobject,0, o[f].cx,o[f].cy,o[f].cz, o[f].rx,o[f].ry,o[f].rz);
        }
        if (o[f].sparking>0 && distance<effectsrenderdist && o[f].crashzones==0)
        {
          xold=o[f].cx/(o[f].cz/0x100);
          yold=o[f].cy/(o[f].cz/0x100);
          apiprojectile(DRW_SIMPLE,o[f].spark,o[f].sparking-1,o[f].cx,o[f].cy,o[f].cz*o[f].sparkz ,o[f].sparkx,o[f].sparky,apirandom(6553)*10);
//          apiprojectile(DRW_SIMPLE,o[f].spark,o[f].sparking-1,o[f].cx,o[f].cy,o[f].cz ,o[f].sparkx,o[f].sparky,apirandom(6553)*10);
//          if (frame1==0)
          o[f].sparking++;
          if (o[f].sparking>3) o[f].sparking=0;
        } // End of spark
      } // end of existing object
      if (o[f].doing==LEAVING_HYPERSPACE && o[f].type>-1)
      {
        o[f].sx=o[f].sx/1.05;
        o[f].sy=o[f].sy/1.05;
        o[f].sz=o[f].sz/1.05;
        o[f].frame1--;
        if (o[f].frame1<1)
        {
          o[f].doing=ATTACKING;
          o[f].sx=0;
          o[f].sy=0;
          o[f].sz=0;
          o[f].speed=0;
        }
      }
      if (o[f].doing==ENTERING_HYPERSPACE && o[f].type>-1)
      {
        o[f].sx=o[f].dx[0]*((float)o[f].frame1/50);
        o[f].sy=o[f].dy[0]*((float)o[f].frame1/50);
        o[f].sz=o[f].dz[0]*((float)o[f].frame1/50);
        o[f].frame1++;
        if (o[f].frame1>100) // Vanish the ship
        {
          createexplosion(complexity*3, o[f].cx, o[f].cy, o[f].cz, 20,20,20 );
          complatest=0;
          addcomputer( o[f].name , o[f].side);
          addcomputer( "HAS LEFT." , o[f].side);
          matter[f]=0;
          free_memory_for_ship(f);
         } // End of vanish the ship
      } // End of entering hyperspace
    } // of for f

    if (closestcapshipdistance>0)
    {
      distance=closestcapshipdistance-pythag3d(viewx,viewy,viewz);
      if (distance<0) distance=-distance;
      playsoundeffect(10,distance);
    }
    if (closestfighterdistance>0)
    {
      distance=closestfighterdistance-pythag3d(viewx,viewy,viewz);
      if (distance<0) distance=-distance;
      if (distance<250) playsoundeffect(12,distance*2);
    }

    projectiles();
    if (norand==0) keyboardstuff();

//    apiclearobjects();
    dddInsertObject(light);
    apidrawobjects();
    apiclearobjects();                               

    if (view==0 &&norand==0) moveyourguns();
    dddInsertObject(light);
    dddSelectCamera(ccamera);// The objects are drawn later!
    apidrawobjects();

    if (completedcount>ships-1 && notcompleted==0 && missiontime>finishtime) missioncompleted=COMPLETED;

    if (view<=3 && o[0].shields<o[0].maxshields/2 && frame1<5 && o[0].doing!=10)
    {
      if (frame1==0 && fx==1 && soundblaster==1 && (o[0].crashzones==0 || o[0].armour<o[0].maxarmour/10))
      {
        playing[14]=0;
        playsoundeffect(14,0);
      }
      if(drawcockpit==0)
      {
        apibox(160,0,0,319,5);
        apibox(160,0,194,319,199);
      }
    }
    if (view==0 && norand==0)
    {
      updatescanner();
      if (commtimer>0)
      {
        commtimer++;
        if (commtimer>50) commtimer=0;
        col1=107; col2=104; col3=97;
        if (c[currentprintcomm].side==1)
        {
          col1=140;col2=134;col3=124;
        }
        if (c[currentprintcomm].side==2)
        {
          col1=156;col2=151;col3=144;
        }
        jx=judx+o[0].rsz*10;
        jy=judy+o[0].rsx*5;
        g=2;
        for(f=146; f<=154; f++)
        {
          apiline(col1+g,jx+((g/2)+158-(strlen(c[currentprintcomm].msg)*2)),jy+f,
                          jx+(-(g/2)+161+(strlen(c[currentprintcomm].msg)*2)),jy+f);
          if(f<150) g-=2;
          else g+=2;
        }
        apiniceprint3(col3,col2,jx+(160-(strlen(c[currentprintcomm].msg)*2)),jy+148,c[currentprintcomm].msg );
        if (o[c[currentprintcomm].from].type>-1 && c[currentprintcomm].from>-1 )
        {
          g=2;
          for(f=136; f<=144; f++)
          {
            apiline(col1+g,jx+((g/2)+158-(strlen(o[c[currentprintcomm].from].name)*2)),jy+f,
                           jx+(-(g/2)+161+(strlen(o[c[currentprintcomm].from].name)*2)),jy+f);
            if(f<140) g-=2;
            else g+=2;
          }
          apiniceprint3(col3,col2,jx+(160-(strlen(o[c[currentprintcomm].from].name)*2)),jy+138,o[c[currentprintcomm].from].name );
        }
      }
      if (c[currentprintcomm].newcomm==1 && commtimer==0)
      {
        commtimer=1; currentprintcomm++;
        if (currentprintcomm>comms-1) currentprintcomm=0;
      }
      if (critical==1) apiniceprint3(209,2,132+judx, 105+judy, "MISSION CRITICAL" );
      if (ground>0 && ((height<300 && gr[4].dy[0]<0) || height<50 ))
      {
        apiniceprint3(209,2,148+judx, 111+judy, "PULL UP" );
        playtricia(19);
      }
      if (computer==1 && view==0) printcomputer( missioncompleted , notcompleted , critical );
      // Red warning bars
    }
    else if (norand==0) apiniceprint3(11,33,10, 10, views[view] );
    else if (norand==1) displaybriefing();

    this_time = apireadtimer();
    old_time=this_time-first_time;

    if(debug==1)
    {
      gcvt((this_time-first_time),7,s1);
      strcat(s1, " T" ); //1179650 seconds
      apigameprint3(1,10,134,s1);
    }

    while (this_time<maxspeed) this_time=apireadtimer();
            
    if (key[_D] && key[_B] && demo!=2) debug=1;
    if(debug==1)
    {
      gcvt(1179650L/(this_time-first_time),3,s1);
      strcat(s1, " FPS" ); //1179650 seconds
      apigameprint3(1,10,140,s1);
      sprintf(s1,"SOUND:%d MUSIC:%d FX:%d",soundblaster,music,fx);
      apigameprint3(1,10,128,s1);
      sprintf(s1,"FRAME:%d ",frame1);
      if(frame1<10) apigameprint3(1,10,110,s1);
      else apigameprint3(2,10,110,s1);
      if(ground>0)
      {
        gcvt( height ,7,s1); strcat(s1, " HEIGHT" );
        apigameprint3(1,10,116,s1);
//        apiline(1,160,50,160+(gr[4].dx[0]/ ((gr[4].dz[0]/250)+50) ),50+(gr[4].dy[0]/ ((gr[4].dz[0]/250)+50) ));
//        apiline(1,160,50,160+(gr[4].dx[1]/ ((gr[4].dz[1]/250)+50) ),50+(gr[4].dy[1]/ ((gr[4].dz[1]/250)+50) ));
//        apiline(1,160,50,160+(gr[4].dx[2]/ ((gr[4].dz[2]/250)+50) ),50+(gr[4].dy[2]/ ((gr[4].dz[2]/250)+50) ));
//        apiline(2,160,50,160+(grx[0]/ ((grz[0]/250)+50) ),50+(gry[0]/ ((grz[0]/250)+50) ));
//        apiline(2,160,50,160+(grx[1]/ ((grz[1]/250)+50) ),50+(gry[1]/ ((grz[1]/250)+50) ));
//        apiline(2,160,50,160+(grx[2]/ ((grz[2]/250)+50) ),50+(gry[2]/ ((grz[2]/250)+50) ));
      }
      gcvt( pilot.kills ,7,s1); strcat(s1, " KILLS" );
      apigameprint3(1,10,122,s1);
      gcvt( missiontime ,7,s1); strcat(s1, " U" );
      apigameprint3(1,10,146,s1);
      gcvt( no_projectiles ,7,s1); strcat(s1, " P" );
      apigameprint3(1,10,152,s1);
      gcvt( o[0].target ,7,s1);
      apigameprint3(1,10,158,s1);
      gcvt( missioncompleted ,7,s1); strcat(s1, " C" );
      apigameprint3(1,10,164,s1);
      if (key[_U] ) spinobject(49, o[49].cx,o[49].cy,o[49].cz, 1,0, 0 ,0 );
      if (key[_M] ) spinobject(49, o[49].cx,o[49].cy,o[49].cz, -1,0, 0 ,0 );
      if (key[_H] ) spinobject(49, o[49].cx,o[49].cy,o[49].cz, 0,-1, 0 ,0 );
      if (key[_K] ) spinobject(49, o[49].cx,o[49].cy,o[49].cz, 0,1, 0 ,0 );
      if (key[_D] )
      {
        if (o[49].guns>0) for (g=0; g<o[49].guns; g++)
        {
          xold=((o[49].cx + o[49].dx[0] * 0.8) + (o[49].dx[2] * o[49].g[g].fireflag * o[49].g[g].gun ) + (o[49].dx[0] * o[49].g[g].gunz ) + (o[49].dx[1] * o[49].g[g].guny ))
          / (((o[49].cz + o[49].dz[0] * 0.8) + (o[49].dz[2] * o[49].g[g].fireflag * o[49].g[g].gun ) + (o[49].dz[0] * o[49].g[g].gunz ) + (o[49].dz[1] * o[49].g[g].guny ))/0x100);
          yold=   ((o[49].cy + o[49].dy[0] * 0.8) + (o[49].dy[2] * o[49].g[g].fireflag * o[49].g[g].gun ) + (o[49].dy[0] * o[49].g[g].gunz ) + (o[49].dy[1] * o[49].g[g].guny )) /
          (((o[49].cz + o[49].dz[0] * 0.8) + (o[49].dz[2] * o[49].g[g].fireflag * o[49].g[g].gun ) + (o[49].dz[0] * o[49].g[g].gunz ) + (o[49].dz[1] * o[49].g[g].guny ))/0x100);
          safelineellipse(2,160+xold,(100+yold), 7,7);
          f=22;
        }
      }
      if (key[_S])
      {
        xold=(o[49].cx)/(o[49].cz/0x100);
        yold=(o[49].cy)/(o[49].cz/0x100);
        if ( (xold>-150)&&(xold<150)&&(yold>-90)&&(yold<90) )
        {
          if (o[49].crashzones>0) for (g=0; g<o[49].crashzones; g++)
          {
            tx=o[49].cx+(0.01*( (o[49].dx[2]*o[49].c[g].x)+(o[49].dx[0]*o[49].c[g].z)+(o[49].dx[1]*o[49].c[g].y)   )  ) ;
            ty=o[49].cy+(0.01*( (o[49].dy[2]*o[49].c[g].x)+(o[49].dy[0]*o[49].c[g].z)+(o[49].dy[1]*o[49].c[g].y)   )  ) ;
            tz=o[49].cz+(0.01*( (o[49].dz[2]*o[49].c[g].x)+(o[49].dz[0]*o[49].c[g].z)+(o[49].dz[1]*o[49].c[g].y)   )  ) ;
            xold = (tx/(tz/0x100));
            yold = (ty/(tz/0x100));
            zold= o[49].c[g].size / (o[49].cz / 0x100) ;
            safelineellipse(1,160+xold,(100+yold), zold,zold);
          }
        }
      }
      if (key[_TAB] && o[0].target>0) damageship(o[0].target,gunpower[NUKE]);
      if (key[_C])
      {
        o[0].shields=o[0].maxshields;
        o[0].armour=o[0].maxarmour;
      }
    }
    if (key[_ALTERNATE] && key[_P] && targetframe==0) pause();
    if (key[_ALTERNATE] && key[_C]) calibrate();
    apiscreenswap();
  } // End while.
  if(music==1 && norand==0)
  {
    mod_data = tempmodsong;
    ModCommand(v_stop);
  }
} // End of game.

void  keyboardstuff(void)
{
  int f;
  int g,h,createtype;
  int soundtype;
  float tempx,tempy,tempz;
  float wantx,wanty,wantz;
  char s1[80];

  if ((key[_ALTERNATE])&&(key[_D])&&(targetframe==0))
  {
    targetframe=1;
    detailsettings();
  }
  if ((key[_ALTERNATE])&&(key[_O])&&(targetframe==0))
  {
    targetframe=1;
    options();
  }

  if (o[0].doing==10 || (o[0].doing==ENTERING_HYPERSPACE && o[0].frame1<0)) return;  // If person is dead or hyperspacing, ignore these controls

  if((key[_F1] || key[_F2] || key[_F3] ||
      key[_F4] || key[_F5] || key[_F6] ||
      key[_F7] || key[_F8]) ||(o[0].target>0 && (key[_F9] || key[_F10])))
  {
    if(key[_F1]) view=0;
    if(key[_F2]) view=1;
    if(key[_F3]) view=3;
    if(key[_F4]) view=2;
    if(key[_F5]) view=4;
    if(key[_F6]) view=5;
    if(key[_F7]) view=6;
    if(key[_F8]) view=7;
    if(key[_F9]) view=8;
    if(key[_F10]) view=9;
  }

  switch(control)  // Ship control done depending on what is used as controller
  {
    case 0:  // Keyboard
      if (key[_C_LEFT])
      {
        if (o[0].rsy>-o[0].toprevs) o[0].rsy -= 0.1*1.5;
        if (o[0].rsz<0.75*o[0].toprevs) o[0].rsz += 0.075*1.5;
      }
      else if (key[_C_RIGHT])
      {
        if (o[0].rsy<o[0].toprevs) o[0].rsy += 0.1*1.5;
        if (o[0].rsz>-0.75*o[0].toprevs) o[0].rsz -= 0.075*1.5;
      }
      else
      {
        o[0].rsy=o[0].rsy/1.3; // 1.2
        if (o[0].rsy<0.1 && o[0].rsy>-0.1) o[0].rsy=0;
        o[0].rsz=o[0].rsz/1.3; // 1.2
        if (o[0].rsz<0.02 && o[0].rsz>-0.02) o[0].rsz=0;
      }
      if (key[_C_UP] && o[0].rsx>-o[0].toprevs) o[0].rsx -= 0.1*1.5;
      else if (key[_C_DOWN] && o[0].rsx<o[0].toprevs) o[0].rsx += 0.1*1.5;
      else
      {
        o[0].rsx=o[0].rsx/1.3; // 1.1
        if ((o[0].rsx<0.09)&&(o[0].rsx>-0.09)) o[0].rsx=0;
      }
      if (key[_COMMA] && o[0].rsz<2*o[0].toprevs) o[0].rsz += 0.2*1;
      else if (key[_FULL_STOP] && o[0].rsz>-2*o[0].toprevs) o[0].rsz -= 0.2*1;
      else
      {
        o[0].rsz=o[0].rsz/1.3; // 1.1
        if (o[0].rsz<0.02 && o[0].rsz>-0.02) o[0].rsz=0;
      }
      break;
    case 1: //Joystick

      apireadjoystick();
      // if stick in little range then be GENTLE. if stick in large range then be HARD
      tempx=((apijoystick_x_position)-jcenterx);
      tempy=((apijoystick_y_position)-jcentery);
      if (debug==1)
      {
        apibox(44,0,100,30,130);
        apiplot(1,15+tempx/30,(115+tempy/30));
      } // 120!!!!
      tempx=(tempx/16.0); if (tempx>-1 && tempx<1) tempx=0;
      tempy=(tempy/16.0); if (tempy>-1 && tempy<1) tempy=0;
      if (tempx>0) tempx--;
      if (tempx<0) tempx++;
      if (tempy>0) tempy--;
      if (tempy<0) tempy++;
      if (debug==1)
      {
        apiplot(2,15+tempx*4,(115+tempy*4));
      }
      wantx=(tempy*o[0].toprevs)/3.3;
      wanty=(tempx*o[0].toprevs)/3.3;
      wantz=-(tempx*o[0].toprevs*0.75)/3.3;
      if (o[0].rsx<wantx || o[0].rsx>wantx) o[0].rsx+=wantx/6;
      o[0].rsx=o[0].rsx/1.1;
      if (o[0].rsx<0.09 && o[0].rsx>-0.09 && wantx==0) o[0].rsx=0;
      if (o[0].rsx<wanty || o[0].rsx>wanty) o[0].rsy+=wanty/6;
      o[0].rsy=o[0].rsy/1.1;
      if (o[0].rsy<0.09 && o[0].rsy>-0.09 && wanty==0) o[0].rsy=0;
      if (o[0].rsz<wantz || o[0].rsz>wantz) o[0].rsz+=wantz/6;
      o[0].rsz=o[0].rsz/1.1;
      if (o[0].rsz<0.09 && o[0].rsz>-0.09 && wantz==0) o[0].rsz=0;
      if (o[0].rsx>o[0].toprevs) o[0].rsx=o[0].toprevs;
      if (o[0].rsx<-o[0].toprevs) o[0].rsx=-o[0].toprevs;
      if (o[0].rsy>o[0].toprevs) o[0].rsy=o[0].toprevs;
      if (o[0].rsy<-o[0].toprevs) o[0].rsy=-o[0].toprevs;
      if (o[0].rsz>o[0].toprevs) o[0].rsz=o[0].toprevs;
      if (o[0].rsz<-o[0].toprevs) o[0].rsz=-o[0].toprevs;
      apibuttons=0;
      if (apijoystick_right_button==0) apibuttons=1;
      else if (apijoystick_left_button==0) apibuttons=3;

      break;
    case 2: //Mouse
//      apimousegetrelpointerxy(&myXpos,&myYpos);
//      apigetmousepos();
      tempy=myYpos;
      tempx=myXpos;
      tempx=(int)(tempx/10);
      tempy=(int)(tempy/10);
      wantx=(tempy*o[0].toprevs)/10;
      wanty=(tempx*o[0].toprevs)/10;
      wantz=-(tempx*o[0].toprevs*0.75)/10;
      if (o[0].rsx<wantx || o[0].rsx>wantx) o[0].rsx+=wantx/10;
      o[0].rsx=o[0].rsx/1.1;
      if (o[0].rsx<0.09 && o[0].rsx>-0.09 && wantx==0) o[0].rsx=0;
      if (o[0].rsx<wanty || o[0].rsx>wanty) o[0].rsy+=wanty/10;
      o[0].rsy=o[0].rsy/1.1;
      if (o[0].rsy<0.09 && o[0].rsy>-0.09 && wanty==0) o[0].rsy=0;
      if (o[0].rsz<wantz || o[0].rsz>wantz) o[0].rsz+=wantz/10;
      o[0].rsz=o[0].rsz/1.1;
      if (o[0].rsz<0.09 && o[0].rsz>-0.09 && wantz==0) o[0].rsz=0;
      if (o[0].rsx>o[0].toprevs) o[0].rsx=o[0].toprevs;
      if (o[0].rsx<-o[0].toprevs) o[0].rsx=-o[0].toprevs;
      if (o[0].rsy>o[0].toprevs) o[0].rsy=o[0].toprevs;
      if (o[0].rsy<-o[0].toprevs) o[0].rsy=-o[0].toprevs;
      if (o[0].rsz>o[0].toprevs) o[0].rsz=o[0].toprevs;
      if (o[0].rsz<-o[0].toprevs) o[0].rsz=-o[0].toprevs;
      break;
  }

  if (key[_C_PGUP] && o[0].speed<o[0].topspeed) o[0].speed+=1;  //Speed
  if (key[_C_PGDN] && ((o[0].speed>1 && ground==0)||(o[0].speed>7 && ground>0))   ) o[0].speed-=1;
  if (targetframe==0)
  {
    if (key[_1] && o[0].guns>0) { o[0].g[0].selected=1-o[0].g[0].selected; targetframe=1; }
    else if (key[_2] && o[0].guns>1) { o[0].g[1].selected=1-o[0].g[1].selected; targetframe=1; }
    else if (key[_3] && o[0].guns>2) { o[0].g[2].selected=1-o[0].g[2].selected; targetframe=1; }
    else if (key[_4] && o[0].guns>3) { o[0].g[3].selected=1-o[0].g[3].selected; targetframe=1; }
    else if (key[_5] && o[0].guns>4) { o[0].g[4].selected=1-o[0].g[4].selected; targetframe=1; }
    else if (key[_6] && o[0].guns>5) { o[0].g[5].selected=1-o[0].g[5].selected; targetframe=1; }
    else if (key[_7] && o[0].guns>6) { o[0].g[6].selected=1-o[0].g[6].selected; targetframe=1; }
    else if (key[_8] && o[0].guns>7) { o[0].g[7].selected=1-o[0].g[7].selected; targetframe=1; }
    else if (key[_9] && o[0].guns>8) { o[0].g[8].selected=1-o[0].g[8].selected; targetframe=1; }
    else if (key[_0] && o[0].guns>9) { o[0].g[9].selected=1-o[0].g[9].selected; targetframe=1; }
  }

  // Fire guns that are selected
  for(g=0;g<o[0].guns;g++) if(o[0].g[g].selected==1 || o[0].g[g].type==CHAINGUN)
  {
    soundtype=-1;
    createtype=-1;
    if (o[0].g[g].type!=CHAINGUN)
    {
      if (key[gunkey[o[0].g[g].type]] || apibuttons==gunmouse[o[0].g[g].type]) switch(o[0].g[g].type)
      {
        case LASER:
          if(o[0].g[g].fireframe==0 && ((g==1 && o[0].g[0].type==LASER && o[0].g[0].fireframe>3) || g==0 ))
          {
            if(o[0].side==1 || o[0].side==6) createtype=1; else createtype=2;
            soundtype=LASER;
          }
          break;
        case BEAM:
        case ALIENBEAM:
          if (o[0].g[g].type==BEAM) createtype=3;
          else if (o[0].g[g].type==ALIENBEAM) createtype=4;
          soundtype=5;
          createobject(createtype,o[0].g[g].fireflag*120*o[0].g[g].gun,25,-90+(o[0].g[g].gunz*120),0,0,o[0].dz[0]/1.4,o[0].side,0);
          createobject(createtype,-o[0].g[g].fireflag*120*o[0].g[g].gun,25,-90+(o[0].g[g].gunz*120),0,0,o[0].dz[0]/1.4,o[0].side,0);
          for (h=1;h<ships;h++) if ( o[h].cx>-40 && o[h].cx<40 && o[h].cy>-40 && o[h].cy<40 && o[h].cz>0 && o[h].type>-1 && o[h].doing<10)
          {
            if (createtype==3) damageship(h,gunpower[BEAM]);
            else if (createtype==4) damageship(h,gunpower[ALIENBEAM]);
            o[h].sparking=3;
            o[h].sparkx=o[0].dx[0];
            o[h].sparky=o[0].dy[0];
            o[h].sparkz=0.99;
          }
          break;
        case ION:
          if(o[0].g[g].fireframe<ioncharge && frame2==0)
          {
            createtype=5;
            soundtype=3;
          }
          break;
        case BOMB:
        case NUKE:
        case TORP:
        case MISSILE:
           if(o[0].g[g].fireframe==0 && o[0].target>-1 && o[o[0].target].side!=o[0].side && o[0].g[g].left>0)
           {
             createtype=o[0].g[g].type+2;
             if (o[0].g[g].type!=MISSILE) soundtype=BOMB;
             else soundtype=MISSILE;
           }
           break;
        case TURBOLASER:
          if(o[0].g[g].fireframe==0)
          {
            createtype=11;
            soundtype=8;
          }
          break;
        case ALIENTORP:
          if(o[0].g[g].fireframe==0 && o[0].target>-1 && o[o[0].target].side!=o[0].side && o[0].g[g].left>0)
          {
            createtype=12;
            soundtype=6;
          }
          break;
      }
      if(createtype!=-1)
      {
        createobject(createtype, o[0].g[g].fireflag*120*o[0].g[g].gun,25+o[0].g[g].guny,25+(o[0].g[g].gunz*120), 0,0,o[0].dz[0]*gunvelocity[o[0].g[g].type],o[0].target,0);
        if(o[0].g[g].fireframe==0) o[0].g[g].fireframe=1;
        if(o[0].g[g].type!=LASER && o[0].g[g].type!=BEAM && o[0].g[g].type!=ION && o[0].g[g].type!=TURBOLASER && o[0].g[g].type!=ALIENBEAM) o[0].g[g].left--;
        else o[0].g[g].fireflag=-o[0].g[g].fireflag;
        if(soundtype>-1 && soundblaster==1 && sound1[soundtype]!=NULL)
        {
          playing[soundtype]=0;
          playsoundeffect(soundtype,10);
        }
      }
    }
    else
    {
      if ((key[gunkey[o[0].g[g].type]] || apibuttons==gunmouse[o[0].g[g].type]) && o[0].g[g].selected==1)
      {
        if (o[0].g[g].fireframe<30) o[0].g[g].fireframe++;
        else
        {
          if(o[0].g[g].fireframe>30) o[0].g[g].fireframe=30;
          if(frame2==0 && o[0].g[g].left>0)
          {
            o[0].g[g].left--;
            soundtype=2;
            if(soundtype>-1 && soundblaster==1 && sound1[soundtype]!=NULL)
            {
              playing[soundtype]=0;
              playsoundeffect(soundtype,10);
            }
            createobject(13, 120*o[0].g[g].gun,25+o[0].g[g].guny,25+(o[0].g[g].gunz*120)+apirandom(30), 0,0,o[0].dz[0]*gunvelocity[o[0].g[g].type],o[0].target,0);
            createobject(13, -120*o[0].g[g].gun,25+o[0].g[g].guny,25+(o[0].g[g].gunz*120)+apirandom(30), 0,0,o[0].dz[0]*gunvelocity[o[0].g[g].type],o[0].target,0);
          }
        }
      }
      else
      {
        if (o[0].g[g].fireframe>0) o[0].g[g].fireframe-=2;
      }
    }

  }

  if(targetframe==0 && (key[_L_SHIFT] || key[_R_SHIFT]))  // Communication keys
  {
    targetframe=1;
    if(o[0].target>0 && o[o[0].target].side!=o[0].side)
    {
      if (key[_A])
      {
        createcomm(0,0,o[0].side,"ATTACK MY CURRENT TARGET");
        for(f=1; f<ships; f++) if(o[f].wingleader==0 && o[f].side==o[0].side && o[f].type>0)
        {
          o[f].target=o[0].target;
          sprintf(s1,"%s TARGETTING AYE",shapedata[o[f].shape].type);
          createcomm(f,0,o[f].side,s1);
          break;
        }
      }
      else if(key[_K])
      {
        createcomm(0,0,o[0].side,"KILL CURRENT TARGET, ALL SUBORDINATES!");
        for(f=1;f<ships;f++) if((o[f].rank < o[0].rank || o[f].wingleader==0 || o[o[f].wingleader].wingleader==0) && o[f].side==o[0].side && o[f].type>0 && o[f].type<4)
        {
          o[f].target=o[0].target;
          sprintf(s1,"%s ATTACKING TARGET",shapedata[o[f].shape].type);
          createcomm(f,0,o[f].side,s1);
        }
      }
      else if(key[_P])
      {
        createcomm(0,0,o[0].side,"PROTECT TARGET REQUEST");
        for(f=1; f<ships; f++) if((o[f].rank < o[0].rank || o[f].wingleader==0 || o[o[f].wingleader].wingleader==0) && o[f].side==o[0].side && o[f].type>0)
        {
          o[f].wingleader=-o[0].target;
          sprintf(s1,"%s FORMING ON %s",shapedata[o[f].shape].type,shapedata[o[o[0].target].shape].type);
          createcomm(f,0,o[f].side,s1);
        }
      }
      else if(key[_B])
      {
        createcomm(0,0,o[0].side,"BREAK FORMATION");
        for (f=1; f<ships; f++)
        {
          if ((o[f].rank<o[0].rank || o[f].wingleader==0) && o[f].side==o[0].side && o[f].type>0)
          {
            o[f].wingtype=3; // was o[f].wingleader=-1;
            sprintf(s1,"%s BREAKING FORMATION",shapedata[o[f].shape].type);
            createcomm(f,0,o[f].side,s1);
          }
        }
      }
      if(key[_M])
      {
        if (o[0].shields<10)
        {
          createcomm(0,0,o[0].side,"MAYDAY! MAYDAY!");
          for (f=1; f<ships; f++) if((o[f].wingleader==0 || o[f].rank<=o[0].rank) && o[f].side==o[0].side && o[f].type>0 && apirandom(10)>4)
          {
            for (g=1; g<ships; g++)
            {
              if (g!=f && o[g].target==0 && o[g].type>-1)
              {
                o[f].target=g;
                sprintf(s1,"%s REPORTS MAYDAY RECIEVED",shapedata[o[f].shape].type);
                break;
              }
              else
              {
                sprintf(s1,"YOU ARE NOT TARGETTED");
                createcomm(f,0,o[f].side,s1);
                break;
              }
            }
            createcomm(f,0,o[f].side,s1);
          }
        }
      }
      else if(key[_D])
      {
        createcomm(0,0,o[0].side,"DEFEND ME!");
        for(f=1;f<ships;f++) if((o[f].wingleader==0 || o[f].rank<o[0].rank) && o[f].side==o[0].side && o[f].type>0)
        {
          for(g=1;g<ships;g++)
          {
            if(g!=f && o[g].target==0 && o[g].type>-1)
            {
              o[f].target=g;
              sprintf(s1,"%s DEFENDING YOU",shapedata[o[f].shape].type);
              break;
            }
            else sprintf(s1,"YOU ARE NOT TARGETTED");
          }
          createcomm(f,0,o[f].side,s1);
          break;
        }
      }
      else targetframe=0;
    }
    else
    {
      if(key[_D])
      {
        createcomm(0,0,o[0].side,"DEFEND ME!");
        for(f=1;f<ships;f++) if((o[f].wingleader==0 || o[f].rank<o[0].rank) && o[f].side==o[0].side && o[f].type>0)
        {
          for(g=1;g<ships;g++)
          {
            if(g!=f && o[g].target==0 && o[g].type>-1)
            {
              o[f].target=g;
              sprintf(s1,"%s DEFENDING YOU",shapedata[o[f].shape].type);
              break;
            }
            else sprintf(s1,"YOU ARE NOT TARGETTED");
          }
          createcomm(f,0,o[f].side,s1);
          break;
        }
      }
      if(key[_M])
      {
        if (o[0].shields<10)
        {
          createcomm(0,0,o[0].side,"MAYDAY! MAYDAY!");
          for (f=1; f<ships; f++) if((o[f].wingleader==0 || o[f].rank<=o[0].rank) && o[f].side==o[0].side && o[f].type>0 && apirandom(10)>4)
          {
            for (g=1; g<ships; g++)
            {
              if (g!=f && o[g].target==0 && o[g].type>-1)
              {
                o[f].target=g;
                sprintf(s1,"%s REPORTS MAYDAY RECIEVED",shapedata[o[f].shape].type);
                break;
              }
              else
              {
                sprintf(s1,"YOU ARE NOT TARGETTED");
                createcomm(f,0,o[f].side,s1);
                break;
              }
            }
            createcomm(f,0,o[f].side,s1);
          }
        }
      }
      if(key[_F])
      {
        createcomm(0,0,o[0].side,"FORM ON ME REQUEST");
        if (o[o[0].target].rank<o[0].rank && o[o[0].target].type>0 || (o[o[0].target].wingtype!=1 && o[o[0].target].wingleader==0))
        {
          o[o[0].target].wingleader=0;
          o[o[0].target].wingtype=1;
          createcomm(o[0].target,0,o[0].side,"ROGER THAT, FORMING ON YOU");
        }
      }
      if(key[_R])
      {
        createcomm(0,0,o[0].side,"RETREAT AND REGROUP REQUEST");
        for (f=1; f<ships; f++) if((o[f].wingleader==0 || o[f].rank<=o[0].rank) && o[f].side==o[0].side && o[f].type>0 && apirandom(10)>2 && o[f].target>-1 && o[f].doing!=WITHDRAWING)
        {
          sprintf(s1,"REGROUPING");
          createcomm(f,0,o[f].side,s1);
          o[f].doing=WITHDRAWING;
          o[f].frame1=-100;
        }
      }
      else if(key[_B])
      {
        createcomm(0,0,o[0].side,"BREAK FORMATION");
        for (f=1; f<ships; f++)
        {
          if ((o[f].rank<o[0].rank || o[f].wingleader==0) && o[f].side==o[0].side && o[f].type>0)
          {
            o[f].wingtype=3; // was o[f].wingleader=-1;
            sprintf(s1,"%s BREAKING FORMATION",shapedata[o[f].shape].type);
            createcomm(f,0,o[f].side,s1);
          }
        }
      }
      else if(key[_I])
      {
        createcomm(0,0,o[0].side,"IGNORE TARGET REQUEST");
        for (f=1; f<ships; f++)
        {
          if ((o[f].rank < o[0].rank || o[f].wingleader==0 || o[o[f].wingleader].wingleader==0) && (o[f].side==o[0].side)&&(o[f].type>0))
          {
            if (o[f].target==o[0].target)
            {
              o[f].target=-1;
              sprintf(s1,"%s IGNORING TARGET",shapedata[o[f].shape].type);
              createcomm(f,0,o[f].side,s1);
            }
          }
        }
      }
      else if(key[_L])
      {
        if (o[0].target>-1 && o[o[0].target].hangerzones>0 && o[o[0].target].side==o[0].side && o[0].doing!=LANDING)
        {
          createcomm(0,0,o[0].side,"REQUEST LANDING CLEARANCE");
          g=0;
          h=apirandom(o[o[0].target].hangerzones);
          for (f=0; f<o[o[0].target].hangerzones; f++)
          {
            h++;
            if(h>o[o[0].target].hangerzones) h=0;
            if(o[o[0].target].h[h].type==1)
            {
              g=1;
              o[0].motherhangerzone=h;
            }
          }
          if((enemypower==0 || missioncompleted==1) && g==1)
          {
            createcomm(o[0].target,0,o[o[0].target].side,"ROGER, YOU ARE CLEARED TO DOCK");
            sprintf(s1,"PROCEED TO HANGERBAY %d",o[0].motherhangerzone+1);
            createcomm(o[0].target,0,o[o[0].target].side,s1);
            o[0].doing=LANDING;
            o[0].mother=o[0].target;
          }
          else createcomm(o[0].target,0,o[o[0].target].side,"NEGATIVE, DO NOT LAND");
        }
      }
      else targetframe=0;
    }
//    apikeypressed=0;
  }
  else if(targetframe==0 && (key[_T] || key[_Y] || key[_R] || key[_E]))  //Select target by various methods
  {
    targetframe=1;
    if (o[0].target>-1) g=o[0].target;
    else g=1;
    tempx = 0;
    tempy = 0;
    tempz = 0;
    if(key[_T]) for (f=1; f<ships; f++) //Nearest on screen
    {
      g++;
      if (g>=ships) g=1;
      if (o[g].type>-1 && o[g].shape!=36 && o[g].shape!=37 && o[g].shape!=38 &&
          o[g].type<20 && o[g].cz>10 && o[g].shape!=99 && o[g].shape!=100&& o[g].shape!=99 && o[g].shape!=100 && (tempx+tempy==0 ||
          pythag2d(tempx,tempy) > pythag2d(o[g].cx/o[g].cz,o[g].cy/o[g].cz)))
      {

        o[0].target=g;
        targ=dddLoad(shapedata[o[o[0].target].shape].filename);
        if(targetinfoupdown==10) targetinfoupdown=0;
        tempx = o[o[0].target].cx/o[o[0].target].cz;
        tempy = o[o[0].target].cy/o[o[0].target].cz;
        tat=10;
        targetturret=0; targetturretflash=0;
      } // End of existing type check and close to cross hair check

    } // End of for f
    else if(key[_E]) for (f=1; f<ships-1; f++) //Nearest threat targeting you
    {
      g++;
      if(g>=ships) g=1;
      if(o[g].shape!=36 && o[g].shape!=37 && o[g].shape!=38 && o[g].shape!=99 && o[g].shape!=100 && o[g].type>-1 && o[g].type<20 && o[g].target==0)
      {
        if(tempx+tempy==0 || o[o[0].target].doing>=DIEING || (pythag3d(tempx,tempy,tempz)>pythag3d(o[g].cx,o[g].cy,o[g].cz)))
        {
          o[0].target=g;
          targ=dddLoad(shapedata[o[o[0].target].shape].filename);
          if(targetinfoupdown==10) targetinfoupdown=0;
          tempx=o[o[0].target].cx;
          tempy=o[o[0].target].cy;
          tempz=o[o[0].target].cz;
          tat=10;
          targetturret=0; targetturretflash=0;
        } // End of target closeness to cross hair check
      } // End of existing type check
    }
    else for (f=1; f<ships-1; f++) //Nearest (Y) or nearest enemy (R)
    {
      g++;
      if(g>=ships) g=1;
      if( o[g].shape!=36 && o[g].shape!=37 && o[g].shape!=38 && o[g].type>-1 && o[g].type<20 && o[g].shape!=99 && o[g].shape!=100)
      {
        if(tempx+tempy==0 || o[o[0].target].doing>=DIEING || (pythag3d(tempx,tempy,tempz)>pythag3d(o[g].cx,o[g].cy,o[g].cz)))
        {
          if(key[_Y] || (key[_R] && o[0].side!=o[g].side))
          {
            o[0].target=g;
            targ=dddLoad(shapedata[o[o[0].target].shape].filename);
            if(targetinfoupdown==10) targetinfoupdown=0;
            tempx=o[o[0].target].cx;
            tempy=o[o[0].target].cy;
            tempz=o[o[0].target].cz;
            tat=10;
            targetturret=0; targetturretflash=0;
          }
        } // End of target closeness to cross hair check
      } // End of existing type check
    } // End of for f

    for (g=0; g<o[0].guns; g++) // Select guns depending on target
    {
      o[0].g[g].selected=0;
      switch(o[0].g[g].type)
      {
        case LASER:
        case BEAM:
        case ION:
        case TURBOLASER:
        case CHAINGUN:
        case ALIENTORP:
        case ALIENBEAM:
          o[0].g[g].selected=1;
          break;
        case BOMB:
        case TORP:
        case NUKE:
          if(o[0].target>0 && o[0].g[g].left>0 && o[o[0].target].crashzones>0) o[0].g[g].selected=1;
          break;
        case MISSILE:
          if(o[0].target>0 && o[0].g[g].left>0 && o[o[0].target].crashzones==0) o[0].g[g].selected=1;
          break;
      }
    } // End of loop through gun selection
  } //End if if changing target
  if(targetframe==0 && key[_TAB])  //Select target by various methods
  {
    if(key[_R_SHIFT] || key[_R_SHIFT])
    {
      targetturret--;
      if(targetturret<0) targetturret=o[o[0].target].turrets;
    }
    else
    {
      targetturret++;
      if(targetturret>o[o[0].target].turrets) targetturret=0;
    }
    targetframe=1;
  }

  //Deselect target
  if (key[_C_HOME] && o[0].target>-1)  targetinfoupdown=0;  //Targetinfo up down
  if (key[_C_END]) targetinfoupdown=10;
  if (key[_O])
  {
    o[0].target=-1;
    targetinfoupdown=10;
    if (view==8 || view==9) view=0;
  }
  if (key[_G] && o[0].doing==LANDING)
  {
    o[0].doing=ATTACKING;
  }
  if (key[_H] && targetframe==0)
  {
    if(o[0].doing<ENTERING_HYPERSPACE)
    {
      o[0].doing=ENTERING_HYPERSPACE;
      o[0].frame1=10;
    }
    else if(o[0].doing==ENTERING_HYPERSPACE)
    {
      o[0].doing=ATTACKING;
    }
    targetframe=1;
  }
  if (!key[_T] && !key[_Y] && !key[_R] && !key[_O] &&
      !key[_D] && !key[_1] && !key[_2] && !key[_3] &&
      !key[_4] && !key[_5] && !key[_6] && !key[_7] &&
      !key[_8] && !key[_9] && !key[_0] && !key[_ALTERNATE] &&
      !key[_H] && !key[_TAB] && !key[_E] &&
      !key[_R_SHIFT] && !key[_L_SHIFT]  ) targetframe=0;
}

void you(void)
{
  float dx,dy,dz,distance2;
  calculateheight(0);
  if(pilot.inmisfriendlyhits>2 && frame1==0) pilot.inmisfriendlyhits--; // Forgive and not quite forget....
  if (o[0].doing==10) // your own death
  {
    if(o[0].frame3<90) o[0].frame3++;
    if (o[0].frame3>70)
    {
      view=6;
      if ((o[0].rsy>0.1) || (o[0].rsy<-0.1)) o[0].rsy=o[0].rsy/1.01;
      if (o[0].frame3==72)
      {
        killoff(0);
        o[0].rsx=0;
        o[0].rsy=1; if(ground>0) o[0].rsy=0;
        o[0].rsz=0;
        o[0].speed=0;
      }
    }
  }
  if (view>3 && o[0].type>-1)
  {
    apishape(DRAWFULL,o[0].object,0, o[0].cx,o[0].cy+10,o[0].cz , o[0].rx,o[0].ry,o[0].rz);
    attached(0);
  }
  if (o[0].doing==LANDING)
  {
    dx=-o[0].cx+o[o[0].mother].cx+(o[o[0].mother].h[o[0].motherhangerzone].cx);
    dy=-o[0].cy+o[o[0].mother].cy+(o[o[0].mother].h[o[0].motherhangerzone].cy);
    dz=-o[0].cz+o[o[0].mother].cz+(o[o[0].mother].h[o[0].motherhangerzone].cz);
    distance2=pythag3d(dx,dy,dz);
    if (distance2<300)
    {
      if (o[0].speed>1 && frame2==0) o[0].speed--;
      if(distance2<50 && o[0].speed<3)
      {
        terminateflag=DOCKED;
      }
    }
  }
  if(o[0].doing==ENTERING_HYPERSPACE)
  {
    if (frame1==0) o[0].frame1--;
    if (o[0].frame1<0)
    {
      view=4;
      o[0].cz+=400;
      o[0].frame2-=100;
      o[0].rsx=o[0].rsy=o[0].rsz=0;
    }
    if (o[0].frame1<-2)
    {
      terminateflag=HYPERSPACED;
    }
  }
}

int complete(void)
{
  if(demo==1 && (pilot.mission>5 || pilot.campaign>1)) // You've done the demo...
  {
    reset();
    load("COMP1");
    terminateflag=0;
    view=0;
    missiontime=0;
    prepareyourguns();
    game(); //Sets terminateflag and missioncompleted
    return(1);
  }
  else if(demo==2 && (pilot.mission>5 || pilot.campaign>1)) // You've done the demo...
  {
    reset();
    load("COMP2");
    terminateflag=0;
    view=0;
    missiontime=0;
    prepareyourguns();
    game(); //Sets terminateflag and missioncompleted

    reset();
    load("CUT2");
    terminateflag=0;
    view=0;
    missiontime=0;
    prepareyourguns();
    game(); //Sets terminateflag and missioncompleted

    reset();
    load("CUT3");
    terminateflag=0;
    view=0;
    missiontime=0;
    prepareyourguns();
    game(); //Sets terminateflag and missioncompleted

    reset();
    load("CUT4");
    terminateflag=0;
    view=0;
    missiontime=0;
    prepareyourguns();
    game(); //Sets terminateflag and missioncompleted

    reset();
    load("CUT1");
    terminateflag=0;
    view=0;
    missiontime=0;
    prepareyourguns();
    game(); //Sets terminateflag and missioncompleted


    reset();
    load("CUT5");
    terminateflag=0;
    view=0;
    missiontime=0;
    prepareyourguns();
    game(); //Sets terminateflag and missioncompleted

    return(1);
  }
  return(0);
}
