LTBOOL ScaleSprite::Update() { if (m_bStartOn) { g_pCommonLT->SetObjectFlags(m_hObject, OFT_User, USRFLG_VISIBLE, USRFLG_VISIBLE); g_pCommonLT->SetObjectFlags(m_hObject, OFT_Flags, FLAG_VISIBLE, FLAG_VISIBLE); } SetNextUpdate(UPDATE_NEVER); // BUG - This isn't quite right. Sometimes this works (flipping the sprite) // other times the sprite shouldn't be flipped...Not sure what the bug is. // For some reason the sprites are sometimes backwards...Get the rotation // so we can flip it... LTRotation rRot; LTVector vPos, vDir, vU, vR, vF; g_pLTServer->GetObjectPos(m_hObject, &vPos); g_pLTServer->GetObjectRotation(m_hObject, &rRot); vU = rRot.Up(); vR = rRot.Right(); vF = rRot.Forward(); if (m_bFlushWithWorld) { // Align the sprite to the surface directly behind the sprite // (i.e., opposite the forward vector)... VEC_NORM(vF); VEC_MULSCALAR(vDir, vF, -1.0f); // Determine where on the surface to place the sprite... IntersectInfo iInfo; IntersectQuery qInfo; VEC_COPY(qInfo.m_From, vPos); VEC_COPY(qInfo.m_Direction, vDir); qInfo.m_Flags = IGNORE_NONSOLID | INTERSECT_OBJECTS | INTERSECT_HPOLY; qInfo.m_FilterFn = LTNULL; if (g_pLTServer->CastRay(&qInfo, &iInfo)) { LTVector vTemp; VEC_COPY(vPos, iInfo.m_Point); VEC_COPY(vDir, iInfo.m_Plane.m_Normal); // Place the sprite just above the surface... VEC_MULSCALAR(vTemp, vDir, 1.0f); VEC_ADD(vPos, vPos, vTemp); g_pLTServer->SetObjectPos(m_hObject, &vPos); } } return LTTRUE; }
bool CClientWeaponDisc::CalculateControlDirection( LTVector *pvControlDirection ) { // // safety check // // params ASSERT( 0 != pvControlDirection ); // globals ASSERT( 0 != g_pLTClient ); ASSERT( 0 != g_pPlayerMgr ); // // The control direction is the direction the player is facing // // get the camera HOBJECT hCamera; hCamera = g_pPlayerMgr->GetCamera(); ASSERT( 0 != hCamera ); // determine the orientation of the segment LTRotation rRot; g_pLTClient->GetObjectRotation( hCamera, &rRot ); // determine the direction of the segment LTVector vForward; *pvControlDirection = rRot.Forward(); return true; }
bool CFallingStuffFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps) { // Perform base class initialisation if (!CBaseFX::Init(pClientDE, pBaseData, pProps)) return false; // Store the first position as the last position m_vLastPos = pBaseData->m_vPos; // If we have a parent object, get it and apply it's rotation // to the plane direction m_vPlaneDir = GetProps()->m_vPlaneDir; if (m_hParent) { LTRotation orient; m_pLTClient->GetObjectRotation(m_hParent, &orient); LTMatrix mRot; Mat_SetBasisVectors(&mRot, &orient.Right(), &orient.Up(), &orient.Forward()); LTVector vTmp = m_vPlaneDir; MatVMul(&m_vPlaneDir, &mRot, &vTmp); } LTVector vUp; vUp.x = 0.0f; vUp.y = 1.0f; vUp.z = 0.0f; LTVector vTest = m_vPlaneDir; vTest.x = (float)fabs(vTest.x); vTest.y = (float)fabs(vTest.y); vTest.z = (float)fabs(vTest.z); if (vTest == vUp) { // Gotsta use another axis vUp.x = -1.0f; vUp.y = 0.0f; vUp.z = 0.0f; } m_vRight = m_vPlaneDir.Cross(vUp); m_vUp = m_vPlaneDir.Cross(m_vRight); // Create the base object CreateDummyObject(); // Success !! return true; }
void CDestructibleModel::DoExplosion(char* pTargetName) { CWeapons weapons; weapons.Init(m_hObject); weapons.ObtainWeapon(m_nExplosionWeaponId); weapons.ChangeWeapon(m_nExplosionWeaponId); CWeapon* pWeapon = weapons.GetCurWeapon(); if (!pWeapon) return; weapons.SetAmmo(pWeapon->GetAmmoId()); pWeapon->SetDamageFactor(m_fDamageFactor); LTRotation rRot; g_pLTServer->GetObjectRotation(m_hObject, &rRot); LTVector vF, vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); vF = rRot.Forward(); // Just blow up in place if we're not supposed to fire along // forward vector and we don't have a target... if (!m_bFireAlongForward) { pWeapon->SetLifetime(0.0f); VEC_SET(vF, 0.0f, -1.0f, 0.0f); // Fire down } // See if we have a target...If so, point at it. if (pTargetName) { ObjArray <HOBJECT, MAX_OBJECT_ARRAY_SIZE> objArray; g_pLTServer->FindNamedObjects(pTargetName, objArray); if (objArray.NumObjects()) { LTVector vObjPos; g_pLTServer->GetObjectPos(objArray.GetObject(0), &vObjPos); vF = vObjPos - vPos; vF.Normalize(); rRot = LTRotation(vF, LTVector(0.0f, 1.0f, 0.0f)); g_pLTServer->SetObjectRotation(m_hObject, &rRot); } } WeaponFireInfo weaponFireInfo; weaponFireInfo.hFiredFrom = m_hObject; weaponFireInfo.vPath = vF; weaponFireInfo.vFirePos = vPos; weaponFireInfo.vFlashPos = vPos; pWeapon->Fire(weaponFireInfo); }
bool GunMount::FireWeapon( ) { CWeapon* pWeapon = m_Arsenal.GetCurWeapon( ); if( !pWeapon ) return false; // Get the direction we're firing. LTRotation rot; g_pLTServer->GetObjectRotation( m_hObject, &rot ); LTVector vDir = rot.Forward( ); LTVector vPos; if( !GetFirePos( vPos )) { g_pLTServer->GetObjectPos( m_hObject, &vPos ); } // Tell the weapon to fire. WeaponFireInfo weaponFireInfo; static uint8 s_nCount = GetRandom( 0, 255 ); s_nCount++; weaponFireInfo.hFiredFrom = m_hObject; weaponFireInfo.hFiringWeapon = pWeapon->GetModelObject( ); weaponFireInfo.vPath = vDir; weaponFireInfo.vFirePos = vPos; weaponFireInfo.vFlashPos = vPos; weaponFireInfo.nSeed = (uint8)GetRandom( 2, 255 ); weaponFireInfo.nPerturbCount = s_nCount; weaponFireInfo.nFireTimestamp = g_pLTServer->GetRealTimeMS( ); WeaponState eWeaponState = pWeapon->UpdateWeapon( weaponFireInfo, true ); if( eWeaponState == W_FIRED ) { // Count the round as fired. if( m_nRoundsToFire > 0 ) m_nRoundsToFire--; } // Keep ammo count up and clip loaded. The weapon could have refused // firing due to weapon fire time limitations, but it still decrements // ammo. m_Arsenal.AddAmmo( pWeapon->GetAmmoRecord(), 10 ); pWeapon->ReloadClip( false ); return true; }
LTBOOL CLaserTriggerFX::CalcBeamCoords() { if (!m_hServerObject) return LTFALSE; // The beam is relative to the server object's dims... LTVector vPos; g_pLTClient->GetObjectPos(m_hServerObject, &vPos); LTRotation rRot; g_pLTClient->GetObjectRotation(m_hServerObject, &rRot); LTVector vU, vR, vF; vU = rRot.Up(); vR = rRot.Right(); vF = rRot.Forward(); // Okay, the beam is always along the object's longest dim... LTVector vDir = vF; LTFLOAT fLongestDim = m_cs.vDims.z; // Assume forward first... m_pls.fMaxWidth = (m_cs.vDims.x + m_cs.vDims.y); // Assume x/y are same... if (m_cs.vDims.y > fLongestDim) { vDir = vU; fLongestDim = m_cs.vDims.y; m_pls.fMaxWidth = (m_cs.vDims.x + m_cs.vDims.z); } if (m_cs.vDims.x > fLongestDim) { vDir = vR; fLongestDim = m_cs.vDims.x; m_pls.fMaxWidth = (m_cs.vDims.y + m_cs.vDims.z); } m_pls.vStartPos = vPos + (vDir * fLongestDim); m_pls.vEndPos = vPos - (vDir * fLongestDim); return LTTRUE; }
bool ConstraintWheel::SetupBodySpaceData(const LTRigidTransform& tInvBody1, const LTRigidTransform& tInvBody2) { //get the position of our object which will serve as the constraint point LTVector vConstraintPos; if(g_pLTServer->GetObjectPos(m_hObject, &vConstraintPos) != LT_OK) return false; LTRotation rConstraintOr; if(g_pLTServer->GetObjectRotation(m_hObject, &rConstraintOr) != LT_OK) return false; m_vPivotPt1 = tInvBody1 * vConstraintPos; m_vPivotPt2 = tInvBody2 * vConstraintPos; m_vRotation1 = tInvBody1.m_rRot.RotateVector(rConstraintOr.Forward()); m_vRotation2 = tInvBody2.m_rRot.RotateVector(rConstraintOr.Forward()); m_vSuspension2 = tInvBody2.m_rRot.RotateVector(rConstraintOr.Up()); return true; }
void CFlashLight3rdPerson::GetLightPositions(LTVector& vStartPos, LTVector& vEndPos, LTVector& vUOffset, LTVector& vROffset) { if ( !m_hObj ) return; HMODELSOCKET hSocket; if ( LT_OK == g_pModelLT->GetSocket(m_hObj, "LeftHand", hSocket) ) { LTransform tf; if ( LT_OK == g_pModelLT->GetSocketTransform(m_hObj, hSocket, tf, LTTRUE) ) { LTVector vPos = tf.m_Pos; LTRotation rRot = tf.m_Rot; LTVector vRight, vUp, vForward; vRight = rRot.Right(); vUp = rRot.Up(); vForward = rRot.Forward(); //vStartPos = vPos - vUp*4.0f + vForward*8.0f; //vEndPos = vPos + vForward*200.0f; //vUOffset = vUp; //vROffset = vRight; vStartPos = vPos; vEndPos = vPos + (vForward * g_cvarFLLightOffsetForward.GetFloat()); vROffset = (vRight * g_cvarFLLightOffsetRight.GetFloat()); vUOffset = (vUp * g_cvarFLLightOffsetUp.GetFloat()); // Update the Start/End position to addjust for any offset... vEndPos += vROffset; vEndPos += vUOffset; vStartPos += vROffset; vStartPos += vUOffset; } } }
void CDestructibleModel::SetSurfaceType() { uint32 dwSurfUsrFlgs = 0; SurfaceType eSurfType = ST_UNKNOWN; // See if this object is a world model... if (GetObjectType(m_hObject) == OT_WORLDMODEL) { LTBOOL bDoBruteForce = LTTRUE; // See if we have a surface override... if (m_hstrSurfaceOverride) { const char* pSurfName = g_pLTServer->GetStringData(m_hstrSurfaceOverride); if (pSurfName) { SURFACE* pSurf = g_pSurfaceMgr->GetSurface(pSurfName); if (pSurf && pSurf->eType != ST_UNKNOWN) { eSurfType = pSurf->eType; bDoBruteForce = LTFALSE; } } } // Determine our surface...the hard way... if (bDoBruteForce) { IntersectQuery qInfo; IntersectInfo iInfo; LTVector vPos, vDims; LTRotation rRot; g_pLTServer->GetObjectPos(m_hObject, &vPos); g_pLTServer->GetObjectRotation(m_hObject, &rRot); g_pPhysicsLT->GetObjectDims(m_hObject, &vDims); LTFLOAT fMaxDims = vDims.x; fMaxDims = Max(fMaxDims, vDims.y); fMaxDims = Max(fMaxDims, vDims.z); qInfo.m_From = vPos + (rRot.Forward() * (fMaxDims + 1)); qInfo.m_To = vPos; qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY; SurfaceType eType = ST_UNKNOWN; if (g_pLTServer->IntersectSegment(&qInfo, &iInfo)) { if (iInfo.m_hObject == m_hObject) { eSurfType = GetSurfaceType(iInfo); } } } } else { DEBRIS* pDebris = g_pDebrisMgr->GetDebris(m_nDebrisId); if (pDebris) { eSurfType = pDebris->eSurfaceType; } } dwSurfUsrFlgs = SurfaceToUserFlag(eSurfType); g_pCommonLT->SetObjectFlags(m_hObject, OFT_User, dwSurfUsrFlgs, dwSurfUsrFlgs); g_pCommonLT->GetObjectFlags(m_hObject, OFT_Flags, m_dwOriginalFlags); }
bool CCreateRayFX::Update( float tmFrameTime ) { //track our performance CTimedSystemBlock TimingBlock(g_tsClientFXCreateRayFX); //update our base object BaseUpdate(tmFrameTime); //we only want to create the effect as we become active if(IsInitialFrame() && (GetProps()->m_nNumToCreate > 0)) { //determine the object position and orientation of our object LTVector vObjPos; LTRotation rObjRot; GetCurrentTransform(GetUnitLifetime(), vObjPos, rObjRot); //handle two special pipelines to gain performance when there is no scattering if(MATH_RADIANS_TO_DEGREES(GetProps()->m_fRandomCone) < 1.0f) { LTRigidTransform tHitTrans; HOBJECT hHitObj; //no scattering, just do a single intersection for all effects if(DetermineIntersection(vObjPos, rObjRot.Forward(), hHitObj, tHitTrans)) { //and now generate all of our effects for(uint32 nCurrEffect = 0; nCurrEffect < GetProps()->m_nNumToCreate; nCurrEffect++) { CLIENTFX_CREATESTRUCT CreateStruct("", GetProps()->m_nFXFlags, hHitObj, tHitTrans); CBaseCreateFX::CreateEffect(CreateStruct); } } } else { //we need to scatter //extract our vectors from the orientation LTVector vObjRight, vObjUp, vObjForward; rObjRot.GetVectors(vObjRight, vObjUp, vObjForward); //and now generate all of our effects for(uint32 nCurrEffect = 0; nCurrEffect < GetProps()->m_nNumToCreate; nCurrEffect++) { LTRigidTransform tHitTrans; HOBJECT hHitObj; //now build up the forward within a specified cone //first off spin it randomly around the forward float fPlaneAngle = GetRandom(0.0f, MATH_CIRCLE); LTVector vPlaneVector = vObjRight * cosf(fPlaneAngle) + vObjUp * sinf(fPlaneAngle); //now tilt it away from the forward vector float fTiltPercent = powf(GetRandom(0.0f, 1.0f), GetProps()->m_fCenterBias); float fTiltAngle = fTiltPercent * GetProps()->m_fRandomCone; LTVector vRandomForward = vObjForward * cosf(fTiltAngle) + vPlaneVector * sinf(fTiltAngle); if(DetermineIntersection(vObjPos, vRandomForward, hHitObj, tHitTrans)) { CLIENTFX_CREATESTRUCT CreateStruct("", GetProps()->m_nFXFlags, hHitObj, tHitTrans); CBaseCreateFX::CreateEffect(CreateStruct); } } } } //we always return false because we always want to be placed into a shutting down state since //we just emit and then do nothing return false; }
// ----------------------------------------------------------------------- // // // ROUTINE: CTronPlayerObj::GetDefensePercentage() // // PURPOSE: How much of the attack damage has our defenese prevented // // NOTES: There are actually 2 defense percentages. One is based // on timing, i.e. player's reation speed, animation speed, // etc. The other is based on the player's orientation to // the incoming projectile. If the vector parameter is // specified, BOTH percentages will be computed and the // combined result will be returned. If the vector is NOT // specified, only the timing will be computed. // // ----------------------------------------------------------------------- // float CTronPlayerObj::GetDefensePercentage( LTVector const *pIncomingProjectilePosition /*=0*/) const { if ( TRONPLAYEROBJ_NO_DEFEND == m_cDefendType ) { // not blocking return 0.0f; } // // Do this in 2 passes. The first pass willl determine // the contribution to the defense percentage due to the // timing of the player/animations. The second pass // will add the contribution of the player's orientation. // float fDefenseTimingPercentage; float fDefenseOrientationPercentage; // get the weapon AMMO const *pAmmoData = g_pWeaponMgr->GetAmmo( m_cDefendAmmoId ); ASSERT( 0 != pAmmoData ); ASSERT( 0 != pAmmoData->pProjectileFX ); // get the ammo specific data DISCCLASSDATA *pDiscData = dynamic_cast< DISCCLASSDATA* >( pAmmoData->pProjectileFX->pClassData ); ASSERT( 0 != pDiscData ); // // Determine Timing Percentage // switch ( m_cDefendType ) { case MPROJ_START_SWAT_BLOCK: case MPROJ_START_ARM_BLOCK: { // get the current server time float fCurrentServerTime = g_pLTServer->GetTime() * 1000.0f; // make sure we're within the range of the block if ( ( static_cast< int >( fCurrentServerTime ) - m_nDefendServerTimeStarted ) > m_nDefendDuration ) { // nope, the block is over return 0.0f; } // Swat and Arm defenses are similar, so fill out these // variables uniquely (depending on which case we are // handling), then use the common generic math to figure // out the answer. float fMidpointTime; float fMaxStartTime; float fMaxEndTime; float fStartDefendPercentage; float fMaxDefendPercentage; float fEndDefendPercentage; if ( MPROJ_START_SWAT_BLOCK == m_cDefendType ) { // determine at exactly what time the midpoint takes place // NOTE: this is relative time, not absolute fMidpointTime = ( pDiscData->fSwatDefendMidpoint * m_nDefendDuration ); // determine at exactly what time the max starts // NOTE: this is relative time, not absolute fMaxStartTime = fMidpointTime - fMidpointTime * pDiscData->fSwatDefendStartMaxDefendPercentage; // determine at exactly what time the max ends // NOTE: this is relative time, not absolute fMaxEndTime = fMidpointTime + ( ( m_nDefendDuration - fMidpointTime ) * pDiscData->fSwatDefendEndMaxDefendPercentage ); // determine the starting defend percentage fStartDefendPercentage = pDiscData->fSwatDefendStartDefendPercentage; // detecmine the max defend percentage fMaxDefendPercentage = pDiscData->fSwatDefendMaxDefendPercentage; // determine the ending defend percentage fEndDefendPercentage = pDiscData->fSwatDefendEndDefendPercentage; } else if ( MPROJ_START_ARM_BLOCK == m_cDefendType ) { // Not implemented yet. The main question I haven't figured // out yet is where does the information come from? fMidpointTime = 0.0f; fMaxStartTime = 0.0f; fMaxEndTime = 0.0f; fStartDefendPercentage = 0.0f; fMaxDefendPercentage = 0.0f; fEndDefendPercentage = 0.0f; } // determine at exactly how much time we've been in the block // NOTE: this is relative time, not absolute float fBlockTime = fCurrentServerTime - m_nDefendServerTimeStarted; if ( ( -MATH_EPSILON <= fBlockTime ) && ( fBlockTime <= fMaxStartTime ) ) { // somewhere on the uprise fDefenseTimingPercentage = fStartDefendPercentage + ( ( ( fMaxDefendPercentage - fStartDefendPercentage ) / fMaxStartTime ) * fBlockTime ); } else if ( ( fMaxStartTime < fBlockTime ) && ( fBlockTime <= fMaxEndTime ) ) { // within the max range fDefenseTimingPercentage = fMaxDefendPercentage; } else if ( ( fMaxEndTime < fBlockTime ) && ( fBlockTime <= m_nDefendDuration ) ) { // somewhere on the downfall fDefenseTimingPercentage = fMaxDefendPercentage - ( ( ( fMaxDefendPercentage - fEndDefendPercentage ) / ( m_nDefendDuration - fMaxEndTime ) ) * ( fBlockTime - fMaxEndTime ) ); } else { // math problem, we should be here if we are outside // the bounds of the defense ASSERT( 0 ); fDefenseTimingPercentage = 0.0f; } } break; case MPROJ_START_HOLD_BLOCK: { // get the current server time float fCurrentServerTime = g_pLTServer->GetTime() * 1000.0f; // determine the starting defend percentage float fStartDefendPercentage = pDiscData->fHoldDefendStartDefendPercentage; // determine the max defend percentage float fMaxDefendPercentage = pDiscData->fHoldDefendMaxDefendPercentage; // determine at exactly how much time we've been in the block // NOTE: this is relative time, not absolute float fBlockTime = fCurrentServerTime - m_nDefendServerTimeStarted; if ( ( -MATH_EPSILON <= fBlockTime ) && ( fBlockTime <= m_nDefendDuration ) ) { // somewhere on the uprise fDefenseTimingPercentage = fStartDefendPercentage + ( ( ( fMaxDefendPercentage - fStartDefendPercentage ) / static_cast< float >( m_nDefendDuration ) ) * fBlockTime ); } else if ( m_nDefendDuration < fBlockTime ) { // within the max range fDefenseTimingPercentage = fMaxDefendPercentage; } else { // math problem, we should be here if we are outside // the bounds of the defense ASSERT( 0 ); fDefenseTimingPercentage = 0.0f; } } break; case MPROJ_END_HOLD_BLOCK: { // get the current server time float fCurrentServerTime = g_pLTServer->GetTime() * 1000.0f; // make sure we're within the range of the block if ( ( static_cast< int >( fCurrentServerTime ) - m_nDefendServerTimeStarted ) > m_nDefendDuration ) { // nope, the block is over return 0.0f; } // detecmine the max defend percentage float fMaxDefendPercentage = pDiscData->fHoldDefendMaxDefendPercentage; // determine the ending defend percentage float fEndDefendPercentage = pDiscData->fHoldDefendEndDefendPercentage; // determine at exactly how much time we've been in the block // NOTE: this is relative time, not absolute float fBlockTime = fCurrentServerTime - m_nDefendServerTimeStarted; // somewhere on the downfall fDefenseTimingPercentage = fMaxDefendPercentage - ( ( ( fMaxDefendPercentage - fEndDefendPercentage ) / ( m_nDefendDuration ) ) * ( fBlockTime ) ); } break; default: { // There is some type of block defined that we // are not handling, and we SHOULD be handling it. ASSERT( 0 ); return 0.0f; } break; }; //TODO: skip this section of the camera position is too old? // check if the oriention percentage should be computed if ( 0 == pIncomingProjectilePosition ) { // No vector specifed, there is no way // to compute orientation defense. return fDefenseTimingPercentage; } // // Determine Orientation percentage // // The 3 cases are the same, but they could have different // control values. Figure out what the specific variables // are (depending on the specific type of block), then apply // the generic equations. float fOrientationMinDefendPercentage; float fOrientationMaxDefendPercentage; float fOrientationDeadZone; float fOrientationMaxZone; switch ( m_cDefendType ) { case MPROJ_START_SWAT_BLOCK: { fOrientationMinDefendPercentage = pDiscData->fSwatDefendOrientationMinDefendPercentage; fOrientationMaxDefendPercentage = pDiscData->fSwatDefendOrientationMaxDefendPercentage; fOrientationDeadZone = MATH_PI - pDiscData->fSwatDefendOrientationDeadZone; fOrientationMaxZone = pDiscData->fSwatDefendOrientationMaxZone; } break; case MPROJ_START_HOLD_BLOCK: case MPROJ_END_HOLD_BLOCK: { fOrientationMinDefendPercentage = pDiscData->fHoldDefendOrientationMinDefendPercentage; fOrientationMaxDefendPercentage = pDiscData->fHoldDefendOrientationMaxDefendPercentage; fOrientationDeadZone = MATH_PI - pDiscData->fHoldDefendOrientationDeadZone; fOrientationMaxZone = pDiscData->fHoldDefendOrientationMaxZone; } break; case MPROJ_START_ARM_BLOCK: { // Not implemented yet. The main question I haven't figured // out yet is where does the information come from? fOrientationMinDefendPercentage = 0.0f; fOrientationMaxDefendPercentage = 0.0f; fOrientationDeadZone = 0.0f; fOrientationMaxZone = 0.0f; } break; default: { // There is some type of block defined that we // are not handling, and we SHOULD be handling it. ASSERT( 0 ); return 0.0f; } break; }; LTRESULT ltResult; LTVector vDefendPos; LTVector vDefendPosToProjectile; // get the player's position ltResult = g_pLTServer->GetObjectPos( m_hObject, &vDefendPos ); ASSERT( LT_OK == ltResult ); // REMOVE THIS CODE FOR FINAL RELEASE, BUT LEAVE FOR TESTING MULTIPLAYER // print a warning if the time is new enough if ( TRONPLAYEROBJ_CLIENT_CAMERA_TIME_OLD_THRESHOLD < ( g_pLTServer->GetTime() - m_nClientCameraOffsetTimeReceivedMS ) ) { g_pLTServer->CPrint( "Client Camera Offset time is low, possible lag\n" ); g_pLTServer->CPrint( " condition that will affect defensive accuracy.\n" ); g_pLTServer->CPrint( " Currnt value is %5.3f units old.\n", ( g_pLTServer->GetTime() - m_nClientCameraOffsetTimeReceivedMS ) ); } // add the camera offset vDefendPos += m_vClientCameraOffset; // find a unit vector from us to the projectile vDefendPosToProjectile = *pIncomingProjectilePosition - ( m_vClientCameraOffset + vDefendPos ); vDefendPosToProjectile.y = 0; vDefendPosToProjectile.Normalize(); // determine a forward vector reprensenting the direction the // player is facing LTRotation vPlayerViewOrientation; ltResult = g_pLTServer->GetObjectRotation( m_hObject, &vPlayerViewOrientation ); ASSERT( LT_OK == ltResult ); LTVector vPlayerViewForward = vPlayerViewOrientation.Forward(); vPlayerViewForward.y = 0; vPlayerViewForward.Normalize(); float fDotProd = vPlayerViewForward.Dot( vDefendPosToProjectile ); // find the angle between the two vectors float fDefenseAngle = ltacosf( vPlayerViewForward.Dot( vDefendPosToProjectile ) ); if ( ( MATH_EPSILON <= fDefenseAngle) && ( fDefenseAngle <= fOrientationMaxZone ) ) { // it's within the max zone fDefenseOrientationPercentage = fOrientationMaxDefendPercentage; } else if ( ( fOrientationMaxZone < fDefenseAngle) && ( fDefenseAngle <= fOrientationDeadZone ) ) { // it's within the dropoff range fDefenseOrientationPercentage = fOrientationMaxDefendPercentage + ( fDefenseAngle - fOrientationMaxZone ) * ( fOrientationMinDefendPercentage - fOrientationMaxDefendPercentage ) / ( fOrientationDeadZone - fOrientationMaxZone ); } else if ( fOrientationDeadZone <= fDefenseAngle) { // it's within the dead zone fDefenseOrientationPercentage = 0.0f; } // // Final Defense Result // float fFinalDefensePercentage = fDefenseTimingPercentage - fDefenseOrientationPercentage; return fFinalDefensePercentage; }
void CTargetMgr::CheckForIntersect(float &fDistAway) { m_hTarget = LTNULL; m_ActivationData.Init(); uint32 dwUsrFlags = 0; const float fMaxDist = 100000.0f; // Cast ray from the camera to see if there is an object to activate... LTRotation rRot; LTVector vPos; HLOCALOBJ hCamera = g_pPlayerMgr->GetCamera(); g_pLTClient->GetObjectPos(hCamera, &vPos); g_pLTClient->GetObjectRotation(hCamera, &rRot); m_ActivationData.m_vPos = vPos; m_ActivationData.m_rRot = rRot; IntersectQuery IQuery; IntersectInfo IInfo; IQuery.m_From = vPos; IQuery.m_To = IQuery.m_From + (rRot.Forward() * fMaxDist); // NOTE the use of the CHECK_FROM_POINT_INSIDE_OBJECTS flag. This flag will // make sure that any objects that m_From is inside are considered IQuery.m_Flags = CHECK_FROM_POINT_INSIDE_OBJECTS | INTERSECT_HPOLY | INTERSECT_OBJECTS | IGNORE_NONSOLID; IQuery.m_FilterActualIntersectFn = ActivateFilterFn; IQuery.m_pActualIntersectUserData = (void*)&IQuery; IQuery.m_PolyFilterFn = DoVectorPolyFilterFn; // [KLS 8/3/02] - ActivateFilterFn may save an object to use that may not be // the best activation choice (i.e., a fallback choice). However, if a // better choice isn't found, the fallback choice should be used. That // fallback choice is stored in g_adFallbackActivationObject so we clear // it here... g_adFallbackActivationObject.Init(); if (g_pLTClient->IntersectSegment(&IQuery, &IInfo)) { m_ActivationData.m_vIntersect = IInfo.m_Point; if (IsMainWorld(IInfo.m_hObject)) { if (IInfo.m_hPoly != INVALID_HPOLY) { SurfaceType eType = GetSurfaceType(IInfo.m_hPoly); SURFACE *pSurf = g_pSurfaceMgr->GetSurface(eType); // See if the surface we tried to activate has an activation // sound...If so, the user can activate it... if (pSurf && pSurf->szActivationSnd[0] && pSurf->fActivationSndRadius > 0) { m_hTarget = IInfo.m_hObject; m_ActivationData.m_hTarget = m_hTarget; m_ActivationData.m_nSurfaceType = eType; } } } else { LTVector vObjPos = m_ActivationData.m_vIntersect; vObjPos -= vPos; if (vObjPos.Mag() <= fMaxDist) { m_hTarget = IInfo.m_hObject; m_ActivationData.m_hTarget = m_hTarget; } } // Calculate how far away the object is... LTVector vDist = m_ActivationData.m_vIntersect - vPos; fDistAway = vDist.Mag(); } // [KLS 8/3/02] - Use the fallback object if we have one and we didn't // find another object more suitable object... bool bCanUseFallback = (m_ActivationData.m_hTarget ? false : true); if (!bCanUseFallback) { // We can still use the fallback object if it isn't the world or a // world model... if (IsMainWorld(m_ActivationData.m_hTarget) || OT_WORLDMODEL == GetObjectType(m_ActivationData.m_hTarget)) { bCanUseFallback = true; } } if ( bCanUseFallback && g_adFallbackActivationObject.m_hTarget ) { // Ok we hit the fallback object reset some of our target data LTVector vObjPos; g_pLTClient->GetObjectPos(g_adFallbackActivationObject.m_hTarget, &vObjPos); m_ActivationData.m_vIntersect = vObjPos; vObjPos -= vPos; if (vObjPos.Mag() <= fMaxDist) { m_hTarget = g_adFallbackActivationObject.m_hTarget; m_ActivationData.m_hTarget = m_hTarget; } // Calculate how far away the object is... LTVector vDist = m_ActivationData.m_vIntersect - vPos; fDistAway = vDist.Mag(); } }
bool CFallingStuffFX::Update(float tmFrameTime) { // Base class update first m_vLastPos = m_vPos; if (!CBaseFX::Update(tmFrameTime)) return false; //increment our emission time by the elapsed frame time m_tmElapsedEmission += tmFrameTime; if (!IsShuttingDown() && !IsSuspended() && (m_tmElapsedEmission > GetProps()->m_tmFallingStuffFXEmission)) { ObjectCreateStruct ocs; INIT_OBJECTCREATESTRUCT(ocs); LTVector vScale; vScale.Init(m_scale, m_scale, m_scale); LTVector vInterp; LTVector vInterpCur = m_vPos; // Calculate interpolant for particle system if (GetProps()->m_nFallingStuffFXEmission) { vInterp = m_vPos - m_vLastPos; vInterp /= (float)GetProps()->m_nFallingStuffFXEmission; } for (uint32 i = 0; i < GetProps()->m_nFallingStuffFXEmission; i ++) { ocs.m_ObjectType = OT_SPRITE; ocs.m_Flags = FLAG_VISIBLE | FLAG_NOLIGHT | FLAG_ROTATABLESPRITE; // Compute the initial position float xRand = GetProps()->m_fRadius * ((-10000.0f + (rand() % 20000)) / 10000.0f); float zRand = GetProps()->m_fRadius * ((-10000.0f + (rand() % 20000)) / 10000.0f); ocs.m_Pos = m_vPos + (m_vRight * xRand) + (m_vUp * zRand); ocs.m_Scale = vScale; strcpy(ocs.m_Filename, GetProps()->m_sSpriteName); // Move the start point vInterpCur += vInterp; HLOCALOBJ hNewSprite = m_pLTClient->CreateObject(&ocs); if (hNewSprite) { // Create a new sprite FALLING_THING *pNewSprite = debug_new( FALLING_THING ); if (GetProps()->m_nImpactCreate) { if (g_dwSplash > (uint32)GetProps()->m_nImpactCreate) { pNewSprite->m_bSplash = true; g_dwSplash = 0; } else { pNewSprite->m_bSplash = false; } } else { pNewSprite->m_bSplash = false; } g_dwSplash ++; if (pNewSprite) { LTVector v; // Compute the initial velocity v = m_vPlaneDir * GetProps()->m_fVel; pNewSprite->m_hObject = hNewSprite; pNewSprite->m_vVel = v; pNewSprite->m_tmElapsed = 0.0f; pNewSprite->m_vPos = ocs.m_Pos; pNewSprite->m_vLastPos = ocs.m_Pos; m_collSprites.AddTail(pNewSprite); } } } m_tmElapsedEmission = 0.0f; // And store the last position m_vLastPos = m_vPos; } LTMatrix mSpin; if (GetProps()->m_bUseSpin) { // Setup rotation LTMatrix vRight; LTMatrix vUp; LTMatrix vForward; LTMatrix vTmp; Mat_SetupRot(&vRight, &m_vRight, m_xRot); Mat_SetupRot(&vUp, &m_vUp, m_yRot); Mat_SetupRot(&vForward, &m_vPlaneDir, m_zRot); MatMul(&vTmp, &vRight, &vUp); MatMul(&mSpin, &vTmp, &vForward); m_xRot += GetProps()->m_vRotAdd.x * tmFrameTime; m_yRot += GetProps()->m_vRotAdd.y * tmFrameTime; m_zRot += GetProps()->m_vRotAdd.z * tmFrameTime; } // Get the camera rotation LTRotation orient; m_pLTClient->GetObjectRotation(m_hCamera, &orient); LTRotation dRot(orient); LTVector vF = orient.Forward(); float rot = (float)atan2(vF.x, vF.z); // Update the sprites.... CLinkListNode<FALLING_THING *> *pNode = m_collSprites.GetHead(); CLinkListNode<FALLING_THING *> *pDelNode; while (pNode) { pDelNode = NULL; FALLING_THING *pSprite = pNode->m_Data; //adjust our elapsed time pSprite->m_tmElapsed += tmFrameTime; // Check for expiration if (pSprite->m_tmElapsed > GetProps()->m_tmSpriteLifespan) { // Destroy this object m_pLTClient->RemoveObject(pSprite->m_hObject); pDelNode = pNode; } else { // Update !! pSprite->m_vLastPos = pSprite->m_vPos; pSprite->m_vPos += (pSprite->m_vVel * tmFrameTime); // Rotate if neccessary TVector3<float> vPos = pSprite->m_vPos; if (GetProps()->m_bUseSpin) { MatVMul_InPlace(&mSpin, &vPos); } // Add in wind vPos += (GetProps()->m_vWind * GetProps()->m_fWindAmount) * tmFrameTime; // Setup the new sprite position LTVector vPos2 = vPos; m_pLTClient->SetObjectPos(pSprite->m_hObject, &vPos2); // Setup the colour float r, g, b, a; m_pLTClient->GetObjectColor(pSprite->m_hObject, &r, &g, &b, &a); CalcColour(pSprite->m_tmElapsed, GetProps()->m_tmSpriteLifespan, &r, &g, &b, &a); m_pLTClient->SetObjectColor(pSprite->m_hObject, r, g, b, a); // Setup the scale float scale = 0.1f; CalcScale(pSprite->m_tmElapsed, GetProps()->m_tmSpriteLifespan, &scale); LTVector vScale; vScale.Init(scale, scale * GetProps()->m_fStretchMul, scale); m_pLTClient->SetObjectScale(pSprite->m_hObject, &vScale); // Setup the rotation dRot = LTRotation(0, 0, 0, 1); LTRotation orient(dRot); orient.Rotate( orient.Up(), rot ); m_pLTClient->SetObjectRotation(pSprite->m_hObject, &orient); // Check to see if we need to start a splash sprite if (pSprite->m_bSplash) { ClientIntersectQuery ciq; ClientIntersectInfo cii; ciq.m_From = pSprite->m_vLastPos; ciq.m_To = pSprite->m_vPos; if ((GetProps()->m_sImpactSpriteName[0]) && (m_pLTClient->IntersectSegment(&ciq, &cii))) { // Create a splash sprite SPLASH *pSplash = debug_new( SPLASH ); ObjectCreateStruct ocs; INIT_OBJECTCREATESTRUCT(ocs); LTVector vScale; vScale.Init(0.0f, 0.0f, 0.0f); ocs.m_ObjectType = OT_SPRITE; ocs.m_Flags = FLAG_VISIBLE | FLAG_ROTATABLESPRITE | FLAG_NOLIGHT; ocs.m_Pos = cii.m_Point + (cii.m_Plane.m_Normal * 2.0f); ocs.m_Scale = vScale; LTRotation dOrient( cii.m_Plane.m_Normal, LTVector(0.0f, 1.0f, 0.0f) ); strcpy(ocs.m_Filename, GetProps()->m_sImpactSpriteName); pSplash->m_hObject = m_pLTClient->CreateObject(&ocs); pSplash->m_scale = 0.0f; LTRotation orient(dRot); m_pLTClient->SetObjectRotation(pSplash->m_hObject, &orient); pSplash->m_tmElapsed = 0.0f; m_collSplashes.AddTail(pSplash); // Destroy this object m_pLTClient->RemoveObject(pSprite->m_hObject); // Delete the sprite pDelNode = pNode; } } } pNode = pNode->m_pNext; if (pDelNode) m_collSprites.Remove(pDelNode); } // Update our splashes CLinkListNode<SPLASH *> *pSplashNode = m_collSplashes.GetHead(); while (pSplashNode) { CLinkListNode<SPLASH *> *pDelNode = NULL; SPLASH *pSplash = pSplashNode->m_Data; //update the elapsed time on the splash pSplash->m_tmElapsed += tmFrameTime; // Calculate the new scale float scale = GetProps()->m_fImpactScale1 + ((GetProps()->m_fImpactScale2 - GetProps()->m_fImpactScale1) * (pSplash->m_tmElapsed / GetProps()->m_tmImpactLifespan)); LTVector vScale(scale, scale, scale); m_pLTClient->SetObjectScale(pSplash->m_hObject, &vScale); float r, g, b, a; m_pLTClient->GetObjectColor(pSplash->m_hObject, &r, &g, &b, &a); a = (float)(int)(pSplash->m_tmElapsed / GetProps()->m_tmImpactLifespan); if (a < 0.0f) a = 0.0f; if (a > 1.0f) a = 1.0f; m_pLTClient->SetObjectColor(pSplash->m_hObject, r, g, b, a); if (pSplash->m_tmElapsed > GetProps()->m_tmImpactLifespan) { m_pLTClient->RemoveObject(pSplash->m_hObject); pDelNode = pSplashNode; } pSplashNode = pSplashNode->m_pNext; if (pDelNode) m_collSplashes.Remove(pDelNode); } // Success !! return true; }
void CLaserBeam::Update(LTVector &vBeamStartPos, const LTRotation* pRDirRot, LTBOOL b3rdPerson, LTBOOL bDetect) { if (!m_bOn) return; // Calculate beam position... HOBJECT hCamera = g_pPlayerMgr->GetCamera(); if (!hCamera) return; HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject(); if (!hPlayerObj) return; HOBJECT hFilterList[] = {hPlayerObj, g_pPlayerMgr->GetMoveMgr()->GetObject(), LTNULL}; IntersectQuery qInfo; IntersectInfo iInfo; LTVector vPos(0, 0, 0); LTRotation rRot; LTVector vU, vR, vF; if (pRDirRot && b3rdPerson) { vPos = vBeamStartPos; vU = pRDirRot->Up(); vR = pRDirRot->Right(); vF = pRDirRot->Forward(); } else { g_pLTClient->GetObjectRotation(hCamera, &rRot); g_pLTClient->GetObjectPos(hCamera, &vPos); vU = rRot.Up(); vR = rRot.Right(); vF = rRot.Forward(); if (g_cvarLaserBeamDebug.GetFloat() == 0.0f) { vBeamStartPos += vPos; } else if (g_cvarLaserBeamDebug.GetFloat() == 1.0f) { vBeamStartPos = vPos; } else if (pRDirRot) { vU = pRDirRot->Up(); vR = pRDirRot->Right(); vF = pRDirRot->Forward(); vBeamStartPos = vBeamStartPos; } } LTVector vEndPos = vPos + (vF * 10000.0f); qInfo.m_From = vPos; qInfo.m_To = vEndPos; qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; qInfo.m_FilterFn = ObjListFilterFn; qInfo.m_pUserData = hFilterList; if (g_pLTClient->IntersectSegment(&qInfo, &iInfo)) { vEndPos = iInfo.m_Point; } // Show the light beam... LTVector vColor = LTVector(GetRandom(235.0f, 255.0f), GetRandom(35.0f, 55.0f), GetRandom(35.0f, 55.0f));; LTFLOAT fAlpha = g_cvarLaserBeamAlpha.GetFloat(); if (iInfo.m_hObject && bDetect) { uint32 dwUsrFlgs = 0; g_pCommonLT->GetObjectFlags(iInfo.m_hObject, OFT_User, dwUsrFlgs); if (dwUsrFlgs & USRFLG_CHARACTER) { fAlpha = 0.95f; vColor.Init(GetRandom(35.0f, 55.0f), GetRandom(235.0f, 255.0f), GetRandom(35.0f, 55.0f));; } } LTFLOAT fWidth = g_cvarLaserBeamThickness.GetFloat(); fWidth = b3rdPerson ? fWidth*2.0f : fWidth; vBeamStartPos += (vF * g_cvarLaserBeamFOffset.GetFloat()); vBeamStartPos += (vR * g_cvarLaserBeamROffset.GetFloat()); vBeamStartPos += (vU * g_cvarLaserBeamUOffset.GetFloat()); PLFXCREATESTRUCT pls; if (g_cvarLaserBeamDebug.GetFloat() >= 0.0f) { // g_pLTClient->CPrint("StartPos = %.2f, %.2f, %.2f", VEC_EXPAND(vBeamStartPos)); // g_pLTClient->CPrint("EndPos = %.2f, %.2f, %.2f", VEC_EXPAND(vEndPos)); } pls.vStartPos = vBeamStartPos; pls.vEndPos = vEndPos; pls.vInnerColorStart = vColor; pls.vInnerColorEnd = pls.vInnerColorStart; pls.vOuterColorStart = LTVector(0, 0, 0); pls.vOuterColorEnd = LTVector(0, 0, 0); pls.fAlphaStart = fAlpha; pls.fAlphaEnd = fAlpha; pls.fMinWidth = 0; pls.fMaxWidth = fWidth; pls.fMinDistMult = 1.0f; pls.fMaxDistMult = 1.0f; pls.fLifeTime = 1.0f; pls.fAlphaLifeTime = 1.0f; pls.fPerturb = 0.0f; pls.bAdditive = LTTRUE; pls.bAlignFlat = b3rdPerson ? LTFALSE : LTTRUE; pls.nWidthStyle = PLWS_CONSTANT; pls.nNumSegments = (int)g_cvarLaserBeamNumSegments.GetFloat(); if (m_LightBeam.HasBeenDrawn()) { // Keep the light beam in the vis list... m_LightBeam.SetPos(vBeamStartPos); // Hide the beam in portals if 1st person...Also set flag really // close to true... uint32 dwFlags2, dwFlags; dwFlags = m_LightBeam.GetFlags(); dwFlags2 = m_LightBeam.GetFlags2(); if (b3rdPerson) { dwFlags &= ~FLAG_REALLYCLOSE; } else { if (g_cvarLaserBeamDebug.GetFloat() > 1.0f) { dwFlags |= FLAG_REALLYCLOSE; pls.bUseObjectRotation = LTTRUE; } } m_LightBeam.SetFlags(dwFlags); m_LightBeam.SetFlags2(dwFlags2); m_LightBeam.ReInit(&pls); } else { m_LightBeam.Init(&pls); m_LightBeam.CreateObject(g_pLTClient); } m_LightBeam.Update(); }
void CLightningFX::EmitBolts( float tmFrameTime ) { // Make sure enough time between emissions has passed... m_tmElapsedEmission += tmFrameTime; if( m_fDelay < m_tmElapsedEmission ) { LTransform lTrans; LTVector vAttractorPos; ILTModel *pModelLT = m_pLTClient->GetModelLT(); uint32 nActiveBolts = GetRandom( (int)GetProps()->m_nMinNumBolts, (int)GetProps()->m_nMaxNumBolts ); uint32 nBolt; bool bCanUseAttractors = (m_lstAttractors.size() > 0); bool bCanUseRadius = (GetProps()->m_fOmniDirectionalRadius >= 1.0f); CLightningBolt *pBolt = LTNULL; LightningBolts::iterator iter; for( nBolt = 0, iter = m_lstBolts.begin(); iter != m_lstBolts.end(), nBolt < nActiveBolts; ++iter, ++nBolt ) { pBolt = *iter; pBolt->m_fWidth = GetRandom( GetProps()->m_fMinBoltWidth, GetProps()->m_fMaxBoltWidth ); pBolt->m_fLifetime = GetRandom( GetProps()->m_fMinLifetime, GetProps()->m_fMaxLifetime ); pBolt->m_tmElapsed = 0.0f; pBolt->m_bActive = true; // Grab the position of the object to compensate for offset if( m_hTarget ) { m_pLTClient->GetObjectPos( m_hTarget, &vAttractorPos ); } else { vAttractorPos = m_vTargetPos; } // Decide if we should use an attractor or radius for the end pos... if( bCanUseAttractors && (!bCanUseRadius || GetRandom(0,1)) ) { uint8 nIndex = GetRandom( 0, (int)(m_lstAttractors.size()) - 1 ); CAttractor cAttractor = m_lstAttractors[nIndex]; if( cAttractor.GetTransform( lTrans, true ) == LT_OK ) { vAttractorPos = lTrans.m_Pos; } } else if( bCanUseRadius ) { LTVector vRandomPos; vRandomPos.x = GetRandom( -1.0f, 1.0f ); vRandomPos.y = GetRandom( -1.0f, 1.0f ); vRandomPos.z = GetRandom( -1.0f, 1.0f ); vRandomPos.Normalize(); vRandomPos *= GetRandom( -GetProps()->m_fOmniDirectionalRadius, GetProps()->m_fOmniDirectionalRadius ); vAttractorPos = m_vPos + vRandomPos; IntersectQuery iQuery; IntersectInfo iInfo; iQuery.m_From = m_vPos; iQuery.m_To = vAttractorPos; if( m_pLTClient->IntersectSegment( &iQuery, &iInfo )) { vAttractorPos = iInfo.m_Point; } } LTVector vNew = m_vPos; LTVector vDir = vAttractorPos - vNew; float fStep = vDir.Length() / (float)pBolt->m_nNumSegments; float fPerturb = GetRandom( GetProps()->m_fMinPerturb, GetProps()->m_fMaxPerturb ); vDir.Normalize(); LTRotation rRot = LTRotation( vDir, LTVector( 0.0f, 1.0f, 0.0f )); CLinkListNode<PT_TRAIL_SECTION> *pNode = pBolt->m_collPathPts.GetHead(); while( pNode ) { pNode->m_Data.m_vPos = vNew; pNode->m_Data.m_tmElapsed = 0.0f; pNode->m_Data.m_vBisector.Init(); // Add in some perturb going in the direction of the attractor pos for the next section... vNew += (rRot.Forward() * fStep ); vNew += (rRot.Up() * GetRandom( -fPerturb, fPerturb )); vNew += (rRot.Right() * GetRandom( -fPerturb, fPerturb )); // Make sure the last section goes to the end pos... if( !pNode->m_pNext ) pNode->m_Data.m_vPos = vAttractorPos; pNode = pNode->m_pNext; } } // Decide when the next emission will be... m_tmElapsedEmission = 0.0f; m_fDelay = GetRandom( GetProps()->m_fMinDelay, GetProps()->m_fMaxDelay ); } }
bool CPolyTubeFX::Update(float tmFrameTime) { // Base class update first if (!CBaseFX::Update(tmFrameTime)) return false; if ((!m_hTexture) && (!m_bLoadFailed)) { m_pLTClient->GetTexInterface()->CreateTextureFromName(m_hTexture, GetProps()->m_sPath); if (m_hTexture) { // Retrieve texture dims uint32 nHeight; m_pLTClient->GetTexInterface()->GetTextureDims(m_hTexture, m_dwWidth, nHeight); } else { m_bLoadFailed = true; } } if ((m_collPathPts.GetSize() < 2) && IsShuttingDown()) { m_collPathPts.RemoveAll(); return true; } float tmAddPtInterval = GetProps()->m_tmAddPtInterval * 2.0f; LTRotation rRot; m_pLTClient->GetObjectRotation( m_hObject, &rRot ); //increase the emission time elapse m_tmElapsedEmission += tmFrameTime; if (!IsShuttingDown() && (m_collPathPts.GetSize() < GetProps()->m_nMaxTrailLength) && ((m_tmElapsedEmission > GetProps()->m_tmAddPtInterval) || (m_collPathPts.GetSize() == 1))) { LTVector vNew = m_vPos; // Only add the new point if it's not the same as the last one.... // Add a new trail section PT_TRAIL_SECTION ts; ts.m_vPos = vNew; ts.m_tmElapsed = 0.0f; switch( GetProps()->m_eAllignment ) { case ePTA_Up: ts.m_vBisector = rRot.Up(); break; case ePTA_Right: ts.m_vBisector = rRot.Right(); break; case ePTA_Forward: ts.m_vBisector = rRot.Forward(); break; case ePTA_Camera: default: ts.m_vBisector.Init(); break; } // Compute u coordinate if (m_collPathPts.GetSize()) { LTVector vPrev = m_collPathPts.GetTail()->m_Data.m_vPos; float fUPrev = m_collPathPts.GetTail()->m_Data.m_uVal; float fWidth = (float)m_dwWidth; float fScalar = fWidth / GetProps()->m_fTrailWidth; ts.m_uVal = fUPrev + ((((vNew - vPrev).Mag()) / fWidth) * fScalar); } else { ts.m_uVal = 0.0f; } m_collPathPts.AddTail(ts); m_tmElapsedEmission = 0.0f; } // Render the tube.... if (m_collPathPts.GetSize() < 2) return true; CLinkListNode<PT_TRAIL_SECTION> *pNode = m_collPathPts.GetHead(); // Fudge the last point to be the current one... if( !IsShuttingDown() ) m_collPathPts.GetTail()->m_Data.m_vPos = m_vPos; // Transform the path LTMatrix mCam; if( m_bReallyClose || (GetProps()->m_eAllignment != ePTA_Camera)) { mCam.Identity(); } else { mCam = GetCamTransform(m_pLTClient, m_hCamera); } while (pNode) { MatVMul(&pNode->m_Data.m_vTran, &mCam, &pNode->m_Data.m_vPos); pNode = pNode->m_pNext; } // Do some precalculations pNode = m_collPathPts.GetHead(); float fCurU = 0.0f; while (pNode) { pNode->m_Data.m_tmElapsed += tmFrameTime; if( GetProps()->m_eAllignment == ePTA_Camera ) { LTVector vBisector; vBisector.z = 0.0f; // Compute the midpoint vectors if (pNode == m_collPathPts.GetHead()) { LTVector vStart = pNode->m_Data.m_vTran; LTVector vEnd = pNode->m_pNext->m_Data.m_vTran; vBisector.x = vEnd.y - vStart.y; vBisector.y = -(vEnd.x - vStart.x); } else if (pNode == m_collPathPts.GetTail()) { LTVector vEnd = pNode->m_Data.m_vTran; LTVector vStart = pNode->m_pPrev->m_Data.m_vTran; vBisector.x = vEnd.y - vStart.y; vBisector.y = -(vEnd.x - vStart.x); } else { LTVector vPrev = pNode->m_pPrev->m_Data.m_vTran; LTVector vStart = pNode->m_Data.m_vTran; LTVector vEnd = pNode->m_pNext->m_Data.m_vTran; float x1 = vEnd.y - vStart.y; float y1 = -(vEnd.x - vStart.x); float z1 = vStart.z - vEnd.z; float x2 = vStart.y - vPrev.y; float y2 = -(vStart.x - vPrev.x); float z2 = vPrev.z - vEnd.z; vBisector.x = (x1 + x2) / 2.0f; vBisector.y = (y1 + y2) / 2.0f; } pNode->m_Data.m_vBisector = vBisector; } LTFLOAT fWidth = CalcCurWidth(); pNode->m_Data.m_vBisector.Norm( fWidth ); // Setup the colour float r, g, b, a; CalcColour(pNode->m_Data.m_tmElapsed, GetProps()->m_tmSectionLifespan, &r, &g, &b, &a); int ir = (int)(r * 255.0f); int ig = (int)(g * 255.0f); int ib = (int)(b * 255.0f); int ia = (int)(a * 255.0f); pNode->m_Data.m_red = Clamp( ir, 0, 255 ); pNode->m_Data.m_green = Clamp( ig, 0, 255 ); pNode->m_Data.m_blue = Clamp( ib, 0, 255 ); pNode->m_Data.m_alpha = Clamp( ia, 0, 255 ); pNode = pNode->m_pNext; } pNode = m_collPathPts.GetHead(); pNode = m_collPathPts.GetHead(); // Delete any dead nodes while (pNode->m_pNext) { CLinkListNode<PT_TRAIL_SECTION> *pDelNode= NULL; if (pNode->m_Data.m_tmElapsed >= GetProps()->m_tmSectionLifespan) { pDelNode = pNode; } pNode = pNode->m_pNext; if (pDelNode) m_collPathPts.Remove(pDelNode); } // Increment the offset m_uOffset += tmFrameTime * GetProps()->m_uAdd; // Success !! return true; }
void CPolyGridFX::CreateModelWaves(uint32 nKernalSize, uint32 nBuffer, float fFrameTime) { //maximum number of objects to find intersecting the grid static const uint32 knMaxObjToFind = 32; //find the radius of our polygrid float fPolyRad = m_vDims.Mag(); //amount to displace for a model float fDisplaceAmount = m_fModelDisplace * fFrameTime; //just bail if the models aren't going to displace at all if(fDisplaceAmount < 0.01f) return; HLOCALOBJ hFound[knMaxObjToFind]; uint32 nFound = 0; LTVector vPGPos; m_pClientDE->GetObjectPos(m_hObject, &vPGPos); LTVector vPGDims; m_pClientDE->Physics()->GetObjectDims(m_hObject, &vPGDims); //now run through all the characters and see which ones intersect CSpecialFXList* pCharacterList = g_pGameClientShell->GetSFXMgr()->GetFXList(SFX_CHARACTER_ID); LTVector vPGMin = vPGPos - vPGDims; LTVector vPGMax = vPGPos + vPGDims; for(uint32 nCurrChar = 0; nCurrChar < (uint32)pCharacterList->GetNumItems(); nCurrChar++) { if(!(*pCharacterList)[nCurrChar]) continue; //determine the HOBJECT of this character HOBJECT hChar = (*pCharacterList)[nCurrChar]->GetServerObj(); if(!hChar) continue; //get the object position and dimensions LTVector vCharPos, vCharDims; m_pClientDE->GetObjectPos(hChar, &vCharPos); m_pClientDE->Physics()->GetObjectDims(hChar, &vCharDims); LTVector vCharMin = vCharPos - vCharDims; LTVector vCharMax = vCharPos + vCharDims; //if it overlaps, add it to our list if( (vPGMin.x < vCharMax.x) && (vPGMax.x > vCharMin.x) && (vPGMin.y < vCharMax.y) && (vPGMax.y > vCharMin.y) && (vPGMin.z < vCharMax.z) && (vPGMax.z > vCharMin.z)) { //they intersect, add it to the list hFound[nFound] = hChar; nFound++; //see if we need to stop looking for objects if(nFound >= knMaxObjToFind) break; } } //bail if none if(nFound == 0) { //make sure all objects are cleared from the list for(uint32 nCurrRemove = 0; nCurrRemove < MAX_MODELS_TO_TRACK; nCurrRemove++) { m_hTrackedModels[nCurrRemove] = NULL; } return; } //precalc info //find the orienation of the polygrid LTRotation rRot; m_pClientDE->GetObjectRotation(m_hObject, &rRot); //now get the basis vectors of the object space LTVector vRight = rRot.Right(); LTVector vForward = rRot.Forward(); //make sure the polygrid is valid if((m_dwNumPoliesX == 0) || (m_dwNumPoliesY == 0)) return; //find the dimensions of the polygons of the polygrid float fXPolySize = (m_vDims.x * 2.0f) / (float)m_dwNumPoliesX; float fYPolySize = (m_vDims.z * 2.0f) / (float)m_dwNumPoliesY; //bail if not a valid size if((fXPolySize < 0.01f) || (fYPolySize < 0.01f)) return; //flag indicating which tracked models should be kept around bool bTouchedTrackedModels[MAX_MODELS_TO_TRACK]; for(uint32 nCurrTrack = 0; nCurrTrack < MAX_MODELS_TO_TRACK; nCurrTrack++) { bTouchedTrackedModels[nCurrTrack] = false; } //ok, now we run through all the objects we found and update our grid accordingly for(uint32 nCurrObj = 0; nCurrObj < nFound; nCurrObj++) { //the object we are checking HLOCALOBJ hObj = hFound[nCurrObj]; //now lets see if this is a tracked model, if it is, we know where it was last //update and we can create a wave line, otherwise we have no clue, and should //track it for the next update bool bTracked = false; LTVector vPrevPos; LTVector vPos; m_pClientDE->GetObjectPos(hObj, &vPos); //if we aren't currently tracking it, this is where to put it uint32 nInsertPos = MAX_MODELS_TO_TRACK - 1; for(uint32 nCurrModel = 0; nCurrModel < MAX_MODELS_TO_TRACK; nCurrModel++) { if(m_hTrackedModels[nCurrModel] == hObj) { //we found a match, we need to save this value, move //it to the front of the list, and update it vPrevPos = m_vTrackedModelsPos[nCurrModel]; //move all the items back so that this will be in the first slot for(uint32 nCurrMove = nCurrModel; nCurrMove > 0; nCurrMove--) { m_hTrackedModels[nCurrMove] = m_hTrackedModels[nCurrMove - 1]; m_vTrackedModelsPos[nCurrMove] = m_vTrackedModelsPos[nCurrMove - 1]; bTouchedTrackedModels[nCurrMove] = bTouchedTrackedModels[nCurrMove - 1]; } //update the first element m_hTrackedModels[0] = hObj; m_vTrackedModelsPos[0] = vPos; bTouchedTrackedModels[0] = true; //all done bTracked = true; break; } //also bail if one of the slots is NULL if(m_hTrackedModels[nCurrModel] == NULL) { nInsertPos = nCurrModel; } } //see if this was tracked or not if(!bTracked) { //was not! We need to add it to the list m_hTrackedModels[nInsertPos] = hObj; m_vTrackedModelsPos[nInsertPos] = vPos; bTouchedTrackedModels[nInsertPos] = true; continue; } //make sure that the model is actually moving if((vPrevPos - vPos).MagSqr() < 0.5f) continue; //ok, we have a model that intersects our polygrid, let us create some waves //find out the endpoints of the line that will displace float fX1 = vRight.Dot(vPrevPos - vPGPos) + m_vDims.x; float fY1 = vForward.Dot(vPrevPos - vPGPos) + m_vDims.z; float fX2 = vRight.Dot(vPos - vPGPos) + m_vDims.x; float fY2 = vForward.Dot(vPos - vPGPos) + m_vDims.z; //now find the greater delta in polygon units float fXDelta = (float)fabs(fX1 - fX2) / fXPolySize; float fYDelta = (float)fabs(fY1 - fY2) / fYPolySize; //increments for the X and Y directions float fXInc, fYInc; float fCurrX, fCurrY; //the variable to use for threshold comparisons float *pfCompare; //the threshold float fThreshold; //now scan convert accordingly if(fYDelta > fXDelta) { //make sure Y1 is smaller if(fY2 < fY1) { Swap(fY1, fY2); Swap(fX1, fX2); } fYInc = fYPolySize; fXInc = (fX2 - fX1) / (fY2 - fY1) * fYInc; fThreshold = fY2 / fYPolySize; pfCompare = &fCurrY; } else { //make sure Y1 is smaller if(fX2 < fX1) { Swap(fY1, fY2); Swap(fX1, fX2); } fXInc = fXPolySize; fYInc = (fY2 - fY1) / (fX2 - fX1) * fXInc; fThreshold = fX2 / fXPolySize; pfCompare = &fCurrX; } //start out at the first point fCurrY = fY1 / fYPolySize; fCurrX = fX1 / fXPolySize; fXInc /= fXPolySize; fYInc /= fXPolySize; float fXFrac; float fYFrac; uint32 nPrevBuffer = (nBuffer + 1) % 2; //we need to scale the displacement amount by the speed at which we are moving fDisplaceAmount *= (vPrevPos - vPos).Mag() / (fFrameTime * g_cvarPGDisplaceMoveScale.GetFloat()); //now scan convert! while(*pfCompare < fThreshold) { //convert this to an integer position int32 nXPos = (int32)(fCurrX); int32 nYPos = (int32)(fCurrY); //handle clipping if((nXPos >= (int32)nKernalSize) && (nYPos >= (int32)nKernalSize) && (nXPos < (int32)m_dwNumPoliesX - (int32)nKernalSize - 1) && (nYPos < (int32)m_dwNumPoliesY - (int32)nKernalSize - 1)) { fXFrac = fCurrX - nXPos; fYFrac = fCurrY - nYPos; m_WaveBuffer[nBuffer].Get(nXPos, nYPos) += fDisplaceAmount * (1.0f - fXFrac) * (1.0f - fYFrac); m_WaveBuffer[nBuffer].Get(nXPos + 1, nYPos) += fDisplaceAmount * fXFrac * (1.0f - fYFrac); m_WaveBuffer[nBuffer].Get(nXPos, nYPos + 1) += fDisplaceAmount * (1.0f - fXFrac) * fYFrac; m_WaveBuffer[nBuffer].Get(nXPos + 1, nYPos + 1) += fDisplaceAmount * fXFrac * fYFrac; m_WaveBuffer[nPrevBuffer].Get(nXPos, nYPos) += fDisplaceAmount * (1.0f - fXFrac) * (1.0f - fYFrac); m_WaveBuffer[nPrevBuffer].Get(nXPos + 1, nYPos) += fDisplaceAmount * fXFrac * (1.0f - fYFrac); m_WaveBuffer[nPrevBuffer].Get(nXPos, nYPos + 1) += fDisplaceAmount * (1.0f - fXFrac) * fYFrac; m_WaveBuffer[nPrevBuffer].Get(nXPos + 1, nYPos + 1) += fDisplaceAmount * fXFrac * fYFrac; } //move along fCurrX += fXInc; fCurrY += fYInc; } } //now that we are done, clear out any models that were not touched for(uint32 nCurrRemove = 0; nCurrRemove < MAX_MODELS_TO_TRACK; nCurrRemove++) { if(!bTouchedTrackedModels[nCurrRemove]) m_hTrackedModels[nCurrRemove] = NULL; } }
bool CClientWeaponDisc::CalculatePointGuidedTarget( LTVector *pvTargetPoint ) { // // safety check // // params ASSERT( 0 != pvTargetPoint ); // globals ASSERT( 0 != g_pLTClient ); ASSERT( 0 != g_pPlayerMgr ); // // Cast a ray from the camera to determine where // the point guided weapon's target is. // // get the camera HOBJECT hCamera; hCamera = g_pPlayerMgr->GetCamera(); // determine the start point of the segment LTVector vStartPos; g_pLTClient->GetObjectPos( hCamera, &vStartPos ); // determine the orientation of the segment LTRotation rRot; g_pLTClient->GetObjectRotation( hCamera, &rRot ); // determine the direction of the segment LTVector vForward; vForward = rRot.Forward(); // scale the direction to get the distance we're going to check LTVector vDistance; VEC_MULSCALAR( vDistance, vForward, CLIENTWEAPONDISC_PROBE_LENGTH ); // determine the end point of the segment LTVector vEndPos; VEC_ADD( vEndPos, vStartPos, vDistance ); // setup the intersect segment IntersectInfo iInfo; IntersectQuery qInfo; qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY; // DON'T collide with these objects HOBJECT hFilterList[] = { g_pLTClient->GetClientObject() // the player , g_pPlayerMgr->GetMoveMgr()->GetObject() // the player , LTNULL }; // callback function when we hit something // ObjListFilterFn: just filter out objects specified in above list, // otherwise register a hit qInfo.m_FilterFn = ObjListFilterFn; qInfo.m_pUserData = hFilterList; // end points qInfo.m_From = vStartPos; qInfo.m_To = vEndPos; // do the intersect segment LTBOOL bResult; bResult = g_pLTClient->IntersectSegment( &qInfo, &iInfo ); // if we hit something, set the point if ( bResult ) { *pvTargetPoint = iInfo.m_Point; } return ( LTTRUE == bResult ); }
bool CTracerFX::Init(const FX_BASEDATA *pBaseData, const CBaseFXProps *pProps) { //track our performance CTimedSystemBlock TimingBlock(g_tsClientFXTracer); //cleanup any old data Term(); // Perform base class initialisation if( !CBaseFX::Init(pBaseData, pProps)) return false; //determine our starting position and orientation LTVector vPos; LTRotation rRot; GetCurrentTransform(0.0f, vPos, rRot); m_vStartPos = vPos; //determine what target position we want to use LTVector vTargetPos; //if we are using target data, just get the transform from this if(GetProps()->m_bUseTargetPos && pBaseData->m_bUseTargetData) { LTRigidTransform tTargetOffset(pBaseData->m_vTargetOffset, LTRotation::GetIdentity()); LTRigidTransform tWS = GetWorldSpaceTransform(NULL, pBaseData->m_hTargetObject, INVALID_MODEL_NODE, INVALID_MODEL_SOCKET, tTargetOffset); LTVector vToTarget = tWS.m_vPos - vPos; m_fRayLength = vToTarget.Mag(); m_vDirection = vToTarget / m_fRayLength; vTargetPos = tWS.m_vPos; } else { //determine the end point where we want to stop testing m_vDirection = rRot.Forward(); m_fRayLength = GetProps()->m_fMaxDistance; vTargetPos = vPos + m_vDirection * m_fRayLength; } //handle intersection if we need to if(GetProps()->m_bBlockedByGeometry) { //we need to perform a ray cast and determine if we actually hit anything in the world. If not, //we just want to use the maximum tracer length IntersectQuery iQuery; IntersectInfo iInfo; iQuery.m_Flags = INTERSECT_HPOLY | INTERSECT_OBJECTS | IGNORE_NONSOLID; iQuery.m_FilterFn = TracerListFilterFn; iQuery.m_pUserData = NULL; iQuery.m_From = m_vStartPos; iQuery.m_To = vTargetPos; //now find the point of intersection if( g_pLTClient->IntersectSegment( iQuery, &iInfo ) ) { //we hit something, so use that as our ending position m_fRayLength = (iInfo.m_Point - m_vStartPos).Mag(); } } //now determine our starting position (this is zero unless we start emitted, in which case //it is the length of the tracer) if(GetProps()->m_bStartEmitted) { //determine the length of this tracer m_fRayPosition = GetTracerLength(); } // Combine the direction we would like to face with our parents rotation... ObjectCreateStruct ocs; //create a custom render object with the associated material ocs.m_Pos = vPos; ocs.m_Rotation = rRot; ocs.m_ObjectType = OT_CUSTOMRENDER; if(!GetProps()->m_bSolid) ocs.m_Flags2 |= FLAG2_FORCETRANSLUCENT; if(!GetProps()->m_bTranslucentLight) ocs.m_Flags |= FLAG_NOLIGHT; m_hObject = g_pLTClient->CreateObject( &ocs ); if( !m_hObject ) return false; //setup our rendering layer if(GetProps()->m_bPlayerView) g_pLTClient->GetRenderer()->SetObjectDepthBiasTableIndex(m_hObject, eRenderLayer_Player); //setup the callback on the object so that it will render us g_pLTClient->GetCustomRender()->SetRenderingSpace(m_hObject, eRenderSpace_World); g_pLTClient->GetCustomRender()->SetRenderCallback(m_hObject, CustomRenderCallback); g_pLTClient->GetCustomRender()->SetCallbackUserData(m_hObject, this); //load up the material for this particle system, and assign it to the object HMATERIAL hMaterial = g_pLTClient->GetRenderer()->CreateMaterialInstance(GetProps()->m_pszMaterial); g_pLTClient->GetCustomRender()->SetMaterial(m_hObject, hMaterial); g_pLTClient->GetRenderer()->ReleaseMaterialInstance(hMaterial); //we don't setup the visibility for this object yet since when it starts out it is not visible //setup the dynamic light object if the user specified a radius if(GetProps()->m_fLightRadius > 0.1f) { ObjectCreateStruct LightOCS; LightOCS.m_Pos = vPos; LightOCS.m_Rotation = rRot; LightOCS.m_ObjectType = OT_LIGHT; m_hTracerLight = g_pLTClient->CreateObject( &LightOCS ); //setup the properties of the light g_pLTClient->SetLightRadius(m_hTracerLight, GetProps()->m_fLightRadius); g_pLTClient->SetObjectColor(m_hTracerLight, VEC4_EXPAND(GetProps()->m_vLightColor)); g_pLTClient->SetLightType(m_hTracerLight, eEngineLight_Point); g_pLTClient->SetLightDetailSettings(m_hTracerLight, GetProps()->m_eLightLOD, GetProps()->m_eWorldShadowsLOD, GetProps()->m_eObjectShadowsLOD); } // Success !! return true; }
//function that handles the custom rendering void CParticleSystemGroup::RenderParticleSystem(ILTCustomRenderCallback* pInterface, const LTRigidTransform& tCamera) { //track our performance CTimedSystemBlock TimingBlock(g_tsClientFXParticles); //setup our vertex declaration if(pInterface->SetVertexDeclaration(g_ClientFXVertexDecl.GetTexTangentSpaceDecl()) != LT_OK) return; //bind a quad index stream if(pInterface->BindQuadIndexStream() != LT_OK) return; //set the fact that we were visible *m_pVisibleFlag = true; //now determine the largest number of particles that we can render at any time uint32 nMaxParticlesPerBatch = QUAD_RENDER_INDEX_STREAM_SIZE / 6; nMaxParticlesPerBatch = LTMIN(nMaxParticlesPerBatch, DYNAMIC_RENDER_VERTEX_STREAM_SIZE / (sizeof(STexTangentSpaceVert) * 4)); //determine the screen orientation LTRotation rCamera = tCamera.m_rRot; if (m_pProps->m_bObjectSpace) { LTRotation rObjectRotation; g_pLTClient->GetObjectRotation(m_hCustomRender, &rObjectRotation); rCamera = rObjectRotation.Conjugate() * rCamera; } LTVector vUp = rCamera.Up(); LTVector vRight = rCamera.Right(); //create some vectors to offset to each corner (avoids adding for displacement in the inner loop) //Each one can just be scaled by the size of the particle to get the final offset static const float kfHalfRoot2 = 0.5f * MATH_SQRT2; //premultiplied versions of up and right scaled by half the square root of two LTVector vUpHalfRoot2 = vUp * kfHalfRoot2; LTVector vRightHalfRoot2 = vRight * kfHalfRoot2; //precalculate the diagonals for non-rotating particles since these are constant LTVector vDiagonals[4]; vDiagonals[0] = vUpHalfRoot2 - vRightHalfRoot2; vDiagonals[1] = vUpHalfRoot2 + vRightHalfRoot2; vDiagonals[2] = -vUpHalfRoot2 + vRightHalfRoot2; vDiagonals[3] = -vUpHalfRoot2 - vRightHalfRoot2; uint32 nNumParticlesLeft = m_Particles.GetNumParticles(); //precalculate some data for the basis space of the particles LTVector vNormal = -rCamera.Forward(); LTVector vTangent = vRight; LTVector vBinormal = -vUp; //the U scale for particle images float fUImageWidth = 1.0f / (float)m_pProps->m_nNumImages; //variables used within the inner loop float fSize; uint32 nColor; //now run through all the particles and render CParticleIterator itParticles = m_Particles.GetIterator(); while(nNumParticlesLeft > 0) { //determine our batch size uint32 nBatchSize = LTMIN(nNumParticlesLeft, nMaxParticlesPerBatch); //lock down our buffer for rendering SDynamicVertexBufferLockRequest LockRequest; if(pInterface->LockDynamicVertexBuffer(nBatchSize * 4, LockRequest) != LT_OK) return; //fill in a batch of particles STexTangentSpaceVert* pCurrOut = (STexTangentSpaceVert*)LockRequest.m_pData; if(m_pProps->m_bRotate) { //we need to render the particles rotated for(uint32 nBatchParticle = 0; nBatchParticle < nBatchSize; nBatchParticle++) { //sanity check LTASSERT(!itParticles.IsDone(), "Error: Particle count and iterator mismatch"); //get the particle from the iterator SParticle* pParticle = (SParticle*)itParticles.GetParticle(); GetParticleSizeAndColor(pParticle, nColor, fSize); //determine the sin and cosine of this particle angle float fAngle = pParticle->m_fAngle; float fSinAngle = LTSin(fAngle); float fCosAngle = LTCos(fAngle); LTVector vRotRight = (vRightHalfRoot2 * fCosAngle + vUpHalfRoot2 * fSinAngle) * fSize; LTVector vRotUp = vNormal.Cross(vRotRight); LTVector vRotTangent = vTangent * fCosAngle + vBinormal * fSinAngle; LTVector vRotBinormal = vTangent * fSinAngle + vBinormal * fCosAngle; SetupParticle( pCurrOut, pParticle->m_Pos + vRotUp - vRotRight, pParticle->m_Pos + vRotUp + vRotRight, pParticle->m_Pos - vRotUp + vRotRight, pParticle->m_Pos - vRotUp - vRotRight, nColor, vNormal, vRotTangent, vRotBinormal, pParticle->m_nUserData & PARTICLE_IMAGE_MASK, fUImageWidth); //move onto the next set of particles pCurrOut += 4; //move onto the next particle for processing itParticles.Next(); } } else if (m_pProps->m_bStreak) { //the particles are non-rotated but streaked along their velocity for(uint32 nBatchParticle = 0; nBatchParticle < nBatchSize; nBatchParticle++) { //sanity check LTASSERT(!itParticles.IsDone(), "Error: Particle count and iterator mismatch"); //get the particle from the iterator SParticle* pParticle = (SParticle*)itParticles.GetParticle(); GetParticleSizeAndColor(pParticle, nColor, fSize); //in order to render the streak, we determine a line that passes through //the particle and runs in the direction of the velocity of the particle //we need to project the velocity onto the screen LTVector2 vScreen; vScreen.x = -(pParticle->m_Velocity.Dot(vRight)); vScreen.y = -(pParticle->m_Velocity.Dot(vUp)); //we know that the up and right vectors are normalized, so we can save some work by //just doing a 2d normalization float fMag = vScreen.Mag(); if(fMag == 0.0f) vScreen.Init(fSize, 0.0f); else vScreen *= fSize / fMag; //determine our actual screen space velocity LTVector vScreenRight = vUp * vScreen.y + vRight * vScreen.x; LTVector vScreenUp = vUp * -vScreen.x + vRight * vScreen.y; //and now compute the endpoint of the streak LTVector vEndPos = pParticle->m_Pos - pParticle->m_Velocity * m_pProps->m_fStreakScale; SetupParticle( pCurrOut, pParticle->m_Pos - vScreenRight - vScreenUp, vEndPos + vScreenRight - vScreenUp, vEndPos + vScreenRight + vScreenUp, pParticle->m_Pos - vScreenRight + vScreenUp, nColor, vNormal, vScreenRight, vScreenUp, pParticle->m_nUserData & PARTICLE_IMAGE_MASK, fUImageWidth); //move onto the next set of particles pCurrOut += 4; //move onto the next particle for processing itParticles.Next(); } } else { //the particles are non-rotated for(uint32 nBatchParticle = 0; nBatchParticle < nBatchSize; nBatchParticle++) { //sanity check LTASSERT(!itParticles.IsDone(), "Error: Particle count and iterator mismatch"); //get the particle from the iterator SParticle* pParticle = (SParticle*)itParticles.GetParticle(); GetParticleSizeAndColor(pParticle, nColor, fSize); SetupParticle( pCurrOut, pParticle->m_Pos + vDiagonals[0] * fSize, pParticle->m_Pos + vDiagonals[1] * fSize, pParticle->m_Pos + vDiagonals[2] * fSize, pParticle->m_Pos + vDiagonals[3] * fSize, nColor, vNormal, vTangent, vBinormal, pParticle->m_nUserData & PARTICLE_IMAGE_MASK, fUImageWidth); //move onto the next set of particles pCurrOut += 4; //move onto the next particle for processing itParticles.Next(); } } //unlock and render the batch pInterface->UnlockAndBindDynamicVertexBuffer(LockRequest); pInterface->RenderIndexed( eCustomRenderPrimType_TriangleList, 0, nBatchSize * 6, LockRequest.m_nStartIndex, 0, nBatchSize * 4); nNumParticlesLeft -= nBatchSize; } }
LTBOOL CProjectileFX::CreateObject(ILTClient* pClientDE) { if (!CSpecialFX::CreateObject(pClientDE) || !m_hServerObject) return LTFALSE; CGameSettings* pSettings = g_pInterfaceMgr->GetSettings(); if (!pSettings) return LTFALSE; uint8 nDetailLevel = pSettings->SpecialFXSetting(); LTVector vPos; LTRotation rRot; g_pLTClient->GetObjectPos(m_hServerObject, &vPos); g_pLTClient->GetObjectRotation(m_hServerObject, &rRot); //m_pClientDE->CPrint("Client start pos (%.2f, %.2f, %.2f)", vPos.x, vPos.y, vPos.z); //m_fStartTime = m_pClientDE->GetTime(); if (nDetailLevel != RS_LOW) { if (m_nFX & PFX_SMOKETRAIL) { CreateSmokeTrail(vPos, rRot); } if (m_nFX & PFX_LIGHT) { CreateLight(vPos, rRot); } } if (m_nFX & PFX_FLARE) { CreateFlare(vPos, rRot); } if (m_nFX & PFX_FLYSOUND) { CreateFlyingSound(vPos, rRot); } // Do client-side projectiles in multiplayer games... if ( g_pClientMultiplayerMgr->IsConnectedToRemoteServer( )) { // Set the velocity of the "server" object if it is really just a local // object... if (m_bLocal) { VEC_COPY(m_vFirePos, vPos); m_fStartTime = m_pClientDE->GetTime(); LTVector vVel, vF; vF = rRot.Forward(); m_vPath = vF; // Special case of adjusting the projectile speed... LTFLOAT fVel = (LTFLOAT) m_pProjectileFX->nVelocity; if (m_bAltFire) { fVel = (LTFLOAT) m_pProjectileFX->nAltVelocity; } LTFLOAT fMultiplier = 1.0f; if (m_pClientDE->GetSConValueFloat("MissileSpeed", fMultiplier) != LT_NOTFOUND) { fVel *= fMultiplier; } vVel = vF * fVel; g_pPhysicsLT->SetVelocity(m_hServerObject, &vVel); } } return LTTRUE; }
void DebugLineSystem::AddOrientation( const LTVector& vCenter, const LTRotation& rRot, float fLength, uint8 nAlpha) { AddArrow(vCenter, vCenter + rRot.Right() * fLength, Color::Red, nAlpha); AddArrow(vCenter, vCenter + rRot.Up() * fLength, Color::Green, nAlpha); AddArrow(vCenter, vCenter + rRot.Forward() * fLength, Color::Blue, nAlpha); }
void CLTMessage_Write::WriteYRotation(CPacket_Write &cPacket, const LTRotation &cRotation) { LTVector forward = cRotation.Forward(); float fAngle = (float)atan2(forward.x, forward.z); cPacket.Writeint8((int8)(fAngle * (127.0f / MATH_PI))); }
void CFlashLightPlayer::GetLightPositions(LTVector& vStartPos, LTVector& vEndPos, LTVector& vUOffset, LTVector& vROffset) { vStartPos.Init(); vEndPos.Init(); vUOffset.Init(); vROffset.Init(); CMoveMgr* pMoveMgr = g_pPlayerMgr->GetMoveMgr(); if (!pMoveMgr) return; LTRotation rRot; if (pMoveMgr->GetVehicleMgr()->IsVehiclePhysics()) { if (g_pPlayerMgr->IsFirstPerson()) { pMoveMgr->GetVehicleMgr()->GetVehicleLightPosRot(vStartPos, rRot); } else // 3rd person vehicle { // Get light pos on 3rd-person vehicle... HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject(); if (hPlayerObj) { g_pLTClient->GetObjectRotation(hPlayerObj, &rRot); g_pLTClient->GetObjectPos(hPlayerObj, &vStartPos); } } } else if (g_pPlayerMgr->IsFirstPerson()) { HOBJECT hCamera = g_pPlayerMgr->GetCamera(); if (!hCamera) return; g_pLTClient->GetObjectRotation(hCamera, &rRot); g_pLTClient->GetObjectPos(hCamera, &vStartPos); } else // 3rd person { // Get light pos from 3rd-person model... HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject(); if (hPlayerObj) { // g_pLTClient->GetObjectRotation(hPlayerObj, &rRot); // g_pLTClient->GetObjectPos(hPlayerObj, &vStartPos); HMODELSOCKET hSocket; if ( LT_OK == g_pModelLT->GetSocket(hPlayerObj, "LeftHand", hSocket) ) { LTransform tf; if ( LT_OK == g_pModelLT->GetSocketTransform(hPlayerObj, hSocket, tf, LTTRUE) ) { vStartPos = tf.m_Pos; rRot = tf.m_Rot; } } } } vEndPos = vStartPos + (rRot.Forward() * g_cvarFLLightOffsetForward.GetFloat()); if (g_pPlayerMgr->IsFirstPerson()) { vROffset = (rRot.Right() * g_cvarFLLightOffsetRight.GetFloat()); vUOffset = (rRot.Up() * g_cvarFLLightOffsetUp.GetFloat()); // Update the Start/End position to addjust for any offset... vEndPos += vROffset; vEndPos += vUOffset; vStartPos += vROffset; vStartPos += vUOffset; } }