// ----------------------------------------------------------------------- // // // ROUTINE: CAutoTargetMgr::GenerateNodeArray() // // PURPOSE: Find the nodes closest to the center of view // // ----------------------------------------------------------------------- // void CAutoTargetMgr::GenerateNodeArray() { int cNodes; ILTModel *pModelLT = g_pLTClient->GetModelLT(); //clear our node array m_nNodeCount = 0; //step through the chars we know about CharFXArray::iterator iter = m_Targets.begin(); while (iter != m_Targets.end()) { CCharacterFX* pChar = (CCharacterFX*)(*iter); ModelsDB::HSKELETON hModelSkeleton = pChar->GetModelSkeleton(); cNodes = g_pModelsDB->GetSkeletonNumNodes(hModelSkeleton); // Enumerate through the nodez for(int iNode = 0; iNode < cNodes && m_nNodeCount < MAX_AUTOTARGET_NODES; iNode++) { ModelsDB::HNODE hCurNode = g_pModelsDB->GetSkeletonNode( hModelSkeleton, iNode ); if( g_pModelsDB->GetNodeAutoTarget( hCurNode )) { // get the nodes position LTTransform lTrans; HMODELNODE hNode; char const* szNodeName = g_pModelsDB->GetNodeName( hCurNode ); if( LT_OK == pModelLT->GetNode( pChar->GetServerObj(), szNodeName, hNode ) ) { if( LT_OK == pModelLT->GetNodeTransform( pChar->GetServerObj(), hNode, lTrans, true ) ) { m_NodeArray[m_nNodeCount].vPos = lTrans.m_vPos; m_NodeArray[m_nNodeCount].hChar = pChar->GetServerObj(); m_nNodeCount++; } } } } iter++; } }
void CNodeController::HandleNodeControlRecoilMessage(HMESSAGEREAD hMessage) { if ( m_cRecoils >= MAX_RECOILS ) return; m_fRecoilTimers[m_cRecoils++] = 0.50f; ModelNode eModelNode; eModelNode = (ModelNode)g_pLTClient->ReadFromMessageByte(hMessage); LTVector vRecoilDir; g_pLTClient->ReadFromMessageCompVector(hMessage, &vRecoilDir); // Get the magnitude of the recoil vector LTFLOAT fRecoilMag = VEC_MAGSQR(vRecoilDir); // Get the unit impact/recoil vector vRecoilDir /= (float)sqrt(fRecoilMag); // Cap it if necessary if ( fRecoilMag > 100.0f ) { fRecoilMag = 100.0f; } // Get the position of the impact NSTRUCT* pNode = &m_aNodes[eModelNode]; ILTModel* pModelLT = g_pLTClient->GetModelLT(); LTransform transform; pModelLT->GetNodeTransform(GetCFX()->GetServerObj(), pNode->hModelNode, transform, LTTRUE); // Decompose the transform into the position and rotation LTVector vPos; ILTTransform* pTransformLT = g_pLTClient->GetTransformLT(); pTransformLT->GetPos(transform, vPos); LTVector vRecoilPos = vPos; // Add angular rotations up the recoil parent chain ModelNode eModelNodeCurrent = g_pModelButeMgr->GetSkeletonNodeRecoilParent(GetCFX()->GetModelSkeleton(), eModelNode); while ( eModelNodeCurrent != eModelNodeInvalid ) { // Get the rotation of the node NSTRUCT* pNode = &m_aNodes[eModelNodeCurrent]; LTransform transform; ILTModel* pModelLT = g_pLTClient->GetModelLT(); // Get the transform of the node we're controlling pModelLT->GetNodeTransform(GetCFX()->GetServerObj(), pNode->hModelNode, transform, LTTRUE); ILTTransform* pTransformLT = g_pLTClient->GetTransformLT(); // Decompose the transform into the position and rotation LTVector vPos; LTRotation rRot; pTransformLT->Get(transform, vPos, rRot); // Get the rotation vectors of the transform LTVector vRight, vUp, vForward; g_pLTClient->GetRotationVectors(&rRot, &vUp, &vRight, &vForward); // Cross the right vector with the impact vector to get swing LTVector vRotationAxis = vRight.Cross(vRecoilDir); vRotationAxis.Norm(); // Add the timed rotation control for the swing // !!! HACK // !!! Do not add swing if this is a leg node if ( !strstr(g_pModelButeMgr->GetSkeletonNodeName(GetCFX()->GetModelSkeleton(), eModelNodeCurrent), "leg") ) AddNodeControlRotationTimed(eModelNodeCurrent, vRotationAxis, MATH_PI/1000.0f*fRecoilMag, 0.50f); // Use the right vector to get twist, but make sure the sign is correct based on location // of impact and whether we're getting shot at from behind/front etc vRotationAxis = vRight; vRotationAxis.Norm(); // Get the twist LTVector vSideDir = vRecoilPos-vPos; vSideDir.Norm(); LTFLOAT fSign = vUp.Dot(vRecoilDir); fSign *= vForward.Dot(vSideDir); if ( fSign > 0.0f ) { vRotationAxis = -vRotationAxis; } // Add the timed rotation control for the twist // AddNodeControlRotationTimed(eModelNodeCurrent, vRotationAxis, MATH_PI/1000.0f*fRecoilMag, 0.50f); // Decrease the magnitude fRecoilMag /= 2.0f; eModelNodeCurrent = g_pModelButeMgr->GetSkeletonNodeRecoilParent(GetCFX()->GetModelSkeleton(), eModelNodeCurrent); } }
void CNodeController::UpdateHeadFollowPosControl(NCSTRUCT *pNodeControl) { LTVector vPos; LTRotation rRot; LTransform transform; LTVector vU, vR, vF; //---------------------------------------------------------------------- // Get information about the control node... // *** NOTE: On the head node... vU faces forward, vR faces down, vF faces right *** // Get access to the controls... ILTMath *pMathLT = g_pLTClient->GetMathLT(); ILTModel *pModelLT = g_pLTClient->GetModelLT(); ILTTransform *pTransformLT = g_pLTClient->GetTransformLT(); // Get the transform of the node we're controlling pModelLT->GetNodeTransform(GetCFX()->GetServerObj(), m_aNodes[pNodeControl->eModelNode].hModelNode, transform, LTTRUE); // Decompose the transform into the position and rotation pTransformLT->Get(transform, vPos, rRot); pMathLT->GetRotationVectors(rRot, vR, vU, vF); // Get information about the follow position... LTVector vObjPos = pNodeControl->vFollowPos; // Turn the follow control off if the expire time has past if(pNodeControl->fFollowExpireTime <= 0.0f) { pNodeControl->fFollowExpireTime = 0.0f; pNodeControl->bFollowOn = LTFALSE; } else pNodeControl->fFollowExpireTime -= g_pGameClientShell->GetFrameTime(); //---------------------------------------------------------------------- // Setup the rotation matrix to directly follow the destination position // Get the direction that we're going to face... LTVector vDir = vObjPos - vPos; // Setup some temp vectors that are on the x/z plane... LTVector vTempU, vTempF, vTempDir; vTempU = vU; vTempU.y = 0.0f; vTempF = vF; vTempF.y = 0.0f; vTempDir = vDir; vTempDir.y = 0.0f; VEC_NORM(vTempU); VEC_NORM(vTempF); VEC_NORM(vTempDir); // Get the dot products between the dir vector and the up and forward to determine the rotation angles LTFLOAT fDotUDir = VEC_DOT(vTempU, vTempDir); LTFLOAT fDotFDir = VEC_DOT(vTempF, vTempDir); LTFLOAT fDotRDir = 0.0f; // Init the vectors to get a rotation matrix from... LTVector vRotAxisR(1.0f, 0.0f, 0.0f); // Get the first rotation angle LTFLOAT fAngle1 = pNodeControl->bFollowOn ? fDotUDir : 1.0f; if(fAngle1 < -0.1f) fAngle1 = -0.1f; // HACK! Limit the head rotation fAngle1 = (1.0f - fAngle1) * MATH_HALFPI; if(fDotFDir < 0.0f) fAngle1 *= -1.0f; // Do a full rotation around the first axis so we can get an angle for the second axis LTFLOAT fTempAngle = pNodeControl->bFollowOn ? ((1.0f - fDotUDir) * MATH_HALFPI) : 0.0f; pMathLT->RotateAroundAxis(rRot, vR, (fDotFDir < 0.0f) ? -fTempAngle : fTempAngle); pMathLT->GetRotationVectors(rRot, vR, vU, vF); VEC_NORM(vDir); fDotUDir = VEC_DOT(vU, vDir); fDotRDir = VEC_DOT(vR, vDir); // Get the second rotation angle LTFLOAT fAngle2 = pNodeControl->bFollowOn ? fDotUDir : 1.0f; if(fAngle2 < 0.25f) fAngle2 = 0.25f; // HACK! Limit the head rotation fAngle2 = (1.0f - fAngle2) * MATH_HALFPI; if(fDotRDir > 0.0f) fAngle2 *= -1.0f; // Calculate a max rotation value LTFLOAT fRotMax = (pNodeControl->fFollowRate * g_pGameClientShell->GetFrameTime() / 180.0f) * MATH_PI; // Interpolate the angles based off the previous angle if(fAngle1 > pNodeControl->vFollowAngles.y + fRotMax) fAngle1 = pNodeControl->vFollowAngles.y + fRotMax; else if(fAngle1 < pNodeControl->vFollowAngles.y - fRotMax) fAngle1 = pNodeControl->vFollowAngles.y - fRotMax; if(fAngle2 > pNodeControl->vFollowAngles.x + fRotMax) fAngle2 = pNodeControl->vFollowAngles.x + fRotMax; else if(fAngle2 < pNodeControl->vFollowAngles.x - fRotMax) fAngle2 = pNodeControl->vFollowAngles.x - fRotMax; // Create a new rotation and rotate around each controlled axis LTRotation rNewRot; rNewRot.Init(); pMathLT->RotateAroundAxis(rNewRot, vRotAxisR, fAngle1); pNodeControl->vFollowAngles.y = fAngle1; pMathLT->GetRotationVectors(rNewRot, vR, vU, vF); pMathLT->RotateAroundAxis(rNewRot, vF, fAngle2); pNodeControl->vFollowAngles.x = fAngle2; // If we're turned off and back at the start rotation... make the control invalid if(!pNodeControl->bFollowOn && pNodeControl->vFollowAngles.x == 0.0f && pNodeControl->vFollowAngles.y == 0.0f) { pNodeControl->bValid = LTFALSE; return; } // Create a rotation matrix and apply it to the current offset matrix LTMatrix m1; pMathLT->SetupRotationMatrix(m1, rNewRot); m_aNodes[pNodeControl->eModelNode].matTransform = m_aNodes[pNodeControl->eModelNode].matTransform * m1; }