dhewm3-sdk/game/Weapon.cpp
revility dd30a38bb1 Update Weapon.cpp
launch from barrel is no longer needed for projectiles to launch from the weapon's barrel, and then to the thirdperson cross hair position.  This fixes the projectiles not launching to the center of the thirdperson cross and also fixes the offset when aiming too high or too low.
projectiles in weapon.def files need launchfrombarrel set to 0 for this work.  the crosshair offsets also need to be adjust in the cursor.gui file as each one offset manually in Rivensin/Ruiner 2010 build.
2018-10-21 04:31:15 +02:00

5340 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;
}
/*
================
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.
gameLocal.clip.Translation( tr, muzzle_pos, muzzle_pos + dir * 4096.0f, NULL, mat3_identity, MASK_SHOT_RENDERMODEL, owner ); //REVILITY 2018 WAS VIEW_POS
traceDist = (tr.endpos - muzzle_pos).LengthSqr(); //REVILITY 2018 WAS VIEW_POS. THIS FIXES PROJECTILES FIRED FROM THE BARREL NOT GOING TO THE CROSSHAIR
//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