DVector CMovement::FindPosAroundObj(DVector vStart, DVector vDir) { CServerDE* pServerDE = BaseClass::GetServerDE(); if (!pServerDE) return vStart; DVector vDims, vPoint, vColor; m_nWidthPoints = 10; //get the parent's dims pServerDE->GetObjectDims(m_hObject,&vDims); DFLOAT fDim = (DFLOAT)sqrt((vDims.x * vDims.x) + (vDims.z * vDims.z)) + 0.1f; VEC_ADDSCALED(vPoint, vStart, vDir, fDim); while(m_nWidthPoints) { if(pServerDE->GetPointShade(&vPoint,&vColor)) { return vPoint; } else { VEC_ADDSCALED(vPoint, vPoint, vDir, fDim); } m_nWidthPoints--; } return vStart; }
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; }
DVector CMovement::FindTurn(DVector vStart, DVector vTestDir, DVector vMoveDir, DFLOAT fMoveLen, DFLOAT fTestLen) { DVector vFinal,vCurPos; DBOOL bStop = DTRUE; DFLOAT fMaxDist = 0.0f; VEC_INIT(vFinal); VEC_COPY(vCurPos, vStart); CServerDE* pServerDE = BaseClass::GetServerDE(); if (!pServerDE) return vFinal; IntersectQuery IQuery; IntersectInfo IInfo; IQuery.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; IQuery.m_FilterFn = DNULL; VEC_COPY(IQuery.m_From,vStart); VEC_COPY(IQuery.m_Direction,vMoveDir); //find maximum searchable distance in vMoveDir if(pServerDE->CastRay(&IQuery,&IInfo)) { fMaxDist = VEC_DIST(vStart,IInfo.m_Point); } //loop til we find a spot to turn for(float fDist = 0.0f; !((fDist + fMoveLen) >= fMaxDist); fDist += fMoveLen) { VEC_ADDSCALED(vCurPos, vCurPos, vMoveDir, fMoveLen); VEC_COPY(IQuery.m_From,vCurPos); VEC_ADDSCALED(IQuery.m_To,vCurPos, vTestDir, fTestLen); if(!pServerDE->IntersectSegment(&IQuery, &IInfo)) { VEC_ADDSCALED(vFinal, vCurPos, vMoveDir, fMoveLen); return vFinal; } } if(m_nNumPoints >= 10 || (VEC_DIST(vCurPos,vStart) <= 0.0)) return vCurPos; //we can't turn here so we add to list and keep searching in new direction AddPosToPathList(vCurPos); DVector vNewMoveDir; VEC_MULSCALAR(vNewMoveDir, vTestDir, -1.0f); return FindTurn(vCurPos, vMoveDir, vNewMoveDir, fMoveLen, (fMaxDist - fDist) + 1.0f); }
DBOOL CMovement::ClearToPoint(DVector vStart, DVector vDestPos, DVector vDims, IntersectInfo* IInfo) { GlobalFilterFnData globalFilterFnData; CServerDE* pServerDE = BaseClass::GetServerDE(); if (!pServerDE) return DFALSE; DFLOAT fDim = (DFLOAT)sqrt((vDims.x * vDims.x) + (vDims.z * vDims.z)) + 0.1f; IntersectQuery IQuery; IQuery.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; IQuery.m_FilterFn = GlobalFilterFn; globalFilterFnData.m_dwFlags = IGNORE_CHARACTER; globalFilterFnData.m_nIgnoreObjects = 1; globalFilterFnData.m_hIgnoreObjects = &m_hObject; IQuery.m_pUserData = &globalFilterFnData; DVector vDir; DRotation rRot; VEC_SUB(vDir, vDestPos, vStart); VEC_NORM(vDir); pServerDE->AlignRotation(&rRot, &vDir, &m_vUp); DVector vU,vR,vF; pServerDE->GetRotationVectors(&rRot,&vU,&vR,&vF); //check the right side VEC_ADDSCALED(IQuery.m_From, vStart, vR, fDim); VEC_ADDSCALED(IQuery.m_To, vDestPos, vR, fDim); if(pServerDE->IntersectSegment(&IQuery, IInfo)) { return DFALSE; } //check the left side VEC_ADDSCALED(IQuery.m_From, vStart, vR, (fDim * -1.0f)); VEC_ADDSCALED(IQuery.m_To,vDestPos, vR, (fDim * -1.0f)); if(pServerDE->IntersectSegment(&IQuery, IInfo)) { return DFALSE; } return DTRUE; }
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; }
int CDestructable::CalculateHitLimb(DVector vDir, DVector vPos, DFLOAT fDamage) { CServerDE* pServerDE = BaseClass::GetServerDE(); if (!pServerDE || !m_hObject || !m_pInventoryMgr || !m_pAnim_Sound) return -1; int nNode = -1; DFLOAT fNodeDist = 0.0f, fDist = 999.0f, fTemp = 0.0f; DVector vShot, vNewShot, vTemp, vObjDims, vNodePos, vZ; DFLOAT fX, fY, ft; DBOOL bStatus = DFALSE; DRotation rRot; if(pServerDE->GetModelAnimUserDims(m_hObject, &vObjDims, pServerDE->GetModelAnimation(m_hObject)) == DE_INVALIDPARAMS) pServerDE->DebugOut("CalculateHitLimb() f****d up\r\n"); vTemp.x = (float)fabs(vDir.x); vTemp.y = (float)fabs(vDir.y); vTemp.z = (float)fabs(vDir.z); if(vTemp.x > vTemp.y && vTemp.x > vTemp.z) { fTemp = vObjDims.x / vTemp.x; } else if(vTemp.y > vTemp.x && vTemp.y > vTemp.z) { fTemp = vObjDims.y / vTemp.y; } else if(vTemp.z > vTemp.x && vTemp.z > vTemp.y) { fTemp = vObjDims.z / vTemp.z; } VEC_MULSCALAR(vNewShot,vDir,fTemp); VEC_ADD(vShot,vPos,vNewShot); DVector vC; VEC_SUB(vC,vShot,vPos); fX = 1 / VEC_DOT(vC,vC); fY = fX * -(VEC_DOT(vC,vPos)); for(int i = 0; i < NUM_STD_NODES; i++) { pServerDE->GetModelNodeHideStatus(m_hObject, szNodes[i], &bStatus); if(!bStatus) { DBOOL bRet = pServerDE->GetModelNodeTransform(m_hObject, szNodes[i], &vNodePos, &rRot); ft = VEC_DOT(vC,vNodePos) * fX + fY; if(ft >= 0.0f && ft <= 1.0f) { VEC_ADDSCALED(vZ,vPos,vC, ft); fNodeDist = VEC_DIST(vNodePos, vZ); if(fNodeDist < fDist && fNodeDist <= m_pAnim_Sound->m_fHitSpheres[i]) { fDist = fNodeDist; nNode = i; } } } } /* //Do we leave a pass through mark behind us? if(nNode != -1) { CWeapon *pW = m_pInventoryMgr->GetCurrentWeapon(); if(pW) { VEC_MULSCALAR(vTemp,vDir,-1.0f); // TODO: combine sparks with weaponFX GK 8/27 // pW->AddSparks(vPos, vTemp, fDamage * 2.0f, m_hObject, SURFTYPE_FLESH); // pW->AddBloodSpurt(vPos, vTemp, fDamage * 2.0f, m_hObject, SURFTYPE_FLESH); // Took this out - more efficient to send one message. GK 8/27 // vTemp.x *= -1.0f; // vTemp.z *= -1.0f; // pW->AddBloodSpurt(vPos, vTemp, fDamage * 2.0f, m_hObject, SURFTYPE_FLESH); IntersectQuery iq; IntersectInfo ii; // Set the intersection query values iq.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; iq.m_FilterFn = DNULL; iq.m_pUserData = DNULL; VEC_COPY(iq.m_From, vPos); VEC_ADDSCALED(iq.m_To, vPos, vDir, 75.0f); // Apply a blood splat to the wall if(pServerDE->IntersectSegment(&iq, &ii) && (ii.m_hObject == pServerDE->GetWorldObject())) { // pW->AddImpact(WFX_BLOODSPLAT, ii.m_Point, vDir, ii.m_Plane.m_Normal, fDamage * 2.0f, // ii.m_hObject, SURFTYPE_FLESH); // pW->AddSparks(ii.m_Point, ii.m_Plane.m_Normal, fDamage * 2.0f, ii.m_hObject, SURFTYPE_FLESH); } } } */ return nNode; }
DVector CMovement::FindShortestTurn(DVector vStart, DRotation* prRot, DFLOAT fMoveLen) { CServerDE* pServerDE = BaseClass::GetServerDE(); if (!pServerDE) return vStart; DVector vDir, vEnd, vCurPos; DVector vUp,vRight,vForward,vLeft; VEC_COPY(vCurPos, vStart); IntersectQuery IQuery; IntersectInfo ii; DFLOAT fLeftDist = 0.0f, fRightDist = 0.0f, fMaxDist = 0.0f; pServerDE->GetRotationVectors(prRot,&vUp,&vRight,&vForward); VEC_MULSCALAR(vLeft,vRight,-1.0f); //create the left rotation vector IQuery.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; IQuery.m_FilterFn = DNULL; //get the farthest left we could travel VEC_COPY(IQuery.m_From,vCurPos); VEC_COPY(IQuery.m_Direction,vLeft); if(pServerDE->CastRay(&IQuery,&ii)) { fMaxDist = fLeftDist = VEC_DIST(vCurPos,ii.m_Point); } //now get the farthest right VEC_COPY(IQuery.m_Direction,vRight); if(pServerDE->CastRay(&IQuery,&ii)) { fRightDist = VEC_DIST(vCurPos,ii.m_Point); if(fRightDist > fMaxDist) fMaxDist = fRightDist; } //travel the obstacle in both directions looking for a clearing VEC_INIT(vDir); VEC_MULSCALAR(vEnd,vForward,fMoveLen + 5.0f); for(float fWidth = fMoveLen; !(fWidth >= fRightDist && fWidth >= fLeftDist); fWidth += fMoveLen) { //Check the right side if(fWidth < fRightDist) { VEC_ADDSCALED(IQuery.m_From,vCurPos,vRight,fWidth); VEC_ADD(IQuery.m_To,IQuery.m_From,vEnd); if(!pServerDE->IntersectSegment(&IQuery,&ii)) { VEC_ADDSCALED(IQuery.m_From,IQuery.m_From,vRight,fWidth/2); pServerDE->AlignRotation(prRot, &vLeft, &m_vUp); return IQuery.m_From; } } //Check the left side if(fWidth < fLeftDist) { VEC_ADDSCALED(IQuery.m_From,vCurPos,vLeft,fWidth); VEC_ADD(IQuery.m_To,IQuery.m_From,vEnd); if(!pServerDE->IntersectSegment(&IQuery,&ii)) { VEC_ADDSCALED(IQuery.m_From,IQuery.m_From,vLeft,fWidth/2); pServerDE->AlignRotation(prRot, &vRight, &m_vUp); return IQuery.m_From; } } } return vStart; }
DBOOL CMovement::CalculatePath(DVector vDestPos) { CServerDE* pServerDE = BaseClass::GetServerDE(); if (!pServerDE) return DFALSE; DVector vDims, vTest; DRotation rRot; //sanity check to make sure vDestPos is valid VEC_INIT(vTest); if(VEC_DIST(vTest, vDestPos) <= 0) return DFALSE; IntersectQuery IQuery; IntersectInfo IInfo; IQuery.m_Flags = INTERSECT_OBJECTS; IQuery.m_FilterFn = DNULL; // LARGE_INTEGER start; // QueryPerformanceCounter(&start); //clear the path list out Term(); //get the parent's dims pServerDE->GetObjectDims(m_hObject,&vDims); DFLOAT fDim = (DFLOAT)sqrt((vDims.x * vDims.x) + (vDims.z * vDims.z)) + 0.1f; if(!ClearToPoint(m_vPos, vDestPos,vDims, &IInfo)) { VEC_ADDSCALED(IInfo.m_Point,IInfo.m_Point, IInfo.m_Plane.m_Normal, fDim - 0.1f) AddPosToPathList(IInfo.m_Point); //align a test rotation to the obstacles normal and retrieve the rotation vectors VEC_MULSCALAR(IInfo.m_Plane.m_Normal, IInfo.m_Plane.m_Normal, -1.0f); pServerDE->AlignRotation(&rRot, &(IInfo.m_Plane.m_Normal), &m_vUp); DVector vTurnPoint = FindShortestTurn(IInfo.m_Point, &rRot, fDim); if(VEC_DIST(vTurnPoint, IInfo.m_Point) <= 0.0f) return DFALSE; AddPosToPathList(vTurnPoint); DVector vU,vR,vF; pServerDE->GetRotationVectors(&rRot,&vU,&vR,&vF); vTurnPoint = FindTurn(vTurnPoint, vF, IInfo.m_Plane.m_Normal, fDim, fDim); if(VEC_DIST(vTurnPoint, vDestPos) <= 0.0f) return DFALSE; if(ClearToPoint(vTurnPoint, vDestPos, vDims, &IInfo)) { AddPosToPathList(vTurnPoint); AddPosToPathList(vDestPos); // ConsolidatePath(); } else return DFALSE; } else AddPosToPathList(vDestPos); /* LARGE_INTEGER end; QueryPerformanceCounter(&end); pServerDE->DebugOut("Shortest Path Computed: %u ticks\r\n", (unsigned long)(end.QuadPart - start.QuadPart)); */ return DTRUE; }