void DisplayWeaponModelPieces( LTObjRef hObject, HWEAPON hWeapon, const char* ModelPieceListAtt, bool bShow, bool bUseAIWeapons ) { if( !hWeapon || !hObject ) return; // get the model interface ILTModel *pModelLT = g_pLTServer->GetModelLT(); ASSERT( 0 != pModelLT ); HWEAPONDATA hWpnData = g_pWeaponDB->GetWeaponData(hWeapon, bUseAIWeapons); uint32 NumPieces = g_pWeaponDB->GetNumValues(hWpnData,ModelPieceListAtt); for (uint32 PieceIndex=0; PieceIndex < NumPieces; PieceIndex++) { const char* pszPiece = g_pWeaponDB->GetString(hWpnData, ModelPieceListAtt, PieceIndex); HMODELPIECE hPiece = 0; if( LT_OK == pModelLT->GetPiece( hObject, pszPiece, hPiece ) ) { // show or hide the model piece LTRESULT ltResult = pModelLT->SetPieceHideStatus( hObject, hPiece, !bShow ); ASSERT( ( LT_OK == ltResult) || ( LT_NOCHANGE == ltResult ) ); } } }
// ----------------------------------------------------------------------- // // // 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++; } }
bool CLightningFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps) { LTVector vSave = pBaseData->m_vPos; // Perform base class initialisation if (!CBaseFX::Init(pClientDE, pBaseData, pProps)) return false; ObjectCreateStruct ocs; INIT_OBJECTCREATESTRUCT(ocs); ocs.m_ObjectType = OT_NORMAL; ocs.m_Flags = pBaseData->m_dwObjectFlags | FLAG_NOLIGHT; ocs.m_Flags2 |= pBaseData->m_dwObjectFlags2; ocs.m_Pos = m_vCreatePos; m_hObject = m_pLTClient->CreateObject(&ocs); if( !m_hObject ) return false; // Are we rendering really close? m_bReallyClose = !!(pBaseData->m_dwObjectFlags & FLAG_REALLYCLOSE); // Create the max number of bolts CLightningBolt *pBolt = LTNULL; PT_TRAIL_SECTION ts; for( uint32 nBolts = 0; nBolts < GetProps()->m_nMaxNumBolts; ++nBolts ) { pBolt = debug_new( CLightningBolt ); pBolt->m_nNumSegments = GetRandom( (int)GetProps()->m_nMinSegmentsPerBolt, (int)GetProps()->m_nMaxSegmentsPerBolt ); // Add all the trail sections now since we don't need to constantly create and delete them... for( uint32 nSegs = 0; nSegs < pBolt->m_nNumSegments; ++nSegs ) { ts.m_vPos = m_vCreatePos; pBolt->m_collPathPts.AddTail( ts ); } m_lstBolts.push_back( pBolt ); } // Setup the target data so we now where the lightning is going... if( pBaseData->m_bUseTargetData ) { if( pBaseData->m_hTarget ) { m_hTarget = pBaseData->m_hTarget; } else if( m_hParent ) { m_hTarget = m_hParent; } else { m_hTarget = LTNULL; } m_vTargetPos = pBaseData->m_vTargetPos; } else { // Use our parent as the target if we have one otherwise just use ourselves... m_hTarget = (m_hParent ? m_hParent : m_hObject); m_vTargetPos = m_vCreatePos; } // Load the texture if one was specified... if( !m_hTexture && GetProps()->m_szTexture[0] ) { m_pLTClient->GetTexInterface()->CreateTextureFromName( m_hTexture, GetProps()->m_szTexture ); } // Create a list of attractor nodes if( m_hTarget ) { ILTModel *pModelLT = m_pLTClient->GetModelLT(); ILTCommon *pCommonLT = m_pLTClient->Common(); HMODELNODE hNode = -1; HMODELSOCKET hSocket = -1; HATTRACTOR hAttractor = INVALID_ATTRACTOR; CAttractor cAttractor; // Add any nodes to our attractor list... if( GetProps()->m_szNodeAttractors[0] ) { ConParse parse( GetProps()->m_szNodeAttractors ); while( pCommonLT->Parse( &parse ) == LT_OK ) { if( parse.m_nArgs > 0 && parse.m_Args[0] ) { if( pModelLT->GetNode( m_hTarget, parse.m_Args[0], hAttractor ) == LT_OK ) { cAttractor.m_hModel = m_hTarget; cAttractor.m_hAttractor = hAttractor; cAttractor.m_eType = CAttractor::eNode; m_lstAttractors.push_back( cAttractor ); } } } } // Add any sockets to our attractor list... if( GetProps()->m_szSocketAttractors[0] ) { ConParse parse( GetProps()->m_szSocketAttractors ); while( pCommonLT->Parse( &parse ) == LT_OK ) { if( parse.m_nArgs > 0 && parse.m_Args[0] ) { if( pModelLT->GetSocket( m_hTarget, parse.m_Args[0], hAttractor ) == LT_OK ) { cAttractor.m_hModel = m_hTarget; cAttractor.m_hAttractor = hAttractor; cAttractor.m_eType = CAttractor::eSocket; m_lstAttractors.push_back( cAttractor ); } } } } } m_tmElapsedEmission = 0.0f; m_fDelay = 0.0f; return true; }
bool CLTBModelFX::Update(float tmFrameTime) { //Ok, what we are going to do is see if we are supposed to be sync'd to the //animation. If so, we are going to flat out ignore tmCur, and instead generate //our own. This way we can match the model exactly. if(GetProps()->m_bSyncToModelAnim) { //we need to find out where in the animation the model currently is ILTModel *pLTModel = m_pLTClient->GetModelLT(); ANIMTRACKERID nTracker; if(pLTModel->GetMainTracker( m_hObject, nTracker ) == LT_OK) { //we have the main tracker, see where in its timeline it is uint32 nCurrTime; uint32 nAnimTime; pLTModel->GetCurAnimTime(m_hObject, nTracker, nCurrTime); pLTModel->GetCurAnimLength(m_hObject, nTracker, nAnimTime); if(nAnimTime) { //handle wrapping nCurrTime %= nAnimTime; //ok, now convert cur time to a valid time m_tmElapsed = (nCurrTime * GetProps()->m_tmLifespan) / (float)nAnimTime; } else { //zero length animation? m_tmElapsed = 0.0f; } } } else if(GetProps()->m_bSyncToKey) { //we need to find out where in the key we currently are ILTModel *pLTModel = m_pLTClient->GetModelLT(); ANIMTRACKERID nTracker; if(pLTModel->GetMainTracker( m_hObject, nTracker ) == LT_OK) { //we have the main tracker, see where in its timeline it is uint32 nAnimLength; m_pLTClient->GetModelLT()->ResetAnim( m_hObject, nTracker ); pLTModel->GetCurAnimLength(m_hObject, nTracker, nAnimLength); if(nAnimLength > 0) nAnimLength--; float tmWrappedTime = fmodf(m_tmElapsed / GetProps()->m_tmLifespan, 1.0f); uint32 nAnimTime = (uint32)(tmWrappedTime * nAnimLength); pLTModel->SetCurAnimTime(m_hObject, nTracker, nAnimTime); } } // Base class update first if (!CBaseFX::Update(tmFrameTime)) return false; //see if we should reset our model animation if(!GetProps()->m_bSyncToKey && IsFinishedShuttingDown()) { //Reset the animation ANIMTRACKERID nTracker; m_pLTClient->GetModelLT()->GetMainTracker( m_hObject, nTracker ); m_pLTClient->GetModelLT()->ResetAnim( m_hObject, nTracker ); if(GetProps()->m_bOverrideAniLength) m_pLTClient->GetModelLT()->SetAnimRate( m_hObject, nTracker, m_fAniRate); } // Align if neccessary, to the rotation of our parent if ((m_hParent) && (GetProps()->m_nFacing == FACE_PARENTALIGN)) { LTRotation rParentRot; m_pLTClient->GetObjectRotation(m_hParent, &rParentRot); rParentRot = (GetProps()->m_bRotate ? rParentRot : rParentRot * m_rNormalRot); m_pLTClient->SetObjectRotation(m_hObject, &rParentRot); } // If we want to add a rotation, make sure we are facing the correct way... if( GetProps()->m_bRotate ) { LTFLOAT tmFrame = tmFrameTime; LTVector vR( m_rRot.Right() ); LTVector vU( m_rRot.Up() ); LTVector vF( m_rRot.Forward() ); LTRotation rRotation; if( m_hCamera && (GetProps()->m_nFacing == FACE_CAMERAFACING)) { m_pLTClient->GetObjectRotation( m_hCamera, &rRotation ); } else { m_pLTClient->GetObjectRotation( m_hObject, &rRotation ); } m_rRot.Rotate( vR, MATH_DEGREES_TO_RADIANS( GetProps()->m_vRotAdd.x * tmFrame )); m_rRot.Rotate( vU, MATH_DEGREES_TO_RADIANS( GetProps()->m_vRotAdd.y * tmFrame )); m_rRot.Rotate( vF, MATH_DEGREES_TO_RADIANS( GetProps()->m_vRotAdd.z * tmFrame )); rRotation = rRotation * m_rRot; m_pLTClient->SetObjectRotation( m_hObject, &(rRotation * m_rNormalRot)); } else if( GetProps()->m_nFacing == FACE_CAMERAFACING ) { LTRotation rCamRot; m_pLTClient->GetObjectRotation( m_hCamera, &rCamRot ); m_pLTClient->SetObjectRotation( m_hObject, &(rCamRot * m_rNormalRot) ); } // Success !! return true; }
bool CLTBModelFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps) { // Perform base class initialisation if (!CBaseFX::Init(pClientDE, pBaseData, pProps)) return false; // Use the "target" Normal instead, if one was specified... LTVector vNorm = GetProps()->m_vNorm; if( pBaseData->m_vTargetNorm.LengthSquared() > MATH_EPSILON ) { vNorm = pBaseData->m_vTargetNorm; vNorm.Normalize(); } // Develop the Right and Up vectors based off the Forward... LTVector vR, vU; if( (1.0f == vNorm.y) || (-1.0f == vNorm.y) ) { vR = LTVector( 1.0f, 0.0f, 0.0f ).Cross( vNorm ); } else { vR = LTVector( 0.0f, 1.0f, 0.0f ).Cross( vNorm ); } vU = vNorm.Cross( vR ); m_rNormalRot = LTRotation( vNorm, vU ); ObjectCreateStruct ocs; // Combine the direction we would like to face with our parents rotation... if( m_hParent ) { m_pLTClient->GetObjectRotation( m_hParent, &ocs.m_Rotation ); } else { ocs.m_Rotation = m_rCreateRot; } ocs.m_Rotation = ocs.m_Rotation * m_rNormalRot; ocs.m_ObjectType = OT_MODEL; ocs.m_Flags |= pBaseData->m_dwObjectFlags | (GetProps()->m_bShadow ? FLAG_SHADOW : 0 ); ocs.m_Flags2 |= pBaseData->m_dwObjectFlags2; // Calculate the position with the offset in 'local' coordinate space... LTMatrix mMat; ocs.m_Rotation.ConvertToMatrix( mMat ); m_vPos = ocs.m_Pos = m_vCreatePos + (mMat * GetProps()->m_vOffset); SAFE_STRCPY( ocs.m_Filename, GetProps()->m_szModelName ); SAFE_STRCPY( ocs.m_SkinNames[0], GetProps()->m_szSkinName[0] ); SAFE_STRCPY( ocs.m_SkinNames[1], GetProps()->m_szSkinName[1] ); SAFE_STRCPY( ocs.m_SkinNames[2], GetProps()->m_szSkinName[2] ); SAFE_STRCPY( ocs.m_SkinNames[3], GetProps()->m_szSkinName[3] ); SAFE_STRCPY( ocs.m_SkinNames[4], GetProps()->m_szSkinName[4] ); SAFE_STRCPY( ocs.m_RenderStyleNames[0], GetProps()->m_szRenderStyle[0] ); SAFE_STRCPY( ocs.m_RenderStyleNames[1], GetProps()->m_szRenderStyle[1] ); SAFE_STRCPY( ocs.m_RenderStyleNames[2], GetProps()->m_szRenderStyle[2] ); SAFE_STRCPY( ocs.m_RenderStyleNames[3], GetProps()->m_szRenderStyle[3] ); m_hObject = m_pLTClient->CreateObject(&ocs); if( !m_hObject ) return LTFALSE; ILTModel *pLTModel = m_pLTClient->GetModelLT(); ANIMTRACKERID nTracker; pLTModel->GetMainTracker( m_hObject, nTracker ); //setup the animation if the user specified one if( strlen(GetProps()->m_szAnimName) > 0) { //ok, we need to set this HMODELANIM hAnim = m_pLTClient->GetAnimIndex(m_hObject, GetProps()->m_szAnimName); if(hAnim != INVALID_MODEL_ANIM) { //ok, lets set this animation pLTModel->SetCurAnim(m_hObject, nTracker, hAnim); pLTModel->ResetAnim(m_hObject, nTracker); } } //disable looping on this animation (so we can actually stop!) pLTModel->SetLooping(m_hObject, nTracker, false); // Setup the initial data needed to override the models animation length... if( GetProps()->m_bOverrideAniLength ) { uint32 nAnimLength; pLTModel->GetCurAnimLength( m_hObject, nTracker, nAnimLength ); pLTModel->SetCurAnimTime( m_hObject, nTracker, 0 ); float fAniLength = (GetProps()->m_fAniLength < MATH_EPSILON) ? GetProps()->m_tmLifespan : GetProps()->m_fAniLength; if( fAniLength >= MATH_EPSILON || fAniLength <= -MATH_EPSILON ) m_fAniRate = (nAnimLength * 0.001f) / fAniLength; pLTModel->SetAnimRate( m_hObject, nTracker, m_fAniRate ); } // Success !! return LTTRUE; }
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; }