bool CAIWeaponAbstract::DefaultFire(CAI* pAI, const LTVector& vTargetPos, bool bAnimatesReload) { if( !( m_pWeapon && m_pAIWeaponRecord ) ) { return false; } HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject(); // Get our fire position LTVector vFirePos = GetFirePosition(pAI); // Get our firing vector LTVector vDir = vTargetPos - vFirePos; vDir.Normalize(); // Now fire the weapon WeaponFireInfo weaponFireInfo; static uint8 s_nCount = GetRandom( 0, 255 ); s_nCount++; weaponFireInfo.hFiredFrom = pAI->GetHOBJECT(); weaponFireInfo.vPath = vDir; weaponFireInfo.vFirePos = vFirePos; weaponFireInfo.vFlashPos = vFirePos; weaponFireInfo.hTestObj = hTarget; weaponFireInfo.hFiringWeapon = m_pWeapon->GetModelObject(); weaponFireInfo.nSeed = (uint8)GetRandom( 2, 255 ); weaponFireInfo.nPerturbCount = s_nCount; weaponFireInfo.nFireTimestamp = g_pLTServer->GetRealTimeMS( ); weaponFireInfo.bLeftHandWeapon = ( LTStrIEquals( m_szFireSocketName.c_str( ), "LEFTHAND" ) ); if( pAI->GetAIBlackBoard()->GetBBPerfectAccuracy() ) { weaponFireInfo.fPerturb = 0.0f; } else { weaponFireInfo.fPerturb = 1.f; } WeaponState eWeaponState = m_pWeapon->UpdateWeapon( weaponFireInfo, true ); if( eWeaponState == W_FIRED ) { UpdateWeaponAnimation( pAI ); } if( m_pWeapon->GetAmmoInClip() == 0 ) { // Automatically reload if: // 1) The AI has more ammo for this weapon and // 2) Either the AI is flagged to autoreload, or the weapon is flagged to not animation reloads. if( AIWeaponUtils::HasAmmo(pAI, m_pAIWeaponRecord->eAIWeaponType, !AIWEAP_CHECK_HOLSTER) && ( ( pAI->GetAIBlackBoard()->GetBBAutoReload() && m_pAIWeaponRecord->bAllowAutoReload ) || !bAnimatesReload) ) { Reload(pAI); } else { pAI->GetAIWorldState()->SetWSProp( kWSK_WeaponLoaded, pAI->GetHOBJECT(), kWST_bool, false ); } } else { pAI->GetAIWorldState()->SetWSProp( kWSK_WeaponLoaded, pAI->GetHOBJECT(), kWST_bool, true ); } // If the primary weapon is now out of ammo, set the WeaponArmed // worldstate to false. if( pAI->GetAIBlackBoard()->GetBBPrimaryWeaponType() == m_pAIWeaponRecord->eAIWeaponType && !AIWeaponUtils::HasAmmo(pAI, m_pAIWeaponRecord->eAIWeaponType, !AIWEAP_CHECK_HOLSTER)) { pAI->GetAIBlackBoard()->SetBBSelectAction(true); } return true; }
bool CAIWeaponAbstract::DefaultThrow(CAI* pAI) { // Make sure the basic pointers are valid. ASSERT(m_pWeapon); ASSERT(pAI); if (!pAI || !m_pWeapon || !m_pAIWeaponRecord) { return false; } // Don't fire if AI has no target. if( !pAI->HasTarget( kTarget_Character | kTarget_Object ) ) { return false; } HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject(); // Throw at the last known position. LTVector vTargetPos; CAIWMFact factTargetQuery; factTargetQuery.SetFactType( kFact_Character ); factTargetQuery.SetTargetObject( hTarget ); CAIWMFact* pFact = pAI->GetAIWorkingMemory()->FindWMFact( factTargetQuery ); if( pFact ) { vTargetPos = pFact->GetPos(); } else { g_pLTServer->GetObjectPos(hTarget, &vTargetPos); } // Offset the target pos a little so projectile lands in front of the target. LTVector vOffsetDir; vOffsetDir = pAI->GetPosition() - vTargetPos; vOffsetDir.y = 0.f; vOffsetDir.Normalize(); vTargetPos += vOffsetDir * 384.f; // Get our fire position LTVector vFirePos = GetFirePosition(pAI); // Velocity Vo LTVector vGravity; g_pPhysicsLT->GetGlobalForce( vGravity ); // Vo = (S - R - 1/2*G*t^2) / t // Vo = initial velocity // S = destination // R = origin // G = gravity // t = hangtime float fHangtime = 0.5f; LTVector vVelocity = ( vTargetPos - vFirePos - vGravity * .5f * fHangtime * fHangtime ) / fHangtime; float fVelocity = vVelocity.Mag(); LTVector vDir( vVelocity / fVelocity ); // Now fire the weapon WeaponFireInfo weaponFireInfo; static uint8 s_nCount = GetRandom( 0, 255 ); s_nCount++; weaponFireInfo.hFiredFrom = pAI->GetHOBJECT(); weaponFireInfo.vPath = vDir; weaponFireInfo.bOverrideVelocity = LTTRUE; weaponFireInfo.fOverrideVelocity = fVelocity; weaponFireInfo.vFirePos = vFirePos; weaponFireInfo.vFlashPos = vFirePos; weaponFireInfo.hTestObj = hTarget; weaponFireInfo.fPerturb = 1.0f * (1.0f - pAI->GetAccuracy() ); weaponFireInfo.nSeed = (uint8)GetRandom( 2, 255 ); weaponFireInfo.nPerturbCount = s_nCount; weaponFireInfo.nFireTimestamp = g_pLTServer->GetRealTimeMS( ); m_pWeapon->ReloadClip( LTFALSE ); if (m_pAIWeaponRecord->bAllowAmmoGeneration) { m_pWeapon->GetArsenal()->AddAmmo( m_pWeapon->GetAmmoRecord(), 999999 ); } m_pWeapon->UpdateWeapon( weaponFireInfo, LTTRUE ); return true; }
//---------------------------------------------------------------------------- // // ROUTINE: CAIHumanStrategyShootStream::UpdateFiring() // // PURPOSE: Updates the firing state, first allowing the base class to // handle the basics, then extending it to check the animation // lock state for handling progression from eFireStateStart to // eFireStateFiring. // //---------------------------------------------------------------------------- /*virtual*/ void CAIHumanStrategyShootStream::UpdateFiring(HOBJECT hTarget,const LTVector& vTargetPos, CWeapon* pWeapon) { AIASSERT( LTTRUE == m_bFired, GetAI()->GetHOBJECT(), "Expected Fired to be true. Check logic."); switch ( m_eFireState ) { case eFireStateStart: { if ( !GetAI()->GetAnimationContext()->IsLocked() ) { m_eFireState = eFireStateFiring; } } break; case eFireStateFiring: { // Get our fire position AIASSERT( GetAI()->GetCurrentWeapon(), GetAI()->m_hObject, "UpdateFiring without a weapon" ); LTVector vFirePos = GetFirePosition(GetAI()->GetCurrentWeapon()); // Now fire the weapon WeaponFireInfo weaponFireInfo; weaponFireInfo.nDiscTrackingType = MPROJ_DISC_TRACKING_STEADY; weaponFireInfo.hSocket = m_hFiringSocket!=INVALID_MODEL_SOCKET ? m_hFiringSocket : GetAI()->GetWeaponSocket(GetAI()->GetCurrentWeapon()); weaponFireInfo.hFiredFrom = GetAI()->GetObject(); weaponFireInfo.vPath = vTargetPos - vFirePos; weaponFireInfo.vFirePos = vFirePos; weaponFireInfo.vFlashPos = vFirePos; weaponFireInfo.hTestObj = hTarget; weaponFireInfo.fPerturbR = LOWER_BY_DIFFICULTY(s_fPerturbScale)*(1.0f - GetAI()->GetAccuracy()); weaponFireInfo.fPerturbU = LOWER_BY_DIFFICULTY(s_fPerturbScale)*(1.0f - GetAI()->GetAccuracy()); pWeapon->UpdateWeapon(weaponFireInfo, LTTRUE); Fire(); // Check to see our fire timer expired if ( m_flStreamTime < g_pLTServer->GetTime() || !GetAI()->GetAnimationContext()->IsLocked()) { m_eFireState = eFireStateEnding; } } break; case eFireStateEnding: { if ( !GetAI()->GetAnimationContext()->IsLocked() ) { m_eFireState = eFireStateInvalid; m_bFiringStream = LTFALSE; m_eState = eStateAiming; return; } } break; default: { AIASSERT( 0, m_pAIHuman->GetHOBJECT(), "CAIHumanStrategyShootStream::UpdateAnimation: Unexpected m_eFireState"); } break; } }