/*============================================================================= Name : AITrack.c Purpose : Given a desired velocity, heading, etc. this AI layer will make the ship track the desired velocity, heading, etc. Created 6/25/1997 by gshaw Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include #include "types.h" #include "debug.h" #include "vector.h" #include "matrix.h" #include "fastmath.h" #include "physics.h" #include "spaceobj.h" #include "AItrack.h" #include "statscript.h" #include "universe.h" #include "aiship.h" #ifdef gshaw #define DEBUG_AITRACK 0 #else #define DEBUG_AITRACK 0 #endif /*============================================================================= Tweakables =============================================================================*/ real32 ERROR_VELOCITY_SQUARED = 0.05f; real32 STILL_VELOCITY_LO = -3.0f; real32 STILL_VELOCITY_HI = 3.0f; real32 STILL_ROT_LO = -0.3f; real32 STILL_ROT_HI = 0.3f; real32 STABILIZE_Z_LO = -0.1f; real32 STABILIZE_Z_HI = 0.1f; real32 AITRACKRIGHT_UPACCURACY = 0.985f; scriptEntry AITrackTweaks[] = { { "ErrorVelocitySquared", scriptSetReal32CB, &ERROR_VELOCITY_SQUARED }, { "StillVelocityLo", scriptSetReal32CB, &STILL_VELOCITY_LO }, { "StillVelocityHi", scriptSetReal32CB, &STILL_VELOCITY_HI }, { "StillRotLo", scriptSetReal32CB, &STILL_ROT_LO }, { "StillRotHi", scriptSetReal32CB, &STILL_ROT_HI }, makeEntry(STABILIZE_Z_LO,scriptSetReal32CB), makeEntry(STABILIZE_Z_HI,scriptSetReal32CB), makeEntry(AITRACKRIGHT_UPACCURACY,scriptSetCosAngCB), { NULL, NULL, 0 } }; /*----------------------------------------------------------------------------- Name : aitrackIsStabilizeShip Description : Returns TRUE if ship is stablized Inputs : ship Outputs : Return : Returns TRUE if ship is stablized ----------------------------------------------------------------------------*/ bool aitrackIsStabilizeShip(Ship *ship) { vector heading,up,right; bool stabilizedpitch; real32 rotx = ship->rotinfo.rotspeed.x; matGetVectFromMatrixCol3(heading,ship->rotinfo.coordsys); matGetVectFromMatrixCol1(up,ship->rotinfo.coordsys); matGetVectFromMatrixCol2(right,ship->rotinfo.coordsys); stabilizedpitch = isBetweenExclusive(heading.z,STABILIZE_Z_LO,STABILIZE_Z_HI); if (stabilizedpitch) { if (isBetweenExclusive(rotx,STILL_ROT_LO,STILL_ROT_HI) && // isBetweenExclusive(roty,STILL_ROT_LO,STILL_ROT_HI) && // isBetweenExclusive(rotz,STILL_ROT_LO,STILL_ROT_HI) && // (stabilizedpitch) && isBetweenExclusive(right.z,STABILIZE_Z_LO,STABILIZE_Z_HI) && (up.z > 0) ) { return TRUE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : aitrackStabilizeShip Description : this ai will stabilize the ship (e.g. stop all pitch, roll, and yaw, although it will not change the velocity of the ship) Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ bool aitrackStabilizeGuidance(SpaceObjRotImpTargGuidance *ship) { real32 rotx = ship->rotinfo.rotspeed.x; real32 roty = ship->rotinfo.rotspeed.y; real32 rotz = ship->rotinfo.rotspeed.z; vector heading; vector up; vector right; real32 rotstr; real32 oneovertime; bool stabilizedpitch; StaticInfoHealthGuidance *shipstaticinfo; matGetVectFromMatrixCol3(heading,ship->rotinfo.coordsys); matGetVectFromMatrixCol1(up,ship->rotinfo.coordsys); matGetVectFromMatrixCol2(right,ship->rotinfo.coordsys); stabilizedpitch = isBetweenExclusive(heading.z,STABILIZE_Z_LO,STABILIZE_Z_HI); if (stabilizedpitch) { roty = ship->rotinfo.rotspeed.y = 0.0f; } if (isBetweenExclusive(rotx,STILL_ROT_LO,STILL_ROT_HI) && // isBetweenExclusive(roty,STILL_ROT_LO,STILL_ROT_HI) && // isBetweenExclusive(rotz,STILL_ROT_LO,STILL_ROT_HI) && (stabilizedpitch) && isBetweenExclusive(right.z,STABILIZE_Z_LO,STABILIZE_Z_HI) && (up.z > 0) ) { return TRUE; } #ifdef gshaw // dbgMessagef("\nZeroing Rot %f %f %f %x",rotx,roty,rotz,(udword)ship); #endif shipstaticinfo = ship->staticinfo; oneovertime = 1.0f / universe.phystimeelapsed; if (rotx > 0) { rotstr = rotx * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCW]),ROT_ABOUTXCW); } else { rotstr = -rotx * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCCW]),ROT_ABOUTXCCW); } if (stabilizedpitch) { if (rotz > 1.0f) { rotstr = rotz * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCW]),ROT_ABOUTZCW); } else if (rotz < -1.0f) { rotstr = -rotz * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCCW]),ROT_ABOUTZCCW); } else { if (right.z > 0) { physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_ROLLRIGHT]*right.z,ROT_ROLLRIGHT); } else { physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_ROLLLEFT]*(-right.z),ROT_ROLLLEFT); } } } else { if (rotz > 0.0f) { rotstr = rotz * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCW]),ROT_ABOUTZCW); } else { rotstr = -rotz * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCCW]),ROT_ABOUTZCCW); } if (roty > 1.0f) { rotstr = roty * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCW]),ROT_ABOUTYCW); } else if (roty < -1.0f) { rotstr = -roty * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCCW]),ROT_ABOUTYCCW); } else { if (heading.z < 0) { physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_PITCHUP]*(-heading.z),ROT_PITCHUP); } else { physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_PITCHDOWN]*heading.z,ROT_PITCHDOWN); } } } #if 0 desiredrotspeed = -heading.z if (ship->rotinfo.rotspeed.z < desiredrotspeed) { physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_ABOUTYCCW],ROT_ABOUTYCCW); } else { physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_ABOUTYCW],ROT_ABOUTYCW); } #endif return FALSE; } /*----------------------------------------------------------------------------- Name : aitrackIsZeroRotation Description : returns TRUE if rotation is zero Inputs : Outputs : Return : returns TRUE if rotation is zero ----------------------------------------------------------------------------*/ bool aitrackIsZeroRotation(Ship *ship) { real32 rotx = ship->rotinfo.rotspeed.x; real32 roty = ship->rotinfo.rotspeed.y; real32 rotz = ship->rotinfo.rotspeed.z; if (isBetweenExclusive(rotx,STILL_ROT_LO,STILL_ROT_HI) && isBetweenExclusive(roty,STILL_ROT_LO,STILL_ROT_HI) && isBetweenExclusive(rotz,STILL_ROT_LO,STILL_ROT_HI)) { return TRUE; } return FALSE; } /*----------------------------------------------------------------------------- Name : aitrackZeroRotationAnywhere Description : this ai will stabilize the ship (e.g. stop all pitch, roll, and yaw, although it will not change the velocity of the ship) It does not necessarily stop the ship oriented up Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ bool aitrackZeroRotationAnywhere(Ship *ship) { real32 rotx = ship->rotinfo.rotspeed.x; real32 roty = ship->rotinfo.rotspeed.y; real32 rotz = ship->rotinfo.rotspeed.z; vector heading; vector up; vector right; real32 rotstr; real32 oneovertime; ShipStaticInfo *shipstaticinfo; matGetVectFromMatrixCol3(heading,ship->rotinfo.coordsys); matGetVectFromMatrixCol1(up,ship->rotinfo.coordsys); matGetVectFromMatrixCol2(right,ship->rotinfo.coordsys); if (isBetweenExclusive(rotx,STILL_ROT_LO,STILL_ROT_HI) && isBetweenExclusive(roty,STILL_ROT_LO,STILL_ROT_HI) && isBetweenExclusive(rotz,STILL_ROT_LO,STILL_ROT_HI)) { return TRUE; } shipstaticinfo = (ShipStaticInfo *)ship->staticinfo; oneovertime = 1.0f / universe.phystimeelapsed; if (rotx > 0) { rotstr = rotx * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCW]),ROT_ABOUTXCW); } else { rotstr = -rotx * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCCW]),ROT_ABOUTXCCW); } if (roty > 0) { rotstr = roty * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCW]),ROT_ABOUTYCW); } else { rotstr = -roty * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCCW]),ROT_ABOUTYCCW); } if (rotz > 0) { rotstr = rotz * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCW]),ROT_ABOUTZCW); } else { rotstr = -rotz * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCCW]),ROT_ABOUTZCCW); } return FALSE; } /*----------------------------------------------------------------------------- Name : aitrackHeading Description : given a desired heading vector, this ai will orient the ship in the correct heading as well as stopping any roll. Inputs : desiredHeading Outputs : Return : TRUE if heading has been successfully tracked. ----------------------------------------------------------------------------*/ bool aitrackHeadingAndUp(Ship *ship,vector *desiredHeading,vector *desiredUp,real32 accuracy) { ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo; vector curheading; vector curup; real32 dotProdCheckHeading; real32 dotProdCheckUp; real32 desiredrotspeed; real32 rotspeed; vector desiredHeadingInShipCoordSys; vector desiredUpInShipCoordSys; real32 rotstr; real32 oneovertime; if(ship->objtype == OBJ_ShipType) { if(ship->dontrotateever) { return TRUE; } } matGetVectFromMatrixCol3(curheading,ship->rotinfo.coordsys); matGetVectFromMatrixCol1(curup,ship->rotinfo.coordsys); dotProdCheckHeading = vecDotProduct(*desiredHeading,curheading); dotProdCheckUp = vecDotProduct(*desiredUp,curup); #if DEBUG_AITRACK dbgMessagef("\nHeading accuracy: %f",dotProdCheckHeading); #endif if (dotProdCheckHeading <= -1.0f) // use <= in case inaccuraces cause number slightly less than 1.0 { // Exactly opposite direction, so arbitrarily chose a direction and rotate that way physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_ABOUTXCW],ROT_ABOUTXCW); return FALSE; } if (dotProdCheckUp <= -1.0f) // use <= in case inaccuraces cause number slightly less than 1.0 { // Exactly opposite direction, so arbitrarily chose a direction and rotate that way physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_ABOUTZCW],ROT_ABOUTZCW); return FALSE; } if ((dotProdCheckHeading >= accuracy) && (dotProdCheckUp >= accuracy)) { #if DEBUG_AITRACK dbgMessage("\nOn correct heading..."); #endif aitrackForceShipZeroRotation(ship); return TRUE; // heading close enough to desired heading, so return } // Our heading is not close to the desired heading, so we have // to do more work... // transform desiredHeading into desiredHeading in Ship co-ordinate system matMultiplyVecByMat(&desiredHeadingInShipCoordSys,desiredHeading,&ship->rotinfo.coordsys); // transform desiredUp into desiredUp in Ship co-ordinate system matMultiplyVecByMat(&desiredUpInShipCoordSys,desiredUp,&ship->rotinfo.coordsys); oneovertime = 1.0f / universe.phystimeelapsed; // Check if we need to rotate about x axis (yaw) if (desiredHeadingInShipCoordSys.y != 0) { if (desiredHeadingInShipCoordSys.z < 0.0f) { if (desiredHeadingInShipCoordSys.y < 0.0f) { desiredrotspeed = ship->nonstatvars.turnspeed[TURN_ABOUTX]; } else { desiredrotspeed = -ship->nonstatvars.turnspeed[TURN_ABOUTX]; } } else { desiredrotspeed = -desiredHeadingInShipCoordSys.y * ship->nonstatvars.turnspeed[TURN_ABOUTX]; } rotspeed = ship->rotinfo.rotspeed.x; if (rotspeed < desiredrotspeed) { rotstr = (desiredrotspeed - rotspeed) * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCCW]),ROT_ABOUTXCCW); } else { rotstr = (rotspeed - desiredrotspeed) * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCW]),ROT_ABOUTXCW); } } // Check if we need to rotate about y axis (pitch) if (desiredHeadingInShipCoordSys.x != 0) { desiredrotspeed = desiredHeadingInShipCoordSys.x * ship->nonstatvars.turnspeed[TURN_ABOUTY]; rotspeed = ship->rotinfo.rotspeed.y; if (rotspeed < desiredrotspeed) { rotstr = (desiredrotspeed - rotspeed) * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCCW]),ROT_ABOUTYCCW); } else { rotstr = (rotspeed - desiredrotspeed) * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCW]),ROT_ABOUTYCW); } } // Check if we need to rotate about z axis (roll) to make up-vector of ship // align with world z axis. if (desiredUpInShipCoordSys.y != 0.0f) { desiredrotspeed = desiredUpInShipCoordSys.y * ship->nonstatvars.turnspeed[TURN_ABOUTZ]; rotspeed = ship->rotinfo.rotspeed.z; if (rotspeed < desiredrotspeed) { rotstr = (desiredrotspeed - rotspeed) * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCCW]),ROT_ABOUTZCCW); } else { rotstr = (rotspeed - desiredrotspeed) * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCW]),ROT_ABOUTZCW); } } return FALSE; } /*----------------------------------------------------------------------------- Name : aitrackHeading Description : given a desired heading vector, this ai will orient the ship in the correct heading as well as stopping any roll. Inputs : desiredHeading Outputs : Return : TRUE if heading has been successfully tracked. ----------------------------------------------------------------------------*/ bool aitrackHeadingFunc(SpaceObjRotImpTargGuidance *ship,vector *desiredHeading,real32 accuracy,real32 upaccuracy,real32 sinbank,udword flags) { StaticInfoHealthGuidance *shipstaticinfo = ship->staticinfo; vector curheading; vector curup; real32 dotProdCheckHeading; real32 dotProdCheckUp; real32 desiredrotspeed; real32 rotspeed; vector desiredHeadingInShipCoordSys; vector desiredUp = { 0.0f,0.0f,1.0f }; vector desiredUpInShipCoordSys; real32 rotstr; real32 oneovertime; real32 yawcloseness = 0.0f; if(ship->objtype == OBJ_ShipType) { if(((Ship *)ship)->dontrotateever) //if this flag is set we don't want to rotate the ship at all { return TRUE; } } if (ship->nonstatvars.rotstrength[ROT_PITCHUP] == 0) { desiredHeading->z = 0.0f; vecNormalize(desiredHeading); // renormalize } matGetVectFromMatrixCol3(curheading,ship->rotinfo.coordsys); matGetVectFromMatrixCol1(curup,ship->rotinfo.coordsys); aishipStatsDesiredHeading(*desiredHeading); aishipStatsActualHeading(curheading); dotProdCheckHeading = vecDotProduct(*desiredHeading,curheading); dotProdCheckUp = curup.z; //vecDotProduct(desiredUp,curup); #if DEBUG_AITRACK dbgMessagef("\nHeading accuracy: %f",dotProdCheckHeading); #endif if (dotProdCheckHeading <= -1.0f) { // Exactly opposite direction, so arbitrarily chose a direction and rotate that way physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_ABOUTXCW],ROT_ABOUTXCW); return FALSE; } if ((dotProdCheckHeading >= accuracy) && ((flags & (AITRACKHEADING_IGNOREUPVEC+AITRACKHEADING_DONTROLL)) || (dotProdCheckUp >= upaccuracy)) ) { #if DEBUG_AITRACK dbgMessage("\nOn correct heading..."); #endif if(!(flags & AITRACK_DONT_ZERO_ME)) { aitrackForceGuidanceZeroRotation(ship); } return TRUE; // heading close enough to desired heading, so return } // Our heading is not close to the desired heading, so we have // to do more work... // transform desiredHeading into desiredHeading in Ship co-ordinate system matMultiplyVecByMat(&desiredHeadingInShipCoordSys,desiredHeading,&ship->rotinfo.coordsys); // transform desiredUp into desiredUp in Ship co-ordinate system matMultiplyVecByMat(&desiredUpInShipCoordSys,&desiredUp,&ship->rotinfo.coordsys); oneovertime = 1.0f / universe.phystimeelapsed; // Check if we need to rotate about x axis (yaw) if (desiredHeadingInShipCoordSys.y != 0) { if (desiredHeadingInShipCoordSys.z < 0.0f) { if (desiredHeadingInShipCoordSys.y < 0.0f) { desiredrotspeed = ship->nonstatvars.turnspeed[TURN_ABOUTX]; } else { desiredrotspeed = -ship->nonstatvars.turnspeed[TURN_ABOUTX]; } } else { desiredrotspeed = -desiredHeadingInShipCoordSys.y * ship->nonstatvars.turnspeed[TURN_ABOUTX]; } if (sinbank != 0.0f) { if (desiredHeadingInShipCoordSys.z < 0.0f) { if (desiredHeadingInShipCoordSys.y < 0.0f) { yawcloseness = sinbank; } else { yawcloseness = -sinbank; } } else { yawcloseness = -desiredHeadingInShipCoordSys.y * sinbank; } } rotspeed = ship->rotinfo.rotspeed.x; if (rotspeed < desiredrotspeed) { rotstr = (desiredrotspeed - rotspeed) * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCCW]),ROT_ABOUTXCCW); } else { rotstr = (rotspeed - desiredrotspeed) * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCW]),ROT_ABOUTXCW); } } // Check if we need to rotate about y axis (pitch) if (desiredHeadingInShipCoordSys.x != 0) { desiredrotspeed = desiredHeadingInShipCoordSys.x * ship->nonstatvars.turnspeed[TURN_ABOUTY]; rotspeed = ship->rotinfo.rotspeed.y; if (rotspeed < desiredrotspeed) { rotstr = (desiredrotspeed - rotspeed) * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCCW]),ROT_ABOUTYCCW); } else { rotstr = (rotspeed - desiredrotspeed) * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCW]),ROT_ABOUTYCW); } } if (flags & AITRACKHEADING_DONTROLL) { return FALSE; } // Check if we need to rotate about z axis (roll) to make up-vector of ship // align with world z axis. if (desiredUpInShipCoordSys.y != yawcloseness) { desiredrotspeed = (desiredUpInShipCoordSys.y - yawcloseness) * ship->nonstatvars.turnspeed[TURN_ABOUTZ]; rotspeed = ship->rotinfo.rotspeed.z; if (rotspeed < desiredrotspeed) { rotstr = (desiredrotspeed - rotspeed) * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCCW]),ROT_ABOUTZCCW); } else { rotstr = (rotspeed - desiredrotspeed) * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCW]),ROT_ABOUTZCW); } } return FALSE; } bool aitrackHeadingWithBankPitchFunc(Ship *ship,vector *desiredHeading,real32 accuracy,real32 sinbank,real32 pitchdescend,real32 pitchturn,udword flags) { vector curheading; vector desheading; real32 curheadingsqr,curheadingmag; real32 desheadingsqr,desheadingmag; vector curup; real32 dotprodheading; real32 dotProdCheckUp; real32 actualpitchturn; real32 finalpitch; real32 temp1,temp2; if(ship->objtype == OBJ_ShipType) { if(ship->dontrotateever) { //don't rotate this ship return TRUE; } } matGetVectFromMatrixCol3(curheading,ship->rotinfo.coordsys); matGetVectFromMatrixCol1(curup,ship->rotinfo.coordsys); // I will treat curheading.z as = 0, but will not set it. desheading.x = desiredHeading->x; desheading.y = desiredHeading->y; // I will treat desheading.z as = 0, but will not set it. desheadingsqr = desheading.x * desheading.x + desheading.y * desheading.y; curheadingsqr = curheading.x * curheading.x + curheading.y * curheading.y; if (desheadingsqr == 0.0f) // extreme case where heading directly up { desheading.x = 1.0f; desheadingsqr = 1.0f; } if (curheadingsqr == 0.0f) // extreme case where heading directly up { curheading.x = 1.0f; curheadingsqr = 1.0f; } curheadingmag = fsqrt(curheadingsqr); desheadingmag = fsqrt(desheadingsqr); temp1 = 1.0f / curheadingmag; temp2 = 1.0f / desheadingmag; curheading.x *= temp1; curheading.y *= temp1; desheading.x *= temp2; desheading.y *= temp2; dotprodheading = (curheading.x * desheading.x) + (curheading.y * desheading.y); // no need to mulitply z components because it is 0 dotProdCheckUp = curup.z; //vecDotProduct({0,0,1},curup); if ((dotprodheading >= accuracy) && (pitchdescend == 0.0f) && isBetweenExclusive(curheading.z,STABILIZE_Z_LO,STABILIZE_Z_HI) && ((flags & AITRACKHEADING_IGNOREUPVEC) || (dotProdCheckUp >= accuracy)) ) { #if DEBUG_AITRACK dbgMessage("\nCapital ship on correct heading..."); #endif ship->rotinfo.rotspeed.x = 0.0f; ship->rotinfo.rotspeed.y = 0.0f; ship->rotinfo.rotspeed.z = 0.0f; return TRUE; // heading close enough to desired heading, so return } actualpitchturn = (1.0f - abs(dotprodheading)) * pitchturn; if (pitchdescend < 0.0f) { actualpitchturn = -actualpitchturn; if (pitchdescend < actualpitchturn) { finalpitch = pitchdescend; } else { finalpitch = actualpitchturn; } } else { if (pitchdescend > actualpitchturn) { finalpitch = pitchdescend; } else { finalpitch = actualpitchturn; } } // we now have the final desired pitch, finalpitch. desheading.z = (real32)tan(finalpitch); // z = tan(theta) * 1 (because sqrt(desheading.x^2 + desheading.y^2) == 1) temp1 = 1.0f / fsqrt(desheading.z * desheading.z + 1.0f); desheading.x *= temp1; // normalize vector desheading.y *= temp1; desheading.z *= temp1; return aitrackHeadingFunc((SpaceObjRotImpTargGuidance *)ship,&desheading,accuracy,accuracy, sinbank,flags); } /*----------------------------------------------------------------------------- Name : aitrackRightVector Description : given a desired right vector, this ai will orient the ship in the correct heading as well as stopping any roll. Inputs : desiredRightVector Outputs : Return : ----------------------------------------------------------------------------*/ bool aitrackRightVector(Ship *ship,vector *desiredRightVector,real32 accuracy) { ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo; vector curright; vector curup; real32 dotProdCheckRight; real32 dotProdCheckUp; vector desiredRightInShipCoordSys; vector desiredUp = { 0.0f,0.0f,1.0f }; vector desiredUpInShipCoordSys; real32 desiredrotspeed; real32 rotspeed; real32 rotstr; real32 oneovertime; if(ship->objtype == OBJ_ShipType) { if(ship->dontrotateever) { //don't rotate this ship return TRUE; } } matGetVectFromMatrixCol2(curright,ship->rotinfo.coordsys); matGetVectFromMatrixCol1(curup,ship->rotinfo.coordsys); dotProdCheckRight = vecDotProduct(*desiredRightVector,curright); dotProdCheckUp = curup.z; //vecDotProduct(desiredUp,curup) #if DEBUG_AITRACK dbgMessagef("\nHeading accuracy: %f",dotProdCheckRight); #endif if (dotProdCheckRight <= -1.0f) { // Exactly opposite direction, so arbitrarily chose a direction and rotate that way physApplyRotToObj((SpaceObjRot *)ship,ship->nonstatvars.rotstrength[ROT_ABOUTXCW],ROT_ABOUTXCW); return FALSE; } if ((dotProdCheckRight >= accuracy) && (dotProdCheckUp >= AITRACKRIGHT_UPACCURACY)) { #if DEBUG_AITRACK dbgMessage("\nOn correct heading..."); #endif aitrackForceShipZeroRotation(ship); return TRUE; // heading close enough to desired heading, so return } // Our heading is not close to the desired heading, so we have // to do more work... // transform desiredRightVector into desiredRightVector in Ship co-ordinate system matMultiplyVecByMat(&desiredRightInShipCoordSys,desiredRightVector,&ship->rotinfo.coordsys); // transform desiredUp into desiredUp in Ship co-ordinate system matMultiplyVecByMat(&desiredUpInShipCoordSys,&desiredUp,&ship->rotinfo.coordsys); oneovertime = 1.0f / universe.phystimeelapsed; // Check if we need to rotate about x axis (yaw) if (desiredRightInShipCoordSys.z != 0) { if (desiredRightInShipCoordSys.y < 0.0f) { if (desiredRightInShipCoordSys.z > 0.0f) { desiredrotspeed = ship->nonstatvars.turnspeed[TURN_ABOUTX]; } else { desiredrotspeed = -ship->nonstatvars.turnspeed[TURN_ABOUTX]; } } else { desiredrotspeed = desiredRightInShipCoordSys.z * ship->nonstatvars.turnspeed[TURN_ABOUTX]; } rotspeed = ship->rotinfo.rotspeed.x; if (rotspeed < desiredrotspeed) { rotstr = (desiredrotspeed - rotspeed) * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCCW]),ROT_ABOUTXCCW); } else { rotstr = (rotspeed - desiredrotspeed) * shipstaticinfo->staticheader.momentOfInertiaX * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTXCW]),ROT_ABOUTXCW); } } // Check if we need to rotate about y axis (pitch) to make up-vector of ship // align with world z axis. if (desiredUpInShipCoordSys.z != 0) { if (desiredUpInShipCoordSys.x < 0.0f) { if (desiredUpInShipCoordSys.z < 0.0f) { desiredrotspeed = ship->nonstatvars.turnspeed[TURN_ABOUTY]; } else { desiredrotspeed = -ship->nonstatvars.turnspeed[TURN_ABOUTY]; } } else { desiredrotspeed = -desiredUpInShipCoordSys.z * ship->nonstatvars.turnspeed[TURN_ABOUTY]; } rotspeed = ship->rotinfo.rotspeed.y; if (rotspeed < desiredrotspeed) { rotstr = (desiredrotspeed - rotspeed) * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCCW]),ROT_ABOUTYCCW); } else { rotstr = (rotspeed - desiredrotspeed) * shipstaticinfo->staticheader.momentOfInertiaY * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTYCW]),ROT_ABOUTYCW); } } // Check if we need to rotate about z axis (roll) if (desiredRightInShipCoordSys.x != 0) { if (desiredRightInShipCoordSys.y < 0.0f) { if (desiredRightInShipCoordSys.x < 0.0f) { desiredrotspeed = ship->nonstatvars.turnspeed[TURN_ABOUTZ]; } else { desiredrotspeed = -ship->nonstatvars.turnspeed[TURN_ABOUTZ]; } } else { desiredrotspeed = -desiredRightInShipCoordSys.x * ship->nonstatvars.turnspeed[TURN_ABOUTZ]; } rotspeed = ship->rotinfo.rotspeed.z; if (rotspeed < desiredrotspeed) { rotstr = (desiredrotspeed - rotspeed) * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCCW]),ROT_ABOUTZCCW); } else { rotstr = (rotspeed - desiredrotspeed) * shipstaticinfo->staticheader.momentOfInertiaZ * oneovertime; physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCW]),ROT_ABOUTZCW); } } return FALSE; } /*----------------------------------------------------------------------------- Name : aitrackVelocityVector Description : given a velocity vector, makes the ship track it. Note that it does not change the heading, only the velocity of the ship. Inputs : desiredVelocity Outputs : Return : ----------------------------------------------------------------------------*/ void aitrackVelocityVectorGuidance(SpaceObjRotImpTargGuidance *ship,vector *desiredVelocity) { StaticInfoHealthGuidance *shipstaticinfo = ship->staticinfo; vector errorDifference; real32 errorMagSquared; real32 thruststr; real32 massOverTime; vector desiredVelocityInShipCoordSys; vector shipVelocityInShipCoordSys; // check if desiredVelocity is approximately the same as current velocity vecSub(errorDifference,*desiredVelocity,ship->posinfo.velocity); // later is there a faster way to do this? errorMagSquared = vecMagnitudeSquared(errorDifference); #if DEBUG_AITRACK dbgMessagef("\nVelocity Error = %f",errorMagSquared); #endif if (errorMagSquared < ERROR_VELOCITY_SQUARED) { #if DEBUG_AITRACK dbgMessage("\nVelocity tracking locked..."); #endif return; // ship velocity close enought to desired velocity, so return } // current velocity is not close enought to desiredVelocity, so // we have to do more work. // transfrom desiredVelocity into desiredVelocity in ship co-ordinate system // transfrom shipVelocity into shipVelocity in ship co-ordinate system matMultiplyVecByMat(&desiredVelocityInShipCoordSys,desiredVelocity,&ship->rotinfo.coordsys); matMultiplyVecByMat(&shipVelocityInShipCoordSys,&ship->posinfo.velocity,&ship->rotinfo.coordsys); massOverTime = shipstaticinfo->staticheader.mass / universe.phystimeelapsed; if (shipVelocityInShipCoordSys.x < desiredVelocityInShipCoordSys.x) { thruststr = (desiredVelocityInShipCoordSys.x - shipVelocityInShipCoordSys.x) * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_UP]),TRANS_UP); } else if (shipVelocityInShipCoordSys.x > desiredVelocityInShipCoordSys.x) { thruststr = (shipVelocityInShipCoordSys.x - desiredVelocityInShipCoordSys.x) * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_DOWN]),TRANS_DOWN); } if (shipVelocityInShipCoordSys.y < desiredVelocityInShipCoordSys.y) { thruststr = (desiredVelocityInShipCoordSys.y - shipVelocityInShipCoordSys.y) * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_RIGHT]),TRANS_RIGHT); } else if (shipVelocityInShipCoordSys.y > desiredVelocityInShipCoordSys.y) { thruststr = (shipVelocityInShipCoordSys.y - desiredVelocityInShipCoordSys.y) * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_LEFT]),TRANS_LEFT); } if (shipVelocityInShipCoordSys.z < desiredVelocityInShipCoordSys.z) { thruststr = (desiredVelocityInShipCoordSys.z - shipVelocityInShipCoordSys.z) * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_FORWARD]),TRANS_FORWARD); } else if (shipVelocityInShipCoordSys.z > desiredVelocityInShipCoordSys.z) { thruststr = (shipVelocityInShipCoordSys.z - desiredVelocityInShipCoordSys.z) * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_BACKWARD]),TRANS_BACKWARD); } } /*----------------------------------------------------------------------------- Name : aitrackIsZeroVelocity Description : returns TRUE if ship has stopped drifting Inputs : Outputs : Return : returns TRUE if ship has stopped drifting ----------------------------------------------------------------------------*/ bool aitrackIsZeroVelocity(Ship *ship) { vector shipVelocity; shipVelocity = ship->posinfo.velocity; if (isBetweenExclusive(shipVelocity.x,STILL_VELOCITY_LO,STILL_VELOCITY_HI) && isBetweenExclusive(shipVelocity.y,STILL_VELOCITY_LO,STILL_VELOCITY_HI) && isBetweenExclusive(shipVelocity.z,STILL_VELOCITY_LO,STILL_VELOCITY_HI) ) { return TRUE; // ship velocity close enought to desired velocity, so return } else { return FALSE; } } bool aitrackZeroForwardVelocity(Ship *ship) { ShipStaticInfo *shipstaticinfo = ship->staticinfo; real32 thruststr; real32 massOverTime; real32 forwardvelocity; vector heading; matGetVectFromMatrixCol3(heading,ship->rotinfo.coordsys); forwardvelocity = vecDotProduct(heading,ship->posinfo.velocity); if (isBetweenExclusive(forwardvelocity,STILL_VELOCITY_LO,STILL_VELOCITY_HI)) { return TRUE; // ship velocity close enought to desired velocity, so return } massOverTime = shipstaticinfo->staticheader.mass / universe.phystimeelapsed; if (forwardvelocity < 0) { thruststr = -forwardvelocity * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_FORWARD]),TRANS_FORWARD); } else { thruststr = forwardvelocity * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_BACKWARD]),TRANS_BACKWARD); } return FALSE; } /*----------------------------------------------------------------------------- Name : aitrackZeroVelocity Description : stops ship from drifting Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ bool aitrackZeroVelocity(Ship *ship) { vector shipVelocity; vector shipVelocityInShipCoordSys; ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo; real32 thruststr; real32 massOverTime; shipVelocity = ship->posinfo.velocity; if (isBetweenExclusive(shipVelocity.x,STILL_VELOCITY_LO,STILL_VELOCITY_HI) && isBetweenExclusive(shipVelocity.y,STILL_VELOCITY_LO,STILL_VELOCITY_HI) && isBetweenExclusive(shipVelocity.z,STILL_VELOCITY_LO,STILL_VELOCITY_HI) ) { return TRUE; // ship velocity close enought to desired velocity, so return } #ifdef gshaw // dbgMessagef("\nZeroing velocity %f %f %f %x",hshipVelocity.x,hshipVelocity.y,hshipVelocity.z,(udword)ship); #endif // transfrom shipVelocity into shipVelocity in ship co-ordinate system matMultiplyVecByMat(&shipVelocityInShipCoordSys,&shipVelocity,&ship->rotinfo.coordsys); massOverTime = shipstaticinfo->staticheader.mass / universe.phystimeelapsed; if (shipVelocityInShipCoordSys.x < 0) { thruststr = -shipVelocityInShipCoordSys.x * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_UP]),TRANS_UP); } else { thruststr = shipVelocityInShipCoordSys.x * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_DOWN]),TRANS_DOWN); } if (shipVelocityInShipCoordSys.y < 0) { thruststr = -shipVelocityInShipCoordSys.y * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_RIGHT]),TRANS_RIGHT); } else { thruststr = shipVelocityInShipCoordSys.y * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_LEFT]),TRANS_LEFT); } if (shipVelocityInShipCoordSys.z < 0) { thruststr = -shipVelocityInShipCoordSys.z * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_FORWARD]),TRANS_FORWARD); } else { thruststr = shipVelocityInShipCoordSys.z * massOverTime; physApplyForceToObj((SpaceObj *)ship,capNumber(thruststr,ship->nonstatvars.thruststrength[TRANS_BACKWARD]),TRANS_BACKWARD); } return FALSE; } /*----------------------------------------------------------------------------- Name : aitrackSteadyShipDriftOnly Description : stops ship from drifting only Inputs : ship Outputs : Return : ----------------------------------------------------------------------------*/ bool aitrackSteadyShipDriftOnly(Ship *ship) { if (aitrackZeroVelocity(ship)) { aitrackForceZeroVelocity(ship); return TRUE; } else { return FALSE; } } /*----------------------------------------------------------------------------- Name : aitrackIsShipSteadyAnywhere Description : returns TRUE if ship is steady anywhere (not necessarily oriented up) Inputs : ship Outputs : Return : returns TRUE if ship is steady anywhere (not necessarily oriented up) ----------------------------------------------------------------------------*/ bool aitrackIsShipSteadyAnywhere(Ship *ship) { return (aitrackIsZeroRotation(ship) & aitrackIsZeroVelocity(ship)); } /*----------------------------------------------------------------------------- Name : aitrackSteadyShipAnywhere Description : stops ship from drifting, and stops ship from rotating (not necessarily oriented up) Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ bool aitrackSteadyShipAnywhere(Ship *ship) { bool stabilized = aitrackZeroRotationAnywhere(ship); bool zerovel = aitrackZeroVelocity(ship); if (stabilized && zerovel) { aitrackForceSteadyShip(ship); return TRUE; } else { return FALSE; } } /*----------------------------------------------------------------------------- Name : aitrackIsShipSteady Description : returns TRUE if ship is steady Inputs : ship Outputs : Return : returns TRUE if ship is steady ----------------------------------------------------------------------------*/ bool aitrackIsShipSteady(Ship *ship) { return (aitrackIsStabilizeShip(ship) & aitrackIsZeroVelocity(ship)); } /*----------------------------------------------------------------------------- Name : aitrackSteadyShip Description : stops ship from drifting, and stops ship from rotating Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ bool aitrackSteadyShip(Ship *ship) { bool stabilized = aitrackStabilizeShip(ship); bool zerovel = aitrackZeroVelocity(ship); if (stabilized && zerovel) { aitrackForceSteadyShip(ship); return TRUE; } else { return FALSE; } } /*----------------------------------------------------------------------------- Name : aitrackForceSteadyShip Description : stops ship from drifting/rotating, perfectly. Use as an approximation to aitrackSteadyShip, if ship is moving very slow. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void aitrackForceSteadyShip(Ship *ship) { if (ship->flags & SOF_Crazy) { return; // ship is crazy, so return } ship->posinfo.velocity.x = 0.0f; ship->posinfo.velocity.y = 0.0f; ship->posinfo.velocity.z = 0.0f; ship->rotinfo.rotspeed.x = 0.0f; ship->rotinfo.rotspeed.y = 0.0f; ship->rotinfo.rotspeed.z = 0.0f; } /*----------------------------------------------------------------------------- Name : aitrackForceShipZeroRotation Description : stops ships from rotating, perfectly. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void aitrackForceGuidanceZeroRotation(SpaceObjRotImpTargGuidance *ship) { if (ship->flags & SOF_Crazy) { return; // ship is crazy, so return } ship->rotinfo.rotspeed.x = 0.0f; ship->rotinfo.rotspeed.y = 0.0f; ship->rotinfo.rotspeed.z = 0.0f; } /*----------------------------------------------------------------------------- Name : aitrackForceZeroVelocity Description : stops ship from moving, perfectly Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void aitrackForceZeroVelocity(Ship *ship) { if (ship->flags & SOF_Crazy) { return; // ship is crazy, so return } ship->posinfo.velocity.x = 0.0f; ship->posinfo.velocity.y = 0.0f; ship->posinfo.velocity.z = 0.0f; } /*----------------------------------------------------------------------------- Name : aitrackForceHeading Description : points ship in a particular direction Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void aitrackForceHeading(Ship *ship, vector *heading, vector *upvector) { vector rightvec; if (ship->flags & SOF_Crazy) { return; // ship is crazy, so return } vecCrossProduct(rightvec,*heading,*upvector); // set up vector ship->rotinfo.coordsys.m11 = upvector->x; ship->rotinfo.coordsys.m21 = upvector->y; ship->rotinfo.coordsys.m31 = upvector->z; // set right vector ship->rotinfo.coordsys.m12 = rightvec.x; ship->rotinfo.coordsys.m22 = rightvec.y; ship->rotinfo.coordsys.m32 = rightvec.z; // set heading vector ship->rotinfo.coordsys.m13 = heading->x; ship->rotinfo.coordsys.m23 = heading->y; ship->rotinfo.coordsys.m33 = heading->z; } /*----------------------------------------------------------------------------- Name : MoveReachedDestinationVariable Description : returns TRUE if ship has reached destination (or is close enough) Inputs : ship,destination,bounds Outputs : Return : TRUE if ship has reached destination (or is close enough) ----------------------------------------------------------------------------*/ bool MoveReachedDestinationVariable(Ship *ship,vector *destination,real32 bounds) { vector lefttogo; real32 negbounds = -bounds; vecSub(lefttogo,*destination,ship->posinfo.position); if ((isBetweenExclusive(lefttogo.x,negbounds,bounds)) && (isBetweenExclusive(lefttogo.y,negbounds,bounds)) && (isBetweenExclusive(lefttogo.z,negbounds,bounds))) { #ifdef gshaw // dbgMessagef("\nShip %x reached destination!",(udword)ship); #endif return TRUE; } else { #ifdef gshaw // dbgMessagef("\nLeft to go: %f %f %f",lefttogo.x,lefttogo.y,lefttogo.z); #endif return FALSE; } } /*----------------------------------------------------------------------------- Name : MoveLeftToGo Description : returns the maximum distance along a axis which the ship has left to go Inputs : ship, destination Outputs : Return : returns the maximum distance along a axis which the ship has left to go ----------------------------------------------------------------------------*/ real32 MoveLeftToGo(Ship *ship,vector *destination) { real32 absx = abs(destination->x - ship->posinfo.position.x); real32 absy = abs(destination->y - ship->posinfo.position.y); real32 absz = abs(destination->z - ship->posinfo.position.z); return max(max(absx,absy),absz); } /*----------------------------------------------------------------------------- Name : aitrackRotationSpeed Description : make's a ship track a desired speed Inputs : ship, rotation speed, track Outputs : none Return : void ----------------------------------------------------------------------------*/ bool aitrackRotationSpeed(Ship *ship, real32 desiredrotspeed, uword track) { real32 rotstr; real32 oneovertime; real32 rotspeed; oneovertime = 1.0f / universe.phystimeelapsed; switch (track) { case ROT_ABOUTXCCW : case ROT_ABOUTXCW : if (isBetweenExclusive(ship->rotinfo.rotspeed.x, desiredrotspeed+STILL_ROT_LO, desiredrotspeed+STILL_ROT_HI)) return(TRUE); rotspeed = ship->rotinfo.rotspeed.x; rotstr = (desiredrotspeed - rotspeed) * ship->staticinfo->staticheader.momentOfInertiaX * oneovertime; break; case ROT_ABOUTYCCW : case ROT_ABOUTYCW : if (isBetweenExclusive(ship->rotinfo.rotspeed.y, desiredrotspeed+STILL_ROT_LO, desiredrotspeed+STILL_ROT_HI)) return(TRUE); rotspeed = ship->rotinfo.rotspeed.y; rotstr = (desiredrotspeed - rotspeed) * ship->staticinfo->staticheader.momentOfInertiaY * oneovertime; break; case ROT_ABOUTZCCW : case ROT_ABOUTZCW : if (isBetweenExclusive(ship->rotinfo.rotspeed.z, desiredrotspeed+STILL_ROT_LO, desiredrotspeed+STILL_ROT_HI)) return(TRUE); rotspeed = ship->rotinfo.rotspeed.z; rotstr = (desiredrotspeed - rotspeed) * ship->staticinfo->staticheader.momentOfInertiaZ * oneovertime; break; } if (rotspeed < desiredrotspeed) { physApplyRotToObj((SpaceObjRot *)ship,capNumber(rotstr,ship->nonstatvars.rotstrength[track]),track); return(FALSE); } else { rotstr = -capNumber(-rotstr,ship->nonstatvars.rotstrength[ROT_ABOUTZCW]); physApplyRotToObj((SpaceObjRot *)ship,rotstr,track); return(FALSE); } }