Legs in Firstperson (2013)

From Valve Developer Community
Jump to navigation Jump to search
Note.pngNote:This hasn't been tested with Mapbase Mapbase, Team Fortress 2 Team Fortress 2, nor Source 2013 Multiplayer Source SDK Base 2013 - Multiplayer.
Note.pngNote: Mapbase Mapbase already support Legs in Firstperson, as of this commit/pull request. This commit specifically. This commit specifically.

Implementing First person legs onto your Source 2013 (Singleplayer) mod is relatively simple. This guide is based on Half-Life 2: ReCharged's implementation of the 2007 guide onto 2013 SP.

Requirements

  1. Animation state system implementation.
  2. Knowledge of C++
  3. A single player mod running on Source SDK 2013

Full implementation

c_baseplayer.h

Search for bool IsInFreezeCam( void ); and under it add:

bool IsInEye( void );

Search for virtual int DrawModel( int flags ); and under it add:

const Vector &C_BasePlayer::GetRenderOrigin();

c_baseplayer.cpp

Find the function bool IsInFreezeCam( void ) and under it add:

bool IsInEye( void )
{
	C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
	if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
	{
		return true;
	}
	else
	{
		return false;
	}
}

After that, under C_BasePlayer::ShouldDraw function add:

Todo: Replace this part with ReCharged's implementation to avoid errors.
extern ConVar cl_legs;
extern ConVar cl_legs_origin_shift;
extern ConVar cl_legs_clip_height;

const Vector &C_BasePlayer::GetRenderOrigin( void )
{
	// If we're not observing this player, or if we're not drawing it at the
	// moment then use the normal absolute origin.
	// NOTE: the GetCurrentlyDrawingEntity check is here to make sure the
	// shadow is rendered from the correct origin
	if( !IsInEye() || view->GetCurrentlyDrawingEntity() != this )
		return BaseClass::GetRenderOrigin();

	// Get the forward vector
	static Vector forward; // static because this method returns a reference
	AngleVectors(GetRenderAngles(), &forward);

	// Shift the render origin by a fixed amount
	forward *= cl_legs_origin_shift.GetFloat();
	forward += GetAbsOrigin();

	return forward;
}

Now in the top of the file, add #include "convar_firstperson.h" and create the file with the following code:

convar_firstperson.h

#include "cbase.h"
static ConVar cl_legs( "cl_legs", "1", FCVAR_CHEAT, "Enable or disable player leg rendering", true, 0, true, 1 );
static ConVar cl_legs_origin_shift( "cl_legs_origin_shift", "-17", FCVAR_CHEAT, "Amount in game units to shift the player model relative to the direction the player is facing" );
static ConVar cl_legs_clip_height( "cl_legs_clip_height", "0", FCVAR_CHEAT, "Amount in game units of the player model to render up to [0 = disable]", true, 0, false, 0 );

c_baseplayer.cpp

Now, in the int C_BasePlayer::DrawModel( int flags ) function add:

	CMatRenderContextPtr context( materials );

	if ( cl_legs_clip_height.GetInt() > 0 )
	{
		context->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT );
		context->SetHeightClipZ( GetAbsOrigin().z + cl_legs_clip_height.GetFloat() );
	}

Weapon activity list tables

Note.pngNote:This part has been written for Source 2013 Multiplayer Source SDK Base 2013 - Multiplayer.
Todo: Add a singleplayer version of this code.

weapon_357.cpp

In the class description, under the macro DECLARE_DATADESC(), add this line:

DECLARE_ACTTABLE();

Under the class definition around line 50, add this activity table list:

acttable_t CWeapon357::m_acttable[] =
{
	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_PISTOL,					false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_PISTOL,					false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_PISTOL,			false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_PISTOL,			false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,	false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_PISTOL,		false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_PISTOL,					false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_PISTOL,				false },
};

IMPLEMENT_ACTTABLE( CWeapon357 );

weapon_ar2.cpp

There is already an activity list. At its foot, after //{ ACT_RANGE_ATTACK2, ACT_RANGE_ATTACK_AR2_GRENADE, true }, add the following list:

	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_AR2,						false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_AR2,						false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_AR2,				false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_AR2,				false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2,		false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_GESTURE_RELOAD_SMG1,				false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_AR2,						false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_AR2,					false },

weapon_crossbow.cpp

In the class description, around line 450, under the macro DECLARE_DATADESC(), add this line:

DECLARE_ACTTABLE();

Under the class definition around line 489, add this activity table list:

acttable_t CWeaponCrossbow::m_acttable[] =
{
	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_CROSSBOW,					false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_CROSSBOW,						false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_CROSSBOW,				false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_CROSSBOW,				false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW,	false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_CROSSBOW,			false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_CROSSBOW,					false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_SHOTGUN,					false },
};

IMPLEMENT_ACTTABLE( CWeaponCrossbow );

weapon_crowbar.cpp

There is already an activity list. At its foot, after { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, false }, add the following list:

	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_SLAM,					true },
	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_MELEE,					false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_MELEE,					false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_MELEE,			false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_MELEE,			false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE,	false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_MELEE,			false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_MELEE,					false },

weapon_frag.cpp

There is already an activity list. At its foot, after { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true }, add the following list:

	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_GRENADE,						false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_GRENADE,						false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_GRENADE,				false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_GRENADE,				false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE,		false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_GRENADE,			false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_GRENADE,						false },

weapon_physcannon.cpp

In the class description, around line 1203, under the macro DECLARE_DATADESC(), add this line:

DECLARE_ACTTABLE();

Under the class definition around line 1374, add this activity table list:

acttable_t CWeaponPhysCannon::m_acttable[] =
{
	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_PHYSGUN,						false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_PHYSGUN,						false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_PHYSGUN,				false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_PHYSGUN,				false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_PHYSGUN,		false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_PHYSGUN,			false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_PHYSGUN,						false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_SLAM,						false },
};

IMPLEMENT_ACTTABLE( CWeaponPhysCannon );

weapon_pistol.cpp

There is already an activity list. At its foot, after { ACT_RUN, ACT_RUN_PISTOL, false }, add the following list:

	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_PISTOL,					false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_PISTOL,					false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_PISTOL,			false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_PISTOL,			false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,	false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_PISTOL,		false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_PISTOL,					false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_PISTOL,				false },

weapon_rpg.cpp

There is already an activity list. At it's foot, after { ACT_COVER_LOW, ACT_COVER_LOW_RPG, true }, add the following list:

	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_RPG,						false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_RPG,						false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_RPG,				false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_RPG,				false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_RPG,		false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_RPG,			false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_RPG,						false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_RPG,					false },

weapon_shotgun.cpp

There is already an activity list. At its foot, after { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false }, add the following list:

	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_SHOTGUN,						false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_SHOTGUN,						false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_SHOTGUN,				false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_SHOTGUN,				false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN,		false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_SHOTGUN,			false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_SHOTGUN,						false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_SHOTGUN,					false },

weapon_smg1.cpp

There is already an activity list. At its foot, after { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true }, add the following list:

	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_SMG1,					false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_SMG1,						false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_SMG1,				false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_SMG1,				false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1,	false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_GESTURE_RELOAD_SMG1,				false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_SMG1,					false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_SMG1,					false },