dhewm3-sdk/game/Weapon.cpp
revility 1f82525502 pm_projectileOrigin added
New cvar to enable and disable launching projectiles from the weapon's world model barrel joint and also towards the crosshair's position.  launchfrombarrel must be set to 0 in projectile def files to use.  Done incase a weapon doesn't need it or has issues using it in the future.  none currently do.
2018-10-21 04:31:15 +02:00

5351 lines
150 KiB
C++

/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "sys/platform.h"
#include "framework/DeclEntityDef.h"
#include "framework/DeclSkin.h"
#include "gamesys/SysCvar.h"
#include "ai/AI.h"
#include "Player.h"
#include "Trigger.h"
#include "SmokeParticles.h"
#include "WorldSpawn.h"
#include "Moveable.h"
#include "BrittleFracture.h"
#include "renderer/ModelManager.h"
#include "Weapon.h"
/***********************************************************************
idWeapon
***********************************************************************/
//
// event defs
//
const idEventDef EV_Weapon_Clear( "<clear>" );
const idEventDef EV_Weapon_GetOwner( "getOwner", NULL, 'e' );
const idEventDef EV_Weapon_Next( "nextWeapon" );
const idEventDef EV_Weapon_State( "weaponState", "sd" );
const idEventDef EV_Weapon_UseAmmo( "useAmmo", "d" );
const idEventDef EV_Weapon_AddToClip( "addToClip", "d" );
const idEventDef EV_Weapon_AmmoInClip( "ammoInClip", NULL, 'f' );
const idEventDef EV_Weapon_AmmoAvailable( "ammoAvailable", NULL, 'f' );
const idEventDef EV_Weapon_TotalAmmoCount( "totalAmmoCount", NULL, 'f' );
const idEventDef EV_Weapon_ClipSize( "clipSize", NULL, 'f' );
const idEventDef EV_Weapon_WeaponOutOfAmmo( "weaponOutOfAmmo" );
const idEventDef EV_Weapon_WeaponReady( "weaponReady" );
const idEventDef EV_Weapon_WeaponReloading( "weaponReloading" );
const idEventDef EV_Weapon_WeaponHolstered( "weaponHolstered" );
const idEventDef EV_Weapon_WeaponRising( "weaponRising" );
const idEventDef EV_Weapon_WeaponLowering( "weaponLowering" );
const idEventDef EV_Weapon_Flashlight( "flashlight", "d" );
const idEventDef EV_Weapon_LaunchProjectiles( "launchProjectiles", "dffffdd" ); //ivan last "dd" added
//was: const idEventDef EV_Weapon_CreateProjectile( "createProjectile", NULL, 'e' );
const idEventDef EV_Weapon_CreateProjectile( "createProjectile", "d", 'e' ); //ivan "d" added
const idEventDef EV_Weapon_EjectBrass( "ejectBrass" );
const idEventDef EV_Weapon_Melee( "melee", NULL, 'd' );
const idEventDef EV_Weapon_GetWorldModel( "getWorldModel", NULL, 'e' );
const idEventDef EV_Weapon_AllowDrop( "allowDrop", "d" );
const idEventDef EV_Weapon_AutoReload( "autoReload", NULL, 'f' );
const idEventDef EV_Weapon_NetReload( "netReload" );
const idEventDef EV_Weapon_IsInvisible( "isInvisible", NULL, 'f' );
const idEventDef EV_Weapon_NetEndReload( "netEndReload" );
//rev grab
const idEventDef EV_Weapon_GrabberHasTarget( "grabberHasTarget", NULL, 'd' );
const idEventDef EV_Weapon_Grabber( "grabber", "d" );
const idEventDef EV_Weapon_Grabber_SetGrabDistance( "grabberGrabDistance", "f" );
//rev grab
// New------------------
#ifdef _DENTONMOD
const idEventDef EV_Weapon_ChangeProjectileDef( "changeProjectileDef" , "d", 'f' ); // New
const idEventDef EV_Weapon_GetProjectileType( "getProjectileType", NULL, 'f' );
const idEventDef EV_Weapon_SetZoom( "setZoom" , "d"); // New
const idEventDef EV_Weapon_StartParticle( "startWeaponParticle", "s" );
const idEventDef EV_Weapon_StopParticle( "stopWeaponParticle", "s" );
const idEventDef EV_Weapon_StartWeaponLight( "startWeaponLight", "s" );
const idEventDef EV_Weapon_StopWeaponLight( "stopWeaponLight", "s" );
#endif //_DENTONMOD
//ivan start
const idEventDef EV_Weapon_StartAutoMelee( "startAutoMelee", "fd" );
const idEventDef EV_Weapon_StopAutoMelee( "stopAutoMelee" );
const idEventDef EV_Weapon_StartMeleeBeam( "startMeleeBeam", "d" );
const idEventDef EV_Weapon_StopMeleeBeam( "stopMeleeBeam" );
const idEventDef EV_Weapon_SetWeaponMode( "setWeaponMode", "d" );
const idEventDef EV_Weapon_GetWeaponMode( "getWeaponMode", NULL, 'd' );
//ivan end
//
// class def
//
CLASS_DECLARATION( idAnimatedEntity, idWeapon )
#ifdef _DENTONMOD
EVENT( EV_Weapon_SetZoom, idWeapon::Event_SetZoom ) // New
#endif //_DENTONMOD
EVENT( EV_Weapon_Clear, idWeapon::Event_Clear )
EVENT( EV_Weapon_GetOwner, idWeapon::Event_GetOwner )
EVENT( EV_Weapon_State, idWeapon::Event_WeaponState )
EVENT( EV_Weapon_WeaponReady, idWeapon::Event_WeaponReady )
EVENT( EV_Weapon_WeaponOutOfAmmo, idWeapon::Event_WeaponOutOfAmmo )
EVENT( EV_Weapon_WeaponReloading, idWeapon::Event_WeaponReloading )
EVENT( EV_Weapon_WeaponHolstered, idWeapon::Event_WeaponHolstered )
EVENT( EV_Weapon_WeaponRising, idWeapon::Event_WeaponRising )
EVENT( EV_Weapon_WeaponLowering, idWeapon::Event_WeaponLowering )
EVENT( EV_Weapon_UseAmmo, idWeapon::Event_UseAmmo )
EVENT( EV_Weapon_AddToClip, idWeapon::Event_AddToClip )
EVENT( EV_Weapon_AmmoInClip, idWeapon::Event_AmmoInClip )
EVENT( EV_Weapon_AmmoAvailable, idWeapon::Event_AmmoAvailable )
EVENT( EV_Weapon_TotalAmmoCount, idWeapon::Event_TotalAmmoCount )
EVENT( EV_Weapon_ClipSize, idWeapon::Event_ClipSize )
EVENT( AI_PlayAnim, idWeapon::Event_PlayAnim )
EVENT( AI_PlayCycle, idWeapon::Event_PlayCycle )
EVENT( AI_SetBlendFrames, idWeapon::Event_SetBlendFrames )
EVENT( AI_GetBlendFrames, idWeapon::Event_GetBlendFrames )
EVENT( AI_AnimDone, idWeapon::Event_AnimDone )
EVENT( EV_Weapon_Next, idWeapon::Event_Next )
EVENT( EV_SetSkin, idWeapon::Event_SetSkin )
EVENT( EV_Weapon_Flashlight, idWeapon::Event_Flashlight )
EVENT( EV_Light_GetLightParm, idWeapon::Event_GetLightParm )
EVENT( EV_Light_SetLightParm, idWeapon::Event_SetLightParm )
EVENT( EV_Light_SetLightParms, idWeapon::Event_SetLightParms )
EVENT( EV_Weapon_LaunchProjectiles, idWeapon::Event_LaunchProjectiles )
EVENT( EV_Weapon_CreateProjectile, idWeapon::Event_CreateProjectile )
EVENT( EV_Weapon_EjectBrass, idWeapon::Event_EjectBrass )
EVENT( EV_Weapon_Melee, idWeapon::Event_Melee )
EVENT( EV_Weapon_GetWorldModel, idWeapon::Event_GetWorldModel )
EVENT( EV_Weapon_AllowDrop, idWeapon::Event_AllowDrop )
EVENT( EV_Weapon_AutoReload, idWeapon::Event_AutoReload )
EVENT( EV_Weapon_NetReload, idWeapon::Event_NetReload )
EVENT( EV_Weapon_IsInvisible, idWeapon::Event_IsInvisible )
EVENT( EV_Weapon_NetEndReload, idWeapon::Event_NetEndReload )
//rev grab
EVENT( EV_Weapon_Grabber, idWeapon::Event_Grabber )
EVENT( EV_Weapon_GrabberHasTarget, idWeapon::Event_GrabberHasTarget )
EVENT( EV_Weapon_Grabber_SetGrabDistance, idWeapon::Event_GrabberSetGrabDistance )
//rev grab
#ifdef _DENTONMOD
EVENT( EV_Weapon_ChangeProjectileDef, idWeapon::Event_ChangeProjectileDef ) // New
EVENT( EV_Weapon_GetProjectileType, idWeapon::Event_GetProjectileType ) // New
EVENT( EV_Weapon_StartParticle, idWeapon::Event_StartWeaponParticle ) // All Four New
EVENT( EV_Weapon_StopParticle, idWeapon::Event_StopWeaponParticle )
EVENT( EV_Weapon_StartWeaponLight, idWeapon::Event_StartWeaponLight )
EVENT( EV_Weapon_StopWeaponLight, idWeapon::Event_StopWeaponLight )
#endif // _DENTONMOD
//ivan start
EVENT( EV_Weapon_StartAutoMelee, idWeapon::Event_StartAutoMelee )
EVENT( EV_Weapon_StopAutoMelee, idWeapon::Event_StopAutoMelee )
//EVENT( EV_Weapon_StartMeleeBeam, idWeapon::Event_StartMeleeBeam )
//EVENT( EV_Weapon_StopMeleeBeam, idWeapon::Event_StopMeleeBeam )
EVENT( EV_Weapon_SetWeaponMode, idWeapon::Event_SetWeaponMode )
EVENT( EV_Weapon_GetWeaponMode, idWeapon::Event_GetWeaponMode )
//ivan end
END_CLASS
/***********************************************************************
init
***********************************************************************/
/*
================
idWeapon::idWeapon()
================
*/
idWeapon::idWeapon() {
owner = NULL;
//worldModel = NULL;
weaponDef = NULL;
thread = NULL;
//memset( &guiLight, 0, sizeof( guiLight ) );
//memset( &muzzleFlash, 0, sizeof( muzzleFlash ) );
memset( &worldMuzzleFlash, 0, sizeof( worldMuzzleFlash ) );
memset( &nozzleGlow, 0, sizeof( nozzleGlow ) );
muzzleFlashEnd = 0;
flashColor = vec3_origin;
//muzzleFlashHandle = -1;
worldMuzzleFlashHandle = -1;
//guiLightHandle = -1;
nozzleGlowHandle = -1;
modelDefHandle = -1;
//REV GRAB START
grabberState = -1;
//REV GRAB END
berserk = 2;
brassDelay = 0;
allowDrop = true;
//ivan start
#ifdef TRAIL_FX_CHAIN
//done in Clear()
#else
trailGen = NULL;
#endif
//ivan end
Clear();
fl.networkSync = true;
projectileOrigin = 1; //rev 2018
}
/*
================
idWeapon::~idWeapon()
================
*/
idWeapon::~idWeapon() {
Clear();
//delete worldModel.GetEntity();
//ivan start
#ifdef TRAIL_FX_CHAIN
//no need to delete lastBeamInChain
#else
//this is not strictly necessary because weapon is only deallocated at map end... and that's when trailsManager would do this for me.
gameLocal.trailsManager->RemoveTrailGen( trailGen );
#endif
//ivan start
}
/*
================
idWeapon::Spawn
================
*/
void idWeapon::Spawn( void ) {
//if ( !gameLocal.isClient ) {
// // setup the world model
// worldModel = static_cast< idAnimatedEntity * >( gameLocal.SpawnEntityType( idAnimatedEntity::Type, NULL ) );
// worldModel.GetEntity()->fl.networkSync = true;
//}
//REV GRAB
if ( 1 /*!gameLocal.isMultiplayer*/ ) {
grabber.Initialize();
}
//REV GRAB
thread = new idThread();
thread->ManualDelete();
thread->ManualControl();
//ivan start
#ifdef TRAIL_FX_CHAIN
//nothing to spawn for beams. lastBeamInChain is already null.
#else
//this is spawned once at player spawn and then it is always there.
if(!trailGen){
trailGen = gameLocal.trailsManager->NewTrailGen();
}
#endif
//ivan end
}
/*
================
idWeapon::SetOwner
Only called at player spawn time, not each weapon switch
================
*/
void idWeapon::SetOwner( idPlayer *_owner ) {
assert( !owner );
owner = _owner;
SetName( va( "%s_weapon", owner->name.c_str() ) );
/*if ( worldModel.GetEntity() ) {
worldModel.GetEntity()->SetName( va( "%s_weapon_worldmodel", owner->name.c_str() ) );
}*/
}
/*
================
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 idWeapon::ShouldConstructScriptObjectAtSpawn( void ) const {
return false;
}
/*
================
idWeapon::CacheWeapon
================
*/
void idWeapon::CacheWeapon( const char *weaponName ) {
const idDeclEntityDef *weaponDef;
const char *brassDefName;
const char *clipModelName;
idTraceModel trm;
const char *guiName;
weaponDef = gameLocal.FindEntityDef( weaponName, false );
if ( !weaponDef ) {
return;
}
// precache the brass collision model
brassDefName = weaponDef->dict.GetString( "def_ejectBrass" );
if ( brassDefName[0] ) {
const idDeclEntityDef *brassDef = gameLocal.FindEntityDef( brassDefName, false );
if ( brassDef ) {
brassDef->dict.GetString( "clipmodel", "", &clipModelName );
if ( !clipModelName[0] ) {
clipModelName = brassDef->dict.GetString( "model" ); // use the visual model
}
// load the trace model
collisionModelManager->TrmFromModel( clipModelName, trm );
}
}
guiName = weaponDef->dict.GetString( "gui" );
if ( guiName[0] ) {
uiManager->FindGui( guiName, true, false, true );
}
}
/*
================
idWeapon::Save
================
*/
void idWeapon::Save( idSaveGame *savefile ) const {
savefile->WriteInt( status );
savefile->WriteObject( thread );
savefile->WriteString( state );
savefile->WriteString( idealState );
savefile->WriteInt( animBlendFrames );
savefile->WriteInt( animDoneTime );
savefile->WriteInt( lastFiredTime ); //ivan
savefile->WriteBool( isLinked );
savefile->WriteObject( owner );
//worldModel.Save( savefile );
savefile->WriteInt( hideTime );
savefile->WriteFloat( hideDistance );
savefile->WriteInt( hideStartTime );
savefile->WriteFloat( hideStart );
savefile->WriteFloat( hideEnd );
//savefile->WriteFloat( hideOffset );
savefile->WriteBool( hide );
savefile->WriteBool( disabled );
savefile->WriteInt( berserk );
savefile->WriteVec3( playerViewOrigin );
savefile->WriteMat3( playerViewAxis );
/*
savefile->WriteVec3( viewWeaponOrigin );
savefile->WriteMat3( viewWeaponAxis );
*/
savefile->WriteVec3( muzzleOrigin );
savefile->WriteMat3( muzzleAxis );
savefile->WriteVec3( pushVelocity );
savefile->WriteString( weaponDef->GetName() );
savefile->WriteFloat( meleeDistance );
savefile->WriteString( meleeDefName );
savefile->WriteInt( brassDelay );
savefile->WriteString( icon );
/*
savefile->WriteInt( guiLightHandle );
savefile->WriteRenderLight( guiLight );
savefile->WriteInt( muzzleFlashHandle );
savefile->WriteRenderLight( muzzleFlash );
*/
savefile->WriteInt( worldMuzzleFlashHandle );
savefile->WriteRenderLight( worldMuzzleFlash );
savefile->WriteVec3( flashColor );
savefile->WriteInt( muzzleFlashEnd );
savefile->WriteInt( flashTime );
savefile->WriteBool( lightOn );
savefile->WriteBool( silent_fire );
/*
savefile->WriteInt( kick_endtime );
savefile->WriteInt( muzzle_kick_time );
savefile->WriteInt( muzzle_kick_maxtime );
savefile->WriteAngles( muzzle_kick_angles );
savefile->WriteVec3( muzzle_kick_offset );
*/
savefile->WriteInt( ammoType );
savefile->WriteInt( ammoRequired );
savefile->WriteInt( clipSize );
savefile->WriteInt( ammoClip );
savefile->WriteInt( lowAmmo );
savefile->WriteBool( powerAmmo );
// savegames <= 17
savefile->WriteInt( 0 );
savefile->WriteInt( zoomFov );
/*
savefile->WriteJoint( barrelJointView );
savefile->WriteJoint( flashJointView );
savefile->WriteJoint( ejectJointView );
savefile->WriteJoint( guiLightJointView );
savefile->WriteJoint( ventLightJointView );
*/
savefile->WriteJoint( flashJointWorld );
savefile->WriteJoint( barrelJointWorld );
savefile->WriteJoint( ejectJointWorld );
savefile->WriteJoint( meleeJointWorld ); //ivan
//ivan start
savefile->WriteBool( autoMeleeEnabled );
savefile->WriteBool( useMeleeBox );
savefile->WriteFloat( comboMultiplier );
savefile->WriteFloat( firingWalkSpeedMult );
savefile->WriteBounds( meleebox );
savefile->WriteInt( trailNumType );
#ifdef TRAIL_FX_CHAIN
lastBeamInChain.Save( savefile );
#else
//trailGen is saved elsewhere. Here we save only the id to retrieve it later
savefile->WriteInt( gameLocal.trailsManager->GetSafeUniqueId( trailGen ) );
#endif
savefile->WriteInt( trailLowOffset );
savefile->WriteInt( trailHighOffset );
//spread
savefile->WriteFloat( dynamicSpreadValue );
savefile->WriteFloat( spreadBaseValue );
savefile->WriteFloat( spreadVelocityFactor );
savefile->WriteFloat( spreadCrouchFactor );
savefile->WriteFloat( spreadCrouchFactor );
//ivan end
savefile->WriteBool( hasBloodSplat );
savefile->WriteSoundShader( sndHum );
savefile->WriteParticle( weaponSmoke );
savefile->WriteInt( weaponSmokeStartTime );
savefile->WriteBool( continuousSmoke );
savefile->WriteParticle( strikeSmoke );
savefile->WriteInt( strikeSmokeStartTime );
savefile->WriteVec3( strikePos );
savefile->WriteMat3( strikeAxis );
savefile->WriteInt( nextStrikeFx );
savefile->WriteInt( nextMeleeSnd ); //ivan
savefile->WriteBool( nozzleFx );
savefile->WriteInt( nozzleFxFade );
savefile->WriteInt( lastAttack );
savefile->WriteInt( nozzleGlowHandle );
savefile->WriteRenderLight( nozzleGlow );
savefile->WriteVec3( nozzleGlowColor );
savefile->WriteMaterial( nozzleGlowShader );
savefile->WriteFloat( nozzleGlowRadius );
savefile->WriteInt( weaponAngleOffsetAverages );
savefile->WriteFloat( weaponAngleOffsetScale );
savefile->WriteFloat( weaponAngleOffsetMax );
savefile->WriteFloat( weaponOffsetTime );
savefile->WriteFloat( weaponOffsetScale );
savefile->WriteBool( allowDrop );
savefile->WriteObject( projectileEnt );
savefile->WriteObject( lastMeleeEnt ); //ivan
//REV GRAB
savefile->WriteStaticObject( grabber );
savefile->WriteInt( grabberState );
//REV GRAB
// New----------------------------------------------
#ifdef _DENTONMOD
savefile->WriteInt(weaponParticles.Num());
for(int i = 0; i < weaponParticles.Num(); i++) {
WeaponParticle_t* part = weaponParticles.GetIndex(i);
particleFlags_s flags = part->particleFlags;
LittleBitField( &flags, sizeof( flags ) );
savefile->Write( &flags, sizeof( flags ) );
savefile->WriteString( part->name );
savefile->WriteString( part->particlename );
savefile->WriteInt( part->startTime );
savefile->WriteJoint( part->joint );
if( !part->particleFlags.isSmoke ) {
savefile->WriteRenderEntity( part->renderEntity );
}
if( part->particleFlags.isDir ) {
savefile->WriteVec3(part->dir);
}
if( part->particleFlags.isOffset ) {
savefile->WriteVec3(part->offset);
}
}
savefile->WriteInt(weaponLights.Num());
for(int i = 0; i < weaponLights.Num(); i++) {
WeaponLight_t* light = weaponLights.GetIndex(i);
lightFlags_s flags = light->lightFlags;
LittleBitField( &flags, sizeof( flags ) );
savefile->Write( &flags, sizeof( flags ) );
savefile->WriteString( light->name );
savefile->WriteInt( light->startTime );
savefile->WriteJoint( light->joint );
savefile->WriteInt( light->lightHandle );
savefile->WriteRenderLight( light->light );
if( !light->lightFlags.isAlwaysOn ) {
savefile->WriteInt( light->endTime );
}
if( light->lightFlags.isDir ) {
savefile->WriteVec3(light->dir);
}
if( light->lightFlags.isOffset ) {
savefile->WriteVec3(light->offset);
}
}
#endif// _DENTONMOD
//ivan start
savefile->WriteInt( maxAmmo );
savefile->WriteInt( spreadMode );
//ivan end
}
/*
================
idWeapon::Restore
================
*/
void idWeapon::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 );
savefile->ReadInt( lastFiredTime ); //ivan
savefile->ReadBool( isLinked );
// Re-link script fields
WEAPON_ATTACK.LinkTo( scriptObject, "WEAPON_ATTACK" );
WEAPON_SPECIAL.LinkTo( scriptObject, "WEAPON_SPECIAL" ); // New
WEAPON_SPECIAL_HOLD.LinkTo( scriptObject, "WEAPON_SPECIAL_HOLD" ); //
WEAPON_RELOAD.LinkTo( scriptObject, "WEAPON_RELOAD" );
WEAPON_NETRELOAD.LinkTo( scriptObject, "WEAPON_NETRELOAD" );
WEAPON_NETENDRELOAD.LinkTo( scriptObject, "WEAPON_NETENDRELOAD" );
WEAPON_NETFIRING.LinkTo( scriptObject, "WEAPON_NETFIRING" );
WEAPON_RAISEWEAPON.LinkTo( scriptObject, "WEAPON_RAISEWEAPON" );
WEAPON_LOWERWEAPON.LinkTo( scriptObject, "WEAPON_LOWERWEAPON" );
savefile->ReadObject( reinterpret_cast<idClass *&>( owner ) );
//worldModel.Restore( savefile );
savefile->ReadInt( hideTime );
savefile->ReadFloat( hideDistance );
savefile->ReadInt( hideStartTime );
savefile->ReadFloat( hideStart );
savefile->ReadFloat( hideEnd );
//savefile->ReadFloat( hideOffset );
savefile->ReadBool( hide );
savefile->ReadBool( disabled );
savefile->ReadInt( berserk );
savefile->ReadVec3( playerViewOrigin );
savefile->ReadMat3( playerViewAxis );
/*
savefile->ReadVec3( viewWeaponOrigin );
savefile->ReadMat3( viewWeaponAxis );
*/
savefile->ReadVec3( muzzleOrigin );
savefile->ReadMat3( muzzleAxis );
savefile->ReadVec3( pushVelocity );
idStr objectname;
savefile->ReadString( objectname );
weaponDef = gameLocal.FindEntityDef( objectname );
meleeDef = gameLocal.FindEntityDef( weaponDef->dict.GetString( "def_melee" ), false );
/* const idDeclEntityDef *projectileDef = gameLocal.FindEntityDef( weaponDef->dict.GetString( "def_projectile" ), false );
if ( projectileDef ) {
projectileDict = projectileDef->dict;
} else {
projectileDict.Clear();
}*/
const idDeclEntityDef *brassDef = gameLocal.FindEntityDef( weaponDef->dict.GetString( "def_ejectBrass" ), false );
if ( brassDef ) {
brassDict = brassDef->dict;
} else {
brassDict.Clear();
}
savefile->ReadFloat( meleeDistance );
savefile->ReadString( meleeDefName );
savefile->ReadInt( brassDelay );
savefile->ReadString( icon );
/*
savefile->ReadInt( guiLightHandle );
savefile->ReadRenderLight( guiLight );
savefile->ReadInt( muzzleFlashHandle );
savefile->ReadRenderLight( muzzleFlash );
*/
savefile->ReadInt( worldMuzzleFlashHandle );
savefile->ReadRenderLight( worldMuzzleFlash );
savefile->ReadVec3( flashColor );
savefile->ReadInt( muzzleFlashEnd );
savefile->ReadInt( flashTime );
savefile->ReadBool( lightOn );
savefile->ReadBool( silent_fire );
/*
savefile->ReadInt( kick_endtime );
savefile->ReadInt( muzzle_kick_time );
savefile->ReadInt( muzzle_kick_maxtime );
savefile->ReadAngles( muzzle_kick_angles );
savefile->ReadVec3( muzzle_kick_offset );
*/
savefile->ReadInt( (int &)ammoType );
savefile->ReadInt( ammoRequired );
savefile->ReadInt( clipSize );
savefile->ReadInt( ammoClip );
savefile->ReadInt( lowAmmo );
savefile->ReadBool( powerAmmo );
// savegame versions <= 17
int foo;
savefile->ReadInt( foo );
savefile->ReadInt( zoomFov );
/*
savefile->ReadJoint( barrelJointView );
savefile->ReadJoint( flashJointView );
savefile->ReadJoint( ejectJointView );
savefile->ReadJoint( guiLightJointView );
savefile->ReadJoint( ventLightJointView );
*/
savefile->ReadJoint( flashJointWorld );
savefile->ReadJoint( barrelJointWorld );
savefile->ReadJoint( ejectJointWorld );
savefile->ReadJoint( meleeJointWorld ); //ivan
//ivan start
savefile->ReadBool( autoMeleeEnabled );
savefile->ReadBool( useMeleeBox );
savefile->ReadFloat( comboMultiplier );
savefile->ReadFloat( firingWalkSpeedMult );
savefile->ReadBounds( meleebox );
savefile->ReadInt( trailNumType );
#ifdef TRAIL_FX_CHAIN
lastBeamInChain.Restore( savefile );
#else
int trailId; //trailGen was saved elsewhere. Here we read its id to retrieve it.
savefile->ReadInt( trailId );
trailGen = gameLocal.trailsManager->FindTrailByUniqueId( trailId );
#ifdef TEST_TRAIL
//the test trail was not saved. Create a new one.
//NOTE: the trail object has been correctly restored by the manager, so it's sill there. We just don't know the id.
testGen = NULL;
#endif
#endif
savefile->ReadInt( trailLowOffset );
savefile->ReadInt( trailHighOffset );
//spread
savefile->ReadFloat( dynamicSpreadValue );
savefile->ReadFloat( spreadBaseValue );
savefile->ReadFloat( spreadVelocityFactor );
savefile->ReadFloat( spreadCrouchFactor );
//ivan end
savefile->ReadBool( hasBloodSplat );
savefile->ReadSoundShader( sndHum );
savefile->ReadParticle( weaponSmoke );
savefile->ReadInt( weaponSmokeStartTime );
savefile->ReadBool( continuousSmoke );
savefile->ReadParticle( strikeSmoke );
savefile->ReadInt( strikeSmokeStartTime );
savefile->ReadVec3( strikePos );
savefile->ReadMat3( strikeAxis );
savefile->ReadInt( nextStrikeFx );
savefile->ReadInt( nextMeleeSnd ); //ivan
savefile->ReadBool( nozzleFx );
savefile->ReadInt( nozzleFxFade );
savefile->ReadInt( lastAttack );
savefile->ReadInt( nozzleGlowHandle );
savefile->ReadRenderLight( nozzleGlow );
savefile->ReadVec3( nozzleGlowColor );
savefile->ReadMaterial( nozzleGlowShader );
savefile->ReadFloat( nozzleGlowRadius );
savefile->ReadInt( weaponAngleOffsetAverages );
savefile->ReadFloat( weaponAngleOffsetScale );
savefile->ReadFloat( weaponAngleOffsetMax );
savefile->ReadFloat( weaponOffsetTime );
savefile->ReadFloat( weaponOffsetScale );
savefile->ReadBool( allowDrop );
savefile->ReadObject( reinterpret_cast<idClass *&>( projectileEnt ) );
savefile->ReadObject( reinterpret_cast<idClass *&>( lastMeleeEnt ) ); //ivan
//REV GRAB
savefile->ReadStaticObject( grabber );
savefile->ReadInt( grabberState );
//REV GRAB
#ifdef _DENTONMOD
if( !ChangeProjectileDef( owner->GetProjectileType() ) ) { // if restore fails we must clear the dict
projectileDict.Clear();
}
//All rest New
int particleCount;
savefile->ReadInt( particleCount );
for(int i = 0; i < particleCount; i++) {
WeaponParticle_t newParticle;
memset(&newParticle, 0, sizeof(newParticle));
savefile->Read( &newParticle.particleFlags, sizeof( newParticle.particleFlags ) );
LittleBitField( &newParticle.particleFlags, sizeof( newParticle.particleFlags ) );
idStr prtName, particlename;
savefile->ReadString( prtName );
savefile->ReadString( particlename );
strcpy( newParticle.name, prtName.c_str() );
strcpy( newParticle.particlename, particlename.c_str() );
savefile->ReadInt( newParticle.startTime );
savefile->ReadJoint( newParticle.joint );
if(newParticle.particleFlags.isSmoke) {
newParticle.particle = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, particlename, false ) );
}
else {
savefile->ReadRenderEntity( newParticle.renderEntity );
newParticle.modelDefHandle = -1;
}
if( newParticle.particleFlags.isDir ) {
savefile->ReadVec3( newParticle.dir );
}
if( newParticle.particleFlags.isOffset ) {
savefile->ReadVec3( newParticle.offset );
}
weaponParticles.Set(newParticle.name, newParticle);
}
int lightCount;
savefile->ReadInt( lightCount );
for(int i = 0; i < lightCount; i++) {
WeaponLight_t newLight;
memset(&newLight, 0, sizeof(newLight));
savefile->Read( &newLight.lightFlags, sizeof( newLight.lightFlags ) );
LittleBitField( &newLight.lightFlags, sizeof( newLight.lightFlags ) );
idStr lightName;
savefile->ReadString( lightName );
strcpy( newLight.name, lightName.c_str() );
savefile->ReadInt( newLight.startTime );
savefile->ReadJoint( newLight.joint );
savefile->ReadInt( newLight.lightHandle );
savefile->ReadRenderLight( newLight.light );
if ( newLight.lightHandle >= 0 ) {
newLight.lightHandle = gameRenderWorld->AddLightDef( &newLight.light );
}
if( !newLight.lightFlags.isAlwaysOn ) {
savefile->ReadInt( newLight.endTime );
}
if( newLight.lightFlags.isDir ) {
savefile->ReadVec3(newLight.dir);
}
if( newLight.lightFlags.isOffset ) {
savefile->ReadVec3(newLight.offset);
}
weaponLights.Set(newLight.name, newLight);
}
#endif //_DENTONMOD
//ivan start
savefile->ReadInt( maxAmmo );
savefile->ReadInt( spreadMode );
//ivan end
}
/***********************************************************************
Weapon definition management
***********************************************************************/
/*
================
idWeapon::Clear
================
*/
void idWeapon::Clear( void ) {
CancelEvents( &EV_Weapon_Clear );
DeconstructScriptObject();
scriptObject.Free();
WEAPON_ATTACK.Unlink();
WEAPON_SPECIAL.Unlink(); //new
WEAPON_SPECIAL_HOLD.Unlink(); //new
WEAPON_RELOAD.Unlink();
WEAPON_NETRELOAD.Unlink();
WEAPON_NETENDRELOAD.Unlink();
WEAPON_NETFIRING.Unlink();
WEAPON_RAISEWEAPON.Unlink();
WEAPON_LOWERWEAPON.Unlink();
/*
if ( muzzleFlashHandle != -1 ) {
gameRenderWorld->FreeLightDef( muzzleFlashHandle );
muzzleFlashHandle = -1;
}
if ( muzzleFlashHandle != -1 ) {
gameRenderWorld->FreeLightDef( muzzleFlashHandle );
muzzleFlashHandle = -1;
}
*/
if ( worldMuzzleFlashHandle != -1 ) {
gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle );
worldMuzzleFlashHandle = -1;
}
/*
if ( guiLightHandle != -1 ) {
gameRenderWorld->FreeLightDef( guiLightHandle );
guiLightHandle = -1;
}
*/
if ( nozzleGlowHandle != -1 ) {
gameRenderWorld->FreeLightDef( nozzleGlowHandle );
nozzleGlowHandle = -1;
}
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;
if ( refSound.referenceSound ) {
refSound.referenceSound->Free( true );
}
memset( &refSound, 0, sizeof( refSound_t ) );
// setting diversity to 0 results in no random sound. -1 indicates random.
refSound.diversity = -1.0f;
if ( owner ) {
// 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_" );
}
hideTime = 300;
hideDistance = -15.0f;
hideStartTime = gameLocal.time - hideTime;
hideStart = 0.0f;
hideEnd = 0.0f;
//hideOffset = 0.0f;
hide = false;
disabled = false;
weaponSmoke = NULL;
weaponSmokeStartTime = 0;
continuousSmoke = false;
strikeSmoke = NULL;
strikeSmokeStartTime = 0;
strikePos.Zero();
strikeAxis = mat3_identity;
nextStrikeFx = 0;
nextMeleeSnd = 0; //ivan
icon = "";
playerViewAxis.Identity();
playerViewOrigin.Zero();
//viewWeaponAxis.Identity();
//viewWeaponOrigin.Zero();
muzzleAxis.Identity();
muzzleOrigin.Zero();
pushVelocity.Zero();
status = WP_HOLSTERED;
state = "";
idealState = "";
animBlendFrames = 0;
animDoneTime = 0;
lastFiredTime = 0; //ivan
projectileDict.Clear();
meleeDef = NULL;
meleeDefName = "";
meleeDistance = 0.0f;
brassDict.Clear();
flashTime = 250;
lightOn = false;
silent_fire = false;
//rev grab
grabberState = -1;
grabber.Update( owner, true );
//rev grab
ammoType = 0;
ammoRequired = 0;
ammoClip = 0;
clipSize = 0;
lowAmmo = 0;
powerAmmo = false;
/*
kick_endtime = 0;
muzzle_kick_time = 0;
muzzle_kick_maxtime = 0;
muzzle_kick_angles.Zero();
muzzle_kick_offset.Zero();
*/
zoomFov = 90;
/*
barrelJointView = INVALID_JOINT;
flashJointView = INVALID_JOINT;
ejectJointView = INVALID_JOINT;
guiLightJointView = INVALID_JOINT;
ventLightJointView = INVALID_JOINT;
*/
barrelJointWorld = INVALID_JOINT;
flashJointWorld = INVALID_JOINT;
ejectJointWorld = INVALID_JOINT;
meleeJointWorld = INVALID_JOINT; //ivan
// ------------------- New Start
#ifdef _DENTONMOD
//Clean up the weapon particles
for(int i = 0; i < weaponParticles.Num(); i++) {
WeaponParticle_t* part = weaponParticles.GetIndex(i);
if(!part->particleFlags.isSmoke) {
if ( part->modelDefHandle >= 0 )
gameRenderWorld->FreeEntityDef( part->modelDefHandle );
}
}
weaponParticles.Clear();
//Clean up the weapon lights
for(int i = 0; i < weaponLights.Num(); i++) {
WeaponLight_t* light = weaponLights.GetIndex(i);
if ( light->lightHandle != -1 ) {
gameRenderWorld->FreeLightDef( light->lightHandle );
}
}
weaponLights.Clear();
//------------------------------------ New End
#endif //_DENTONMOD
hasBloodSplat = false;
nozzleFx = false;
nozzleFxFade = 1500;
lastAttack = 0;
// lastSpecialFunc = 0; // new
nozzleGlowHandle = -1;
nozzleGlowShader = NULL;
nozzleGlowRadius = 10;
nozzleGlowColor.Zero();
weaponAngleOffsetAverages = 0;
weaponAngleOffsetScale = 0.0f;
weaponAngleOffsetMax = 0.0f;
weaponOffsetTime = 0.0f;
weaponOffsetScale = 0.0f;
allowDrop = true;
animator.ClearAllAnims( gameLocal.time, 0 );
FreeModelDef();
sndHum = NULL;
isLinked = false;
projectileEnt = NULL;
//ivan start
lastMeleeEnt = NULL;
isFiring = false;
isSecFiring = false;
autoMeleeEnabled = false;
useMeleeBox = false;
comboMultiplier = 1.0f;
firingWalkSpeedMult = 1.0f;
meleebox.Zero();
trailNumType = TRAIL_NONE;
#ifdef TRAIL_FX_CHAIN
lastBeamInChain = NULL;
#else
//check if trailGen is != null because this is also called by the constructor!
if( trailGen && trailGen->IsEnabled() ){ //this also happens when weapon change. Make sure no trail is going.
trailGen->StopTrail();
}
trailLowOffset = 0;
trailHighOffset = 0;
#endif
//spread
dynamicSpreadValue = 0.0f;
spreadBaseValue = 0.0f;
spreadVelocityFactor = 0.0f;
spreadCrouchFactor = 0.0f;
//ivan end
}
/*
================
idWeapon::InitWorldModel
================
*/
void idWeapon::InitWorldModel( const idDeclEntityDef *def ) {
/*
idEntity *ent;
ent = worldModel.GetEntity();
assert( ent );
*/
assert( def );
const char *model = def->dict.GetString( "model_world" );
const char *attach = def->dict.GetString( "joint_attach" );
/*
//old code
ent->SetSkin( NULL );
if ( model[0] && attach[0] ) {
ent->Show();
ent->SetModel( model );
if ( ent->GetAnimator()->ModelDef() ) {
ent->SetSkin( ent->GetAnimator()->ModelDef()->GetDefaultSkin() );
}
ent->GetPhysics()->SetContents( 0 );
ent->GetPhysics()->SetClipModel( NULL, 1.0f );
ent->BindToJoint( owner, 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();
}
flashJointWorld = ent->GetAnimator()->GetJointHandle( "flash" );
ejectJointWorld = ent->GetAnimator()->GetJointHandle( "eject" );
meleeJointWorld = ent->GetAnimator()->GetJointHandle( "melee" ); //ivan
//ivan - fix for bfg or custom barrel joint
//was: barrelJointWorld = ent->GetAnimator()->GetJointHandle( "barrel" ); //ivan - was "muzzle"
barrelJointWorld = ent->GetAnimator()->GetJointHandle( def->dict.GetString( "world_barrel_joint", "barrel" ) );
//ivan end
*/
//ivan start
if ( model[0] && attach[0] ) {
SetModel( model );
GetPhysics()->SetContents( 0 );
GetPhysics()->SetClipModel( NULL, 1.0f );
BindToJoint( owner, attach, true );
GetPhysics()->SetOrigin( vec3_origin );
GetPhysics()->SetAxis( mat3_identity );
// supress model in player views, but allow it in mirrors and remote views
renderEntity.suppressSurfaceInViewID = owner->entityNumber+1;
renderEntity.suppressShadowInViewID = owner->entityNumber+1;
renderEntity.suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
} else {
SetModel( "" );
}
// find some joints in the model for locating effects
barrelJointWorld = animator.GetJointHandle( def->dict.GetString( "world_barrel_joint", "barrel" ) );
flashJointWorld = animator.GetJointHandle( "flash" );
ejectJointWorld = animator.GetJointHandle( "eject" );
meleeJointWorld = animator.GetJointHandle( "melee" ); //ivan
//ivan end
//ivan - initialize the tracer bbox
meleebox.Zero();
float expansion = def->dict.GetFloat("melee_tracerWidth","0");
if(expansion > 0){
useMeleeBox = true;
meleebox.ExpandSelf( expansion );
}
}
//van start
/*
================
idWeapon::UpdSpreadSettings
================
*/
void idWeapon::UpdSpreadSettings( void ) {
int myMode = owner->GetCurrentWeaponMode();
//base value
spreadBaseValue = weaponDef->dict.GetFloat( va( "spread_mode%d", myMode ), "-1" ); //use a negative default to check if it's present quickly
if( spreadBaseValue < 0 ) {
spreadBaseValue = weaponDef->dict.GetFloat( "spread", "0" ); //default no spread
}
//spreadVelocityPct
spreadVelocityFactor = weaponDef->dict.GetFloat( va( "spreadVelocityPct_mode%d", myMode ), "-1" ); //use a negative default to check if it's present quickly
if( spreadVelocityFactor < 0 ) {
spreadVelocityFactor = weaponDef->dict.GetFloat( "spreadVelocityPct", "0" ); //default no extra-speed-based spread
}
//spreadCrouchPct
spreadCrouchFactor = weaponDef->dict.GetFloat( va( "spreadCrouchPct_mode%d", myMode ), "-1" ); //use a negative default to check if it's present quickly
if( spreadCrouchFactor < 0 ) {
spreadCrouchFactor = weaponDef->dict.GetFloat( "spreadCrouchPct", "100" ); //default crouch leave spread 100% unaltered
}
/*
gameLocal.Printf("-- mode %d --\n",myMode);
gameLocal.Printf("spreadBaseValue %f\n",spreadBaseValue);
gameLocal.Printf("spreadVelocityFactor %f\n",spreadVelocityFactor);
gameLocal.Printf("spreadCrouchFactor %f\n",spreadCrouchFactor);
*/
spreadVelocityFactor = spreadVelocityFactor/100; //pct velocity to use
spreadCrouchFactor = spreadCrouchFactor/100; //pct spread to use when crouched
}
//ivan end
/*
================
idWeapon::GetWeaponDef
================
*/
void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) {
const char *shader;
const char *objectType;
//const char *vmodel;
const char *guiName;
// const char *projectileName;
const char *brassDefName;
const char *smokeName;
int ammoAvail;
Clear();
if ( !objectname || !objectname[ 0 ] ) {
return;
}
assert( owner );
weaponDef = gameLocal.FindEntityDef( objectname );
ammoType = GetAmmoNumForName( weaponDef->dict.GetString( "ammoType" ) );
ammoRequired = weaponDef->dict.GetInt( "ammoRequired" );
clipSize = weaponDef->dict.GetInt( "clipSize" );
lowAmmo = weaponDef->dict.GetInt( "lowAmmo" );
//ivan start
maxAmmo = owner->inventory.MaxAmmoForAmmoClass( owner, weaponDef->dict.GetString( "ammoType" ) );
spreadMode = weaponDef->dict.GetInt( "spreadMode", "0" );
//ivan end
icon = weaponDef->dict.GetString( "icon" );
silent_fire = weaponDef->dict.GetBool( "silent_fire" );
powerAmmo = weaponDef->dict.GetBool( "powerAmmo" );
/*
#ifdef _DENTONMOD
#else
muzzle_kick_time = SEC2MS( weaponDef->dict.GetFloat( "muzzle_kick_time" ) );
muzzle_kick_maxtime = SEC2MS( weaponDef->dict.GetFloat( "muzzle_kick_maxtime" ) );
muzzle_kick_angles = weaponDef->dict.GetAngles( "muzzle_kick_angles" );
muzzle_kick_offset = weaponDef->dict.GetVector( "muzzle_kick_offset" );
#endif
*/
hideTime = SEC2MS( weaponDef->dict.GetFloat( "hide_time", "0.3" ) );
hideDistance = weaponDef->dict.GetFloat( "hide_distance", "-15" );
// muzzle smoke
smokeName = weaponDef->dict.GetString( "smoke_muzzle" );
if ( *smokeName != '\0' ) {
weaponSmoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
} else {
weaponSmoke = NULL;
}
continuousSmoke = weaponDef->dict.GetBool( "continuousSmoke" );
weaponSmokeStartTime = ( continuousSmoke ) ? gameLocal.time : 0;
smokeName = weaponDef->dict.GetString( "smoke_strike" );
if ( *smokeName != '\0' ) {
strikeSmoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
} else {
strikeSmoke = NULL;
}
strikeSmokeStartTime = 0;
strikePos.Zero();
strikeAxis = mat3_identity;
nextStrikeFx = 0;
//ivan start
nextMeleeSnd = 0;
firingWalkSpeedMult = weaponDef->dict.GetFloat( "firingWalkSpeedMult", "1.0" );
trailLowOffset = weaponDef->dict.GetInt( "trailLowOffset", "0" );
trailHighOffset = weaponDef->dict.GetInt( "trailHighOffset", "0" );
//spread
UpdSpreadSettings();
//ivan end
/*
// setup gui light
memset( &guiLight, 0, sizeof( guiLight ) );
const char *guiLightShader = weaponDef->dict.GetString( "mtr_guiLightShader" );
if ( *guiLightShader != '\0' ) {
guiLight.shader = declManager->FindMaterial( guiLightShader, false );
guiLight.lightRadius[0] = guiLight.lightRadius[1] = guiLight.lightRadius[2] = 3;
guiLight.pointLight = true;
}
// setup the view model
vmodel = weaponDef->dict.GetString( "model_view" );
SetModel( vmodel );
*/
// setup the world model
InitWorldModel( weaponDef );
// copy the sounds from the weapon view model def into out spawnargs
const idKeyValue *kv = weaponDef->dict.MatchPrefix( "snd_" );
while( kv ) {
spawnArgs.Set( kv->GetKey(), kv->GetValue() );
kv = weaponDef->dict.MatchPrefix( "snd_", kv );
}
/*
// find some joints in the model for locating effects
barrelJointView = animator.GetJointHandle( "barrel" );
flashJointView = animator.GetJointHandle( "flash" );
ejectJointView = animator.GetJointHandle( "eject" );
guiLightJointView = animator.GetJointHandle( "guiLight" );
ventLightJointView = animator.GetJointHandle( "ventLight" );
*/
#ifdef _DENTONMOD
#else
// get the projectile
projectileDict.Clear();
const char *projectileName = weaponDef->dict.GetString( "def_projectile" );
if ( projectileName[0] != '\0' ) {
const idDeclEntityDef *projectileDef = gameLocal.FindEntityDef( projectileName, false );
if ( !projectileDef ) {
gameLocal.Warning( "Unknown projectile '%s' in weapon '%s'", projectileName, objectname );
} else {
const char *spawnclass = projectileDef->dict.GetString( "spawnclass" );
idTypeInfo *cls = idClass::GetClass( spawnclass );
if ( !cls || !cls->IsType( idProjectile::Type ) ) {
gameLocal.Warning( "Invalid spawnclass '%s' on projectile '%s' (used by weapon '%s')", spawnclass, projectileName, objectname );
} else {
projectileDict = projectileDef->dict;
}
}
}
#endif
// set up muzzleflash render light
const idMaterial*flashShader;
idVec3 flashTarget;
idVec3 flashUp;
idVec3 flashRight;
float flashRadius;
bool flashPointLight;
weaponDef->dict.GetString( "mtr_flashShader", "", &shader );
flashShader = declManager->FindMaterial( shader, false );
flashPointLight = weaponDef->dict.GetBool( "flashPointLight", "1" );
weaponDef->dict.GetVector( "flashColor", "0 0 0", flashColor );
flashRadius = (float)weaponDef->dict.GetInt( "flashRadius" ); // if 0, no light will spawn
flashTime = SEC2MS( weaponDef->dict.GetFloat( "flashTime", "0.25" ) );
flashTarget = weaponDef->dict.GetVector( "flashTarget" );
flashUp = weaponDef->dict.GetVector( "flashUp" );
flashRight = weaponDef->dict.GetVector( "flashRight" );
/*
//old code
memset( &muzzleFlash, 0, sizeof( muzzleFlash ) );
muzzleFlash.lightId = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
muzzleFlash.allowLightInViewID = owner->entityNumber+1;
// the weapon lights will only be in first person
guiLight.allowLightInViewID = owner->entityNumber+1;
nozzleGlow.allowLightInViewID = owner->entityNumber+1;
muzzleFlash.pointLight = flashPointLight;
muzzleFlash.shader = flashShader;
muzzleFlash.shaderParms[ SHADERPARM_RED ] = flashColor[0];
muzzleFlash.shaderParms[ SHADERPARM_GREEN ] = flashColor[1];
muzzleFlash.shaderParms[ SHADERPARM_BLUE ] = flashColor[2];
muzzleFlash.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f;
muzzleFlash.lightRadius[0] = flashRadius;
muzzleFlash.lightRadius[1] = flashRadius;
muzzleFlash.lightRadius[2] = flashRadius;
if ( !flashPointLight ) {
muzzleFlash.target = flashTarget;
muzzleFlash.up = flashUp;
muzzleFlash.right = flashRight;
muzzleFlash.end = flashTarget;
}
// the world muzzle flash is the same, just positioned differently
worldMuzzleFlash = muzzleFlash;
worldMuzzleFlash.suppressLightInViewID = owner->entityNumber+1;
worldMuzzleFlash.allowLightInViewID = 0;
worldMuzzleFlash.lightId = LIGHTID_WORLD_MUZZLE_FLASH + owner->entityNumber;
*/
//ivan start
memset( &worldMuzzleFlash, 0, sizeof( worldMuzzleFlash ) );
//nozzleGlow will only be in first person //TODO: use nozzle stuff in 3th person?
nozzleGlow.allowLightInViewID = owner->entityNumber+1;
worldMuzzleFlash.suppressLightInViewID = owner->entityNumber+1;
worldMuzzleFlash.allowLightInViewID = 0;
worldMuzzleFlash.lightId = LIGHTID_WORLD_MUZZLE_FLASH + owner->entityNumber;
worldMuzzleFlash.pointLight = flashPointLight;
worldMuzzleFlash.shader = flashShader;
worldMuzzleFlash.shaderParms[ SHADERPARM_RED ] = flashColor[0];
worldMuzzleFlash.shaderParms[ SHADERPARM_GREEN ] = flashColor[1];
worldMuzzleFlash.shaderParms[ SHADERPARM_BLUE ] = flashColor[2];
worldMuzzleFlash.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f;
worldMuzzleFlash.lightRadius[0] = flashRadius;
worldMuzzleFlash.lightRadius[1] = flashRadius;
worldMuzzleFlash.lightRadius[2] = flashRadius;
if ( !flashPointLight ) {
worldMuzzleFlash.target = flashTarget;
worldMuzzleFlash.up = flashUp;
worldMuzzleFlash.right = flashRight;
worldMuzzleFlash.end = flashTarget;
}
//ivan end
//-----------------------------------
nozzleFx = weaponDef->dict.GetBool("nozzleFx");
nozzleFxFade = weaponDef->dict.GetInt("nozzleFxFade", "1500");
nozzleGlowColor = weaponDef->dict.GetVector("nozzleGlowColor", "1 1 1");
nozzleGlowRadius = weaponDef->dict.GetFloat("nozzleGlowRadius", "10");
weaponDef->dict.GetString( "mtr_nozzleGlowShader", "", &shader );
nozzleGlowShader = declManager->FindMaterial( shader, false );
// get the melee damage def
meleeDistance = weaponDef->dict.GetFloat( "melee_distance" );
meleeDefName = weaponDef->dict.GetString( "def_melee" );
if ( meleeDefName.Length() ) {
meleeDef = gameLocal.FindEntityDef( meleeDefName, false );
if ( !meleeDef ) {
gameLocal.Error( "Unknown melee '%s'", meleeDefName.c_str() );
}
}
// get the brass def
brassDict.Clear();
brassDelay = weaponDef->dict.GetInt( "ejectBrassDelay", "0" );
brassDefName = weaponDef->dict.GetString( "def_ejectBrass" );
if ( brassDefName[0] ) {
const idDeclEntityDef *brassDef = gameLocal.FindEntityDef( brassDefName, false );
if ( !brassDef ) {
gameLocal.Warning( "Unknown brass '%s'", brassDefName );
} else {
brassDict = brassDef->dict;
}
}
if ( ( ammoType < 0 ) || ( ammoType >= AMMO_NUMTYPES ) ) {
gameLocal.Warning( "Unknown ammotype in object '%s'", objectname );
}
ammoClip = ammoinclip;
if ( ( ammoClip < 0 ) || ( ammoClip > clipSize ) ) {
// first time using this weapon so have it fully loaded to start
ammoClip = clipSize;
ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired );
if ( ammoClip > ammoAvail ) {
ammoClip = ammoAvail;
}
//In D3XP we use ammo as soon as it is moved into the clip. This allows for weapons that share ammo
//owner->inventory.UseAmmo(ammoType, ammoClip); //ivan - commented out!
}
renderEntity.gui[ 0 ] = NULL;
guiName = weaponDef->dict.GetString( "gui" );
if ( guiName[0] ) {
renderEntity.gui[ 0 ] = uiManager->FindGui( guiName, true, false, true );
}
zoomFov = weaponDef->dict.GetInt( "zoomFov", "70" );
berserk = weaponDef->dict.GetInt( "berserk", "2" );
weaponAngleOffsetAverages = weaponDef->dict.GetInt( "weaponAngleOffsetAverages", "10" );
weaponAngleOffsetScale = weaponDef->dict.GetFloat( "weaponAngleOffsetScale", "0.25" );
weaponAngleOffsetMax = weaponDef->dict.GetFloat( "weaponAngleOffsetMax", "10" );
weaponOffsetTime = weaponDef->dict.GetFloat( "weaponOffsetTime", "400" );
weaponOffsetScale = weaponDef->dict.GetFloat( "weaponOffsetScale", "0.005" );
if ( !weaponDef->dict.GetString( "weapon_scriptobject", NULL, &objectType ) ) {
gameLocal.Error( "No 'weapon_scriptobject' set on '%s'.", objectname );
}
// setup script object
if ( !scriptObject.SetType( objectType ) ) {
gameLocal.Error( "Script object '%s' not found on weapon '%s'.", objectType, objectname );
}
WEAPON_ATTACK.LinkTo( scriptObject, "WEAPON_ATTACK" );
WEAPON_SPECIAL.LinkTo( scriptObject, "WEAPON_SPECIAL" ); //new
WEAPON_SPECIAL_HOLD.LinkTo( scriptObject, "WEAPON_SPECIAL_HOLD" ); //
WEAPON_RELOAD.LinkTo( scriptObject, "WEAPON_RELOAD" );
WEAPON_NETRELOAD.LinkTo( scriptObject, "WEAPON_NETRELOAD" );
WEAPON_NETENDRELOAD.LinkTo( scriptObject, "WEAPON_NETENDRELOAD" );
WEAPON_NETFIRING.LinkTo( scriptObject, "WEAPON_NETFIRING" );
WEAPON_RAISEWEAPON.LinkTo( scriptObject, "WEAPON_RAISEWEAPON" );
WEAPON_LOWERWEAPON.LinkTo( scriptObject, "WEAPON_LOWERWEAPON" );
spawnArgs = weaponDef->dict;
#ifdef _DENTONMOD
projectileDict.Clear();
ChangeProjectileDef( owner->GetProjectileType() );
#endif
shader = spawnArgs.GetString( "snd_hum" );
if ( shader && *shader ) {
sndHum = declManager->FindSound( shader );
StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL );
}
isLinked = true;
// call script object's constructor
ConstructScriptObject();
// make sure we have the correct skin
UpdateSkin();
#ifdef _DENTONMOD
InitWeaponFx();
#endif
}
/*********************
idWeapon::initWeaponFx
**********************/
#ifdef _DENTONMOD
void idWeapon::InitWeaponFx( void )
{
const idKeyValue *pkv;
/*
// Create new joints
const idKeyValue *pkv = weaponDef->dict.MatchPrefix( "weapon_createjoint", NULL );
while( pkv ) {
WeaponJoint_t newJoint;
jointHandle_t joint;
idStr jointName = pkv->GetValue();
bool isOnWorldModel = weaponDef->dict.GetBool( va( "%s_onWorldModel", jointName.c_str() ), "0");
idStr referenceJoint = weaponDef->dict.GetString(va("%s_referencejoint", jointName.c_str()));
idAnimator *weapAnimator;
if ( !isOnWorldModel ) {
joint = animator.GetJointHandle( referenceJoint.c_str() );
weapAnimator = &animator;
}
else {
idEntity *ent = worldModel.GetEntity();
weapAnimator = ent->GetAnimator();
joint = weapAnimator->GetJointHandle( referenceJoint.c_str() );
}
if( joint != INVALID_JOINT ) { // To create a new joint we need a reference to an existing joint
idVec3 offset, origin, dir;
idMat3 axis;
GetGlobalJointTransform( !isOnWorldModel, joint, origin, axis );
if( weaponDef->dict.GetVector( va( "%s_offset", jointName.c_str() ), "0 0 0", offset) ) {
origin += axis * offset;
}
if ( weaponDef->dict.GetVector( va( "%s_dir", jointName.c_str() ), "1 0 0", dir) ) {
idVec3 &xAxis = axis[0];
xAxis = axis * dir;
xAxis.Normalize();
axis = xAxis.ToMat3 ();
}
strcpy( newJoint.name, jointName.c_str() );
newJoint.joint = (jointHandle_t)weapAnimator->NumJoints();
weapAnimator->SetJointPos( newJoint.joint, JOINTMOD_WORLD_OVERRIDE, origin );
weapAnimator->SetJointAxis( newJoint.joint, JOINTMOD_WORLD_OVERRIDE, axis );
weaponJoints.Set( jointName.c_str(), newJoint );
}
pkv = weaponDef->dict.MatchPrefix( "weapon_createjoint", pkv );
}
// Update existing joints
pkv = weaponDef->dict.MatchPrefix( "weapon_updatejoint", NULL );
while( pkv ) {
jointHandle_t refJoint, joint;
idStr jointName = pkv->GetValue();
bool isOnWorldModel = weaponDef->dict.GetBool( va( "%s_onWorldModel", jointName.c_str() ), "0");
idStr refJointName = weaponDef->dict.GetString(va("%s_referencejoint", jointName.c_str()));
idAnimator *weapAnimator;
if ( !isOnWorldModel ) {
refJoint = animator.GetJointHandle( refJointName.c_str() );
joint = animator.GetJointHandle( jointName.c_str() );
weapAnimator = &animator;
}
else {
idEntity *ent = worldModel.GetEntity();
weapAnimator = ent->GetAnimator();
refJoint = weapAnimator->GetJointHandle( refJointName.c_str() );
joint = weapAnimator->GetJointHandle( jointName.c_str() );
}
if( joint != INVALID_JOINT && refJoint != INVALID_JOINT ) {
idVec3 offset, origin, dir;
idMat3 axis;
GetGlobalJointTransform( !isOnWorldModel, refJoint, origin, axis );
if( weaponDef->dict.GetVector( va( "%s_offset", jointName.c_str() ), "0 0 0", offset) ) {
origin += axis * offset;
}
if ( weaponDef->dict.GetVector( va( "%s_dir", jointName.c_str() ), "1 0 0", dir) ) {
idVec3 &xAxis = axis[0];
xAxis = axis * dir;
xAxis.Normalize();
axis = xAxis.ToMat3 ();
}
weapAnimator->SetJointAxis( joint, JOINTMOD_WORLD_OVERRIDE, axis );
weapAnimator->SetJointPos( joint, JOINTMOD_WORLD_OVERRIDE, origin );
}
pkv = weaponDef->dict.MatchPrefix( "weapon_updatejoint", pkv );
}
*/
//Initialize the particles
pkv = weaponDef->dict.MatchPrefix( "weapon_particle", NULL );
while( pkv ) {
WeaponParticle_t newParticle;
memset( &newParticle, 0, sizeof( newParticle ) );
idStr prtName = pkv->GetValue();
strcpy(newParticle.name, prtName.c_str());
newParticle.particleFlags.isOffset = weaponDef->dict.GetVector( va( "%s_offset", prtName.c_str() ), "0 0 0", newParticle.offset ); // this offset will be added to the origin
newParticle.particleFlags.isDir = weaponDef->dict.GetVector( va( "%s_dir", prtName.c_str() ), "1 0 0", newParticle.dir ); // adjust the dir
newParticle.particleFlags.isViewDir = weaponDef->dict.GetBool( va( "%s_useViewDir", prtName.c_str() ), "0"); //ivan
newParticle.particleFlags.isOnWorldModel = weaponDef->dict.GetBool( va( "%s_onWorldModel", prtName.c_str() ), "0");
idStr jointName = weaponDef->dict.GetString(va("%s_joint", prtName.c_str()));
// WeaponJoint_t *customJoint;
//ivan start
/*
//was
if ( !newParticle.particleFlags.isOnWorldModel ) { // Smoke is not differentiated as world and view particles
newParticle.particleFlags.isSmoke = weaponDef->dict.GetBool(va("%s_smoke", prtName.c_str()), "0");
newParticle.joint = animator.GetJointHandle( jointName.c_str() );
}
else {
idEntity *ent = worldModel.GetEntity();
newParticle.particleFlags.isSmoke = false;
newParticle.joint = ent->GetAnimator()->GetJointHandle( jointName.c_str() );
}
*/
newParticle.particleFlags.isSmoke = weaponDef->dict.GetBool(va("%s_smoke", prtName.c_str()), "0");
if ( newParticle.particleFlags.isOnWorldModel ) { //now worldmodel is the weapon model itself
newParticle.joint = animator.GetJointHandle( jointName.c_str() );
}
else { //not supported
newParticle.joint = INVALID_JOINT;
}
/*
if( newParticle.joint == INVALID_JOINT ){
gameLocal.Printf( "joint %s for %s is INVALID\n", jointName.c_str(), prtName.c_str());
}else{
gameLocal.Printf( "joint %s for %s is OK\n", jointName.c_str(), prtName.c_str());
}
*/
//ivan end
newParticle.particleFlags.isActive = false;
newParticle.startTime = 0;
idStr particle = weaponDef->dict.GetString(va("%s_particle", prtName.c_str()));
strcpy(newParticle.particlename, particle.c_str());
newParticle.particleFlags.isContinuous = weaponDef->dict.GetBool(va("%s_continuous", prtName.c_str()), "1");
if(newParticle.particleFlags.isSmoke) {
// newParticle.particleFlags.isContinuous = weaponDef->dict.GetBool(va("%s_continuous", prtName.c_str()), "1");
newParticle.particle = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, particle.c_str(), false ) );
}
else {
newParticle.renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0;
newParticle.renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0;
newParticle.renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0;
newParticle.renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 1.0;
if ( newParticle.particleFlags.isOnWorldModel ) {
newParticle.renderEntity.suppressSurfaceInViewID = owner->entityNumber+1; // Make sure this is third person effect only.
}
else {
newParticle.renderEntity.weaponDepthHack = weaponDef->dict.GetBool(va("%s_weaponDepthHack", prtName.c_str()), "0");
newParticle.renderEntity.allowSurfaceInViewID = owner->entityNumber+1; // Make sure this is first person effect only.
}
const idDeclModelDef *modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, newParticle.particlename ) );
if ( modelDef ) {
newParticle.renderEntity.hModel = renderModelManager->FindModel( newParticle.particlename );
}
newParticle.modelDefHandle = -1;
}
weaponParticles.Set(prtName.c_str(), newParticle);
pkv = weaponDef->dict.MatchPrefix( "weapon_particle", pkv );
}
const idKeyValue *lkv = weaponDef->dict.MatchPrefix( "weapon_light", NULL );
while( lkv ) {
WeaponLight_t newLight;
memset( &newLight, 0, sizeof( newLight ) );
newLight.lightHandle = -1;
newLight.lightFlags.isActive = false;
newLight.startTime = 0;
idStr lightName = lkv->GetValue(), debug;
strcpy(newLight.name, lightName.c_str());
newLight.lightFlags.isOffset = weaponDef->dict.GetVector( va( "%s_offset", lightName.c_str() ), "0 0 0", newLight.offset ); // this offset will be added to the origin
newLight.lightFlags.isDir = weaponDef->dict.GetVector( va( "%s_dir", lightName.c_str() ), "1 0 0", newLight.dir ); // Direction can be adjusted with this
idStr lightShader = weaponDef->dict.GetString(va("%s_shader", lightName.c_str()));
newLight.light.shader = declManager->FindMaterial( lightShader.c_str(), false );
float radius = weaponDef->dict.GetFloat(va("%s_radius", lightName.c_str()));
newLight.light.lightRadius[0] = radius;
newLight.light.lightRadius[1] = radius;
newLight.light.lightRadius[2] = radius;
newLight.lightFlags.isAlwaysOn = weaponDef->dict.GetBool( va( "%s_alwaysOn", lightName.c_str () ), "1" );
newLight.light.pointLight = weaponDef->dict.GetBool( va( "%s_pointLight", lightName.c_str() ), "0" );
newLight.light.noShadows = weaponDef->dict.GetBool( va( "%s_noShadows", lightName.c_str() ), "0" );
if (!newLight.light.pointLight) {
newLight.light.target = weaponDef->dict.GetVector( va( "%s_target", lightName.c_str() ) );
newLight.light.up = weaponDef->dict.GetVector( va( "%s_up", lightName.c_str() ) );
newLight.light.right = weaponDef->dict.GetVector( va( "%s_right", lightName.c_str() ) );
newLight.light.end = newLight.light.target;
}
if (!newLight.lightFlags.isAlwaysOn) {
newLight.endTime = SEC2MS( weaponDef->dict.GetFloat( va( "%s_endTime", lightName.c_str() ), "0.25" ) );
}
idVec3 lightColor = weaponDef->dict.GetVector( va( "%s_color", lightName.c_str() ), "1 1 1");
newLight.light.shaderParms[ SHADERPARM_RED ] = lightColor[0];
newLight.light.shaderParms[ SHADERPARM_GREEN ] = lightColor[1];
newLight.light.shaderParms[ SHADERPARM_BLUE ] = lightColor[2];
newLight.light.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f;
newLight.lightFlags.isOnWorldModel = weaponDef->dict.GetBool( va( "%s_onWorldModel", lightName.c_str() ), "0");
idStr jointName = weaponDef->dict.GetString(va("%s_joint", lightName.c_str()));
/*
//was
if ( newLight.lightFlags.isOnWorldModel ) { // third person only light
idEntity *ent = worldModel.GetEntity();
newLight.joint = ent->GetAnimator()->GetJointHandle( jointName.c_str() );
newLight.light.suppressLightInViewID = owner->entityNumber+1;
}
else {
newLight.joint = animator.GetJointHandle(jointName.c_str());
newLight.light.allowLightInViewID = owner->entityNumber+1;
}
*/
//ivan start
if ( newLight.lightFlags.isOnWorldModel ) { // third person only light
newLight.joint = animator.GetJointHandle( jointName.c_str() ); //ivan
newLight.light.suppressLightInViewID = owner->entityNumber+1;
}
else { //not supported
newLight.joint = INVALID_JOINT; //ivan
newLight.light.allowLightInViewID = owner->entityNumber+1;
}
//ivan end
weaponLights.Set(lightName.c_str(), newLight);
lkv = weaponDef->dict.MatchPrefix( "weapon_light", lkv );
}
}
#endif //_DENTONMOD
/***********************************************************************
GUIs
***********************************************************************/
/*
================
idWeapon::Icon
================
*/
const char *idWeapon::Icon( void ) const {
return icon;
}
/*
================
idWeapon::UpdateGUI
================
*/
void idWeapon::UpdateGUI( void ) {
if ( !renderEntity.gui[ 0 ] ) {
return;
}
if ( status == WP_HOLSTERED ) {
return;
}
if ( owner->weaponGone ) {
// dropping weapons was implemented wierd, so we have to not update the gui when it happens or we'll get a negative ammo count
return;
}
if ( 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 ) {
return;
}
} else {
return;
}
}
int inclip = AmmoInClip();
int ammoamount = AmmoAvailable();
if ( ammoamount < 0 ) {
// show infinite ammo
renderEntity.gui[ 0 ]->SetStateString( "player_ammo", "" );
} else {
// show remaining ammo
renderEntity.gui[ 0 ]->SetStateString( "player_totalammo", va( "%i", ammoamount) );//new
// renderEntity.gui[ 0 ]->SetStateString( "player_totalammo", va( "%i", ammoamount - inclip) );
renderEntity.gui[ 0 ]->SetStateString( "player_ammo", ClipSize() ? va( "%i", inclip ) : "--" );
renderEntity.gui[ 0 ]->SetStateString( "player_clips", ClipSize() ? va("%i", ammoamount / ClipSize()) : "--" );
// renderEntity.gui[ 0 ]->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount - inclip ) );
renderEntity.gui[ 0 ]->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount ) );//new
}
renderEntity.gui[ 0 ]->SetStateBool( "player_ammo_empty", ( ammoamount == 0 ) );
renderEntity.gui[ 0 ]->SetStateBool( "player_clip_empty", ( inclip == 0 ) );
renderEntity.gui[ 0 ]->SetStateBool( "player_clip_low", ( inclip <= lowAmmo ) );
//Let the HUD know the total amount of ammo regardless of the ammo required value
renderEntity.gui[ 0 ]->SetStateString( "player_ammo_count", va("%i", AmmoCount())); //new
//rev grab
//Grabber Gui Info
renderEntity.gui[ 0 ]->SetStateString( "grabber_state", va("%i", grabberState));
//rev grab
}
/***********************************************************************
Model and muzzleflash
***********************************************************************/
/********************************************************************
idWeapon::UpdateWeaponFx( void )
Updates custom weapon particles and lights- By Clone JC Denton
********************************************************************/
#ifdef _DENTONMOD
void idWeapon::UpdateWeaponFx (void )
{
for( int i = 0; i < weaponParticles.Num(); i++ ) {
WeaponParticle_t* part = weaponParticles.GetIndex(i);
//ivan - skip view particles!
if( !part->particleFlags.isOnWorldModel ) continue;
if(part->particleFlags.isActive) {
if(part->particleFlags.isSmoke) {
if(part->joint != INVALID_JOINT) {
//ivan start
/*
//was
GetGlobalJointTransform( true, part->joint, muzzleOrigin, muzzleAxis );
*/
GetGlobalJointTransform( part->joint, muzzleOrigin, muzzleAxis );
if( part->particleFlags.isViewDir ){ //use view dir awyway
muzzleAxis = playerViewAxis;
}else{
//direction fix!
idVec3 tmp = muzzleAxis[2];
muzzleAxis[2] = muzzleAxis[0];
muzzleAxis[0] = -tmp;
}
//ivan end
} else {
// default to going straight out the view
muzzleOrigin = playerViewOrigin;
muzzleAxis = playerViewAxis;
}
if ( part->particleFlags.isOffset ) {
muzzleOrigin += muzzleAxis * part->offset;
}
if ( part->particleFlags.isDir ) {
idVec3 &dir = muzzleAxis[ 0 ];
dir = muzzleAxis * part->dir;
dir.Normalize();
muzzleAxis = dir.ToMat3 ();
}
if ( !gameLocal.smokeParticles->EmitSmoke( part->particle, part->startTime, gameLocal.random.RandomFloat(), muzzleOrigin, muzzleAxis ) ) {
if ( !part->particleFlags.isContinuous ) {
part->particleFlags.isActive = false; // all done
part->startTime = 0;
}
else {
part->startTime = gameLocal.time; // for continuous effect
}
}
}
else {
if( part->renderEntity.hModel ) {
//ivan start
/*
//was:
GetGlobalJointTransform( !part->particleFlags.isOnWorldModel, part->joint, part->renderEntity.origin, part->renderEntity.axis );
if ( part->particleFlags.isOffset ) {
part->renderEntity.origin += part->renderEntity.axis * part->offset;
}
if ( part->particleFlags.isDir ) {
idVec3 &dir = part->renderEntity.axis[ 0 ];
dir = part->renderEntity.axis * part->dir;
dir.Normalize();
part->renderEntity.axis = dir.ToMat3();
}
*/
//GetGlobalJointTransform( !part->particleFlags.isOnWorldModel, part->joint, muzzleOrigin, muzzleAxis );
GetGlobalJointTransform( part->joint, muzzleOrigin, muzzleAxis );
if( part->particleFlags.isViewDir ){ //use view dir awyway
muzzleAxis = playerViewAxis;
}
//direction fix!
//do this also is isViewDir, so the "up" of the particle means "forward" also in that case
idVec3 tmp = muzzleAxis[2];
muzzleAxis[2] = muzzleAxis[0];
muzzleAxis[0] = -tmp;
if ( part->particleFlags.isDir ) {
idVec3 &dir = muzzleAxis[ 0 ];
dir = muzzleAxis * part->dir;
dir.Normalize();
muzzleAxis = dir.ToMat3();
}
if ( part->particleFlags.isOffset ) {
muzzleOrigin += muzzleAxis * part->offset;
}
part->renderEntity.origin = muzzleOrigin;
part->renderEntity.axis = muzzleAxis;
//ivan end
if ( part->modelDefHandle != -1 ) {
gameRenderWorld->UpdateEntityDef( part->modelDefHandle, &part->renderEntity );
}
else {
part->renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
part->renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.RandomFloat(); // For effects like muzzleflashes etc.
part->modelDefHandle = gameRenderWorld->AddEntityDef( &part->renderEntity );
}
}
}
}
}
for(int i = 0; i < weaponLights.Num(); i++) {
WeaponLight_t* light = weaponLights.GetIndex(i);
//ivan - skip view lights!
if( !light->lightFlags.isOnWorldModel ) continue;
if(light->lightFlags.isActive) {
//if (GetGlobalJointTransform( !light->lightFlags.isOnWorldModel, light->joint, light->light.origin, light->light.axis )) {
if (GetGlobalJointTransform( light->joint, light->light.origin, light->light.axis )) {
if ( light->lightFlags.isOffset ) {
light->light.origin += light->light.axis[ 0 ] * light->offset[ 0 ] + light->light.axis[ 1 ] * light->offset[ 1 ] + light->light.axis[ 2 ] * light->offset[ 2 ];
}
if ( light->lightFlags.isDir ) {
idVec3 &dir = light->light.axis[ 0 ];
dir = light->light.axis * light->dir;
dir.Normalize();
light->light.axis = dir.ToMat3();
}
if ( ( light->lightHandle != -1 ) ) {
gameRenderWorld->UpdateLightDef( light->lightHandle, &light->light );
}
else {
light->light.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
light->light.shaderParms[ SHADERPARM_DIVERSITY ] = renderEntity.shaderParms[ SHADERPARM_DIVERSITY ]; // For muzzleflashes.
light->lightHandle = gameRenderWorld->AddLightDef( &light->light );
}
if ( !light->lightFlags.isAlwaysOn && ( gameLocal.time >= light->endTime ) ) {
light->endTime -= light->startTime; // readjust the value.
Event_StopWeaponLight( light->name );
}
}
}
}
}
/********************************************************************
idWeapon::StopWeaponFx( void )
Stops custom weapon particles and lights temporarily- By Clone JC Denton
********************************************************************/
void idWeapon::StopWeaponFx( void )
{
for( int i = 0; i < weaponParticles.Num(); i++ ) {
WeaponParticle_t* part = weaponParticles.GetIndex(i);
if(part->particleFlags.isActive) {
//Free the particles
if( !part->particleFlags.isSmoke && part->modelDefHandle > -1 ) {
gameRenderWorld->FreeEntityDef( part->modelDefHandle );
part->modelDefHandle = -1;
}
}
}
for(int i = 0; i < weaponLights.Num(); i++) {
WeaponLight_t* light = weaponLights.GetIndex(i);
if( light->lightFlags.isActive ) {
if(light->lightHandle != -1) {
gameRenderWorld->FreeLightDef( light->lightHandle );
light->lightHandle = -1;
}
}
}
}
#endif
/*
================
idWeapon::UpdateFlashPosition
================
*/
void idWeapon::UpdateFlashPosition( void ) {
/*
if ( flashJointView != INVALID_JOINT ) { //ivan
// the flash has an explicit joint for locating it
GetGlobalJointTransform( true, flashJointView, muzzleFlash.origin, muzzleFlash.axis );
}
*/
/* ivan - commented out - don't waste time for useless things
// if the desired point is inside or very close to a wall, back it up until it is clear
idVec3 start = muzzleFlash.origin - playerViewAxis[0] * 16;
idVec3 end = muzzleFlash.origin + playerViewAxis[0] * 8;
trace_t tr;
gameLocal.clip.TracePoint( tr, start, end, MASK_SHOT_RENDERMODEL, owner );
// be at least 8 units away from a solid
muzzleFlash.origin = tr.endpos - playerViewAxis[0] * 8;
*/
// put the world muzzle flash on the end of the joint, no matter what
//GetGlobalJointTransform( false, flashJointWorld, worldMuzzleFlash.origin, worldMuzzleFlash.axis );
GetGlobalJointTransform( flashJointWorld, worldMuzzleFlash.origin, worldMuzzleFlash.axis );
}
/*
================
idWeapon::MuzzleFlashLight
================
*/
void idWeapon::MuzzleFlashLight( void ) {
if ( !lightOn && ( !g_muzzleFlash.GetBool() || !worldMuzzleFlash.lightRadius[0] ) ) { //was: muzzleFlash
return;
}
if ( flashJointWorld == INVALID_JOINT ) {
return;
}
UpdateFlashPosition();
// these will be different each fire
//commented out by ivan
//muzzleFlash.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
//muzzleFlash.shaderParms[ SHADERPARM_DIVERSITY ] = renderEntity.shaderParms[ SHADERPARM_DIVERSITY ];
worldMuzzleFlash.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
worldMuzzleFlash.shaderParms[ SHADERPARM_DIVERSITY ] = renderEntity.shaderParms[ SHADERPARM_DIVERSITY ];
// the light will be removed at this time
muzzleFlashEnd = gameLocal.time + flashTime;
//ivan start
/*
//was:
if ( muzzleFlashHandle != -1 ) {
gameRenderWorld->UpdateLightDef( muzzleFlashHandle, &muzzleFlash );
gameRenderWorld->UpdateLightDef( worldMuzzleFlashHandle, &worldMuzzleFlash );
} else {
muzzleFlashHandle = gameRenderWorld->AddLightDef( &muzzleFlash );
worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash );
}
*/
if ( worldMuzzleFlashHandle != -1 ) {
gameRenderWorld->UpdateLightDef( worldMuzzleFlashHandle, &worldMuzzleFlash );
} else {
worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash );
}
//ivan end
}
/*
================
idWeapon::UpdateSkin
================
*/
bool idWeapon::UpdateSkin( void ) {
const function_t *func;
if ( !isLinked ) {
return false;
}
func = scriptObject.GetFunction( "UpdateSkin" );
if ( !func ) {
common->Warning( "Can't find function 'UpdateSkin' in object '%s'", scriptObject.GetTypeName() );
return false;
}
// use the frameCommandThread since it's safe to use outside of framecommands
gameLocal.frameCommandThread->CallFunction( this, func, true );
gameLocal.frameCommandThread->Execute();
return true;
}
/*
================
idWeapon::SetModel
================
*/
void idWeapon::SetModel( const char *modelname ) {
assert( modelname );
if ( modelDefHandle >= 0 ) {
gameRenderWorld->RemoveDecals( modelDefHandle );
}
renderEntity.hModel = animator.SetModel( modelname );
if ( renderEntity.hModel ) {
renderEntity.customSkin = animator.ModelDef()->GetDefaultSkin();
animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints );
} else {
renderEntity.customSkin = NULL;
renderEntity.callback = NULL;
renderEntity.numJoints = 0;
renderEntity.joints = NULL;
}
// hide the model until an animation is played
Hide();
}
/*
================
idWeapon::GetGlobalJointTransform
This returns the offset and axis of a weapon bone in world space, suitable for attaching models or lights
================
*/
//bool idWeapon::GetGlobalJointTransform( bool viewModel, const jointHandle_t jointHandle, idVec3 &offset, idMat3 &axis ) {
bool idWeapon::GetGlobalJointTransform( const jointHandle_t jointHandle, idVec3 &offset, idMat3 &axis ) {
/*
//was:
if ( viewModel ) {
// view model
if ( animator.GetJointTransform( jointHandle, gameLocal.time, offset, axis ) ) {
offset = offset * viewWeaponAxis + viewWeaponOrigin;
axis = axis * viewWeaponAxis;
return true;
}
} else {
// world model
if ( worldModel.GetEntity() && worldModel.GetEntity()->GetAnimator()->GetJointTransform( jointHandle, gameLocal.time, offset, axis ) ) {
offset = worldModel.GetEntity()->GetPhysics()->GetOrigin() + offset * worldModel.GetEntity()->GetPhysics()->GetAxis();
axis = axis * worldModel.GetEntity()->GetPhysics()->GetAxis();
return true;
}
}
offset = viewWeaponOrigin;
axis = viewWeaponAxis;
return false;
*/
//ivan start - world model is now the model itself
if ( animator.GetJointTransform( jointHandle, gameLocal.time, offset, axis ) ) {
offset = GetPhysics()->GetOrigin() + offset * GetPhysics()->GetAxis();
axis = axis * GetPhysics()->GetAxis();
return true;
}
offset = GetPhysics()->GetOrigin(); //viewWeaponOrigin;
axis = GetPhysics()->GetAxis(); //viewWeaponAxis;
return false;
//ivan end
}
/*
================
idWeapon::SetPushVelocity
================
*/
void idWeapon::SetPushVelocity( const idVec3 &pushVelocity ) {
this->pushVelocity = pushVelocity;
}
/***********************************************************************
State control/player interface
***********************************************************************/
/*
================
idWeapon::Think
================
*/
void idWeapon::Think( void ) {
// do nothing because the present is called from the player through PresentWeapon
}
/*
================
idWeapon::Raise
================
*/
void idWeapon::Raise( void ) {
if ( isLinked ) {
WEAPON_RAISEWEAPON = true;
}
}
/*
================
idWeapon::PutAway
================
*/
void idWeapon::PutAway( void ) {
hasBloodSplat = false;
if ( isLinked ) {
WEAPON_LOWERWEAPON = true;
}
}
/*
================
idWeapon::Reload
NOTE: this is only for impulse-triggered reload, auto reload is scripted
================
*/
void idWeapon::Reload( void ) {
if ( isLinked ) {
WEAPON_RELOAD = true;
}
}
/*
================
idWeapon::LowerWeapon
================
*/
void idWeapon::LowerWeapon( void ) {
if ( !hide ) {
hideStart = 0.0f;
hideEnd = hideDistance;
if ( gameLocal.time - hideStartTime < hideTime ) {
hideStartTime = gameLocal.time - ( hideTime - ( gameLocal.time - hideStartTime ) );
} else {
hideStartTime = gameLocal.time;
}
hide = true;
}
}
/*
================
idWeapon::RaiseWeapon
================
*/
void idWeapon::RaiseWeapon( void ) {
Show();
if ( hide ) {
hideStart = hideDistance;
hideEnd = 0.0f;
if ( gameLocal.time - hideStartTime < hideTime ) {
hideStartTime = gameLocal.time - ( hideTime - ( gameLocal.time - hideStartTime ) );
} else {
hideStartTime = gameLocal.time;
}
hide = false;
}
}
/*
================
idWeapon::HideWeapon
================
*/
void idWeapon::HideWeapon( void ) {
Hide();
/*
if ( worldModel.GetEntity() ) {
worldModel.GetEntity()->Hide();
}
*/
muzzleFlashEnd = 0;
}
/*
================
idWeapon::ShowWeapon
================
*/
void idWeapon::ShowWeapon( void ) {
Show();
/*
if ( worldModel.GetEntity() ) {
worldModel.GetEntity()->Show();
}
*/
if ( lightOn ) {
MuzzleFlashLight();
}
}
/*
================
idWeapon::HideWorldModel
================
*/
void idWeapon::HideWorldModel( void ) {
/*
//was:
if ( worldModel.GetEntity() ) {
worldModel.GetEntity()->Hide();
}
*/
Hide(); //ivan
}
/*
================
idWeapon::ShowWorldModel
================
*/
void idWeapon::ShowWorldModel( void ) {
/*
//was:
if ( worldModel.GetEntity() ) {
worldModel.GetEntity()->Show();
}
*/
Show(); //ivan
}
/*
================
idWeapon::OwnerDied
================
*/
void idWeapon::OwnerDied( void ) {
if ( isLinked ) {
SetState( "OwnerDied", 0 );
thread->Execute();
//rev grab
// Update the grabber effects
if ( /*!gameLocal.isMultiplayer &&*/ grabberState != -1 ) {
grabber.Update( owner, hide );
}
//rev grab
}
Hide();
/*
if ( worldModel.GetEntity() ) {
worldModel.GetEntity()->Hide();
}
*/
// don't clear the weapon immediately since the owner might have killed himself by firing the weapon
// within the current stack frame
PostEventMS( &EV_Weapon_Clear, 0 );
}
/*
================
idWeapon::BeginSpecialFunction
================
*/
void idWeapon::BeginSpecialFunction( bool keyTapped ) { // new
if ( isLinked ) {
if (keyTapped){
WEAPON_SPECIAL = true;
}
WEAPON_SPECIAL_HOLD = true;
}
}
/*
================
idWeapon::EndSpecialFunc
================
*/
void idWeapon::EndSpecialFunction( void ) { //New
if ( !WEAPON_SPECIAL_HOLD.IsLinked() ) {
return;
}
if ( WEAPON_SPECIAL_HOLD ) {
WEAPON_SPECIAL_HOLD = false;
}
}
/*
================
idWeapon::BeginAttack
================
*/
void idWeapon::BeginAttack( void ) {
if ( status != WP_OUTOFAMMO ) {
lastAttack = gameLocal.time;
}
if ( !isLinked ) {
return;
}
if ( !WEAPON_ATTACK ) {
//rev grab
//if ( sndHum ) {
if ( sndHum && grabberState == -1 ) { // _D3XP :: don't stop grabber hum
//rev grab
StopSound( SND_CHANNEL_BODY, false );
}
}
WEAPON_ATTACK = true;
}
/*
================
idWeapon::EndAttack
================
*/
void idWeapon::EndAttack( void ) {
if ( !WEAPON_ATTACK.IsLinked() ) {
return;
}
if ( WEAPON_ATTACK ) {
WEAPON_ATTACK = false;
//rev grab
//if ( sndHum ) {
if ( sndHum && grabberState == -1 ) { // _D3XP :: don't stop grabber hum
//rev grab
StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL );
}
}
}
/*
================
idWeapon::isReady
================
*/
bool idWeapon::IsReady( void ) const {
return !hide && !IsHidden() && ( ( status == WP_RELOAD ) || ( status == WP_READY ) || ( status == WP_OUTOFAMMO ) );
}
/*
================
idWeapon::IsReloading
================
*/
bool idWeapon::IsReloading( void ) const {
return ( status == WP_RELOAD );
}
/*
================
idWeapon::IsHolstered
================
*/
bool idWeapon::IsHolstered( void ) const {
return ( status == WP_HOLSTERED );
}
/*
================
idWeapon::ShowCrosshair
================
*/
bool idWeapon::ShowCrosshair( void ) const {
return !( state == idStr( WP_RISING ) || state == idStr( WP_LOWERING ) || state == idStr( WP_HOLSTERED ) );
}
/*
=====================
idWeapon::CanDrop
=====================
*/
bool idWeapon::CanDrop( void ) const {
if ( !weaponDef ) { // || !worldModel.GetEntity()
return false;
}
const char *classname = weaponDef->dict.GetString( "def_dropItem" );
if ( !classname[ 0 ] ) {
return false;
}
return true;
}
/*
================
idWeapon::WeaponStolen
================
*/
void idWeapon::WeaponStolen( void ) {
assert( !gameLocal.isClient );
//ivan start - always set WeaponDropped state
/*
//was:
if ( projectileEnt ) {
if ( isLinked ) {
SetState( "WeaponStolen", 0 );
thread->Execute();
}
projectileEnt = NULL;
}
*/
if ( isLinked ) {
SetState( "WeaponDropped", 0 );
thread->Execute();
}
if ( projectileEnt ) {
projectileEnt = NULL;
}
//ivan end
// set to holstered so we can switch weapons right away
status = WP_HOLSTERED;
HideWeapon();
}
/*
=====================
idWeapon::DropItem
=====================
*/
idEntity * idWeapon::DropItem( const idVec3 &velocity, int activateDelay, int removeDelay, bool died ) {
if ( !weaponDef ) { //|| !worldModel.GetEntity()
return NULL;
}
if ( !allowDrop ) {
return NULL;
}
const char *classname = weaponDef->dict.GetString( "def_dropItem" );
if ( !classname[0] ) {
return NULL;
}
StopSound( SND_CHANNEL_BODY, true );
StopSound( SND_CHANNEL_BODY3, true );
//ivan start
//was:
//idMoveableItem::DropItem( classname, worldModel.GetEntity()->GetPhysics()->GetOrigin(), worldModel.GetEntity()->GetPhysics()->GetAxis(), velocity, activateDelay, removeDelay );
return idMoveableItem::DropItem( classname, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), velocity, activateDelay, removeDelay );
//ivan end
}
/***********************************************************************
Script state management
***********************************************************************/
/*
=====================
idWeapon::SetState
=====================
*/
void idWeapon::SetState( const char *statename, int blendFrames ) {
const function_t *func;
if ( !isLinked ) {
return;
}
func = scriptObject.GetFunction( statename );
if ( !func ) {
assert( 0 );
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 = "";
}
/***********************************************************************
Particles/Effects
***********************************************************************/
/*
================
idWeapon::UpdateNozzelFx
================
*/
void idWeapon::UpdateNozzleFx( void ) {
if ( !nozzleFx ) {
return;
}
//
// shader parms
//
int la = gameLocal.time - lastAttack + 1;
float s = 1.0f;
float l = 0.0f;
if ( la < nozzleFxFade ) {
s = ((float)la / nozzleFxFade);
l = 1.0f - s;
}
renderEntity.shaderParms[5] = s;
renderEntity.shaderParms[6] = l;
/*
if ( ventLightJointView == INVALID_JOINT ) {
return;
}
//
// vent light
//
if ( nozzleGlowHandle == -1 ) {
memset(&nozzleGlow, 0, sizeof(nozzleGlow));
if ( owner ) {
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;
nozzleGlow.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f;
nozzleGlow.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
GetGlobalJointTransform( true, ventLightJointView, nozzleGlow.origin, nozzleGlow.axis );
nozzleGlowHandle = gameRenderWorld->AddLightDef(&nozzleGlow);
}
GetGlobalJointTransform( true, ventLightJointView, nozzleGlow.origin, nozzleGlow.axis );
nozzleGlow.shaderParms[ SHADERPARM_RED ] = nozzleGlowColor.x * s;
nozzleGlow.shaderParms[ SHADERPARM_GREEN ] = nozzleGlowColor.y * s;
nozzleGlow.shaderParms[ SHADERPARM_BLUE ] = nozzleGlowColor.z * s;
gameRenderWorld->UpdateLightDef(nozzleGlowHandle, &nozzleGlow);
*/
}
/*
================
idWeapon::BloodSplat
================
*/
bool idWeapon::BloodSplat( float size ) {
float s, c;
idMat3 localAxis, axistemp;
idVec3 localOrigin, normal;
if ( hasBloodSplat ) {
return true;
}
hasBloodSplat = true;
if ( modelDefHandle < 0 ) {
return false;
}
if ( !GetGlobalJointTransform( ejectJointWorld, localOrigin, localAxis ) ) { //ivan
//was: if ( !GetGlobalJointTransform( true, ejectJointView, localOrigin, localAxis ) ) {
return false;
}
localOrigin[0] += gameLocal.random.RandomFloat() * -10.0f;
localOrigin[1] += gameLocal.random.RandomFloat() * 1.0f;
localOrigin[2] += gameLocal.random.RandomFloat() * -2.0f;
normal = idVec3( gameLocal.random.CRandomFloat(), -gameLocal.random.RandomFloat(), -1 );
normal.Normalize();
idMath::SinCos16( gameLocal.random.RandomFloat() * idMath::TWO_PI, s, c );
localAxis[2] = -normal;
localAxis[2].NormalVectors( axistemp[0], axistemp[1] );
localAxis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s;
localAxis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c;
localAxis[0] *= 1.0f / size;
localAxis[1] *= 1.0f / size;
idPlane localPlane[2];
localPlane[0] = localAxis[0];
localPlane[0][3] = -(localOrigin * localAxis[0]) + 0.5f;
localPlane[1] = localAxis[1];
localPlane[1][3] = -(localOrigin * localAxis[1]) + 0.5f;
const idMaterial *mtr = declManager->FindMaterial( "textures/decals/duffysplatgun" );
gameRenderWorld->ProjectOverlay( modelDefHandle, localPlane, mtr );
return true;
}
/***********************************************************************
Visual presentation
***********************************************************************/
/*
================
idWeapon::MuzzleRise
The machinegun and chaingun will incrementally back up as they are being fired
================
void idWeapon::MuzzleRise( idVec3 &origin, idMat3 &axis ) {
int time;
float amount;
idAngles ang;
idVec3 offset;
time = kick_endtime - gameLocal.time;
if ( time <= 0 ) {
return;
}
if ( muzzle_kick_maxtime <= 0 ) {
return;
}
if ( time > muzzle_kick_maxtime ) {
time = muzzle_kick_maxtime;
}
amount = ( float )time / ( float )muzzle_kick_maxtime;
ang = muzzle_kick_angles * amount;
offset = muzzle_kick_offset * amount;
origin = origin - axis * offset;
axis = ang.ToMat3() * axis;
}
*/
/*
================
idWeapon::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 *idWeapon::ConstructScriptObject( void ) {
const function_t *constructor;
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;
}
/*
================
idWeapon::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 idWeapon::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();
}
/*
================
idWeapon::UpdateScript
================
*/
void idWeapon::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;
WEAPON_SPECIAL = false;
}
/*
================
idWeapon::AlertMonsters
================
*/
void idWeapon::AlertMonsters( void ) {
trace_t tr;
idEntity *ent;
/*
//was:
idVec3 end = muzzleFlash.origin + muzzleFlash.axis * muzzleFlash.target;
gameLocal.clip.TracePoint( tr, muzzleFlash.origin, end, CONTENTS_OPAQUE | MASK_SHOT_RENDERMODEL | CONTENTS_FLASHLIGHT_TRIGGER, owner );
if ( g_debugWeapon.GetBool() ) {
gameRenderWorld->DebugLine( colorYellow, muzzleFlash.origin, end, 0 );
gameRenderWorld->DebugArrow( colorGreen, muzzleFlash.origin, tr.endpos, 2, 0 );
}
*/
//ivan start
idVec3 end = worldMuzzleFlash.origin + worldMuzzleFlash.axis * worldMuzzleFlash.target;
gameLocal.clip.TracePoint( tr, worldMuzzleFlash.origin, end, CONTENTS_OPAQUE | MASK_SHOT_RENDERMODEL | CONTENTS_FLASHLIGHT_TRIGGER, owner );
if ( g_debugWeapon.GetBool() ) {
gameRenderWorld->DebugLine( colorYellow, worldMuzzleFlash.origin, end, 0 );
gameRenderWorld->DebugArrow( colorGreen, worldMuzzleFlash.origin, tr.endpos, 2, 0 );
}
//ivan end
if ( tr.fraction < 1.0f ) {
ent = gameLocal.GetTraceEntity( tr );
if ( ent->IsType( idAI::Type ) ) {
static_cast<idAI *>( ent )->TouchedByFlashlight( owner );
} else if ( ent->IsType( idTrigger::Type ) ) {
ent->Signal( SIG_TOUCH );
ent->ProcessEvent( &EV_Touch, owner, &tr );
}
}
// jitter the trace to try to catch cases where a trace down the center doesn't hit the monster
/*
//was:
end += muzzleFlash.axis * muzzleFlash.right * idMath::Sin16( MS2SEC( gameLocal.time ) * 31.34f );
end += muzzleFlash.axis * muzzleFlash.up * idMath::Sin16( MS2SEC( gameLocal.time ) * 12.17f );
gameLocal.clip.TracePoint( tr, muzzleFlash.origin, end, CONTENTS_OPAQUE | MASK_SHOT_RENDERMODEL | CONTENTS_FLASHLIGHT_TRIGGER, owner );
if ( g_debugWeapon.GetBool() ) {
gameRenderWorld->DebugLine( colorYellow, muzzleFlash.origin, end, 0 );
gameRenderWorld->DebugArrow( colorGreen, muzzleFlash.origin, tr.endpos, 2, 0 );
}
*/
//ivan start
end += worldMuzzleFlash.axis * worldMuzzleFlash.right * idMath::Sin16( MS2SEC( gameLocal.time ) * 31.34f );
end += worldMuzzleFlash.axis * worldMuzzleFlash.up * idMath::Sin16( MS2SEC( gameLocal.time ) * 12.17f );
gameLocal.clip.TracePoint( tr, worldMuzzleFlash.origin, end, CONTENTS_OPAQUE | MASK_SHOT_RENDERMODEL | CONTENTS_FLASHLIGHT_TRIGGER, owner );
if ( g_debugWeapon.GetBool() ) {
gameRenderWorld->DebugLine( colorYellow, worldMuzzleFlash.origin, end, 0 );
gameRenderWorld->DebugArrow( colorGreen, worldMuzzleFlash.origin, tr.endpos, 2, 0 );
}
//ivan end
if ( tr.fraction < 1.0f ) {
ent = gameLocal.GetTraceEntity( tr );
if ( ent->IsType( idAI::Type ) ) {
static_cast<idAI *>( ent )->TouchedByFlashlight( owner );
} else if ( ent->IsType( idTrigger::Type ) ) {
ent->Signal( SIG_TOUCH );
ent->ProcessEvent( &EV_Touch, owner, &tr );
}
}
}
//ivan start
/*
================
idWeapon::CalculateDynamicSpread
================
*/
void idWeapon::CalculateDynamicSpread( void ) {
if( spreadVelocityFactor > 0 ){
//float velocity = owner->GetPlayerPhysics()->GetLinearVelocity().LengthFast();
////Updated Rev 2018 for walk aiming Movement speed is no longer a factor. Spread changes depend on the player walking, running and crouching.
dynamicSpreadValue = spreadBaseValue + spreadVelocityFactor; //dynamicSpreadValue = spreadBaseValue + velocity * spreadVelocityFactor;
}else{
dynamicSpreadValue = spreadBaseValue;
}
if( owner->AI_CROUCH ){
dynamicSpreadValue = dynamicSpreadValue * spreadCrouchFactor;
}
if( owner->AI_RUN ){ //Added in 2018 by Rev for new walk aim system. We will just use crouch factor to set this instead of making a clone of it. Really no need for the extra code
dynamicSpreadValue = dynamicSpreadValue * spreadCrouchFactor;
}
//gameLocal.Printf("dynamicSpreadValue: %f\n", dynamicSpreadValue);
}
//ivan end
/*
================
idWeapon::PresentWeapon
================
*/
void idWeapon::PresentWeapon( bool showViewModel ) { //showViewModel is "ui_showGun". We want to make everything to work in 3th person even if this is false
playerViewOrigin = owner->firstPersonViewOrigin;
#ifdef USE_AIM_DIR_FIX
playerViewAxis = owner->fixedAimViewAxis;
#else
playerViewAxis = owner->firstPersonViewAxis;
#endif
/*
//ivan test start
if ( worldModel.GetEntity() ) {
gameLocal.Printf( "DIVERSITY: %f", worldModel.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_DIVERSITY ] );
gameLocal.Printf( " - TIMEOFFSET: %f", worldModel.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_TIMEOFFSET ] );
gameLocal.Printf( " - MODE: %f", worldModel.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_MODE ] );
gameLocal.Printf( " - TIMESCALE: %f", worldModel.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_TIMESCALE ] );
gameLocal.Printf( " - PARTICLE_STOPTIME: %f\n", worldModel.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] );
}
//ivan test end
*/
//ivan start
// calculate dynamic spread
CalculateDynamicSpread();
//ivan end
/*
//was:
// calculate weapon position based on player movement bobbing
owner->CalculateViewWeaponPos( viewWeaponOrigin, viewWeaponAxis ); //no: now weapon is bound to joint
// hide offset is for dropping the gun when approaching a GUI or NPC //no: now weapon is bound to joint
// This is simpler to manage than doing the weapon put-away animation
if ( gameLocal.time - hideStartTime < hideTime ) {
float frac = ( float )( gameLocal.time - hideStartTime ) / ( float )hideTime;
if ( hideStart < hideEnd ) {
frac = 1.0f - frac;
frac = 1.0f - frac * frac;
} else {
frac = frac * frac;
}
hideOffset = hideStart + ( hideEnd - hideStart ) * frac;
} else {
hideOffset = hideEnd;
if ( hide && disabled ) {
Hide();
}
}
viewWeaponOrigin += hideOffset * viewWeaponAxis[ 2 ];
// kick up based on repeat firing //no: now weapon is bound to joint
MuzzleRise( viewWeaponOrigin, viewWeaponAxis );
// set the physics position and orientation //no: now weapon is bound to joint
GetPhysics()->SetOrigin( viewWeaponOrigin );
GetPhysics()->SetAxis( viewWeaponAxis );
UpdateVisuals(); //not needed now?
*/
// update the weapon script
UpdateScript();
UpdateGUI();
// update animation
UpdateAnimation();
/*
//was:
// 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
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;
}
}
*/
//ivan start
Present(); //always show the model
renderEntity.suppressShadowInViewID = 0; //allow shadows
//ivan end
if ( nozzleFx ) {
UpdateNozzleFx();
}
// muzzle smoke
if ( !disabled && weaponSmoke && ( weaponSmokeStartTime != 0 ) ) {
// use the barrel joint if available
/*
//was:
//ivan start - try worldmodel first!
if ( barrelJointWorld != INVALID_JOINT ) { //ivan - compare with INVALID_JOINT !
GetGlobalJointTransform( false, barrelJointWorld, muzzleOrigin, muzzleAxis );
} else
//ivan end
if ( showViewModel && barrelJointView != INVALID_JOINT ) { //ivan - compare with INVALID_JOINT ! - showViewModel added
GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis );
} else {
// default to going straight out the view
muzzleOrigin = playerViewOrigin;
muzzleAxis = playerViewAxis;
}
*/
//ivan start
if ( barrelJointWorld != INVALID_JOINT ) { //compare with INVALID_JOINT !
GetGlobalJointTransform( barrelJointWorld, muzzleOrigin, muzzleAxis );
} else {
// default to going straight out the view
muzzleOrigin = playerViewOrigin;
muzzleAxis = playerViewAxis;
}
//ivan end
// spit out a particle
if ( !gameLocal.smokeParticles->EmitSmoke( weaponSmoke, weaponSmokeStartTime, gameLocal.random.RandomFloat(), muzzleOrigin, muzzleAxis ) ) {
weaponSmokeStartTime = ( continuousSmoke ) ? gameLocal.time : 0;
}
}
if ( strikeSmoke && strikeSmokeStartTime != 0 ) {
// spit out a particle
if ( !gameLocal.smokeParticles->EmitSmoke( strikeSmoke, strikeSmokeStartTime, gameLocal.random.RandomFloat(), strikePos, strikeAxis ) ) {
strikeSmokeStartTime = 0;
}
}
#ifdef _DENTONMOD
//ivan start
/*
//was:
if ( showViewModel && !disabled ) {
UpdateWeaponFx();
}
*/
//disabled flag ensures that fx wont be played when entering cinematic
if ( !disabled ) {
UpdateWeaponFx();
}
//ivan end
#endif //_DENTONMOD
//rev grab
// Update the grabber effects
if ( grabberState != -1 ) {
grabberState = grabber.Update( owner, hide );
}
//rev grab
// remove the muzzle flash light when it's done
if ( ( !lightOn && ( gameLocal.time >= muzzleFlashEnd ) ) || IsHidden() ) {
/*
if ( muzzleFlashHandle != -1 ) {
gameRenderWorld->FreeLightDef( muzzleFlashHandle );
muzzleFlashHandle = -1;
}
*/
if ( worldMuzzleFlashHandle != -1 ) {
gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle );
worldMuzzleFlashHandle = -1;
}
}
// update the muzzle flash light, so it moves with the gun
if ( worldMuzzleFlashHandle != -1 ) { //was: muzzleFlashHandle
UpdateFlashPosition();
//gameRenderWorld->UpdateLightDef( muzzleFlashHandle, &muzzleFlash );
gameRenderWorld->UpdateLightDef( worldMuzzleFlashHandle, &worldMuzzleFlash );
// wake up monsters with the flashlight
if ( !gameLocal.isMultiplayer && lightOn && !owner->fl.notarget ) {
AlertMonsters();
}
}
/*
// update the gui light
if ( guiLight.lightRadius[0] && guiLightJointView != INVALID_JOINT ) {
GetGlobalJointTransform( true, guiLightJointView, guiLight.origin, guiLight.axis );
if ( ( guiLightHandle != -1 ) ) {
gameRenderWorld->UpdateLightDef( guiLightHandle, &guiLight );
} else {
guiLightHandle = gameRenderWorld->AddLightDef( &guiLight );
}
}
*/
if ( status != WP_READY && sndHum ) {
StopSound( SND_CHANNEL_BODY, false );
}
UpdateSound();
//ivan start
if ( autoMeleeEnabled && !disabled ) { //no in cinematic
EvaluateMelee();
}
#ifdef TRAIL_FX_CHAIN
//the beams'chain is updated inside EvaluateMelee();
#else
if( trailGen->IsEnabled() ){
UpdateTrailVerts();
}
#endif
//ivan end
}
//Ivan start
/*
=====================
idWeapon::StartAutoMelee
=====================
*/
void idWeapon::StartAutoMelee( float dmgMult, int trailNum ) {
if ( g_debugWeapon.GetBool() ) {
gameLocal.Printf("idWeapon::StartAutoMelee - dmgMult: %f,trailNum: %d - time:%d\n", dmgMult, trailNum, gameLocal.time);
}
comboMultiplier = dmgMult;
lastMeleeEnt = NULL; //reset it so that can be hit again
autoMeleeEnabled = true;
nextStrikeFx = gameLocal.time + 100; //delay snd+prt for LOW priority entities after the beginning of the attack
nextMeleeSnd = gameLocal.time + 100; //don't play snd on world too early - this could not be used
//-- trail --
//make sure no trail is started if there is ever started if there is no melee joint
if ( meleeJointWorld == INVALID_JOINT ) {
return;
}
#ifdef TRAIL_FX_CHAIN
lastBeamInChain = NULL; //next node will be the first of the chain. This also allows the beam type to change.
trailNumType = ( trailNum >= 0 ) ? trailNum : TRAIL_NONE;
#else
if ( trailNum < 0 ){ //no trail. stop the current one, if any.
if( trailGen->IsEnabled() ){
trailGen->FadeTrail();
}
trailNumType = TRAIL_NONE;
}else{
if( trailNumType == trailNum ){ //last trail type used was exactly this one
trailGen->RestartTrail(); //this is faster
}else{
trailGen->StartTrail( weaponDef->dict.GetString( va( "def_trail%d", trailNum ) ) );
}
trailNumType = trailNum;
#ifdef TEST_TRAIL
if( trailNumType != 0){
//random remove test
int randPos = 1 + gameLocal.random.RandomInt( 8 ); //never remove the first one... weapon is using it
idTrailGenerator* toRemove = gameLocal.trailsManager->FindTrailByLocalPos( randPos );
gameLocal.trailsManager->RemoveTrailGen( toRemove );
toRemove = NULL;
}else{
//create new test
testGen = gameLocal.trailsManager->NewTrailGen();
testGen->StartTrail( weaponDef->dict.GetString( va( "def_trail%d", trailNum ) ) );
}
#endif
}
#endif
}
/*
=====================
idWeapon::StopAutoMelee
=====================
*/
void idWeapon::StopAutoMelee( void ) {
comboMultiplier = 1.0f;
lastMeleeEnt = NULL; //don't remember it in the future
autoMeleeEnabled = false;
//beam
#ifdef TRAIL_FX_CHAIN
trailNumType = TRAIL_NONE; //turn off the trail
lastBeamInChain = NULL; //next node will be the first of the chain. This also allows the beam type to change.
#else
//note: don't set trailNumType = TRAIL_NONE in this case.
//The trail will start fading and could be restored wihout changing the type.
if( trailGen->IsEnabled() ){
trailGen->FadeTrail();
}
#endif
}
/*
=====================
idWeapon::Event_StartAutoMelee
=====================
*/
void idWeapon::Event_StartAutoMelee( float dmgMult, int trailNum ) {
StartAutoMelee( dmgMult, trailNum );
}
/*
=====================
idWeapon::Event_StopAutoMelee
=====================
*/
void idWeapon::Event_StopAutoMelee( void ) {
StopAutoMelee();
}
#ifdef TRAIL_FX_CHAIN
/*
=====================
idWeapon::SpawnMeleeBeam
NOTE: this only spawns the first elem of the chain. The other will be just a copy of this one.
=====================
*/
idBeam * idWeapon::SpawnMeleeBeam( const idVec3 &pos ) {
idEntity *ent;
const char *classname = weaponDef->dict.GetString( va( "def_meleeBeam%d", trailNumType ) );
if ( !classname[0] ) {
return NULL;
}
const idDict *beam_args = gameLocal.FindEntityDefDict( classname, false );
if ( !beam_args ) {
gameLocal.Error( "Unknown classname '%s'", classname );
}
gameLocal.SpawnEntityDef( *beam_args, &ent, false );
if ( !ent || !ent->IsType( idBeam::Type ) ) {
gameLocal.Error( "Beam entity is not an idBeam" );
}
ent->SetOrigin(pos);
//gameLocal.Printf("Created first node at '%s'\n", pos.ToString() );
return ( static_cast< idBeam *>( ent ) );
}
#else
//custom geometry trail only
void idWeapon::UpdateTrailVerts( void ) {
//meleeJointWorld should be a valid joint. It is checked when we try to start a trail.
GetGlobalJointTransform( meleeJointWorld, meleeJointOrigin, meleeJointAxis ); //to do: upd this somewhere else?
trailGen->AddNewPoints( meleeJointOrigin + meleeJointAxis[0] * trailLowOffset, meleeJointOrigin + meleeJointAxis[0] * trailHighOffset );
#ifdef TEST_TRAIL
if( testGen && testGen->IsEnabled() ){
testGen->AddNewPoints( meleeJointOrigin + meleeJointAxis[0] * 20, meleeJointOrigin + meleeJointAxis[0] * 50);
}
#endif
}
#endif
/*
=====================
idWeapon::EvaluateMelee
=====================
*/
bool idWeapon::EvaluateMelee( void ) {
idEntity *ent;
trace_t tr;
if ( !meleeDef ) {
gameLocal.Error( "No meleeDef on '%s'", weaponDef->dict.GetString( "classname" ) );
}
if ( !gameLocal.isClient ) {
idVec3 start;
idVec3 end;
//get origin end axis of the joint "melee" if available
if ( meleeJointWorld == INVALID_JOINT ) {
//gameLocal.Printf( "idWeapon::EvaluateMelee - Invalid joint 'melee' \n" );
start = playerViewOrigin;
end = start + playerViewAxis[0] * ( meleeDistance * owner->PowerUpModifier( MELEE_DISTANCE ) );
}else{
GetGlobalJointTransform( meleeJointWorld, meleeJointOrigin, meleeJointAxis ); //to do: upd this somewhere else?
start = meleeJointOrigin;
end = start + meleeJointAxis[0] * ( meleeDistance * owner->PowerUpModifier( MELEE_DISTANCE ) );
//gameLocal.Printf( "idWeapon::EvaluateMelee - start %f %f %f \n",start[0],start[1],start[2] );
}
#ifdef TRAIL_FX_CHAIN
//fx test start
if( trailNumType != TRAIL_NONE ){
idVec3 beamPos;
if ( meleeJointWorld == INVALID_JOINT ) { //this should not happen...
beamPos = end;
}else{
beamPos = start + meleeJointAxis[0] * ( meleeDistance/2 );
}
if( lastBeamInChain.GetEntity() ){
lastBeamInChain = lastBeamInChain.GetEntity()->AddChainNodeAtPos( beamPos );
}else{ //first one!
lastBeamInChain = SpawnMeleeBeam( beamPos );
}
if( lastBeamInChain.GetEntity() ){
//NOTE: make sure they auto-remove themself!
lastBeamInChain.GetEntity()->PostEventMS( &EV_FadeBeamColor, 1 ); //wait 1 frame so it has time to check its targets!
}
}
//fx test end
#endif
if(useMeleeBox){
gameLocal.clip.TraceBounds( tr, start, end, meleebox, MASK_SHOT_RENDERMODEL, owner ); //ignore player
}else{
gameLocal.clip.TracePoint( tr, start, end, MASK_SHOT_RENDERMODEL, owner ); //ignore player
}
if ( tr.fraction < 1.0f ) {
ent = gameLocal.entities[ tr.c.entityNum ]; //fix the headshot bug with melee attacks
if(( ent ) && !(ent->IsType( idAFAttachment::Type))){ //only if it's not an idAFAttachment
ent = gameLocal.GetTraceEntity( tr );
}
} else {
ent = NULL;
}
if ( g_debugWeapon.GetBool() ) {
gameRenderWorld->DebugLine( colorYellow, start, end, 100 );
if(useMeleeBox){
gameRenderWorld->DebugBounds( colorBlue,meleebox, start, 100 );
gameRenderWorld->DebugBounds( colorBlue,meleebox, end, 100 );
}
if ( ent ) {
gameRenderWorld->DebugBounds( colorRed, ent->GetPhysics()->GetBounds(), ent->GetPhysics()->GetOrigin(), 100 );
}
}
bool hit = false;
const char *hitSound = meleeDef->dict.GetString( "snd_miss" );
if ( ent ) { //something hit
//gameLocal.Printf( "idWeapon::EvaluateMelee - ent = %s \n",ent->GetName());
if(autoMeleeEnabled &&( ent == lastMeleeEnt)){ //ignore the last entity hit
//gameLocal.Printf( "idWeapon::EvaluateMelee - entity ignored\n" );
return true; //we hit the same thing again... do nothing now.
}
//gameLocal.Printf( "idWeapon::EvaluateMelee - ent = %s \n",ent->GetName());
if ( gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) && ( ent->IsType( idActor::Type ) || ent->IsType( idAFAttachment::Type) ) ) { //no melee if noweapons = 1?
autoMeleeEnabled = false; //make sure
return false;
}
// weapon stealing - do this before damaging so weapons are not dropped twice - disabled if autoMeleeEnabled
if ( !autoMeleeEnabled
&& gameLocal.isMultiplayer
&& weaponDef && weaponDef->dict.GetBool( "stealing" )
&& ent->IsType( idPlayer::Type )
&& !owner->PowerUpActive( BERSERK )
&& ( gameLocal.gameType != GAME_TDM || gameLocal.serverInfo.GetBool( "si_teamDamage" ) || ( owner->team != static_cast< idPlayer * >( ent )->team ) )
) {
owner->StealWeapon( static_cast< idPlayer * >( ent ) );
}
if ( ent->fl.takedamage ) {
idVec3 kickDir, globalKickDir;
meleeDef->dict.GetVector( "kickDir", "0 0 0", kickDir );
globalKickDir = muzzleAxis * kickDir;
//Ivan fix - transform clipmodel to joint handle to correctly get the damage zone in idActor::Damage
//was: ent->Damage( owner, owner, globalKickDir, meleeDefName, owner->PowerUpModifier( MELEE_DAMAGE ), tr.c.id );
ent->Damage( owner, owner, globalKickDir, meleeDefName, (comboMultiplier * owner->PowerUpModifier( MELEE_DAMAGE )) , CLIPMODEL_ID_TO_JOINT_HANDLE( tr.c.id ) );
lastMeleeEnt = ent; //remember this to avoid hitting it consecutively
hit = true;
}
//push
float push = meleeDef->dict.GetFloat( "push" );
idVec3 impulse = -push * owner->PowerUpModifier( SPEED ) * tr.c.normal;
//extra push for AFs
if( (ent->health <= 0) && (ent->IsType(idAFEntity_Base::Type)) ){
idAFEntity_Base *p = static_cast< idAFEntity_Base * >( ent );
if ( p->IsActiveAF() ){
//gameLocal.Printf( "p->IsActiveAF()\n" );
impulse *= meleeDef->dict.GetInt( "pushAFMult","1" );
//quinak and dirty fix for flying ragdolls
/*
if(impulse.z > 70000 ){
impulse.z = 70000,
}else if( impulse.z < -70000 ){
impulse.z = -70000,
}
*/
//gameLocal.Printf( "idWeapon::EvaluateMelee - impulse: %s, lenght: %f\n", impulse.ToString(), impulse.Length() );
}
}
ent->ApplyImpulse( this, tr.c.id, tr.c.point, impulse );
if ( weaponDef->dict.GetBool( "impact_damage_effect" ) ) {
/* ivan - was:
if ( ent->spawnArgs.GetBool( "bleed" ) ) {
hitSound = meleeDef->dict.GetString( owner->PowerUpActive( BERSERK ) ? "snd_hit_berserk" : "snd_hit" );
ent->AddDamageEffect( tr, impulse, meleeDef->dict.GetString( "classname" ) );
} */
//case 1/3: HIGH priority entities: ALWAYS play the snd and the prt on them, unless 'bleed' key is set to '0'. (sword or chainsaw on HIGH priority entities)
if ( (ent->IsType(idBrittleFracture::Type) || ent->IsType(idAnimatedEntity::Type) || ent->IsType(idMoveable::Type) || ent->IsType(idMoveableItem::Type)) && ent->spawnArgs.GetBool( "bleed", "1" ) ) {
nextStrikeFx = gameLocal.time + 500; ///delay snd+prt for LOW priority entities after an hit on HIGH priority entity
hitSound = meleeDef->dict.GetString( owner->PowerUpActive( BERSERK ) ? "snd_hit_berserk" : "snd_hit" );
ent->AddDamageEffect( tr, impulse, meleeDef->dict.GetString( "classname" ) ); //play the sound from the entity hit!
hitSound = ""; //don't play hitsound because AddDamageEffect already plays its own sound
}
//case 2/3: (LOW priority entities + we don't have our own .prt to show) AND (can bleed) -> play the snd and the prt less frequently - (example: sword on LOW priority entities)
else if (strikeSmoke == NULL && ent->spawnArgs.GetBool( "bleed", "1" )){ // Again, this is not done if 'bleed' key is set to '0'.
if (( gameLocal.time > nextStrikeFx ) ){ //this is usually the worldspawn... don't play too much snd and prt on it!
nextStrikeFx = gameLocal.time + 300; //delay snd+prt for LOW priority entities after an hit on LOW priority entity
hitSound = meleeDef->dict.GetString( owner->PowerUpActive( BERSERK ) ? "snd_hit_berserk" : "snd_hit" );
ent->AddDamageEffect( tr, impulse, meleeDef->dict.GetString( "classname" ), this ); //play the sound from the weapon itself!
hitSound = ""; //don't play hitsound because AddDamageEffect already plays its own sound from the weapon
}
}
//case 3/3: (LOW priority entities + we have our own .prt to show) OR (cannot bleed) -> play our snd and our prt less frequently (example: chainsaw on LOW priority entities)
else {
int type = tr.c.material->GetSurfaceType();
if ( type == SURFTYPE_NONE ) {
type = GetDefaultSurfaceType();
}
const char *materialType = gameLocal.sufaceTypeNames[ type ];
// start impact sound based on material type
hitSound = meleeDef->dict.GetString( va( "snd_%s", materialType ) );
if ( *hitSound == '\0' ) {
hitSound = meleeDef->dict.GetString( "snd_metal" );
}
if ( gameLocal.time > nextStrikeFx ) {
const char *decal;
// project decal
decal = weaponDef->dict.GetString( "mtr_strike" );
if ( decal && *decal ) {
gameLocal.ProjectDecal( tr.c.point, -tr.c.normal, 8.0f, true, 6.0, decal );
}
nextStrikeFx = gameLocal.time + 200;
} else {
hitSound = "";
}
strikeSmokeStartTime = gameLocal.time;
strikePos = tr.c.point;
strikeAxis = -tr.endAxis;
}
}
}
//always play sound if autoMelee is disabled, otherwise only if (we damaged something ) or (hit something not damaged, as world, and we are beyond the min time)
if( (hit) || (ent && gameLocal.time > nextMeleeSnd ) || (!autoMeleeEnabled )) {
if ( *hitSound != '\0' ) {
const idSoundShader *snd = declManager->FindSound( hitSound );
StartSoundShader( snd, SND_CHANNEL_BODY2, 0, true, NULL );
nextMeleeSnd = gameLocal.time + 1000;
}
}
if(!autoMeleeEnabled){ owner->WeaponFireFeedback( &weaponDef->dict ); } //autoMeleeEnabled --> no need for feedback
return hit;
}
if(!autoMeleeEnabled){ owner->WeaponFireFeedback( &weaponDef->dict ); } //autoMeleeEnabled --> no need for feedback
return false;
}
//Ivan end
/*
================
idWeapon::EnterCinematic
================
*/
void idWeapon::EnterCinematic( void ) {
StopSound( SND_CHANNEL_ANY, false );
#ifdef _DENTONMOD
StopWeaponFx();
#endif
if ( isLinked ) {
SetState( "EnterCinematic", 0 );
thread->Execute();
WEAPON_ATTACK = false;
WEAPON_SPECIAL = false; // new
WEAPON_SPECIAL_HOLD = false; // new
WEAPON_RELOAD = false;
WEAPON_NETRELOAD = false;
WEAPON_NETENDRELOAD = false;
WEAPON_NETFIRING = false;
WEAPON_RAISEWEAPON = false;
WEAPON_LOWERWEAPON = false;
//rev grab
grabber.Update( this->GetOwner(), true );
//rev grab
}
disabled = true;
autoMeleeEnabled = false; //ivan - disable in cinematic
LowerWeapon();
}
/*
================
idWeapon::ExitCinematic
================
*/
void idWeapon::ExitCinematic( void ) {
disabled = false;
if ( isLinked ) {
SetState( "ExitCinematic", 0 );
thread->Execute();
}
RaiseWeapon();
}
/*
================
idWeapon::NetCatchup
================
*/
void idWeapon::NetCatchup( void ) {
if ( isLinked ) {
SetState( "NetCatchup", 0 );
thread->Execute();
}
}
/*
================
idWeapon::GetZoomFov
================
*/
int idWeapon::GetZoomFov( void ) {
return zoomFov;
}
/*
================
idWeapon::GetWeaponAngleOffsets
================
*/
void idWeapon::GetWeaponAngleOffsets( int *average, float *scale, float *max ) {
*average = weaponAngleOffsetAverages;
*scale = weaponAngleOffsetScale;
*max = weaponAngleOffsetMax;
}
/*
================
idWeapon::GetWeaponTimeOffsets
================
*/
void idWeapon::GetWeaponTimeOffsets( float *time, float *scale ) {
*time = weaponOffsetTime;
*scale = weaponOffsetScale;
}
/***********************************************************************
Ammo
***********************************************************************/
/*
================
idWeapon::GetAmmoNumForName
================
*/
ammo_t idWeapon::GetAmmoNumForName( const char *ammoname ) {
int num;
const idDict *ammoDict;
assert( ammoname );
ammoDict = gameLocal.FindEntityDefDict( "ammo_types", false );
if ( !ammoDict ) {
gameLocal.Error( "Could not find entity definition for 'ammo_types'\n" );
}
if ( !ammoname[ 0 ] ) {
return 0;
}
if ( !ammoDict->GetInt( ammoname, "-1", num ) ) {
gameLocal.Error( "Unknown ammo type '%s'", ammoname );
}
if ( ( num < 0 ) || ( num >= AMMO_NUMTYPES ) ) {
gameLocal.Error( "Ammo type '%s' value out of range. Maximum ammo types is %d.\n", ammoname, AMMO_NUMTYPES );
}
return ( ammo_t )num;
}
/*
================
idWeapon::GetAmmoNameForNum
================
*/
const char *idWeapon::GetAmmoNameForNum( ammo_t ammonum ) {
int i;
int num;
const idDict *ammoDict;
const idKeyValue *kv;
char text[ 32 ];
ammoDict = gameLocal.FindEntityDefDict( "ammo_types", false );
if ( !ammoDict ) {
gameLocal.Error( "Could not find entity definition for 'ammo_types'\n" );
}
sprintf( text, "%d", ammonum );
num = ammoDict->GetNumKeyVals();
for( i = 0; i < num; i++ ) {
kv = ammoDict->GetKeyVal( i );
if ( kv->GetValue() == text ) {
return kv->GetKey();
}
}
return NULL;
}
/*
================
idWeapon::GetAmmoPickupNameForNum
================
*/
const char *idWeapon::GetAmmoPickupNameForNum( ammo_t ammonum ) {
int i;
int num;
const idDict *ammoDict;
const idKeyValue *kv;
ammoDict = gameLocal.FindEntityDefDict( "ammo_names", false );
if ( !ammoDict ) {
gameLocal.Error( "Could not find entity definition for 'ammo_names'\n" );
}
const char *name = GetAmmoNameForNum( ammonum );
if ( name && *name ) {
num = ammoDict->GetNumKeyVals();
for( i = 0; i < num; i++ ) {
kv = ammoDict->GetKeyVal( i );
if ( idStr::Icmp( kv->GetKey(), name) == 0 ) {
return kv->GetValue();
}
}
}
return "";
}
/*
================
idWeapon::AmmoAvailable
================
*/
int idWeapon::AmmoAvailable( void ) const {
if ( owner ) {
//ivan - this was wrong! everyone expects this being the real amount of ammo avalable, including clip!
return owner->inventory.HasAmmo( ammoType, ammoRequired );
} else {
return 0;
}
}
/*
================
idWeapon::AmmoInClip
================
*/
int idWeapon::AmmoInClip( void ) const {
return ammoClip;
}
//ivan start
/*
================
idWeapon::GetMaxAmmo
================
*/
int idWeapon::GetMaxAmmo( void ) const {
return maxAmmo;
}
//ivan end
/*
================
idWeapon::ResetAmmoClip
================
*/
void idWeapon::ResetAmmoClip( void ) {
ammoClip = -1;
}
/*
================
idWeapon::GetAmmoType
================
*/
ammo_t idWeapon::GetAmmoType( void ) const {
return ammoType;
}
/*
================
idWeapon::ClipSize
================
*/
int idWeapon::ClipSize( void ) const {
return clipSize;
}
/*
================
idWeapon::LowAmmo
================
*/
int idWeapon::LowAmmo() const {
return lowAmmo;
}
/*
================
idWeapon::AmmoRequired
================
*/
int idWeapon::AmmoRequired( void ) const {
return ammoRequired;
}
//REV GRAB START
/*
================
idWeapon::GetGrabberState
Returns the current grabberState
================
*/
int idWeapon::GetGrabberState( void ) const {
return grabberState;
}
//REV GRAB END
/*
================
idWeapon::WriteToSnapshot
================
*/
void idWeapon::WriteToSnapshot( idBitMsgDelta &msg ) const {
msg.WriteBits( ammoClip, ASYNC_PLAYER_INV_CLIP_BITS );
//msg.WriteBits( worldModel.GetSpawnId(), 32 );
msg.WriteBits( lightOn, 1 );
msg.WriteBits( isFiring ? 1 : 0, 1 );
}
/*
================
idWeapon::ReadFromSnapshot
================
*/
void idWeapon::ReadFromSnapshot( const idBitMsgDelta &msg ) {
ammoClip = msg.ReadBits( ASYNC_PLAYER_INV_CLIP_BITS );
//worldModel.SetSpawnId( msg.ReadBits( 32 ) );
bool snapLight = msg.ReadBits( 1 ) != 0;
isFiring = msg.ReadBits( 1 ) != 0;
// WEAPON_NETFIRING is only turned on for other clients we're predicting. not for local client
if ( owner && gameLocal.localClientNum != owner->entityNumber && WEAPON_NETFIRING.IsLinked() ) {
// immediately go to the firing state so we don't skip fire animations
if ( !WEAPON_NETFIRING && isFiring ) {
idealState = "Fire";
}
// immediately switch back to idle
if ( WEAPON_NETFIRING && !isFiring ) {
idealState = "Idle";
}
WEAPON_NETFIRING = isFiring;
}
if ( snapLight != lightOn ) {
Reload();
}
}
/*
================
idWeapon::ClientReceiveEvent
================
*/
bool idWeapon::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
switch( event ) {
case EVENT_RELOAD: {
if ( gameLocal.time - time < 1000 ) {
if ( WEAPON_NETRELOAD.IsLinked() ) {
WEAPON_NETRELOAD = true;
WEAPON_NETENDRELOAD = false;
}
}
return true;
}
case EVENT_ENDRELOAD: {
if ( WEAPON_NETENDRELOAD.IsLinked() ) {
WEAPON_NETENDRELOAD = true;
}
return true;
}
case EVENT_CHANGESKIN: {
int index = gameLocal.ClientRemapDecl( DECL_SKIN, msg.ReadInt() );
renderEntity.customSkin = ( index != -1 ) ? static_cast<const idDeclSkin *>( declManager->DeclByIndex( DECL_SKIN, index ) ) : NULL;
UpdateVisuals();
/*
if ( worldModel.GetEntity() ) {
worldModel.GetEntity()->SetSkin( renderEntity.customSkin );
}
*/
return true;
}
default:
break;
}
return idEntity::ClientReceiveEvent( event, time, msg );
}
/***********************************************************************
Script events
***********************************************************************/
/*
===============
idWeapon::Event_Clear
===============
*/
void idWeapon::Event_Clear( void ) {
Clear();
}
/*
===============
idWeapon::Event_GetOwner
===============
*/
void idWeapon::Event_GetOwner( void ) {
idThread::ReturnEntity( owner );
}
/*
===============
idWeapon::Event_WeaponState
===============
*/
void idWeapon::Event_WeaponState( const char *statename, int blendFrames ) {
const function_t *func;
func = scriptObject.GetFunction( statename );
if ( !func ) {
assert( 0 );
gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() );
}
idealState = statename;
//ivan start
/* was:
if ( !idealState.Icmp( "Fire" ) ) {
isFiring = true;
} else {
isFiring = false;
} */
//ivan start
if ( !idealState.Icmp( "Fire" ) ) {
isFiring = true;
isSecFiring = false;
} else if ( !idealState.Icmp( "SecFire" ) ) {
isFiring = false;
isSecFiring = true;
} else {
isFiring = false;
isSecFiring = false;
}
//ivan end
animBlendFrames = blendFrames;
thread->DoneProcessing();
}
/*
===============
idWeapon::Event_WeaponReady
===============
*/
void idWeapon::Event_WeaponReady( void ) {
status = WP_READY;
if ( isLinked ) {
WEAPON_RAISEWEAPON = false;
}
if ( sndHum ) {
StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL );
}
}
/*
===============
idWeapon::Event_WeaponOutOfAmmo
===============
*/
void idWeapon::Event_WeaponOutOfAmmo( void ) {
status = WP_OUTOFAMMO;
if ( isLinked ) {
WEAPON_RAISEWEAPON = false;
}
}
/*
===============
idWeapon::Event_WeaponReloading
===============
*/
void idWeapon::Event_WeaponReloading( void ) {
status = WP_RELOAD;
}
/*
===============
idWeapon::Event_WeaponHolstered
===============
*/
void idWeapon::Event_WeaponHolstered( void ) {
status = WP_HOLSTERED;
if ( isLinked ) {
WEAPON_LOWERWEAPON = false;
}
}
/*
===============
idWeapon::Event_WeaponRising
===============
*/
void idWeapon::Event_WeaponRising( void ) {
status = WP_RISING;
if ( isLinked ) {
WEAPON_LOWERWEAPON = false;
}
owner->WeaponRisingCallback();
}
/*
===============
idWeapon::Event_WeaponLowering
===============
*/
void idWeapon::Event_WeaponLowering( void ) {
status = WP_LOWERING;
if ( isLinked ) {
WEAPON_RAISEWEAPON = false;
}
owner->WeaponLoweringCallback();
}
/*
===============
idWeapon::Event_UseAmmo
===============
*/
void idWeapon::Event_UseAmmo( int amount ) {
if ( gameLocal.isClient ) {
return;
}
//#ifdef _DENTONMOD
//#else
owner->inventory.UseAmmo( ammoType, ( powerAmmo ) ? amount : ( amount * ammoRequired ) );
//#endif
if ( clipSize && ammoRequired ) {
ammoClip -= powerAmmo ? amount : ( amount * ammoRequired );
if ( ammoClip < 0 ) {
//#ifdef _DENTONMOD
// Now, the ammo in clip is separate from that of ammo in inventory. So when the ammo is removed from clip,
// only remove remaining ammo from the inventory
// owner->inventory.UseAmmo( ammoType, -ammoClip );
//#endif
ammoClip = 0;
}
}
}
/*
===============
idWeapon::Event_AddToClip
===============
*/
void idWeapon::Event_AddToClip( int amount ) {
int ammoAvail;
if ( gameLocal.isClient ) {
return;
}
/*
//ivan - commented out
int oldAmmo = ammoClip;
ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired );
ammoClip += amount;
if ( ammoClip > clipSize ) {
ammoClip = clipSize;
}
if ( ammoClip > ammoAvail ) {
ammoClip = ammoAvail;
}
// for shared ammo we need to use the ammo when it is moved into the clip
int usedAmmo = ammoClip - oldAmmo;
owner->inventory.UseAmmo(ammoType, usedAmmo);
*/
ammoClip += amount;
if ( ammoClip > clipSize ) {
ammoClip = clipSize;
}
ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired );
if ( ammoClip > ammoAvail ) {
ammoClip = ammoAvail;
}
//ivan end
}
/*
===============
idWeapon::Event_AmmoInClip
===============
*/
void idWeapon::Event_AmmoInClip( void ) {
int ammo = AmmoInClip();
idThread::ReturnFloat( ammo );
}
/*
===============
idWeapon::Event_AmmoAvailable
===============
*/
void idWeapon::Event_AmmoAvailable( void ) {
int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired );
//ivan - out: ammoAvail += AmmoInClip();
idThread::ReturnFloat( ammoAvail );
}
/*
===============
idWeapon::Event_TotalAmmoCount
===============
*/
void idWeapon::Event_TotalAmmoCount( void ) {
int ammoAvail = owner->inventory.HasAmmo( ammoType, 1 );
idThread::ReturnFloat( ammoAvail );
}
/*
===============
idWeapon::Event_ClipSize
===============
*/
void idWeapon::Event_ClipSize( void ) {
idThread::ReturnFloat( clipSize );
}
/*
===============
idWeapon::Event_AutoReload
===============
*/
void idWeapon::Event_AutoReload( void ) {
assert( owner );
if ( gameLocal.isClient ) {
idThread::ReturnFloat( 0.0f );
return;
}
idThread::ReturnFloat( gameLocal.userInfo[ owner->entityNumber ].GetBool( "ui_autoReload" ) );
}
/*
===============
idWeapon::Event_NetReload
===============
*/
void idWeapon::Event_NetReload( void ) {
assert( owner );
if ( gameLocal.isServer ) {
ServerSendEvent( EVENT_RELOAD, NULL, false, -1 );
}
}
/*
===============
idWeapon::Event_NetEndReload
===============
*/
void idWeapon::Event_NetEndReload( void ) {
assert( owner );
if ( gameLocal.isServer ) {
ServerSendEvent( EVENT_ENDRELOAD, NULL, false, -1 );
}
}
/*
===============
idWeapon::Event_PlayAnim
===============
*/
void idWeapon::Event_PlayAnim( int channel, const char *animname ) {
int anim;
anim = animator.GetAnim( animname );
if ( !anim ) {
gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
animator.Clear( channel, gameLocal.time, FRAME2MS( animBlendFrames ) );
animDoneTime = 0;
} else {
if ( !( owner && owner->GetInfluenceLevel() ) ) {
Show();
}
animator.PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
animDoneTime = animator.CurrentAnim( channel )->GetEndTime();
/*
if ( worldModel.GetEntity() ) {
anim = worldModel.GetEntity()->GetAnimator()->GetAnim( animname );
if ( anim ) {
worldModel.GetEntity()->GetAnimator()->PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
}
}
*/
}
animBlendFrames = 0;
idThread::ReturnInt( 0 );
}
/*
===============
idWeapon::Event_PlayCycle
===============
*/
void idWeapon::Event_PlayCycle( int channel, const char *animname ) {
int anim;
anim = animator.GetAnim( animname );
if ( !anim ) {
gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
animator.Clear( channel, gameLocal.time, FRAME2MS( animBlendFrames ) );
animDoneTime = 0;
} else {
if ( !( owner && owner->GetInfluenceLevel() ) ) {
Show();
}
animator.CycleAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
animDoneTime = animator.CurrentAnim( channel )->GetEndTime();
/*
if ( worldModel.GetEntity() ) {
anim = worldModel.GetEntity()->GetAnimator()->GetAnim( animname );
worldModel.GetEntity()->GetAnimator()->CycleAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
}
*/
}
animBlendFrames = 0;
idThread::ReturnInt( 0 );
}
/*
===============
idWeapon::Event_AnimDone
===============
*/
void idWeapon::Event_AnimDone( int channel, int blendFrames ) {
if ( animDoneTime - FRAME2MS( blendFrames ) <= gameLocal.time ) {
idThread::ReturnInt( true );
} else {
idThread::ReturnInt( false );
}
}
/*
===============
idWeapon::Event_SetBlendFrames
===============
*/
void idWeapon::Event_SetBlendFrames( int channel, int blendFrames ) {
animBlendFrames = blendFrames;
}
/*
===============
idWeapon::Event_GetBlendFrames
===============
*/
void idWeapon::Event_GetBlendFrames( int channel ) {
idThread::ReturnInt( animBlendFrames );
}
/*
================
idWeapon::Event_Next
================
*/
void idWeapon::Event_Next( void ) {
// change to another weapon if possible
owner->NextBestWeapon();
}
/*
================
idWeapon::Event_SetSkin
================
*/
void idWeapon::Event_SetSkin( const char *skinname ) {
const idDeclSkin *skinDecl;
if ( !skinname || !skinname[ 0 ] ) {
skinDecl = NULL;
} else {
skinDecl = declManager->FindSkin( skinname );
}
renderEntity.customSkin = skinDecl;
UpdateVisuals();
/*
if ( worldModel.GetEntity() ) {
worldModel.GetEntity()->SetSkin( skinDecl );
}
*/
if ( gameLocal.isServer ) {
idBitMsg msg;
byte msgBuf[MAX_EVENT_PARAM_SIZE];
msg.Init( msgBuf, sizeof( msgBuf ) );
msg.WriteInt( ( skinDecl != NULL ) ? gameLocal.ServerRemapDecl( -1, DECL_SKIN, skinDecl->Index() ) : -1 );
ServerSendEvent( EVENT_CHANGESKIN, &msg, false, -1 );
}
}
/*
================
idWeapon::Event_Flashlight
================
*/
void idWeapon::Event_Flashlight( int enable ) {
if ( enable ) {
lightOn = true;
MuzzleFlashLight();
} else {
lightOn = false;
muzzleFlashEnd = 0;
}
}
/*
================
idWeapon::Event_GetLightParm
================
*/
void idWeapon::Event_GetLightParm( int parmnum ) {
if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
gameLocal.Error( "shader parm index (%d) out of range", parmnum );
}
idThread::ReturnFloat( worldMuzzleFlash.shaderParms[ parmnum ] ); //was muzzleFlash
}
/*
================
idWeapon::Event_SetLightParm
================
*/
void idWeapon::Event_SetLightParm( int parmnum, float value ) {
if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
gameLocal.Error( "shader parm index (%d) out of range", parmnum );
}
//muzzleFlash.shaderParms[ parmnum ] = value;
worldMuzzleFlash.shaderParms[ parmnum ] = value;
UpdateVisuals();
}
/*
================
idWeapon::Event_SetLightParms
================
*/
void idWeapon::Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
/*
muzzleFlash.shaderParms[ SHADERPARM_RED ] = parm0;
muzzleFlash.shaderParms[ SHADERPARM_GREEN ] = parm1;
muzzleFlash.shaderParms[ SHADERPARM_BLUE ] = parm2;
muzzleFlash.shaderParms[ SHADERPARM_ALPHA ] = parm3;
*/
worldMuzzleFlash.shaderParms[ SHADERPARM_RED ] = parm0;
worldMuzzleFlash.shaderParms[ SHADERPARM_GREEN ] = parm1;
worldMuzzleFlash.shaderParms[ SHADERPARM_BLUE ] = parm2;
worldMuzzleFlash.shaderParms[ SHADERPARM_ALPHA ] = parm3;
UpdateVisuals();
}
//rev grab start
/*
================
idWeapon::Event_Grabber
================
*/
void idWeapon::Event_Grabber( int enable ) {
if ( enable ) {
grabberState = 0;
} else {
grabberState = -1;
}
}
/*
================
idWeapon::Event_GrabberHasTarget
================
*/
void idWeapon::Event_GrabberHasTarget() {
idThread::ReturnInt( grabberState );
}
/*
================
idWeapon::Event_GrabberSetGrabDistance
================
*/
void idWeapon::Event_GrabberSetGrabDistance( float dist ) {
grabber.SetDragDistance( dist );
}
//rev grab end
/*
================
idWeapon::Event_CreateProjectile
================
*/
void idWeapon::Event_CreateProjectile( int projtype ) { //ivan: projtype added
if ( !gameLocal.isClient ) {
//ivan start
if( projtype != owner->GetProjectileType() ) {
if(!ChangeProjectileDef(projtype)){
gameLocal.Warning( "Cannot fire proj number %d", projtype );
return;
}
}
//ivan end
projectileEnt = NULL;
gameLocal.SpawnEntityDef( projectileDict, &projectileEnt, false );
if ( projectileEnt ) {
projectileEnt->SetOrigin( GetPhysics()->GetOrigin() );
projectileEnt->Bind( owner, false );
projectileEnt->Hide();
}
idThread::ReturnEntity( projectileEnt );
} else {
idThread::ReturnEntity( NULL );
}
}
/*
================
idWeapon::Event_LaunchProjectiles
Modified & rearranged by Clone JCD for barrel launched Projectiles to hit the target accurately.
================
*/
void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float fuseOffset, float launchPower, float dmgPower, int projtype, int useBarrelDir ) { //ivan: projtype, useBarrelDir added
idProjectile *proj;
idEntity *ent;
int i;
idVec3 dir;
float ang = 0.0f;
float spin;
//float distance;
trace_t tr;
//idVec3 start;
//idBounds ownerBounds, projBounds;
bool barrelLaunch;
bool tracer, beam;
if ( IsHidden() ) {
return;
}
//ivan start
if( projtype != owner->GetProjectileType() ) {
if(!ChangeProjectileDef(projtype)){
gameLocal.Warning( "Cannot fire proj number %d", projtype );
return;
}
}
//ivan end
if ( !projectileDict.GetNumKeyVals() ) {
const char *classname = weaponDef->dict.GetString( "classname" );
gameLocal.Warning( "No projectile defined on '%s'", classname );
return;
}
// avoid all ammo considerations on an MP client
if ( !gameLocal.isClient ) {
// check if we're out of ammo or the clip is empty
int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired );
if ( !ammoAvail || ( ( clipSize != 0 ) && ( ammoClip <= 0 ) ) ) {
return;
}
// if this is a power ammo weapon ( currently only the bfg ) then make sure
// we only fire as much power as available in each clip
if ( powerAmmo ) {
// power comes in as a float from zero to max
// if we use this on more than the bfg will need to define the max
// in the .def as opposed to just in the script so proper calcs
// can be done here.
dmgPower = ( int )dmgPower + 1;
if ( dmgPower > ammoClip ) {
dmgPower = ammoClip;
}
}
owner->inventory.UseAmmo( ammoType, ( powerAmmo ) ? dmgPower : ammoRequired );
if ( clipSize && ammoRequired ) {
ammoClip -= powerAmmo ? dmgPower : ammoRequired;
}
}
if ( !silent_fire ) {
// wake up nearby monsters
gameLocal.AlertAI( owner );
}
// set the shader parm to the time of last projectile firing,
// which the gun material shaders can reference for single shot barrel glows, etc
/*
//was:
renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.CRandomFloat();
renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.realClientTime );
if( weaponDef->dict.GetBool( "resetShaderParms", "1" ) ){ //ivan - new "resetShaderParms" key
if ( worldModel.GetEntity() ) {
worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] ); //an offset
worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] ); //restart from zero
}
}
*/
//ivan start
if( weaponDef->dict.GetBool( "resetShaderParms", "1" ) ){ //ivan - new "resetShaderParms" key
renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.CRandomFloat();
renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.realClientTime );
}
//ivan end
/*
// add some to the kick time, incrementally moving repeat firing weapons back
if ( kick_endtime < gameLocal.realClientTime ) {
kick_endtime = gameLocal.realClientTime;
}
kick_endtime += muzzle_kick_time;
if ( kick_endtime > gameLocal.realClientTime + muzzle_kick_maxtime ) {
kick_endtime = gameLocal.realClientTime + muzzle_kick_maxtime;
}
*/
//ownerBounds = owner->GetPhysics()->GetAbsBounds();
// predict instant hit projectiles
const bool isPrediction = gameLocal.isClient && projectileDict.GetBool( "net_instanthit" );
//ivan start
//spread
if( spread < 0 ){ //auto spread!
spread = dynamicSpreadValue;
}
//ivan end
const float spreadRad = DEG2RAD( spread );
idVec3 view_pos = playerViewOrigin + playerViewAxis[ 0 ] * 2.0f; // Muzzle pos for translation clip model only-- For barrel Launched projectiles
idVec3 muzzle_pos;
// float muzzleDistFromView; // DG: unused
float traceDist = 0.0f, muzzleToTargetDist = 0.0f; // DG: make sure it's initialized to shut up compiler
idVec3 muzzleDir;
beam = projectileDict.GetFloat( "fuse" ) <= 0 || projectileDict.GetBool( "rail_beam");
tracer = !beam && projectileDict.GetBool( "tracers" ) && (projectileDict.GetFloat("tracer_probability", "1.0") > gameLocal.random.RandomFloat());
barrelLaunch = projectileDict.GetBool( "launchFromBarrel" );
if ( barrelLaunch || tracer || beam || useBarrelDir ) { //ivan - useBarrelDir added, so we get muzzleAxis
// calculate the muzzle position
if ( barrelJointWorld != INVALID_JOINT ) { //ivan - was barrelJointView
// there is an explicit joint for the muzzle
GetGlobalJointTransform( barrelJointWorld, muzzleOrigin, muzzleAxis ); //ivan: was true , barrelJointView
if ( barrelLaunch ) {
tracer = false;
}
muzzle_pos = muzzleOrigin; // + playerViewAxis[ 0 ] * 2.0f; // muzzle_pos for multiplayer prediction as well as for launching the projectiles
// muzzleDistFromView = (muzzle_pos - view_pos).Length( ) * 3.5f;
// muzzleDistFromView = (muzzle_pos - view_pos).LengthSqr( ) * 3.5f; // This is faster - DG: unused
} else { // if we dont find a proper bone then cancel all the effects.
barrelLaunch = false;
tracer = false;
beam = false;
useBarrelDir = false; //ivan - useBarrelDir added
}
}
idVec3 &launch_pos = view_pos;
const float tracer_speed = projectileDict.GetFloat( "tracer_speed", "0.0f" );
//ivan start - fire modes - setup
int firemodeCounter = 0;
int firemodeCounterPos = 0;
bool odd_proj_num = (num_projectiles%2 != 0); //dispari
idVec3 updown_offset;
const idMat3 &aimAxis = ( useBarrelDir ? muzzleAxis : playerViewAxis );
updown_offset.Zero();
if( spreadMode == WP_SPREADMODE_2D_STEP){
if(num_projectiles > 1){ //Example: spread = 90, num projs = 5
ang = 2*spread/(num_projectiles-1); //Spread step: 2* 90 /(5-1) = 45 degrees
ang = ang/180.0f; //normalized from 0 to 1: 45/180 = 0.5 --> % of 180 degrees to use: 0, 0.25, -0.25, 0.5, -0.5
}
}
//ivan end
for( i = 0; i < num_projectiles; i++ ) {
//ang = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
//spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
//ivan start - fire modes - direction
switch( spreadMode ) {
case WP_SPREADMODE_DEFAULT: {
ang = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
dir = aimAxis[ 0 ] + aimAxis[ 2 ] * ( ang * idMath::Sin( spin ) ) - aimAxis[ 1 ] * ( ang * idMath::Cos( spin ) );
break;
}
case WP_SPREADMODE_2D_STEP: {
// FIXME: DG: what if num_projectiles == 1? then ang is not initialized properly (I set it to 0 above)
dir = (aimAxis[ 0 ] * (1-ang*firemodeCounterPos) ) + ( aimAxis[ 2 ] * ang*firemodeCounter );
//upd counter
if(firemodeCounter >= 0){
firemodeCounter++;
firemodeCounterPos = firemodeCounter;
}
firemodeCounter = - firemodeCounter;
break;
}
case WP_SPREADMODE_2D_PARALLEL: {
dir = aimAxis[ 0 ];
//upd counter before if even number of projs
if( !odd_proj_num && firemodeCounter >= 0){ firemodeCounter++; }
updown_offset = playerViewAxis[ 2 ]*spread*firemodeCounter;
//upd counter after if odd number of projs
if( odd_proj_num && firemodeCounter >= 0){ firemodeCounter++; }
firemodeCounter = - firemodeCounter;
break;
}
case WP_SPREADMODE_2D_RANDOM: {
ang = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
dir = aimAxis[ 0 ] + aimAxis[ 2 ] * ( ang * idMath::Sin( spin ) );
break;
}
default: {
gameLocal.Error("Unknown WEAPON fire mode: %d", spreadMode );
break;
}
}
//ivan test end
dir.Normalize();
if ( barrelLaunch || tracer || beam ) { // Do not execute this part unless projectile is barrel launched or has a tracer effect.
//Rev start
projectileOrigin = cvarSystem->GetCVarInteger( "pm_projectileOrigin" );
if ( projectileOrigin > 0 ) {
gameLocal.clip.Translation( tr, muzzle_pos, muzzle_pos + dir * 4096.0f, NULL, mat3_identity, MASK_SHOT_RENDERMODEL, owner );
traceDist = (tr.endpos - muzzle_pos).LengthSqr(); //THIS FIXES PROJECTILES FIRED FROM THE BARREL NOT GOING TO THE CROSSHAIR
//Launching projectiles now always comes from the thirdperson weapon's barrel model... even in first person. Direction is always towards Thirdperson crosshair.
//Launchfrombarrel should be set to 0 in weapon defs. setting to 1 is no longer needed.
} else {
gameLocal.clip.Translation( tr, view_pos, view_pos + dir * 4096.0f, NULL, mat3_identity, MASK_SHOT_RENDERMODEL, owner );
traceDist = (tr.endpos - view_pos).LengthSqr();
}
//Rev end
//ivan start - fix aim
// Problem: muzzleDistFromView is the dist from muzzle and viewpos.
// It was usually very low in D3.
// If tracer lenght was smaller than it, then we are too close to a wall/something and the aim was corrected.
// Now: dist from muzzle and viewpos is very big --> aim was corrected even when it should not.
// Aim correction is now disabled.
/*
if ( traceDist > muzzleDistFromView ) { // make sure the muzzle is not to close to walls etc
if ( barrelLaunch ) {
dir = tr.endpos - muzzle_pos;
dir.Normalize();
}
else if ( tracer ) {
muzzleDir = tr.endpos - muzzle_pos;
// muzzleToTargetDist = muzzleDir.Length();
muzzleToTargetDist = muzzleDir.LengthSqr(); // This is faster
muzzleDir.Normalize();
}
}
else{
if ( tracer || beam ) { // Dont do tracers when weapon is too close to walls, objects etc.
tracer = false;
beam = false;
}
}
*/
//fix - tracer still need muzzleToTargetDist
if ( tracer ) {
muzzleDir = tr.endpos - muzzle_pos;
muzzleToTargetDist = muzzleDir.LengthSqr();
muzzleDir.Normalize();
}
//fix end
//ivan end
}
if ( isPrediction ) {
if ( tr.fraction < 1.0f ) {
if ( barrelLaunch ) { //a new trace should be made for multiplayer prediction of barrel launched projectiles
gameLocal.clip.Translation( tr, muzzle_pos, muzzle_pos + dir * 4096.0f, NULL, mat3_identity, MASK_SHOT_RENDERMODEL, owner );
}
else
{
gameLocal.clip.Translation( tr, view_pos, view_pos + dir * 4096.0f, NULL, mat3_identity, MASK_SHOT_RENDERMODEL, owner );
}
idProjectile::ClientPredictionCollide( this, projectileDict, tr, vec3_origin, true );
}
}
else {
if ( projectileEnt ) {
ent = projectileEnt;
ent->Show();
ent->Unbind();
projectileEnt = NULL;
} else {
gameLocal.SpawnEntityDef( projectileDict, &ent, false );
}
if ( !ent || !ent->IsType( idProjectile::Type ) ) {
const char *projectileName = weaponDef->dict.GetString( "def_projectile" );
gameLocal.Error( "'%s' is not an idProjectile", projectileName );
}
if ( projectileDict.GetBool( "net_instanthit" ) ) {
// don't synchronize this on top of the already predicted effect
ent->fl.networkSync = false;
}
if ( barrelLaunch ){
launch_pos = muzzle_pos;
}
proj = static_cast<idProjectile *>(ent);
// proj->Create( owner, muzzleOrigin, dir );
proj->Create( owner, launch_pos, dir );
// make sure the projectile starts inside the bounding box of the owner
/*
//commented out by ivan: don't check bbox
// Do this for every projectile, no matter how slow it makes whole thing
// if ( i == 0 ) { // Do this only for first projectile
projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() );
if ( ( ownerBounds - projBounds).RayIntersection( launch_pos, playerViewAxis[0], distance ) ) {
start = launch_pos + distance * playerViewAxis[0];
>>>>>>>
} else {
start = ownerBounds.GetCenter();
}
gameLocal.clip.Translation( tr, start, launch_pos, proj->GetPhysics()->GetClipModel(), proj->GetPhysics()->GetClipModel()->GetAxis(), MASK_SHOT_RENDERMODEL, owner );
launch_pos = tr.endpos;
// }
*/
#ifdef _DENTONMOD
if( tracer ) {
/* if ( traceDist <= muzzleToTargetDist ) // Ideally, this should never happen
gameLocal.Printf ( " Unpredicted traceDistance in idWeapon::Event_LaunchProjectiles " );
*/
bool beamTracer = (projectileDict.GetString( "beam_skin", NULL ) != NULL);
if ( tracer_speed != 0.0f ) {
if( beamTracer ) { // Check whether it's a beamTracer
proj->setTracerEffect( new dnBeamSpeedTracer(proj, tracer_speed, muzzleToTargetDist * idMath::RSqrt( muzzleToTargetDist ), muzzle_pos, muzzleDir.ToMat3()) );
}
else {
proj->setTracerEffect( new dnSpeedTracer(proj, tracer_speed, muzzleToTargetDist * idMath::RSqrt( muzzleToTargetDist ), muzzle_pos, muzzleDir.ToMat3()) );
}
}
else {
if( beamTracer ) {
proj->setTracerEffect( new dnBeamTracer(proj, traceDist/muzzleToTargetDist, view_pos, muzzle_pos, muzzleDir.ToMat3()) );
}
else {
proj->setTracerEffect( new dnTracer(proj, traceDist/muzzleToTargetDist, view_pos, muzzle_pos, muzzleDir.ToMat3()) );
}
}
}
else if( beam ) {
proj->setTracerEffect( new dnRailBeam(proj, muzzleOrigin) );
}
#endif
//ivan start - fire modes - postion offset
//proj->Launch( launch_pos, dir, pushVelocity, fuseOffset, launchPower, dmgPower );
proj->Launch( launch_pos + updown_offset, dir, pushVelocity, fuseOffset, launchPower, dmgPower );
//ivan test end
}
}
if ( !gameLocal.isClient ) {
// toss the brass
if (brassDelay >= 0) // eject brass behaviour can be disabled by simply setting the delay to 0
PostEventMS( &EV_Weapon_EjectBrass, brassDelay );
}
// add the light for the muzzleflash
if ( !lightOn ) {
MuzzleFlashLight();
}
owner->WeaponFireFeedback( &weaponDef->dict ); //ivan - todo: call WeaponSecFireFeedback if is secondary firemode
// reset muzzle smoke
weaponSmokeStartTime = gameLocal.realClientTime;
//ivan - keep track of this moment
lastFiredTime = gameLocal.time;
}
//----------------New Start
#ifdef _DENTONMOD
bool idWeapon::ChangeProjectileDef( int number ) {
if( projectileEnt != NULL ) {
gameLocal.Printf("Projectile Entity exists \n ");
return false;
}
const idKeyValue *kv = spawnArgs.MatchPrefix( "def_projectile", NULL);
for (int i=0; kv && i < number; i++ ) {
kv = spawnArgs.MatchPrefix( "def_projectile", kv);
}
if (kv == NULL) {
return false;
}
const idDeclEntityDef *projectileDef = gameLocal.FindEntityDef( kv->GetValue(), false );
if ( projectileDef ) {
const char *spawnclass = projectileDef->dict.GetString( "spawnclass" );
idTypeInfo *cls = idClass::GetClass( spawnclass );
if ( !cls || !cls->IsType( idProjectile::Type ) ) {
gameLocal.Warning( "Invalid spawnclass in Event_ChangeProjectileDef.\n" );
} else {
projectileDict = projectileDef->dict;
owner->SetProjectileType( number );
/*
float time_in_secs;
if ( projectileDict.GetFloat( "muzzle_kick_time", "0.0f", time_in_secs ) ) {
muzzle_kick_time = SEC2MS( time_in_secs );
}
else {
muzzle_kick_time = SEC2MS( spawnArgs.GetFloat( "muzzle_kick_time" ) );
}
if ( projectileDict.GetFloat( "muzzle_kick_maxtime", "0.0f", time_in_secs ) ) {
muzzle_kick_maxtime = SEC2MS( time_in_secs );
}
else {
muzzle_kick_maxtime = SEC2MS( spawnArgs.GetFloat( "muzzle_kick_maxtime" ) );
}
if( !projectileDict.GetAngles( "muzzle_kick_angles", "0 0 0", muzzle_kick_angles ) ) {
muzzle_kick_angles = spawnArgs.GetAngles( "muzzle_kick_angles" );
}
if( !projectileDict.GetVector( "muzzle_kick_offset", "0 0 0", muzzle_kick_offset ) ) {
muzzle_kick_offset = spawnArgs.GetVector( "muzzle_kick_offset" );
}
*/
return true;
}
}
return false;
}
void idWeapon::Event_ChangeProjectileDef( int number ) {
if( number == owner->GetProjectileType() ) {
idThread::ReturnFloat( 1 );
}
idThread::ReturnFloat( ChangeProjectileDef(number) ? 1 : 0 );
}
void idWeapon::Event_GetProjectileType( void ) {
idThread::ReturnFloat( owner->GetProjectileType() );
}
void idWeapon::StartWeaponParticle( const char* prtName) {
WeaponParticle_t* part;
weaponParticles.Get(prtName, &part);
if(part) {
part->particleFlags.isActive = true;
if( part->particleFlags.isSmoke ) {
part->startTime = gameLocal.time;
} else {
if( part->modelDefHandle > -1 ) {
gameRenderWorld->FreeEntityDef( part->modelDefHandle );
part->modelDefHandle = -1;
}
//part->renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
//part->renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.RandomFloat(); // For effects like muzzleflashes etc.
}
}
}
void idWeapon::Event_StartWeaponParticle( const char* prtName) {
StartWeaponParticle( prtName );
}
void idWeapon::StopWeaponParticle( const char* prtName) {
WeaponParticle_t* part;
weaponParticles.Get(prtName, &part);
if(part) {
part->particleFlags.isActive = false;
part->startTime = 0;
//Free the particles
if(!part->particleFlags.isSmoke && part->modelDefHandle >= 0) {
gameRenderWorld->FreeEntityDef( part->modelDefHandle );
part->modelDefHandle = -1;
}
}
}
void idWeapon::Event_StopWeaponParticle( const char* prtName) {
StopWeaponParticle( prtName );
}
void idWeapon::Event_StartWeaponLight( const char* lightName) {
WeaponLight_t* light;
weaponLights.Get(lightName, &light);
if( light ) {
light->lightFlags.isActive = true;
light->startTime = gameLocal.time;
// these will be different each fire
light->light.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
light->light.shaderParms[ SHADERPARM_DIVERSITY ] = renderEntity.shaderParms[ SHADERPARM_DIVERSITY ];
if( !light->lightFlags.isAlwaysOn ){
light->endTime += light->startTime;
}
}
}
void idWeapon::Event_StopWeaponLight( const char* lightName) {
WeaponLight_t* light;
weaponLights.Get(lightName, &light);
if(light) {
light->lightFlags.isActive = false;
light->startTime = 0;
if(light->lightHandle != -1) {
gameRenderWorld->FreeLightDef( light->lightHandle );
light->lightHandle = -1;
}
}
}
#endif //_DENTONMOD
//----------------- New End
/*
=====================
idWeapon::Event_Melee
=====================
*/
void idWeapon::Event_Melee( void ) {
if( !autoMeleeEnabled && EvaluateMelee() ){ //don't do this if it's already enabled...
idThread::ReturnInt( 1 );
}else{
idThread::ReturnInt( 0 );
}
}
/*
=====================
idWeapon::Event_GetWorldModel
=====================
*/
void idWeapon::Event_GetWorldModel( void ) {
idThread::ReturnEntity( this ); //ivan - was: worldModel.GetEntity()
}
/*
=====================
idWeapon::Event_AllowDrop
=====================
*/
void idWeapon::Event_AllowDrop( int allow ) {
if ( allow ) {
allowDrop = true;
} else {
allowDrop = false;
}
}
/*
================
idWeapon::Event_EjectBrass
Toss a shell model out from the breach if the bone is present
================
*/
void idWeapon::Event_EjectBrass( void ) {
if ( !g_showBrass.GetBool() || !owner->CanShowWeaponViewmodel() ) {
return;
}
if ( ejectJointWorld == INVALID_JOINT || !brassDict.GetNumKeyVals() ) { //was: ejectJointView
return;
}
if ( gameLocal.isClient ) {
return;
}
idMat3 axis;
idVec3 origin, linear_velocity, angular_velocity;
idEntity *ent;
if ( !GetGlobalJointTransform( ejectJointWorld, origin, axis ) ) { //was: ejectJointView
return;
}
gameLocal.SpawnEntityDef( brassDict, &ent, false );
if ( !ent || !ent->IsType( idDebris::Type ) ) {
gameLocal.Error( "'%s' is not an idDebris", weaponDef ? weaponDef->dict.GetString( "def_ejectBrass" ) : "def_ejectBrass" );
}
idDebris *debris = static_cast<idDebris *>(ent);
debris->Create( owner, origin, axis );
debris->Launch();
if( spawnArgs.GetBool( "fixed_brass_dir" ) ) {
linear_velocity = 40 * ( playerViewAxis[0] + playerViewAxis[1] + playerViewAxis[2] );
angular_velocity.Set( 10 * gameLocal.random.CRandomFloat(), 10 * gameLocal.random.CRandomFloat(), 10 * gameLocal.random.CRandomFloat() );
debris->GetPhysics()->SetLinearVelocity( linear_velocity );
debris->GetPhysics()->SetAngularVelocity( angular_velocity );
}
}
/*
===============
idWeapon::Event_IsInvisible
===============
*/
void idWeapon::Event_IsInvisible( void ) {
if ( !owner ) {
idThread::ReturnFloat( 0 );
return;
}
idThread::ReturnFloat( owner->PowerUpActive( INVISIBILITY ) ? 1 : 0 );
}
// New------------------
#ifdef _DENTONMOD
/*
===============
idWeapon::Event_StartZoom
===============
*/
void idWeapon::Event_SetZoom( int status ) { //New
if( status ){
owner->SetWeaponZoom( true );
}
else {
owner->SetWeaponZoom( false );
}
}
#endif// _DENTONMOD
/*
===============
idWeapon::ClientPredictionThink
===============
*/
void idWeapon::ClientPredictionThink( void ) {
UpdateAnimation();
}
/*
================
idWeapon::AmmoCount
Returns the total number of rounds regardless of the required ammo // new
================
*/
int idWeapon::AmmoCount( void ) const {
if ( owner ) {
return owner->inventory.HasAmmo( ammoType, 1 );
} else {
return 0;
}
}
//ivan start
/*
===============
idWeapon::HasToWalk
===============
*/
bool idWeapon::HasToWalk( void ) const {
if ( isFiring || isSecFiring ) {
return true;
} else if( lastFiredTime + 500 > gameLocal.time){ //go on walking after the last fired proj for a bit
return true;
} else {
return false;
}
}
/*
================
idWeapon::GetWalkSpeedMult
================
*/
float idWeapon::GetWalkSpeedMult() const {
if ( HasToWalk() ) {
return firingWalkSpeedMult;
} else {
return 1.0f;
}
}
/*
===============
idWeapon::Event_PwAmmoAvailable
===============
*/
void idWeapon::Event_SetWeaponMode( int value ) {
owner->SetCurrentWeaponMode( value );
UpdateSkin();
UpdSpreadSettings(); //upd spread settings
}
/*
===============
idWeapon::Event_PwAmmoAvailable
===============
*/
void idWeapon::Event_GetWeaponMode( void ) {
int myMode = owner->GetCurrentWeaponMode();
idThread::ReturnInt( myMode );
}
//ivan end