DBOOL Prophet::Fire(DBOOL bAltFire) { DBOOL bFire = DFALSE; CWeapon* pW = m_InventoryMgr.GetCurrentWeapon(); if(pW == DNULL) { SetNewState(STATE_Idle); return DFALSE; } DVector vTargetVel, vVel; m_pServerDE->GetVelocity(m_hTarget, &vTargetVel); m_pServerDE->GetVelocity(m_hObject, &vVel); DFLOAT fTargetVel = VEC_MAG(vTargetVel); DFLOAT fVel = VEC_MAG(vVel); if(fTargetVel <= 5.0f && fVel <= 5.0f && pW->GetType() != WEAP_ASSAULTRIFLE && pW->GetType() != WEAP_NAPALMCANNON && pW->GetType() != WEAP_SNIPERRIFLE) { if(m_InventoryMgr.GetAmmoCount(pW->GetAmmoType(DFALSE)) >= pW->GetAltAmmoUse()) bFire = DTRUE; } // DDWORD m_nFiredWeapon = m_InventoryMgr.FireCurrentWeapon(&m_MoveObj.GetPos(), &m_MoveObj.GetRotation(), bFire); return AI_Mgr::Fire(bFire); }
void CDeathFX::CreateVehicleDeathFX() { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; GIBCREATESTRUCT gib; m_pClientDE->AlignRotation(&(gib.rRot), &m_vDir, LTNULL); LTFLOAT fDamage = VEC_MAG(m_vDir); VEC_COPY(gib.vPos, m_vPos); VEC_SET(gib.vMinVel, 50.0f, 100.0f, 50.0f); VEC_MULSCALAR(gib.vMinVel, gib.vMinVel, fDamage); VEC_SET(gib.vMaxVel, 100.0f, 200.0f, 100.0f); VEC_MULSCALAR(gib.vMaxVel, gib.vMaxVel, fDamage); gib.fLifeTime = 20.0f; gib.fFadeTime = 7.0f; gib.nGibFlags = 0; gib.bRotate = LTTRUE; gib.eModelId = m_eModelId; gib.eModelStyle = m_eModelStyle; gib.nCode = m_eCode; gib.bSubGibs = LTTRUE; SetupGibTypes(gib); psfxMgr->CreateSFX(SFX_GIB_ID, &gib); }
DBOOL CSmokeTrailFX::Update() { CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell(); CSFXMgr* psfxMgr = pShell->GetSFXMgr(); if (!psfxMgr || !m_pClientDE || !m_hServerObject) return DFALSE; DFLOAT fTime = m_pClientDE->GetTime(); // Check to see if we should go away... if (m_bWantRemove) { return DFALSE; } // See if it is time to create a new trail segment... if ((m_fStartTime < 0) || (fTime > m_fStartTime + m_fSegmentTime)) { STSCREATESTRUCT sts; sts.hServerObj = m_hServerObject; VEC_COPY(sts.vVel, m_vVel); VEC_COPY(sts.vColor1, m_vColor1); VEC_COPY(sts.vColor2, m_vColor2); sts.bSmall = m_bSmall; sts.fLifeTime = m_fLifeTime; sts.fFadeTime = m_fFadeTime; sts.fOffsetTime = m_fOffsetTime; sts.fRadius = 1000.0f; sts.fGravity = 15.0f; sts.nNumPerPuff = m_nNumPerPuff; if(VEC_MAG(sts.vVel) < 1.0f) { sts.fGravity = 25.0f; sts.fOffsetTime = 0.1f; sts.fRadius = 500.0f; sts.nNumPerPuff = 1; sts.fLifeTime = 1.0f; } CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_SMOKETRAILSEG_ID, &sts, DFALSE, this); // Let each smoke segment do its initial update... if (pFX) pFX->Update(); m_fStartTime = fTime; } return DTRUE; }
DBOOL CLaserBeamFX::UpdateBeam() { if(!m_pClientDE) return DFALSE; DVector vDist, vUp; DRotation rRot; VEC_SET(vUp, 0.0f, 1.0f, 0.0f); VEC_SUB(vDist, m_vDest, m_vSource); m_pClientDE->AlignRotation(&rRot, &vDist, &vUp); m_pClientDE->SetObjectPos(m_hObject, &m_vSource); m_pClientDE->SetObjectRotation(m_hObject, &rRot); VEC_SET(m_vScale, m_fMinScale, m_fMinScale, VEC_MAG(vDist)); return DTRUE; }
DBOOL CFlashlightFX::Update() { if (!m_pClientDE || m_bWantRemove || !m_hServerObject || !m_hObject) return DFALSE; DDWORD dwUsrFlags; m_pClientDE->GetObjectUserFlags(m_hServerObject, &dwUsrFlags); // Hidden if (!(dwUsrFlags & USRFLG_VISIBLE)) { m_pClientDE->SetObjectFlags(m_hObject, 0); } else { DRotation rRot; DVector vPos, vF, vR, vU; m_pClientDE->GetObjectRotation(m_hServerObject, &rRot); m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF); m_pClientDE->GetObjectPos(m_hServerObject, &vPos); // Cast a line to see where to put the light.. ClientIntersectQuery iQuery; ClientIntersectInfo iInfo; VEC_COPY(iQuery.m_From, vPos); VEC_COPY(iQuery.m_Direction, vF); iQuery.m_Flags = INTERSECT_OBJECTS; DFLOAT fDistance = 1000.0f; // Far, far, away... if (m_pClientDE->CastRay(&iQuery, &iInfo)) { // Place the light m_pClientDE->SetObjectPos(m_hObject, &iInfo.m_Point); // Calculate the distance VEC_SUB(vPos, vPos, iInfo.m_Point); fDistance = VEC_MAG(vPos); if (fDistance < 10.0f) fDistance = 10.0f; // The farther away, the brighter and bigger the light DFLOAT fRadius = fDistance * 0.40f; m_pClientDE->SetLightRadius(m_hObject, fRadius); // Determine the minimum intensity based on the current light level // (so we don't end up casting a dark light instead). DFLOAT fMinIntensity = 100.0f; DVector vColor; if (m_pClientDE->Common()->GetPointShade(&vPos, &vColor)) { if (vColor.x > fMinIntensity) fMinIntensity = vColor.x; if (vColor.y > fMinIntensity) fMinIntensity = vColor.y; if (vColor.z > fMinIntensity) fMinIntensity = vColor.z; } fMinIntensity = DCLAMP((fMinIntensity + 32), 0, 255); fMinIntensity /= 255.0f; DFLOAT fIntensity = (1000.0f - (fDistance/2.0f)) / 1000.0f; if (fIntensity < fMinIntensity) fIntensity = fMinIntensity; m_pClientDE->SetLightColor(m_hObject, fIntensity, fIntensity, fIntensity); m_pClientDE->SetObjectFlags(m_hObject, FLAG_VISIBLE); } else { m_pClientDE->SetObjectFlags(m_hObject, 0); } } return DTRUE; }
LTBOOL CBulletTrailFX::Update() { if (!m_hObject || !m_pClientDE) return LTFALSE; LTFLOAT fTime = m_pClientDE->GetTime(); if (m_bFirstUpdate) { // See if we can figure out what color bubbles to make, based on the // container we start in... HLOCALOBJ objList[1]; uint32 dwNum = m_pClientDE->GetPointContainers(&m_vStartPos, objList, 1); if (dwNum > 0 && objList[0]) { uint32 dwUserFlags; m_pClientDE->GetObjectUserFlags(objList[0], &dwUserFlags); if (dwUserFlags & USRFLG_VISIBLE) { uint16 dwCode; if (m_pClientDE->GetContainerCode(objList[0], &dwCode)) { GetLiquidColorRange((ContainerCode)dwCode, &m_vColor1, &m_vColor2); } } } // Move the particle system to the correct position... m_pClientDE->SetObjectPos(m_hObject, &m_vStartPos); m_bFirstUpdate = LTFALSE; m_fStartTime = fTime; m_fLastTime = fTime; VEC_INIT(m_vLastPos); // Find the end position... ClientIntersectQuery iQuery; ClientIntersectInfo iInfo; LTVector vTemp, vEndPoint; VEC_MULSCALAR(vTemp, m_vDir, MAX_TRAIL_LENGTH); VEC_ADD(vEndPoint, m_vStartPos, vTemp); VEC_COPY(iQuery.m_From, m_vStartPos); VEC_COPY(iQuery.m_To, vEndPoint); if (m_pClientDE->IntersectSegment(&iQuery, &iInfo)) { VEC_SUB(vEndPoint, iInfo.m_Point, m_vStartPos); m_fDistance = VEC_MAG(vEndPoint); } if (m_fDistance <= 0.0f || m_fFadeTime <= 0.0f) return LTFALSE; // Calculate the trail velocity... m_fTrailVel = m_fDistance / m_fFadeTime; VEC_MULSCALAR(m_vDir, m_vDir, m_fTrailVel); } // Check to see if we should just wait for last bubble to go away... if (fTime > m_fStartTime + m_fFadeTime) { if (fTime > m_fLastTime + m_fLifeTime) { return LTFALSE; } LTFLOAT fScale = (m_fLifeTime - (fTime - m_fLastTime)) / m_fLifeTime; // m_pClientDE->SetParticleSystemColorScale(m_hObject, fScale); LTFLOAT r, g, b, a; m_pClientDE->GetObjectColor(m_hObject, &r, &g, &b, &a); m_pClientDE->SetObjectColor(m_hObject, r, g, b, fScale); return LTTRUE; } // Create the necessary particles... LTFLOAT fTimeOffset = g_pGameClientShell->GetFrameTime(); // Calculate distance traveled this frame... LTFLOAT fDist = m_fTrailVel * fTimeOffset; if (fDist > m_fDistance) fDist = m_fDistance; m_fDistTraveled += fDist; if (m_fDistTraveled > m_fDistance) { fDist = m_fDistance - (m_fDistTraveled - fDist); if (fDist <= 0.0f) return LTTRUE; } // Calculate number of particles to create... LTFLOAT fNumParticles = fDist * m_fNumParticles / m_fDistance; // Calculate starting bubble position... LTVector vCurPos, vPos, vDelta, vTemp, vDriftVel, vColor; VEC_MULSCALAR(vTemp, m_vDir, fTimeOffset); VEC_ADD(vCurPos, m_vLastPos, vTemp); // What is the range of colors? LTFLOAT fRange = m_vColor2.x - m_vColor1.x; // Fill the distance between the last projectile position, and it's // current position with bubbles... VEC_SUB(vTemp, vCurPos, m_vLastPos); VEC_MULSCALAR(vDelta, vTemp, 1.0f/fNumParticles); VEC_COPY(vPos, m_vLastPos); LTFLOAT fLifeTime = 100.0f; LTFLOAT fOffset = 0.0f; LTVector vDriftOffset; VEC_SET(vDriftOffset, 0.0f, 0.0f, 0.0f); int nNumParticles = GetNumParticles((int)fNumParticles); for (int i=0; i < nNumParticles; i++) { // Build the individual bubbless... for (int j=0; j < 1; j++) { VEC_COPY(vTemp, vPos); VEC_SET(vDriftVel, 0.0f, GetRandom(5.0f, 6.0f), 0.0f); vTemp.x += GetRandom(-fOffset, fOffset); vTemp.y += GetRandom(-fOffset, fOffset); vTemp.z += GetRandom(-fOffset, fOffset); GetRandomColorInRange(vColor); m_pClientDE->AddParticle(m_hObject, &vTemp, &vDriftVel, &vColor, fLifeTime); } VEC_ADD(vPos, vPos, vDelta); } VEC_COPY(m_vLastPos, vCurPos); m_fLastTime = fTime; return LTTRUE; }
LTBOOL AISpatialNeighbor::Init(AISpatialRepresentation* pThis, AISpatialRepresentation* pNeighbor) { m_pVolume = pNeighbor; // 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->InsideMasked(pNeighbor->GetFrontTopLeft(), eAxisAll) || pThis->InsideMasked(pNeighbor->GetBackTopRight(), eAxisAll) || pThis->InsideMasked(pNeighbor->GetFrontBottomLeft(), eAxisAll) || pThis->InsideMasked(pNeighbor->GetBackBottomRight(), eAxisAll) ) { 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.Normalize(); } 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.Normalize(); } m_vConnectionMidpoint = m_avConnectionEndpoints[0] + ( m_vConnectionDir * ( m_fConnectionLength * 0.5f ) ); LTFLOAT fTemp = m_vConnectionPerpDir[0]; m_vConnectionPerpDir[0] = m_vConnectionPerpDir[2]; m_vConnectionPerpDir[2] = fTemp; m_vConnectionPerpDir.Normalize(); // Ensure that perp dir is axis-aligned. RoundVector( m_vConnectionPerpDir ); // Make sure it points into this volume LTVector vThisCenter = (pThis->GetFrontTopLeft()+pThis->GetBackTopRight())/2.0f; LTVector vThisCenterDir = vThisCenter - m_vConnectionPos; vThisCenterDir.y = 0; vThisCenterDir.Normalize(); if ( vThisCenterDir.Dot(m_vConnectionPerpDir) < 0.0f ) { m_vConnectionPerpDir = -m_vConnectionPerpDir; } m_cGates = (uint32)(m_fConnectionLength/48.0f); // Check for invalid neighbors. if(m_cGates == 0) { AIError("Volume has Invalid Neighbor %s -> %s. Connection < 48 units!", pThis->GetName(), pNeighbor->GetName() ); return LTFALSE; } m_vecfGateOccupancy.resize(m_cGates); for ( uint32 iGate = 0 ; iGate < m_cGates ; iGate++ ) { m_vecfGateOccupancy[iGate] = 0.0f; } if( m_avConnectionEndpoints[0].z == m_avConnectionEndpoints[1].z ) { m_eVolumeConnectionType = eVolumeConnectionTypeHorizontal; if( m_pVolume->GetCenter().z < m_vConnectionPos.z ) { m_eVolumeConnectionLocation = eVolumeConnectionLocationFront; } else { m_eVolumeConnectionLocation = eVolumeConnectionLocationBack; } } else { m_eVolumeConnectionType = eVolumeConnectionTypeVertical; if( m_pVolume->GetCenter().x < m_vConnectionPos.x ) { m_eVolumeConnectionLocation = eVolumeConnectionLocationRight; } else { m_eVolumeConnectionLocation = eVolumeConnectionLocationLeft; } } //g_pLTServer->CPrint("cxn @ %f,%f,%f in %f,%f,%f : %f,%f,%f", // EXPANDVEC(m_vConnectionPos), EXPANDVEC(vThisCenter), EXPANDVEC(m_vConnectionPerpDir)); return LTTRUE; }
DVector CPlayerCamera::FindOptimalCameraPosition() { DVector pos; VEC_INIT(pos); if (!m_pClientDE || !m_hTarget) return pos; DVector up, right, forward, dir; DFLOAT distToOptimal; DVector TargetPlusOffset; DVector vTargetPos; m_pClientDE->GetObjectPos(m_hTarget, &vTargetPos); DRotation rRot; m_pClientDE->GetObjectRotation(m_hTarget, &rRot); if (Equal(vTargetPos, m_vLastTargetPos) && Equal(rRot, m_rLastTargetRot) && m_eCameraMode != DEATH) { return m_vLastOptPos; } else { VEC_COPY(m_vLastTargetPos, vTargetPos); ROT_COPY(m_rLastTargetRot, rRot); } DVector vTemp; if (m_eCameraMode == DEATH) { VEC_COPY(vTemp, m_TargetDeathOffset); } else { VEC_COPY(vTemp, m_TargetChaseOffset); } VEC_ADD(vTemp, vTargetPos, vTemp); VEC_COPY(TargetPlusOffset, vTemp); m_pClientDE->GetRotationVectors(&rRot, &up, &right, &forward); // pos = TargetPlusOffset + right*m_OptX + up*m_OptY + forward*m_OptZ; DVector vTemp1, vTemp2; if (m_eCameraMode == DEATH) { VEC_MULSCALAR(vTemp, right, m_DeathOptX); VEC_MULSCALAR(vTemp2, forward, m_DeathOptZ); } else { VEC_MULSCALAR(vTemp, right, m_OptX); VEC_MULSCALAR(vTemp2, forward, m_OptZ); } VEC_MULSCALAR(vTemp1, up, m_OptY); ClientIntersectQuery iQuery; ClientIntersectInfo iInfo; VEC_ADD(vTemp, vTemp, vTemp1); VEC_ADD(vTemp, vTemp, vTemp2); VEC_ADD(pos, TargetPlusOffset, vTemp); VEC_SUB(vTemp, TargetPlusOffset, pos); distToOptimal = VEC_MAG(vTemp); VEC_SUB(dir, pos, TargetPlusOffset); VEC_NORM(dir); VEC_COPY(iQuery.m_From, TargetPlusOffset); VEC_COPY(iQuery.m_To, pos); if (m_pClientDE->IntersectSegment(&iQuery, &iInfo)) { VEC_SUB(vTemp, iInfo.m_Point, TargetPlusOffset); // If there was something in the way, move in front of that thing. if (VEC_MAG(vTemp) < distToOptimal) { VEC_ADD(pos, iInfo.m_Point, iInfo.m_Plane.m_Normal); } } #ifdef DOING_EXTRA_CHECKS // Make sure we aren't clipping into walls... DFLOAT fClipDistance = 100.0f; // 15.0f; DBOOL bClipRightIssues = DTRUE; DBOOL bClipUpIssues = DTRUE; // Check for walls to the right... VEC_MULSCALAR(vTemp, right, fClipDistance); VEC_ADD(vTemp, pos, vTemp); VEC_COPY(iQuery.m_From, pos); VEC_COPY(iQuery.m_To, vTemp); if (m_pClientDE->IntersectSegment(&iQuery, &iInfo)) { VEC_SUB(vTemp, iInfo.m_Point, pos); DFLOAT fDist = (fClipDistance - VEC_MAG(vTemp)); VEC_MULSCALAR(vTemp, right, -fDist) VEC_ADD(pos, pos, vTemp); } else { bClipRightIssues = DFALSE; } // If we didn't adjust for a wall to the right, check walls to the left... if (!bClipRightIssues) { VEC_MULSCALAR(vTemp, right, -fClipDistance); VEC_ADD(vTemp, pos, vTemp); VEC_COPY(iQuery.m_From, pos); VEC_COPY(iQuery.m_To, vTemp); if (m_pClientDE->IntersectSegment(&iQuery, &iInfo)) { VEC_SUB(vTemp, iInfo.m_Point, pos); DFLOAT fDist = (fClipDistance - VEC_MAG(vTemp)); VEC_MULSCALAR(vTemp, right, fDist) VEC_ADD(pos, pos, vTemp); } } // Check for ceilings... VEC_MULSCALAR(vTemp, up, fClipDistance); VEC_ADD(vTemp, pos, vTemp); VEC_COPY(iQuery.m_From, pos); VEC_COPY(iQuery.m_To, vTemp); if (m_pClientDE->IntersectSegment(&iQuery, &iInfo)) { VEC_SUB(vTemp, iInfo.m_Point, pos); DFLOAT fDist = (fClipDistance - VEC_MAG(vTemp)); VEC_MULSCALAR(vTemp, up, -fDist) VEC_ADD(pos, pos, vTemp); } else { bClipUpIssues = DFALSE; } // If we didn't hit any ceilings, check for floors... if (!bClipUpIssues) { VEC_MULSCALAR(vTemp, up, -fClipDistance); VEC_ADD(vTemp, pos, vTemp); VEC_COPY(iQuery.m_From, pos); VEC_COPY(iQuery.m_To, vTemp); if (m_pClientDE->IntersectSegment(&iQuery, &iInfo)) { VEC_SUB(vTemp, iInfo.m_Point, pos); DFLOAT fDist = (fClipDistance - VEC_MAG(vTemp)); VEC_MULSCALAR(vTemp, up, fDist) VEC_ADD(pos, pos, vTemp); } } #endif // DOING_EXTRA_CHECKS VEC_COPY(m_vLastOptPos, pos); return pos; }
void CPlayerCamera::MoveCameraToPosition(DVector pos, DVector vStartPos, DFLOAT deltaTime) { if (!m_pClientDE || !m_hTarget) return; DFLOAT nCurrentTime = m_pClientDE->GetTime(); // Handle transition if (m_eCameraMode == GOINGFIRSTPERSON || m_eCameraMode == GOINGCHASE || m_eCameraMode == DEATH) { if (nCurrentTime > m_fTransitionStart + m_fTransitionTime) { switch (m_eCameraMode) { case GOINGFIRSTPERSON: m_eCameraMode = FIRSTPERSON; break; case GOINGCHASE: m_eCameraMode = CHASE; break; } } else { // vStartPos is starting pos, pos is the position we want DFLOAT percentage = (nCurrentTime - m_fTransitionStart) / (m_fTransitionTime); DVector vMagnitude; VEC_SUB (vMagnitude, pos, vStartPos); VEC_MULSCALAR (vMagnitude, vMagnitude, percentage); VEC_ADD (pos, vStartPos, vMagnitude); } } DVector dir; VEC_SUB(dir, pos, m_vPos); DFLOAT multiplier = 1.0f; // 0.5f; DVector toMove; VEC_MULSCALAR(toMove, dir, multiplier); DFLOAT moveMag; if(m_bSlide) { moveMag = VEC_MAG(toMove); if(moveMag > VEC_MAG(dir)) moveMag = VEC_MAG(dir); if (toMove.x != 0.0f || toMove.y != 0.0f || toMove.z != 0.0f) { VEC_NORM(toMove); } VEC_MULSCALAR(toMove, toMove, moveMag); VEC_ADD(m_vPos, m_vPos, toMove); } else { VEC_COPY(m_vPos, pos); } }
DBOOL Equal(DVector & v1, DVector & v2) { DVector v; VEC_SUB(v, v1, v2); return DBOOL(VEC_MAG(v) < 1.0f); }
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; } }
void SoccerBall::Update( ) { DVector vVel, vAccel, vAccelAdd, vPos, vForward, vCross, vTemp, vTemp2; CollisionInfo collInfo; float fVelMag, fDistTraveled, fTime, fRotAmount, fExp; DRotation rRot; g_pServerDE->GetObjectPos( m_hObject, &vPos ); g_pServerDE->GetVelocity( m_hObject, &vVel ); fVelMag = VEC_MAG( vVel ); fTime = g_pServerDE->GetTime( ); // Remove the ball if it's been sitting around for a while. if( fTime > m_fRespawnTime ) { g_pServerDE->RemoveObject( m_hObject ); return; } // Update the on ground info g_pServerDE->GetStandingOn( m_hObject, &collInfo ); m_bOnGround = ( collInfo.m_hObject ) ? DTRUE : DFALSE; if( m_bOnGround ) { m_fLastTimeOnGround = fTime; } // Get how far we've traveled. VEC_SUB( vForward, vPos, m_vLastPos ); fDistTraveled = VEC_MAG( vForward ); VEC_COPY( m_vLastPos, vPos ); // Rotate the ball if( fDistTraveled > 0.0f ) { VEC_MULSCALAR( vForward, vForward, 1.0f / fDistTraveled ); if( m_bOnGround ) { VEC_COPY( m_vLastNormal, collInfo.m_Plane.m_Normal ); VEC_CROSS( vCross, vForward, m_vLastNormal ); fRotAmount = VEC_MAG( vCross ) * fDistTraveled / m_fRadius; } else { VEC_CROSS( vCross, vForward, m_vLastNormal ); fRotAmount = VEC_MAG( vCross ) * fDistTraveled / m_fRadius; } if( fRotAmount > 0.0f ) { VEC_NORM( vCross ); g_pServerDE->GetObjectRotation( m_hObject, &rRot ); g_pServerDE->RotateAroundAxis( &rRot, &vCross, fRotAmount ); g_pServerDE->SetObjectRotation( m_hObject, &rRot ); } } // Adjust the velocity and accel if( fVelMag < MINBALLVEL ) { VEC_INIT( vVel ); g_pServerDE->SetVelocity( m_hObject, &vVel ); } else if( fVelMag > MAXBALLVEL ) { VEC_MULSCALAR( vVel, vVel, MAXBALLVEL / fVelMag ); g_pServerDE->SetVelocity( m_hObject, &vVel ); } else { // new velocity is given by: v = ( a / k ) + ( v_0 - a / k ) * exp( -k * t ) g_pServerDE->GetAcceleration( m_hObject, &vAccel ); fExp = ( float )exp( -BALLDRAG * g_pServerDE->GetFrameTime( )); VEC_DIVSCALAR( vTemp, vAccel, BALLDRAG ); VEC_SUB( vTemp2, vVel, vTemp ); VEC_MULSCALAR( vTemp2, vTemp2, fExp ); VEC_ADD( vVel, vTemp2, vTemp ); g_pServerDE->SetVelocity( m_hObject, &vVel ); } // Make sure we're rolling if we're on a slope. This counteracts the way the // engine stops objects on slopes. if( m_bOnGround ) { if( collInfo.m_Plane.m_Normal.y < 0.9f && fabs( vVel.y ) < 50.0f ) { g_pServerDE->GetGlobalForce( &vAccelAdd ); vAccel.y += vAccelAdd.y * 0.5f; g_pServerDE->SetAcceleration( m_hObject, &vAccel ); } } // Play a bounce sound if enough time has elapsed if( m_bBounced ) { if( fTime > m_fLastBounceTime + TIMEBETWEENBOUNCESOUNDS ) { // Play a bounce sound... PlaySoundFromPos( &vPos, "Sounds_ao\\events\\soccerball.wav", 750, SOUNDPRIORITY_MISC_MEDIUM ); } m_bBounced = DFALSE; } g_pServerDE->SetNextUpdate( m_hObject, 0.001f ); }
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)); }
DBOOL CCastLineFX::Update() { if(!m_hObject || !m_pClientDE || !m_hServerObject) return DFALSE; if (m_bWantRemove) { return DFALSE; } DRotation rRot; m_pClientDE->GetObjectRotation(m_hServerObject, &rRot); m_pClientDE->SetObjectRotation(m_hObject, &rRot); DVector vPos; m_pClientDE->GetObjectPos(m_hServerObject, &vPos); m_pClientDE->SetObjectPos(m_hObject, &vPos); if (m_bFirstUpdate) { m_bFirstUpdate = DFALSE; DELine line; // Set first vertex... VEC_SET(line.m_Points[0].m_Pos, 0.0f, 0.0f, 0.0f); line.m_Points[0].r = m_vStartColor.x; line.m_Points[0].g = m_vStartColor.y; line.m_Points[0].b = m_vStartColor.z; line.m_Points[0].a = m_fStartAlpha; // Set second vertex (cast a ray to find it)... DVector vEndPoint, vU, vR, vF; m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF); VEC_NORM(vF); DFLOAT fDistance = 10000.0f; // Far, far, away... if (!m_hCastTo) { ClientIntersectQuery iQuery; ClientIntersectInfo iInfo; VEC_COPY(iQuery.m_From, vPos); VEC_COPY(iQuery.m_Direction, vF); iQuery.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; if (m_pClientDE->CastRay(&iQuery, &iInfo)) { VEC_COPY(vEndPoint, iInfo.m_Point); fDistance = VEC_MAG(vEndPoint); } } else { m_pClientDE->GetObjectPos(m_hCastTo, &vEndPoint); VEC_SUB(vEndPoint, vEndPoint, vPos); fDistance = VEC_MAG(vEndPoint); } VEC_SET(vEndPoint, 0.0f, 0.0f, 1.0f); VEC_MULSCALAR(vEndPoint, vEndPoint, fDistance); VEC_COPY(line.m_Points[1].m_Pos, vEndPoint); line.m_Points[1].r = m_vEndColor.x; line.m_Points[1].g = m_vEndColor.y; line.m_Points[1].b = m_vEndColor.z; line.m_Points[1].a = m_fEndAlpha; m_pClientDE->AddLine(m_hObject, &line); } return DTRUE; }
void VolumeBrush::UpdatePhysics(ContainerPhysics* pCPStruct) { if (m_bHidden || !pCPStruct || !pCPStruct->m_hObject) return; LTFLOAT fUpdateDelta = g_pLTServer->GetFrameTime(); // Let the character know if they are in liquid... if (IsLiquid(m_eContainerCode) && IsCharacter(pCPStruct->m_hObject)) { CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(pCPStruct->m_hObject); if (pCharacter) { pCharacter->UpdateInLiquid(this, pCPStruct); } } // Player container physics is done on the client... if (!IsPlayer(pCPStruct->m_hObject)) { // Dampen velocity based on the viscosity of the container... LTVector vVel, vCurVel; vVel = vCurVel = pCPStruct->m_Velocity; if (m_fViscosity > 0.0f && VEC_MAG(vCurVel) > 1.0f) { LTVector vDir; VEC_COPY(vDir, vCurVel); VEC_NORM(vDir); LTFLOAT fAdjust = MAX_CONTAINER_VISCOSITY * m_fViscosity * fUpdateDelta; vVel = (vDir * fAdjust); if (VEC_MAG(vVel) < VEC_MAG(vCurVel)) { VEC_SUB(vVel, vCurVel, vVel); } else { VEC_INIT(vVel); } vVel += (m_vCurrent * fUpdateDelta); pCPStruct->m_Velocity = vVel; } // Do special liquid handling... if (IsLiquid(m_eContainerCode)) { UpdateLiquidPhysics(pCPStruct); } } // Update damage... // Make damage relative to update delta... LTFLOAT fDamage = 0.0f; if (m_fDamage > 0.0f) { fDamage = m_fDamage * fUpdateDelta; } // Damage using progressive damage. This insures that the correct // damage effect is shown on the client... if (fDamage) { DamageStruct damage; damage.eType = m_eDamageType; damage.fDamage = fDamage; damage.hDamager = m_hObject; // Use progressive damage... damage.fDuration = 0.25f; damage.hContainer = m_hObject; damage.DoDamage(this, pCPStruct->m_hObject); } }