Ru/Legs in Firstperson: Difference between revisions
| Line 1,187: | Line 1,187: | ||
| При создание модели делайте её как  gordon_body_ref.smd или как на картинки [http://img689.imageshack.us/img689/7449/part1s.jpg здесь]. | При создание модели делайте её как  gordon_body_ref.smd или как на картинки [http://img689.imageshack.us/img689/7449/part1s.jpg здесь]. | ||
| == | ==Конечный продукт== | ||
| Посмотрите конечный продукт  [http://youtu.be/GiPg3-QJeic here] здесь. | |||
| ==Acknowledgments== | ==Acknowledgments== | ||
Revision as of 10:59, 8 February 2014
Примечание: Работает только в 2007 версии движка( OB )
Это не работает в мультиплеере, потому что заменяет модель thirdperson на модель без рук и головы.
Примечание:Не работает в 2013 версии движка
Рекомендуется
- Valve's Source Engine code ( 2007 ) Single Player.
- Программы для 3д моделирование ( XSI, 3DS Max, Blender etc )
- Модели ( доступные здесь Here ) <-- Исправленные текстуры
- Мозг
Система анимации.
Вам необходимо использовать код Malortie для работы.
Создайте два файла в shared папке вашего мода.
Первый это "singleplayer_animstate.h".
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Single Player animation state 'handler'. This utility is used
//            to evaluate the pose parameter value based on the direction
//            and speed of the player.
//
//====================================================================================//
#ifndef SINGLEPLAYER_ANIMSTATE_H
#define SINGLEPLAYER_ANIMSTATE_H
#ifdef _WIN32
#pragma once
#endif
#include "cbase.h"
#ifdef CLIENT_DLL
#include "c_baseplayer.h"
#else
#include "player.h"
#endif
class CSinglePlayerAnimState
{
public:
    enum
    {
        TURN_NONE = 0,
        TURN_LEFT,
        TURN_RIGHT
    };
    CSinglePlayerAnimState( CBasePlayer *pPlayer );
    void Init( CBasePlayer *pPlayer );
    Activity            BodyYawTranslateActivity( Activity activity );
    void                Update();
    const QAngle&        GetRenderAngles();
               
    void                GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] );
    CBasePlayer        *GetBasePlayer();
    void Release();
private:
    void                GetOuterAbsVelocity( Vector& vel );
    int                    ConvergeAngles( float goal,float maxrate, float dt, float& current );
    void                EstimateYaw( void );
    void                ComputePoseParam_BodyYaw( void );
    void                ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr );
    void                ComputePoseParam_BodyLookYaw( void );
    void                ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr );
    void                ComputePlaybackRate();
    CBasePlayer        *m_pPlayer;
    float                m_flGaitYaw;
    float                m_flStoredCycle;
    float                m_flGoalFeetYaw;
    float                m_flCurrentFeetYaw;
    float                m_flCurrentTorsoYaw;
    float                m_flLastYaw;
    float                m_flLastTurnTime;
    int                    m_nTurningInPlace;
    QAngle                m_angRender;
    float                m_flTurnCorrectionTime;
};
CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer );
#endif // SINGLEPLAYER_ANIMSTATE_H
Файл завершен добавляем второй файл "singleplayer_animstate.cpp"
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Single Player animation state 'handler'. This utility is used
//            to evaluate the pose parameter value based on the direction
//            and speed of the player.
//
//====================================================================================//
#include "cbase.h"
#include "singleplayer_animstate.h"
#include "tier0/vprof.h"
#include "animation.h"
#include "studio.h"
#include "apparent_velocity_helper.h"
#include "utldict.h"
#include "filesystem.h"
extern ConVar mp_facefronttime, mp_feetyawrate, mp_ik;
#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION        15.0f
CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer )
{
    MDLCACHE_CRITICAL_SECTION();
    CSinglePlayerAnimState *pState = new CSinglePlayerAnimState( pPlayer );
    pState->Init(pPlayer);
    return pState;
}
// Below this many degrees, slow down turning rate linearly
#define FADE_TURN_DEGREES    45.0f
// After this, need to start turning feet
#define MAX_TORSO_ANGLE        90.0f
// Below this amount, don't play a turning animation/perform IK
#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION        15.0f
//static ConVar tf2_feetyawrunscale( "tf2_feetyawrunscale", "2", FCVAR_REPLICATED, "Multiplier on tf2_feetyawrate to allow turning faster when running." );
extern ConVar sv_backspeed;
extern ConVar mp_feetyawrate;
extern ConVar mp_facefronttime;
extern ConVar mp_ik;
CSinglePlayerAnimState::CSinglePlayerAnimState( CBasePlayer *pPlayer ): m_pPlayer( pPlayer )
{
    m_flGaitYaw = 0.0f;
    m_flGoalFeetYaw = 0.0f;
    m_flCurrentFeetYaw = 0.0f;
    m_flCurrentTorsoYaw = 0.0f;
    m_flLastYaw = 0.0f;
    m_flLastTurnTime = 0.0f;
    m_flTurnCorrectionTime = 0.0f;
    m_pPlayer = NULL;
};
void CSinglePlayerAnimState::Init( CBasePlayer *pPlayer )
{
    m_pPlayer = pPlayer;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::Update()
{
    m_angRender = GetBasePlayer()->GetLocalAngles();
    ComputePoseParam_BodyYaw();
    ComputePoseParam_BodyPitch(GetBasePlayer()->GetModelPtr());
    ComputePoseParam_BodyLookYaw();
    ComputePoseParam_HeadPitch(GetBasePlayer()->GetModelPtr());
    ComputePlaybackRate();
}
void CSinglePlayerAnimState::Release()
{
    delete this;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePlaybackRate()
{
    // Determine ideal playback rate
    Vector vel;
    GetOuterAbsVelocity( vel );
    float speed = vel.Length2D();
    bool isMoving = ( speed > 0.5f ) ? true : false;
    float maxspeed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() );
   
    if ( isMoving && ( maxspeed > 0.0f ) )
    {
        float flFactor = 1.0f;
        // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
        GetBasePlayer()->SetPlaybackRate( ( speed * flFactor ) / maxspeed );
        // BUG BUG:
        // This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed
    }
    else
    {
        GetBasePlayer()->SetPlaybackRate( 1.0f );
    }
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : CBasePlayer
//-----------------------------------------------------------------------------
CBasePlayer *CSinglePlayerAnimState::GetBasePlayer()
{
    return m_pPlayer;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input  : dt -
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::EstimateYaw( void )
{
    float dt = gpGlobals->frametime;
    if ( !dt )
    {
        return;
    }
    Vector est_velocity;
    QAngle    angles;
    GetOuterAbsVelocity( est_velocity );
    angles = GetBasePlayer()->GetLocalAngles();
    if ( est_velocity[1] == 0 && est_velocity[0] == 0 )
    {
        float flYawDiff = angles[YAW] - m_flGaitYaw;
        flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
        if (flYawDiff > 180)
            flYawDiff -= 360;
        if (flYawDiff < -180)
            flYawDiff += 360;
        if (dt < 0.25)
            flYawDiff *= dt * 4;
        else
            flYawDiff *= dt;
        m_flGaitYaw += flYawDiff;
        m_flGaitYaw = m_flGaitYaw - (int)(m_flGaitYaw / 360) * 360;
    }
    else
    {
        m_flGaitYaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
        if (m_flGaitYaw > 180)
            m_flGaitYaw = 180;
        else if (m_flGaitYaw < -180)
            m_flGaitYaw = -180;
    }
}
//-----------------------------------------------------------------------------
// Purpose: Override for backpeddling
// Input  : dt -
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_BodyYaw( void )
{
    int iYaw = GetBasePlayer()->LookupPoseParameter( "move_yaw" );
    if ( iYaw < 0 )
        return;
    // view direction relative to movement
    float flYaw;     
    EstimateYaw();
    QAngle    angles = GetBasePlayer()->GetLocalAngles();
    float ang = angles[ YAW ];
    if ( ang > 180.0f )
    {
        ang -= 360.0f;
    }
    else if ( ang < -180.0f )
    {
        ang += 360.0f;
    }
    // calc side to side turning
    flYaw = ang - m_flGaitYaw;
    // Invert for mapping into 8way blend
    flYaw = -flYaw;
    flYaw = flYaw - (int)(flYaw / 360) * 360;
    if (flYaw < -180)
    {
        flYaw = flYaw + 360;
    }
    else if (flYaw > 180)
    {
        flYaw = flYaw - 360;
    }
   
    GetBasePlayer()->SetPoseParameter( iYaw, flYaw );
#ifndef CLIENT_DLL
        //Adrian: Make the model's angle match the legs so the hitboxes match on both sides.
        GetBasePlayer()->SetLocalAngles( QAngle( GetBasePlayer()->EyeAngles().x, m_flCurrentFeetYaw, 0 ) );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
{
    // Get pitch from v_angle
    float flPitch = GetBasePlayer()->GetLocalAngles()[ PITCH ];
    if ( flPitch > 180.0f )
    {
        flPitch -= 360.0f;
    }
    flPitch = clamp( flPitch, -90, 90 );
    QAngle absangles = GetBasePlayer()->GetAbsAngles();
    absangles.x = 0.0f;
    m_angRender = absangles;
    // See if we have a blender for pitch
    GetBasePlayer()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input  : goal -
//            maxrate -
//            dt -
//            current -
// Output : int
//-----------------------------------------------------------------------------
int CSinglePlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current )
{
    int direction = TURN_NONE;
    float anglediff = goal - current;
    float anglediffabs = fabs( anglediff );
    anglediff = AngleNormalize( anglediff );
    float scale = 1.0f;
    if ( anglediffabs <= FADE_TURN_DEGREES )
    {
        scale = anglediffabs / FADE_TURN_DEGREES;
        // Always do at least a bit of the turn ( 1% )
        scale = clamp( scale, 0.01f, 1.0f );
    }
    float maxmove = maxrate * dt * scale;
    if ( fabs( anglediff ) < maxmove )
    {
        current = goal;
    }
    else
    {
        if ( anglediff > 0 )
        {
            current += maxmove;
            direction = TURN_LEFT;
        }
        else
        {
            current -= maxmove;
            direction = TURN_RIGHT;
        }
    }
    current = AngleNormalize( current );
    return direction;
}
void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void )
{
    QAngle absangles = GetBasePlayer()->GetAbsAngles();
    absangles.y = AngleNormalize( absangles.y );
    m_angRender = absangles;
    // See if we even have a blender for pitch
    int upper_body_yaw = GetBasePlayer()->LookupPoseParameter( "aim_yaw" );
    if ( upper_body_yaw < 0 )
    {
        return;
    }
    // Assume upper and lower bodies are aligned and that we're not turning
    float flGoalTorsoYaw = 0.0f;
    int turning = TURN_NONE;
    float turnrate = 360.0f;
    Vector vel;
   
    GetOuterAbsVelocity( vel );
    bool isMoving = ( vel.Length() > 1.0f ) ? true : false;
    if ( !isMoving )
    {
        // Just stopped moving, try and clamp feet
        if ( m_flLastTurnTime <= 0.0f )
        {
            m_flLastTurnTime    = gpGlobals->curtime;
            m_flLastYaw            = GetBasePlayer()->EyeAngles().y;
            // Snap feet to be perfectly aligned with torso/eyes
            m_flGoalFeetYaw        = GetBasePlayer()->EyeAngles().y;
            m_flCurrentFeetYaw    = m_flGoalFeetYaw;
            m_nTurningInPlace    = TURN_NONE;
        }
        // If rotating in place, update stasis timer
        if ( m_flLastYaw != GetBasePlayer()->EyeAngles().y )
        {
            m_flLastTurnTime    = gpGlobals->curtime;
            m_flLastYaw            = GetBasePlayer()->EyeAngles().y;
        }
        if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
        {
            m_flLastTurnTime    = gpGlobals->curtime;
        }
        turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
        QAngle eyeAngles = GetBasePlayer()->EyeAngles();
        QAngle vAngle = GetBasePlayer()->GetLocalAngles();
        // See how far off current feetyaw is from true yaw
        float yawdelta = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw;
        yawdelta = AngleNormalize( yawdelta );
        bool rotated_too_far = false;
        float yawmagnitude = fabs( yawdelta );
        // If too far, then need to turn in place
        if ( yawmagnitude > 45 )
        {
            rotated_too_far = true;
        }
        // Standing still for a while, rotate feet around to face forward
        // Or rotated too far
        // FIXME:  Play an in place turning animation
        if ( rotated_too_far ||
            ( gpGlobals->curtime > m_flLastTurnTime + mp_facefronttime.GetFloat() ) )
        {
            m_flGoalFeetYaw        = GetBasePlayer()->EyeAngles().y;
            m_flLastTurnTime    = gpGlobals->curtime;
        /*    float yd = m_flCurrentFeetYaw - m_flGoalFeetYaw;
            if ( yd > 0 )
            {
                m_nTurningInPlace = TURN_RIGHT;
            }
            else if ( yd < 0 )
            {
                m_nTurningInPlace = TURN_LEFT;
            }
            else
            {
                m_nTurningInPlace = TURN_NONE;
            }
            turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
            yawdelta = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw;*/
        }
        // Snap upper body into position since the delta is already smoothed for the feet
        flGoalTorsoYaw = yawdelta;
        m_flCurrentTorsoYaw = flGoalTorsoYaw;
    }
    else
    {
        m_flLastTurnTime = 0.0f;
        m_nTurningInPlace = TURN_NONE;
        m_flCurrentFeetYaw = m_flGoalFeetYaw = GetBasePlayer()->EyeAngles().y;
        flGoalTorsoYaw = 0.0f;
        m_flCurrentTorsoYaw = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw;
    }
    if ( turning == TURN_NONE )
    {
        m_nTurningInPlace = turning;
    }
    if ( m_nTurningInPlace != TURN_NONE )
    {
        // If we're close to finishing the turn, then turn off the turning animation
        if ( fabs( m_flCurrentFeetYaw - m_flGoalFeetYaw ) < MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION )
        {
            m_nTurningInPlace = TURN_NONE;
        }
    }
    // Rotate entire body into position
    absangles = GetBasePlayer()->GetAbsAngles();
    absangles.y = m_flCurrentFeetYaw;
    m_angRender = absangles;
    GetBasePlayer()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) );
    /*
    // FIXME: Adrian, what is this?
    int body_yaw = GetBasePlayer()->LookupPoseParameter( "body_yaw" );
    if ( body_yaw >= 0 )
    {
        GetBasePlayer()->SetPoseParameter( body_yaw, 30 );
    }
    */
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr )
{
    // Get pitch from v_angle
    int iHeadPitch = GetBasePlayer()->LookupPoseParameter("head_pitch");
    float flPitch = GetBasePlayer()->EyeAngles()[PITCH];
    if ( flPitch > 180.0f )
    {
        flPitch -= 360.0f;
    }
    flPitch = clamp( flPitch, -90, 90 );
    QAngle absangles = GetBasePlayer()->GetAbsAngles();
    absangles.x = 0.0f;
    m_angRender = absangles;
    GetBasePlayer()->SetPoseParameter( pStudioHdr, iHeadPitch, flPitch );
}
 
//-----------------------------------------------------------------------------
// Purpose:
// Input  : activity -
// Output : Activity
//-----------------------------------------------------------------------------
Activity CSinglePlayerAnimState::BodyYawTranslateActivity( Activity activity )
{
    // Not even standing still, sigh
    if ( activity != ACT_IDLE )
        return activity;
    // Not turning
    switch ( m_nTurningInPlace )
    {
    default:
    case TURN_NONE:
        return activity;
    /*
    case TURN_RIGHT:
        return ACT_TURNRIGHT45;
    case TURN_LEFT:
        return ACT_TURNLEFT45;
    */
    case TURN_RIGHT:
    case TURN_LEFT:
        return mp_ik.GetBool() ? ACT_TURN : activity;
    }
    Assert( 0 );
    return activity;
}
const QAngle& CSinglePlayerAnimState::GetRenderAngles()
{
    return m_angRender;
}
void CSinglePlayerAnimState::GetOuterAbsVelocity( Vector& vel )
{
#if defined( CLIENT_DLL )
    GetBasePlayer()->EstimateAbsVelocity( vel );
#else
    vel = GetBasePlayer()->GetAbsVelocity();
#endif
}
Полная реализация
В "c_baseplayer.cpp" иищем следующие функцию:
bool IsInFreezeCam( void )И внизу добавляем:
bool IsInEye( void )
{
	C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
	if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
	return true;
}
Потом, в этом файле ищем: 
bool C_BasePlayer::ShouldDraw()
И заменяем на:
bool C_BasePlayer::ShouldDraw()
{
	return BaseClass::ShouldDraw();
}
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);
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;
}
Теперь в функции
int C_BasePlayer::DrawModel( int flags )
Добавляем:
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());
        }
Теперь, ищем функцию
void C_BasePlayer::AddEntity( void )
и под этим
// Add in lighting effects
CreateLightEffects();
добавляем
SetLocalAnglesDim(X_INDEX, 0 );
Сейчас, в "c_baseplayer.h", ищем 
bool IsInFreezeCam( void );
и под этим добавляем:
bool IsInEye( void );
В этом же файле ищем:
virtual int DrawModel( int flags );
И добавляем:
const Vector& C_BasePlayer::GetRenderOrigin();
Потом, открываем "hl2_player.cpp" и добавляем
#define PLAYER_MODEL "models/player.mdl"
После всех #define.
Сейчас ищем:
void CHL2_Player::Precache( void )
И добавляем
PrecacheModel(PLAYER_MODEL);
Теперь, ищем
void CHL2_Player::Spawn(void)
и ищем следующею линию
SetModel( "models/player.mdl" );
и заменяем на
SetModel( PLAYER_MODEL );
Сейчас, Ищем
CHL2_Player::~CHL2_Player( void )
и заменяем на:
	
CHL2_Player::~CHL2_Player( void )
{
	// FPLEGS - Destructor defualt empty! Added code below!
	// Clears the animation state.
	if ( m_pPlayerAnimState != NULL )
	{
	    m_pPlayerAnimState->Release();
	    m_pPlayerAnimState = NULL;
	}
}
Так, ищем
CHL2_Player::CHL2_Player()
и заменяем на:
CHL2_Player::CHL2_Player()
{
	// FPLEGS
	m_pPlayerAnimState = CreatePlayerAnimationState(this);
	m_angEyeAngles.Init();
	// FPLEGS END
	m_nNumMissPositions	= 0;
	m_pPlayerAISquad = 0;
	m_bSprintEnabled = true;
	m_flArmorReductionTime = 0.0f;
	m_iArmorReductionFrom = 0;
}
Сейчас, поднимите голову верх:
void CHL2_Player::PostThink( void )
и замените на:
void CHL2_Player::PostThink( void )
{
	BaseClass::PostThink();
	if ( !g_fGameOver && !IsPlayerLockedInPlace() && IsAlive() )
	{
		 HandleAdmireGlovesAnimation();
	}
	// FPLEGS
	m_angEyeAngles = EyeAngles();
	QAngle angles = GetLocalAngles();
	angles[PITCH] = 0;
	SetLocalAngles( angles );
	m_pPlayerAnimState->Update();
}
Сейчас,Добавьте это в конец файла:
void CHL2_Player::SetAnimation( PLAYER_ANIM playerAnim )
{
    int animDesired;
 
    float speed;
 
    speed = GetAbsVelocity().Length2D();
 
    if ( GetFlags() & ( FL_FROZEN | FL_ATCONTROLS ) )
    {
        speed = 0;
        playerAnim = PLAYER_IDLE;
    }
 
    Activity idealActivity = ACT_HL2MP_RUN;
 
    if ( playerAnim == PLAYER_JUMP )
    {
        if ( HasWeapons() )
            idealActivity = ACT_HL2MP_JUMP;
        else
            idealActivity = ACT_JUMP;
    }
    else if ( playerAnim == PLAYER_DIE )
    {
        if ( m_lifeState == LIFE_ALIVE )
        {
            return;
        }
    }
    else if ( playerAnim == PLAYER_ATTACK1 )
    {
        if ( GetActivity( ) == ACT_HOVER    ||
             GetActivity( ) == ACT_SWIM        ||
             GetActivity( ) == ACT_HOP        ||
             GetActivity( ) == ACT_LEAP        ||
             GetActivity( ) == ACT_DIESIMPLE )
        {
            idealActivity = GetActivity( );
        }
        else
        {
            idealActivity = ACT_HL2MP_GESTURE_RANGE_ATTACK;
        }
    }
    else if ( playerAnim == PLAYER_RELOAD )
    {
        idealActivity = ACT_HL2MP_GESTURE_RELOAD;
    }
    else if ( playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK )
    {
        if ( !( GetFlags() & FL_ONGROUND ) && ( GetActivity( ) == ACT_HL2MP_JUMP || GetActivity( ) == ACT_JUMP ) )    // Still jumping
        {
            idealActivity = GetActivity( );
        }   
        else if ( GetWaterLevel() > 1 )
        {
            if ( speed == 0 )
            {
                if ( HasWeapons() )
                    idealActivity = ACT_HL2MP_IDLE;
                else
                    idealActivity = ACT_IDLE;
            }
            else
            {
                if ( HasWeapons() )
                    idealActivity = ACT_HL2MP_RUN;
                else
                    idealActivity = ACT_RUN;
            }
        }
        else
        {
            if ( GetFlags() & FL_DUCKING )
            {
                if ( speed > 0 )
                {
                    if ( HasWeapons() )
                        idealActivity = ACT_HL2MP_WALK_CROUCH;
                    else
                        idealActivity = ACT_WALK_CROUCH;
                }
                else
                {
                    if ( HasWeapons() )
                        idealActivity = ACT_HL2MP_IDLE_CROUCH;
                    else
                        idealActivity = ACT_COVER_LOW;
                }
            }
            else
            {
                if ( speed > 0 )
                {
                    {
                        if ( HasWeapons() )
                            idealActivity = ACT_HL2MP_RUN;
                        else
                        {
                            if ( speed > HL2_WALK_SPEED + 20.0f )
                                idealActivity = ACT_RUN;
                            else
                                idealActivity = ACT_WALK;
                        }
                    }
                }
                else
                {
                    if ( HasWeapons() )
                    idealActivity = ACT_HL2MP_IDLE;
                    else
                    idealActivity = ACT_IDLE;
                }
            }
        }
 
        //idealActivity = TranslateTeamActivity( idealActivity );
    }
 
    if ( IsInAVehicle() )
    {
        idealActivity = ACT_COVER_LOW;
    }
 
    if ( idealActivity == ACT_HL2MP_GESTURE_RANGE_ATTACK )
    {
        RestartGesture( Weapon_TranslateActivity( idealActivity ) );
 
        // FIXME: this seems a bit wacked
        Weapon_SetActivity( Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 );
 
        return;
    }
    else if ( idealActivity == ACT_HL2MP_GESTURE_RELOAD )
    {
        RestartGesture( Weapon_TranslateActivity( idealActivity ) );
        return;
    }
    else
    {
        SetActivity( idealActivity );
 
        animDesired = SelectWeightedSequence( Weapon_TranslateActivity ( idealActivity ) );
 
        if (animDesired == -1)
        {
            animDesired = SelectWeightedSequence( idealActivity );
 
            if ( animDesired == -1 )
            {
                animDesired = 0;
            }
        }
 
        // Already using the desired animation?
        if ( GetSequence() == animDesired )
            return;
 
        m_flPlaybackRate = 1.0;
        ResetSequence( animDesired );
        SetCycle( 0 );
        return;
    }
 
    // Already using the desired animation?
    if ( GetSequence() == animDesired )
        return;
 
    //Msg( "Set animation to %d\n", animDesired );
    // Reset to first frame of desired animation
    ResetSequence( animDesired );
    SetCycle( 0 );
}
Потом, идём в "hl2_player.h" и добавляем
#include "singleplayer_animstate.h"
в начала файла.
Сейчас, идем в конец "public:" в классе
class CHL2_Player : public
и добавляем
void SetAnimation( PLAYER_ANIM playerAnim );
сейчас,идём в конец класс, в "private:" секцую добавляем 
	CSinglePlayerAnimState *m_pPlayerAnimState;
	QAngle m_angEyeAngles;
Weapon activity list tables
In 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 );
In weapon_ar2.cpp:
There is already an activity list. At it's 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 },
In 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 );
In weapon_crowbar.cpp:
There is already an activity list. At it's 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 },
In weapon_frag.cpp:
There is already an activity list. At it's 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,
In 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 );
In weapon_pistol.cpp:
There is already an activity list. At it's 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 },
In 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 },
In weapon_shotgun.cpp:
There is already an activity list. At it's 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 },
In weapon_smg1.cpp:
There is already an activity list. At it's 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 },
Создание модели
Если ты хочешь создать свою модель, скачайте оригинальные player.mdl SMD файлы вот ссылка здесь.
При создание модели делайте её как gordon_body_ref.smd или как на картинки здесь.
Конечный продукт
Посмотрите конечный продукт here здесь.
Acknowledgments
- Singleplayer Animation Code - Malortie
- Weapon Activity Tables - Malortie
- Other Stuff - Zombie Killa
- Gordon Freeman - VALVe and DPFilms
- Туториал ExoBacon
- Перевёл я