예제 #1
0
void P2MultiBeamFrigateAttackDoAttack(Ship *ship,SpaceObjRotImpTarg *target,real32 maxdist,bool PassiveAttack)

{
    ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo;

    P2MultiBeamFrigateStatics *frigstat = (P2MultiBeamFrigateStatics *)shipstaticinfo->custstatinfo;
    P2MultiBeamFrigateSpec    *spec     = (P2MultiBeamFrigateSpec *)ship->ShipSpecifics;

    vector trajectory;
    vector shipRightVec;
    real32 range;

        spec->aiattacklast = universe.totaltimeelapsed;
    ship->autostabilizeship = FALSE;

    aishipGetTrajectory(ship, target, &trajectory);
    range = RangeToTarget(ship,target,&trajectory);

    if (range > frigstat->MultiBeamRange[ship->tacticstype])
    {
        //not in range
        if(!PassiveAttack)
        {
            //do aiship fly to stuff here

            //if not in range...fly to the ship
            //else track zero velocity
                aishipFlyToShipAvoidingObjs(ship,target,AISHIP_PointInDirectionFlying + AISHIP_CarTurn,0.0f);
        }
        return;
    }

    //we are in range

    vecNormalize(&trajectory);
    if(!PassiveAttack)
	{
		aitrackZeroVelocity(ship);
	}
    matGetVectFromMatrixCol2(shipRightVec,ship->rotinfo.coordsys);

    aitrackHeadingAndUp(ship,&trajectory,&shipRightVec,0.9999f);

    
	if(vecMagnitudeSquared(ship->rotinfo.rotspeed) > frigstat->AttackRotationSpeed)
    {
		if(aitrackHeadingWithFlags(ship,&trajectory,0.99f,AITRACKHEADING_IGNOREUPVEC|AITRACK_DONT_ZERO_ME))
		{
			//rotation speed reached
			//lets fire guns if we can
			P2MultiBeamFrigateFire(ship,target);
		}
    }
}
예제 #2
0
//fires the bursts for the ship
bool doBurstFire(Ship *ship)
{
    HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics;
    GunInfo *gunInfo = ship->gunInfo;
    sdword numGuns = gunInfo->numGuns;
    //Gun *gun;
    sdword done;
    vector trajectory,heading;
    real32 range,one_over_range;
    SpaceObjRotImpTarg dummyTarg;

    vecSub(trajectory,spec->burstFireVector,ship->posinfo.position);
    range = vecMagnitudeSquared(trajectory);
    range = fsqrt(range);
    one_over_range = 1.0f/range;
    vecScalarMultiply(trajectory,trajectory,one_over_range);

    dummyTarg.objtype = OBJ_ShipType;
    dummyTarg.posinfo.position = spec->burstFireVector;
    dummyTarg.collInfo.collPosition = spec->burstFireVector;
    dummyTarg.currentLOD = ship->currentLOD;
    dummyTarg.collMyBlob = ship->collMyBlob;
    vecSet(dummyTarg.posinfo.velocity,0.0f,0.0f,0.0f);

    //track target even more precisely
    vecSub(heading,spec->burstFireVector,ship->posinfo.position);
    vecNormalize(&heading);
    aitrackHeadingWithFlags(ship,&heading,0.9999f,AITRACKHEADING_IGNOREUPVEC);

    //set special information that needs to be 'transmitted'
    //to the code in gunshoot.

    //fix later
    spec->bulletLifeTime = range*oneOverburstSpeed;



    bitSet(ship->specialFlags,SPECIAL_BurstFiring);
    done = gunShootGunsAtTarget(ship,&dummyTarg,0.0f,&trajectory);
    bitClear(ship->specialFlags,SPECIAL_BurstFiring);
    if(done == TRUE)
    {
        spec->cooldown = TRUE;
        spec->burstChargeState2 = burstCoolDownTime;
    }
    return done;
}
예제 #3
0
//this function flies the ship to within range of the desired target location and
//orients itself to fire.  Returns true when in position
bool flytoBurstPosition(Ship *ship)
{
    HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics;
    vector heading;
    bool ready = FALSE;
    //maybe track to within gun gimbleness
    vecSub(heading,spec->burstFireVector,ship->posinfo.position);
    vecNormalize(&heading);
    if(aitrackHeadingWithFlags(ship,&heading,0.99f,AITRACKHEADING_IGNOREUPVEC))
    {
        ready = TRUE;
    }

    if(!MoveReachedDestinationVariable(ship,&spec->burstFireVector,burstRange))
    {
        aishipFlyToPointAvoidingObjs(ship,&spec->burstFireVector,AISHIP_FastAsPossible,0.0f);
        return(FALSE);
    }
    aitrackZeroVelocity(ship);
    return(ready);
}
void MineLayerAttackRun(Ship *ship,SpaceObjRotImpTarg *target,AttackSideStep *attacksidestep,AttackSideStepParameters *parameters)
{
    vector trajectory;
    //real32 dist;
    real32 range;
    //real32 temp;
//    bool didshoot;
    ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo;
    Gun *gun;
    udword numGuns,target_class;
    GunInfo *guninfo = ship->gunInfo;
    //vector tmpvec;
    //real32 randegf;
    //sdword randeg;
    //matrix tmpmat;
    //vector targetheading;
    MinelayerCorvetteSpec *spec = (MinelayerCorvetteSpec *)ship->ShipSpecifics;
    MinelayerCorvetteStatics *minelayercorvettestatics;
    minelayercorvettestatics = (MinelayerCorvetteStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo;

    numGuns = guninfo->numGuns;

    gun = &guninfo->guns[0];
    if(target != NULL)
    {
        if(target->objtype == OBJ_ShipType)
            target_class = ((Ship *)target)->staticinfo->shipclass;
        else
            target_class = CLASS_NonCombat;
    }

    switch (ship->aistateattack)
    {
        case ATTACK_INIT:
        case APPROACH:
#ifdef DEBUG_ATTACK
            dbgMessagef("\nShip %x MINELAYER_ATTACK_APPROACH",(udword)ship);
#endif
            aishipGetTrajectory(ship,target,&trajectory);
            aishipFlyToShipAvoidingObjs(ship,target,AISHIP_PointInDirectionFlying,0.0f);
            range = RangeToTarget(ship,target,&trajectory);

			//lets check if we want to force drop...
			if(target->objtype == OBJ_ShipType)
			{
				if(((Ship *)target)->shiptype == Mothership)
				{
					//its a mothership
					vector tempvec;
					real32 tempreal;
					vecSub(tempvec,target->collInfo.collPosition,ship->collInfo.collPosition);
					tempreal = vecMagnitudeSquared(tempvec);
					if(tempreal < mothershipDistSqr)
					{
						//we're within range of force dropping!
						ship->aistateattack = DROP_MOTHERSHIP;
					}
					break;
				}

			}


            if (range < minelayercorvettestatics->breakInAwayDist)
            {
                ship->aistateattack = BREAKPOSITION;
                spec->aivec.x = 0.0f;
                spec->aivec.y = 0.0f;
                spec->aivec.z = 0.0f;
            }

            break;
		case DROP_MOTHERSHIP:
			{
				vector tempvec;
				real32 tempreal;
				vecSub(tempvec,ship->collInfo.collPosition,target->collInfo.collPosition);
				tempreal = vecMagnitudeSquared(tempvec);
				vecNormalize(&tempvec);
				if(tempreal > mothershipDistSqr2)
				{
					ship->aistateattack = ATTACK_INIT;
				}
				if(aitrackHeadingWithFlags(ship,&tempvec,0.97f,AITRACKHEADING_IGNOREUPVEC))
				{
					if(MinelayerCorvetteStaticMineDrop(ship,target))		//problem...there will be other targets...bah..lets see..
					{
						MinelayerCorvetteOrderChangedCleanUp(ship);
					}
				}
				break;
			}
        case BREAKPOSITION:
#ifdef DEBUG_ATTACK
        dbgMessagef("\nShip %x BREAKPOSITION",(udword)ship);
#endif

            aishipGetTrajectory(ship,target,&trajectory);
            range = RangeToTarget(ship,target,&trajectory);
            vecNormalize(&trajectory);

            SetAIVecHeading(ship,target,&trajectory);

            ship->aistateattack = BREAK1;

        case BREAK1:
#ifdef DEBUG_ATTACK
    dbgMessagef("\nShip %x BREAK1",(udword)ship);
#endif

            aishipGetTrajectory(ship,target,&trajectory);
            range = RangeToTarget(ship,target,&trajectory);


            //aishipFlyToPointAvoidingObjs(ship,&spec->aivec,AISHIP_FastAsPossible | AISHIP_PointInDirectionFlying,INTERCEPTORBREAK_MINVELOCITY);
            aishipFlyToPointAvoidingObjs(ship,&target->posinfo.position,AISHIP_FastAsPossible | AISHIP_PointInDirectionFlying,INTERCEPTORBREAK_MINVELOCITY);
            if(range < minelayercorvettestatics->DropRange)
            {
                //temp
                vecNormalize(&trajectory);
                SetAIVecHeading(ship,target,&trajectory);
                //temp

                ship->aistateattack = KILL;    //within mining range so start dropping
                spec->aispheretime=0.0f;            //reset time;
            }

            break;
        case KILL:
#ifdef DEBUG_ATTACK
    dbgMessagef("\nShip %x KILL",(udword)ship);
#endif
            aishipGetTrajectory(ship,target,&trajectory);
            range = RangeToTarget(ship,target,&trajectory);

            spec->aispheretime += universe.phystimeelapsed;

            if(gunCanShoot(ship, gun))
            {
                if(gun->numMissiles > 0)
                {
                   spec->mineaistate = MINE_DROP_ATTACK;
                   MinelayerCorvetteFire(ship,target);
                 }
            }
            if(range > minelayercorvettestatics->DropStopRange)
            {   //out of range....
                ship->aistateattack = BREAK2;
            }
            if(spec->aispheretime > minelayercorvettestatics->Break2SphereizeFreq)
            {    //time to sphereize;
                spec->aivec.x =0.0f;
                spec->aivec.y =0.0f;
                spec->aivec.z =0.0f;
                spec->aispheretime = -1000000.0f;     // Reset, and never do again till next attack pass...
                vecNormalize(&trajectory);
                SetAIVecHeading(ship,target,&trajectory);

#ifdef DEBUG_ATTACK
    dbgMessagef("\nShip %x KILL: Adjust for Break2 Sphereizing Godliness Maneuver :)",(udword)ship);
#endif

            }

            aishipFlyToPointAvoidingObjs(ship,&spec->aivec,AISHIP_FastAsPossible | AISHIP_PointInDirectionFlying,INTERCEPTORBREAK_MINVELOCITY);
            break;
        case BREAK2:
#ifdef DEBUG_ATTACK
    dbgMessagef("\nShip %x BREAK2",(udword)ship);
#endif

            aishipGetTrajectory(ship,target,&trajectory);
            range = RangeToTarget(ship,target,&trajectory);
            aishipFlyToPointAvoidingObjs(ship,&spec->aivec,AISHIP_FastAsPossible | AISHIP_PointInDirectionFlying,INTERCEPTORBREAK_MINVELOCITY);
            if(range > minelayercorvettestatics->FlyAwayDist[target_class] ||
               (MoveReachedDestinationVariable(ship,&spec->aivec,minelayercorvettestatics->FlyAwayTolerance)))
            {    //turn around and start over
                ship->aistateattack = APPROACH;
            }
            break;
        default:
            dbgAssert(FALSE);
            break;
    }

}
예제 #5
0
void doKamikazeAttack(Ship *ship,SpaceObjRotImpTarg *target)
{
    real32 mag,dist,range,shipvel;
    vector destination,trajectory,heading,shipheading,EinsteinVelocity;
    ShipStaticInfo *shipstaticinfo = ship->staticinfo;

    vecSub(trajectory,target->collInfo.collPosition,ship->posinfo.position);
    mag = vecMagnitudeSquared(trajectory);
    dist = fsqrt(mag);

    destination = trajectory;
    vecNormalize(&destination);
    heading = destination;

    //this hokey fudge factor is needed so the kamikaze ship doesn't
    //slow down as it reaches its destination
    mag = dist + 500.0f;
    vecScalarMultiply(destination,destination,mag);
    vecAddTo(destination,target->collInfo.collPosition);

    range = RangeToTargetGivenDist(ship,target,dist);

    switch(ship->kamikazeState)
    {
    case K_Start:
        //if within a threshold range
        bitClear(ship->specialFlags,SPECIAL_KamikazeCrazyFast);
        if(range < 500.0f)
        {
            //calculate flyby dist
            matGetVectFromMatrixCol3(shipheading, ship->rotinfo.coordsys);
            vecScalarMultiply(shipheading,shipheading,kamikazeFlyByDist);
            vecAdd(ship->kamikazeVector,shipheading,target->collInfo.collPosition);
            ship->kamikazeState = K_TurnAround;
        }
        ship->kamikazeState = K_Ram;

        break;

    case K_Ram:
        if (range < 400.0f)
        {
            ship->kamikazeState = K_Yell;
        }
    case K_Ram2:
        //lets use...mmmmm..twister theor...no...relativity
        vecSub(EinsteinVelocity,ship->posinfo.velocity,target->posinfo.velocity);
        shipvel = fsqrt(vecMagnitudeSquared(EinsteinVelocity));
        if(ship->shiptype == MinelayerCorvette)
        {
            ((MinelayerCorvetteSpec *)(ship->ShipSpecifics))->mineaistate = MINE_DROP_ATTACK;
        }
        else if (ship->shiptype == DefenseFighter)
        {
            goto dontshoot;
        }

        if (isShipStaticInterceptor(shipstaticinfo))
        {
            if (range < shipstaticinfo->bulletRange[ship->tacticstype])
            {
                GenericInterceptorStatics *interceptorstat = (GenericInterceptorStatics *)shipstaticinfo->custstatinfo;
                uword targetIndex;

                if (target->objtype == OBJ_ShipType)
                {
                    targetIndex = (uword)((ShipStaticInfo *)target->staticinfo)->shipclass;
                }
                else
                {
                    targetIndex = (uword)NUM_CLASSES;
                }

                if (GenericInterceptorCanFire(ship,target,&trajectory,interceptorstat->triggerHappy[ship->tacticstype][targetIndex]))
                {
                    ship->staticinfo->custshipheader.CustShipFire(ship,target);
                }
            }
        }
        else
        {
            gunShootGunsAtTarget(ship,target,range,&trajectory);
        }
dontshoot:
        aishipFlyToPointAvoidingObjs(ship,&destination,AISHIP_PointInDirectionFlying | AISHIP_FirstPointInDirectionFlying | AISHIP_FastAsPossible,0.0f);
        if(range < 1500.0f)
        {
            bitSet(ship->specialFlags,SPECIAL_KamikazeCrazyFast);
        }
        else
        {
            bitClear(ship->specialFlags,SPECIAL_KamikazeCrazyFast);
        }

/*
        if(range < 400.0f && (shipvel < ship->staticinfo->staticheader.maxvelocity*0.7f ||
                   vecDotProduct(trajectory,heading) < 0))
        {
            //ship is inside 400.0f, and isn't faceing ship, or isn't
            //going fast enough

            //calculate flyby dist
            matGetVectFromMatrixCol3(shipheading, ship->rotinfo.coordsys);
            vecScalarMultiply(shipheading,shipheading,kamikazeFlyByDist);
            vecAdd(ship->kamikazeVector,shipheading,target->posinfo.position);
            ship->kamikazeState = K_TurnAround;
        }
*/
        break;
    case K_TurnAround:
        bitClear(ship->specialFlags,SPECIAL_KamikazeCrazyFast);
        aishipFlyToPointAvoidingObjs(ship,&ship->kamikazeVector,AISHIP_PointInDirectionFlying | AISHIP_FirstPointInDirectionFlying | AISHIP_FastAsPossible,0.0f);
        if(MoveReachedDestinationVariable(ship,&ship->kamikazeVector,300.0f))
            ship->kamikazeState = K_TurnAround2;
        break;
    case K_TurnAround2:
        bitClear(ship->specialFlags,SPECIAL_KamikazeCrazyFast);
        if(aitrackHeadingWithFlags(ship,&heading,0.90f,AITRACKHEADING_IGNOREUPVEC))
            ship->kamikazeState = K_Ram;
        break;
    case K_Yell:
//      speechEvent(ship, COMM_LInt_Kamikaze, 0);
        battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_Kamikaze, ship, SOUND_EVENT_DEFAULT);
        ship->kamikazeState = K_Ram2;
        break;
    }

        //fire guns here...
    //
    //
    //Sound note:   Could put in kamikaze state change here after
    //              getting to within a certain distance of target
    //
    //          ask bryce how to...
}
예제 #6
0
void ResearchShipHouseKeep(Ship *ship)
{
    ResearchShipSpec *spec = (ResearchShipSpec *)ship->ShipSpecifics;
    SelectCommand selection;
    vector up,destination,desiredheading,newup;
    vector univup = {0.0f,0.0f,1.0f};
    bool InParadeandMoving = FALSE;
    matrix rot_matrix,tmpmat,rotmat;
    real32 radangle;
    ResearchShipStatics *researchshipstatics;
    researchshipstatics = (ResearchShipStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo;

    if(bitTest(ship->specialFlags,SPECIAL_StopForResearchDocking))
    {
        vecScalarMultiply(ship->posinfo.velocity,ship->posinfo.velocity,0.94);
        vecScalarMultiply(ship->rotinfo.rotspeed,ship->rotinfo.rotspeed,0.94);
        bitSet(ship->dontapplyforceever,1);
        bitSet(ship->dontrotateever,1);
    }
    else
    {
        bitClear(ship->dontapplyforceever,1);
        bitClear(ship->dontrotateever,1);
    }

    if(ship->flags & SOF_Slaveable)
    {
        if(ship->slaveinfo->flags & SF_MASTER)
        {
            CommandToDo *command = getShipAndItsCommand(&universe.mainCommandLayer,ship);
            if(command != NULL)
            {
                //ship may be in parade...
                if(command->ordertype.order == COMMAND_MILITARY_PARADE)
                {
                    //ship is in parade
                    CommandToDo *ashipCom = getShipAndItsCommand(&universe.mainCommandLayer,command->militaryParade->aroundShip);
                    if(ashipCom != NULL)
                    {
                        //probably shouldn't be null regardless..should be equal to command..but ohwell
                        if(ashipCom->ordertype.order == COMMAND_MOVE ||
                           ashipCom->ordertype.order == COMMAND_ATTACK ||
                           ashipCom->ordertype.order == COMMAND_SPECIAL ||
                           ashipCom->ordertype.order == COMMAND_MP_HYPERSPACING)
                        {
                            InParadeandMoving = TRUE;
                            spec->rotate_state = ROTATE_WAIT;
                        }
                    }
                //in parade
                    if(!InParadeandMoving)
                    {
                        if(bitTest(ship->specialFlags,SPECIAL_ParadeNeedTomoveCloser))
                        {
                            InParadeandMoving = TRUE;
                            spec->rotate_state = ROTATE_WAIT;
                        }
                    }
                }
            }
        }
    }
    if(ship->flags & SOF_Slaveable)
    {    //ship is slaveable
        bitSet(ship->flags,SOF_DontDrawTrails);
        ship->autostabilizeship = FALSE;        // never have univupdate autostabilize research ships
        if(ship->slaveinfo->flags & SF_MASTER)
        {    //ship is a master
            if(!InParadeandMoving)
            {
                if(ship->shiprace == R1)
                {   //ship is a race 1 MASTER research ship...
                    //i.e. it controls the motion
                    switch(spec->rotate_state)
                    {
                    case ANGLE_ESTABLISH:       //establishes the angle at which the station is supposed to rotate at
                        break;
                    case ROTATE_WAIT:           //wait to rotate
                        if(ship->slaveinfo->slaves.num >= 5)
                        {   //correct # of ships...
                            if(!ship_is_moving(ship))
                            {
                                if(!spec->prepshipforanother)
                                {   //no ships are coming to dock
                                    //do up vector tracking!
                                    //Later Calculate this vector ONCE at code start up...Let Daly do it
                                    //and get as a static value

                                    radangle = DEG_TO_RAD(researchshipstatics->RotationAngle);
                                    matMakeRotAboutX(&rotmat,(real32) cos(radangle),(real32) sin(radangle));
                                    matMultiplyMatByVec(&newup, &rotmat, &univup);
                                    //matGetVectFromMatrixCol3(desiredHeading,ship->rotinfo.coordsys);
                                    if(aitrackHeadingWithFlags(ship,&newup,0.96f,AITRACKHEADING_IGNOREUPVEC))
                                    {
                                        spec->rotate_state = ROTATE_DO;
                                        getRotatePoint(ship, &spec->rotate_point,&spec->rotate_distance);
                                    }
                                }
                            }
                            if(!spec->have_removed_from_parade)
                            {
                                spec->have_removed_from_parade = TRUE;
                                selection.numShips = 1;
                                selection.ShipPtr[0] = ship;
                                //RemoveShipsFromDoingStuff(&universe.mainCommandLayer,&selection);
                                //clHalt(&universe.mainCommandLayer,&selection);
                            }
                        }
                        break;
                    case ROTATE_STOP:
                    case ROTATE_STOP_QUICK:
                    case ROTATE_DO:
                        ship->posinfo.isMoving = ISMOVING_MOVING | ISMOVING_ROTATING;
                        make_all_slaves_moving(ship);
                        if(ship->slaveinfo->slaves.num < 5)
                        {
                            //don't rotate anymore because slaves dropped below threhold for whatever reasons!
                            spec->rotate_state = ROTATE_STOP;
                            break;
                        }
                        if(spec->prepshipforanother)
                        {   //need to prep ship for a docking ship..
                            spec->rotate_state = ROTATE_STOP;
                        }
                        else if(ship_is_moving(ship))
                        {   //ship is being moved
                            spec->rotate_state = ROTATE_STOP_QUICK;
                        }
                        else
                        {
                            spec->rotate_state = ROTATE_DO;
                        }

                        //matGetVectFromMatrixCol3(heading,ship->rotinfo.coordsys);
                        matGetVectFromMatrixCol1(up,ship->rotinfo.coordsys);
                        //vecScalarMultiply(rotate_point, heading, -250.0f);
                        //vecAdd(rotate_point,rotate_point, ship->posinfo.position);

                        switch(spec->rotate_state)
                        {
                        case ROTATE_DO:
                            if(spec->theta >= researchshipstatics->max_rotate)
                                spec->theta = researchshipstatics->max_rotate;
                            else
                                spec->theta += researchshipstatics->rotate_acelleration;
                            break;
                        case ROTATE_STOP_QUICK:
                            spec->theta *= researchshipstatics->rotate_slow;
                            spec->theta *= researchshipstatics->rotate_slow;
                        case ROTATE_STOP:
                            if(spec->theta <= 0.00001f)
                            {
                                spec->theta = 0.0f;
                                spec->rotate_state = ROTATE_WAIT;
                                break;
                            }
                            else
                                spec->theta *= researchshipstatics->rotate_slow;
                            break;
                        default:
                            dbgAssertOrIgnore(FALSE);
                            break;
                        }
                        matMakeRotAboutX(&rot_matrix,(real32) cos(spec->theta),(real32) sin(spec->theta));
                        //matMultiplyMatByMat(&tmpmat, &rot_matrix, &ship->rotinfo.coordsys);
                        matMultiplyMatByMat(&tmpmat, &ship->rotinfo.coordsys, &rot_matrix);
                        //vecSub(tmpvec, ship->posinfo.position, spec->rotate_point);
                        //dist = vecMagnitudeSquared(tmpvec);
                        //dist = fsqrt(dist);

                        matGetVectFromMatrixCol3(desiredheading,tmpmat);
                        vecScalarMultiply(destination, desiredheading, spec->rotate_distance);      //old was dist
                        vecAdd(destination,destination,spec->rotate_point);

                        ship->posinfo.position = destination;
                        ship->rotinfo.coordsys = tmpmat;
                        univUpdateObjRotInfo((SpaceObjRot *)ship);
                        break;
                    default:
                        dbgMessagef("Shouldn't Get Here...unknown Research Ship Rotate State");
                        dbgAssertOrIgnore(FALSE);
                        break;
                    }


                }
                else
                {    //Ship is an R2 Master...so rotate differently
                    switch(spec->rotate_state)
                    {
                    case ANGLE_ESTABLISH:
                        break;
                    case ROTATE_WAIT:           //wait to rotate
                        if(ship->slaveinfo->slaves.num >= 3)
                        {   //correct # of ships...
                            if(!spec->prepshipforanother && !ship_is_moving(ship))
                            {   //no ships are coming to dock
                                radangle = DEG_TO_RAD(researchshipstatics->RotationAngle);
                                matMakeRotAboutX(&rotmat,(real32) cos(radangle),(real32) sin(radangle));
                                matMultiplyMatByVec(&newup, &rotmat, &univup);
                                if(aitrackHeadingWithFlags(ship,&newup,0.96f,AITRACKHEADING_IGNOREUPVEC))
                                {
                                    spec->rotate_state = ROTATE_DO;
                                }
                            }
                            else
                            {
                                vecSet(ship->rotinfo.rotspeed,0.0f,0.0f,0.0f);
                                vecSet(ship->rotinfo.torque,0.0f,0.0f,0.0f);
                            }
                        }
                        if(ship->slaveinfo->slaves.num >= 1)
                        {   //correct # of ships...
                            if(!spec->have_removed_from_parade)
                            {
                                spec->have_removed_from_parade = TRUE;
                                selection.numShips = 1;
                                selection.ShipPtr[0] = ship;
                                //RemoveShipsFromDoingStuff(&universe.mainCommandLayer,&selection);
                                //clHalt(&universe.mainCommandLayer,&selection);
                            }
                        }
                        break;
                    case ROTATE_STOP:
                    case ROTATE_STOP_QUICK:
                    case ROTATE_DO:
                        ship->posinfo.isMoving = ISMOVING_MOVING | ISMOVING_ROTATING;
                        make_all_slaves_moving(ship);
                        if(ship->slaveinfo->slaves.num < 3)
                        {
                            //don't rotate anymore because slaves dropped below threhold for whatever reasons!
                            spec->rotate_state = ROTATE_STOP;
                            break;
                        }
                        if(spec->prepshipforanother)
                        {   //need to prep ship for a docking ship..
                            spec->rotate_state = ROTATE_STOP;
                        }
                        if(ship_is_moving(ship))
                        {   //ship is being moved
                            spec->rotate_state = ROTATE_STOP_QUICK;
                        }
                        switch(spec->rotate_state)
                        {
                        case ROTATE_DO:
                            if(spec->theta >= researchshipstatics->max_rotate)
                                spec->theta = researchshipstatics->max_rotate;
                            else
                                spec->theta += researchshipstatics->rotate_acelleration;
                            break;
                        case ROTATE_STOP_QUICK:
                            spec->theta *= researchshipstatics->rotate_slow;
                            spec->theta *= researchshipstatics->rotate_slow;
                        case ROTATE_STOP:
                            if(spec->theta <= 0.00001f)
                                {
                                spec->theta = 0.0f;
                                spec->rotate_state = ROTATE_WAIT;
                                break;
                                }
                            else
                                spec->theta *= researchshipstatics->rotate_slow;
                            break;
                        default:
                            dbgAssertOrIgnore(FALSE);
                            break;
                        }
                        matMakeRotAboutZ(&rot_matrix,(real32) cos(spec->theta),(real32) sin(spec->theta));
                        tmpmat = ship->rotinfo.coordsys;
                        matMultiplyMatByMat(&ship->rotinfo.coordsys,&tmpmat,&rot_matrix);
                        univUpdateObjRotInfo((SpaceObjRot *)ship);
                        break;
                    default:
                        dbgMessagef("Shouldn't Get Here...unknown Research Ship Rotate State");
                        dbgAssertOrIgnore(FALSE);
                        break;
                    }
                }
            }
        }
        else
        {
            vecScalarMultiply(ship->posinfo.velocity,ship->posinfo.velocity, 0.0f);
        }

    }
}
void P2MultiBeamFrigateAttackDoAttack(Ship *ship,SpaceObjRotImpTarg *target,real32 maxdist,bool PassiveAttack)

{
    ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo;

    P2MultiBeamFrigateStatics *frigstat = (P2MultiBeamFrigateStatics *)shipstaticinfo->custstatinfo;
    P2MultiBeamFrigateSpec    *spec     = (P2MultiBeamFrigateSpec *)ship->ShipSpecifics;

    vector trajectory;
    vector shipRightVec;
    real32 range;

        spec->aiattacklast = universe.totaltimeelapsed;
    ship->autostabilizeship = FALSE;

    aishipGetTrajectory(ship, target, &trajectory);
    range = RangeToTarget(ship,target,&trajectory);

    if (range > frigstat->MultiBeamRange[ship->tacticstype])
    {
        //not in range
        if(!PassiveAttack)
        {
            //do aiship fly to stuff here

            //if not in range...fly to the ship
            //else track zero velocity
                aishipFlyToShipAvoidingObjs(ship,target,AISHIP_PointInDirectionFlying + AISHIP_CarTurn,0.0f);
        }
        return;
    }

    //we are in range

    vecNormalize(&trajectory);
    if(!PassiveAttack)
	{
		aitrackZeroVelocity(ship);
	}
    matGetVectFromMatrixCol2(shipRightVec,ship->rotinfo.coordsys);

    aitrackHeadingAndUp(ship,&trajectory,&shipRightVec,0.9999f);

    
	if(vecMagnitudeSquared(ship->rotinfo.rotspeed) > frigstat->AttackRotationSpeed)
    {
		if(aitrackHeadingWithFlags(ship,&trajectory,0.99f,AITRACKHEADING_IGNOREUPVEC|AITRACK_DONT_ZERO_ME))
		{
			//rotation speed reached
			//lets fire guns if we can
			P2MultiBeamFrigateFire(ship,target);
		}
    }

/*  OLD SCHOOL CODE  */

    /*
    switch (ship->aistateattack)
    {
        case STATE_INIT:
            // deliberatly fall through to state_approach
//            spec->steady = FALSE;
            ship->aistateattack=STATE_APPROACH;
        case STATE_APPROACH:
#ifdef DEBUG_FRIGATEATTACK
            dbgMessagef("\nShip %x STATE_APPROACH", (udword)ship);
#endif
            if (spec->spining)
            {
                ship->aistateattack = STATE_SPINDOWN;
                break;
            }

            aishipGetTrajectory(ship, target, &trajectory);

            range = RangeToTarget(ship,target,&trajectory);

            if (range < frigstat->MultiBeamRange[ship->tacticstype] || PassiveAttack)
            {
                temp = trajectory;
                temp.z+=5;
                temp.y+=5;
                temp.x+=5;

                //vecCrossProduct(heading,trajectory,temp);

                //vecNormalize(&heading);
                vecNormalize(&trajectory);

				if(!PassiveAttack)
				{
					aitrackZeroVelocity(ship);
				}


                if (aitrackHeadingWithFlags(ship,&trajectory,0.99f,AITRACKHEADING_IGNOREUPVEC))
                {
                    ship->aistateattack = STATE_SPINUP;
                    //get up vector
                    matGetVectFromMatrixCol1(temp,ship->rotinfo.coordsys);
                    aitrackForceHeading(ship,&trajectory,&temp);
                }
            }
            else
            {
				aishipFlyToShipAvoidingObjs(ship,target,AISHIP_PointInDirectionFlying + AISHIP_CarTurn,0.0f);
			}
            break;
        case STATE_SPINUP:
#ifdef DEBUG_FRIGATEATTACK
            dbgMessagef("\nShip %x STATE_SPINUP", (udword)ship);
#endif
            desiredrotspeed = frigstat->AttackRotationSpeed;

			if(!PassiveAttack)
			{
				aitrackZeroVelocity(ship);
			}
            aitrackHeadingAndUp(ship,&heading,&shipRightVec,0.99f);

			if (aitrackRotationSpeed(ship,desiredrotspeed,ROT_ABOUTZCCW))
            {
                ship->aistateattack = STATE_FIRE;
                spec->spining = TRUE;
                spec->aifirestarttime = universe.totaltimeelapsed + frigstat->BeamFireTime;
            }

            break;
        case STATE_FIRE:
#ifdef DEBUG_FRIGATEATTACK
            dbgMessagef("\nShip %x STATE_FIRE", (udword)ship);
#endif
            shipstaticinfo->custshipheader.CustShipFire(ship, target);

            if(!PassiveAttack)
			{
				aitrackZeroVelocity(ship);
			}
			aishipGetTrajectory(ship,target,&trajectory);

            range = RangeToTarget(ship,target,&trajectory);

            if (range > frigstat->MultiBeamRange[ship->tacticstype])
                ship->aistateattack = STATE_INIT;

            temp = trajectory;
            temp.z+=5;
            temp.y+=5;
            temp.x+=5;

            vecCrossProduct(heading,trajectory,temp);

            vecNormalize(&heading);
            vecNormalize(&trajectory);

            //if (aitrackHeadingWithFlags(ship,&heading,0.99f,AITRACKHEADING_IGNOREUPVEC))
          //  {
        //        ship->aistateattack = STATE_INIT;
      //      }
            desiredrotspeed = frigstat->AttackRotationSpeed;
            aitrackRotationSpeed(ship,desiredrotspeed,ROT_ABOUTZCCW);

			if(universe.totaltimeelapsed > spec->aifirestarttime)
			{
                //fire time up!  start spindown
				ship->aistateattack = STATE_SPINDOWN;
				spec->aifirestarttime = universe.totaltimeelapsed + frigstat->fireDownTime;
			}
            break;
        case STATE_SPINDOWN:
#ifdef DEBUG_FRIGATEATTACK
            dbgMessagef("\nShip %x STATE_SPINDOWN", (udword)ship);
#endif
            desiredrotspeed = 0;

            if(!PassiveAttack)
			{
				aitrackZeroVelocity(ship);
			}
			if (aitrackRotationSpeed(ship,desiredrotspeed,ROT_ABOUTZCCW) &&
				universe.totaltimeelapsed > spec->aifirestarttime)
            {
                ship->aistateattack = STATE_INIT;
                spec->spining = FALSE;
            }
            break;
    }
    */
}