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; }
//determines if this polygon is concave or not bool CEditPoly::IsConcave() { uint32 nNumPts = NumVerts(); if(nNumPts <= 3) { return false; } //get the normal for this polygon LTVector vNormal = Normal(); //now go through every edge uint32 nPrevPt = nNumPts - 1; for(uint32 nCurrPt = 0; nCurrPt < nNumPts; nPrevPt = nCurrPt, nCurrPt++) { //build the edge normal LTVector vEdge = m_pBrush->m_Points[Index(nCurrPt)] - m_pBrush->m_Points[Index(nPrevPt)]; //find the normal LTVector vEdgeNorm = vNormal.Cross(vEdge); vEdgeNorm.Norm(); //now run through all the other points for(uint32 nTestPt = 0; nTestPt < nNumPts; nTestPt++) { //ignore the points on the edge if((nTestPt == nCurrPt) || (nTestPt == nPrevPt)) continue; //see if it is on the correct side if(vEdgeNorm.Dot(m_pBrush->m_Points[Index(nTestPt)] - m_pBrush->m_Points[Index(nCurrPt)]) > 0.001f) { return true; } } } return false; }
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; }
static void CreateServerExitMark(const CLIENTWEAPONFX & theStruct) { SURFACE* pSurf = g_pSurfaceMgr->GetSurface((SurfaceType)theStruct.nSurfaceType); if (!pSurf || !pSurf->bCanShootThrough) return; int nMaxThickness = pSurf->nMaxShootThroughThickness; if (nMaxThickness < 1) return; // Determine if there is an "exit" surface... IntersectQuery qInfo; IntersectInfo iInfo; LTVector vDir = theStruct.vPos - theStruct.vFirePos; vDir.Norm(); qInfo.m_From = theStruct.vPos + (vDir * (LTFLOAT)(nMaxThickness + 1)); qInfo.m_To = theStruct.vPos; qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY; SurfaceType eType = ST_UNKNOWN; if (g_pLTServer->IntersectSegment(&qInfo, &iInfo)) { eType = GetSurfaceType(iInfo); if (ShowsMark(eType)) { LTRotation rNormRot; g_pLTServer->AlignRotation(&rNormRot, &(iInfo.m_Plane.m_Normal), LTNULL); CLIENTWEAPONFX exitStruct = theStruct; exitStruct.vPos = iInfo.m_Point + vDir; exitStruct.vSurfaceNormal = iInfo.m_Plane.m_Normal; CreateServerMark(exitStruct); } } }
void gr_BuildFrameOfReference(LTVector *pVec, LTVector *pUpRef, LTVector *pRight, LTVector *pUp, LTVector *pForward) { LTVector tempRef; *pForward = *pVec; pForward->Norm(); // Treat the vector as the forward vector and come up with 2 other vectors. if(pUpRef) { tempRef = *pUpRef; tempRef.Norm(); gr_GetPerpendicularVector(pForward, &tempRef, pUp); } else { gr_GetPerpendicularVector(pForward, LTNULL, pUp); } // Create the right vector. *pRight = pForward->Cross(*pUp); }
void Breakable::CrushObject(HOBJECT hObj) { if (!hObj) return; LTVector vPos; LTVector vHisPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); g_pLTServer->GetObjectPos(m_hObject, &vHisPos); LTVector vDir = vPos - vHisPos; vDir.Norm(); DamageStruct damage; damage.eType = DT_CRUSH; damage.fDamage = damage.kInfiniteDamage; damage.hDamager = m_hObject; damage.vDir = vDir; damage.DoDamage(this, hObj); }
LTBOOL CSearchLightFX::Update() { if (!m_pClientDE || !m_hServerObject || m_bWantRemove || !m_hBeam) return LTFALSE; uint32 dwFlags = 0; // Update the lens flare... m_LensFlare.Update(); // Hide/show the fx if necessary... if (m_hServerObject) { uint32 dwUserFlags; m_pClientDE->GetObjectUserFlags(m_hServerObject, &dwUserFlags); if (!(dwUserFlags & USRFLG_VISIBLE)) // Hide fx { if (m_hBeam) { dwFlags = m_pClientDE->GetObjectFlags(m_hBeam); m_pClientDE->SetObjectFlags(m_hBeam, dwFlags & ~FLAG_VISIBLE); } if (m_hLight) { dwFlags = m_pClientDE->GetObjectFlags(m_hLight); m_pClientDE->SetObjectFlags(m_hLight, dwFlags & ~FLAG_VISIBLE); } return LTTRUE; } else // Make all fx visible { if (m_hBeam) { dwFlags = m_pClientDE->GetObjectFlags(m_hBeam); m_pClientDE->SetObjectFlags(m_hBeam, dwFlags | FLAG_VISIBLE); } if (m_hLight) { dwFlags = m_pClientDE->GetObjectFlags(m_hLight); m_pClientDE->SetObjectFlags(m_hLight, dwFlags | FLAG_VISIBLE); } } } // Update the position/rotation of the beam... LTVector vPos; m_pClientDE->GetObjectPos(m_hServerObject, &vPos); LTRotation rRot; m_pClientDE->GetObjectRotation(m_hServerObject, &rRot); LTVector vU, vR, vF; m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF); // See how long to make the beam... LTVector vDest = vPos + (vF * m_cs.fBeamLength); IntersectInfo iInfo; IntersectQuery qInfo; qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; qInfo.m_FilterFn = AttackerLiquidFilterFn; qInfo.m_pUserData = m_hServerObject; qInfo.m_From = vPos; qInfo.m_To = vDest; if (g_pLTClient->IntersectSegment(&qInfo, &iInfo)) { vDest = iInfo.m_Point; } LTVector vDir = vDest - vPos; LTFLOAT fDistance = vDir.Mag(); vDir.Norm(); LTVector vNewPos = vPos + vDir * fDistance/2.0f; m_pClientDE->AlignRotation(&rRot, &vDir, NULL); if (m_cs.fBeamRotTime > 0.0f) { m_fBeamRotation += (360.0f/m_cs.fBeamRotTime * g_pGameClientShell->GetFrameTime()); m_fBeamRotation = m_fBeamRotation > 360.0f ? m_fBeamRotation - 360.0f : m_fBeamRotation; m_pClientDE->RotateAroundAxis(&rRot, &vDir, DEG2RAD(m_fBeamRotation)); } m_pClientDE->SetObjectRotation(m_hBeam, &rRot); m_pClientDE->SetObjectPos(m_hBeam, &vNewPos); LTVector vScale(m_cs.fBeamRadius, m_cs.fBeamRadius, fDistance); m_pClientDE->SetObjectScale(m_hBeam, &vScale); // Move the dynamic light... if (m_hLight) { vDest -= (vDir * 5.0f); m_pClientDE->SetObjectPos(m_hLight, &vDest); } return LTTRUE; }
void Lock::HandleGadgetMsg(HOBJECT hSender, ConParse & parse) { if (parse.m_nArgs < 2 || !parse.m_Args[1]) return; AMMO* pAmmo = g_pWeaponMgr->GetAmmo(atol(parse.m_Args[1])); if (!pAmmo) return; LTBOOL bProcess = LTFALSE; if (m_bWeldable && pAmmo->eInstDamageType == DT_GADGET_WELDER) { bProcess = LTTRUE; } else if (m_bLightable && pAmmo->eInstDamageType == DT_GADGET_LIGHTER) { bProcess = LTTRUE; } else if (!m_bWeldable && pAmmo->eInstDamageType == DT_GADGET_LOCK_PICK) { bProcess = LTTRUE; } if (!bProcess) return; // Pick the lock by doing lock-pick damage to it... DamageStruct damage; damage.eType = pAmmo->eInstDamageType; damage.fDamage = GetRandom(m_fMinUnlockHitPts, m_fMaxUnlockHitPts); damage.vDir.Init(0, 1, 0); damage.hDamager = m_hObject; damage.DoDamage(this, m_hObject); // Play the lock pick sound... LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); if (m_hstrPickSnd) { char* pSound = g_pLTServer->GetStringData(m_hstrPickSnd); if (pSound) { g_pServerSoundMgr->PlaySoundFromPos(vPos, pSound, m_fSndRadius, SOUNDPRIORITY_MISC_MEDIUM); } } // Do fx for welding the lock... if (m_bWeldable && pAmmo->eInstDamageType == DT_GADGET_WELDER) { WEAPON* pWeapon = g_pWeaponMgr->GetWeapon("Lighter"); if (!pWeapon) return; SURFACE* pSurf = g_pSurfaceMgr->GetSurface("Metal"); if (!pSurf) return; LTVector vHisPos; g_pLTServer->GetObjectPos(hSender, &vHisPos); LTVector vDir = vHisPos - vPos; vDir.Norm(); CLIENTWEAPONFX fxStruct; fxStruct.hFiredFrom = hSender; fxStruct.vSurfaceNormal = vDir; fxStruct.vFirePos = vHisPos; fxStruct.vPos = vPos + vDir; fxStruct.hObj = m_hObject; fxStruct.nWeaponId = pWeapon->nId; fxStruct.nAmmoId = pAmmo->nId; fxStruct.nSurfaceType = pSurf->eType; // This should be a player object, get the client id... if (IsPlayer(hSender)) { CPlayerObj* pPlayer = (CPlayerObj*) g_pLTServer->HandleToObject(hSender); if (pPlayer) { fxStruct.nShooterId = (uint8) g_pLTServer->GetClientID(pPlayer->GetClient()); } } CreateClientWeaponFX(fxStruct); } }
// Wrap the textures, starting at a poly index void CRVTrackerTextureWrap::WrapTexture(CTWPolyInfo *pPoly, const CVector &vWrapDir, CTextExtents &cExtents) const { // Mark this poly as wrapped pPoly->m_bTouched = TRUE; CTexturedPlane& Texture = pPoly->m_pPoly->GetTexture(GetCurrTexture()); // Get the texture space LTVector vWrapO = Texture.GetO(); LTVector vWrapP = Texture.GetP(); LTVector vWrapQ = Texture.GetQ(); // Get the texture offset projections float fWrapOdotP = vWrapO.Dot(vWrapP); float fWrapOdotQ = vWrapO.Dot(vWrapQ); // Update the texturing extents for (uint32 nExtentLoop = 0; nExtentLoop < pPoly->m_aEdges.GetSize(); ++nExtentLoop) { LTVector vEdgePt = pPoly->m_aEdges[nExtentLoop]->m_aPt[0]; float fCurU = vWrapP.Dot(vEdgePt) - fWrapOdotP; float fCurV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ; cExtents.m_fMinU = LTMIN(fCurU, cExtents.m_fMinU); cExtents.m_fMaxU = LTMAX(fCurU, cExtents.m_fMaxU); cExtents.m_fMinV = LTMIN(fCurV, cExtents.m_fMinV); cExtents.m_fMaxV = LTMAX(fCurV, cExtents.m_fMaxV); } CMoArray<uint32> aNeighbors; CMoArray<float> aDots; // Insert the neighbors into a list in dot-product order for (uint32 nNeighborLoop = 0; nNeighborLoop < pPoly->m_aNeighbors.GetSize(); ++nNeighborLoop) { CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[nNeighborLoop]; // Skip edges that don't have a neighbor if (!pNeighbor) continue; // Skip neighbors that are already wrapped if (pNeighbor->m_bTouched) continue; // Get our dot product float fCurDot = vWrapDir.Dot(pPoly->m_aEdges[nNeighborLoop]->m_Plane.m_Normal); if ((m_bRestrictWalkDir) && (fCurDot < 0.707f)) continue; // Mark this neighbor as touched (to avoid later polygons pushing it onto the stack) pNeighbor->m_bTouched = TRUE; // Insert it into the list for (uint32 nInsertLoop = 0; nInsertLoop < aNeighbors.GetSize(); ++nInsertLoop) { if (fCurDot > aDots[nInsertLoop]) break; } aDots.Insert(nInsertLoop, fCurDot); aNeighbors.Insert(nInsertLoop, nNeighborLoop); } // Recurse through its neighbors for (uint32 nWrapLoop = 0; nWrapLoop < aNeighbors.GetSize(); ++nWrapLoop) { CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[aNeighbors[nWrapLoop]]; CTWEdgeInfo *pEdge = pPoly->m_aEdges[aNeighbors[nWrapLoop]]; ////////////////////////////////////////////////////////////////////////////// // Wrap this neighbor // Create a matrix representing the basis of the polygon in relation to this edge LTMatrix mPolyBasis; mPolyBasis.SetTranslation(0.0f, 0.0f, 0.0f); mPolyBasis.SetBasisVectors(&pEdge->m_vDir, &pPoly->m_pPoly->m_Plane.m_Normal, &pEdge->m_Plane.m_Normal); // Create a new basis for the neighbor polygon LTMatrix mNeighborBasis; LTVector vNeighborForward; vNeighborForward = pNeighbor->m_pPoly->m_Plane.m_Normal.Cross(pEdge->m_vDir); // Just to be sure.. vNeighborForward.Norm(); mNeighborBasis.SetTranslation(0.0f, 0.0f, 0.0f); mNeighborBasis.SetBasisVectors(&pEdge->m_vDir, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborForward); // Create a rotation matrix from here to there LTMatrix mRotation; mRotation = mNeighborBasis * ~mPolyBasis; // Rotate the various vectors LTVector vNewP; LTVector vNewQ; LTVector vNewDir; mRotation.Apply3x3(vWrapP, vNewP); mRotation.Apply3x3(vWrapQ, vNewQ); mRotation.Apply3x3(vWrapDir, vNewDir); // Rotate the texture basis if we're following a path if (m_nWrapStyle == k_WrapPath) { LTVector vNeighborEdgeDir; if (GetSimilarEdgeDir(pNeighbor, vNewDir, vNeighborEdgeDir, 0.707f)) { LTMatrix mRotatedNeighbor; LTVector vNeighborRight; vNeighborRight = vNeighborEdgeDir.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal); vNeighborRight.Norm(); // Make sure we're pointing the right way... if (vNeighborRight.Dot(pEdge->m_vDir) < 0.0f) vNeighborRight = -vNeighborRight; mRotatedNeighbor.SetTranslation(0.0f, 0.0f, 0.0f); mRotatedNeighbor.SetBasisVectors(&vNeighborRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborEdgeDir); // Build a basis based on an edge from the current polygon LTVector vBestPolyEdge; GetSimilarEdgeDir(pPoly, vWrapDir, vBestPolyEdge); LTVector vPolyRight = vBestPolyEdge.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal); vPolyRight.Norm(); // Make sure we're pointing the right way... if (vPolyRight.Dot(pEdge->m_vDir) < 0.0f) vPolyRight = -vPolyRight; // Build the poly edge matrix LTMatrix mPolyEdgeBasis; mPolyEdgeBasis.SetTranslation(0.0f, 0.0f, 0.0f); mPolyEdgeBasis.SetBasisVectors(&vPolyRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vBestPolyEdge); // Get a matrix from here to there LTMatrix mRotator; mRotator = mRotatedNeighbor * ~mPolyEdgeBasis; // Rotate the texture basis mRotator.Apply3x3(vNewP); mRotator.Apply3x3(vNewQ); // And use the new edge as the new direction vNewDir = vNeighborEdgeDir; } // Remove skew from vNewP/vNewQ if ((float)fabs(vNewP.Dot(vNewQ)) > 0.001f) { float fMagP = vNewP.Mag(); float fMagQ = vNewQ.Mag(); vNewQ *= 1.0f / fMagQ; vNewP -= vNewQ * vNewQ.Dot(vNewP); vNewP.Norm(fMagP); vNewQ *= fMagQ; } } // Get the first edge point.. CVector vEdgePt = pEdge->m_aPt[0]; // Calculate the texture coordinate at this point float fWrapU = vWrapP.Dot(vEdgePt) - fWrapOdotP; float fWrapV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ; // Build the new offset float fNewOdotP = vNewP.Dot(vEdgePt) - fWrapU; float fNewOdotQ = vNewQ.Dot(vEdgePt) - fWrapV; LTVector vNewO; vNewO.Init(); float fNewPMag = vNewP.MagSqr(); if (fNewPMag > 0.0f) vNewO += vNewP * (fNewOdotP / fNewPMag); float fNewQMag = vNewQ.MagSqr(); if (fNewQMag > 0.0f) vNewO += vNewQ * (fNewOdotQ / fNewQMag); pNeighbor->m_pPoly->SetTextureSpace(GetCurrTexture(), vNewO, vNewP, vNewQ); // Recurse into this neighbor WrapTexture(pNeighbor, vNewDir, cExtents); } }
LTBOOL CAIVolumeMgr::FindDangerScatterPosition(CAIVolume* pVolume, const LTVector& vAIPos, const LTVector& vDangerPos, LTFLOAT fDangerDistanceSqr, LTVector* pvScatterPosition, LTBOOL bNeighbor /* = LTFALSE */) { // Is there a Position in this volume that is sufficiently far from the position in question? LTVector avCorners[] = { pVolume->GetBackBottomLeft(), pVolume->GetBackBottomRight(), pVolume->GetFrontBottomLeft(), pVolume->GetFrontBottomRight() }; LTBOOL abCornerValid[] = { LTFALSE, LTFALSE, LTFALSE, LTFALSE }; LTFLOAT fRandomRadiusModifier = GetRandom(1.0f, 1.0f); // Find all valid corners {for ( uint iCorner = 0 ; iCorner < 4 ; iCorner++ ) { if ( avCorners[iCorner].DistSqr(vDangerPos) > fDangerDistanceSqr*fRandomRadiusModifier ) { abCornerValid[iCorner] = LTTRUE; } }} // Decide which, if any, of the valid corners, is best for us to use (ie, don't run through the danger radius to get there) LTFLOAT fMinimumDistanceSqr = (LTFLOAT)INT_MAX; uint32 iCornerBest = -1; {for ( uint iCorner = 0 ; iCorner < 4 ; iCorner++ ) { if ( !abCornerValid[iCorner] ) continue; LTFLOAT fDistanceSqr = avCorners[iCorner].DistSqr(vAIPos); if ( fDistanceSqr < fMinimumDistanceSqr ) { iCornerBest = iCorner; fMinimumDistanceSqr = fDistanceSqr; } }} if ( iCornerBest != -1 ) { // Find opposite corner _ASSERT(iCornerBest >= 0 && iCornerBest <= 3); uint32 iCornerOpposite; switch ( iCornerBest ) { case 0: iCornerOpposite = 3; break; case 1: iCornerOpposite = 2; break; case 2: iCornerOpposite = 1; break; case 3: iCornerOpposite = 0; break; } // Extend towards opposite corner slightly LTVector vOffset = avCorners[iCornerOpposite] - avCorners[iCornerBest]; vOffset.Norm(); vOffset *= 50.0f; *pvScatterPosition = avCorners[iCornerBest] + vOffset; return LTTRUE; } // No - so look into all the neighbors (only 1 deep!) if ( !bNeighbor ) { for ( int32 iNeighbor = 0 ; iNeighbor < pVolume->GetNumNeighbors() ; iNeighbor++ ) { int32 iVolume = pVolume->GetNeighborByIndex(iNeighbor)->GetIndex(); if ( FindDangerScatterPosition(&m_aVolumes[iVolume], vAIPos, vDangerPos, fDangerDistanceSqr, pvScatterPosition, LTTRUE) ) { return LTTRUE; } } } return LTFALSE; }
//* // ----------------------------------------------------------------------- // // Returns the vector that the physics would have the object move by. // ----------------------------------------------------------------------- // void CalcMotion ( MotionInfo* pInfo, LTObject* pObj, //the object LTVector& dr, //displacement LTVector& v, //velocity LTVector& a, //acceleration const bool bApplyGravity, const float dt //time step ) { LTVector velocityDelta, accelDelta; LTVector q, slopeVel, slopeAccel, vel; const LTVector *n; LTVector objectNormal, vTemp, vTemp2; float fExp; float timeIntegral; float velocityMagSqr, accelMagSqr; LTBOOL bFriction; bFriction = LTFALSE; timeIntegral = dt * dt * 0.5f; velocityMagSqr = v.MagSqr(); accelMagSqr = a.MagSqr(); // [KLS - 3/12/02] - Added support for per-object force override... LTVector vForce = pObj->GetGlobalForceOverride(); // If the global force override is zero, use the MotionInfo force... if (LTVector(0.0, 0.0, 0.0) == vForce) { vForce = pInfo->m_Force; } /* // Debug variables LTVector vOldAccel, vOldVel, vOldPos; vOldAccel = a; vOldVel = v; vOldPos = pObj->GetPos(); //*/ // Stop objects that are moving very slowly... if(velocityMagSqr < 0.1f ) { v.Init(); velocityMagSqr = 0; } if( accelMagSqr < 0.1f ) { a.Init(); accelMagSqr = 0; } // Zero out the displacement to start with. dr.Init(); // Update objects affected by gravity... if(bApplyGravity) { // Add friction to objects standing on something... if(pObj->m_pStandingOn) { // Try to disable their physics. if( velocityMagSqr < 0.1f && accelMagSqr < 0.1f ) { pObj->m_Velocity.Init(); pObj->m_Acceleration.Init(); pObj->m_InternalFlags &= ~IFLAG_APPLYPHYSICS; return; } else { // Check if object on world geometry... if( pObj->m_pNodeStandingOn ) { // Calculate vector parallel to plane... n = &pObj->m_pNodeStandingOn->GetPlane()->m_Normal; } else { // Object standing on another object, so assume opposite to gravity... n = &objectNormal; objectNormal = -pInfo->m_UnitForce; } // Calculate the acceleration including the force LTVector vAccelWithForce = a + vForce; // If we're on a slope that's at enough of an angle, allow it to slide LTVector vForceDir = vForce; vForceDir.Norm(); if (vForceDir.Dot(*n) > pInfo->m_SlideRatio) { float fAccelMag = vAccelWithForce.Mag(); a = vAccelWithForce - *n * n->Dot(vAccelWithForce); // Don't allow it to accelerate up the slope.. float fAccelDotForce = a.Dot(vForceDir); if (fAccelDotForce < 0.0f) { a -= vForceDir * fAccelDotForce; } a.Norm(fAccelMag); // dsi_ConsolePrint("Steep"); } else { // Figure out what our new velocity would be if only the force was used (i.e. are they jumping?) LTVector vNewVel = v + vForce * dt; // If we're going to be moving away from the plane, use the full force if (vNewVel.Dot(*n) > 0.01f) { a = vAccelWithForce; // dsi_ConsolePrint("Jump"); } // If the acceleration without the force isn't moving into the surface, project it there else if (a.Dot(*n) > 0.01f) { float fAccelMag = a.Mag(); a -= *n * (n->Dot(a) + 1.0f); a.Norm(fAccelMag); bFriction = LTTRUE; // dsi_ConsolePrint("Downhill"); } else { bFriction = LTTRUE; // dsi_ConsolePrint("Walk"); } } } } // Otherwise just apply gravity else { a += vForce; // dsi_ConsolePrint("Fall"); } } // If there's no gravity and they aren't moving, then disable their physics else if( velocityMagSqr < 0.1f && accelMagSqr < 0.1f ) { pObj->m_Velocity.Init(); pObj->m_Acceleration.Init(); pObj->m_InternalFlags &= ~IFLAG_APPLYPHYSICS; return; } // If friction // new velocity is given by: v = ( a / k ) + ( v_0 - a / k ) * exp( -k * t ) // new position is given by: x = x_0 + ( a / k ) * t + ( k * v_0 - a ) * ( 1 - exp( -k * t )) / k^2 if( bFriction && pObj->m_FrictionCoefficient > 0.0f ) { // Velocity... fExp = ( float )exp( -pObj->m_FrictionCoefficient * dt ); vTemp = a / pObj->m_FrictionCoefficient; vTemp2 = v - vTemp; vTemp2 *= fExp; vel = vTemp2 + vTemp; // Position delta... dr = vTemp * dt; vTemp = v * pObj->m_FrictionCoefficient; vTemp -= a; vTemp *= (( 1.0f - fExp ) / pObj->m_FrictionCoefficient / pObj->m_FrictionCoefficient); dr += vTemp; pObj->m_Velocity = vel; v = pObj->m_Velocity; } // If no friction // new velocity is given by: v = v_0 + a * t // new position is given by: x = x_0 + v_0 * t + .5 * a * t^2 else { // Find the change in velocity... velocityDelta = a * dt; // Position delta... dr = v * dt; vTemp = a * (timeIntegral * 0.5f); dr += vTemp; // Add the final velocity to the new velocity. pObj->m_Velocity += velocityDelta; v = pObj->m_Velocity; } /* // Show debug information, filtering out the server-side player object if(bApplyGravity) { dsi_ConsolePrint("Old - A:<%7.1f,%7.1f,%7.1f> V:<%7.1f,%7.1f,%7.1f> P:<%7.1f,%7.1f,%7.1f>", VEC_EXPAND(vOldAccel), VEC_EXPAND(vOldVel), VEC_EXPAND(vOldPos)); LTVector vNewAccel, vNewVel, vNewPos; vNewAccel = a; vNewVel = v; vNewPos = vOldPos + dr; dsi_ConsolePrint("New - A:<%7.1f,%7.1f,%7.1f> V:<%7.1f,%7.1f,%7.1f> P:<%7.1f,%7.1f,%7.1f>", VEC_EXPAND(vNewAccel), VEC_EXPAND(vNewVel), VEC_EXPAND(vNewPos)); } //*/ return; }
void RenderPolyTrail(ILTClient *pClientDE, CLinkList<TRAIL_SECTION> *pList, HOBJECT hCamera, float fTrailWidth, uint8 r, uint8 g, uint8 b, uint8 a, HTEXTURE hTexture, uint32 dwExtraFlags) { CLinkListNode<TRAIL_SECTION> *pNode = pList->GetHead(); // Transform the path LTMatrix mCam = GetCamTransform(pClientDE, hCamera); while (pNode) { MatVMul(&pNode->m_Data.m_vTran, &mCam, &pNode->m_Data.m_vPos); pNode = pNode->m_pNext; } // Do some precalculations pNode = pList->GetHead(); float fCurU = 0.0f; while (pNode) { LTVector vBisector; vBisector.z = 0.0f; // Compute the midpoint vectors if (pNode == pList->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 == pList->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 x2 = vStart.y - vPrev.y; float y2 = -(vStart.x - vPrev.x); vBisector.x = (x1 + x2) / 2.0f; vBisector.y = (y1 + y2) / 2.0f; } vBisector.Norm(fTrailWidth); pNode->m_Data.m_vBisector = vBisector; pNode->m_Data.m_red = r; pNode->m_Data.m_green = g; pNode->m_Data.m_blue = b; pNode->m_Data.m_alpha = a; pNode = pNode->m_pNext; } pNode = pList->GetHead(); if (pList->GetSize() < 2) return; pNode = pList->GetHead(); ILTDrawPrim *pDrawPrimLT; pDrawPrimLT = pClientDE->GetDrawPrim(); pDrawPrimLT->SetTexture(hTexture); pDrawPrimLT->SetTransformType(DRAWPRIM_TRANSFORM_CAMERA); pDrawPrimLT->BeginDrawPrim(); if (g_bAppFocus) { uint32 nTris = 0; uint32 nVerts = 0; LT_POLYGT3 *pTri = g_pTris; LTVector *pVerts = g_pVerts; while (pNode->m_pNext) { LTVector vStart = pNode->m_Data.m_vTran; LTVector vEnd = pNode->m_pNext->m_Data.m_vTran; LTVector vBisector1 = pNode->m_Data.m_vBisector; LTVector vBisector2 = pNode->m_pNext->m_Data.m_vBisector; *pVerts ++ = vStart + vBisector1; *pVerts ++ = vEnd + vBisector2; *pVerts ++ = vEnd - vBisector2; *pVerts ++ = vStart - vBisector1; uint8 r1 = pNode->m_Data.m_red; uint8 g1 = pNode->m_Data.m_green; uint8 b1 = pNode->m_Data.m_blue; uint8 a1 = pNode->m_Data.m_alpha; float u1 = pNode->m_Data.m_uVal; uint8 r2 = pNode->m_pNext->m_Data.m_red; uint8 g2 = pNode->m_pNext->m_Data.m_green; uint8 b2 = pNode->m_pNext->m_Data.m_blue; uint8 a2 = pNode->m_pNext->m_Data.m_alpha; float u2 = pNode->m_pNext->m_Data.m_uVal; SetupVert(pTri, 0, g_pVerts[nVerts].x, g_pVerts[nVerts].y, g_pVerts[nVerts].z, r1, g1, b1, a1, u1, 0.0f); SetupVert(pTri, 1, g_pVerts[nVerts + 1].x, g_pVerts[nVerts + 1].y, g_pVerts[nVerts + 1].z, r2, g2, b2, a2, u2, 1.0f); SetupVert(pTri, 2, g_pVerts[nVerts + 2].x, g_pVerts[nVerts + 2].y, g_pVerts[nVerts + 2].z, r2, g2, b2, a2, u2, 1.0f); pTri ++; nTris ++; SetupVert(pTri, 0, g_pVerts[nVerts].x, g_pVerts[nVerts].y, g_pVerts[nVerts].z, r1, g1, b1, a1, u1, 0.0f); SetupVert(pTri, 1, g_pVerts[nVerts + 2].x, g_pVerts[nVerts + 2].y, g_pVerts[nVerts + 2].z, r2, g2, b2, a2, u2, 1.0f); SetupVert(pTri, 2, g_pVerts[nVerts + 3].x, g_pVerts[nVerts + 3].y, g_pVerts[nVerts + 3].z, r1, g1, b1, a1, u1, 0.0f); pTri ++; nTris ++; nVerts += 4; pNode = pNode->m_pNext; //see if we need to flush our buffer if(nTris >= MAX_BUFFER_TRIS - 2) { pDrawPrimLT->DrawPrim(g_pTris, nTris); nTris = 0; } } // Draw the polylist if(nTris > 0) { pDrawPrimLT->DrawPrim(g_pTris, nTris); nTris = 0; } } pDrawPrimLT->BeginDrawPrim(); }
bool CLTBBouncyChunkFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps) { // Perform base class initialisation if (!CBaseFX::Init(pClientDE, pBaseData, pProps)) return false; LTVector vChunkDir = GetProps()->m_vChunkDir; if (pBaseData->m_bUseTargetData) { vChunkDir = pBaseData->m_vTargetNorm; } LTVector vPos; LTRotation rRot; if (m_hParent) { m_pLTClient->GetObjectPos(m_hParent, &vPos); m_pLTClient->GetObjectRotation(m_hParent, &rRot); } else { vPos = m_vCreatePos; rRot = m_rCreateRot; } float scale; CalcScale(m_tmElapsed, GetProps()->m_tmLifespan, &scale); LTVector vScale(scale, scale, scale); ObjectCreateStruct ocs; INIT_OBJECTCREATESTRUCT(ocs); ocs.m_ObjectType = OT_MODEL; ocs.m_Flags = FLAG_NOLIGHT | FLAG_VISIBLE; ocs.m_Pos = vPos + GetProps()->m_vOffset; ocs.m_Rotation = rRot; ocs.m_Scale = vScale; strcpy(ocs.m_Filename, GetProps()->m_sModelName); strcpy(ocs.m_SkinName, GetProps()->m_sSkinName); m_hBouncyChunk = m_pLTClient->CreateObject(&ocs); // Setup an initial vector for the velocity LTVector vOther; vOther.x = 1.0f; vOther.y = 0.0f; vOther.z = 1.0f; vOther.Norm(); LTVector vRight = vChunkDir.Cross(vOther); LTVector vUp = vRight.Cross(vOther); m_vVel = vRight * (-GetProps()->m_fChunkSpread + (float)(rand() % (int)(GetProps()->m_fChunkSpread * 2.0f))); m_vVel += vUp * (-GetProps()->m_fChunkSpread + (float)(rand() % (int)(GetProps()->m_fChunkSpread * 2.0f))); m_vVel += vChunkDir * GetProps()->m_fChunkSpeed; m_vVel.Norm(GetProps()->m_fChunkSpeed); // Create the base object CreateDummyObject(); // Success !! return true; }
void CAIVolumeNeighbor::Init(CAIVolume* pThis, CAIVolume* pNeighbor) { m_iVolume = pNeighbor->GetIndex(); // Compute the 2d intersection of the two volumes, and compute important // things about the geometry of the connection LTVector vFrontLeft(0,0,0); LTVector vFrontRight(0,0,0); LTVector vBackLeft(0,0,0); LTVector vBackRight(0,0,0); vFrontLeft.x = Max<LTFLOAT>(pThis->GetFrontTopLeft().x, pNeighbor->GetFrontTopLeft().x); vFrontLeft.z = Min<LTFLOAT>(pThis->GetFrontTopLeft().z, pNeighbor->GetFrontTopLeft().z); vFrontRight.x = Min<LTFLOAT>(pThis->GetFrontTopRight().x, pNeighbor->GetFrontTopRight().x); vFrontRight.z = Min<LTFLOAT>(pThis->GetFrontTopRight().z, pNeighbor->GetFrontTopRight().z); vBackLeft.x = Max<LTFLOAT>(pThis->GetBackTopLeft().x, pNeighbor->GetBackTopLeft().x); vBackLeft.z = Max<LTFLOAT>(pThis->GetBackTopLeft().z, pNeighbor->GetBackTopLeft().z); vBackRight.x = Min<LTFLOAT>(pThis->GetBackTopRight().x, pNeighbor->GetBackTopRight().x); vBackRight.z = Max<LTFLOAT>(pThis->GetBackTopRight().z, pNeighbor->GetBackTopRight().z); // We know connection position (the center of the intersection) easily. m_vConnectionPos = (vFrontLeft+vFrontRight+vBackLeft+vBackRight)/4.0f; // We need y for vertical movement #define _A_b pThis->GetFrontBottomRight().y #define _A_t pThis->GetFrontTopRight().y #define _B_b pNeighbor->GetFrontBottomRight().y #define _B_t pNeighbor->GetFrontTopRight().y if ( (_A_t >= _B_t) && (_A_t >= _B_b) && (_A_b >= _B_t) && (_A_b >= _B_b) ) { m_vConnectionPos.y = _A_b; // or _B_t } else if ( (_A_t <= _B_t) && (_A_t <= _B_b) && (_A_b <= _B_t) && (_A_b <= _B_b) ) { m_vConnectionPos.y = _A_t; // or _B_b } else if ( (_A_t >= _B_t) && (_A_t >= _B_b) && (_A_b <= _B_t) && (_A_b >= _B_b) ) { m_vConnectionPos.y = (_A_b + _B_t)/2.0f; } else if ( (_A_t <= _B_t) && (_A_t >= _B_b) && (_A_b <= _B_t) && (_A_b <= _B_b) ) { m_vConnectionPos.y = (_A_t + _B_b)/2.0f; } else if ( (_A_t >= _B_t) && (_A_t >= _B_b) && (_A_b <= _B_t) && (_A_b <= _B_b) ) { m_vConnectionPos.y = (_B_b + _B_t)/2.0f; } else if ( (_A_t <= _B_t) && (_A_t >= _B_b) && (_A_b <= _B_t) && (_A_b >= _B_b) ) { m_vConnectionPos.y = (_A_b + _A_t)/2.0f; } else { m_vConnectionPos.y = -float(INT_MAX); DANGER(g_pLTServer, blong); } // Find the endpoints of the line across the connection, and the vector perpendicular to this if ( pThis->Inside(pNeighbor->GetFrontTopLeft()) || pThis->Inside(pNeighbor->GetBackTopRight()) || pThis->Inside(pNeighbor->GetFrontBottomLeft()) || pThis->Inside(pNeighbor->GetBackBottomRight()) ) { m_avConnectionEndpoints[0] = vFrontRight + LTVector(0, m_vConnectionPos.y, 0); m_avConnectionEndpoints[1] = vBackLeft + LTVector(0, m_vConnectionPos.y, 0); m_vConnectionPerpDir = vFrontRight - vBackLeft; m_vConnectionDir = m_avConnectionEndpoints[1] - m_avConnectionEndpoints[0]; m_vConnectionDir.y = 0.0f; m_fConnectionLength = VEC_MAG(m_vConnectionDir); m_vConnectionDir.Norm(); } else { m_avConnectionEndpoints[0] = vFrontLeft + LTVector(0, m_vConnectionPos.y, 0); m_avConnectionEndpoints[1] = vBackRight + LTVector(0, m_vConnectionPos.y, 0); m_vConnectionPerpDir = vFrontLeft - vBackRight; m_vConnectionDir = m_avConnectionEndpoints[1] - m_avConnectionEndpoints[0]; m_vConnectionDir.y = 0.0f; m_fConnectionLength = VEC_MAG(m_vConnectionDir); m_vConnectionDir.Norm(); } LTFLOAT fTemp = m_vConnectionPerpDir[0]; m_vConnectionPerpDir[0] = m_vConnectionPerpDir[2]; m_vConnectionPerpDir[2] = fTemp; m_vConnectionPerpDir.Norm(); // Make sure it points into this volume LTVector vThisCenter = (pThis->GetFrontTopLeft()+pThis->GetBackTopRight())/2.0f; LTVector vThisCenterDir = vThisCenter - m_vConnectionPos; vThisCenterDir.y = 0; vThisCenterDir.Norm(); if ( vThisCenterDir.Dot(m_vConnectionPerpDir) < 0.0f ) { m_vConnectionPerpDir = -m_vConnectionPerpDir; } // g_pLTServer->CPrint("cxn @ %f,%f,%f in %f,%f,%f : %f,%f,%f", // EXPANDVEC(m_vConnectionPos), EXPANDVEC(vThisCenter), EXPANDVEC(m_vConnectionPerpDir)); }
void CAIHelicopterStrategyShoot::UpdateFiring(CWeapon* pWeapon, BURSTSTRUCT* pBurst) { // Get our fire position LTVector vFirePos = GetAI()->GetAttachmentPosition(pWeapon->GetModelObject()); LTRotation rFireRot = GetAI()->GetAttachmentRotation(pWeapon->GetModelObject()); LTVector vFireRight, vFireUp, vFireForward; g_pMathLT->GetRotationVectors(rFireRot, vFireUp, vFireRight, vFireForward); // Get target's position LTVector vTargetPos; g_pLTServer->GetObjectPos(m_hTarget, &vTargetPos); // Get our firing vector LTVector vFireDir = vTargetPos - vFirePos; vFireDir.Norm(); // Make sure it's in our field of firce LTFLOAT fDp = vFireDir.Dot(vFireForward); // g_pLTServer->CPrint("fireangle = %f", (acos(fDp)/MATH_PI)*180.0f); if ( fDp <= c_fFOV90 ) { Aim(pWeapon, pBurst); return; } // Now fire the weapon WFireInfo fireInfo; fireInfo.hFiredFrom = GetAI()->GetObject(); fireInfo.vPath = vFireDir; fireInfo.vFirePos = vFirePos; fireInfo.vFlashPos = vFirePos; fireInfo.hTestObj = m_hTarget; fireInfo.fPerturbR = 4.0f*(1.0f - GetAI()->GetAccuracy()); fireInfo.fPerturbU = 4.0f*(1.0f - GetAI()->GetAccuracy()); pWeapon->UpdateWeapon(fireInfo, LTTRUE); // Decrement our burst counter and update the last ammo count pBurst->m_nBurstShots -= Max<int>(0, pBurst->m_nLastAmmoInClip - pWeapon->GetAmmoInClip()); pBurst->m_nLastAmmoInClip = pWeapon->GetAmmoInClip(); if ( pBurst->m_nBurstShots <= 0 ) { // We just finished our burst. Start waiting. CalculateBurst(pWeapon, pBurst); // And just aim. Aim(pWeapon, pBurst); } else { // Keep firing Fire(pWeapon, pBurst); } }
LTBOOL CAIMovementHelicopter::Update() { LTFLOAT fTimeDelta = g_pLTServer->GetFrameTime(); switch ( m_eState ) { case eStateUnset: { } break; case eStateSet: { // Find our unit movement vector LTVector vMove = m_vDest - GetAI()->GetPosition(); // vMove.y = 0.0f; // See if we'll overshoot our LTFLOAT fRemainingDist = vMove.Mag(); LTFLOAT fMoveDist; fMoveDist = GetAI()->GetSpeed()*fTimeDelta; vMove.Norm(); LTBOOL bCrossed = LTFALSE; // See if we crossed the dest plane if ( (vMove.Dot(m_vDestDir) < 0.0f) ) { bCrossed = LTTRUE; } // If we'd overshoot our destination, just move us there if ( (fRemainingDist < fMoveDist) || bCrossed ) { fMoveDist = fRemainingDist; m_eState = eStateDone; } // Scale based on our movement distance vMove *= fMoveDist; // Calculate our new position LTVector vNewPos = GetAI()->GetPosition() + vMove; // Move us - this is an expensive call // GetAI()->Move(vNewPos); // Face us in the right direction GetAI()->FacePos(vNewPos); } break; case eStateDone: { } break; } return LTTRUE; }
LTBOOL CAIMovementHuman::Update() { LTFLOAT fTimeDelta = g_pLTServer->GetFrameTime(); switch ( m_eState ) { case eStateUnset: { } break; case eStateSet: { // Set our speed based on our movement type if ( GetAI()->GetAnimationContext()->IsPropSet(aniWalk) ) { GetAI()->Walk(); } else if ( GetAI()->GetAnimationContext()->IsPropSet(aniRun) ) { GetAI()->Run(); } else if ( GetAI()->GetAnimationContext()->IsPropSet(aniSwim) ) { GetAI()->Swim(); } else { // We're not moving yet... GetAI()->Stop(); } // Find our unit movement vector LTVector vMove = m_vDest - GetAI()->GetPosition(); if ( !m_bUnderwater ) { vMove.y = 0.0f; } // See if we'll overshoot our LTFLOAT fRemainingDist = vMove.Mag(); LTFLOAT fMoveDist; fMoveDist = GetAI()->GetSpeed()*fTimeDelta; // If we'd overshoot our destination, just move us there if ( fRemainingDist < fMoveDist ) { fMoveDist = fRemainingDist; m_eState = eStateDone; } // Scale based on our movement distance vMove.Norm(); vMove *= fMoveDist; // Calculate our new position LTVector vNewPos = GetAI()->GetPosition() + vMove; // Move us - this is an expensive call GetAI()->Move(vNewPos); // Face us in the right direction GetAI()->FacePos(vNewPos); } break; case eStateDone: { } break; } return LTTRUE; }
void CNodeController::HandleNodeControlRecoilMessage(HMESSAGEREAD hMessage) { if ( m_cRecoils >= MAX_RECOILS ) return; m_fRecoilTimers[m_cRecoils++] = 0.50f; ModelNode eModelNode; eModelNode = (ModelNode)g_pLTClient->ReadFromMessageByte(hMessage); LTVector vRecoilDir; g_pLTClient->ReadFromMessageCompVector(hMessage, &vRecoilDir); // Get the magnitude of the recoil vector LTFLOAT fRecoilMag = VEC_MAGSQR(vRecoilDir); // Get the unit impact/recoil vector vRecoilDir /= (float)sqrt(fRecoilMag); // Cap it if necessary if ( fRecoilMag > 100.0f ) { fRecoilMag = 100.0f; } // Get the position of the impact NSTRUCT* pNode = &m_aNodes[eModelNode]; ILTModel* pModelLT = g_pLTClient->GetModelLT(); LTransform transform; pModelLT->GetNodeTransform(GetCFX()->GetServerObj(), pNode->hModelNode, transform, LTTRUE); // Decompose the transform into the position and rotation LTVector vPos; ILTTransform* pTransformLT = g_pLTClient->GetTransformLT(); pTransformLT->GetPos(transform, vPos); LTVector vRecoilPos = vPos; // Add angular rotations up the recoil parent chain ModelNode eModelNodeCurrent = g_pModelButeMgr->GetSkeletonNodeRecoilParent(GetCFX()->GetModelSkeleton(), eModelNode); while ( eModelNodeCurrent != eModelNodeInvalid ) { // Get the rotation of the node NSTRUCT* pNode = &m_aNodes[eModelNodeCurrent]; LTransform transform; ILTModel* pModelLT = g_pLTClient->GetModelLT(); // Get the transform of the node we're controlling pModelLT->GetNodeTransform(GetCFX()->GetServerObj(), pNode->hModelNode, transform, LTTRUE); ILTTransform* pTransformLT = g_pLTClient->GetTransformLT(); // Decompose the transform into the position and rotation LTVector vPos; LTRotation rRot; pTransformLT->Get(transform, vPos, rRot); // Get the rotation vectors of the transform LTVector vRight, vUp, vForward; g_pLTClient->GetRotationVectors(&rRot, &vUp, &vRight, &vForward); // Cross the right vector with the impact vector to get swing LTVector vRotationAxis = vRight.Cross(vRecoilDir); vRotationAxis.Norm(); // Add the timed rotation control for the swing // !!! HACK // !!! Do not add swing if this is a leg node if ( !strstr(g_pModelButeMgr->GetSkeletonNodeName(GetCFX()->GetModelSkeleton(), eModelNodeCurrent), "leg") ) AddNodeControlRotationTimed(eModelNodeCurrent, vRotationAxis, MATH_PI/1000.0f*fRecoilMag, 0.50f); // Use the right vector to get twist, but make sure the sign is correct based on location // of impact and whether we're getting shot at from behind/front etc vRotationAxis = vRight; vRotationAxis.Norm(); // Get the twist LTVector vSideDir = vRecoilPos-vPos; vSideDir.Norm(); LTFLOAT fSign = vUp.Dot(vRecoilDir); fSign *= vForward.Dot(vSideDir); if ( fSign > 0.0f ) { vRotationAxis = -vRotationAxis; } // Add the timed rotation control for the twist // AddNodeControlRotationTimed(eModelNodeCurrent, vRotationAxis, MATH_PI/1000.0f*fRecoilMag, 0.50f); // Decrease the magnitude fRecoilMag /= 2.0f; eModelNodeCurrent = g_pModelButeMgr->GetSkeletonNodeRecoilParent(GetCFX()->GetModelSkeleton(), eModelNodeCurrent); } }
void CAIBrain::GetDodgeStatus(DodgeStatus* peDodgeStatus, Direction* peDirection, DodgeAction* peDodgeAction, uint32* pdwNode) { if ( !GetAI()->HasTarget() || !GetAI()->HasLastVolume() ) { *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusOk; return; } if ( g_pLTServer->GetTime() >= m_fDodgeStatusCheckTimeVector ) { m_fDodgeStatusCheckTimeVector = g_pLTServer->GetTime() + LOWER_BY_DIFFICULTY(m_pBrain->fDodgeVectorCheckTime); if ( GetRandom(0.0f, 1.0f) <= RAISE_BY_DIFFICULTY(m_pBrain->fDodgeVectorCheckChance) ) { if ( GetAI()->GetTarget()->IsVisiblePartially() ) { CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(GetAI()->GetTarget()->GetObject()); if ( pCharacter->HasDangerousWeapon() ) { LTRotation rRot; LTVector vNull, vForward; g_pLTServer->GetObjectRotation(GetAI()->GetTarget()->GetObject(), &rRot); g_pMathLT->GetRotationVectors(rRot, vNull, vNull, vForward); LTVector vDir; vDir = GetAI()->GetPosition() - GetAI()->GetTarget()->GetPosition(); vDir.y = 0; vDir.Norm(); // TODO: bute this const static LTFLOAT fThreshhold = 0.95f; if ( (vDir.Dot(vForward) > fThreshhold) && (GetAI()->GetForwardVector().Dot(vForward) < -fThreshhold) ) { LTFLOAT fCheckDistance; LTFLOAT fRandom = GetRandom(0.0f, 1.0f); if ( fRandom > m_pBrain->fDodgeVectorCoverChance ) { if ( fRandom > (m_pBrain->fDodgeVectorCoverChance + m_pBrain->fDodgeVectorRollChance) ) { *peDodgeAction = eDodgeActionShuffle; fCheckDistance = 109.0f; } else { *peDodgeAction = eDodgeActionRoll; fCheckDistance = 140.0f; } // MAKE SURE WE WON'T DODGE OUT OF THE VOLUME if ( GetAI()->GetLastVolume()->Inside2d(GetAI()->GetPosition()+GetAI()->GetRightVector()*fCheckDistance, GetAI()->GetRadius()) ) { *peDirection = eDirectionRight; *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusVector; return; } else if ( GetAI()->GetLastVolume()->Inside2d(GetAI()->GetPosition()-GetAI()->GetRightVector()*fCheckDistance, GetAI()->GetRadius()) ) { *peDirection = eDirectionLeft; *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusVector; return; } else { *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusOk; return; } } else { CAINode* pNode = g_pAINodeMgr->FindNearestCoverFromThreat(GetAI()->GetPosition(), GetAI()->GetTarget()->GetObject()); if ( pNode ) { *peDodgeAction = eDodgeActionCover; *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusVector; *pdwNode = pNode->GetID(); } else { *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusOk; } return; } } } } } } if ( g_pLTServer->GetTime() >= m_fDodgeStatusCheckTimeProjectile ) { m_fDodgeStatusCheckTimeProjectile = g_pLTServer->GetTime() + RAISE_BY_DIFFICULTY(m_pBrain->fDodgeProjectileCheckTime); if ( GetRandom(0.0f, 1.0f) <= RAISE_BY_DIFFICULTY(m_pBrain->fDodgeProjectileCheckChance) ) { CGrenade* pGrenade; if ( FindGrenadeDangerPosition(GetAI()->GetPosition(), 40000.0f, &m_vDodgeProjectilePosition, &pGrenade) ) { FREE_HSTRING(m_hstrDodgeProjectileName); // $STRING m_hstrDodgeProjectileName = g_pLTServer->CreateString(g_pLTServer->GetObjectName(pGrenade->m_hObject)); *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusProjectile; *peDodgeAction = eDodgeActionFlee; return; } } } *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusOk; return; }
bool CLTBBouncyChunkFX::Update(float tmFrameTime) { // Base class update first if (!CBaseFX::Update(tmFrameTime)) return false; if ((m_hImpactSound) && (m_pLTClient->IsDone(m_hImpactSound))) { m_pLTClient->SoundMgr()->KillSound(m_hImpactSound); m_hImpactSound = NULL; } // Set the object scale LTVector vScale(m_scale, m_scale, m_scale); m_pLTClient->SetObjectScale(m_hBouncyChunk, &vScale); LTVector vCur; m_pLTClient->GetObjectPos(m_hBouncyChunk, &vCur); // Compute the new position of the chunk LTVector vNew = vCur; vNew += m_vVel * tmFrameTime; m_vVel += GetProps()->m_vGravity * tmFrameTime; // Move the object and collide against the world ClientIntersectQuery ciq; ClientIntersectInfo cii; ciq.m_From = vCur; ciq.m_To = vNew; if (m_pLTClient->IntersectSegment(&ciq, &cii)) { vNew = cii.m_Point + cii.m_Plane.m_Normal; vCur = vNew; // Compute the reflected velocity LTVector N = cii.m_Plane.m_Normal; LTVector L = m_vVel; L.x = -L.x; L.y = -L.y; L.z = -L.z; LTVector vReflected = N * 2.0f; vReflected *= (N.Dot(L)); vReflected -= L; vReflected.Norm(); vReflected *= (m_vVel.Mag() * 0.7f); m_vVel = vReflected; const char *sImpactSound = GetProps()->m_sImpactSound; if (sImpactSound[0] != '.') { // Play the bounce sound PlaySoundInfo psi; memset(&psi, 0, sizeof(PlaySoundInfo)); psi.m_dwFlags = PLAYSOUND_GETHANDLE | PLAYSOUND_CTRL_VOL | PLAYSOUND_CLIENT | PLAYSOUND_TIME | PLAYSOUND_3D | PLAYSOUND_REVERB; psi.m_nVolume = 50; strcpy(psi.m_szSoundName, GetProps()->m_sImpactSound); psi.m_nPriority = 0; psi.m_vPosition = m_vPos; psi.m_fInnerRadius = 100; psi.m_fOuterRadius = 300; if (!m_hImpactSound) { if (m_pLTClient->SoundMgr()->PlaySound(&psi, m_hImpactSound) == LT_OK) { m_hImpactSound = psi.m_hSound; } } } } m_pLTClient->SetObjectPos(m_hBouncyChunk, &vNew); m_pLTClient->SetObjectColor(m_hBouncyChunk, m_red, m_green, m_blue, m_alpha); m_pLTClient->SetObjectPos(m_hObject, &vNew); // Success !! return true; }
void CNudge::Update(LTBOOL bMoving) { m_eState = eStateNoNudge; // If we're moving or high priority, then we don't need to worry about nudging if ( bMoving || (m_ePriority == ePriorityHigh) ) { return; } LTVector vPos = m_pAI->GetPosition(); LTFLOAT fRadius = m_pAI->GetRadius(); /* // If we're not inside our volume, don't nudge if ( !m_pAI->GetLastVolume() || !m_pAI->GetLastVolume()->Inside2d(vPos, fRadius) ) { return; } */ HOBJECT hPlayer = LTNULL; CAIHuman* apAIs[64]; uint32 cAIs = 0; static HCLASS hClass = g_pLTServer->GetClass("CAIHuman"); ObjectList* pObjectList = g_pLTServer->FindObjectsTouchingSphere(&vPos, fRadius); ObjectLink* pObject = pObjectList ? pObjectList->m_pFirstLink : LTNULL; while ( pObject && cAIs < 64 ) { HOBJECT hObject = pObject->m_hObject; if ( hObject != m_pAI->m_hObject ) { if ( IsPlayer(hObject) ) { hPlayer = hObject; } else if ( g_pLTServer->IsKindOf(g_pLTServer->GetObjectClass(hObject), hClass) ) { apAIs[cAIs++] = (CAIHuman*)g_pLTServer->HandleToObject(hObject); } } pObject = pObject->m_pNext; } if ( pObjectList ) { g_pLTServer->RelinquishList(pObjectList); } if ( cAIs == 0 ) return; m_eState = eStateNudge; m_vNudge = LTVector(0,0,0); if ( hPlayer ) { LTVector vPlayerPosition; g_pLTServer->GetObjectPos(hPlayer, &vPlayerPosition); LTVector vNudgeDir = m_pAI->GetPosition()-vPlayerPosition; vNudgeDir.y = 0.0f; vNudgeDir.Norm(); m_vNudge += vNudgeDir*64.0f*g_pLTServer->GetFrameTime(); } for ( uint32 iAI = 0 ; iAI < cAIs ; iAI++ ) { CAIHuman* pAI = apAIs[iAI]; CNudge* pNudge = pAI->GetNudge(); LTVector vNudgeDir; LTFLOAT fNudgeAmount; if ( pNudge->GetPriority() == ePriorityLow ) { fNudgeAmount = 24.0f; vNudgeDir = m_pAI->GetPosition()-pAI->GetPosition(); vNudgeDir.y = 0.0f; vNudgeDir.Norm(); } else // if ( pNudge->GetPriority() == ePriorityHigh ) { fNudgeAmount = 48.0f; vNudgeDir = m_pAI->GetPosition()-pAI->GetPosition(); vNudgeDir.y = 0.0f; vNudgeDir.Norm(); } m_vNudge += vNudgeDir*fNudgeAmount*g_pLTServer->GetFrameTime(); } _ASSERT((LTFLOAT)fabs(m_vNudge.y < MATH_EPSILON)); }