Legs in Firstperson (2013): Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Create guide.)
 
No edit summary
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
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.
{{Note|This hasn't been tested with {{Mapbase|4.1}}, {{Team Fortress 2|4}}, nor {{src13mp|4|nt=0}}.}}
{{Note| {{Mapbase|4.1}} already support Legs in Firstperson, as of this commit/pull request. {{github|mapbase-source/source-sdk-2013/pull/316/commits/abeb035d29676725bd492ee94486687b3deae9a2|This commit specifically}}.
Can be enabled by placing ''player_default_legs 1'' into your gameinfo, and replacing the default player.mdl with one from ''models\player'' directory.}}
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 ==
== Requirements ==
# Animation state system implementation.
# Animation state system implementation.
# Knowledge of C++
# Knowledge of C++
# A single player mod running on Source SDK 2013 ({{Mapbase|3.2}} has NOT been tested.)
# A single player mod running on Source SDK 2013


== Full implementation ==
== Full implementation ==
Line 25: Line 28:
else
else
{
{
return false;
return false;
}
}
}
}
Line 80: Line 83:


== Weapon activity list tables ==
== Weapon activity list tables ==
 
{{Note|This part has been written for {{src13mp|4|nt=0}}.}}
{{Todo|Add a singleplayer version of this code.}}
=== weapon_357.cpp ===
=== weapon_357.cpp ===


Line 105: Line 109:
=== weapon_ar2.cpp ===
=== weapon_ar2.cpp ===


There is already an activity list. At it's foot, after <code>//{ ACT_RANGE_ATTACK2, ACT_RANGE_ATTACK_AR2_GRENADE, true },</code> add the following list:
There is already an activity list. At its foot, after <code>//{ ACT_RANGE_ATTACK2, ACT_RANGE_ATTACK_AR2_GRENADE, true },</code> add the following list:
<source lang=cpp>
<source lang=cpp>
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR2, false },
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR2, false },
Line 141: Line 145:
=== weapon_crowbar.cpp ===
=== weapon_crowbar.cpp ===


There is already an activity list. At it's foot, after <code>{ ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, false },</code> add the following list:
There is already an activity list. At its foot, after <code>{ ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, false },</code> add the following list:
<source lang=cpp>
<source lang=cpp>
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true },
Line 155: Line 159:
=== weapon_frag.cpp ===
=== weapon_frag.cpp ===


There is already an activity list. At it's foot, after <code>{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true },</code> add the following list:
There is already an activity list. At its foot, after <code>{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true },</code> add the following list:
<source lang=cpp>
<source lang=cpp>
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_GRENADE, false },
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_GRENADE, false },
Line 190: Line 194:
=== weapon_pistol.cpp ===
=== weapon_pistol.cpp ===


There is already an activity list. At it's foot, after <code>{ ACT_RUN, ACT_RUN_PISTOL, false },</code> add the following list:
There is already an activity list. At its foot, after <code>{ ACT_RUN, ACT_RUN_PISTOL, false },</code> add the following list:
<source lang=cpp>
<source lang=cpp>
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false },
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false },
Line 218: Line 222:
=== weapon_shotgun.cpp ===
=== weapon_shotgun.cpp ===


There is already an activity list. At it's foot, after <code>{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false },</code> add the following list:
There is already an activity list. At its foot, after <code>{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false },</code> add the following list:
<source lang=cpp>
<source lang=cpp>
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SHOTGUN, false },
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SHOTGUN, false },
Line 232: Line 236:
=== weapon_smg1.cpp ===
=== weapon_smg1.cpp ===


There is already an activity list. At it's foot, after <code>{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true },</code> add the following list:
There is already an activity list. At its foot, after <code>{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true },</code> add the following list:
<source lang=cpp>
<source lang=cpp>
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SMG1, false },
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SMG1, false },

Latest revision as of 01:58, 21 April 2025

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. Can be enabled by placing player_default_legs 1 into your gameinfo, and replacing the default player.mdl with one from models\player directory.

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 },