Adding Ironsights: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
m (fixed an error in weapon_parse.cpp)
m (fixed code-errors)
Line 71: Line 71:
These ConVars usually go after the includes:
These ConVars usually go after the includes:
<pre>
<pre>
ConVar viewmodel_adjust_forward("viewmodel_adjust_forward", "0", FCVAR_REPLICATED);
ConVar viewmodel_adjust_forward("viewmodel_adjust_forward", "0");
ConVar viewmodel_adjust_right("viewmodel_adjust_right", "0", FCVAR_REPLICATED);
ConVar viewmodel_adjust_right("viewmodel_adjust_right", "0");
ConVar viewmodel_adjust_up("viewmodel_adjust_up", "0", FCVAR_REPLICATED);
ConVar viewmodel_adjust_up("viewmodel_adjust_up", "0");
ConVar viewmodel_adjust_pitch("viewmodel_adjust_pitch", "0", FCVAR_REPLICATED);
ConVar viewmodel_adjust_pitch("viewmodel_adjust_pitch", "0");
ConVar viewmodel_adjust_yaw("viewmodel_adjust_yaw", "0", FCVAR_REPLICATED);
ConVar viewmodel_adjust_yaw("viewmodel_adjust_yaw", "0");
ConVar viewmodel_adjust_roll("viewmodel_adjust_roll", "0", FCVAR_REPLICATED);
ConVar viewmodel_adjust_roll("viewmodel_adjust_roll", "0");
ConVar viewmodel_adjust_fov("viewmodel_adjust_fov", "0", FCVAR_REPLICATED);
ConVar viewmodel_adjust_fov("viewmodel_adjust_fov", "0");
ConVar viewmodel_adjust_enabled("viewmodel_adjust_enabled", "0", FCVAR_REPLICATED|FCVAR_CHEAT);
ConVar viewmodel_adjust_enabled("viewmodel_adjust_enabled", "0", FCVAR_CHEAT);
#if !defined( GAME_DLL )
#if !defined( GAME_DLL )
extern const ConVar *sv_cheats;
extern const ConVar *sv_cheats;
Line 95: Line 95:
QAngle CBaseCombatWeapon::GetSightAngleOffset( void ) const
QAngle CBaseCombatWeapon::GetSightAngleOffset( void ) const
{
{
if( dels_viewmodel_adjust_enabled.GetBool() )
if( viewmodel_adjust_enabled.GetBool() )
return QAngle( viewmodel_adjust_pitch.GetFloat(), viewmodel_adjust_yaw.GetFloat(), viewmodel_adjust_roll.GetFloat() );
return QAngle( viewmodel_adjust_pitch.GetFloat(), viewmodel_adjust_yaw.GetFloat(), viewmodel_adjust_roll.GetFloat() );
return GetWpnData().angIronsightAngOffset;
return GetWpnData().angIronsightAngOffset;
Line 143: Line 143:
virtual bool HasIronsights( void ) { return true; } //default yes
virtual bool HasIronsights( void ) { return true; } //default yes
bool IsIronsighted( void );
bool IsIronsighted( void );
void ToggleIronsights( void ) { IsIronsighted() ? DisableSights() : EnableSights(); }
void ToggleIronsights( void ) { IsIronsighted() ? DisableIronsights() : EnableIronsights(); }
void EnableIronsights( void );
void EnableIronsights( void );
void DisableIronsights( void );
void DisableIronsights( void );
Line 154: Line 154:
{
{
if( viewmodel_adjust_enabled.GetBool() && !sv_cheats->GetBool() )
if( viewmodel_adjust_enabled.GetBool() && !sv_cheats->GetBool() )
viewmodel_adjust_enabled.SetValue( "0" );
viewmodel_adjust_enabled.SetValue( "0" ); //TODO: make viewmodel_adjust_enabled a ConCommand to set itself to 0 if sv_cheats 0
return ( m_bIsIronsighted || viewmodel_adjust_enabled.GetBool() );
return ( m_bIsIronsighted || viewmodel_adjust_enabled.GetBool() );
}
}
Line 160: Line 160:
void CBaseCombatWeapon::EnableIronsights( void )
void CBaseCombatWeapon::EnableIronsights( void )
{
{
if( m_bIsIronsighted )
if( !HasIronsights() || m_bIsIronsighted )
return;
return;


Line 177: Line 177:
void CBaseCombatWeapon::DisableIronsights( void )
void CBaseCombatWeapon::DisableIronsights( void )
{
{
if( !m_bIsIronsighted )
if( !HasIronsights() || !m_bIsIronsighted )
return;
return;



Revision as of 05:11, 14 September 2008

This is a tutorial how to add Ironsights and is an alternative to Jorg's code.

The new approach allows you to control the toggling server-side and thus you can add different bullet spread and such easily. It also has working angles and fov-change. However, the code still has to be edited to work in multiplayer and also only has been tested with a singleplayer OB-Mod.

New Approach

Weaponscript

At first, we will add some custom script-variables to be able to adjust the ironsight-offset via the weapon-script.

weapon_parse.h

Add this to the member-variables of FileWeaponInfo_t:

	Vector					vecIronsightPosOffset;
	QAngle					angIronsightAngOffset;
	float					flIronsightFOVOffset;

weapon_parse.cpp

This goes to FileWeaponInfo_t::Parse:

	KeyValues *pSights = pKeyValuesData->FindKey( "IronSight" );
	if (pSights)
	{
		vecIronsightPosOffset.x		= pSights->GetFloat( "forward", 0.0f );
		vecIronsightPosOffset.y		= pSights->GetFloat( "right", 0.0f );
		vecIronsightPosOffset.z		= pSights->GetFloat( "up", 0.0f );

		angIronsightAngOffset[PITCH]	= pSights->GetFloat( "pitch", 0.0f );
		angIronsightAngOffset[YAW]		= pSights->GetFloat( "yaw", 0.0f );
		angIronsightAngOffset[ROLL]		= pSights->GetFloat( "roll", 0.0f );

		flIronsightFOVOffset		= pSights->GetFloat( "fov", 0.0f );
	}
	else
	{
		vecIronsightPosOffset = vec3_origin;
		angIronsightAngOffset.Init();
		flIronsightFOVOffset = 0.0f;
	}

weapon_smg1.txt

This is an example of how to add the ironsight-offsets to your script:

	IronSight
	{
		"forward"	"-10"
		"right"		"-6.91"
		"up"		"0.185"
		"roll"		"-20"
		"fov"		"-20"
	}

Getting the offsets

Now we will add simple functions to get the information we parsed from the weapon-scripts. But we also want to have console-variables to overwrite the parsed info so we can easily make new ironsight-offsets.

basecombatweapon_shared.h

This goes to the public functions:

	Vector					GetIronsightPositonOffset( void ) const;
	QAngle					GetIronsightAngleOffset( void ) const;
	float					GetIronsightFOVOffset( void ) const;

basecombatweapon_shared.cpp

These ConVars usually go after the includes:

ConVar viewmodel_adjust_forward("viewmodel_adjust_forward", "0");
ConVar viewmodel_adjust_right("viewmodel_adjust_right", "0");
ConVar viewmodel_adjust_up("viewmodel_adjust_up", "0");
ConVar viewmodel_adjust_pitch("viewmodel_adjust_pitch", "0");
ConVar viewmodel_adjust_yaw("viewmodel_adjust_yaw", "0");
ConVar viewmodel_adjust_roll("viewmodel_adjust_roll", "0");
ConVar viewmodel_adjust_fov("viewmodel_adjust_fov", "0");
ConVar viewmodel_adjust_enabled("viewmodel_adjust_enabled", "0", FCVAR_CHEAT);
#if !defined( GAME_DLL )
extern const ConVar *sv_cheats;
#endif

And then you add the function definitions:

Vector CBaseCombatWeapon::GetSightPositonOffset( void ) const
{
	if( viewmodel_adjust_enabled.GetBool() )
		return Vector( viewmodel_adjust_forward.GetFloat(), viewmodel_adjust_right.GetFloat(), viewmodel_adjust_up.GetFloat() );
	return GetWpnData().vecIronsightPosOffset;
}

QAngle CBaseCombatWeapon::GetSightAngleOffset( void ) const
{
	if( viewmodel_adjust_enabled.GetBool() )
		return QAngle( viewmodel_adjust_pitch.GetFloat(), viewmodel_adjust_yaw.GetFloat(), viewmodel_adjust_roll.GetFloat() );
	return GetWpnData().angIronsightAngOffset;
}

float CBaseCombatWeapon::GetSightFOVOffset( void ) const
{
	if( viewmodel_adjust_enabled.GetBool() )
		return viewmodel_adjust_fov.GetFloat();
	return GetWpnData().flIronsightFOVOffset;
}

Adding toggle-functions

Of course you also want to be able to use the sights.

basecombatweapon_shared.h

Add these two networked variables:

CNetworkVar( bool, m_bIsIronighted );
CNetworkVar( float, m_flIronsightedTime );

basecombatweapon_shared.cpp

Network them and give 'em default values.

Constructor:

	m_bIsIronsighted = false;
	m_flIronsightedTime = 0.0f;

Network-table:

	SendPropBool( SENDINFO( m_bIsIronsighted ) ),
	SendPropFloat( SENDINFO( m_flIronsightedTime ) ),

and

	RecvPropBool( RECVINFO( m_bIsIronSighted ) ),
	RecvPropFloat( RECVINFO( m_flIronsightedTime ) ),

basecombatweapon_shared.h

Now that we have the variables, we also want accessors:

	virtual bool				HasIronsights( void ) { return true; } //default yes
	bool					IsIronsighted( void );
	void					ToggleIronsights( void ) { IsIronsighted() ? DisableIronsights() : EnableIronsights(); }
	void					EnableIronsights( void );
	void					DisableIronsights( void );

basecombatweapon_shared.cpp

And of course define them:

bool CBaseCombatWeapon::IsIronsighted( void )
{
	if( viewmodel_adjust_enabled.GetBool() && !sv_cheats->GetBool() )
		viewmodel_adjust_enabled.SetValue( "0" ); //TODO: make viewmodel_adjust_enabled a ConCommand to set itself to 0 if sv_cheats 0
	return ( m_bIsIronsighted || viewmodel_adjust_enabled.GetBool() );
}

void CBaseCombatWeapon::EnableIronsights( void )
{
	if( !HasIronsights() || m_bIsIronsighted )
		return;

	CBasePlayer *pOwner = ToBasePlayer( GetOwner() );

	if( !pOwner )
		return;

	if( pOwner->SetFOV( this, pOwner->GetDefaultFOV()+GetIronsightFOVOffset(), 1.0f, 0.3f ) ) //modify these values to adjust how fast the fov is applied
	{
		m_bIsIronsighted = true;
		m_flIronsightedTime = gpGlobals->curtime;
	}
}

void CBaseCombatWeapon::DisableIronsights( void )
{
	if( !HasIronsights() || !m_bIsIronsighted )
		return;

	CBasePlayer *pOwner = ToBasePlayer( GetOwner() );

	if( !pOwner )
		return;

	if( pOwner->SetFOV( this, 0, 0.4f, 0.1f ) ) //modify these values to adjust how fast the fov is applied
	{
		m_bIsIronsighted = false;
		m_flIronsightedTime = gpGlobals->curtime;
	}
}

hl2_player.cpp

You probably want a command to switch between normal and sighted mode. I've put them in hl2_player.cpp.

void CC_ToggleIronSights( void )
{
	CBasePlayer* pPlayer = UTIL_GetCommandClient();
	if ( pPlayer == NULL )
		return;

	CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
	if( pWeapon == NULL )
		return;

	pWeapon->ToggleIronsights();
}

static ConCommand toggle_ironsight("toggle_ironsight", CC_ToggleIronSights);

Adjust the viewmodel

Ok, now for the last step we want to move the viewmodel according to the offsets. That code is based off Jorg's. Thanks from z33ky.

There are still some little issues to fix, though. Viewmodel-bob is still active while iron-sighting and the viewmodel lags way too much when going out of ironsight and rotating the view. You can try adding m_flIronsightedTime to this or moving CalcIronsights in front of those bob-things, I don't know. Since I'm not working on Delusion: Source anymore I didn't try to fix those issues.

baseviewmodel_shared.cpp

void CBaseViewModel::CalcIronsights( Vector &pos, QAngle &ang )
{
	CBaseCombatWeapon *pWeapon = GetOwningWeapon();

	if ( !pWeapon )
		return;

	//get delta time for interpolation
	float delta( ( gpGlobals->curtime - pWeapon->m_flIronsightedTime ) / 0.4f ); //modify this value to adjust how fast the interpolation is
	float exp = ( pWeapon->IsIronsighted() ) ? 
		( delta > 1.0f ) ? 1.0f : delta : //normal blending
		( delta > 1.0f ) ? 0.0f : 1.0f - delta; //reverse interpolation

	if( exp == 0.0f ) //fully not ironsighted; save performance
		return;

	Vector newPos = pos;
	QAngle newAng = ang;

	Vector vForward, vRight, vUp, vOffset;
	AngleVectors( newAng, &vForward, &vRight, &vUp );
	vOffset = pWeapon->GetIronsightPositonOffset();

	newPos += vForward * vOffset.x;
	newPos += vRight * vOffset.y;
	newPos += vUp * vOffset.z;
	newAng += pWeapon->GetIronsightAngleOffset();
	//fov is handled by CBaseCombatWeapon

	pos += ( newPos - pos ) * exp;
	ang += ( newAng - ang ) * exp;
}

Make use of this code in CBaseViewModel::CalcViewModelView:

void CBaseViewModel::CalcViewModelView( CBasePlayer *owner, const Vector& eyePosition, const QAngle& eyeAngles )
{
	// UNDONE: Calc this on the server?  Disabled for now as it seems unnecessary to have this info on the server
#if defined( CLIENT_DLL )
	QAngle vmangoriginal = eyeAngles;
	QAngle vmangles = eyeAngles;
	Vector vmorigin = eyePosition;

	CBaseCombatWeapon *pWeapon = m_hWeapon.Get();
	//Allow weapon lagging
	//only if not in ironsight-mode
	if( pWeapon == NULL || !pWeapon->IsIronsighted() )
	{
		if ( pWeapon != NULL )
		{
	#if defined( CLIENT_DLL )
			if ( !prediction->InPrediction() )
	#endif
			{
				// add weapon-specific bob 
				pWeapon->AddViewmodelBob( this, vmorigin, vmangles );
			}
		}

		// Add model-specific bob even if no weapon associated (for head bob for off hand models)
		AddViewModelBob( owner, vmorigin, vmangles );

		// Add lag
		CalcViewModelLag( vmorigin, vmangles, vmangoriginal );

#if defined( CLIENT_DLL )
		if ( !prediction->InPrediction() )
		{
			// Let the viewmodel shake at about 10% of the amplitude of the player's view
			vieweffects->ApplyShake( vmorigin, vmangles, 0.1 );	
		}
#endif
	}

	CalcIronsights( vmorigin, vmangles );

	SetLocalOrigin( vmorigin );
	SetLocalAngles( vmangles );

#endif
}

baseviewmodel_shared.h

Don't forget to declare the new function:

 	void		CalcIronsights( Vector &pos, QAngle &ang ); 

Add keybind

Last but not least, add the key to the Options/Keyboard-menu:

kb_act.lst

Probably somewhere in "#Valve_Combat_Title":

 "toggle_ironsight"		"#MOD_Toggle_Ironsight" 

And don't forget to add this #MOD_Toggle_Ironsight to your resource/MOD_english.txt (and the other lanuages).

Notes

It would be great if someone would add the changes you need for a HL2MP-mod and a Scratch-mod and maybe for the ep1-engine (if any are needed).

I would appreciate it if you would credit me, z33ky, if you use this code (modified or unmodified) - but there is no need to.

Also, if you fix the issues, post how to!