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; }
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; }
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; }
void CGrenade::HandleImpact(HOBJECT hObj) { if (!g_vtGrenadeDampenPercent.IsInitted()) { g_vtGrenadeDampenPercent.Init(g_pLTServer, "GrenadeDampenPercent", LTNULL, DEFAULT_GRENADE_DAMPEN_PERCENT); } if (!g_vtGrenadeMinVelMag.IsInitted()) { g_vtGrenadeMinVelMag.Init(g_pLTServer, "GrenadeMinVelMag", LTNULL, DEFAULT_GRENADE_MIN_VELOCITY); } LTVector vVel; g_pLTServer->GetVelocity(m_hObject, &vVel); // See if we are impacting on liquid... LTBOOL bEnteringLiquid = LTFALSE; uint16 code; if (g_pLTServer->GetContainerCode(hObj, &code)) { if (IsLiquid((ContainerCode)code)) { bEnteringLiquid = LTTRUE; } } CollisionInfo info; g_pLTServer->GetLastCollision(&info); // Do the bounce, if the object we hit isn't liquid... if (!bEnteringLiquid) { vVel += (info.m_vStopVel * 2.0f); } // Dampen the grenade's new velocity based on the surface type... LTFLOAT fDampenPercent = g_vtGrenadeDampenPercent.GetFloat(); m_eLastHitSurface = GetSurfaceType(info); SURFACE* pSurf = g_pSurfaceMgr->GetSurface(m_eLastHitSurface); if (pSurf) { // Play a bounce sound (based on the surface type) if one isn't // already playing... if ( ShouldPlayBounceSound(pSurf) ) { // Only play one sound at a time... if (m_hBounceSnd) { g_pLTServer->KillSound(m_hBounceSnd); m_hBounceSnd = LTNULL; } uint32 dwFlags = PLAYSOUND_GETHANDLE | PLAYSOUND_TIME; int nVolume = IsLiquid(m_eContainerCode) ? 50 : 100; LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); m_hBounceSnd = g_pServerSoundMgr->PlaySoundFromPos(vPos, (char*)GetBounceSound(pSurf), pSurf->fGrenadeSndRadius, SOUNDPRIORITY_MISC_MEDIUM, dwFlags, nVolume); } fDampenPercent = (1.0f - pSurf->fHardness); } fDampenPercent = fDampenPercent > 1.0f ? 1.0f : (fDampenPercent < 0.0f ? 0.0f : fDampenPercent); vVel *= (1.0f - fDampenPercent); // See if we should come to a rest... LTVector vTest = vVel; vTest.y = 0.0f; if (vTest.Mag() < g_vtGrenadeMinVelMag.GetFloat()) { // If we're on the ground (or an object), stop movement... CollisionInfo standingInfo; g_pLTServer->GetStandingOn(m_hObject, &standingInfo); CollisionInfo* pInfo = standingInfo.m_hObject ? &standingInfo : &info; if (pInfo->m_hObject) { // Don't stop on walls... if (pInfo->m_Plane.m_Normal.y > 0.75f) { vVel.Init(); // Turn off gravity, solid, and touch notify.... uint32 dwFlags = g_pLTServer->GetObjectFlags(m_hObject); dwFlags &= ~(FLAG_GRAVITY | FLAG_TOUCH_NOTIFY | FLAG_SOLID); g_pLTServer->SetObjectFlags(m_hObject, dwFlags); // Rotate to rest... RotateToRest(); } } } // Reset rotation velocities due to the bounce... ResetRotationVel(&vVel, pSurf); // We need to subtact this out because the engine will add it back in, // kind of a kludge but necessary... vVel -= info.m_vStopVel; g_pLTServer->SetVelocity(m_hObject, &vVel); m_cBounces++; }
void Prop::HandleAttachmentImpact( CAttachmentPosition *pAttachPos, const LTVector& vDir ) { if( !pAttachPos ) return; // TODO: Init these somewhere else if( !s_vtAttachmentMinVel.IsInitted() ) { s_vtAttachmentMinVel.Init( g_pLTServer, "AttachmentMinVel", LTNULL, DEFAULT_ATTACH_MIN_VEL ); } if( !s_vtAttachmentMaxVel.IsInitted() ) { s_vtAttachmentMaxVel.Init( g_pLTServer, "AttachmentMaxVel", LTNULL, DEFAULT_ATTACH_MAX_VEL ); } if( !s_vtAttachmentMinYAdd.IsInitted() ) { s_vtAttachmentMinYAdd.Init( g_pLTServer, "AttachmentMinYAdd", LTNULL, DEFAULT_ATTACH_MIN_YADD ); } if( !s_vtAttachmentMaxYAdd.IsInitted() ) { s_vtAttachmentMaxYAdd.Init( g_pLTServer, "AttachmentMaxYAdd", LTNULL, DEFAULT_ATTACH_MAX_YADD ); } if( !s_vtAttachmentFadeDelay.IsInitted() ) { s_vtAttachmentFadeDelay.Init( g_pLTServer, "AttachmentFadeDelay", LTNULL, DEFAULT_ATTACH_FADE_DELAY ); } if( !s_vtAttachmentFadeDuration.IsInitted() ) { s_vtAttachmentFadeDuration.Init( g_pLTServer, "AttachmentFadeDuration", LTNULL, DEFAULT_ATTACH_FADE_DURATION ); } // Set the owner of the attachment... m_hAttachmentOwner = pAttachPos->GetAttachment()->GetObject(); uint32 dwFlags = FLAG_POINTCOLLIDE | FLAG_NOSLIDING | FLAG_TOUCH_NOTIFY | FLAG_GRAVITY; g_pCommonLT->SetObjectFlags( m_hObject, OFT_Flags, dwFlags, dwFlags | FLAG_GOTHRUWORLD ); // Play the world animation so the prop is flat when it comes to rest... HMODELANIM hWorldAnim = INVALID_MODEL_ANIM; if( (g_pModelLT->GetAnimIndex( m_hObject, "WORLD", hWorldAnim ) == LT_OK) && (hWorldAnim != INVALID_MODEL_ANIM) ) { g_pModelLT->SetLooping( m_hObject, MAIN_TRACKER, true ); g_pModelLT->SetCurAnim( m_hObject, MAIN_TRACKER, hWorldAnim ); } LTVector vVel = vDir; vVel.Normalize(); vVel *= GetRandom( s_vtAttachmentMinVel.GetFloat(), s_vtAttachmentMaxVel.GetFloat() ); vVel.y += GetRandom( s_vtAttachmentMinYAdd.GetFloat(), s_vtAttachmentMaxYAdd.GetFloat() ); g_pPhysicsLT->SetVelocity( m_hObject, &vVel ); // Don't play the touch animation and sounds when recieving a touch notify... m_bTouchable = LTFALSE; m_bAttachmentShotOff = LTTRUE; g_pLTServer->SetBlockingPriority( m_hObject, 0 ); g_pPhysicsLT->SetForceIgnoreLimit( m_hObject, 0.0f ); // Give it some rotation... float fVal = MATH_PI; float fVal2 = MATH_CIRCLE; m_fPitchVel = GetRandom( -fVal2, fVal2 ); m_fYawVel = GetRandom( -fVal2, fVal2 ); m_fRollVel = GetRandom( -fVal2, fVal2 ); m_bRotating = true; SetNextUpdate(UPDATE_NEXT_FRAME); }
bool CFallingStuffFX::Update(float tmFrameTime) { // Base class update first m_vLastPos = m_vPos; if (!CBaseFX::Update(tmFrameTime)) return false; //increment our emission time by the elapsed frame time m_tmElapsedEmission += tmFrameTime; if (!IsShuttingDown() && !IsSuspended() && (m_tmElapsedEmission > GetProps()->m_tmFallingStuffFXEmission)) { ObjectCreateStruct ocs; INIT_OBJECTCREATESTRUCT(ocs); LTVector vScale; vScale.Init(m_scale, m_scale, m_scale); LTVector vInterp; LTVector vInterpCur = m_vPos; // Calculate interpolant for particle system if (GetProps()->m_nFallingStuffFXEmission) { vInterp = m_vPos - m_vLastPos; vInterp /= (float)GetProps()->m_nFallingStuffFXEmission; } for (uint32 i = 0; i < GetProps()->m_nFallingStuffFXEmission; i ++) { ocs.m_ObjectType = OT_SPRITE; ocs.m_Flags = FLAG_VISIBLE | FLAG_NOLIGHT | FLAG_ROTATABLESPRITE; // Compute the initial position float xRand = GetProps()->m_fRadius * ((-10000.0f + (rand() % 20000)) / 10000.0f); float zRand = GetProps()->m_fRadius * ((-10000.0f + (rand() % 20000)) / 10000.0f); ocs.m_Pos = m_vPos + (m_vRight * xRand) + (m_vUp * zRand); ocs.m_Scale = vScale; strcpy(ocs.m_Filename, GetProps()->m_sSpriteName); // Move the start point vInterpCur += vInterp; HLOCALOBJ hNewSprite = m_pLTClient->CreateObject(&ocs); if (hNewSprite) { // Create a new sprite FALLING_THING *pNewSprite = debug_new( FALLING_THING ); if (GetProps()->m_nImpactCreate) { if (g_dwSplash > (uint32)GetProps()->m_nImpactCreate) { pNewSprite->m_bSplash = true; g_dwSplash = 0; } else { pNewSprite->m_bSplash = false; } } else { pNewSprite->m_bSplash = false; } g_dwSplash ++; if (pNewSprite) { LTVector v; // Compute the initial velocity v = m_vPlaneDir * GetProps()->m_fVel; pNewSprite->m_hObject = hNewSprite; pNewSprite->m_vVel = v; pNewSprite->m_tmElapsed = 0.0f; pNewSprite->m_vPos = ocs.m_Pos; pNewSprite->m_vLastPos = ocs.m_Pos; m_collSprites.AddTail(pNewSprite); } } } m_tmElapsedEmission = 0.0f; // And store the last position m_vLastPos = m_vPos; } LTMatrix mSpin; if (GetProps()->m_bUseSpin) { // Setup rotation LTMatrix vRight; LTMatrix vUp; LTMatrix vForward; LTMatrix vTmp; Mat_SetupRot(&vRight, &m_vRight, m_xRot); Mat_SetupRot(&vUp, &m_vUp, m_yRot); Mat_SetupRot(&vForward, &m_vPlaneDir, m_zRot); MatMul(&vTmp, &vRight, &vUp); MatMul(&mSpin, &vTmp, &vForward); m_xRot += GetProps()->m_vRotAdd.x * tmFrameTime; m_yRot += GetProps()->m_vRotAdd.y * tmFrameTime; m_zRot += GetProps()->m_vRotAdd.z * tmFrameTime; } // Get the camera rotation LTRotation orient; m_pLTClient->GetObjectRotation(m_hCamera, &orient); LTRotation dRot(orient); LTVector vF = orient.Forward(); float rot = (float)atan2(vF.x, vF.z); // Update the sprites.... CLinkListNode<FALLING_THING *> *pNode = m_collSprites.GetHead(); CLinkListNode<FALLING_THING *> *pDelNode; while (pNode) { pDelNode = NULL; FALLING_THING *pSprite = pNode->m_Data; //adjust our elapsed time pSprite->m_tmElapsed += tmFrameTime; // Check for expiration if (pSprite->m_tmElapsed > GetProps()->m_tmSpriteLifespan) { // Destroy this object m_pLTClient->RemoveObject(pSprite->m_hObject); pDelNode = pNode; } else { // Update !! pSprite->m_vLastPos = pSprite->m_vPos; pSprite->m_vPos += (pSprite->m_vVel * tmFrameTime); // Rotate if neccessary TVector3<float> vPos = pSprite->m_vPos; if (GetProps()->m_bUseSpin) { MatVMul_InPlace(&mSpin, &vPos); } // Add in wind vPos += (GetProps()->m_vWind * GetProps()->m_fWindAmount) * tmFrameTime; // Setup the new sprite position LTVector vPos2 = vPos; m_pLTClient->SetObjectPos(pSprite->m_hObject, &vPos2); // Setup the colour float r, g, b, a; m_pLTClient->GetObjectColor(pSprite->m_hObject, &r, &g, &b, &a); CalcColour(pSprite->m_tmElapsed, GetProps()->m_tmSpriteLifespan, &r, &g, &b, &a); m_pLTClient->SetObjectColor(pSprite->m_hObject, r, g, b, a); // Setup the scale float scale = 0.1f; CalcScale(pSprite->m_tmElapsed, GetProps()->m_tmSpriteLifespan, &scale); LTVector vScale; vScale.Init(scale, scale * GetProps()->m_fStretchMul, scale); m_pLTClient->SetObjectScale(pSprite->m_hObject, &vScale); // Setup the rotation dRot = LTRotation(0, 0, 0, 1); LTRotation orient(dRot); orient.Rotate( orient.Up(), rot ); m_pLTClient->SetObjectRotation(pSprite->m_hObject, &orient); // Check to see if we need to start a splash sprite if (pSprite->m_bSplash) { ClientIntersectQuery ciq; ClientIntersectInfo cii; ciq.m_From = pSprite->m_vLastPos; ciq.m_To = pSprite->m_vPos; if ((GetProps()->m_sImpactSpriteName[0]) && (m_pLTClient->IntersectSegment(&ciq, &cii))) { // Create a splash sprite SPLASH *pSplash = debug_new( SPLASH ); ObjectCreateStruct ocs; INIT_OBJECTCREATESTRUCT(ocs); LTVector vScale; vScale.Init(0.0f, 0.0f, 0.0f); ocs.m_ObjectType = OT_SPRITE; ocs.m_Flags = FLAG_VISIBLE | FLAG_ROTATABLESPRITE | FLAG_NOLIGHT; ocs.m_Pos = cii.m_Point + (cii.m_Plane.m_Normal * 2.0f); ocs.m_Scale = vScale; LTRotation dOrient( cii.m_Plane.m_Normal, LTVector(0.0f, 1.0f, 0.0f) ); strcpy(ocs.m_Filename, GetProps()->m_sImpactSpriteName); pSplash->m_hObject = m_pLTClient->CreateObject(&ocs); pSplash->m_scale = 0.0f; LTRotation orient(dRot); m_pLTClient->SetObjectRotation(pSplash->m_hObject, &orient); pSplash->m_tmElapsed = 0.0f; m_collSplashes.AddTail(pSplash); // Destroy this object m_pLTClient->RemoveObject(pSprite->m_hObject); // Delete the sprite pDelNode = pNode; } } } pNode = pNode->m_pNext; if (pDelNode) m_collSprites.Remove(pDelNode); } // Update our splashes CLinkListNode<SPLASH *> *pSplashNode = m_collSplashes.GetHead(); while (pSplashNode) { CLinkListNode<SPLASH *> *pDelNode = NULL; SPLASH *pSplash = pSplashNode->m_Data; //update the elapsed time on the splash pSplash->m_tmElapsed += tmFrameTime; // Calculate the new scale float scale = GetProps()->m_fImpactScale1 + ((GetProps()->m_fImpactScale2 - GetProps()->m_fImpactScale1) * (pSplash->m_tmElapsed / GetProps()->m_tmImpactLifespan)); LTVector vScale(scale, scale, scale); m_pLTClient->SetObjectScale(pSplash->m_hObject, &vScale); float r, g, b, a; m_pLTClient->GetObjectColor(pSplash->m_hObject, &r, &g, &b, &a); a = (float)(int)(pSplash->m_tmElapsed / GetProps()->m_tmImpactLifespan); if (a < 0.0f) a = 0.0f; if (a > 1.0f) a = 1.0f; m_pLTClient->SetObjectColor(pSplash->m_hObject, r, g, b, a); if (pSplash->m_tmElapsed > GetProps()->m_tmImpactLifespan) { m_pLTClient->RemoveObject(pSplash->m_hObject); pDelNode = pSplashNode; } pSplashNode = pSplashNode->m_pNext; if (pDelNode) m_collSplashes.Remove(pDelNode); } // Success !! return true; }
//* // ----------------------------------------------------------------------- // // 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 CTransitionAggregate::Load( ILTMessage_Read *pMsg, uint32 dwLoadFlags ) { if( !pMsg ) return; LOAD_HOBJECT( m_hObject ); // The rest is dependent on the load type... if( dwLoadFlags != LOAD_TRANSITION ) return; HOBJECT hTransArea = g_pTransMgr->GetTransitionArea(); if( !hTransArea ) return; TransitionArea *pTransArea = (TransitionArea*)g_pLTServer->HandleToObject( hTransArea ); if( !pTransArea ) return; LTransform tfLocal; LTransform tfObjectWorld; LTVector vVelRel; LTransform const& tfTransAreaWorld = pTransArea->GetWorldTransform( ); LTMatrix mRotation; tfTransAreaWorld.m_Rot.ConvertToMatrix( mRotation ); LOAD_VECTOR( tfLocal.m_Pos ); LOAD_ROTATION( tfLocal.m_Rot ); LOAD_VECTOR( vVelRel ); // Calc pos and rot based on offsets and current TransArea... tfObjectWorld.m_Pos = tfTransAreaWorld.m_Pos + ( mRotation * tfLocal.m_Pos ); tfObjectWorld.m_Rot = tfTransAreaWorld.m_Rot * tfLocal.m_Rot; LTVector vVel = mRotation * vVelRel; if( IsPlayer( m_hObject )) { // Since the PlayerObj is controlled by the client we need to notify the // client of the rotation. We are only worried about the Yaw since Roll doesn't // matter and Pitch can be preserved on the client. CPlayerObj *pPlayer = (CPlayerObj*)g_pLTServer->HandleToObject( m_hObject ); if( !pPlayer ) return; LTFLOAT fYaw; LTVector vF = tfObjectWorld.m_Rot.Forward(); // We don't care about Roll... vF.y = 0.0f; vF.Normalize(); // Yaw = arctan( vF.x / vF.z ); // atan2 is well defined even for vF.z == 0 fYaw = (LTFLOAT)atan2( vF.x, vF.z ); // Inform the client of the correct camera/player orientation... LTVector vVec( 0.0f, fYaw, 0.0f ); CAutoMessage cMsg; cMsg.Writeuint8( MID_PLAYER_ORIENTATION ); cMsg.Writeuint8( MID_ORIENTATION_YAW ); cMsg.WriteLTVector( vVec ); g_pLTServer->SendToClient(cMsg.Read(), pPlayer->GetClient(), MESSAGE_GUARANTEED); } g_pLTServer->SetObjectPos( m_hObject, &tfObjectWorld.m_Pos ); g_pLTServer->SetObjectRotation( m_hObject, &tfObjectWorld.m_Rot ); g_pPhysicsLT->SetVelocity( m_hObject, &vVel ); }
bool CAISensorPassTarget::NeedToHoldPosition( bool* pbCalledFindPath ) { // Sanity check. if( !pbCalledFindPath ) { return false; } // No need to hold position if not targeting a character. if( !m_pAI->HasTarget( kTarget_Character ) ) { m_hVerifiedNode = NULL; return false; } // Only check for passing the target if we are within some distance of the target. LTVector vTargetPos = m_pAI->GetAIBlackBoard()->GetBBTargetPosition(); float fDistSqr = vTargetPos.DistSqr( m_pAI->GetPosition() ); if( fDistSqr > g_pAIDB->GetAIConstantsRecord()->fHoldPositionDistanceSqr ) { m_hVerifiedNode = NULL; return false; } // Character is outside of the NavMesh. ENUM_NMPolyID ePolyTarget = GetTargetNavMeshPoly(); if( ePolyTarget == kNMPoly_Invalid ) { m_hVerifiedNode = NULL; return false; } // Bail if AI is not going for cover or ambush. CAIWMFact factQuery; factQuery.SetFactType( kFact_Task ); factQuery.SetTaskType( kTask_Cover ); CAIWMFact* pFact = m_pAI->GetAIWorkingMemory()->FindWMFact( factQuery ); if( !pFact ) { factQuery.SetTaskType( kTask_Ambush ); pFact = m_pAI->GetAIWorkingMemory()->FindWMFact( factQuery ); } if( !( pFact && ( pFact->GetConfidence( CAIWMFact::kFactMask_TaskType ) == 1.f ) ) ) { m_hVerifiedNode = NULL; return false; } // Bail if AI is scripted to go for cover. if( pFact->GetFactFlags() & kFactFlag_Scripted ) { m_hVerifiedNode = NULL; return false; } // We have already determined that we can get to this node without // crossing the target's position. HOBJECT hNode = pFact->GetTargetObject(); if( hNode == m_hVerifiedNode ) { // AI is not going anywhere. CAIPathNavMesh* pNMPath = m_pAI->GetAINavigationMgr()->GetNMPath(); if( ( !pNMPath ) || ( !m_pAI->GetAINavigationMgr()->IsNavSet() ) || ( m_pAI->GetAIBlackBoard()->GetBBDestStatus() != kNav_Set ) ) { return false; } // Existing path is still valid. Path does not cross target. if( !PathIncludesPoly( *pNMPath, ePolyTarget ) ) { return false; } } // No path exists to node. *pbCalledFindPath = true; static CAIPathNavMesh NMPath; if( !FindPathToNode( hNode, &NMPath ) ) { return false; } // Path does cross target's position. if( PathIncludesPoly( NMPath, ePolyTarget ) ) { AvoidNode( hNode ); return true; } // Path does not cross target's position. m_hVerifiedNode = hNode; return false; }
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(); }
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)); }
static void d3d_DrawRotatableSprite(const ViewParams& Params, SpriteInstance *pInstance, SharedTexture *pShared) { if(!d3d_SetTexture(pShared, 0, eFS_SpriteTexMemory)) return; float fWidth = (float)((RTexture*)pShared->m_pRenderData)->GetBaseWidth(); float fHeight = (float)((RTexture*)pShared->m_pRenderData)->GetBaseHeight(); //cache the object position LTVector vPos = pInstance->GetPos(); LTMatrix mRotation; d3d_SetupTransformation(&vPos, (float*)&pInstance->m_Rotation, &pInstance->m_Scale, &mRotation); //get our basis vectors LTVector vRight, vUp, vForward; mRotation.GetBasisVectors(&vRight, &vUp, &vForward); //scale the vectors to be the appropriate size vRight *= fWidth; vUp *= fHeight; // Setup the points. RGBColor Color; d3d_GetSpriteColor(pInstance, &Color); uint32 nColor = Color.color; CSpriteVertex SpriteVerts[4]; SpriteVerts[0].SetupVert(vPos + vUp - vRight, nColor, 0.0f, 0.0f); SpriteVerts[1].SetupVert(vPos + vUp + vRight, nColor, 1.0f, 0.0f); SpriteVerts[2].SetupVert(vPos + vRight - vUp, nColor, 1.0f, 1.0f); SpriteVerts[3].SetupVert(vPos - vRight - vUp, nColor, 0.0f, 1.0f); //figure out our final vertices to use CSpriteVertex *pPoints; uint32 nPoints; CSpriteVertex ClippedSpriteVerts[40 + 5]; if(pInstance->m_ClipperPoly != INVALID_HPOLY) { if(!d3d_ClipSprite(pInstance, pInstance->m_ClipperPoly, &pPoints, &nPoints, ClippedSpriteVerts)) { return; } } else { pPoints = SpriteVerts; nPoints = 4; } if((pInstance->m_Flags & FLAG_SPRITEBIAS) && !(pInstance->m_Flags & FLAG_REALLYCLOSE)) { //adjust the points for(uint32 nCurrPt = 0; nCurrPt < nPoints; nCurrPt++) { //get the sprite vertex that we are modifying LTVector& vPt = SpriteVerts[nCurrPt].m_Vec; //find a point relative to the viewer position LTVector vPtRelCamera = vPt - Params.m_Pos; //determine the distance from the camera float fZ = vPtRelCamera.Dot(Params.m_Forward); if(fZ <= NEARZ) continue; //find the bias, up to, but not including the near plane float fBiasDist = SPRITE_POSITION_ZBIAS; if((fZ + fBiasDist) < NEARZ) fBiasDist = NEARZ - fZ; //now adjust our vectors accordingly so that we can move it forward //but have it be the same size float fScale = 1 + fBiasDist / fZ; vPt = Params.m_Right * vPtRelCamera.Dot(Params.m_Right) * fScale + Params.m_Up * vPtRelCamera.Dot(Params.m_Up) * fScale + (fZ + fBiasDist) * Params.m_Forward + Params.m_Pos; } } LTEffectImpl* pEffect = (LTEffectImpl*)LTEffectShaderMgr::GetSingleton().GetEffectShader(pInstance->m_nEffectShaderID); if(pEffect) { pEffect->UploadVertexDeclaration(); ID3DXEffect* pD3DEffect = pEffect->GetEffect(); if(pD3DEffect) { RTexture* pTexture = (RTexture*)pShared->m_pRenderData; pD3DEffect->SetTexture("texture0", pTexture->m_pD3DTexture); i_client_shell->OnEffectShaderSetParams(pEffect, NULL, NULL, LTShaderDeviceStateImp::GetSingleton()); UINT nPasses = 0; pD3DEffect->Begin(&nPasses, 0); for(int i = 0; i < nPasses; ++i) { pD3DEffect->BeginPass(i); D3D_CALL(PD3DDEVICE->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, nPoints-2, pPoints, sizeof(CSpriteVertex))); pD3DEffect->EndPass(); } pD3DEffect->End(); } } else { D3D_CALL(PD3DDEVICE->SetVertexShader(NULL)); D3D_CALL(PD3DDEVICE->SetFVF(SPRITEVERTEX_FORMAT)); D3D_CALL(PD3DDEVICE->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, nPoints-2, pPoints, sizeof(CSpriteVertex))); } d3d_DisableTexture(0); }
//function that handles the custom rendering void CBaseSpriteFX::RenderSprite(ILTCustomRenderCallback* pInterface, const LTRigidTransform& tCamera) { //setup our vertex declaration if(pInterface->SetVertexDeclaration(g_ClientFXVertexDecl.GetTexTangentSpaceDecl()) != LT_OK) return; //bind a quad index stream if(pInterface->BindQuadIndexStream() != LT_OK) return; //determine how many indices we are going to need uint32 nNumIndices = (GetProps()->m_bTwoSided) ? 12 : 6; uint32 nNumVertices = (GetProps()->m_bTwoSided) ? 8 : 4; //sanity check to ensure that we can at least render a sprite LTASSERT(QUAD_RENDER_INDEX_STREAM_SIZE >= nNumIndices, "Error: Quad index list is too small to render a sprite"); LTASSERT(DYNAMIC_RENDER_VERTEX_STREAM_SIZE / sizeof(STexTangentSpaceVert) >= nNumVertices, "Error: Dynamic vertex buffer size is too small to render a sprite"); //determine the up and right vectors for the sprite LTVector vTangent, vBinormal; //get the position of this sprite LTRigidTransform tObjTransform; g_pLTClient->GetObjectTransform(m_hObject, &tObjTransform); //determine the center of this sprite LTVector vCenter = tObjTransform.m_vPos; //determine the orientation of the sprite based upon its facing if(GetProps()->m_bAlignToCamera) { //apply the to camera offset LTVector vToCamera = tCamera.m_vPos - vCenter; float fScale = GetProps()->m_fToCameraOffset / vToCamera.Mag(); vCenter += vToCamera * fScale; //perform the rotation float fCosAng = LTCos(m_fCurrRotationRad); float fSinAng = LTSin(m_fCurrRotationRad); LTVector vRight = tCamera.m_rRot.Right(); LTVector vUp = -tCamera.m_rRot.Up(); vTangent = fCosAng * vRight + fSinAng * vUp; vBinormal = fCosAng * vUp - fSinAng * vRight; } else if(GetProps()->m_bAlignAroundZ) { //we want to orient around the Z axis and align to the camera //we need to determine our U vector, which is always our forward LTVector vU = tObjTransform.m_rRot.Forward(); //and now we want to offset our center so that we are anchored on the right hand //side of the sprite to the point vCenter += vU * (m_fWidth * 0.5f); //determine the axis from our camera to our object LTVector vToCamera = tCamera.m_vPos - vCenter; //and now derive our V vector from the forward and the direction to the camera LTVector vV = vToCamera.Cross(vU); //detect degenerate cases if(vV == LTVector::GetIdentity()) { //degenerate case, any orientation will work fine since the sprite won't //be visible anyway vV.Init(0.0f, 1.0f, 0.0f); } //and normalize our vector vV.Normalize(); //now we can determine our tangent and binormal vectors vTangent = -vU; vBinormal = vV; } else { vTangent = -tObjTransform.m_rRot.Right(); vBinormal = -tObjTransform.m_rRot.Up(); } LTVector vNormal = vBinormal.Cross(vTangent); //scale the right and down values to be the appropriate size LTVector vRight = vTangent * m_fWidth * -0.5f; LTVector vDown = vBinormal * m_fWidth * GetProps()->m_fAspectRatio * 0.5f; //lock down our buffer for rendering SDynamicVertexBufferLockRequest LockRequest; if(pInterface->LockDynamicVertexBuffer(nNumVertices, LockRequest) != LT_OK) return; //fill in our sprite vertices STexTangentSpaceVert* pCurrOut = (STexTangentSpaceVert*)LockRequest.m_pData; uint32 nColor = SETRGBA( (uint8)(m_vColor.x * 255.0f), (uint8)(m_vColor.y * 255.0f), (uint8)(m_vColor.z * 255.0f), (uint8)(m_vColor.w * 255.0f)); //fill in the particle vertices pCurrOut[0].m_vPos = vCenter + vRight - vDown; pCurrOut[0].m_vUV.Init(0.0f, 0.0f); pCurrOut[1].m_vPos = vCenter - vRight - vDown; pCurrOut[1].m_vUV.Init(1.0f, 0.0f); pCurrOut[2].m_vPos = vCenter - vRight + vDown; pCurrOut[2].m_vUV.Init(1.0f, 1.0f); pCurrOut[3].m_vPos = vCenter + vRight + vDown; pCurrOut[3].m_vUV.Init(0.0f, 1.0f); //setup the remaining vertex components for(uint32 nCurrVert = 0; nCurrVert < 4; nCurrVert++) { pCurrOut[nCurrVert].m_nPackedColor = nColor; pCurrOut[nCurrVert].m_vNormal = vNormal; pCurrOut[nCurrVert].m_vTangent = vTangent; pCurrOut[nCurrVert].m_vBinormal = vBinormal; } //and fill in the back side if appropriate if(GetProps()->m_bTwoSided) { pCurrOut[4].m_vPos = vCenter - vRight - vDown; pCurrOut[4].m_vUV.Init(1.0f, 0.0f); pCurrOut[5].m_vPos = vCenter + vRight - vDown; pCurrOut[5].m_vUV.Init(0.0f, 0.0f); pCurrOut[6].m_vPos = vCenter + vRight + vDown; pCurrOut[6].m_vUV.Init(0.0f, 1.0f); pCurrOut[7].m_vPos = vCenter - vRight + vDown; pCurrOut[7].m_vUV.Init(1.0f, 1.0f); //setup the remaining vertex components for(uint32 nCurrVert = 4; nCurrVert < 8; nCurrVert++) { pCurrOut[nCurrVert].m_nPackedColor = nColor; pCurrOut[nCurrVert].m_vNormal = -vNormal; pCurrOut[nCurrVert].m_vTangent = -vTangent; pCurrOut[nCurrVert].m_vBinormal = vBinormal; } } //unlock and render the batch pInterface->UnlockAndBindDynamicVertexBuffer(LockRequest); pInterface->RenderIndexed( eCustomRenderPrimType_TriangleList, 0, nNumIndices, LockRequest.m_nStartIndex, 0, nNumVertices); }
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); } }
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)); }
bool CAIActionGotoValidPosition::GetValidPosition(CAI* pAI, LTVector& outValidPosition) { // fail if the AI does not currently have a nav mesh poly. // find the nearest nav mesh poly that is not a border // find the nearest point on the poly // return this point //---- // AI is not in a nav mesh poly. ENUM_NMPolyID eID = pAI->GetCurrentNavMeshPoly(); if ( kNMPoly_Invalid == eID) { return false; } // Find the closest non edge poly. const LTVector vAIPosition(pAI->GetPosition().x, 0, pAI->GetPosition().z); float flBestDistance = FLT_MAX; LTVector vBestPosition(0.f, 0.f, 0.f); LTVector vBestCenter(0.f, 0.f, 0.f); CAINavMeshPoly* pNMPoly = g_pAINavMesh->GetNMPoly( eID ); int nEdges = pNMPoly->GetNumNMPolyEdges(); for (int i = 0; i < nEdges; ++i) { CAINavMeshEdge* pEdge = pNMPoly->GetNMPolyEdge(i); if (pEdge) { if (kNMEdgeType_Border == pEdge->GetNMEdgeType()) { // This edge is a border, skip it. continue; } // Verify that the other poly is valid for entry CAINavMeshPoly* pNMOtherPoly = NULL; if ( eID == pEdge->GetNMPolyIDA()) { pNMOtherPoly = g_pAINavMesh->GetNMPoly( pEdge->GetNMPolyIDB() ); } else { pNMOtherPoly = g_pAINavMesh->GetNMPoly( pEdge->GetNMPolyIDA() ); } // Verify that the other link, if there is one, is valid for entry if (pNMOtherPoly && (kNMLink_Invalid != pNMOtherPoly->GetNMLinkID())) { AINavMeshLinkAbstract* pLink = g_pAINavMesh->GetNMLink(pNMOtherPoly->GetNMLinkID()); if (pLink) { if (!pLink->IsNMLinkEnabledToAI(pAI, !LINK_CHECK_TIMEOUT)) { continue; } } } // Find the closest point on the poly LTVector vEdge0 = pEdge->GetNMEdge0(); vEdge0.y = 0.f; LTVector vEdge1 = pEdge->GetNMEdge1(); vEdge1.y = 0.f; LTVector vPos; float flDummy; float flDist = LTIntersect::Point_Segment_DistSqr(vAIPosition, vEdge0, vEdge1, vPos, flDummy); // Better exit location found. if (flDist < flBestDistance) { flBestDistance = flDist; vBestPosition = vPos; vBestCenter = pNMOtherPoly->GetNMPolyCenter(); } } } // Failed to find a valid position. if (FLT_MAX == flBestDistance) { return false; } // Return the position (adjust it by moving the height to match the AIs // current elevation, and adjust the point by a fraction in the direction the AI is // moving to insure that he gets out of the disabled link. LTVector vDirection = vBestPosition - vAIPosition; vDirection.Normalize(); LTVector vDestination = LTVector(vBestPosition.x, pAI->GetPosition().y, vBestPosition.z) + (vDirection * pAI->GetRadius()); if( g_pAIPathMgrNavMesh->StraightPathExists( pAI, pAI->GetCharTypeMask(), pAI->GetPosition(), vDestination, pAI->GetLastNavMeshPoly(), pAI->GetRadius() ) ) { outValidPosition = vDestination; return true; } // Failed to move to the ideal location. Try moving to the center of the // poly. This should always succeed. If it doesn't, add a fix which will // work to handle this case. AIASSERT(g_pAIPathMgrNavMesh->HasPath(pAI, pAI->GetCharTypeMask(), vBestCenter), pAI->GetHOBJECT(), "CAIActionGotoValidPosition::GetValidPosition : Failed to find path to the center of a neighboring poly." ); outValidPosition = vBestCenter; return true; }
bool CAIActionSurpriseAttackLaunch::ValidateContextPreconditions( CAI* pAI, CAIWorldState& wsWorldStateGoal, bool bIsPlanning ) { if ( !super::ValidateContextPreconditions( pAI, wsWorldStateGoal, bIsPlanning ) ) { return false; } // Verify the node has a smartobject. (if it doesn't, this node will // not be used. This is an level design error, but an easy one to make, // so report it. if ( NULL == GetAtNodeSmartObjectRecord( *pAI->GetAIWorldState(), pAI->GetHOBJECT() ) ) { return false; } // AI is either not at a surprise node, or the node does not have a // valid action. if ( kAP_Invalid == GetAtNodeAttackProp( *pAI->GetAIWorldState(), pAI->GetHOBJECT(), pAI->GetAIBlackBoard()->GetBBTargetObject() ) ) { return false; } // Fail if the AI is not facing the node. SAIWORLDSTATE_PROP* pAtNodeProp = pAI->GetAIWorldState()->GetWSProp( kWSK_AtNode, pAI->GetHOBJECT() ); if ( !pAtNodeProp || ( !pAtNodeProp->hWSValue ) ) { return false; } AINode* pNode = AINode::HandleToObject( pAtNodeProp->hWSValue ); if ( !pNode ) { return false; } if ( pNode->GetFaceNode() ) { LTVector vNodeDir = pNode->GetNodeFaceDir(); vNodeDir.y = 0.0f; vNodeDir.Normalize(); if ( vNodeDir == LTVector::GetIdentity() ) { return false; } LTVector vAIForward = pAI->GetForwardVector(); vAIForward.y = 0.0f; vAIForward.Normalize(); if ( vAIForward == LTVector::GetIdentity() ) { return false; } if ( vAIForward.Dot( vNodeDir ) < 0.9999f ) { return false; } } // Success! return true; }
void Breakable::UpdateFalling() { LTVector vOldPos; g_pLTServer->GetObjectPos(m_hObject, &vOldPos); LTVector vPos = vOldPos; vPos += (m_vVel * g_pLTServer->GetFrameTime()); LTBOOL bDone = LTFALSE; if (vPos.y < m_vFinalPos.y) { vPos.y = m_vFinalPos.y; bDone = LTTRUE; } g_pLTServer->TeleportObject(m_hObject, &vPos); if (vPos.Equals(m_vFinalPos, 10.0f)) { bDone = LTTRUE; } if (bDone) { m_bFalling = LTFALSE; uint32 dwFlags = g_pLTServer->GetObjectFlags(m_hObject); dwFlags |= FLAG_SOLID; g_pLTServer->SetObjectFlags(m_hObject, dwFlags); g_pLTServer->SetNextUpdate(m_hObject, 0.0f); // Create impact fx... CreateImpactFX(); if (m_bDestroyOnImpact) { Destroy(); } else { // Play the impact sound... if (m_hstrImpactSound) { LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); char* pSnd = g_pLTServer->GetStringData(m_hstrImpactSound); if (pSnd) { g_pServerSoundMgr->PlaySoundFromPos(vPos, pSnd, m_fImpactSoundRadius, SOUNDPRIORITY_MISC_MEDIUM); } } } } }
void CTriggerFX::CalcLocalClientDistance() { m_fDistPercent = -1.0f; // Don't do anything if the trigger is locked or our distances are too small.. if( m_cs.bLocked || (m_cs.fHUDAlwaysOnDist <= 0.0f && m_cs.fHUDLookAtDist <= 0.0f) ) return; // See if the player is within the trigger... LTVector vTrigPos; g_pLTClient->GetObjectPos( m_hServerObject, &vTrigPos ); g_pLTClient->SetObjectPos( m_hDimsObject, vTrigPos ); HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject(); LTVector vPlayerPos, vPlayerDims; g_pLTClient->GetObjectPos( hPlayerObj, &vPlayerPos ); // Make sure we are within the display radius... float fMaxRadius = LTMAX( m_cs.fHUDAlwaysOnDist, m_cs.fHUDLookAtDist ); float fDistSqr = vTrigPos.DistSqr( vPlayerPos ); bool bWithinLookAtDist = (fDistSqr < m_cs.fHUDLookAtDist * m_cs.fHUDLookAtDist); bool bWithinAlwaysOnDist = (fDistSqr < m_cs.fHUDAlwaysOnDist * m_cs.fHUDAlwaysOnDist); if( !bWithinLookAtDist && !bWithinAlwaysOnDist ) { // We are not close enough... m_bWithinIndicatorRadius = false; return; } m_bWithinIndicatorRadius = true; g_pPhysicsLT->GetObjectDims( hPlayerObj, &vPlayerDims ); LTVector vTrigMin = vTrigPos - m_cs.vDims; LTVector vTrigMax = vTrigPos + m_cs.vDims; LTVector vPlayerMin = vPlayerPos - vPlayerDims; LTVector vPlayerMax = vPlayerPos + vPlayerDims; // Check if we are within the height of the trigger... bool bWithinHeight =false; if( vPlayerMax.y > vTrigMin.y && vPlayerMin.y < vTrigMax.y ) bWithinHeight = true; // See if we are inside the trigger at all... if( bWithinHeight && (BoxesIntersect( vTrigMin, vTrigMax, vPlayerMin, vPlayerMax ) || bWithinAlwaysOnDist)) { m_fDistPercent = 1.0f; } else { // We are within the height of the trigger, show how far from it we are... float fMinDist = (vPlayerDims.x + vPlayerDims.z) * 0.5f; float fMaxDist = 100000.0f; LTVector vDir; if( bWithinAlwaysOnDist ) { vDir = vTrigPos - vPlayerPos; vDir.Normalize(); } else { LTRotation const& rRot = g_pPlayerMgr->GetPlayerCamera()->GetCameraRotation( ); vDir = rRot.Forward(); } IntersectQuery IQuery; IntersectInfo IInfo; IQuery.m_From = vPlayerPos + (vDir * fMinDist); IQuery.m_To = IQuery.m_From + (vDir * fMaxDist); IQuery.m_Flags = INTERSECT_OBJECTS | INTERSECT_HPOLY | IGNORE_NONSOLID; // We need to recieve rayhits for this intersect call... g_pCommonLT->SetObjectFlags( m_hDimsObject, OFT_Flags, FLAG_RAYHIT, FLAG_RAYHIT ); if( g_pLTClient->IntersectSegment( IQuery, &IInfo )) { if( IInfo.m_hObject == m_hDimsObject ) { IInfo.m_Point.y = vPlayerPos.y; float fDist = vPlayerPos.Dist( IInfo.m_Point ); m_fDistPercent = 1.0f - (fDist / fMaxRadius); } } // No more rayhits... g_pCommonLT->SetObjectFlags( m_hDimsObject, OFT_Flags, 0, FLAG_RAYHIT ); } }
void Prop::HandleAttachmentTouch( HOBJECT hToucher ) { if( !hToucher || !m_bAttachmentShotOff ) return; // Don't touch the owner... if( hToucher == m_hAttachmentOwner ) return; // Or any non-solid objects... uint32 dwToucherFlags; g_pCommonLT->GetObjectFlags( hToucher, OFT_Flags, dwToucherFlags ); if( !(dwToucherFlags & FLAG_SOLID) ) return; CollisionInfo info; g_pLTServer->GetLastCollision( &info ); LTVector vVel; g_pPhysicsLT->GetVelocity( m_hObject, &vVel ); // Calculate where we really hit the world... if( IsMainWorld( hToucher )) { LTVector vPos, vCurVel, vP0, vP1; g_pLTServer->GetObjectPos( m_hObject, &vPos ); vP1 = vPos; vCurVel = vVel * g_pLTServer->GetFrameTime(); vP0 = vP1 - vCurVel; vP1 += vCurVel; LTFLOAT fDot1 = VEC_DOT( info.m_Plane.m_Normal, vP0 ) - info.m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT( info.m_Plane.m_Normal, vP1 ) - info.m_Plane.m_Dist; if( fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f ) { vPos = vP1; } else { LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1); VEC_LERP( vPos, vP0, vP1, fPercent); } // Set our new "real" pos... g_pLTServer->SetObjectPos( m_hObject, &vPos ); } // If we're on the ground (or an object), stop movement... CollisionInfo standingInfo; g_pLTServer->GetStandingOn( m_hObject, &standingInfo ); CollisionInfo* pInfo = standingInfo.m_hObject ? &standingInfo : &info; if( pInfo->m_hObject ) { // Don't stop on walls... if( pInfo->m_Plane.m_Normal.y > 0.75f ) { vVel.Init(); // Turn off gravity, solid, and touch notify.... uint32 dwFlags = FLAG_POINTCOLLIDE | FLAG_NOSLIDING | FLAG_TOUCH_NOTIFY | FLAG_GRAVITY; g_pCommonLT->SetObjectFlags( m_hObject, OFT_Flags, 0, dwFlags ); // Rotate to rest... if( m_bRotating ) { LTRotation rRot( 0.0f, m_fYaw, 0.0f ); g_pLTServer->SetObjectRotation( m_hObject, &rRot ); m_bRotating = false; StartFade( s_vtAttachmentFadeDuration.GetFloat(), s_vtAttachmentFadeDelay.GetFloat() ); } } } // Remove the stoping velocity... vVel = -info.m_vStopVel; g_pPhysicsLT->SetVelocity( m_hObject, &vVel ); }
void CLaserBeam::Update(LTVector vBeamStartPos, LTRotation* pRDirRot, LTBOOL b3rdPerson, LTBOOL bDetect) { if (!m_bOn) return; // Calculate beam position... HOBJECT hCamera = g_pGameClientShell->GetCamera(); if (!hCamera) return; HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject(); if (!hPlayerObj) return; HOBJECT hFilterList[] = {hPlayerObj, g_pGameClientShell->GetMoveMgr()->GetObject(), LTNULL}; IntersectQuery qInfo; IntersectInfo iInfo; LTVector vPos(0, 0, 0); LTRotation rRot; rRot.Init(); LTVector vU, vR, vF; if (pRDirRot && b3rdPerson) { vPos = vBeamStartPos; g_pLTClient->GetRotationVectors(pRDirRot, &vU, &vR, &vF); } else { g_pLTClient->GetObjectRotation(hCamera, &rRot); g_pLTClient->GetObjectPos(hCamera, &vPos); g_pLTClient->GetRotationVectors(&rRot, &vU, &vR, &vF); if (g_cvarLaserBeamDebug.GetFloat() == 0.0f) { vBeamStartPos += vPos; } else if (g_cvarLaserBeamDebug.GetFloat() == 1.0f) { vBeamStartPos = vPos; } else { g_pLTClient->GetRotationVectors(pRDirRot, &vU, &vR, &vF); vBeamStartPos = vBeamStartPos; } } LTVector vEndPos = vPos + (vF * 10000.0f); qInfo.m_From = vPos; qInfo.m_To = vEndPos; qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; qInfo.m_FilterFn = ObjListFilterFn; qInfo.m_pUserData = hFilterList; if (g_pLTClient->IntersectSegment(&qInfo, &iInfo)) { vEndPos = iInfo.m_Point; } // Show the light beam... LTVector vColor = LTVector(GetRandom(235.0f, 255.0f), GetRandom(35.0f, 55.0f), GetRandom(35.0f, 55.0f));; LTFLOAT fAlpha = g_cvarLaserBeamAlpha.GetFloat(); if (iInfo.m_hObject && bDetect) { uint32 dwUsrFlgs = 0; g_pLTClient->GetObjectUserFlags(iInfo.m_hObject, &dwUsrFlgs); if (dwUsrFlgs & USRFLG_CHARACTER) { fAlpha = 0.95f; vColor.Init(GetRandom(35.0f, 55.0f), GetRandom(235.0f, 255.0f), GetRandom(35.0f, 55.0f));; } } LTFLOAT fWidth = g_cvarLaserBeamThickness.GetFloat(); fWidth = b3rdPerson ? fWidth*2.0f : fWidth; vBeamStartPos += (vF * g_cvarLaserBeamFOffset.GetFloat()); vBeamStartPos += (vR * g_cvarLaserBeamROffset.GetFloat()); vBeamStartPos += (vU * g_cvarLaserBeamUOffset.GetFloat()); PLFXCREATESTRUCT pls; if (g_cvarLaserBeamDebug.GetFloat() >= 0.0f) { // g_pLTClient->CPrint("StartPos = %.2f, %.2f, %.2f", VEC_EXPAND(vBeamStartPos)); // g_pLTClient->CPrint("EndPos = %.2f, %.2f, %.2f", VEC_EXPAND(vEndPos)); } pls.vStartPos = vBeamStartPos; pls.vEndPos = vEndPos; pls.vInnerColorStart = vColor; pls.vInnerColorEnd = pls.vInnerColorStart; pls.vOuterColorStart = LTVector(0, 0, 0); pls.vOuterColorEnd = LTVector(0, 0, 0); pls.fAlphaStart = fAlpha; pls.fAlphaEnd = fAlpha; pls.fMinWidth = 0; pls.fMaxWidth = fWidth; pls.fMinDistMult = 1.0f; pls.fMaxDistMult = 1.0f; pls.fLifeTime = 1.0f; pls.fAlphaLifeTime = 1.0f; pls.fPerturb = 0.0f; pls.bAdditive = LTTRUE; pls.bAlignFlat = b3rdPerson ? LTFALSE : LTTRUE; pls.nWidthStyle = PLWS_CONSTANT; pls.nNumSegments = (int)g_cvarLaserBeamNumSegments.GetFloat(); if (m_LightBeam.HasBeenDrawn()) { // Keep the light beam in the vis list... m_LightBeam.SetPos(vBeamStartPos); // Hide the beam in portals if 1st person...Also set flag really // close to true... uint32 dwFlags2, dwFlags; dwFlags = m_LightBeam.GetFlags(); dwFlags2 = m_LightBeam.GetFlags2(); if (b3rdPerson) { dwFlags &= ~FLAG_REALLYCLOSE; dwFlags2 &= ~FLAG2_PORTALINVISIBLE; } else { if (g_cvarLaserBeamDebug.GetFloat() > 1.0f) { dwFlags |= FLAG_REALLYCLOSE; pls.bUseObjectRotation = LTTRUE; } dwFlags2 |= FLAG2_PORTALINVISIBLE; } m_LightBeam.SetFlags(dwFlags); m_LightBeam.SetFlags2(dwFlags2); m_LightBeam.ReInit(&pls); } else { m_LightBeam.Init(&pls); m_LightBeam.CreateObject(g_pLTClient); } m_LightBeam.Update(); }
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 ModelDraw::SetupModelLight(ModelInstance* pInstance, const ModelHookData& HookData, CRelevantLightList& LightList) { //setup our light list information uint32 nMaxLights = LTMIN((uint32)g_CV_MaxModelLights, MAX_LIGHTS_SUPPORTED_BY_D3D); LTVector vInstancePosition; // Should we skip the root node and use it's first child node // for lighting consideration? if(g_CV_ModelLightingSkipRootNode) { // Index of the root node (should be 0) uint32 iRootNode = pInstance->NodeGetRootIndex(); // How many children nodes does it have? uint32 iRootNodeNumKids = pInstance->NodeGetNumChildren( iRootNode ); // Is there atleast one? if(iRootNodeNumKids > 0) { // Just get the first one. // This assumes the the first child-node translates with the rest // of the mesh. uint32 iNode = pInstance->NodeGetChild( iRootNode, 0 ); LTransform tf; pInstance->GetNodeTransform( iNode, tf, true ); // Set our calculation position to the node's position vInstancePosition = tf.m_Pos; } else { // If the root node doesn't have any children, // fall back to the root node's position. vInstancePosition = pInstance->GetPos(); } } else // No? Then just use the root node position { //figure out the world position of this instance vInstancePosition = pInstance->GetPos(); } LightList.ClearList(); LightList.SetMaxLights(nMaxLights); LightList.SetObjectPos(vInstancePosition); LightList.SetObjectDims(pInstance->GetDims()); // If they don't want lighting, set the values for no lighting and skip out if((g_CV_LightModels.m_Val == 0) || (HookData.m_ObjectFlags & FLAG_NOLIGHT)) { LightList.AddAmbient(LTVector(255.0f, 255.0f, 255.0f)); return; } //determine if we are in really close space bool bReallyClose = (HookData.m_ObjectFlags & FLAG_REALLYCLOSE) != 0; //////////////////////////////////////////////////////////////////// // Add light from the environment. CRenderLight RenderLight; if(bReallyClose) { //this is really close, we need to transform it into the world g_ViewParams.m_mInvView.Apply(vInstancePosition); } // Global directional light dir. float fDirLightAmount = 0.0f; if (g_have_world && g_CV_ModelApplySun.m_Val && (g_pStruct->m_GlobalLightColor.x || g_pStruct->m_GlobalLightColor.y || g_pStruct->m_GlobalLightColor.z)) { // Use the previous lighting amount if it hasn't moved if ((pInstance->m_LastDirLightAmount >= 0.0f) && (((pInstance->m_Flags2 & FLAG2_DYNAMICDIRLIGHT) == 0) || (vInstancePosition.NearlyEquals(pInstance->m_LastDirLightPos, g_CV_ModelSunVariance.m_Val + 0.001f)))) { fDirLightAmount = pInstance->m_LastDirLightAmount; } else { // Remember where we were last time we did this pInstance->m_LastDirLightPos = vInstancePosition; // Calculate the lighting fDirLightAmount = GetDirLightAmount(pInstance, vInstancePosition); // Remember the result pInstance->m_LastDirLightAmount = fDirLightAmount; } //setup the direction of the light LTVector vDirLightDir = g_pStruct->m_GlobalLightDir; if (bReallyClose) { // Put the lighting in our space g_ViewParams.m_mView.Apply3x3(vDirLightDir); } LTVector vScaledLightColor = g_pStruct->m_GlobalLightColor * fDirLightAmount; //add the directional light to the light list RenderLight.SetupDirLight(vDirLightDir, vScaledLightColor, FLAG_CASTSHADOWS); LightList.InsertLight(RenderLight, g_pStruct->m_GlobalLightConvertToAmbient); } // Ambient lighting if(g_have_world && g_CV_ModelApplyAmbient) { LTRGBColor ambientColor; w_DoLightLookup(world_bsp_shared->LightTable(), &vInstancePosition, &ambientColor); LTVector vAmbientLight; vAmbientLight.x = ambientColor.rgb.r; vAmbientLight.y = ambientColor.rgb.g; vAmbientLight.z = ambientColor.rgb.b; LightList.AddAmbient(vAmbientLight); } //////////////////////////////////////////////////////////////////// // Figure out the lights that will be directionally lighting it. // Dynamic lights.. for(uint32 i=0; i < g_nNumObjectDynamicLights; i++) { DynamicLight* pSrcLight = g_ObjectDynamicLights[i]; if ((pSrcLight->m_Flags & FLAG_ONLYLIGHTWORLD) != 0) continue; LTVector vPos = pSrcLight->GetPos(); if (bReallyClose) { // Put the lighting in our space vPos = g_ViewParams.m_mView * vPos; } LTVector vColor((float)pSrcLight->m_ColorR, (float)pSrcLight->m_ColorG, (float)pSrcLight->m_ColorB); LTVector vAttCoeff(1.0f, 0.0f, 19.0f/(pSrcLight->m_LightRadius*pSrcLight->m_LightRadius)); RenderLight.SetupPointLight(vPos, vColor, vAttCoeff, pSrcLight->m_LightRadius, eAttenuation_D3D, 0); LightList.InsertLight(RenderLight, 0.0f); } // Static lights.. if(g_have_world) { //fill out the callback data structure SStaticLightCallbackData CallbackData; CallbackData.m_pInstance = pInstance; CallbackData.m_pLightList = &LightList; //figure out what radius to use for this model float fModelRadius = pInstance->GetModelDB()->m_VisRadius; FindObjInfo foInfo; foInfo.m_iObjArray = NOA_Lights; foInfo.m_Min = vInstancePosition - LTVector(fModelRadius, fModelRadius, fModelRadius); foInfo.m_Max = vInstancePosition + LTVector(fModelRadius, fModelRadius, fModelRadius); foInfo.m_CB = &ModelDraw::StaticLightCB; foInfo.m_pCBUser = &CallbackData; world_bsp_client->ClientTree()->FindObjectsInBox2(&foInfo); } }
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; }
bool RayIntersectBox(const LTVector& vBoxMin, const LTVector& vBoxMax, const LTVector& vOrigin, const LTVector& vDest, LTVector* pvIntersection) { const uint8 kNumDimensions = 3; // Calculate direction of ray. LTVector vDir = vDest - vOrigin; vDir.Normalize(); // Algorithm taken from Graphics Gems p.736. enum EnumQuadrant { kQuad_Right, kQuad_Left, kQuad_Middle, }; bool bInside = true; EnumQuadrant eQuad[kNumDimensions]; LTFLOAT fCandidatePlane[kNumDimensions]; // Find candidate planes. for( uint32 iDim=0; iDim < kNumDimensions; ++iDim ) { if( vOrigin[iDim] < vBoxMin[iDim] ) { if( vDest[iDim] < vBoxMin[iDim] ) { return false; } eQuad[iDim] = kQuad_Left; fCandidatePlane[iDim] = vBoxMin[iDim]; bInside = false; } else if( vOrigin[iDim] > vBoxMax[iDim] ) { if( vDest[iDim] > vBoxMax[iDim] ) { return false; } eQuad[iDim] = kQuad_Right; fCandidatePlane[iDim] = vBoxMax[iDim]; bInside = false; } else { eQuad[iDim] = kQuad_Middle; } } // Ray origin is inside volume. if( bInside ) { *pvIntersection = vOrigin; return true; } uint32 nWhichPlane = 0; LTFLOAT fMaxT[kNumDimensions]; // Calculate T distances to candidate planes. for(int iDim=0; iDim < kNumDimensions; ++iDim ) { if( ( eQuad[iDim] != kQuad_Middle ) && ( vDir[iDim] != 0.f ) ) { fMaxT[iDim] = ( fCandidatePlane[iDim] - vOrigin[iDim] ) / vDir[iDim]; } else { fMaxT[iDim] = -1.f; } } // Get largest of the maxT's for final choice of intersection. for(int iDim=1; iDim < kNumDimensions; ++iDim ) { if( fMaxT[nWhichPlane] < fMaxT[iDim] ) { nWhichPlane = iDim; } } // Check final candidate actually inside volume. if( fMaxT[nWhichPlane] < 0.f ) { return false; } for(int iDim=0; iDim < kNumDimensions; ++iDim ) { if( nWhichPlane != iDim ) { (*pvIntersection)[iDim] = vOrigin[iDim] + fMaxT[nWhichPlane] * vDir[iDim]; if( ((*pvIntersection)[iDim] < vBoxMin[iDim]) || ((*pvIntersection)[iDim] > vBoxMax[iDim]) ) { return false; } } else { (*pvIntersection)[iDim] = fCandidatePlane[iDim]; } } return true; }