2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# include "../idlib/precompiled.h"
# pragma hdrstop
# include "Game_local.h"
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Contains the AimAssist implementation .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idCVar aa_targetAimAssistEnable ( " aa_targetAimAssistEnable " , " 0 " , CVAR_BOOL | CVAR_ARCHIVE , " Enables/Disables the entire Aim Assist system " ) ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
idCVar aa_targetAdhesionEnable ( " aa_targetAdhesionEnable " , " 1 " , CVAR_BOOL , " Enables Target Adhesion " ) ;
idCVar aa_targetFrictionEnable ( " aa_targetFrictionEnable " , " 1 " , CVAR_BOOL , " Enables Target Friction " ) ;
2012-11-26 18:58:24 +00:00
// Selection
2012-11-28 15:47:07 +00:00
idCVar aa_targetMaxDistance ( " aa_targetMaxDistance " , " 3000 " , CVAR_FLOAT , " The Maximum Distance away for a target to be considered for adhesion, friction and target lock-to " ) ;
idCVar aa_targetSelectionRadius ( " aa_targetSelectionRadius " , " 128.0 " , CVAR_FLOAT , " Radius used to select targets for auto aiming " ) ;
2012-11-26 18:58:24 +00:00
// Adhesion
2012-11-28 15:47:07 +00:00
idCVar aa_targetAdhesionRadius ( " aa_targetAdhesionRadius " , " 96.0 " , CVAR_FLOAT , " Radius used to apply adhesion amount " ) ;
idCVar aa_targetAdhesionYawSpeedMax ( " aa_targetAdhesionYawSpeedMax " , " 0.6 " , CVAR_FLOAT , " Max Yaw Adhesion Speed " ) ;
idCVar aa_targetAdhesionPitchSpeedMax ( " aa_targetAdhesionPitchSpeedMax " , " 0.6 " , CVAR_FLOAT , " Max Pitch Adhesion Speed " ) ;
idCVar aa_targetAdhesionContributionPctMax ( " aa_targetAdhesionContributionPctMax " , " 0.25 " , CVAR_FLOAT , " Max Adhesion Contribution Percentage - Range 0.0 - 1.0 " ) ;
idCVar aa_targetAdhesionPlayerSpeedThreshold ( " aa_targetAdhesionPlayerSpeedThreshold " , " 10.0 " , CVAR_FLOAT , " Speed Threshold that determines how fast the player needs to move before adhesion is allowed to kick in " ) ;
2012-11-26 18:58:24 +00:00
// Friction
2012-11-28 15:47:07 +00:00
idCVar aa_targetFrictionMaxDistance ( " aa_targetFrictionMaxDistance " , " 1024.0 " , CVAR_FLOAT , " Minimum Distance Friction takes effect " ) ;
idCVar aa_targetFrictionOptimalDistance ( " aa_targetFrictionOptimalDistance " , " 768.0 " , CVAR_FLOAT , " Optimal Distance for Friction to take an effect " ) ;
idCVar aa_targetFrictionRadius ( " aa_targetFrictionRadius " , " 96.0 " , CVAR_FLOAT , " Friction Collision Sphere Radius " ) ;
idCVar aa_targetFrictionOptimalRadius ( " aa_targetFrictionOptimalRadius " , " 192.0 " , CVAR_FLOAT , " Friction Collision Sphere Radius when at Optimal Distance " ) ;
idCVar aa_targetFrictionMultiplierMin ( " aa_targetFrictionMultiplierMin " , " 1.0 " , CVAR_FLOAT , " Minimum Friction Scalar " ) ;
idCVar aa_targetFrictionMultiplierMax ( " aa_targetFrictionMultiplierMax " , " 0.4 " , CVAR_FLOAT , " Maximum Friction Scalar " ) ;
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idAimAssist : : Init
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idAimAssist : : Init ( idPlayer * player_ )
{
2012-11-26 18:58:24 +00:00
player = player_ ;
angleCorrection = ang_zero ;
frictionScalar = 1.0f ;
lastTargetPos = vec3_zero ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idAimAssist : : Update
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idAimAssist : : Update ( )
{
2012-11-26 18:58:24 +00:00
angleCorrection = ang_zero ;
2012-11-28 15:47:07 +00:00
UpdateNewAimAssist ( ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idAimAssist : : UpdateNewAimAssist
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idAimAssist : : UpdateNewAimAssist ( )
{
2012-11-26 18:58:24 +00:00
angleCorrection = ang_zero ;
frictionScalar = 1.0f ;
idEntity * lastTarget = targetEntity ;
targetEntity = NULL ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// is aim assisting allowed? If not then just bail out
2012-11-28 15:47:07 +00:00
if ( ! aa_targetAimAssistEnable . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool forceLastTarget = false ;
idVec3 targetPos ;
2012-11-28 15:47:07 +00:00
idEntity * entity = NULL ;
if ( forceLastTarget )
{
2012-11-26 18:58:24 +00:00
entity = lastTarget ;
targetPos = lastTargetPos ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
entity = FindAimAssistTarget ( targetPos ) ;
}
2012-11-28 15:47:07 +00:00
if ( entity ! = NULL )
{
2012-11-26 18:58:24 +00:00
UpdateFriction ( entity , targetPos ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// by default we don't allow adhesion when we are standing still
const float playerMovementSpeedThreshold = Square ( aa_targetAdhesionPlayerSpeedThreshold . GetFloat ( ) ) ;
float playerSpeed = player - > GetPhysics ( ) - > GetLinearVelocity ( ) . LengthSqr ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// only allow adhesion on actors (ai) or players. Disallow adhesion on any static world entities such as explosive barrels
2012-11-28 15:47:07 +00:00
if ( playerSpeed > playerMovementSpeedThreshold )
{
2012-11-26 18:58:24 +00:00
UpdateAdhesion ( entity , targetPos ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
targetEntity = entity ;
2012-11-28 15:47:07 +00:00
}
2012-11-26 18:58:24 +00:00
lastTargetPos = targetPos ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idAimAssist : : FindAimAssistTarget
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idEntity * idAimAssist : : FindAimAssistTarget ( idVec3 & targetPos )
{
if ( player = = NULL )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//TO DO: Make this faster
//TO DO: Defer Traces
2012-11-28 15:47:07 +00:00
idEntity * optimalTarget = NULL ;
2012-11-26 18:58:24 +00:00
float currentBestScore = - idMath : : INFINITY ;
targetPos = vec3_zero ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idVec3 cameraPos ;
idMat3 cameraAxis ;
player - > GetViewPos ( cameraPos , cameraAxis ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float maxDistanceSquared = Square ( aa_targetMaxDistance . GetFloat ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idVec3 dirToTarget ;
float distanceToTargetSquared ;
idVec3 primaryTargetPos ;
idVec3 secondaryTargetPos ;
2012-11-28 15:47:07 +00:00
for ( idEntity * entity = gameLocal . aimAssistEntities . Next ( ) ; entity ! = NULL ; entity = entity - > aimAssistNode . Next ( ) )
{
if ( ! entity - > IsActive ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( entity - > IsHidden ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( entity - > IsType ( idActor : : Type ) )
{
idActor * actor = static_cast < idActor * > ( entity ) ;
if ( actor - > team = = player - > team )
{
2012-11-26 18:58:24 +00:00
// In DM, LMS, and Tourney, all players are on the same team
2012-11-28 15:47:07 +00:00
if ( gameLocal . gameType = = GAME_CTF | | gameLocal . gameType = = GAME_TDM | | gameLocal . gameType = = GAME_SP )
{
2012-11-26 18:58:24 +00:00
continue ;
}
}
}
2012-11-28 15:47:07 +00:00
if ( entity - > IsType ( idAI : : Type ) )
{
idAI * aiEntity = static_cast < idAI * > ( entity ) ;
if ( aiEntity - > ReactionTo ( player ) = = ATTACK_IGNORE )
{
2012-11-26 18:58:24 +00:00
continue ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check whether we have a valid target position for this entity - skip it if we don't
2012-11-28 15:47:07 +00:00
if ( ! ComputeTargetPos ( entity , primaryTargetPos , secondaryTargetPos ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// is it close enough to us
2012-11-28 15:47:07 +00:00
dirToTarget = primaryTargetPos - cameraPos ;
2012-11-26 18:58:24 +00:00
distanceToTargetSquared = dirToTarget . LengthSqr ( ) ;
2012-11-28 15:47:07 +00:00
if ( distanceToTargetSquared > maxDistanceSquared )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Compute a score in the range of 0..1 for how much are looking towards the target.
idVec3 forward = cameraAxis [ 0 ] ;
forward . Normalize ( ) ;
dirToTarget . Normalize ( ) ;
float ViewDirDotTargetDir = idMath : : ClampFloat ( - 1.0f , 1.0f , forward * dirToTarget ) ; // compute the dot and clamp to account for floating point error
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// throw out anything thats outside of weapon's global FOV.
2012-11-28 15:47:07 +00:00
if ( ViewDirDotTargetDir < 0.0f )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// to be consistent we always use the primaryTargetPos to compute the score for this entity
float computedScore = ComputeEntityAimAssistScore ( primaryTargetPos , cameraPos , cameraAxis ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check if the current score beats our current best score and we have line of sight to it.
2012-11-28 15:47:07 +00:00
if ( computedScore > currentBestScore )
{
2012-11-26 18:58:24 +00:00
// determine if the current target is in our line of sight
trace_t tr ;
gameLocal . clip . TracePoint ( tr , cameraPos , primaryTargetPos , MASK_MONSTERSOLID , player ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// did our trace fail?
2012-11-28 15:47:07 +00:00
if ( ( ( tr . fraction < 1.0f ) & & ( tr . c . entityNum ! = entity - > entityNumber ) ) | | ( tr . fraction > = 1.0f ) )
{
2012-11-26 18:58:24 +00:00
// if the collision test failed for the primary position -- check the secondary position
trace_t tr2 ;
gameLocal . clip . TracePoint ( tr2 , cameraPos , secondaryTargetPos , MASK_MONSTERSOLID , player ) ;
2012-11-28 15:47:07 +00:00
if ( ( ( tr2 . fraction < 1.0f ) & & ( tr2 . c . entityNum ! = entity - > entityNumber ) ) | | ( tr2 . fraction > = 1.0f ) )
{
2012-11-26 18:58:24 +00:00
// if the secondary position is also not visible then give up
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// we can see the secondary target position so we should consider this entity but use
// the secondary position as the target position
targetPos = secondaryTargetPos ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
targetPos = primaryTargetPos ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if we got here then this is our new best score
optimalTarget = entity ;
currentBestScore = computedScore ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return optimalTarget ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idAimAssist : : ComputeEntityAimAssistScore
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
float idAimAssist : : ComputeEntityAimAssistScore ( const idVec3 & targetPos , const idVec3 & cameraPos , const idMat3 & cameraAxis )
{
2012-11-26 18:58:24 +00:00
float score = 0.0f ;
2012-11-28 15:47:07 +00:00
idVec3 dirToTarget = targetPos - cameraPos ;
2012-11-26 18:58:24 +00:00
float distanceToTarget = dirToTarget . Length ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Compute a score in the range of 0..1 for how much are looking towards the target.
idVec3 forward = cameraAxis [ 0 ] ;
2012-11-28 15:47:07 +00:00
forward . Normalize ( ) ;
2012-11-26 18:58:24 +00:00
dirToTarget . Normalize ( ) ;
float ViewDirDotTargetDir = idMath : : ClampFloat ( 0.0f , 1.0f , forward * dirToTarget ) ; // compute the dot and clamp to account for floating point error
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// the more we look at the target the higher our score
score = ViewDirDotTargetDir ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// weigh the score from the view angle higher than the distance score
static float aimWeight = 0.8f ;
score * = aimWeight ;
// Add a score of 0..1 for how close the target is to the player
2012-11-28 15:47:07 +00:00
if ( distanceToTarget < aa_targetMaxDistance . GetFloat ( ) )
{
2012-11-26 18:58:24 +00:00
float distanceScore = 1.0f - ( distanceToTarget / aa_targetMaxDistance . GetFloat ( ) ) ;
float distanceWeight = 1.0f - aimWeight ;
score + = ( distanceScore * distanceWeight ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return score * 1000.0f ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idAimAssist : : UpdateAdhesion
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idAimAssist : : UpdateAdhesion ( idEntity * pTarget , const idVec3 & targetPos )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( ! aa_targetAdhesionEnable . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! pTarget )
{
2012-11-26 18:58:24 +00:00
return ;
}
float contributionPctMax = aa_targetAdhesionContributionPctMax . GetFloat ( ) ;
idVec3 cameraPos ;
idMat3 cameraAxis ;
2012-11-28 15:47:07 +00:00
player - > GetViewPos ( cameraPos , cameraAxis ) ;
2012-11-26 18:58:24 +00:00
idAngles cameraViewAngles = cameraAxis . ToAngles ( ) ;
cameraViewAngles . Normalize180 ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idVec3 cameraViewPos = cameraPos ;
idVec3 dirToTarget = targetPos - cameraViewPos ;
float distanceToTarget = dirToTarget . Length ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idAngles aimAngles = dirToTarget . ToAngles ( ) ;
aimAngles . Normalize180 ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// find the delta
aimAngles - = cameraViewAngles ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clamp velocities to some max values
aimAngles . yaw = idMath : : ClampFloat ( - aa_targetAdhesionYawSpeedMax . GetFloat ( ) , aa_targetAdhesionYawSpeedMax . GetFloat ( ) , aimAngles . yaw ) ;
aimAngles . pitch = idMath : : ClampFloat ( - aa_targetAdhesionPitchSpeedMax . GetFloat ( ) , aa_targetAdhesionPitchSpeedMax . GetFloat ( ) , aimAngles . pitch ) ;
idVec3 forward = cameraAxis [ 0 ] ;
forward . Normalize ( ) ;
dirToTarget . Normalize ( ) ;
float ViewDirDotTargetDir = idMath : : ClampFloat ( 0.0f , 1.0f , forward * dirToTarget ) ; // compute the dot and clamp to account for floating point error
float aimLength = ViewDirDotTargetDir * distanceToTarget ;
idVec3 aimPoint = cameraPos + ( forward * aimLength ) ;
float delta = idMath : : Sqrt ( Square ( distanceToTarget ) - Square ( aimLength ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float contribution = idMath : : ClampFloat ( 0.0f , contributionPctMax , 1.0f - ( delta / aa_targetAdhesionRadius . GetFloat ( ) ) ) ;
angleCorrection . yaw = aimAngles . yaw * contribution ;
angleCorrection . pitch = aimAngles . pitch * contribution ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idAimAssist : : ComputeFrictionRadius
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
float idAimAssist : : ComputeFrictionRadius ( float distanceToTarget )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( ( distanceToTarget < = idMath : : FLT_SMALLEST_NON_DENORMAL ) | | distanceToTarget > aa_targetFrictionMaxDistance . GetFloat ( ) )
{
2012-11-26 18:58:24 +00:00
return aa_targetFrictionRadius . GetFloat ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float distanceContributionScalar = ( aa_targetFrictionOptimalDistance . GetFloat ( ) > 0.0f ) ? ( distanceToTarget / aa_targetFrictionOptimalDistance . GetFloat ( ) ) : 0.0f ;
2012-11-28 15:47:07 +00:00
if ( distanceToTarget > aa_targetFrictionOptimalDistance . GetFloat ( ) )
{
2012-11-26 18:58:24 +00:00
const float range = idMath : : ClampFloat ( 0.0f , aa_targetFrictionMaxDistance . GetFloat ( ) , aa_targetFrictionMaxDistance . GetFloat ( ) - aa_targetFrictionOptimalDistance . GetFloat ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( range > idMath : : FLT_SMALLEST_NON_DENORMAL )
{
2012-11-26 18:58:24 +00:00
distanceContributionScalar = 1.0f - ( ( distanceToTarget - aa_targetFrictionOptimalDistance . GetFloat ( ) ) / range ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return Lerp ( aa_targetFrictionRadius . GetFloat ( ) , aa_targetFrictionOptimalRadius . GetFloat ( ) , distanceContributionScalar ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idAimAssist : : UpdateFriction
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idAimAssist : : UpdateFriction ( idEntity * pTarget , const idVec3 & targetPos )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( ! aa_targetFrictionEnable . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( pTarget = = NULL )
{
2012-11-26 18:58:24 +00:00
return ;
}
idVec3 cameraPos ;
idMat3 cameraAxis ;
2012-11-28 15:47:07 +00:00
player - > GetViewPos ( cameraPos , cameraAxis ) ;
2012-11-26 18:58:24 +00:00
idVec3 dirToTarget = targetPos - cameraPos ;
float distanceToTarget = dirToTarget . Length ( ) ;
idVec3 forward = cameraAxis [ 0 ] ;
forward . Normalize ( ) ;
dirToTarget . Normalize ( ) ;
float ViewDirDotTargetDir = idMath : : ClampFloat ( 0.0f , 1.0f , forward * dirToTarget ) ; // compute the dot and clamp to account for floating point error
float aimLength = ViewDirDotTargetDir * distanceToTarget ;
idVec3 aimPoint = cameraPos + ( forward * aimLength ) ;
float delta = idMath : : Sqrt ( Square ( distanceToTarget ) - Square ( aimLength ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float radius = ComputeFrictionRadius ( distanceToTarget ) ;
2012-11-28 15:47:07 +00:00
if ( delta < radius )
{
2012-11-26 18:58:24 +00:00
float alpha = 1.0f - ( delta / radius ) ;
frictionScalar = Lerp ( aa_targetFrictionMultiplierMin . GetFloat ( ) , aa_targetFrictionMultiplierMax . GetFloat ( ) , alpha ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idAimAssist : : ComputeTargetPos
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idAimAssist : : ComputeTargetPos ( idEntity * entity , idVec3 & primaryTargetPos , idVec3 & secondaryTargetPos )
{
2012-11-26 18:58:24 +00:00
primaryTargetPos = vec3_zero ;
secondaryTargetPos = vec3_zero ;
2012-11-28 15:47:07 +00:00
if ( entity = = NULL )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// The target point on actors can now be either the head or the torso
2012-11-28 15:47:07 +00:00
idActor * actor = NULL ;
if ( entity - > IsType ( idActor : : Type ) )
{
actor = ( idActor * ) entity ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( actor ! = NULL )
{
2012-11-26 18:58:24 +00:00
// Actor AimPoint
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idVec3 torsoPos ;
idVec3 headPos = actor - > GetEyePosition ( ) ;
2012-11-28 15:47:07 +00:00
if ( actor - > GetHeadEntity ( ) ! = NULL )
{
2012-11-26 18:58:24 +00:00
torsoPos = actor - > GetHeadEntity ( ) - > GetPhysics ( ) - > GetOrigin ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
const float offsetScale = 0.9f ;
torsoPos = actor - > GetPhysics ( ) - > GetOrigin ( ) + ( actor - > EyeOffset ( ) * offsetScale ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
primaryTargetPos = torsoPos ;
secondaryTargetPos = headPos ;
return true ;
2012-11-28 15:47:07 +00:00
}
else if ( entity - > GetPhysics ( ) - > GetClipModel ( ) ! = NULL )
{
2012-11-26 18:58:24 +00:00
const idBounds & box = entity - > GetPhysics ( ) - > GetClipModel ( ) - > GetAbsBounds ( ) ;
primaryTargetPos = box . GetCenter ( ) ;
secondaryTargetPos = box . GetCenter ( ) ;
return true ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return false ;
}