etqw-sdk/source/game/vehicles/VehicleWeapon.cpp

726 lines
20 KiB
C++
Raw Normal View History

2008-05-29 00:00:00 +00:00
// 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() );
}