DBOOL UpdateMovingObject(PhysicsState *pUserState, MovingObject *pObject, DVector *pNewPos) { if (!pObject || !pNewPos) return DFALSE; PhysicsState* pState = pUserState ? pUserState : GetCurPhysicsState(pObject); if (!pState) return DFALSE; DVector vTemp, velocityDelta, posDelta; if(pObject->m_PhysicsFlags & MO_RESTING) return DFALSE; // Prevent tiny movements. if(VEC_MAGSQR(pObject->m_Acceleration) < 0.01f) { VEC_INIT(pObject->m_Acceleration); } if(VEC_MAGSQR(pObject->m_Velocity) < 0.01f) { VEC_INIT(pObject->m_Velocity); } // velocityDelta = ( acceleration + accelDelta * 0.5 ) * dt; VEC_INIT(vTemp); if (!(pObject->m_PhysicsFlags & MO_NOGRAVITY)) { DFLOAT fScale = 0.5f; if (pObject->m_PhysicsFlags & MO_HALFGRAVITY) { fScale = 0.20f; } VEC_MULSCALAR(vTemp, pState->m_GravityAccel, fScale); } VEC_ADD(vTemp, vTemp, pObject->m_Acceleration); VEC_MULSCALAR(velocityDelta, vTemp, pState->m_TimeStep); // Apply the velocity to the position (p = p + vt + 0.5a(t^2)). VEC_MULSCALAR(posDelta, pObject->m_Acceleration, pState->m_TimeStepIntegral); VEC_ADDSCALED(posDelta, posDelta, pObject->m_Velocity, pState->m_TimeStep); // Add the final velocity to the new velocity. VEC_ADD(pObject->m_Velocity, pObject->m_Velocity, velocityDelta); if(!pNewPos) pNewPos = &pObject->m_Pos; VEC_ADD(*pNewPos, pObject->m_Pos, posDelta); // Zero out the acceleration. VEC_INIT(pObject->m_Acceleration); return DTRUE; }
void WorldModelDebris::Start(LTVector *pvRotationPeriods, LTVector* pvVel) { if (!pvRotationPeriods || !pvVel) return; LTFLOAT fMag = VEC_MAGSQR(*pvRotationPeriods); if (fMag > 0.001f) { m_bRotate = LTTRUE; if (pvRotationPeriods->x < -0.001 || 0.001f < pvRotationPeriods->x) { m_fXRotVel = MATH_CIRCLE / pvRotationPeriods->x; } if (pvRotationPeriods->y < -0.001 || 0.001f < pvRotationPeriods->y) { m_fXRotVel = MATH_CIRCLE / pvRotationPeriods->y; } if (pvRotationPeriods->z < -0.001 || 0.001f < pvRotationPeriods->z) { m_fXRotVel = MATH_CIRCLE / pvRotationPeriods->z; } } uint32 dwFlags = FLAG_VISIBLE | FLAG_GRAVITY | FLAG_RAYHIT; g_pLTServer->SetObjectFlags(m_hObject, dwFlags); g_pLTServer->SetNextUpdate(m_hObject, 0.01f); g_pLTServer->SetVelocity(m_hObject, pvVel); g_pLTServer->SetBlockingPriority(m_hObject, 100); g_pLTServer->SetForceIgnoreLimit(m_hObject, 0.0f); g_pLTServer->SetFrictionCoefficient(m_hObject, GetRandom(10.0f, 20.0f)); m_fLastTime = g_pLTServer->GetTime(); }
LTBOOL CScanner::CanSeeObject(ObjectFilterFn ofn, HOBJECT hObject) { _ASSERT(hObject); if (!hObject) return LTFALSE; if (g_pGameServerShell->GetGameType() == COOPERATIVE_ASSAULT && m_nPlayerTeamFilter && IsPlayer(hObject)) { CPlayerObj* pPlayer = (CPlayerObj*)g_pLTServer->HandleToObject(hObject); if (pPlayer->GetTeamID() != m_nPlayerTeamFilter) return LTFALSE; } LTVector vPos; g_pLTServer->GetObjectPos(hObject, &vPos); LTVector vDir; vDir = vPos - GetScanPosition(); if (VEC_MAGSQR(vDir) >= m_fVisualRange) { return LTFALSE; } vDir.Norm(); LTRotation rRot = GetScanRotation(); LTVector vUp, vRight, vForward; g_pLTServer->GetRotationVectors(&rRot, &vUp, &vRight, &vForward); LTFLOAT fDp = vDir.Dot(vForward); if (fDp < m_fFOV) { return LTFALSE; } // See if we can see the position in question IntersectQuery IQuery; IntersectInfo IInfo; VEC_COPY(IQuery.m_From, GetScanPosition()); VEC_COPY(IQuery.m_To, vPos); IQuery.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; IQuery.m_FilterFn = ofn; if (g_pLTServer->IntersectSegment(&IQuery, &IInfo)) { if (IInfo.m_hObject == hObject) { return LTTRUE; } } return LTFALSE; }
DBOOL BounceMovingObject(PhysicsState *pUserState, MovingObject *pObject, DVector *pNewPos, ClientIntersectInfo* pInfo, SurfaceType *eType) { if (!pObject || !pNewPos || !pInfo) return DFALSE; PhysicsState* pState = pUserState ? pUserState : GetCurPhysicsState(pObject); if (!pState) return DFALSE; ClientIntersectQuery query; float dot; // Only do an intersection test if the line is long enough (sometimes the // intersection test will fail on really short lines). memset(&query, 0, sizeof(query)); VEC_COPY(query.m_From, pObject->m_Pos); VEC_COPY(query.m_To, *pNewPos); if (eType) query.m_Flags = INTERSECT_HPOLY; if (pState->m_pClientDE->IntersectSegment(&query, pInfo)) { // get the surface type if (eType) *eType = GetSurfaceType(pInfo->m_hObject, pInfo->m_hPoly); // Reflect the velocity. dot = VEC_DOT(pObject->m_Velocity, pInfo->m_Plane.m_Normal); dot *= -2.0f; VEC_ADDSCALED(pObject->m_Velocity, pObject->m_Velocity, pInfo->m_Plane.m_Normal, dot); // If the plane hit is in the opposite direction of travel, then move back a little... if( dot > 0.0f ) { // Move the dest point a little in front of the plane. VEC_ADDSCALED(*pNewPos, pInfo->m_Point, pInfo->m_Plane.m_Normal, 0.3f); } // Dampen it. VEC_MULSCALAR(pObject->m_Velocity, pObject->m_Velocity, pState->m_VelocityDampen); // (250 is the max squared magnitude). if(pInfo->m_Plane.m_Normal.y > 0.6f && (VEC_MAGSQR(pObject->m_Velocity) < (250.0f))) { pObject->m_PhysicsFlags |= MO_RESTING; } return DTRUE; } return DFALSE; }
LTBOOL CScanner::CanSeePos(ObjectFilterFn ofn, const LTVector& vPos) { LTVector vDir; vDir = vPos - GetScanPosition(); if (VEC_MAGSQR(vDir) >= m_fVisualRange) { return LTFALSE; } vDir.Norm(); LTRotation rRot = GetScanRotation(); LTVector vUp, vRight, vForward; g_pLTServer->GetRotationVectors(&rRot, &vUp, &vRight, &vForward); LTFLOAT fDp = vDir.Dot(vForward); if (fDp < m_fFOV) { return LTFALSE; } // See if we can see the position in question IntersectQuery IQuery; IntersectInfo IInfo; VEC_COPY(IQuery.m_From, GetScanPosition()); VEC_COPY(IQuery.m_To, vPos); IQuery.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; IQuery.m_FilterFn = ofn; if (!g_pLTServer->IntersectSegment(&IQuery, &IInfo)) { return LTTRUE; } return LTFALSE; }
void CDestructable::ApplyDamagePhysics(DFLOAT fDamage, DVector *pvDir) { CServerDE* pServerDE = BaseClass::GetServerDE(); if (!pServerDE || !m_hObject || !pvDir) return; // Don't apply damage physics if the object is a trapped character (Andy 2/22/99) if(IsBaseCharacter(m_hObject)) { CBaseCharacter *pObj = (CBaseCharacter*)pServerDE->HandleToObject(m_hObject); if(pObj->IsTrapped()) return; } if (VEC_MAGSQR(*pvDir) < 0.01) return; DVector vTemp, vVel; pServerDE->GetVelocity(m_hObject, &vVel); VEC_COPY(vTemp, *pvDir); VEC_NORM(vTemp); if (m_fMass <= 0) m_fMass = 1; DFLOAT fMultiplier = (fDamage * PA_DAMAGE_VEL_MUTLIPLIER) / m_fMass; VEC_MULSCALAR(vTemp, vTemp, fMultiplier); VEC_ADD(vVel, vTemp, vVel); // Accumulate damage velocity for player objects to send to the client.. if (IsPlayer(m_hObject)) { VEC_ADD(m_vAddVelocity, m_vAddVelocity, vTemp); m_bAddVelocity = DTRUE; } pServerDE->SetVelocity(m_hObject, &vVel); }
void SoccerBall::OnInitialUpdate(void* pData, DFLOAT fData) { DVector vDims; DDWORD dwFlags; g_pServerDE->SetForceIgnoreLimit( m_hObject, 0.0f ); // g_pServerDE->SetFrictionCoefficient( m_hObject, 10.0f ); g_pServerDE->GetModelAnimUserDims( m_hObject, &vDims, 0 ); if( VEC_MAGSQR( vDims ) < 1.0f ) VEC_SET( vDims, 1.0f, 1.0f, 1.0f ); g_pServerDE->SetObjectDims( m_hObject, &vDims ); m_fRadius = ( vDims.x + vDims.y + vDims.z ) / 3.0f; g_pServerDE->SetNextUpdate( m_hObject, 0.001f ); // CreateLight( ); // Mark this object as savable dwFlags = g_pServerDE->GetObjectUserFlags( m_hObject ); dwFlags |= USERFLG_NIGHTGOGGLESGLOW; g_pServerDE->SetObjectUserFlags( m_hObject, dwFlags ); }
void CNodeController::HandleNodeControlRecoilMessage(HMESSAGEREAD hMessage) { if ( m_cRecoils >= MAX_RECOILS ) return; m_fRecoilTimers[m_cRecoils++] = 0.50f; ModelNode eModelNode; eModelNode = (ModelNode)g_pLTClient->ReadFromMessageByte(hMessage); LTVector vRecoilDir; g_pLTClient->ReadFromMessageCompVector(hMessage, &vRecoilDir); // Get the magnitude of the recoil vector LTFLOAT fRecoilMag = VEC_MAGSQR(vRecoilDir); // Get the unit impact/recoil vector vRecoilDir /= (float)sqrt(fRecoilMag); // Cap it if necessary if ( fRecoilMag > 100.0f ) { fRecoilMag = 100.0f; } // Get the position of the impact NSTRUCT* pNode = &m_aNodes[eModelNode]; ILTModel* pModelLT = g_pLTClient->GetModelLT(); LTransform transform; pModelLT->GetNodeTransform(GetCFX()->GetServerObj(), pNode->hModelNode, transform, LTTRUE); // Decompose the transform into the position and rotation LTVector vPos; ILTTransform* pTransformLT = g_pLTClient->GetTransformLT(); pTransformLT->GetPos(transform, vPos); LTVector vRecoilPos = vPos; // Add angular rotations up the recoil parent chain ModelNode eModelNodeCurrent = g_pModelButeMgr->GetSkeletonNodeRecoilParent(GetCFX()->GetModelSkeleton(), eModelNode); while ( eModelNodeCurrent != eModelNodeInvalid ) { // Get the rotation of the node NSTRUCT* pNode = &m_aNodes[eModelNodeCurrent]; LTransform transform; ILTModel* pModelLT = g_pLTClient->GetModelLT(); // Get the transform of the node we're controlling pModelLT->GetNodeTransform(GetCFX()->GetServerObj(), pNode->hModelNode, transform, LTTRUE); ILTTransform* pTransformLT = g_pLTClient->GetTransformLT(); // Decompose the transform into the position and rotation LTVector vPos; LTRotation rRot; pTransformLT->Get(transform, vPos, rRot); // Get the rotation vectors of the transform LTVector vRight, vUp, vForward; g_pLTClient->GetRotationVectors(&rRot, &vUp, &vRight, &vForward); // Cross the right vector with the impact vector to get swing LTVector vRotationAxis = vRight.Cross(vRecoilDir); vRotationAxis.Norm(); // Add the timed rotation control for the swing // !!! HACK // !!! Do not add swing if this is a leg node if ( !strstr(g_pModelButeMgr->GetSkeletonNodeName(GetCFX()->GetModelSkeleton(), eModelNodeCurrent), "leg") ) AddNodeControlRotationTimed(eModelNodeCurrent, vRotationAxis, MATH_PI/1000.0f*fRecoilMag, 0.50f); // Use the right vector to get twist, but make sure the sign is correct based on location // of impact and whether we're getting shot at from behind/front etc vRotationAxis = vRight; vRotationAxis.Norm(); // Get the twist LTVector vSideDir = vRecoilPos-vPos; vSideDir.Norm(); LTFLOAT fSign = vUp.Dot(vRecoilDir); fSign *= vForward.Dot(vSideDir); if ( fSign > 0.0f ) { vRotationAxis = -vRotationAxis; } // Add the timed rotation control for the twist // AddNodeControlRotationTimed(eModelNodeCurrent, vRotationAxis, MATH_PI/1000.0f*fRecoilMag, 0.50f); // Decrease the magnitude fRecoilMag /= 2.0f; eModelNodeCurrent = g_pModelButeMgr->GetSkeletonNodeRecoilParent(GetCFX()->GetModelSkeleton(), eModelNodeCurrent); } }
void SoccerBall::OnTouchNotify( HOBJECT hObj, float fForce ) { CollisionInfo colInfo; DVector vVel, vOtherVel, vEffectiveVel, vPos, vNewVel; DVector vNormal; float fEffectiveVelMag, fMultiplier, fVelMag; DRotation rRot; DVector vUp, vRight; DBOOL bIsPlayer; g_pServerDE->GetVelocity( m_hObject, &vVel ); g_pServerDE->GetVelocity( hObj, &vOtherVel ); g_pServerDE->GetObjectPos( m_hObject, &vPos ); if( hObj == g_pServerDE->GetWorldObject( )) { VEC_SUB( vEffectiveVel, vOtherVel, vVel ); fEffectiveVelMag = VEC_MAG( vEffectiveVel ); g_pServerDE->GetLastCollision( &colInfo ); // Compute new velocity reflected off of the surface. if( VEC_MAGSQR( colInfo.m_Plane.m_Normal ) > 0.0f ) { VEC_COPY( vNormal, colInfo.m_Plane.m_Normal ); if( fEffectiveVelMag > MAXBALLVEL ) fMultiplier = MAXBOUNCEFACTOR; else fMultiplier = MINBOUNCEFACTOR + ( MAXBOUNCEFACTOR - MINBOUNCEFACTOR ) * fEffectiveVelMag / MAXBALLVEL; VEC_MULSCALAR( vNormal, vNormal, fEffectiveVelMag * fMultiplier ); VEC_ADD( vNewVel, vVel, vNormal ); if( fabs( vNewVel.y + vVel.y ) < 100.0f ) vNewVel.y = vVel.y; g_pServerDE->SetVelocity( m_hObject, &vNewVel ); } if( fabs( fForce ) > MINFORCESOUND ) m_bBounced = DTRUE; } else { // Ignore non-solid objects if( !( g_pServerDE->GetObjectFlags( hObj ) & FLAG_SOLID )) return; bIsPlayer = IsPlayer( hObj ); if( bIsPlayer ) { if( m_hLastPlayer && hObj != m_hLastPlayer ) { g_pServerDE->BreakInterObjectLink( m_hObject, m_hLastPlayer ); } m_hLastPlayer = hObj; g_pServerDE->CreateInterObjectLink( m_hObject, m_hLastPlayer ); m_fRespawnTime = g_pServerDE->GetTime( ) + BALLRESPAWNTIME; } VEC_ADD( vVel, vVel, vOtherVel ); if( m_bOnGround && vVel.y < 0.0f ) vVel.y = 0.0f; if( bIsPlayer ) vVel.y += g_pServerDE->Random( 150.0f, 300.0f ); fVelMag = VEC_MAG( vVel ); g_pServerDE->AlignRotation( &rRot, &vVel, DNULL ); g_pServerDE->EulerRotateX( &rRot, g_pServerDE->Random( -0.1f, 0.1f )); g_pServerDE->EulerRotateY( &rRot, g_pServerDE->Random( -0.1f, 0.1f )); g_pServerDE->EulerRotateZ( &rRot, g_pServerDE->Random( -0.1f, 0.1f )); g_pServerDE->GetRotationVectors( &rRot, &vUp, &vRight, &vVel ); VEC_MULSCALAR( vVel, vVel, fVelMag ); g_pServerDE->SetVelocity( m_hObject, &vVel ); if( fabs( fForce ) > MINFORCESOUND || bIsPlayer ) m_bBounced = DTRUE; } }