mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
2526 lines
61 KiB
C++
2526 lines
61 KiB
C++
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "prey_local.h"
|
|
|
|
#define WEAPON_DEBUG if(g_debugWeapon.GetBool()) gameLocal.Warning
|
|
|
|
/***********************************************************************
|
|
|
|
hhWeapon
|
|
|
|
***********************************************************************/
|
|
const idEventDef EV_PlayAnimWhenReady( "playAnimWhenReady", "s" );
|
|
const idEventDef EV_Weapon_Aside( "<weaponAside>" );
|
|
const idEventDef EV_Weapon_EjectAltBrass( "ejectAltBrass" );
|
|
|
|
const idEventDef EV_Weapon_HasAmmo( "hasAmmo", "", 'd' );
|
|
const idEventDef EV_Weapon_HasAltAmmo( "hasAltAmmo", "", 'd' );
|
|
|
|
const idEventDef EV_Weapon_GetFireDelay( "getFireDelay", "", 'f' );
|
|
const idEventDef EV_Weapon_GetAltFireDelay( "getAltFireDelay", "", 'f' );
|
|
const idEventDef EV_Weapon_GetSpread( "getSpread", "", 'f' );
|
|
const idEventDef EV_Weapon_GetAltSpread( "getAltSpread", "", 'f' );
|
|
const idEventDef EV_Weapon_GetString( "getString", "s", 's' );
|
|
const idEventDef EV_Weapon_GetAltString( "getAltString", "s", 's' );
|
|
|
|
const idEventDef EV_Weapon_AddToAltClip( "addToAltClip", "f" );
|
|
const idEventDef EV_Weapon_AltAmmoInClip( "altAmmoInClip", "", 'f' );
|
|
const idEventDef EV_Weapon_AltAmmoAvailable( "altAmmoAvailable", "", 'f' );
|
|
const idEventDef EV_Weapon_AltClipSize( "altClipSize", "", 'f' );
|
|
|
|
const idEventDef EV_Weapon_FireAltProjectiles( "fireAltProjectiles" );
|
|
const idEventDef EV_Weapon_FireProjectiles( "fireProjectiles" );
|
|
|
|
const idEventDef EV_Weapon_WeaponAside( "weaponAside" ); // nla
|
|
const idEventDef EV_Weapon_WeaponPuttingAside( "weaponPuttingAside" ); // nla
|
|
const idEventDef EV_Weapon_WeaponUprighting( "weaponUprighting" ); // nla
|
|
|
|
const idEventDef EV_Weapon_IsAnimPlaying( "isAnimPlaying", "s", 'd' );
|
|
const idEventDef EV_Weapon_Raise( "<raise>" ); // nla - For the hands to post an event to raise the weapons
|
|
|
|
const idEventDef EV_Weapon_SetViewAnglesSensitivity( "setViewAnglesSensitivity", "f" );
|
|
const idEventDef EV_Weapon_UseAltAmmo( "useAltAmmo", "d" );
|
|
|
|
const idEventDef EV_Weapon_Hide( "hideWeapon" );
|
|
const idEventDef EV_Weapon_Show( "showWeapon" );
|
|
|
|
CLASS_DECLARATION( hhAnimatedEntity, hhWeapon )
|
|
EVENT( EV_Weapon_FireAltProjectiles, hhWeapon::Event_FireAltProjectiles )
|
|
EVENT( EV_Weapon_FireProjectiles, hhWeapon::Event_FireProjectiles )
|
|
EVENT( EV_PlayAnimWhenReady, hhWeapon::Event_PlayAnimWhenReady )
|
|
EVENT( EV_SpawnFxAlongBone, hhWeapon::Event_SpawnFXAlongBone )
|
|
EVENT( EV_Weapon_EjectAltBrass, hhWeapon::Event_EjectAltBrass )
|
|
EVENT( EV_Weapon_HasAmmo, hhWeapon::Event_HasAmmo )
|
|
EVENT( EV_Weapon_HasAltAmmo, hhWeapon::Event_HasAltAmmo )
|
|
EVENT( EV_Weapon_AddToAltClip, hhWeapon::Event_AddToAltClip )
|
|
EVENT( EV_Weapon_AltAmmoInClip, hhWeapon::Event_AltAmmoInClip )
|
|
EVENT( EV_Weapon_AltAmmoAvailable, hhWeapon::Event_AltAmmoAvailable )
|
|
EVENT( EV_Weapon_AltClipSize, hhWeapon::Event_AltClipSize )
|
|
EVENT( EV_Weapon_GetFireDelay, hhWeapon::Event_GetFireDelay )
|
|
EVENT( EV_Weapon_GetAltFireDelay, hhWeapon::Event_GetAltFireDelay )
|
|
EVENT( EV_Weapon_GetString, hhWeapon::Event_GetString )
|
|
EVENT( EV_Weapon_GetAltString, hhWeapon::Event_GetAltString )
|
|
EVENT( EV_Weapon_Raise, hhWeapon::Event_Raise )
|
|
EVENT( EV_Weapon_WeaponAside, hhWeapon::Event_Weapon_Aside )
|
|
EVENT( EV_Weapon_WeaponPuttingAside, hhWeapon::Event_Weapon_PuttingAside )
|
|
EVENT( EV_Weapon_WeaponUprighting, hhWeapon::Event_Weapon_Uprighting )
|
|
EVENT( EV_Weapon_IsAnimPlaying, hhWeapon::Event_IsAnimPlaying )
|
|
EVENT( EV_Weapon_SetViewAnglesSensitivity, hhWeapon::Event_SetViewAnglesSensitivity )
|
|
EVENT( EV_Weapon_Hide, hhWeapon::Event_HideWeapon )
|
|
EVENT( EV_Weapon_Show, hhWeapon::Event_ShowWeapon )
|
|
|
|
//idWeapon
|
|
EVENT( EV_Weapon_State, hhWeapon::Event_WeaponState )
|
|
EVENT( EV_Weapon_WeaponReady, hhWeapon::Event_WeaponReady )
|
|
EVENT( EV_Weapon_WeaponOutOfAmmo, hhWeapon::Event_WeaponOutOfAmmo )
|
|
EVENT( EV_Weapon_WeaponReloading, hhWeapon::Event_WeaponReloading )
|
|
EVENT( EV_Weapon_WeaponHolstered, hhWeapon::Event_WeaponHolstered )
|
|
EVENT( EV_Weapon_WeaponRising, hhWeapon::Event_WeaponRising )
|
|
EVENT( EV_Weapon_WeaponLowering, hhWeapon::Event_WeaponLowering )
|
|
EVENT( EV_Weapon_AddToClip, hhWeapon::Event_AddToClip )
|
|
EVENT( EV_Weapon_AmmoInClip, hhWeapon::Event_AmmoInClip )
|
|
EVENT( EV_Weapon_AmmoAvailable, hhWeapon::Event_AmmoAvailable )
|
|
EVENT( EV_Weapon_ClipSize, hhWeapon::Event_ClipSize )
|
|
EVENT( AI_PlayAnim, hhWeapon::Event_PlayAnim )
|
|
EVENT( AI_PlayCycle, hhWeapon::Event_PlayCycle )
|
|
EVENT( AI_AnimDone, hhWeapon::Event_AnimDone )
|
|
EVENT( EV_Weapon_Next, hhWeapon::Event_Next )
|
|
EVENT( EV_Weapon_Flashlight, hhWeapon::Event_Flashlight )
|
|
EVENT( EV_Weapon_EjectBrass, hhWeapon::Event_EjectBrass )
|
|
EVENT( EV_Weapon_GetOwner, hhWeapon::Event_GetOwner )
|
|
EVENT( EV_Weapon_UseAmmo, hhWeapon::Event_UseAmmo )
|
|
EVENT( EV_Weapon_UseAltAmmo, hhWeapon::Event_UseAltAmmo )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
hhWeapon::hhWeapon
|
|
================
|
|
*/
|
|
hhWeapon::hhWeapon() {
|
|
owner = NULL;
|
|
worldModel = NULL;
|
|
|
|
thread = NULL;
|
|
|
|
//HUMANHEAD: aob
|
|
fireController = NULL;
|
|
altFireController = NULL;
|
|
fl.networkSync = true;
|
|
cameraShakeOffset.Zero(); //rww - had to move here to avoid den/nan/blah in spawn
|
|
//HUMANHEAD END
|
|
|
|
Clear();
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Spawn
|
|
================
|
|
*/
|
|
void hhWeapon::Spawn() {
|
|
//idWeapon
|
|
if ( !gameLocal.isClient )
|
|
{
|
|
worldModel = static_cast< hhAnimatedEntity * >( gameLocal.SpawnEntityType( hhAnimatedEntity::Type, NULL ) );
|
|
worldModel.GetEntity()->fl.networkSync = true;
|
|
}
|
|
|
|
thread = new idThread();
|
|
thread->ManualDelete();
|
|
thread->ManualControl();
|
|
//idWeapon End
|
|
|
|
physicsObj.SetSelf( this );
|
|
physicsObj.SetClipModel( NULL, 1.0f );
|
|
physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
|
|
physicsObj.SetAxis( GetPhysics()->GetAxis() );
|
|
SetPhysics( &physicsObj );
|
|
|
|
fl.solidForTeam = true;
|
|
|
|
// HUMANHEAD: aob
|
|
memset( &eyeTraceInfo, 0, sizeof(trace_t) );
|
|
eyeTraceInfo.fraction = 1.0f;
|
|
BecomeActive( TH_TICKER );
|
|
handedness = hhMath::hhMax<int>( 1, spawnArgs.GetInt("handedness", "1") );
|
|
fl.neverDormant = true;
|
|
// HUMANHEAD END
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::~hhWeapon()
|
|
================
|
|
*/
|
|
hhWeapon::~hhWeapon() {
|
|
SAFE_REMOVE( worldModel );
|
|
SAFE_REMOVE( thread );
|
|
|
|
SAFE_DELETE_PTR( fireController );
|
|
SAFE_DELETE_PTR( altFireController );
|
|
|
|
if ( nozzleFx && nozzleGlowHandle != -1 ) {
|
|
gameRenderWorld->FreeLightDef( nozzleGlowHandle );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::SetOwner
|
|
================
|
|
*/
|
|
void hhWeapon::SetOwner( idPlayer *_owner ) {
|
|
if( !_owner || !_owner->IsType(hhPlayer::Type) ) {
|
|
owner = NULL;
|
|
return;
|
|
}
|
|
|
|
owner = static_cast<hhPlayer*>( _owner );
|
|
|
|
if( GetPhysics() && GetPhysics()->IsType(hhPhysics_StaticWeapon::Type) ) {
|
|
static_cast<hhPhysics_StaticWeapon*>(GetPhysics())->SetSelfOwner( owner.GetEntity() );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Save
|
|
================
|
|
*/
|
|
void hhWeapon::Save( idSaveGame *savefile ) const {
|
|
savefile->WriteInt( status );
|
|
savefile->WriteObject( thread );
|
|
savefile->WriteString( state );
|
|
savefile->WriteString( idealState );
|
|
savefile->WriteInt( animBlendFrames );
|
|
savefile->WriteInt( animDoneTime );
|
|
|
|
owner.Save( savefile );
|
|
worldModel.Save( savefile );
|
|
|
|
savefile->WriteStaticObject( physicsObj );
|
|
|
|
savefile->WriteObject( fireController );
|
|
savefile->WriteObject( altFireController );
|
|
|
|
savefile->WriteTrace( eyeTraceInfo );
|
|
savefile->WriteVec3( cameraShakeOffset );
|
|
savefile->WriteInt( handedness );
|
|
|
|
savefile->WriteVec3( pushVelocity );
|
|
|
|
savefile->WriteString( weaponDef->GetName() );
|
|
|
|
savefile->WriteString( icon );
|
|
|
|
savefile->WriteInt( kick_endtime );
|
|
|
|
savefile->WriteBool( lightOn );
|
|
|
|
savefile->WriteInt( zoomFov );
|
|
|
|
savefile->WriteInt( weaponAngleOffsetAverages );
|
|
savefile->WriteFloat( weaponAngleOffsetScale );
|
|
savefile->WriteFloat( weaponAngleOffsetMax );
|
|
savefile->WriteFloat( weaponOffsetTime );
|
|
savefile->WriteFloat( weaponOffsetScale );
|
|
|
|
savefile->WriteBool( nozzleFx );
|
|
//HUMANHEAD PCF mdl 05/04/06 - Don't save light handles
|
|
//savefile->WriteInt( nozzleGlowHandle );
|
|
savefile->WriteJoint( nozzleJointHandle.view );
|
|
savefile->WriteJoint( nozzleJointHandle.world );
|
|
savefile->WriteRenderLight( nozzleGlow );
|
|
savefile->WriteVec3( nozzleGlowColor );
|
|
savefile->WriteMaterial( nozzleGlowShader );
|
|
savefile->WriteFloat( nozzleGlowRadius );
|
|
savefile->WriteVec3( nozzleGlowOffset );
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Restore
|
|
================
|
|
*/
|
|
void hhWeapon::Restore( idRestoreGame *savefile ) {
|
|
savefile->ReadInt( (int &)status );
|
|
savefile->ReadObject( reinterpret_cast<idClass*&>(thread) );
|
|
savefile->ReadString( state );
|
|
savefile->ReadString( idealState );
|
|
savefile->ReadInt( animBlendFrames );
|
|
savefile->ReadInt( animDoneTime );
|
|
|
|
//Re-link script fields
|
|
WEAPON_ATTACK.LinkTo( scriptObject, "WEAPON_ATTACK" );
|
|
WEAPON_RELOAD.LinkTo( scriptObject, "WEAPON_RELOAD" );
|
|
WEAPON_RAISEWEAPON.LinkTo( scriptObject, "WEAPON_RAISEWEAPON" );
|
|
WEAPON_LOWERWEAPON.LinkTo( scriptObject, "WEAPON_LOWERWEAPON" );
|
|
WEAPON_NEXTATTACK.LinkTo( scriptObject, "nextAttack" ); //HUMANHEAD rww
|
|
|
|
//HUMANHEAD: aob
|
|
WEAPON_ALTATTACK.LinkTo( scriptObject, "WEAPON_ALTATTACK" );
|
|
WEAPON_ASIDEWEAPON.LinkTo( scriptObject, "WEAPON_ASIDEWEAPON" );
|
|
WEAPON_ALTMODE.LinkTo( scriptObject, "WEAPON_ALTMODE" );
|
|
//HUMANHEAD END
|
|
|
|
owner.Restore( savefile );
|
|
worldModel.Restore( savefile );
|
|
|
|
savefile->ReadStaticObject( physicsObj );
|
|
RestorePhysics( &physicsObj );
|
|
|
|
savefile->ReadObject( reinterpret_cast< idClass *&> ( fireController ) );
|
|
savefile->ReadObject( reinterpret_cast< idClass *&> ( altFireController ) );
|
|
|
|
savefile->ReadTrace( eyeTraceInfo );
|
|
savefile->ReadVec3( cameraShakeOffset );
|
|
savefile->ReadInt( handedness );
|
|
|
|
savefile->ReadVec3( pushVelocity );
|
|
|
|
idStr objectname;
|
|
savefile->ReadString( objectname );
|
|
weaponDef = gameLocal.FindEntityDef( objectname, false );
|
|
if (!weaponDef) {
|
|
gameLocal.Error( "Unknown weaponDef: %s\n", objectname );
|
|
}
|
|
dict = &(weaponDef->dict);
|
|
|
|
savefile->ReadString( icon );
|
|
|
|
savefile->ReadInt( kick_endtime );
|
|
|
|
savefile->ReadBool( lightOn );
|
|
|
|
savefile->ReadInt( zoomFov );
|
|
|
|
savefile->ReadInt( weaponAngleOffsetAverages );
|
|
savefile->ReadFloat( weaponAngleOffsetScale );
|
|
savefile->ReadFloat( weaponAngleOffsetMax );
|
|
savefile->ReadFloat( weaponOffsetTime );
|
|
savefile->ReadFloat( weaponOffsetScale );
|
|
|
|
savefile->ReadBool( nozzleFx );
|
|
//HUMANHEAD PCF mdl 05/04/06 - Don't save light handles
|
|
//savefile->ReadInt( nozzleGlowHandle );
|
|
savefile->ReadJoint( nozzleJointHandle.view );
|
|
savefile->ReadJoint( nozzleJointHandle.world );
|
|
savefile->ReadRenderLight( nozzleGlow );
|
|
savefile->ReadVec3( nozzleGlowColor );
|
|
savefile->ReadMaterial( nozzleGlowShader );
|
|
savefile->ReadFloat( nozzleGlowRadius );
|
|
savefile->ReadVec3( nozzleGlowOffset );
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Clear
|
|
================
|
|
*/
|
|
void hhWeapon::Clear( void ) {
|
|
DeconstructScriptObject();
|
|
scriptObject.Free();
|
|
|
|
WEAPON_ATTACK.Unlink();
|
|
WEAPON_RELOAD.Unlink();
|
|
WEAPON_RAISEWEAPON.Unlink();
|
|
WEAPON_LOWERWEAPON.Unlink();
|
|
WEAPON_NEXTATTACK.Unlink(); //HUMANHEAD rww
|
|
|
|
//HUMANHEAD: aob
|
|
WEAPON_ALTATTACK.Unlink();
|
|
WEAPON_ASIDEWEAPON.Unlink();
|
|
WEAPON_ALTMODE.Unlink();
|
|
|
|
SAFE_DELETE_PTR( fireController );
|
|
SAFE_DELETE_PTR( altFireController );
|
|
//HUMANEAD END
|
|
|
|
//memset( &renderEntity, 0, sizeof( renderEntity ) );
|
|
renderEntity.entityNum = entityNumber;
|
|
|
|
renderEntity.noShadow = true;
|
|
renderEntity.noSelfShadow = true;
|
|
renderEntity.customSkin = NULL;
|
|
|
|
// set default shader parms
|
|
renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f;
|
|
renderEntity.shaderParms[ SHADERPARM_GREEN ]= 1.0f;
|
|
renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
|
|
renderEntity.shaderParms[3] = 1.0f;
|
|
renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = 0.0f;
|
|
renderEntity.shaderParms[5] = 0.0f;
|
|
renderEntity.shaderParms[6] = 0.0f;
|
|
renderEntity.shaderParms[7] = 0.0f;
|
|
|
|
// nozzle fx
|
|
nozzleFx = false;
|
|
memset( &nozzleGlow, 0, sizeof( nozzleGlow ) );
|
|
nozzleGlowHandle = -1;
|
|
nozzleJointHandle.Clear();
|
|
|
|
memset( &refSound, 0, sizeof( refSound_t ) );
|
|
if ( owner.IsValid() ) {
|
|
// don't spatialize the weapon sounds
|
|
refSound.listenerId = owner->GetListenerId();
|
|
}
|
|
|
|
// clear out the sounds from our spawnargs since we'll copy them from the weapon def
|
|
const idKeyValue *kv = spawnArgs.MatchPrefix( "snd_" );
|
|
while( kv ) {
|
|
spawnArgs.Delete( kv->GetKey() );
|
|
kv = spawnArgs.MatchPrefix( "snd_" );
|
|
}
|
|
|
|
weaponDef = NULL;
|
|
dict = NULL;
|
|
|
|
kick_endtime = 0;
|
|
|
|
icon = "";
|
|
|
|
pushVelocity.Zero();
|
|
|
|
status = WP_HOLSTERED;
|
|
state = "";
|
|
idealState = "";
|
|
animBlendFrames = 0;
|
|
animDoneTime = 0;
|
|
|
|
lightOn = false;
|
|
|
|
zoomFov = 90;
|
|
|
|
weaponAngleOffsetAverages = 10; //initialize this to default number to prevent infinite loops
|
|
|
|
FreeModelDef();
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::InitWorldModel
|
|
================
|
|
*/
|
|
void hhWeapon::InitWorldModel( const idDict *dict ) {
|
|
idEntity *ent;
|
|
|
|
ent = worldModel.GetEntity();
|
|
if ( !ent || !dict ) {
|
|
return;
|
|
}
|
|
|
|
const char *model = dict->GetString( "model_world" );
|
|
const char *attach = dict->GetString( "joint_attach" );
|
|
|
|
if (gameLocal.isMultiplayer) { //HUMANHEAD rww - shadow default based on whether the player shadows
|
|
ent->GetRenderEntity()->noShadow = MP_PLAYERNOSHADOW_DEFAULT;
|
|
}
|
|
|
|
if ( model[0] && attach[0] ) {
|
|
ent->Show();
|
|
ent->SetModel( model );
|
|
ent->GetPhysics()->SetContents( 0 );
|
|
ent->GetPhysics()->SetClipModel( NULL, 1.0f );
|
|
ent->BindToJoint( owner.GetEntity(), attach, true );
|
|
ent->GetPhysics()->SetOrigin( vec3_origin );
|
|
ent->GetPhysics()->SetAxis( mat3_identity );
|
|
|
|
// supress model in player views, but allow it in mirrors and remote views
|
|
renderEntity_t *worldModelRenderEntity = ent->GetRenderEntity();
|
|
if ( worldModelRenderEntity ) {
|
|
worldModelRenderEntity->suppressSurfaceInViewID = owner->entityNumber+1;
|
|
worldModelRenderEntity->suppressShadowInViewID = owner->entityNumber+1;
|
|
worldModelRenderEntity->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
|
|
}
|
|
} else {
|
|
ent->SetModel( "" );
|
|
ent->Hide();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::GetWeaponDef
|
|
|
|
HUMANHEAD: aob - this should only be called after the weapon has just been created
|
|
================
|
|
*/
|
|
void hhWeapon::GetWeaponDef( const char *objectname ) {
|
|
//HUMANHEAD: aob - put logic in helper function
|
|
ParseDef( objectname );
|
|
//HUMANHEAD END
|
|
|
|
if( owner->inventory.weaponRaised[owner->GetWeaponNum(objectname)] || gameLocal.isMultiplayer )
|
|
ProcessEvent( &EV_Weapon_State, "Raise", 0 );
|
|
else {
|
|
ProcessEvent( &EV_Weapon_State, "NewRaise", 0 );
|
|
owner->inventory.weaponRaised[owner->GetWeaponNum(objectname)] = true;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::ParseDef
|
|
|
|
HUMANHEAD: aob
|
|
================
|
|
*/
|
|
void hhWeapon::ParseDef( const char* objectname ) {
|
|
if( !objectname || !objectname[ 0 ] ) {
|
|
return;
|
|
}
|
|
|
|
if( !owner.IsValid() ) {
|
|
gameLocal.Error( "hhWeapon::ParseDef: no owner" );
|
|
}
|
|
|
|
weaponDef = gameLocal.FindEntityDef( objectname, false );
|
|
if (!weaponDef) {
|
|
gameLocal.Error( "Unknown weaponDef: %s\n", objectname );
|
|
}
|
|
dict = &(weaponDef->dict);
|
|
|
|
// setup the world model
|
|
InitWorldModel( dict );
|
|
|
|
if (!owner.IsValid() || !owner.GetEntity()) {
|
|
gameLocal.Error("NULL owner in hhWeapon::ParseDef!");
|
|
}
|
|
|
|
//HUMANHEAD: aob
|
|
const idDict* infoDict = gameLocal.FindEntityDefDict( dict->GetString("def_fireInfo"), false );
|
|
if( infoDict ) {
|
|
fireController = CreateFireController();
|
|
if( fireController ) {
|
|
fireController->Init( infoDict, this, owner.GetEntity() );
|
|
}
|
|
}
|
|
|
|
infoDict = gameLocal.FindEntityDefDict( dict->GetString("def_altFireInfo"), false );
|
|
if( infoDict ) {
|
|
altFireController = CreateAltFireController();
|
|
if( altFireController ) {
|
|
altFireController->Init( infoDict, this, owner.GetEntity() );
|
|
}
|
|
}
|
|
//HUMANHEAD END
|
|
|
|
icon = dict->GetString( "inv_icon" );
|
|
|
|
// copy the sounds from the weapon view model def into out spawnargs
|
|
const idKeyValue *kv = dict->MatchPrefix( "snd_" );
|
|
while( kv ) {
|
|
spawnArgs.Set( kv->GetKey(), kv->GetValue() );
|
|
kv = dict->MatchPrefix( "snd_", kv );
|
|
}
|
|
|
|
weaponAngleOffsetAverages = dict->GetInt( "weaponAngleOffsetAverages", "10" );
|
|
weaponAngleOffsetScale = dict->GetFloat( "weaponAngleOffsetScale", "0.1" );
|
|
weaponAngleOffsetMax = dict->GetFloat( "weaponAngleOffsetMax", "10" );
|
|
|
|
weaponOffsetTime = dict->GetFloat( "weaponOffsetTime", "400" );
|
|
weaponOffsetScale = dict->GetFloat( "weaponOffsetScale", "0.002" );
|
|
|
|
zoomFov = dict->GetInt( "zoomFov", "70" );
|
|
|
|
InitScriptObject( dict->GetString("scriptobject") );
|
|
|
|
nozzleFx = weaponDef->dict.GetBool( "nozzleFx", "0" );
|
|
nozzleGlowColor = weaponDef->dict.GetVector("nozzleGlowColor", "1 1 1");
|
|
nozzleGlowRadius = weaponDef->dict.GetFloat("nozzleGlowRadius", "10");
|
|
nozzleGlowOffset = weaponDef->dict.GetVector( "nozzleGlowOffset", "0 0 0" );
|
|
nozzleGlowShader = declManager->FindMaterial( weaponDef->dict.GetString( "mtr_nozzleGlowShader", "" ), false );
|
|
GetJointHandle( weaponDef->dict.GetString( "nozzleJoint", "" ), nozzleJointHandle );
|
|
|
|
//HUMANHEAD bjk
|
|
int clipAmmo = owner->inventory.clip[owner->GetWeaponNum(objectname)];
|
|
if ( ( clipAmmo < 0 ) || ( clipAmmo > fireController->ClipSize() ) ) {
|
|
// first time using this weapon so have it fully loaded to start
|
|
clipAmmo = fireController->ClipSize();
|
|
if ( clipAmmo > fireController->AmmoAvailable() ) {
|
|
clipAmmo = fireController->AmmoAvailable();
|
|
}
|
|
}
|
|
fireController->AddToClip(clipAmmo);
|
|
|
|
WEAPON_ALTMODE = owner->inventory.altMode[owner->GetWeaponNum(objectname)];
|
|
//HUMANHEAD END
|
|
|
|
Show();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWeapon::ShouldConstructScriptObjectAtSpawn
|
|
|
|
Called during idEntity::Spawn to see if it should construct the script object or not.
|
|
Overridden by subclasses that need to spawn the script object themselves.
|
|
================
|
|
*/
|
|
bool hhWeapon::ShouldConstructScriptObjectAtSpawn( void ) const {
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::InitScriptObject
|
|
================
|
|
*/
|
|
void hhWeapon::InitScriptObject( const char* objectType ) {
|
|
if( !objectType || !objectType[0] ) {
|
|
gameLocal.Error( "No scriptobject set on '%s'.", dict->GetString("classname") );
|
|
}
|
|
|
|
if( !idStr::Icmp(scriptObject.GetTypeName(), objectType) ) {
|
|
//Same script object, don't reload it
|
|
return;
|
|
}
|
|
|
|
// setup script object
|
|
if( !scriptObject.SetType(objectType) ) {
|
|
gameLocal.Error( "Script object '%s' not found on weapon '%s'.", objectType, dict->GetString("classname") );
|
|
}
|
|
|
|
WEAPON_ATTACK.LinkTo( scriptObject, "WEAPON_ATTACK" );
|
|
WEAPON_RELOAD.LinkTo( scriptObject, "WEAPON_RELOAD" );
|
|
WEAPON_RAISEWEAPON.LinkTo( scriptObject, "WEAPON_RAISEWEAPON" );
|
|
WEAPON_LOWERWEAPON.LinkTo( scriptObject, "WEAPON_LOWERWEAPON" );
|
|
WEAPON_NEXTATTACK.LinkTo( scriptObject, "nextAttack" ); //HUMANHEAD rww
|
|
|
|
//HUMANHEAD: aob
|
|
WEAPON_ALTATTACK.LinkTo( scriptObject, "WEAPON_ALTATTACK" );
|
|
WEAPON_ASIDEWEAPON.LinkTo( scriptObject, "WEAPON_ASIDEWEAPON" );
|
|
WEAPON_ALTMODE.LinkTo( scriptObject, "WEAPON_ALTMODE" );
|
|
//HUMANHEAD END
|
|
|
|
// call script object's constructor
|
|
ConstructScriptObject();
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
GUIs
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Icon
|
|
================
|
|
*/
|
|
const char *hhWeapon::Icon( void ) const {
|
|
return icon;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::UpdateGUI
|
|
================
|
|
*/
|
|
void hhWeapon::UpdateGUI() {
|
|
if ( !renderEntity.gui[0] ) {
|
|
return;
|
|
}
|
|
|
|
if ( status == WP_HOLSTERED ) {
|
|
return;
|
|
}
|
|
|
|
int ammoamount = AmmoAvailable();
|
|
int altammoamount = AltAmmoAvailable();
|
|
|
|
// show remaining ammo
|
|
renderEntity.gui[ 0 ]->SetStateInt( "ammoamount", ammoamount );
|
|
renderEntity.gui[ 0 ]->SetStateInt( "altammoamount", altammoamount );
|
|
renderEntity.gui[ 0 ]->SetStateBool( "ammolow", ammoamount > 0 && ammoamount <= LowAmmo() );
|
|
renderEntity.gui[ 0 ]->SetStateBool( "altammolow", altammoamount > 0 && altammoamount <= LowAltAmmo() );
|
|
renderEntity.gui[ 0 ]->SetStateBool( "ammoempty", ( ammoamount == 0 ) );
|
|
renderEntity.gui[ 0 ]->SetStateBool( "altammoempty", ( altammoamount == 0 ) );
|
|
renderEntity.gui[ 0 ]->SetStateInt( "clipammoAmount", AmmoInClip() );
|
|
renderEntity.gui[ 0 ]->SetStateInt( "clipaltammoAmount", AltAmmoInClip() );
|
|
renderEntity.gui[ 0 ]->StateChanged(gameLocal.time);
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
Model and muzzleflash
|
|
|
|
***********************************************************************/
|
|
/*
|
|
================
|
|
hhWeapon::GetGlobalJointTransform
|
|
|
|
This returns the offset and axis of a weapon bone in world space, suitable for attaching models or lights
|
|
================
|
|
*/
|
|
bool hhWeapon::GetJointWorldTransform( const char* jointName, idVec3 &offset, idMat3 &axis ) {
|
|
weaponJointHandle_t handle;
|
|
|
|
GetJointHandle( jointName, handle );
|
|
return GetJointWorldTransform( handle, offset, axis );
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::GetGlobalJointTransform
|
|
|
|
This returns the offset and axis of a weapon bone in world space, suitable for attaching models or lights
|
|
================
|
|
*/
|
|
bool hhWeapon::GetJointWorldTransform( const weaponJointHandle_t& handle, idVec3 &offset, idMat3 &axis, bool muzzleOnly ) {
|
|
//FIXME: this seems to work but may need revisiting
|
|
//FIXME: totally forgot about mirrors and portals. This may not work.
|
|
if( (!pm_thirdPerson.GetBool() && owner == gameLocal.GetLocalPlayer()) || (gameLocal.GetLocalPlayer() && gameLocal.GetLocalPlayer()->spectating && gameLocal.GetLocalPlayer()->spectator == owner->entityNumber) || (gameLocal.isServer && !muzzleOnly)) { //rww - mp server should always create projectiles from the viewmodel
|
|
// view model
|
|
if ( hhAnimatedEntity::GetJointWorldTransform(handle.view, offset, axis) ) {
|
|
return true;
|
|
}
|
|
} else {
|
|
// world model
|
|
if ( worldModel.IsValid() && worldModel.GetEntity()->GetJointWorldTransform(handle.world, offset, axis) ) {
|
|
return true;
|
|
}
|
|
}
|
|
offset = GetOrigin();
|
|
axis = GetAxis();
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::GetJointHandle
|
|
|
|
HUMANHEAD: aob
|
|
================
|
|
*/
|
|
void hhWeapon::GetJointHandle( const char* jointName, weaponJointHandle_t& handle ) {
|
|
if( dict ) {
|
|
handle.view = GetAnimator()->GetJointHandle( jointName );
|
|
}
|
|
|
|
if( worldModel.IsValid() ) {
|
|
handle.world = worldModel->GetAnimator()->GetJointHandle( jointName );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::SetPushVelocity
|
|
================
|
|
*/
|
|
void hhWeapon::SetPushVelocity( const idVec3 &pushVelocity ) {
|
|
this->pushVelocity = pushVelocity;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
State control/player interface
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Raise
|
|
================
|
|
*/
|
|
void hhWeapon::Raise( void ) {
|
|
WEAPON_RAISEWEAPON = true;
|
|
WEAPON_ASIDEWEAPON = false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::PutAway
|
|
================
|
|
*/
|
|
void hhWeapon::PutAway( void ) {
|
|
//hasBloodSplat = false;
|
|
WEAPON_LOWERWEAPON = true;
|
|
WEAPON_RAISEWEAPON = false; //HUMANHEAD bjk PCF 5-4-06 : fix for weapons being up after death
|
|
WEAPON_ASIDEWEAPON = false;
|
|
WEAPON_ATTACK = false;
|
|
WEAPON_ALTATTACK = false;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
hhWeapon::PutAside
|
|
================
|
|
*/
|
|
void hhWeapon::PutAside( void ) {
|
|
//HUMANHEAD bjk PCF (4-27-06) - no setting unnecessary weapon state
|
|
//WEAPON_LOWERWEAPON = false;
|
|
//WEAPON_RAISEWEAPON = false;
|
|
WEAPON_ASIDEWEAPON = true;
|
|
WEAPON_ATTACK = false;
|
|
WEAPON_ALTATTACK = false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::PutUpright
|
|
================
|
|
*/
|
|
void hhWeapon::PutUpright( void ) {
|
|
WEAPON_ASIDEWEAPON = false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::SnapDown
|
|
|
|
HUMANHEAD: aob
|
|
================
|
|
*/
|
|
void hhWeapon::SnapDown() {
|
|
ProcessEvent( &EV_Weapon_State, "Down", 0 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::SnapUp
|
|
|
|
HUMANHEAD: aob
|
|
================
|
|
*/
|
|
void hhWeapon::SnapUp() {
|
|
ProcessEvent( &EV_Weapon_State, "Up", 0 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Reload
|
|
================
|
|
*/
|
|
void hhWeapon::Reload( void ) {
|
|
WEAPON_RELOAD = true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::HideWeapon
|
|
================
|
|
*/
|
|
void hhWeapon::HideWeapon( void ) {
|
|
Hide();
|
|
if ( worldModel.GetEntity() ) {
|
|
worldModel.GetEntity()->Hide();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::ShowWeapon
|
|
================
|
|
*/
|
|
void hhWeapon::ShowWeapon( void ) {
|
|
Show();
|
|
if ( worldModel.GetEntity() ) {
|
|
worldModel.GetEntity()->Show();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::HideWorldModel
|
|
================
|
|
*/
|
|
void hhWeapon::HideWorldModel( void ) {
|
|
if ( worldModel.GetEntity() ) {
|
|
worldModel.GetEntity()->Hide();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::ShowWorldModel
|
|
================
|
|
*/
|
|
void hhWeapon::ShowWorldModel( void ) {
|
|
if ( worldModel.GetEntity() ) {
|
|
worldModel.GetEntity()->Show();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::OwnerDied
|
|
================
|
|
*/
|
|
void hhWeapon::OwnerDied( void ) {
|
|
Hide();
|
|
if ( worldModel.GetEntity() ) {
|
|
worldModel.GetEntity()->Hide();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::BeginAltAttack
|
|
================
|
|
*/
|
|
void hhWeapon::BeginAltAttack( void ) {
|
|
WEAPON_ALTATTACK = true;
|
|
|
|
//if ( status != WP_OUTOFAMMO ) {
|
|
// lastAttack = gameLocal.time;
|
|
//}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::EndAltAttack
|
|
================
|
|
*/
|
|
void hhWeapon::EndAltAttack( void ) {
|
|
WEAPON_ALTATTACK = false;
|
|
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::BeginAttack
|
|
================
|
|
*/
|
|
void hhWeapon::BeginAttack( void ) {
|
|
//if ( status != WP_OUTOFAMMO ) {
|
|
// lastAttack = gameLocal.time;
|
|
//}
|
|
|
|
WEAPON_ATTACK = true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::EndAttack
|
|
================
|
|
*/
|
|
void hhWeapon::EndAttack( void ) {
|
|
if ( !WEAPON_ATTACK.IsLinked() ) {
|
|
return;
|
|
}
|
|
if ( WEAPON_ATTACK ) {
|
|
WEAPON_ATTACK = false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::isReady
|
|
================
|
|
*/
|
|
bool hhWeapon::IsReady( void ) const {
|
|
return !IsHidden() && ( ( status == WP_READY ) || ( status == WP_OUTOFAMMO ) );
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::IsReloading
|
|
================
|
|
*/
|
|
bool hhWeapon::IsReloading( void ) const {
|
|
return ( status == WP_RELOAD );
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::IsChangable
|
|
================
|
|
*/
|
|
bool hhWeapon::IsChangable( void ) const {
|
|
//HUMANHEAD: aob - same as IsReady except w/o IsHidden check
|
|
//Allows us to switch weapons while they are hidden
|
|
//Hope this doesn't fuck to many things
|
|
return ( ( status == WP_READY ) || ( status == WP_OUTOFAMMO ) );
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::IsHolstered
|
|
================
|
|
*/
|
|
bool hhWeapon::IsHolstered( void ) const {
|
|
return ( status == WP_HOLSTERED );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
hhWeapon::IsLowered
|
|
================
|
|
*/
|
|
bool hhWeapon::IsLowered( void ) const {
|
|
return ( status == WP_HOLSTERED ) || ( status == WP_LOWERING );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
hhWeapon::IsRising
|
|
================
|
|
*/
|
|
bool hhWeapon::IsRising( void ) const {
|
|
return ( status == WP_RISING );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
hhWeapon::IsAside
|
|
================
|
|
*/
|
|
bool hhWeapon::IsAside( void ) const {
|
|
return ( status == WP_ASIDE );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
hhWeapon::ShowCrosshair
|
|
================
|
|
*/
|
|
bool hhWeapon::ShowCrosshair( void ) const {
|
|
//HUMANHEAD: aob - added cinematic check
|
|
return !( state == idStr( WP_RISING ) || state == idStr( WP_LOWERING ) || state == idStr( WP_HOLSTERED ) ) && !owner->InCinematic();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
hhWeapon::DropItem
|
|
=====================
|
|
*/
|
|
idEntity* hhWeapon::DropItem( const idVec3 &velocity, int activateDelay, int removeDelay, bool died ) {
|
|
if ( !weaponDef || !worldModel.GetEntity() ) {
|
|
return NULL;
|
|
}
|
|
|
|
const char *classname = weaponDef->dict.GetString( "def_dropItem" );
|
|
if ( !classname[0] ) {
|
|
return NULL;
|
|
}
|
|
StopSound( SND_CHANNEL_BODY, !died ); //HUMANHEAD rww - on death, do not broadcast the stop, because the weapon itself is about to be removed
|
|
return idMoveableItem::DropItem( classname, worldModel.GetEntity()->GetPhysics()->GetOrigin(), worldModel.GetEntity()->GetPhysics()->GetAxis(), velocity, activateDelay, removeDelay );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
hhWeapon::CanDrop
|
|
=====================
|
|
*/
|
|
bool hhWeapon::CanDrop( void ) const {
|
|
if ( !weaponDef || !worldModel.GetEntity() ) {
|
|
return false;
|
|
}
|
|
const char *classname = weaponDef->dict.GetString( "def_dropItem" );
|
|
if ( !classname[ 0 ] ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
Script state management
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
hhWeapon::SetState
|
|
=====================
|
|
*/
|
|
void hhWeapon::SetState( const char *statename, int blendFrames ) {
|
|
const function_t *func;
|
|
|
|
func = scriptObject.GetFunction( statename );
|
|
if ( !func ) {
|
|
gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() );
|
|
}
|
|
|
|
thread->CallFunction( this, func, true );
|
|
state = statename;
|
|
|
|
animBlendFrames = blendFrames;
|
|
if ( g_debugWeapon.GetBool() ) {
|
|
gameLocal.Printf( "%d: weapon state : %s\n", gameLocal.time, statename );
|
|
}
|
|
|
|
idealState = "";
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
Visual presentation
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
================
|
|
hhWeapon::MuzzleRise
|
|
|
|
HUMANHEAD: aob
|
|
================
|
|
*/
|
|
void hhWeapon::MuzzleRise( idVec3 &origin, idMat3 &axis ) {
|
|
if( fireController ) {
|
|
fireController->CalculateMuzzleRise( origin, axis );
|
|
}
|
|
|
|
if( altFireController ) {
|
|
altFireController->CalculateMuzzleRise( origin, axis );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::ConstructScriptObject
|
|
|
|
Called during idEntity::Spawn. Calls the constructor on the script object.
|
|
Can be overridden by subclasses when a thread doesn't need to be allocated.
|
|
================
|
|
*/
|
|
idThread *hhWeapon::ConstructScriptObject( void ) {
|
|
const function_t *constructor;
|
|
|
|
//HUMANHEAD: aob
|
|
if( !thread ) {
|
|
return thread;
|
|
}
|
|
//HUMANHEAD END
|
|
|
|
thread->EndThread();
|
|
|
|
// call script object's constructor
|
|
constructor = scriptObject.GetConstructor();
|
|
if ( !constructor ) {
|
|
gameLocal.Error( "Missing constructor on '%s' for weapon", scriptObject.GetTypeName() );
|
|
}
|
|
|
|
// init the script object's data
|
|
scriptObject.ClearObject();
|
|
thread->CallFunction( this, constructor, true );
|
|
thread->Execute();
|
|
|
|
return thread;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::DeconstructScriptObject
|
|
|
|
Called during idEntity::~idEntity. Calls the destructor on the script object.
|
|
Can be overridden by subclasses when a thread doesn't need to be allocated.
|
|
Not called during idGameLocal::MapShutdown.
|
|
================
|
|
*/
|
|
void hhWeapon::DeconstructScriptObject( void ) {
|
|
const function_t *destructor;
|
|
|
|
if ( !thread ) {
|
|
return;
|
|
}
|
|
|
|
// don't bother calling the script object's destructor on map shutdown
|
|
if ( gameLocal.GameState() == GAMESTATE_SHUTDOWN ) {
|
|
return;
|
|
}
|
|
|
|
thread->EndThread();
|
|
|
|
// call script object's destructor
|
|
destructor = scriptObject.GetDestructor();
|
|
if ( destructor ) {
|
|
// start a thread that will run immediately and end
|
|
thread->CallFunction( this, destructor, true );
|
|
thread->Execute();
|
|
thread->EndThread();
|
|
}
|
|
|
|
// clear out the object's memory
|
|
scriptObject.ClearObject();
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::UpdateScript
|
|
================
|
|
*/
|
|
void hhWeapon::UpdateScript( void ) {
|
|
int count;
|
|
|
|
if ( !IsLinked() ) {
|
|
return;
|
|
}
|
|
|
|
// only update the script on new frames
|
|
if ( !gameLocal.isNewFrame ) {
|
|
return;
|
|
}
|
|
|
|
if ( idealState.Length() ) {
|
|
SetState( idealState, animBlendFrames );
|
|
}
|
|
|
|
// update script state, which may call Event_LaunchProjectiles, among other things
|
|
count = 10;
|
|
while( ( thread->Execute() || idealState.Length() ) && count-- ) {
|
|
// happens for weapons with no clip (like grenades)
|
|
if ( idealState.Length() ) {
|
|
SetState( idealState, animBlendFrames );
|
|
}
|
|
}
|
|
|
|
WEAPON_RELOAD = false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::PresentWeapon
|
|
================
|
|
*/
|
|
void hhWeapon::PresentWeapon( bool showViewModel ) {
|
|
UpdateScript();
|
|
|
|
//HUMANHEAD rww - added this gui owner logic here
|
|
bool allowGuiUpdate = true;
|
|
if ( owner.IsValid() && gameLocal.localClientNum != owner->entityNumber ) {
|
|
// if updating the hud for a followed client
|
|
if ( gameLocal.localClientNum >= 0 && gameLocal.entities[ gameLocal.localClientNum ] && gameLocal.entities[ gameLocal.localClientNum ]->IsType( idPlayer::Type ) ) {
|
|
idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ gameLocal.localClientNum ] );
|
|
if ( !p->spectating || p->spectator != owner->entityNumber ) {
|
|
allowGuiUpdate = false;
|
|
}
|
|
} else {
|
|
allowGuiUpdate = false;
|
|
}
|
|
}
|
|
if (allowGuiUpdate) {
|
|
UpdateGUI();
|
|
}
|
|
|
|
// update animation
|
|
UpdateAnimation();
|
|
|
|
// only show the surface in player view
|
|
renderEntity.allowSurfaceInViewID = owner->entityNumber+1;
|
|
|
|
// crunch the depth range so it never pokes into walls this breaks the machine gun gui
|
|
renderEntity.weaponDepthHack = true;
|
|
|
|
// present the model
|
|
if ( showViewModel ) {
|
|
Present();
|
|
} else {
|
|
FreeModelDef();
|
|
}
|
|
|
|
if ( worldModel.GetEntity() && worldModel.GetEntity()->GetRenderEntity() ) {
|
|
// deal with the third-person visible world model
|
|
// don't show shadows of the world model in first person
|
|
#ifdef HUMANHEAD
|
|
if ( gameLocal.isMultiplayer || (g_showPlayerShadow.GetBool() && pm_modelView.GetInteger() == 1) || pm_thirdPerson.GetBool()
|
|
|| (pm_modelView.GetInteger() == 2 && owner->health <= 0)) {
|
|
worldModel->GetRenderEntity()->suppressShadowInViewID = 0;
|
|
} else {
|
|
worldModel->GetRenderEntity()->suppressShadowInViewID = owner->entityNumber+1;
|
|
worldModel->GetRenderEntity()->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
|
|
}
|
|
#else
|
|
|
|
// deal with the third-person visible world model
|
|
// don't show shadows of the world model in first person
|
|
if ( gameLocal.isMultiplayer || g_showPlayerShadow.GetBool() || pm_thirdPerson.GetBool() ) {
|
|
worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID = 0;
|
|
} else {
|
|
worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID = owner->entityNumber+1;
|
|
worldModel.GetEntity()->GetRenderEntity()->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
|
|
}
|
|
}
|
|
#endif // HUMANHEAD pdm
|
|
}
|
|
|
|
// update the muzzle flash light, so it moves with the gun
|
|
//HUMANHEAD: aob
|
|
if( fireController ) {
|
|
fireController->UpdateMuzzleFlash();
|
|
}
|
|
|
|
if( altFireController ) {
|
|
altFireController->UpdateMuzzleFlash();
|
|
}
|
|
//HUMANHEAD END
|
|
|
|
UpdateNozzleFx(); // expensive
|
|
|
|
UpdateSound();
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
hhWeapon::EnterCinematic
|
|
================
|
|
*/
|
|
void hhWeapon::EnterCinematic( void ) {
|
|
StopSound( SND_CHANNEL_ANY, false );
|
|
|
|
if ( IsLinked() ) {
|
|
SetState( "EnterCinematic", 0 );
|
|
thread->Execute();
|
|
|
|
WEAPON_ATTACK = false;
|
|
WEAPON_RELOAD = false;
|
|
// WEAPON_NETRELOAD = false;
|
|
// WEAPON_NETENDRELOAD = false;
|
|
WEAPON_RAISEWEAPON = false;
|
|
WEAPON_LOWERWEAPON = false;
|
|
}
|
|
|
|
//disabled = true;
|
|
|
|
LowerWeapon();
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::ExitCinematic
|
|
================
|
|
*/
|
|
void hhWeapon::ExitCinematic( void ) {
|
|
//disabled = false;
|
|
|
|
if ( IsLinked() ) {
|
|
SetState( "ExitCinematic", 0 );
|
|
thread->Execute();
|
|
}
|
|
|
|
RaiseWeapon();
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::NetCatchup
|
|
================
|
|
*/
|
|
void hhWeapon::NetCatchup( void ) {
|
|
if ( IsLinked() ) {
|
|
SetState( "NetCatchup", 0 );
|
|
thread->Execute();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::GetClipBits
|
|
================
|
|
*/
|
|
int hhWeapon::GetClipBits(void) const {
|
|
return ASYNC_PLAYER_INV_CLIP_BITS;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::GetZoomFov
|
|
================
|
|
*/
|
|
int hhWeapon::GetZoomFov( void ) {
|
|
return zoomFov;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::GetWeaponAngleOffsets
|
|
================
|
|
*/
|
|
void hhWeapon::GetWeaponAngleOffsets( int *average, float *scale, float *max ) {
|
|
*average = weaponAngleOffsetAverages;
|
|
*scale = weaponAngleOffsetScale;
|
|
*max = weaponAngleOffsetMax;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::GetWeaponTimeOffsets
|
|
================
|
|
*/
|
|
void hhWeapon::GetWeaponTimeOffsets( float *time, float *scale ) {
|
|
*time = weaponOffsetTime;
|
|
*scale = weaponOffsetScale;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Ammo
|
|
|
|
**********************************************************************/
|
|
|
|
/*
|
|
================
|
|
hhWeapon::WriteToSnapshot
|
|
================
|
|
*/
|
|
void hhWeapon::WriteToSnapshot( idBitMsgDelta &msg ) const {
|
|
#if 0
|
|
//FIXME: need to add altFire stuff too
|
|
if( fireController ) {
|
|
msg.WriteBits( fireController->AmmoInClip(), GetClipBits() );
|
|
} else {
|
|
msg.WriteBits( 0, GetClipBits() );
|
|
}
|
|
msg.WriteBits(worldModel.GetSpawnId(), 32);
|
|
#else //rww - forget this silliness, let's do this the Right Way.
|
|
msg.WriteBits(owner.GetSpawnId(), 32);
|
|
msg.WriteBits(worldModel.GetSpawnId(), 32);
|
|
|
|
if (fireController) {
|
|
fireController->WriteToSnapshot(msg);
|
|
}
|
|
else { //rwwFIXME this is an ugly hack
|
|
msg.WriteBits(0, 32);
|
|
msg.WriteBits(0, 32);
|
|
msg.WriteBits(0, GetClipBits());
|
|
}
|
|
if (altFireController) {
|
|
altFireController->WriteToSnapshot(msg);
|
|
}
|
|
else { //rwwFIXME this is an ugly hack
|
|
msg.WriteBits(0, 32);
|
|
msg.WriteBits(0, 32);
|
|
msg.WriteBits(0, GetClipBits());
|
|
}
|
|
|
|
msg.WriteBits(WEAPON_ASIDEWEAPON, 1);
|
|
//HUMANHEAD PCF rww 05/09/06 - no need to sync these values
|
|
/*
|
|
msg.WriteBits(WEAPON_LOWERWEAPON, 1);
|
|
msg.WriteBits(WEAPON_RAISEWEAPON, 1);
|
|
*/
|
|
|
|
WriteBindToSnapshot(msg);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::ReadFromSnapshot
|
|
================
|
|
*/
|
|
void hhWeapon::ReadFromSnapshot( const idBitMsgDelta &msg ) {
|
|
#if 0
|
|
//FIXME: need to add altFire stuff too
|
|
if( fireController ) {
|
|
fireController->AddToClip( msg.ReadBits(GetClipBits()) );
|
|
} else {
|
|
msg.ReadBits( GetClipBits() );
|
|
}
|
|
|
|
worldModel.SetSpawnId(msg.ReadBits(32));
|
|
#else
|
|
bool wmInit = false;
|
|
|
|
owner.SetSpawnId(msg.ReadBits(32));
|
|
|
|
if (worldModel.SetSpawnId(msg.ReadBits(32))) { //do this once we finally get the entity in the snapshot
|
|
wmInit = true;
|
|
}
|
|
|
|
//rwwFIXME this is a little hacky, i think. is there a way to do it in ::Spawn? but, the weapon doesn't know its owner at that point.
|
|
if (!dict) {
|
|
if (!owner.IsValid() || !owner.GetEntity()) {
|
|
gameLocal.Error("NULL owner in hhWeapon::ReadFromSnapshot!");
|
|
}
|
|
|
|
assert(owner.IsValid());
|
|
|
|
GetWeaponDef(spawnArgs.GetString("classname"));
|
|
//owner->ForceWeapon(this); it doesn't like this.
|
|
}
|
|
assert(fireController);
|
|
assert(altFireController);
|
|
|
|
if (wmInit) { //need to do this once the ent is valid on the client
|
|
InitWorldModel( dict );
|
|
GetJointHandle( weaponDef->dict.GetString( "nozzleJoint", "" ), nozzleJointHandle );
|
|
fireController->UpdateWeaponJoints();
|
|
altFireController->UpdateWeaponJoints();
|
|
}
|
|
|
|
fireController->ReadFromSnapshot(msg);
|
|
altFireController->ReadFromSnapshot(msg);
|
|
|
|
WEAPON_ASIDEWEAPON = !!msg.ReadBits(1);
|
|
//HUMANHEAD PCF rww 05/09/06 - no need to sync these values
|
|
/*
|
|
WEAPON_LOWERWEAPON = !!msg.ReadBits(1);
|
|
WEAPON_RAISEWEAPON = !!msg.ReadBits(1);
|
|
*/
|
|
|
|
ReadBindFromSnapshot(msg);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::ClientPredictionThink
|
|
================
|
|
*/
|
|
void hhWeapon::ClientPredictionThink( void ) {
|
|
Think();
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
Script events
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
hhWeapon::Event_Raise
|
|
*/
|
|
void hhWeapon::Event_Raise() {
|
|
Raise();
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_WeaponState
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_WeaponState( const char *statename, int blendFrames ) {
|
|
const function_t *func;
|
|
|
|
func = scriptObject.GetFunction( statename );
|
|
if ( !func ) {
|
|
gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() );
|
|
}
|
|
|
|
idealState = statename;
|
|
animBlendFrames = blendFrames;
|
|
thread->DoneProcessing();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_WeaponReady
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_WeaponReady( void ) {
|
|
status = WP_READY;
|
|
WEAPON_RAISEWEAPON = false;
|
|
|
|
//HUMANHEAD bjk PCF (4-27-06) - no setting unnecessary weapon state
|
|
//WEAPON_LOWERWEAPON = false;
|
|
//WEAPON_ASIDEWEAPON = false;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_WeaponOutOfAmmo
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_WeaponOutOfAmmo( void ) {
|
|
status = WP_OUTOFAMMO;
|
|
WEAPON_RAISEWEAPON = false;
|
|
|
|
//HUMANHEAD bjk PCF (4-27-06) - no setting unnecessary weapon state
|
|
//WEAPON_LOWERWEAPON = false;
|
|
//WEAPON_ASIDEWEAPON = false;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_WeaponReloading
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_WeaponReloading( void ) {
|
|
status = WP_RELOAD;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_WeaponHolstered
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_WeaponHolstered( void ) {
|
|
status = WP_HOLSTERED;
|
|
WEAPON_LOWERWEAPON = false;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_WeaponRising
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_WeaponRising( void ) {
|
|
status = WP_RISING;
|
|
WEAPON_LOWERWEAPON = false;
|
|
|
|
//HUMANHEAD bjk PCF (4-27-06) - no setting unnecessary weapon state
|
|
//WEAPON_ASIDEWEAPON = false;
|
|
|
|
owner->WeaponRisingCallback();
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_WeaponAside
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_Weapon_Aside( void ) {
|
|
status = WP_ASIDE;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_Weapon_PuttingAside
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_Weapon_PuttingAside( void ) {
|
|
status = WP_PUTTING_ASIDE;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_Weapon_Uprighting
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_Weapon_Uprighting( void ) {
|
|
status = WP_UPRIGHTING;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_WeaponLowering
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_WeaponLowering( void ) {
|
|
status = WP_LOWERING;
|
|
WEAPON_RAISEWEAPON = false;
|
|
|
|
//HUMANHEAD: aob
|
|
WEAPON_ASIDEWEAPON = false;
|
|
//HUMANHEAD END
|
|
|
|
owner->WeaponLoweringCallback();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_AddToClip
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_AddToClip( int amount ) {
|
|
if( fireController ) {
|
|
fireController->AddToClip( amount );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_AmmoInClip
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_AmmoInClip( void ) {
|
|
int ammo = AmmoInClip();
|
|
idThread::ReturnFloat( ammo );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_AmmoAvailable
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_AmmoAvailable( void ) {
|
|
int ammoAvail = AmmoAvailable();
|
|
idThread::ReturnFloat( ammoAvail );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_ClipSize
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_ClipSize( void ) {
|
|
idThread::ReturnFloat( ClipSize() );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_PlayAnim
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_PlayAnim( int channel, const char *animname ) {
|
|
int anim = 0;
|
|
|
|
anim = GetAnimator()->GetAnim( animname );
|
|
if ( !anim ) {
|
|
//HUMANHEAD: aob
|
|
WEAPON_DEBUG( "missing '%s' animation on '%s'", animname, name.c_str() );
|
|
//HUMANHEAD END
|
|
GetAnimator()->Clear( channel, gameLocal.GetTime(), FRAME2MS( animBlendFrames ) );
|
|
animDoneTime = 0;
|
|
} else {
|
|
//Show(); AOB - removed so we can use hidden weapons Hope this doesn't fuck to many things
|
|
GetAnimator()->PlayAnim( channel, anim, gameLocal.GetTime(), FRAME2MS( animBlendFrames ) );
|
|
animDoneTime = GetAnimator()->CurrentAnim( channel )->GetEndTime();
|
|
if ( worldModel.GetEntity() ) {
|
|
anim = worldModel.GetEntity()->GetAnimator()->GetAnim( animname );
|
|
if ( anim ) {
|
|
worldModel.GetEntity()->GetAnimator()->PlayAnim( channel, anim, gameLocal.GetTime(), FRAME2MS( animBlendFrames ) );
|
|
}
|
|
}
|
|
}
|
|
animBlendFrames = 0;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_AnimDone
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_AnimDone( int channel, int blendFrames ) {
|
|
if ( animDoneTime - FRAME2MS( blendFrames ) <= gameLocal.time ) {
|
|
idThread::ReturnInt( true );
|
|
} else {
|
|
idThread::ReturnInt( false );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Event_Next
|
|
================
|
|
*/
|
|
void hhWeapon::Event_Next( void ) {
|
|
// change to another weapon if possible
|
|
owner->NextBestWeapon();
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Event_Flashlight
|
|
================
|
|
*/
|
|
void hhWeapon::Event_Flashlight( int enable ) {
|
|
/*
|
|
if ( enable ) {
|
|
lightOn = true;
|
|
MuzzleFlashLight();
|
|
} else {
|
|
lightOn = false;
|
|
muzzleFlashEnd = 0;
|
|
}
|
|
*/
|
|
}
|
|
/*
|
|
================
|
|
hhWeapon::Event_FireProjectiles
|
|
|
|
HUMANHEAD: aob
|
|
================
|
|
*/
|
|
void hhWeapon::Event_FireProjectiles() {
|
|
//HUMANHEAD: aob - moved logic to this helper function
|
|
LaunchProjectiles( fireController );
|
|
//HUMANHEAD END
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Event_GetOwner
|
|
================
|
|
*/
|
|
void hhWeapon::Event_GetOwner( void ) {
|
|
idThread::ReturnEntity( owner.GetEntity() );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_UseAmmo
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_UseAmmo( int amount ) {
|
|
UseAmmo();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_UseAltAmmo
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_UseAltAmmo( int amount ) {
|
|
UseAltAmmo();
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::RestoreGUI
|
|
|
|
HUMANHEAD: aob
|
|
================
|
|
*/
|
|
void hhWeapon::RestoreGUI( const char* guiKey, idUserInterface** gui ) {
|
|
if( guiKey && guiKey[0] && gui ) {
|
|
AddRenderGui( dict->GetString(guiKey), gui, dict );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Think
|
|
================
|
|
*/
|
|
void hhWeapon::Think() {
|
|
if( thinkFlags & TH_TICKER ) {
|
|
if (owner.IsValid()) {
|
|
Ticker();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::SpawnWorldModel
|
|
================
|
|
*/
|
|
idEntity* hhWeapon::SpawnWorldModel( const char* worldModelDict, idActor* _owner ) {
|
|
/*
|
|
assert( _owner && worldModelDict );
|
|
|
|
idEntity* pEntity = NULL;
|
|
idDict* pArgs = declManager->FindEntityDefDict( worldModelDict, false );
|
|
if( !pArgs ) { return NULL; }
|
|
|
|
idStr ownerWeaponBindBone = _owner->spawnArgs.GetString( "bone_weapon_bind" );
|
|
idStr attachBone = pArgs->GetString( "attach" );
|
|
if( attachBone.Length() && ownerWeaponBindBone.Length() ) {
|
|
pEntity = gameLocal.SpawnEntityType( idEntity::Type, pArgs );
|
|
HH_ASSERT( pEntity );
|
|
|
|
pEntity->GetPhysics()->SetContents( 0 );
|
|
pEntity->GetPhysics()->DisableClip();
|
|
pEntity->MoveJointToJoint( attachBone.c_str(), _owner, ownerWeaponBindBone.c_str() );
|
|
pEntity->AlignJointToJoint( attachBone.c_str(), _owner, ownerWeaponBindBone.c_str() );
|
|
pEntity->BindToJoint( _owner, ownerWeaponBindBone.c_str(), true );
|
|
|
|
// supress model in player views and in any views on the weapon itself
|
|
pEntity->renderEntity.suppressSurfaceInViewID = _owner->entityNumber + 1;
|
|
}
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::SetModel
|
|
================
|
|
*/
|
|
void hhWeapon::SetModel( const char *modelname ) {
|
|
assert( modelname );
|
|
|
|
if ( modelDefHandle >= 0 ) {
|
|
gameRenderWorld->RemoveDecals( modelDefHandle );
|
|
}
|
|
|
|
hhAnimatedEntity::SetModel( modelname );
|
|
|
|
// hide the model until an animation is played
|
|
Hide();
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::FreeModelDef
|
|
================
|
|
*/
|
|
void hhWeapon::FreeModelDef() {
|
|
hhAnimatedEntity::FreeModelDef();
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::GetPhysicsToVisualTransform
|
|
================
|
|
*/
|
|
bool hhWeapon::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
|
|
bool bResult = hhAnimatedEntity::GetPhysicsToVisualTransform( origin, axis );
|
|
|
|
assert(!FLOAT_IS_NAN(cameraShakeOffset.x));
|
|
assert(!FLOAT_IS_NAN(cameraShakeOffset.y));
|
|
assert(!FLOAT_IS_NAN(cameraShakeOffset.z));
|
|
|
|
if( !cameraShakeOffset.Compare(vec3_zero, VECTOR_EPSILON) ) {
|
|
origin = (bResult) ? cameraShakeOffset + origin : cameraShakeOffset;
|
|
origin *= GetPhysics()->GetAxis().Transpose();
|
|
if( !bResult ) { axis = mat3_identity; }
|
|
return true;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::GetMasterDefaultPosition
|
|
================
|
|
*/
|
|
void hhWeapon::GetMasterDefaultPosition( idVec3 &masterOrigin, idMat3 &masterAxis ) const {
|
|
idActor* actor = NULL;
|
|
idEntity* master = GetBindMaster();
|
|
|
|
if( master ) {
|
|
if( master->IsType(idActor::Type) ) {
|
|
actor = static_cast<idActor*>( master );
|
|
actor->DetermineOwnerPosition( masterOrigin, masterAxis );
|
|
|
|
masterOrigin = actor->ApplyLandDeflect( masterOrigin, 1.1f );
|
|
} else {
|
|
hhAnimatedEntity::GetMasterDefaultPosition( masterOrigin, masterAxis );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::SetShaderParm
|
|
================
|
|
*/
|
|
void hhWeapon::SetShaderParm( int parmnum, float value ) {
|
|
hhAnimatedEntity::SetShaderParm(parmnum, value);
|
|
if ( worldModel.IsValid() ) {
|
|
worldModel->SetShaderParm(parmnum, value);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::SetSkin
|
|
================
|
|
*/
|
|
void hhWeapon::SetSkin( const idDeclSkin *skin ) {
|
|
hhAnimatedEntity::SetSkin(skin);
|
|
if ( worldModel.IsValid() ) {
|
|
worldModel->SetSkin(skin);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::PlayCycle
|
|
================
|
|
*/
|
|
void hhWeapon::Event_PlayCycle( int channel, const char *animname ) {
|
|
int anim;
|
|
|
|
anim = GetAnimator()->GetAnim( animname );
|
|
if ( !anim ) {
|
|
//HUMANHEAD: aob
|
|
WEAPON_DEBUG( "missing '%s' animation on '%s'", animname, name.c_str() );
|
|
//HUMANHEAD END
|
|
GetAnimator()->Clear( channel, gameLocal.GetTime(), FRAME2MS( animBlendFrames ) );
|
|
animDoneTime = 0;
|
|
} else {
|
|
//Show();AOB - removed so we can use hidden weapons Hope this doesn't fuck to many things
|
|
|
|
// NLANOTE - Used to be CARandom
|
|
GetAnimator()->CycleAnim( channel, anim, gameLocal.GetTime(), FRAME2MS( animBlendFrames ) );
|
|
animDoneTime = GetAnimator()->CurrentAnim( channel )->GetEndTime();
|
|
if ( worldModel.GetEntity() ) {
|
|
anim = worldModel.GetEntity()->GetAnimator()->GetAnim( animname );
|
|
// NLANOTE - Used to be CARandom
|
|
worldModel.GetEntity()->GetAnimator()->CycleAnim( channel, anim, gameLocal.GetTime(), FRAME2MS( animBlendFrames ) );
|
|
}
|
|
}
|
|
animBlendFrames = 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Event_IsAnimPlaying
|
|
================
|
|
*/
|
|
void hhWeapon::Event_IsAnimPlaying( const char *animname ) {
|
|
idThread::ReturnInt( animator.IsAnimPlaying(animname) );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Event_EjectBrass
|
|
================
|
|
*/
|
|
void hhWeapon::Event_EjectBrass() {
|
|
if( fireController ) {
|
|
fireController->EjectBrass();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Event_EjectAltBrass
|
|
================
|
|
*/
|
|
void hhWeapon::Event_EjectAltBrass() {
|
|
if( altFireController ) {
|
|
altFireController->EjectBrass();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Event_PlayAnimWhenReady
|
|
================
|
|
*/
|
|
void hhWeapon::Event_PlayAnimWhenReady( const char* animName ) {
|
|
/*
|
|
if( !IsReady() && (!dict || !dict->GetBool("pickupHasRaise") || !IsRaising()) ) {
|
|
CancelEvents( &EV_PlayAnimWhenReady );
|
|
PostEventSec( &EV_PlayAnimWhenReady, 0.5f, animName );
|
|
return;
|
|
}
|
|
|
|
PlayAnim( animName, 0, &EV_Weapon_Ready );
|
|
*/
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::Event_SpawnFXAlongBone
|
|
================
|
|
*/
|
|
void hhWeapon::Event_SpawnFXAlongBone( idList<idStr>* fxParms ) {
|
|
if ( !owner->CanShowWeaponViewmodel() || !fxParms ) {
|
|
return;
|
|
}
|
|
|
|
HH_ASSERT( fxParms->Num() == 2 );
|
|
|
|
hhFxInfo fxInfo;
|
|
fxInfo.UseWeaponDepthHack( true );
|
|
BroadcastFxInfoAlongBone( dict->GetString((*fxParms)[0].c_str()), (*fxParms)[1].c_str(), &fxInfo, NULL, false ); //rww - default to not broadcast from events
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::Event_FireAltProjectiles
|
|
==============================
|
|
*/
|
|
void hhWeapon::Event_FireAltProjectiles() {
|
|
LaunchProjectiles( altFireController );
|
|
}
|
|
|
|
// This is called once per frame to precompute where the weapon is pointing. This is used for determining if crosshairs should display as targetted as
|
|
// well as fire controllers to update themselves. This must be called before UpdateCrosshairs().
|
|
void hhWeapon::PrecomputeTraceInfo() {
|
|
// This is needed for fireControllers, even if there are no crosshairs
|
|
idVec3 eyePos = owner->GetEyePosition();
|
|
idMat3 weaponAxis = GetAxis();
|
|
float traceDist = 1024.0f; // was CM_MAX_TRACE_DIST
|
|
|
|
// Perform eye trace
|
|
gameLocal.clip.TracePoint( eyeTraceInfo, eyePos, eyePos + weaponAxis[0] * traceDist,
|
|
MASK_SHOT_BOUNDINGBOX | CONTENTS_GAME_PORTAL, owner.GetEntity() );
|
|
|
|
// CJR: If the trace hit a portal, then force it to trace the max distance, as if it's tracing through the portal
|
|
if ( eyeTraceInfo.fraction < 1.0f ) {
|
|
idEntity *ent = gameLocal.GetTraceEntity( eyeTraceInfo );
|
|
if ( ent->IsType( hhPortal::Type ) ) {
|
|
eyeTraceInfo.endpos = eyePos + weaponAxis[0] * traceDist;
|
|
eyeTraceInfo.fraction = 1.0f;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::UpdateCrosshairs
|
|
==============================
|
|
*/
|
|
void hhWeapon::UpdateCrosshairs( bool &crosshair, bool &targeting ) {
|
|
idEntity* ent = NULL;
|
|
trace_t traceInfo;
|
|
|
|
crosshair = false;
|
|
targeting = false;
|
|
if (spawnArgs.GetBool("altModeWeapon")) {
|
|
if (WEAPON_ALTMODE) { // Moded weapon in alt-mode
|
|
if (altFireController) {
|
|
crosshair = altFireController->UsesCrosshair();
|
|
}
|
|
}
|
|
else { // Moded weapon in normal mode
|
|
if (fireController) {
|
|
crosshair = fireController->UsesCrosshair();
|
|
}
|
|
}
|
|
}
|
|
else { // Normal non-moded weapon
|
|
if (altFireController && altFireController->UsesCrosshair()) {
|
|
crosshair = true;
|
|
}
|
|
if (fireController && fireController->UsesCrosshair()) {
|
|
crosshair = true;
|
|
}
|
|
}
|
|
|
|
ent = NULL;
|
|
if( crosshair ) {
|
|
traceInfo = GetEyeTraceInfo();
|
|
if( traceInfo.fraction < 1.0f ) {
|
|
ent = gameLocal.GetTraceEntity(traceInfo);
|
|
}
|
|
targeting = ( ent && ent->fl.takedamage && !(ent->IsType( hhDoor::Type ) || ent->IsType( hhModelDoor::Type ) || ent->IsType( hhConsole::Type ) ) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::GetAmmoType
|
|
==============================
|
|
*/
|
|
ammo_t hhWeapon::GetAmmoType( void ) const {
|
|
return (fireController) ? fireController->GetAmmoType() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::AmmoAvailable
|
|
==============================
|
|
*/
|
|
int hhWeapon::AmmoAvailable( void ) const {
|
|
return (fireController) ? fireController->AmmoAvailable() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::AmmoInClip
|
|
==============================
|
|
*/
|
|
int hhWeapon::AmmoInClip( void ) const {
|
|
return (fireController) ? fireController->AmmoInClip() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::ClipSize
|
|
==============================
|
|
*/
|
|
int hhWeapon::ClipSize( void ) const {
|
|
return (fireController) ? fireController->ClipSize() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::AmmoRequired
|
|
==============================
|
|
*/
|
|
int hhWeapon::AmmoRequired( void ) const {
|
|
return (fireController) ? fireController->AmmoRequired() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::LowAmmo
|
|
==============================
|
|
*/
|
|
int hhWeapon::LowAmmo() {
|
|
return (fireController) ? fireController->LowAmmo() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::GetAltAmmoType
|
|
==============================
|
|
*/
|
|
ammo_t hhWeapon::GetAltAmmoType( void ) const {
|
|
return (altFireController) ? altFireController->GetAmmoType() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::AltAmmoAvailable
|
|
==============================
|
|
*/
|
|
int hhWeapon::AltAmmoAvailable( void ) const {
|
|
return (altFireController) ? altFireController->AmmoAvailable() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::AltAmmoInClip
|
|
==============================
|
|
*/
|
|
int hhWeapon::AltAmmoInClip( void ) const {
|
|
return (altFireController) ? altFireController->AmmoInClip() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::AltClipSize
|
|
==============================
|
|
*/
|
|
int hhWeapon::AltClipSize( void ) const {
|
|
return (altFireController) ? altFireController->ClipSize() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::AltAmmoRequired
|
|
==============================
|
|
*/
|
|
int hhWeapon::AltAmmoRequired( void ) const {
|
|
return (altFireController) ? altFireController->AmmoRequired() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::LowAltAmmo
|
|
==============================
|
|
*/
|
|
int hhWeapon::LowAltAmmo() {
|
|
return (altFireController) ? altFireController->LowAmmo() : 0;
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::GetAltMode
|
|
HUMANHEAD bjk
|
|
==============================
|
|
*/
|
|
bool hhWeapon::GetAltMode() const {
|
|
return WEAPON_ALTMODE != 0;
|
|
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::UseAmmo
|
|
==============================
|
|
*/
|
|
void hhWeapon::UseAmmo() {
|
|
if (fireController) {
|
|
fireController->UseAmmo();
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::UseAltAmmo
|
|
==============================
|
|
*/
|
|
void hhWeapon::UseAltAmmo() {
|
|
if (altFireController) {
|
|
altFireController->UseAmmo();
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::CheckDeferredProjectiles
|
|
|
|
HUMANEAD: rww
|
|
==============================
|
|
*/
|
|
void hhWeapon::CheckDeferredProjectiles(void) {
|
|
if (fireController) {
|
|
fireController->CheckDeferredProjectiles();
|
|
}
|
|
if (altFireController) {
|
|
altFireController->CheckDeferredProjectiles();
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::LaunchProjectiles
|
|
|
|
HUMANEAD: aob
|
|
==============================
|
|
*/
|
|
void hhWeapon::LaunchProjectiles( hhWeaponFireController* controller ) {
|
|
if ( IsHidden() ) {
|
|
return;
|
|
}
|
|
|
|
// wake up nearby monsters
|
|
if ( !spawnArgs.GetBool( "silent_fire" ) ) {
|
|
gameLocal.AlertAI( owner.GetEntity() );
|
|
}
|
|
|
|
// set the shader parm to the time of last projectile firing,
|
|
// which the gun material shaders can reference for single shot barrel glows, etc
|
|
SetShaderParm( SHADERPARM_DIVERSITY, gameLocal.random.CRandomFloat() );
|
|
SetShaderParm( SHADERPARM_TIMEOFFSET, -MS2SEC( gameLocal.realClientTime ) );
|
|
|
|
float low = ((float)controller->AmmoAvailable()*controller->AmmoRequired())/controller->LowAmmo();
|
|
|
|
if( !controller->LaunchProjectiles(pushVelocity) ) {
|
|
return;
|
|
}
|
|
|
|
if (!gameLocal.isClient) { //HUMANHEAD rww - let everyone hear this sound, and broadcast it (so don't try to play it for client-projectile weapons)
|
|
if( controller->AmmoAvailable()*controller->AmmoRequired() <= controller->LowAmmo() && low > 1 && spawnArgs.FindKey("snd_lowammo")) {
|
|
StartSound( "snd_lowammo", SND_CHANNEL_ANY, 0, true, NULL );
|
|
}
|
|
}
|
|
|
|
controller->UpdateMuzzleKick();
|
|
|
|
// add the light for the muzzleflash
|
|
controller->MuzzleFlash();
|
|
|
|
//HUMANEHAD: aob
|
|
controller->WeaponFeedback();
|
|
//HUMANHEAD END
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::SetViewAnglesSensitivity
|
|
|
|
HUMANHEAD: aob
|
|
===============
|
|
*/
|
|
void hhWeapon::SetViewAnglesSensitivity( float fov ) {
|
|
if( owner.IsValid() ) {
|
|
owner->SetViewAnglesSensitivity( fov / g_fov.GetFloat() );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::GetDict
|
|
|
|
HUMANHEAD: aob
|
|
===============
|
|
*/
|
|
const idDict* hhWeapon::GetDict( const char* objectname ) {
|
|
return gameLocal.FindEntityDefDict( objectname, false );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::GetFireInfoDict
|
|
|
|
HUMANHEAD: aob
|
|
===============
|
|
*/
|
|
const idDict* hhWeapon::GetFireInfoDict( const char* objectname ) {
|
|
const idDict* dict = GetDict( objectname );
|
|
if( !dict ) {
|
|
return NULL;
|
|
}
|
|
|
|
return gameLocal.FindEntityDefDict( dict->GetString("def_fireInfo"), false );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::GetAltFireInfoDict
|
|
|
|
HUMANHEAD: aob
|
|
===============
|
|
*/
|
|
const idDict* hhWeapon::GetAltFireInfoDict( const char* objectname ) {
|
|
const idDict* dict = GetDict( objectname );
|
|
if( !dict ) {
|
|
return NULL;
|
|
}
|
|
|
|
return gameLocal.FindEntityDefDict( dict->GetString("def_altFireInfo"), false );
|
|
}
|
|
|
|
void hhWeapon::Event_GetString(const char *key) {
|
|
if ( fireController ) {
|
|
idThread::ReturnString( fireController->GetString(key) );
|
|
}
|
|
}
|
|
|
|
void hhWeapon::Event_GetAltString(const char *key) {
|
|
if ( altFireController ) {
|
|
idThread::ReturnString( altFireController->GetString(key) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_AddToAltClip
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_AddToAltClip( int amount ) {
|
|
HH_ASSERT( altFireController );
|
|
|
|
altFireController->AddToClip( amount );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_AmmoInClip
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_AltAmmoInClip( void ) {
|
|
HH_ASSERT( altFireController );
|
|
|
|
idThread::ReturnFloat( altFireController->AmmoInClip() );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_AltAmmoAvailable
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_AltAmmoAvailable( void ) {
|
|
HH_ASSERT( altFireController );
|
|
|
|
idThread::ReturnFloat( altFireController->AmmoAvailable() );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_ClipSize
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_AltClipSize( void ) {
|
|
HH_ASSERT( altFireController );
|
|
|
|
idThread::ReturnFloat( altFireController->ClipSize() );
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::Event_GetFireDelay
|
|
==============================
|
|
*/
|
|
void hhWeapon::Event_GetFireDelay() {
|
|
HH_ASSERT( fireController );
|
|
|
|
idThread::ReturnFloat( fireController->GetFireDelay() );
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::Event_GetAltFireDelay
|
|
==============================
|
|
*/
|
|
void hhWeapon::Event_GetAltFireDelay() {
|
|
HH_ASSERT( altFireController );
|
|
|
|
idThread::ReturnFloat( altFireController->GetFireDelay() );
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::Event_HasAmmo
|
|
==============================
|
|
*/
|
|
void hhWeapon::Event_HasAmmo() {
|
|
idThread::ReturnInt( fireController->HasAmmo() );
|
|
}
|
|
|
|
/*
|
|
==============================
|
|
hhWeapon::Event_HasAltAmmo
|
|
==============================
|
|
*/
|
|
void hhWeapon::Event_HasAltAmmo() {
|
|
idThread::ReturnInt( altFireController->HasAmmo() );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::Event_SetViewAnglesSensitivity
|
|
|
|
HUMANHEAD: aob
|
|
===============
|
|
*/
|
|
void hhWeapon::Event_SetViewAnglesSensitivity( float fov ) {
|
|
SetViewAnglesSensitivity( fov );
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhWeapon::UpdateNozzleFx
|
|
================
|
|
*/
|
|
void hhWeapon::UpdateNozzleFx( void ) {
|
|
|
|
if ( !nozzleFx || !g_projectileLights.GetBool()) {
|
|
return;
|
|
}
|
|
|
|
if ( nozzleJointHandle.view == INVALID_JOINT ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// vent light
|
|
//
|
|
if ( nozzleGlowHandle == -1 ) {
|
|
memset(&nozzleGlow, 0, sizeof(nozzleGlow));
|
|
if ( owner.IsValid() ) {
|
|
nozzleGlow.allowLightInViewID = owner->entityNumber+1;
|
|
}
|
|
nozzleGlow.pointLight = true;
|
|
nozzleGlow.noShadows = true;
|
|
nozzleGlow.lightRadius.x = nozzleGlowRadius;
|
|
nozzleGlow.lightRadius.y = nozzleGlowRadius;
|
|
nozzleGlow.lightRadius.z = nozzleGlowRadius;
|
|
nozzleGlow.shader = nozzleGlowShader;
|
|
GetJointWorldTransform( nozzleJointHandle, nozzleGlow.origin, nozzleGlow.axis );
|
|
|
|
nozzleGlow.origin += nozzleGlowOffset * nozzleGlow.axis;
|
|
nozzleGlowHandle = gameRenderWorld->AddLightDef(&nozzleGlow);
|
|
}
|
|
|
|
GetJointWorldTransform(nozzleJointHandle, nozzleGlow.origin, nozzleGlow.axis );
|
|
nozzleGlow.origin += nozzleGlowOffset * nozzleGlow.axis;
|
|
|
|
nozzleGlow.shaderParms[ SHADERPARM_RED ] = nozzleGlowColor.x;
|
|
nozzleGlow.shaderParms[ SHADERPARM_GREEN ] = nozzleGlowColor.y;
|
|
nozzleGlow.shaderParms[ SHADERPARM_BLUE ] = nozzleGlowColor.z;
|
|
|
|
// Copy parms from the weapon into this light
|
|
for( int i = 4; i < 8; i++ ) {
|
|
nozzleGlow.shaderParms[ i ] = GetRenderEntity()->shaderParms[ i ];
|
|
}
|
|
|
|
gameRenderWorld->UpdateLightDef(nozzleGlowHandle, &nozzleGlow);
|
|
}
|
|
|
|
void hhWeapon::Event_HideWeapon(void) {
|
|
HideWeapon();
|
|
}
|
|
|
|
void hhWeapon::Event_ShowWeapon(void) {
|
|
ShowWeapon();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhWeapon::FillDebugVars
|
|
===============
|
|
*/
|
|
void hhWeapon::FillDebugVars(idDict *args, int page) {
|
|
idStr text;
|
|
|
|
switch(page) {
|
|
case 1:
|
|
args->SetBool("WEAPON_LOWERWEAPON", WEAPON_LOWERWEAPON != 0);
|
|
args->SetBool("WEAPON_RAISEWEAPON", WEAPON_RAISEWEAPON != 0);
|
|
args->SetBool("WEAPON_ASIDEWEAPON", WEAPON_ASIDEWEAPON != 0);
|
|
args->SetBool("WEAPON_ATTACK", WEAPON_ATTACK != 0);
|
|
args->SetBool("WEAPON_ALTATTACK", WEAPON_ALTATTACK != 0);
|
|
args->SetBool("WEAPON_ALTMODE", WEAPON_ALTMODE != 0);
|
|
args->SetBool("WEAPON_RELOAD", WEAPON_RELOAD != 0);
|
|
break;
|
|
}
|
|
}
|