726 lines
20 KiB
C++
726 lines
20 KiB
C++
|
// Copyright (C) 2007 Id Software, Inc.
|
||
|
//
|
||
|
|
||
|
#include "../precompiled.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
#include "VehicleWeapon.h"
|
||
|
#include "Transport.h"
|
||
|
#include "../Weapon.h"
|
||
|
#include "../Player.h"
|
||
|
#include "../Projectile.h"
|
||
|
#include "../ContentMask.h"
|
||
|
#include "../Misc.h"
|
||
|
#include "../script/Script_Helper.h"
|
||
|
#include "../script/Script_ScriptObject.h"
|
||
|
|
||
|
// Gordon: FIXME: Move all IK chains out to vehicle IK so weapons only deal with weapon issues
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdVehicleWeapon
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
extern const idEventDef EV_GetVehicle;
|
||
|
extern const idEventDef EV_SetState;
|
||
|
|
||
|
const idEventDef EV_VehicleWeapon_GetPlayer( "getPlayer", 'e', DOC_TEXT( "Returns the player currently manning the weapon, or $null$ if none." ), 0, NULL );
|
||
|
const idEventDef EV_VehicleWeapon_SetTarget( "setTarget", '\0', DOC_TEXT( "Enables/disables fixed position aiming, and sets a fixed position for the weapon to aim at." ), 2, NULL, "v", "position", "Fixed position in the world to aim at.", "b", "state", "Enable/disable fixed aiming." );
|
||
|
|
||
|
ABSTRACT_DECLARATION( idClass, sdVehicleWeapon )
|
||
|
EVENT( EV_GetKey, sdVehicleWeapon::Event_GetKey )
|
||
|
EVENT( EV_GetFloatKey, sdVehicleWeapon::Event_GetFloatKey )
|
||
|
EVENT( EV_GetVectorKey, sdVehicleWeapon::Event_GetVectorKey )
|
||
|
EVENT( EV_GetVehicle, sdVehicleWeapon::Event_GetVehicle )
|
||
|
EVENT( EV_VehicleWeapon_GetPlayer, sdVehicleWeapon::Event_GetPlayer )
|
||
|
EVENT( EV_SetState, sdVehicleWeapon::Event_SetState )
|
||
|
EVENT( EV_VehicleWeapon_SetTarget, sdVehicleWeapon::Event_SetTarget )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Event_GetKey
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::Event_GetKey( const char* key ) {
|
||
|
sdProgram::ReturnString( GetSpawnParms().GetString( key ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Event_GetFloatKey
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::Event_GetFloatKey( const char* key ) {
|
||
|
sdProgram::ReturnFloat( GetSpawnParms().GetFloat( key ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Event_GetVectorKey
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::Event_GetVectorKey( const char* key ) {
|
||
|
sdProgram::ReturnVector( GetSpawnParms().GetVector( key ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Event_GetVehicle
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::Event_GetVehicle( void ) {
|
||
|
sdProgram::ReturnEntity( vehicle );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Event_GetPlayer
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::Event_GetPlayer( void ) {
|
||
|
sdProgram::ReturnEntity( GetPlayer() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Event_SetState
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::Event_SetState( const char* state ) {
|
||
|
Script_SetState( scriptObject->GetFunction( state ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Event_SetTarget
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::Event_SetTarget( const idVec3& target, bool state ) {
|
||
|
SetTarget( target, state );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::CreateScriptThread
|
||
|
================
|
||
|
*/
|
||
|
sdProgramThread* sdVehicleWeapon::CreateScriptThread( const sdProgram::sdFunction* function ) {
|
||
|
scriptIdealState = function;
|
||
|
scriptState = function;
|
||
|
|
||
|
sdProgramThread* thread = gameLocal.program->CreateThread();
|
||
|
thread->SetName( va( "%s_%s", basePosition->GetTransport()->GetName(), GetName() ) );
|
||
|
thread->CallFunction( scriptObject, function );
|
||
|
thread->ManualControl();
|
||
|
thread->ManualDelete();
|
||
|
return thread;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::ConstructScriptObject
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::ConstructScriptObject( void ) {
|
||
|
const char* weaponScript = GetSpawnParms().GetString( "scriptobject" );
|
||
|
if ( !*weaponScript ) {
|
||
|
gameLocal.Warning( "sdVehicleWeapon::ConstructScriptObject No Script Object Specified" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
scriptObject = gameLocal.program->AllocScriptObject( this, weaponScript );
|
||
|
|
||
|
sdScriptHelper h2;
|
||
|
scriptObject->CallNonBlockingScriptEvent( scriptObject->GetSyncFunc(), h2 );
|
||
|
|
||
|
sdScriptHelper h1;
|
||
|
scriptObject->CallNonBlockingScriptEvent( scriptObject->GetPreConstructor(), h1 );
|
||
|
|
||
|
if ( scriptThread != NULL ) {
|
||
|
gameLocal.Warning( "sdVehicleWeapon::ConstructScriptObject SetState Called before object construction is complete" );
|
||
|
} else {
|
||
|
const sdProgram::sdFunction* constructor = scriptObject->GetConstructor();
|
||
|
if ( constructor ) {
|
||
|
scriptThread = CreateScriptThread( constructor );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::DeconstructScriptObject
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::DeconstructScriptObject( void ) {
|
||
|
if ( scriptObject == NULL ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sdScriptHelper h1;
|
||
|
scriptObject->CallNonBlockingScriptEvent( scriptObject->GetDestructor(), h1 );
|
||
|
gameLocal.program->FreeScriptObject( scriptObject );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Setup
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleWeapon::Setup( sdTransport* _vehicle, const sdDeclStringMap& weaponParms, const angleClamp_t& clampYaw, const angleClamp_t& clampPitch ) {
|
||
|
vehicle = _vehicle;
|
||
|
|
||
|
name = weaponParms.GetDict().GetString( "weapon_name" );
|
||
|
noTophatCrosshair = weaponParms.GetDict().GetBool( "no_tophat_crosshair" );
|
||
|
|
||
|
lockInfo.Load( weaponParms.GetDict() );
|
||
|
|
||
|
if ( !Spawn( weaponParms, clampYaw, clampPitch ) ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
ConstructScriptObject();
|
||
|
|
||
|
const idDict& weaponDict = weaponParms.GetDict();
|
||
|
|
||
|
gunJointHandle = vehicle->GetAnimator()->GetJointHandle( weaponDict.GetString( "muzzle", "" ) );
|
||
|
|
||
|
if ( gunJointHandle == INVALID_JOINT ) {
|
||
|
gunJointHandle = vehicle->GetAnimator()->GetJointHandle( weaponDict.GetString( "joint_muzzle", "" ) );
|
||
|
if ( gunJointHandle == INVALID_JOINT ) {
|
||
|
gunJointHandle = vehicle->GetAnimator()->GetJointHandle( weaponDict.GetString( "muzzle_right", "" ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
weaponReadyFunc = scriptObject->GetFunction( "WeaponCanFire" );
|
||
|
|
||
|
gameLocal.ParseClamp( lockClampYaw, "lock_clamp_yaw", weaponDict );
|
||
|
gameLocal.ParseClamp( lockClampPitch, "lock_clamp_pitch", weaponDict );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=====================
|
||
|
sdVehicleWeapon::IsValidLockDirection
|
||
|
=====================
|
||
|
*/
|
||
|
bool sdVehicleWeapon::IsValidLockDirection( const idVec3& worldDirection ) const {
|
||
|
idVec3 localDirection = vehicle->GetAxis().TransposeMultiply( worldDirection );
|
||
|
idAngles localAngles = localDirection.ToAngles();
|
||
|
localAngles.Normalize180();
|
||
|
|
||
|
if ( lockClampYaw.flags.enabled
|
||
|
&& ( localAngles.yaw < lockClampYaw.extents[ 0 ] || localAngles.yaw > lockClampYaw.extents[ 1 ] ) ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( lockClampPitch.flags.enabled
|
||
|
&& ( localAngles.pitch < lockClampPitch.extents[ 0 ] || localAngles.pitch > lockClampPitch.extents[ 1 ] ) ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=====================
|
||
|
sdVehicleWeapon::GetWeaponOriginAxis
|
||
|
=====================
|
||
|
*/
|
||
|
void sdVehicleWeapon::GetWeaponOriginAxis( idVec3& org, idMat3& axis ) {
|
||
|
vehicle->GetWorldOriginAxis( gunJointHandle, org, axis );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=====================
|
||
|
sdVehicleWeapon::SetPosition
|
||
|
=====================
|
||
|
*/
|
||
|
void sdVehicleWeapon::SetPosition( sdVehiclePosition* _position ) {
|
||
|
position = _position;
|
||
|
|
||
|
if ( position != NULL && position != basePosition ) {
|
||
|
assert( false );
|
||
|
gameLocal.Warning( "sdVehicleWeapon::SetPosition Weapon '%s' Assigned to bad Position '%s'", GetName(), position->GetName() );
|
||
|
}
|
||
|
|
||
|
OnPositionPlayerChanged();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=====================
|
||
|
sdVehicleWeapon::OnPositionPlayerChanged
|
||
|
=====================
|
||
|
*/
|
||
|
void sdVehicleWeapon::OnPositionPlayerChanged( void ) {
|
||
|
sdScriptHelper helper;
|
||
|
if ( !position || !position->GetPlayer() ) {
|
||
|
helper.Push( static_cast< idScriptObject* >( NULL ) );
|
||
|
} else {
|
||
|
helper.Push( position->GetPlayer()->GetScriptObject() );
|
||
|
}
|
||
|
|
||
|
if ( scriptObject ) {
|
||
|
scriptObject->CallNonBlockingScriptEvent( scriptObject->GetFunction( "OnSetPlayer" ), helper );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=====================
|
||
|
sdVehicleWeapon::SetState
|
||
|
=====================
|
||
|
*/
|
||
|
bool sdVehicleWeapon::SetState( void ) {
|
||
|
if ( scriptIdealState == NULL ) {
|
||
|
gameLocal.Error( "sdVehicleWeapon::SetState NULL state" );
|
||
|
}
|
||
|
|
||
|
scriptState = scriptIdealState;
|
||
|
scriptThread->CallFunction( scriptObject, scriptState );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=====================
|
||
|
sdVehicleWeapon::UpdateScript
|
||
|
=====================
|
||
|
*/
|
||
|
void sdVehicleWeapon::UpdateScript( void ) {
|
||
|
if ( scriptThread == NULL || gameLocal.IsPaused() ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// a series of state changes can happen in a single frame.
|
||
|
// this loop limits them in case we've entered an infinite loop.
|
||
|
for( int i = 0; i < 20; i++ ) {
|
||
|
if ( scriptIdealState != scriptState ) {
|
||
|
SetState();
|
||
|
}
|
||
|
|
||
|
// don't call script until it's done waiting
|
||
|
if ( scriptThread->IsWaiting() ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( scriptThread->Execute() ) {
|
||
|
if ( scriptIdealState == scriptState ) {
|
||
|
gameLocal.program->FreeThread( scriptThread );
|
||
|
scriptThread = NULL;
|
||
|
return;
|
||
|
}
|
||
|
} else if ( scriptIdealState == scriptState ) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
scriptThread->Warning( "sdVehicleWeapon::UpdateScript Exited Loop to Prevent Lockup" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Update
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::Update( void ) {
|
||
|
if ( gameLocal.isNewFrame ) {
|
||
|
UpdateScript();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Script_SetState
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeapon::Script_SetState( const sdProgram::sdFunction* function ) {
|
||
|
scriptIdealState = function;
|
||
|
if ( scriptThread != NULL ) {
|
||
|
scriptThread->DoneProcessing();
|
||
|
} else {
|
||
|
scriptThread = CreateScriptThread( scriptIdealState );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::sdVehicleWeapon
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleWeapon::sdVehicleWeapon( void ) {
|
||
|
position = NULL;
|
||
|
scriptThread = NULL;
|
||
|
scriptIdealState = NULL;
|
||
|
scriptState = NULL;
|
||
|
scriptObject = NULL;
|
||
|
weaponReadyFunc = NULL;
|
||
|
gunJointHandle = INVALID_JOINT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::~sdVehicleWeapon
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleWeapon::~sdVehicleWeapon( void ) {
|
||
|
if ( scriptThread != NULL ) {
|
||
|
gameLocal.program->FreeThread( scriptThread );
|
||
|
scriptThread = NULL;
|
||
|
}
|
||
|
|
||
|
DeconstructScriptObject();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::Spawn
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleWeapon::Spawn( const sdDeclStringMap& weaponParms, const angleClamp_t& clampYaw, const angleClamp_t& clampPitch ) {
|
||
|
spawnWeaponParms = &weaponParms;
|
||
|
gunName = declHolder.FindLocStr( weaponParms.GetDict().GetString( "gunName" ) );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
sdVehicleWeapon::IsWeaponReady
|
||
|
===============
|
||
|
*/
|
||
|
bool sdVehicleWeapon::IsWeaponReady( void ) {
|
||
|
if ( !weaponReadyFunc || scriptObject == NULL ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
sdScriptHelper h1;
|
||
|
scriptObject->CallNonBlockingScriptEvent( weaponReadyFunc, h1 );
|
||
|
return gameLocal.program->GetReturnedBoolean();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::GetPlayer
|
||
|
================
|
||
|
*/
|
||
|
idPlayer* sdVehicleWeapon::GetPlayer( void ) {
|
||
|
return position ? position->GetPlayer() : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeapon::GetEnemy
|
||
|
================
|
||
|
*/
|
||
|
idEntity* sdVehicleWeapon::GetEnemy( void ) {
|
||
|
idPlayer* player = GetPlayer();
|
||
|
if ( player != NULL ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return player->GetTargetLocked() ? player->targetEntity.GetEntity() : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdVehicleWeaponFixedMinigun
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
CLASS_DECLARATION( sdVehicleWeapon, sdVehicleWeaponFixedMinigun )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeaponFixedMinigun::Spawn
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleWeaponFixedMinigun::Spawn( const sdDeclStringMap& weaponParms, const angleClamp_t& clampYaw, const angleClamp_t& clampPitch ) {
|
||
|
if( !sdVehicleWeapon::Spawn( weaponParms, clampYaw, clampPitch ) ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const idDict& weaponDict = weaponParms.GetDict();
|
||
|
|
||
|
idAnimator* animator = vehicle->GetAnimator();
|
||
|
|
||
|
jointHandle_t shoulderJoint = animator->GetJointHandle( weaponDict.GetString( "gunJointShoulder", "" ) );
|
||
|
|
||
|
jointHandle_t yawJoint = animator->GetJointHandle( weaponDict.GetString( "gunJointYaw", "" ) );
|
||
|
if ( yawJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleWeaponFixedMinigun::Spawn Invalid Yaw Joint" );
|
||
|
}
|
||
|
jointHandle_t pitchJoint = animator->GetJointHandle( weaponDict.GetString( "gunJointPitch", "" ) );
|
||
|
if ( pitchJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleWeaponFixedMinigun::Spawn Invalid Pitch Joint" );
|
||
|
}
|
||
|
jointHandle_t barrelJoint = animator->GetJointHandle( weaponDict.GetString( "weapon1_muzzle", "" ) );
|
||
|
if ( barrelJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleWeaponFixedMinigun::Spawn Invalid Muzzle Joint" );
|
||
|
}
|
||
|
|
||
|
aimer.Init( weaponDict.GetBool( "fix_barrel" ), weaponDict.GetBool( "invert_pitch" ), vehicle, animator->GetAnim( "base" ), yawJoint, pitchJoint, barrelJoint, shoulderJoint, clampYaw, clampPitch );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeaponFixedMinigun::Update
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeaponFixedMinigun::Update( void ) {
|
||
|
sdVehicleWeapon::Update();
|
||
|
|
||
|
if ( gameLocal.isClient && ( vehicle->aorFlags & AOR_INHIBIT_IK ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
idPlayer* player = GetPlayer();
|
||
|
|
||
|
if ( manualTarget ) {
|
||
|
aimer.SetTarget( manualTargetPos );
|
||
|
} else if ( player ) {
|
||
|
trace_t trace;
|
||
|
idVec3 end = player->renderView.vieworg + ( 4096 * player->renderView.viewaxis[ 0 ] );
|
||
|
|
||
|
gameLocal.clip.TracePoint( CLIP_DEBUG_PARMS trace, player->renderView.vieworg, end, CONTENTS_SOLID | CONTENTS_OPAQUE, player );
|
||
|
|
||
|
aimer.SetTarget( trace.endpos );
|
||
|
} else {
|
||
|
aimer.ClearTarget();
|
||
|
}
|
||
|
|
||
|
aimer.Update();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeaponFixedMinigun::SetTarget
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleWeaponFixedMinigun::SetTarget( const idVec3& target, bool enabled ) {
|
||
|
manualTarget = enabled;
|
||
|
manualTargetPos = target;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeaponFixedMinigun::sdVehicleWeaponFixedMinigun
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleWeaponFixedMinigun::sdVehicleWeaponFixedMinigun( void ) {
|
||
|
manualTarget = false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeaponFixedMinigun::sdVehicleWeaponFixedMinigun
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleWeaponFixedMinigun::~sdVehicleWeaponFixedMinigun( void ) {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeaponFixedMinigun::CanAimAt
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleWeaponFixedMinigun::CanAimAt( const idVec3& idealAimPosition ) {
|
||
|
idPlayer* player = position->GetPlayer();
|
||
|
sdTransport* transport = position->GetTransport();
|
||
|
assert( player );
|
||
|
assert( transport );
|
||
|
|
||
|
trace_t trace;
|
||
|
gameLocal.clip.TracePoint( CLIP_DEBUG_PARMS trace, player->firstPersonViewOrigin, idealAimPosition,
|
||
|
( MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX ) & ~CONTENTS_FORCEFIELD, transport );
|
||
|
idVec3 aimPosition = trace.endpos;
|
||
|
|
||
|
idVec3 weapOrg;
|
||
|
idMat3 weapAxis;
|
||
|
GetWeaponOriginAxis( weapOrg, weapAxis );
|
||
|
|
||
|
idVec3 aimDirection = aimPosition - weapOrg;
|
||
|
float aimLength = aimDirection.Normalize();
|
||
|
if ( aimLength < idMath::FLT_EPSILON ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const idMat3& baseAxis = transport->GetAxis();
|
||
|
idVec3 localAim = baseAxis.TransposeMultiply( aimDirection );
|
||
|
idAngles aimAngles = localAim.ToAngles();
|
||
|
aimAngles.Normalize180();
|
||
|
|
||
|
return aimer.CanAimTo( aimAngles );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdVehicleWeaponLocked
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
CLASS_DECLARATION( sdVehicleWeapon, sdVehicleWeaponLocked )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeaponLocked::Spawn
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleWeaponLocked::Spawn( const sdDeclStringMap& weaponParms, const angleClamp_t& clampYaw, const angleClamp_t& clampPitch ) {
|
||
|
if( !sdVehicleWeapon::Spawn( weaponParms, clampYaw, clampPitch ) ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const idDict& weaponDict = weaponParms.GetDict();
|
||
|
|
||
|
// list of joints to
|
||
|
idAnimator* animator = vehicle->GetAnimator();
|
||
|
for ( int i = 1; i <= MAX_CANAIM_JOINTS; i++ ) {
|
||
|
const char* jointDefName = va( "canaim_joint_%i", i );
|
||
|
jointHandle_t joint = animator->GetJointHandle( weaponDict.GetString( jointDefName, "" ) );
|
||
|
if ( joint == INVALID_JOINT ) {
|
||
|
break;
|
||
|
}
|
||
|
canAimJoints.Append( joint );
|
||
|
}
|
||
|
|
||
|
notReallyLocked = weaponDict.GetBool( "not_really_locked" );
|
||
|
if ( notReallyLocked ) {
|
||
|
nrl_yawClamp.flags.enabled = weaponDict.GetBool( "nrl_yawClamp_enabled" );
|
||
|
nrl_yawClamp.extents[ 0 ] = weaponDict.GetFloat( "nrl_yawClamp_min" );
|
||
|
nrl_yawClamp.extents[ 1 ] = weaponDict.GetFloat( "nrl_yawClamp_max" );
|
||
|
nrl_pitchClamp.flags.enabled = weaponDict.GetBool( "nrl_pitchClamp_enabled" );
|
||
|
nrl_pitchClamp.extents[ 0 ] = weaponDict.GetFloat( "nrl_pitchClamp_min" );
|
||
|
nrl_pitchClamp.extents[ 1 ] = weaponDict.GetFloat( "nrl_pitchClamp_max" );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeaponLocked::CanAimAt
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleWeaponLocked::CanAimAt( const idVec3& idealAimPosition ) {
|
||
|
idPlayer* player = position->GetPlayer();
|
||
|
sdTransport* transport = position->GetTransport();
|
||
|
assert( player );
|
||
|
assert( transport );
|
||
|
|
||
|
trace_t trace;
|
||
|
gameLocal.clip.TracePoint( CLIP_DEBUG_PARMS trace, player->firstPersonViewOrigin, idealAimPosition,
|
||
|
( MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX ) & ~CONTENTS_FORCEFIELD, transport );
|
||
|
idVec3 aimPosition = trace.endpos;
|
||
|
|
||
|
idVec3 org;
|
||
|
idVec3 fwd;
|
||
|
if ( gunJointHandle != INVALID_JOINT ) {
|
||
|
idMat3 axis;
|
||
|
GetWeaponOriginAxis( org, axis );
|
||
|
fwd = axis[ 0 ];
|
||
|
} else {
|
||
|
if ( canAimJoints.Num() ) {
|
||
|
org.Zero();
|
||
|
fwd.Zero();
|
||
|
for ( int i = 0; i < canAimJoints.Num(); i++ ) {
|
||
|
idVec3 tempOrg;
|
||
|
idMat3 tempAxis;
|
||
|
vehicle->GetWorldOriginAxis( canAimJoints[ i ], tempOrg, tempAxis );
|
||
|
|
||
|
org += tempOrg;
|
||
|
fwd += tempAxis[ 0 ];
|
||
|
}
|
||
|
|
||
|
org /= canAimJoints.Num();
|
||
|
fwd.Normalize();
|
||
|
} else {
|
||
|
idMat3 axis;
|
||
|
axis = transport->GetAxis();
|
||
|
org = player->firstPersonViewOrigin;
|
||
|
fwd = axis[ 0 ];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( notReallyLocked ) {
|
||
|
idVec3 aimDirection = aimPosition - org;
|
||
|
float aimLength = aimDirection.Normalize();
|
||
|
if ( aimLength < idMath::FLT_EPSILON ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const idMat3& baseAxis = transport->GetAxis();
|
||
|
idVec3 localAim = baseAxis.TransposeMultiply( aimDirection );
|
||
|
idAngles aimAngles = localAim.ToAngles();
|
||
|
aimAngles.Normalize180();
|
||
|
|
||
|
if ( nrl_yawClamp.flags.enabled ) {
|
||
|
if ( aimAngles.yaw < nrl_yawClamp.extents[ 0 ] || aimAngles.yaw > nrl_yawClamp.extents[ 1 ] ) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
if ( nrl_pitchClamp.flags.enabled ) {
|
||
|
if ( aimAngles.pitch < nrl_pitchClamp.extents[ 0 ] || aimAngles.pitch > nrl_pitchClamp.extents[ 1 ] ) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
idVec3 aimDirection = aimPosition - org;
|
||
|
float aimLength = aimDirection.Normalize();
|
||
|
if ( aimLength < idMath::FLT_EPSILON ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( aimDirection * fwd < 0.999f ) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdVehicleWeaponFactory
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleWeaponFactory::GetWeapon
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleWeapon* sdVehicleWeaponFactory::GetWeapon( const char* weaponType ) {
|
||
|
idTypeInfo* type = idClass::GetClass( weaponType );
|
||
|
if ( !type ) {
|
||
|
gameLocal.Error( "sdVehicleWeaponFactory::GetWeapon Invalid Class Type '%s'", weaponType );
|
||
|
}
|
||
|
if ( !type->IsType( sdVehicleWeapon::Type ) ) {
|
||
|
gameLocal.Error( "sdVehicleWeaponFactory::GetWeapon '%s' Is Not Of Type sdVehicleWeapon", weaponType );
|
||
|
}
|
||
|
|
||
|
return reinterpret_cast< sdVehicleWeapon* >( type->CreateInstance() );
|
||
|
}
|