//given a capsule specified with a transform, two points, and a radius, this will approximate how much is submerged //and distribute that force to the appropriate points on the capsule static bool ApplyCapsuleBuoyancy(const LTVector& vPt1, const LTVector& vPt2, float fLength, float fRadius, const LTPlane& WSPlane, float& fVolume, LTVector& vApplyAt, float& fSurfaceArea) { //convert the capsule to an OBB and apply it //determine information about the main axis LTVector vMainAxis = vPt2 - vPt1; LTASSERT( fLength > 0.0f, "Invalid capsule length." ); LTVector vUnitAxis = vMainAxis / fLength; //we can now build up a rotation given the plane normal and the axis to build our transform LTVector vUp = WSPlane.Normal(); if(fabsf(vUp.Dot(vUnitAxis)) > 0.99f) { //too close to use, built an arbitrary orthonormal vUp = vUnitAxis.BuildOrthonormal(); } LTMatrix3x4 mTemp; LTVector vRight = vUnitAxis.Cross(vUp); vRight.Normalize( ); LTVector vTrueUp = vRight.Cross( vUnitAxis ); mTemp.SetBasisVectors(vRight, vTrueUp, vUnitAxis); LTRotation rRot; rRot.ConvertFromMatrix(mTemp); //now we can form our transform LTRigidTransform tTransform((vPt1 + vPt2) * 0.5f, rRot); LTVector vHalfDims(fRadius, fRadius, fLength * 0.5f + fRadius); return ApplyOBBBuoyancy(tTransform, vHalfDims, WSPlane, fVolume, vApplyAt, fSurfaceArea); }
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; }
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 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); }
void GameBase::CreateBoundingBox() { if (m_hDimsBox) return; if (!g_vtDimsAlpha.IsInitted()) { g_vtDimsAlpha.Init(g_pLTServer, "DimsAlpha", LTNULL, 1.0f); } ObjectCreateStruct theStruct; INIT_OBJECTCREATESTRUCT(theStruct); LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); theStruct.m_Pos = vPos; SAFE_STRCPY(theStruct.m_Filename, "Models\\1x1_square.abc"); SAFE_STRCPY(theStruct.m_SkinName, "Models\\1x1_square.dtx"); theStruct.m_Flags = FLAG_VISIBLE | FLAG_NOLIGHT | FLAG_GOTHRUWORLD; theStruct.m_ObjectType = OT_MODEL; HCLASS hClass = g_pLTServer->GetClass("BaseClass"); LPBASECLASS pModel = g_pLTServer->CreateObject(hClass, &theStruct); if (pModel) { m_hDimsBox = pModel->m_hObject; LTVector vDims; g_pLTServer->GetObjectDims(m_hObject, &vDims); LTVector vScale; VEC_DIVSCALAR(vScale, vDims, 0.5f); g_pLTServer->ScaleObject(m_hDimsBox, &vScale); } LTVector vOffset; LTRotation rOffset; vOffset.Init(); rOffset.Init(); HATTACHMENT hAttachment; LTRESULT dRes = g_pLTServer->CreateAttachment(m_hObject, m_hDimsBox, LTNULL, &vOffset, &rOffset, &hAttachment); if (dRes != LT_OK) { g_pLTServer->RemoveObject(m_hDimsBox); m_hDimsBox = LTNULL; } LTVector vColor = GetBoundingBoxColor(); g_pLTServer->SetObjectColor(m_hDimsBox, vColor.x, vColor.y, vColor.z, g_vtDimsAlpha.GetFloat()); }
bool WorldModel::AttachServerMark( CServerMark& mark, CLIENTWEAPONFX & theStruct) { LTransform globalTransform, parentTransform, localTransform; ILTTransform *pTransformLT; LTVector vParentPos, vOffset; LTRotation rParentRot, rRot; LTRotation rOffset; pTransformLT = g_pLTServer->GetTransformLT(); // Attach the mark to the parent object... // Figure out what the rotation we want is. rOffset.Init(); rRot = LTRotation(theStruct.vSurfaceNormal, LTVector(0.0f, 1.0f, 0.0f)); // MD // Ok, now we have the transform in global space but attachments are specified in // local space (so they can move as the object moves and rotates). // Set the global LTransform. pTransformLT->Set(globalTransform, theStruct.vPos, rRot); // Get the object's transform. g_pLTServer->GetObjectPos( m_hObject, &vParentPos); g_pLTServer->GetObjectRotation( m_hObject, &rParentRot); parentTransform.m_Pos = vParentPos; parentTransform.m_Rot = rParentRot; parentTransform.m_Scale.Init(1,1,1); globalTransform.m_Scale.Init(1,1,1); // Get the offset. pTransformLT->Difference(localTransform, globalTransform, parentTransform); vOffset = localTransform.m_Pos; rOffset = localTransform.m_Rot; HATTACHMENT hAttachment = NULL; LTRESULT dRes = g_pLTServer->CreateAttachment( m_hObject, mark.m_hObject, LTNULL, &vOffset, &rOffset, &hAttachment); if (dRes != LT_OK) { return false; } // Add to the attachment list. LTObjRefNotifier ref( *this ); ref = mark.m_hObject; m_AttachmentList.push_back( ref ); return true; }
void CCoin::RotateToRest() { if ( !m_bRotatedToRest ) { char szSpawn[1024]; sprintf(szSpawn, "WeaponItem Gravity 0;AmmoAmount 1;WeaponType Coin;AmmoType Coin"); LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); vPos.y += 2.0f; // This offsets us from the floor a bit so we don't pop through when WeaponItem sets its dims. LTRotation rRot; rRot.Init(); BaseClass* pObj = SpawnObject(szSpawn, vPos, rRot); if ( pObj && pObj->m_hObject ) { g_pLTServer->SetAcceleration(pObj->m_hObject, <Vector(0,0,0)); g_pLTServer->SetVelocity(pObj->m_hObject, <Vector(0,0,0)); } g_pLTServer->SetObjectFlags(m_hObject, g_pLTServer->GetObjectFlags(m_hObject)&~FLAG_VISIBLE); } CGrenade::RotateToRest(); if ( IsCharacter(m_hFiredFrom) ) { LTVector vPosition; g_pLTServer->GetObjectPos(m_hObject, &vPosition); CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(m_hFiredFrom); CharCoinInfo cinfo; cinfo.fTime = g_pLTServer->GetTime(); cinfo.eSurfaceType = m_eLastHitSurface; cinfo.vPosition = vPosition; SURFACE* pSurf = g_pSurfaceMgr->GetSurface(m_eLastHitSurface); _ASSERT(pSurf); if (pSurf) { cinfo.fVolume = pSurf->fMovementNoiseModifier; } else { cinfo.fVolume = 1.0f; } pCharacter->SetLastCoinInfo(&cinfo); } }
LTBOOL CBaseParticleSystemFX::CreateObject(ILTClient *pClientDE) { if (!CSpecialFX::CreateObject(pClientDE)) return LTFALSE; LTVector vPos = m_vPos; LTRotation rRot; rRot.Init(); // Use server object position if a position wasn't specified... if (m_hServerObject) { LTVector vZero(0, 0, 0), vServObjPos; if (vPos.Equals(vZero)) { pClientDE->GetObjectPos(m_hServerObject, &vServObjPos); vPos = vServObjPos; } else { m_basecs.bClientControlsPos = LTTRUE; } // Calculate our offset from the server object... m_vPosOffset = vPos - vServObjPos; } // Use the specified rotation if applicable if (!m_rRot.IsIdentity()) { rRot = m_rRot; } ObjectCreateStruct createStruct; INIT_OBJECTCREATESTRUCT(createStruct); createStruct.m_ObjectType = OT_PARTICLESYSTEM; createStruct.m_Flags = FLAG_VISIBLE | FLAG_UPDATEUNSEEN | FLAG_FOGDISABLE; createStruct.m_Pos = vPos; createStruct.m_Rotation = rRot; m_hObject = m_pClientDE->CreateObject(&createStruct); // Setup the ParticleSystem... return SetupSystem(); }
void CMuzzleFlashFX::SetRot(LTRotation rRot) { if (!m_pClientDE) return; HOBJECT hObj; if (m_bUsingParticles) { hObj = m_Particle.GetObject(); if (hObj) { if (g_vtReallyClose.GetFloat()) { LTRotation rInitRot; rInitRot.Init(); m_pClientDE->SetObjectRotation(hObj, &rInitRot); } else { m_pClientDE->SetObjectRotation(hObj, &rRot); } } } if (m_bUsingLight) { hObj = m_Light.GetObject(); if (hObj) { m_pClientDE->SetObjectRotation(hObj, &rRot); } } if (m_bUsingScale) { hObj = m_Scale.GetObject(); if (hObj) { LTRotation rTempRot = rRot; // Camera relative rotation... if (m_cs.bPlayerView) { rTempRot.Init(); } m_pClientDE->SetObjectRotation(hObj, &rTempRot); } } }
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; }
void SecurityCamera::CreateLight() { // Create the light...and attach it to the camera... ObjectCreateStruct theStruct; INIT_OBJECTCREATESTRUCT(theStruct); theStruct.m_Pos = m_vPos; g_pServerButeMgr->GetSecurityCameraString("GreenLight", theStruct.m_Filename, ARRAY_LEN(theStruct.m_Filename)); theStruct.m_Flags = FLAG_VISIBLE | FLAG_GLOWSPRITE; theStruct.m_Flags2 = FLAG2_ADDITIVE; theStruct.m_ObjectType = OT_SPRITE; HCLASS hClass = g_pLTServer->GetClass("BaseClass"); LPBASECLASS pSprite = g_pLTServer->CreateObject(hClass, &theStruct); if (!pSprite) return; m_hLight = pSprite->m_hObject; LTVector vScale(1, 1, 1); vScale.x = g_pServerButeMgr->GetSecurityCameraFloat("LightScale"); vScale.y = vScale.x; g_pLTServer->ScaleObject(m_hLight, &vScale); // Attach the sprite to the the camera... LTVector vOffset(0, 0, 0); LTRotation rOffset; rOffset.Init(); HATTACHMENT hAttachment; LTRESULT dRes = g_pLTServer->CreateAttachment(m_hObject, m_hLight, "Light", &vOffset, &rOffset, &hAttachment); if (dRes != LT_OK) { g_pLTServer->RemoveObject(m_hLight); m_hLight = LTNULL; return; } }
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; } } }
LTBOOL CPickupItemFX::Update() { if (!m_pClientDE || m_bWantRemove || !m_hServerObject) return LTFALSE; LTFLOAT fDeltaTime = g_pGameClientShell->GetFrameTime(); if (m_bRotate) { LTRotation rRot; g_pLTClient->GetObjectRotation(m_hServerObject, &rRot); rRot.Rotate(rRot.Up(), PICKUPITEM_ROTVEL * fDeltaTime); g_pLTClient->SetObjectRotation(m_hServerObject, &rRot); } if (m_bBounce) { } // If we have a ClientFX that is playing hide or show it based on the serverobject... if( m_linkClientFX.IsValid() ) { uint32 dwFlags; g_pCommonLT->GetObjectFlags( m_hServerObject, OFT_Flags, dwFlags ); if( dwFlags & FLAG_VISIBLE ) { m_linkClientFX.GetInstance()->Show(); } else { m_linkClientFX.GetInstance()->Hide(); } } return LTTRUE; }
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; }
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; }
void CNodeController::UpdateScriptControl(NCSTRUCT *pNodeControl) { LTFLOAT fTime = g_pLTClient->GetTime() - pNodeControl->fScriptTime; ModelNScript eScript = (ModelNScript)pNodeControl->nScript; int nCurPt = pNodeControl->nCurrentScriptPt; int nLastPt = pNodeControl->nLastScriptPt; // g_pLTClient->CPrint("Running node script!"); // Check to see if the script is over... and make it invalid if so if(fTime > g_pModelButeMgr->GetNScriptPtTime(eScript, nLastPt)) { // g_pLTClient->CPrint("Ending node script!"); pNodeControl->bValid = LTFALSE; return; } // Get access to the controls... ILTMath *pMathLT = g_pLTClient->GetMathLT(); // Get the current script point while(fTime > g_pModelButeMgr->GetNScriptPtTime(eScript, nCurPt)) nCurPt++; // Calculate the scale value from the last position to the current LTFLOAT fPtTime1 = g_pModelButeMgr->GetNScriptPtTime(eScript, nCurPt - 1); LTFLOAT fPtTime2 = g_pModelButeMgr->GetNScriptPtTime(eScript, nCurPt); LTFLOAT fScale = (fTime - fPtTime1) / (fPtTime2 - fPtTime1); //---------------------------------------------------------------------------- // Setup the initial position vector LTVector vPos; // Get a direction vector from the last position to the current LTVector vPosDir = g_pModelButeMgr->GetNScriptPtPosOffset(eScript, nCurPt) - g_pModelButeMgr->GetNScriptPtPosOffset(eScript, nCurPt - 1); VEC_MULSCALAR(vPosDir, vPosDir, fScale); vPos = g_pModelButeMgr->GetNScriptPtPosOffset(eScript, nCurPt - 1) + vPosDir; //---------------------------------------------------------------------------- // Setup the initial rotation vector LTVector vRot; // Get a direction rotation from the last position to the current LTVector vRotDir = g_pModelButeMgr->GetNScriptPtRotOffset(eScript, nCurPt) - g_pModelButeMgr->GetNScriptPtRotOffset(eScript, nCurPt - 1); VEC_MULSCALAR(vRotDir, vRotDir, fScale); vRot = g_pModelButeMgr->GetNScriptPtRotOffset(eScript, nCurPt - 1) + vRotDir; // Calculate the rotation... LTRotation rRot; LTVector vR, vU, vF; rRot.Init(); pMathLT->GetRotationVectors(rRot, vR, vU, vF); pMathLT->RotateAroundAxis(rRot, vR, vRot.x); pMathLT->RotateAroundAxis(rRot, vU, vRot.y); pMathLT->RotateAroundAxis(rRot, vF, vRot.z); //---------------------------------------------------------------------------- // Setup the matrix using the offset position and rotation LTMatrix m1; pMathLT->SetupTransformationMatrix(m1, vPos, rRot); m_aNodes[pNodeControl->eModelNode].matTransform = m_aNodes[pNodeControl->eModelNode].matTransform * m1; }
void CNodeController::UpdateLipSyncControl(NCSTRUCT *pNodeControl) { // Make sure the sound handle is valid and check to see if the sound is done... if(!pNodeControl->hLipSyncSound || g_pLTClient->IsDone(pNodeControl->hLipSyncSound)) { g_pLTClient->KillSound(pNodeControl->hLipSyncSound); pNodeControl->hLipSyncSound = LTNULL; if (pNodeControl->bShowingSubtitles) { g_pInterfaceMgr->ClearSubtitle(); } pNodeControl->pSixteenBitBuffer = LTNULL; pNodeControl->pEightBitBuffer = LTNULL; pNodeControl->bValid = LTFALSE; return; } // // Process the current sound data (average over sound amplitude). // LTFLOAT fAverage = 0.0f; // this will hold the average, normalized from 0.0f to 1.0f. // Get the sound buffer. if( !pNodeControl->pSixteenBitBuffer && !pNodeControl->pEightBitBuffer ) { uint32 dwChannels = 0; g_pLTClient->GetSoundData(pNodeControl->hLipSyncSound, pNodeControl->pSixteenBitBuffer, pNodeControl->pEightBitBuffer, &pNodeControl->dwSamplesPerSecond, &dwChannels); ASSERT( dwChannels == 1); // If you want to use multi-channel sounds (why would you?), you'll need to // to account for the interleaving of channels in the following code. } ASSERT( pNodeControl->pSixteenBitBuffer || pNodeControl->pEightBitBuffer ); // Average over the data. We do an average of the data from the current point // being played to 1/g_vtLipSyncFreq.GetFloat() seconds ahead of that point. uint32 dwOffset = 0; uint32 dwSize = 0; if( LT_OK == g_pLTClient->GetSoundOffset(pNodeControl->hLipSyncSound, &dwOffset, &dwSize) ) { // Determine the end of the data we wish to average over. const uint32 dwDivisor = uint32(g_vtLipSyncFreq.GetFloat()); uint32 dwOffsetEnd = dwOffset + pNodeControl->dwSamplesPerSecond/dwDivisor; if( dwOffsetEnd > dwSize ) dwOffsetEnd = dwSize; // Accumulate the the amplitudes for the average. uint32 dwMaxAmplitude = 0; uint32 dwNumSamples = 0; uint32 dwAccum = 0; if( pNodeControl->pSixteenBitBuffer ) { for( int16 * pIterator = pNodeControl->pSixteenBitBuffer + dwOffset; pIterator < pNodeControl->pSixteenBitBuffer + dwOffsetEnd; ++pIterator) { dwAccum += abs(*pIterator); ++dwNumSamples; } dwMaxAmplitude = 65536/2; #ifdef GRAPH_LIPSYNC_SOUND g_GraphPoints.RecordData(pNodeControl->pSixteenBitBuffer,dwSize,dwOffset); #endif } else if( pNodeControl->pEightBitBuffer ) { for( int8 * pIterator = pNodeControl->pEightBitBuffer + dwOffset; pIterator < pNodeControl->pEightBitBuffer + dwOffsetEnd; ++pIterator) { dwAccum += abs(*pIterator); ++dwNumSamples; } dwMaxAmplitude = 256/2; #ifdef GRAPH_LIPSYNC_SOUND g_GraphPoints.RecordData(pNodeControl->pEightBitBuffer,dwSize,dwOffset); #endif } // And find the average! if( dwNumSamples > 0 ) fAverage = LTFLOAT(dwAccum) / LTFLOAT(dwNumSamples) / LTFLOAT(dwMaxAmplitude); } //if( LT_OK == g_pLTClient->GetSoundOffset(pNodeControl->hLipSyncSound, &dwOffset, &dwSize) ) // // Do the rotation. // ILTMath *pMathLT = g_pLTClient->GetMathLT(); LTRotation rRot; rRot.Init(); LTVector vAxis(0.0f, 0.0f, 1.0f); LTFLOAT fMaxRot = MATH_DEGREES_TO_RADIANS(g_vtLipSyncMaxRot.GetFloat()); // Calculate the rotation. m_fCurLipSyncRot = fAverage*fMaxRot; pMathLT->RotateAroundAxis(rRot, vAxis, -m_fCurLipSyncRot); // Create a rotation matrix and apply it to the current offset matrix LTMatrix m1; pMathLT->SetupRotationMatrix(m1, rRot); m_aNodes[pNodeControl->eModelNode].matTransform = m_aNodes[pNodeControl->eModelNode].matTransform * m1; }
// ----------------------------------------------------------------------- // // // 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 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 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; }
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(); } }
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; } }