7629 lines
194 KiB
C++
7629 lines
194 KiB
C++
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Game Source Code
|
|
//
|
|
// File: XEntityPlayer.cpp
|
|
// Description: Entity player class.
|
|
//
|
|
// History:
|
|
// - August 16, 2001: Created by Alberto Demichelis
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "XPlayer.h"
|
|
#include "WeaponClass.h"
|
|
#include "XVehicle.h"
|
|
#include "WeaponSystemEx.h"
|
|
#include "ScriptObjectStream.h"
|
|
|
|
#include <IEntitySystem.h>
|
|
#include <IAISystem.h>
|
|
#include <IAgent.h>
|
|
|
|
// remove this
|
|
//#include <IAISystem.h>
|
|
#include <ISound.h>
|
|
// <<FIXME>> look above
|
|
#include "I3DEngine.h"
|
|
#include <crycharanimationparams.h>
|
|
|
|
|
|
// to use _isnan()
|
|
#include <float.h>
|
|
|
|
//! Minimal time before player can be alive again.
|
|
#define PLAYER_RESPAWN_TIME 1.0f
|
|
//! Minimal time before player can be respawned.
|
|
#define PLAYER_DEATH_TIME 1.0f
|
|
|
|
//! Minimal time before player can change weapon.
|
|
#define PLAYER_WEAPON_CHANGE_TIME 0.1f
|
|
|
|
/*
|
|
static int64 g_nValidateHeapCounter = 0;
|
|
// central place to turn on/off the heap validation
|
|
inline void ValidateHeap()
|
|
{
|
|
#if defined(WIN64) && defined(_DEBUG) // on AMD64, heap validation is extremely slow
|
|
if (g_nValidateHeapCounter > 1000*1000 || !((++g_nValidateHeapCounter)&0xFF))
|
|
#endif
|
|
assert(IsHeapValid());
|
|
}
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
bool CheckIfNAN( const Vec3d& vPos )
|
|
{
|
|
if (_isnan(vPos.x) || _isnan(vPos.y) || _isnan(vPos.z))
|
|
{
|
|
GameWarning( "NotANumber tried to be set for position of CPlayer" );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
//! CPlayer implemenation.
|
|
|
|
///////////////////////////////////////////////
|
|
CPlayer::CPlayer(CXGame *pGame) :
|
|
m_ssoHitPosVec(pGame->GetScriptSystem()),
|
|
m_ssoHitDirVec(pGame->GetScriptSystem()),
|
|
m_ssoHitNormVec(pGame->GetScriptSystem()),
|
|
m_vColor(1,0,1),
|
|
m_vShake(0,0,0),
|
|
m_pDynLight( NULL ),
|
|
m_vCharacterAngles( 0,0,0 ),
|
|
m_JumpStage(0),
|
|
m_JumpAniLenght(0),
|
|
m_bInertiaOverride(false),
|
|
m_bIsFish(false),
|
|
m_AutoCenter(0),
|
|
m_fNoChangeangleTime(0.0f),
|
|
m_fProcessTime(0.0f),
|
|
m_fCameraTime(0.0f),
|
|
m_vEyeAnglesBaseOffset(0,0,0),
|
|
m_bLastDeltaEyeVehicle( false ),
|
|
m_vSafeAngAtMountedWeapon(0,0,0),
|
|
m_MntWeaponStandTime(0.0f),
|
|
m_vProneEnvNormal(0,0,0),
|
|
m_vCurEntAngle(0,0,0),
|
|
m_bGrenadeAnimation(false)
|
|
{
|
|
m_pLastUsedCharacter = NULL;
|
|
m_weaponPositionState = WEAPON_POS_UNDEFINED;
|
|
m_vEyePos.Set(0,0,0);
|
|
m_bWeaponJustFired = false;
|
|
m_pLightTarget = 0;
|
|
float tm=.3f;
|
|
|
|
m_pBoneHead = NULL;
|
|
m_pBoneNeck = NULL;
|
|
m_pBoneSpine = NULL;
|
|
m_pBoneSpine1 = NULL;
|
|
m_pBoneSpine2 = NULL;
|
|
|
|
m_pGame = pGame;
|
|
m_pTimer = pGame->GetSystem()->GetITimer();
|
|
m_pScriptSystem = pGame->GetScriptSystem();
|
|
m_p3DEngine = pGame->GetSystem()->GetI3DEngine();
|
|
m_pPhysicalWorld=pGame->GetSystem()->GetIPhysicalWorld();
|
|
m_stmScriptStream.Create(m_pScriptSystem);
|
|
m_nSelectedWeaponID = -1;
|
|
m_PrevWeaponID = -1;
|
|
|
|
ZeroStruct( m_stats );
|
|
m_stats.weapon = -1;
|
|
m_stats.inVehicleState = PVS_OUT;
|
|
// m_stats.inVehicleActive = false;
|
|
|
|
ZeroStruct( m_walkParams );
|
|
// Init Walk params.
|
|
m_walkParams.runRoll = 0.2f;
|
|
m_walkParams.runPitch = 0.5f;
|
|
m_walkParams.curLength = 0.0f;
|
|
m_walkParams.stepLength = 3.5f;
|
|
m_walkParams.flyCoeff = 15.0f;
|
|
m_walkParams.prevF = 0.0f;
|
|
m_walkParams.weaponCycle = 0.006f;
|
|
m_walkParams.weaponCycleSpeed = 8;
|
|
m_walkParams.swayAmp=0.0f;
|
|
m_walkParams.swayFreq=0.0f;
|
|
m_walkParams.swayOfs=0.0f;
|
|
m_walkParams.shakeDegree=0.0f;
|
|
m_walkParams.leanAmount = 0.0f;
|
|
m_walkParams.leanStart = 0.0f;
|
|
m_walkParams.leanEnd = 0.0f;
|
|
m_walkParams.leanFactor = 0.0f;
|
|
m_walkParams.fWaterPitchPhase=0.0f;
|
|
m_walkParams.fWaterRollPhase=0.0f;
|
|
|
|
m_walkParams.fLeanTarget=0;
|
|
m_walkParams.fCurrLean=0;
|
|
|
|
m_pVehicle = NULL;
|
|
|
|
//@FIXME Give player some life
|
|
m_stats.health = 100;
|
|
m_stats.armor = 0;
|
|
m_stats.maxHealth = 100;
|
|
m_stats.maxArmor = 100;
|
|
|
|
m_stats.legHealth = 100;
|
|
m_stats.maxLegHealth = 100;
|
|
m_stats.armHealth = 100;
|
|
m_stats.maxArmHealth = 100;
|
|
|
|
m_stats.dmgFireAccuracy = 100;
|
|
m_stats.dmgSpeedCoeff = 100;
|
|
|
|
|
|
m_stats.FiringType = m_stats.LastFiringType = eNotFiring;
|
|
m_stats.cancelFireFlag = false;
|
|
|
|
m_stats.weapon = 0;
|
|
m_stats.score=0;
|
|
m_stats.deaths=0;
|
|
m_stats.firing_grenade = false;
|
|
m_stats.firemode = 0;
|
|
m_stats.canfire = true;
|
|
m_stats.crosshairOnScreen = true;
|
|
m_stats.fSpeedScale = 1.0f;
|
|
m_stats.climbing = false;
|
|
m_stats.holding_breath=false;
|
|
m_stats.concentration=false;
|
|
m_stats.firing=false;
|
|
m_stats.reloading=false;
|
|
m_stats.weapon_busy=0;
|
|
m_stats.grenadetype = 1;
|
|
m_stats.numofgrenades = 0;
|
|
m_stats.drawfpweapon=true;
|
|
m_stats.aiming=false;
|
|
m_stats.fire_rate_busy=false;
|
|
m_stats.fVel=1.0f;
|
|
m_stats.melee_distance = 0.0f;
|
|
m_stats.has_flashlight = false;
|
|
m_stats.has_binoculars = false;
|
|
m_stats.fInWater = 0.0f;
|
|
m_stats.swimTime = 0.0f;
|
|
m_staminaClient = m_stats.stamina = 100;
|
|
// m_breathClient = m_stats.breath = 100;
|
|
|
|
SetDimNormal();
|
|
SetDimCrouch();
|
|
SetDimProne();
|
|
SetDimStealth();
|
|
|
|
m_currDimensions = eDimNone;
|
|
|
|
ZeroStruct( m_AngleLimitBase );
|
|
m_AngleLimitVFlag = false;
|
|
m_AngleLimitHFlag = false;
|
|
|
|
m_fGravityOverride=1E10;
|
|
|
|
m_pScriptObject=NULL;
|
|
m_pRedirected = NULL;
|
|
|
|
m_nStanding = -1;
|
|
m_nMode = -1;
|
|
m_nStrafe = -1;
|
|
m_nForward = -1;
|
|
|
|
m_bFirstPerson = false;
|
|
m_bFirstPersonLoaded = true;
|
|
|
|
m_bLightOn = false;
|
|
|
|
m_LegAngle = 0;
|
|
m_LegAngleDesired = 0;
|
|
m_LegDeltaAngle = 0;
|
|
m_LegAngleIdleTime = 0;
|
|
m_LegADeltaLimit = 110;
|
|
m_LegADeltaLimitForce = 120;
|
|
m_LegAIdleTimeLimit = 2;
|
|
m_LegAngleVelMoving = 350;
|
|
m_LegAngleVelTimed = 320;
|
|
m_LegAngleVel = m_LegAngleVelMoving;
|
|
|
|
|
|
m_FlyTime = 0;
|
|
m_NotRunTime = 0;
|
|
|
|
m_RunSpeed = 4;
|
|
m_WalkSpeed = 3;
|
|
m_CrouchSpeed = 2;
|
|
m_ProneSpeed = 1;
|
|
m_SwimSpeed = 3.5f;
|
|
m_Sprinting = false;
|
|
|
|
m_CameraMode=PCM_OUTVEHICLE;
|
|
m_bCameraTransitionOnlyZ = false;
|
|
|
|
// SetAnimationRefSpeed();
|
|
SetAnimationRefSpeedRun( );
|
|
SetAnimationRefSpeedWalk( );
|
|
SetAnimationRefSpeedXWalk( );
|
|
SetAnimationRefSpeedCrouch( );
|
|
|
|
|
|
m_JumpForce = 4.0f;
|
|
m_LeanDegree = 9.0f;
|
|
|
|
m_Dynamics.gravity = 9.81f;
|
|
m_Dynamics.swimming_gravity = 2.0f;
|
|
m_Dynamics.inertia = 10.0f;
|
|
m_Dynamics.swimming_inertia = 1.0f;
|
|
m_Dynamics.air_control = 0.1f;
|
|
|
|
m_CurStance = eNone;
|
|
m_PrevStance = m_CurStance;
|
|
|
|
m_aimLook = true;
|
|
m_bIsAI = false;
|
|
|
|
//m_PrevAniName = "NoAni";
|
|
|
|
m_AnimationSystemEnabled = 1;
|
|
|
|
m_bAlwaysRun = true;
|
|
m_bSwimming=false;
|
|
m_bEyesInWater=false; // not in water at the beginning
|
|
m_stats.underwater = 0.0f;
|
|
// standing jump
|
|
m_JumpDist[0] = 3.0f;
|
|
m_JumpHeight[0] = 1.3f;
|
|
// walk jump
|
|
m_JumpDist[1] = 3.0f;
|
|
m_JumpHeight[1] = 1.3f;
|
|
// run jump
|
|
m_JumpDist[2] = 4.0f;
|
|
m_JumpHeight[2] = 1.3f;
|
|
m_fRecoilXDelta=0;
|
|
m_fRecoilZDelta=0;
|
|
m_fRecoilXUp=0;
|
|
m_fRecoilZUp=0;
|
|
m_fRecoilX=0;
|
|
m_fRecoilZ=0;
|
|
m_fAccuracy=0;
|
|
m_fAccuracyMod=0;
|
|
memset(m_vWeaponSlots,0,sizeof(m_vWeaponSlots));
|
|
m_stats.lock_weapon=false;
|
|
|
|
m_fHeatBodyFadingSpeed=m_fHeatWeaponsFadingSpeed=-1; // switch immediately
|
|
m_fHeatBodyDesiredValue=m_fHeatWeaponsDesiredValue=-1; // not set
|
|
m_fHeatBodyCurrValue=m_fHeatWeaponsCurrValue=0;
|
|
|
|
m_LastUsed = m_vBlindingList.end();
|
|
|
|
m_RunSpeedScale = 3.63f;
|
|
m_CrouchSpeedScale = .8f;
|
|
m_ProneSpeedScale = .5f;
|
|
m_XRunSpeedScale = 1.5f; // stealthth
|
|
m_XWalkSpeedScale = .81f;
|
|
m_RRunSpeedScale = 3.63f; // relaxed
|
|
m_RWalkSpeedScale = .81f;
|
|
|
|
m_stats.bIsBlinded = false;
|
|
m_stats.curBlindingValue = 0.0f;
|
|
|
|
m_pMountedWeapon = NULL;
|
|
|
|
m_stats.bIsLimping = false;
|
|
|
|
m_pPrevDmgCollider = 0;
|
|
m_timeDmgCollision = 0;
|
|
m_prevCollDamage = 0;
|
|
|
|
m_sPrevAniName = "";
|
|
m_sPrevAniNameLayer1 = "";
|
|
m_sPrevAniNameLayer2 = "";
|
|
m_fShootAniLength = 0.0f;
|
|
|
|
SetBlendTime("aidle_jump_air", .2f);
|
|
|
|
m_fDeathTimer = -1;
|
|
m_stats.onLadder = false;
|
|
m_RunningTime = m_RunningTimeClient = 0;
|
|
m_WalkingTime = m_WalkingTimeClient = 0;
|
|
m_NotRunTime = m_NotRunTimeClient = 0;
|
|
|
|
m_JTWalk = .2f;
|
|
m_JTRun = .4f;
|
|
m_fLastCamUpdateTime = 0;
|
|
|
|
m_vDeltaCamAngles.Set(0,0,0);
|
|
m_vDeltaCamPos.Set(0,0,0);
|
|
m_vPrevCamAngles.Set(0,0,0);
|
|
m_vPrevCamPos.Set(0,0,0);
|
|
m_vWeaponAngles.Set(0,0,0);
|
|
|
|
m_AniSpeedXRun[0] = -1.0f;
|
|
m_AniSpeedXRun[1] = -1.0f;
|
|
m_AniSpeedXRun[2] = -1.0f;
|
|
|
|
m_sVehicleEyeHelper.clear();
|
|
m_bWaitForFireRelease = false;
|
|
|
|
m_vLastMotionDir.Set(0,0,0);
|
|
|
|
m_input_accel = 0;//default is no input acceleration.
|
|
m_input_stop_accel = 0;
|
|
|
|
m_input_accel_indoor = 0;//default is no input acceleration.
|
|
m_input_stop_accel_indoor = 0;
|
|
|
|
m_bWriteOccured = false;
|
|
|
|
m_bStayCrouch = false;
|
|
|
|
m_SynchedRandomSeed.SetParent(this);
|
|
|
|
m_vLadderPosition.Set(0,0,0);
|
|
m_vLadderAngles.Set(0,0,0);
|
|
m_vHeadAngles.Set(0,0,0);
|
|
|
|
m_AreaUser.SetGame( pGame );
|
|
m_AreaUser.SetEntity( GetEntity() );
|
|
|
|
m_fLastProneTime = 0;
|
|
|
|
m_pLastAiming=NULL;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
CPlayer::~CPlayer()
|
|
{
|
|
SwitchFlashLight( false );
|
|
|
|
ListOfPlayers::iterator self = std::find(m_pGame->m_DeadPlayers.begin(), m_pGame->m_DeadPlayers.end(), this);
|
|
if(self!=m_pGame->m_DeadPlayers.end())
|
|
m_pGame->m_DeadPlayers.erase(self);
|
|
|
|
m_pGame->m_XAreaMgr.ExitAllAreas( m_AreaUser );
|
|
// remove shared weapon
|
|
GetEntity()->GetCharInterface()->SetCharacter(1, 0);
|
|
// if(m_pSelectedWeapon){
|
|
// m_pSelectedWeapon->GetEntity()->DrawCharacter(0,0);
|
|
// }
|
|
SetEntity(0);
|
|
|
|
if(m_pScriptObject)
|
|
m_pScriptObject->Release();
|
|
m_pScriptObject=NULL;
|
|
|
|
|
|
m_mapPlayerWeapons.clear();
|
|
|
|
if (m_pDynLight)
|
|
{
|
|
delete m_pDynLight;
|
|
m_pDynLight=NULL;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Initializes the player-container.
|
|
@return true if succeeded, false otherwise
|
|
*/
|
|
bool CPlayer::Init()
|
|
{
|
|
//@FIXME probably should be created in script.
|
|
m_pGame->m_pLog->Log("XEntityPlayer %d initialised\n", m_pEntity->GetId() );
|
|
|
|
m_pEntity->GetScriptObject()->SetValue("type", "Player");
|
|
|
|
IAIObject *pObject = m_pEntity->GetAI();
|
|
if (pObject)
|
|
{
|
|
IPuppet *pPuppet;
|
|
if (pObject->CanBeConvertedTo(AIOBJECT_PUPPET, (void **) &pPuppet))
|
|
m_bIsAI = true;
|
|
}
|
|
|
|
if (!m_bIsAI)
|
|
// if(m_pEntity->GetAI()->GetType() == AIOBJECT_PLAYER)
|
|
m_pEntity->SetNeedUpdate(true);
|
|
// else
|
|
// m_pEntity->SetDestroyable( true );
|
|
|
|
/*
|
|
// if (!m_bIsAI)
|
|
if(m_pEntity->GetAI()->GetType() == AIOBJECT_PLAYER)
|
|
{
|
|
m_pEntity->SetNeedUpdate(true);
|
|
|
|
m_pGame->p_speed_run->Set(m_RunSpeed);
|
|
m_pGame->p_speed_walk->Set(m_WalkSpeed);
|
|
m_pGame->p_speed_crouch->Set(m_CrouchSpeed);
|
|
m_pGame->p_speed_prone->Set(m_ProneSpeed);
|
|
}
|
|
*/
|
|
// create the camera
|
|
// <<FIXME>> create only for client which do the rendering
|
|
|
|
ICryCharInstance* pCharacter = m_pEntity->GetCharInterface()->GetCharacter(0);
|
|
if (pCharacter)
|
|
{
|
|
pCharacter->EnableLastIdleAnimationRestart(0,true);
|
|
if (m_bIsAI)
|
|
pCharacter->EnableLastIdleAnimationRestart(3,true);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Initialize Player Camera Fov.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IEntityCamera *pEntCamera = m_pGame->GetSystem()->GetIEntitySystem()->CreateEntityCamera();
|
|
m_pEntity->SetCamera(pEntCamera);
|
|
int rw = m_pGame->GetSystem()->GetIRenderer()->GetWidth();
|
|
int rh = m_pGame->GetSystem()->GetIRenderer()->GetHeight();
|
|
float fFOV = DEG2RAD(90.0f); // Initialize with 90 degree fov.
|
|
pEntCamera->SetFov(fFOV,rw,rh);
|
|
pEntCamera->GetCamera().Init(rw,rh,fFOV);
|
|
pEntCamera->GetCamera().Update();
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
Vec3d default_offset;
|
|
default_offset(0,m_pGame->cl_ThirdPersonRange->GetFVal(),4);
|
|
m_pEntity->GetCamera()->SetCameraOffset(default_offset);
|
|
|
|
// [kirill] need this to use only z component of entity angles (same as for drawing)
|
|
// when calculating BBox
|
|
GetEntity()->SetFlags( ETY_FLAG_CALCBBOX_ZROTATE );
|
|
|
|
GoStand();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*!Called by the entity when the angles are changed.
|
|
This notification is used to force the orientation of the player.
|
|
*/
|
|
void CPlayer::OnSetAngles( const Vec3d &ang )
|
|
{
|
|
// say to Vladimir if you want to comment this code again
|
|
// if(m_pGame->m_pClient && !m_pVehicle)
|
|
//[kirill] need it in cars for autocentering
|
|
if(m_pGame->m_pClient)
|
|
{
|
|
// if(m_pGame->m_pClient->GetPlayerId()==m_pEntity->GetId() || m_pGame->m_pClient->m_bLocalHost)
|
|
if(m_pGame->m_pClient->GetPlayerId()==m_pEntity->GetId())
|
|
m_pGame->m_pClient->m_PlayerProcessingCmd.SetDeltaAngles(ang);
|
|
}
|
|
}
|
|
|
|
// set a certain shader for the current selected weapon
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::SetHeatVisionValues(int dwFlags,const char *szName,float fValue,float fFadingValue)
|
|
{
|
|
if (dwFlags & BITMASK_WEAPON)
|
|
{
|
|
m_fHeatWeaponsDesiredValue=fValue;
|
|
m_fHeatWeaponsFadingSpeed=fFadingValue;
|
|
}
|
|
|
|
if (dwFlags & BITMASK_PLAYER)
|
|
{
|
|
m_fHeatBodyDesiredValue=fValue;
|
|
m_fHeatBodyFadingSpeed=fFadingValue;
|
|
}
|
|
}
|
|
|
|
/*! Initializes the weapon-information stored in the player-container.
|
|
*/
|
|
void CPlayer::InitWeapons()
|
|
{
|
|
// ValidateHeap();
|
|
IEntitySystem *pEntitySystem = (IEntitySystem *) m_pGame->GetSystem()->GetIEntitySystem();
|
|
|
|
SetWeapon(-1);
|
|
m_mapPlayerWeapons.clear();
|
|
|
|
for (int i=0;i<PLAYER_MAX_WEAPONS;i++)
|
|
m_vWeaponSlots[i]=0;
|
|
|
|
// init weapon instances
|
|
unsigned int weaponCount = GetGame()->GetWeaponSystemEx()->GetNumWeaponClasses();
|
|
|
|
for (unsigned int i = 0; i < weaponCount; ++i)
|
|
{
|
|
CWeaponClass *pWC = GetGame()->GetWeaponSystemEx()->GetWeaponClass(i);
|
|
assert(pWC);
|
|
WeaponInfo wi;
|
|
wi.fireTime = m_pTimer->GetCurrTime();
|
|
wi.fireLastShot = 0;
|
|
wi.reloading = false;
|
|
wi.iFireMode = 0;
|
|
|
|
assert(m_mapPlayerWeapons.count(pWC->GetID())==0); // otherwise we produce memory leaks
|
|
|
|
wi.owns = false;
|
|
m_mapPlayerWeapons[pWC->GetID()] = wi;
|
|
}
|
|
}
|
|
|
|
void CPlayer::SelectFirstWeapon()
|
|
{
|
|
if (!m_pGame->IsServer())
|
|
return;
|
|
|
|
int slot=0;
|
|
while(slot<PLAYER_MAX_WEAPONS && m_vWeaponSlots[slot]==0)
|
|
slot++;
|
|
|
|
if(m_vWeaponSlots[slot]!=0)
|
|
SelectWeapon(m_vWeaponSlots[slot]);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Updates the player torso/head angles. Should be called every frame. CAlled from Update()
|
|
*/
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//UPDATE HEAD ROTATION
|
|
void CPlayer::UpdateRotateHead()
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
m_LegAngleVelMoving = m_pGame->pa_leg_velmoving->GetFVal();
|
|
m_LegAngleVelTimed = m_pGame->pa_leg_velidle->GetFVal();
|
|
m_LegAIdleTimeLimit = m_pGame->pa_leg_idletime->GetFVal();
|
|
|
|
if( !m_bRotateHead )
|
|
{
|
|
if( m_pEntity->GetCurrentAnimation(0, 3)>=0
|
|
|| m_pEntity->IsBound()
|
|
|| m_stats.onLadder // no rotatehead on ladders
|
|
// || m_stats.landing || m_stats.flying // no rotatehead while jumping
|
|
)
|
|
m_LegNeedsForceAngle = true;
|
|
|
|
m_LegRotation = false;
|
|
return;
|
|
}
|
|
|
|
Vec3d angles = GetActualAngles();
|
|
if(m_LegNeedsForceAngle || m_pMountedWeapon) // some animation was played - need to reset all rotations
|
|
{
|
|
m_LegAngle = angles.z;
|
|
m_LegAngleDesired = m_LegAngle;
|
|
m_LegDeltaAngle = 0.0f;
|
|
m_LegNeedsForceAngle = false;
|
|
}
|
|
m_LegRotation = true;
|
|
|
|
float legDeltaAngle = m_LegAngleVel*m_pTimer->GetFrameTime();
|
|
float legDiff = Ffabs(Snap_s180(m_LegAngleDesired - m_LegAngle));
|
|
if(legDiff<legDeltaAngle)
|
|
m_LegAngle = m_LegAngleDesired;
|
|
else
|
|
{
|
|
if(legDiff>160)
|
|
{
|
|
if(Ffabs(Snap_s180(m_LegAngle+legDeltaAngle-angles.z))<Ffabs(Snap_s180(m_LegAngle-legDeltaAngle-angles.z)))
|
|
m_LegAngle += legDeltaAngle;
|
|
else
|
|
m_LegAngle -= legDeltaAngle;
|
|
}
|
|
else
|
|
m_LegAngle += (Snap_s180(m_LegAngleDesired-m_LegAngle))>0?m_LegAngleVel*m_pTimer->GetFrameTime():-m_LegAngleVel*m_pTimer->GetFrameTime();
|
|
m_LegAngle = Snap_s180(m_LegAngle);
|
|
}
|
|
|
|
if( m_stats.moving )
|
|
{
|
|
m_LegDeltaAngle = Snap_s180(m_LegAngle - angles.z);
|
|
|
|
/*
|
|
if(Ffabs(m_LegDeltaAngle) > m_LegADeltaLimitForce)
|
|
{
|
|
if(m_LegDeltaAngle<0)
|
|
{
|
|
m_LegAngleDesired = Snap180(angles.z-m_LegADeltaLimit);
|
|
m_LegAngle = m_LegAngleDesired;
|
|
}
|
|
else
|
|
{
|
|
m_LegAngleDesired = Snap180(angles.z+m_LegADeltaLimit);
|
|
m_LegAngle = m_LegAngleDesired;
|
|
}
|
|
}
|
|
*/
|
|
return;
|
|
}
|
|
|
|
if( m_bRotateHead && IsAlive())
|
|
{
|
|
float prevDelta = m_LegDeltaAngle;
|
|
|
|
m_LegDeltaAngle = Snap_s180(m_LegAngle - angles.z);
|
|
|
|
if(Ffabs(m_LegDeltaAngle) > m_LegADeltaLimit)
|
|
{
|
|
if(m_LegDeltaAngle<0)
|
|
{
|
|
m_LegAngleDesired = Snap_s180(angles.z-m_LegADeltaLimit);
|
|
}
|
|
else
|
|
{
|
|
m_LegAngleDesired = Snap_s180(angles.z+m_LegADeltaLimit);
|
|
}
|
|
m_LegAngleVel = m_LegAngleVelMoving;
|
|
if(Ffabs(m_LegDeltaAngle) > m_LegADeltaLimit*2 && !m_bIsAI) // to prevent player's from twisting legs/upper_body
|
|
m_LegAngleVel *= 100;
|
|
}
|
|
|
|
if(Ffabs(m_LegDeltaAngle) > m_LegADeltaLimit-5 )
|
|
{
|
|
m_LegAngleIdleTime += m_pTimer->GetFrameTime();
|
|
if( m_LegAngleIdleTime>m_LegAIdleTimeLimit )
|
|
{
|
|
m_LegAngleDesired = angles.z;
|
|
m_LegAngleVel = m_LegAngleVelTimed;
|
|
}
|
|
}
|
|
else
|
|
m_LegAngleIdleTime = 0;
|
|
|
|
/*
|
|
// if less than 5 degrees - don't autorotate.
|
|
if(Ffabs(prevDelta)< 5 )
|
|
prevDelta = 0;
|
|
if(m_LegDeltaAngle!=0 && Ffabs(m_LegDeltaAngle - prevDelta)<1.0f)
|
|
{
|
|
m_LegAngleIdleTime += m_pTimer->GetFrameTime();
|
|
if( m_LegAngleIdleTime>m_LegAIdleTimeLimit )
|
|
{
|
|
m_LegAngleDesired = angles.z;
|
|
m_LegAngleVel = m_LegAngleVelTimed;
|
|
}
|
|
}
|
|
else
|
|
m_LegAngleIdleTime = 0;
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
m_LegAngle = angles.z;
|
|
m_LegAngleDesired = m_LegAngle;
|
|
m_LegDeltaAngle = 0.0f;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Updates the player-container. Should be called every frame.
|
|
*/
|
|
void CPlayer::UpdateDead( SPlayerUpdateContext &ctx )
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
if (m_bIsAI && m_fDeathTimer>=0.0f )
|
|
{
|
|
m_fDeathTimer -= m_pTimer->GetFrameTime();
|
|
if(m_fDeathTimer <= 0.0f)
|
|
{
|
|
m_fDeathTimer = 0.0f;
|
|
int nRendererFrameID = m_pGame->GetSystem()->GetIRenderer()->GetFrameID();
|
|
if( nRendererFrameID - m_pEntity->GetDrawFrame() > 60*2 )
|
|
{
|
|
m_pEntity->Remove();
|
|
return;
|
|
}
|
|
// restart the timer
|
|
m_fDeathTimer=m_pGame->p_deathtime->GetFVal();
|
|
}
|
|
}
|
|
|
|
// don't check/update areas for AI's
|
|
if( !m_bIsAI )
|
|
{
|
|
// m_pGame->m_XAreaMgr.UpdatePlayer( this );
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//UPDATE THE CAMERA
|
|
SetEyePosDead();
|
|
UpdateCamera();
|
|
}
|
|
|
|
// UpdateDrawAngles( );
|
|
|
|
if (m_bFirstPerson)
|
|
{
|
|
m_pEntity->SetRegisterInSectors(false);
|
|
UpdateFirstPersonView();
|
|
}
|
|
else
|
|
{
|
|
m_pEntity->SetRegisterInSectors(true);
|
|
UpdateThirdPersonView();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::AutoAiming()
|
|
{
|
|
const char *pszBoneName="Bip01 Spine1\0";
|
|
//const char *pszBoneName=NULL;
|
|
|
|
Vec3 Center;
|
|
Vec3 bestPoint3D;
|
|
float fBestDist=99999;
|
|
IEntity *pBest=NULL;
|
|
|
|
IEntityItPtr It=m_pGame->GetSystem()->GetIEntitySystem()->GetEntityInFrustrumIterator( true );
|
|
CCamera Cam=m_pGame->GetSystem()->GetViewCamera();
|
|
IEntity *pEnt;
|
|
//ray_hit RayHit;
|
|
IEntity *pLocal=m_pGame->GetMyPlayer();
|
|
|
|
Vec3 m_vWpnPos=pLocal->GetPos();
|
|
|
|
while (pEnt=It->Next())
|
|
{
|
|
if (pEnt==m_pEntity)
|
|
continue;
|
|
if (!pEnt->IsTrackable())
|
|
continue;
|
|
|
|
CPlayer *pPlayer;
|
|
if( pEnt->GetContainer() &&
|
|
pEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**)&pPlayer) &&
|
|
!pPlayer->IsAlive() )
|
|
continue;
|
|
|
|
IPhysicalEntity *pPE=pEnt->GetPhysics();
|
|
if (!pPE)
|
|
continue;
|
|
|
|
if (pszBoneName) // if we want a bone instead of bbox-center lets do so...
|
|
{
|
|
IEntityCharacter *pIChar=pEnt->GetCharInterface();
|
|
if (pIChar)
|
|
{
|
|
ICryCharInstance *cmodel=pIChar->GetCharacter(0);
|
|
if (cmodel)
|
|
{
|
|
ICryBone *pBone = cmodel->GetBoneByName(pszBoneName);
|
|
if (pBone)
|
|
{
|
|
Center=pBone->GetBonePosition();
|
|
|
|
Matrix44 m;
|
|
m.SetIdentity();
|
|
m=GetTranslationMat(pEnt->GetPos())*m;
|
|
m=Matrix44::CreateRotationZYX(-pEnt->GetAngles()*gf_DEGTORAD)*m; //NOTE: angles in radians and negated
|
|
Center=m.TransformPointOLD(Center);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Center=pEnt->GetPos();
|
|
}
|
|
}
|
|
|
|
Vec3 diff(Center-m_vWpnPos);
|
|
|
|
float length2=GetLengthSquared(diff);
|
|
if(length2>15*15 || length2<1.5*1.5)
|
|
continue;
|
|
|
|
// pick the closest
|
|
float fDist=(float)sqrt(length2);
|
|
if (fDist<fBestDist)
|
|
{
|
|
pBest=pEnt;
|
|
fBestDist=fDist;
|
|
bestPoint3D=Center;
|
|
}
|
|
}
|
|
|
|
float fCurrTime=m_pGame->GetSystem()->GetITimer()->GetCurrTime();
|
|
|
|
//ICVar *pCvar=m_pGame->GetSystem()->GetIConsole()->GetCVar("fixed_time_step");
|
|
|
|
if (!pBest)
|
|
{
|
|
m_pLastAiming=NULL;
|
|
return;
|
|
}
|
|
|
|
if (m_pLastAiming)
|
|
{
|
|
CPlayer *pPlayer;
|
|
if(m_pLastAiming->GetContainer() &&
|
|
m_pLastAiming->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**)&pPlayer) &&
|
|
!pPlayer->IsAlive() )
|
|
m_pLastAiming=NULL;
|
|
}
|
|
|
|
if (m_pLastAiming && m_pLastAiming!=pBest)
|
|
{
|
|
if (fCurrTime-m_fLastTime<2.0f)
|
|
return;
|
|
|
|
m_fLastTime=fCurrTime;
|
|
}
|
|
else
|
|
m_fLastTime=m_pGame->GetSystem()->GetITimer()->GetCurrTime();
|
|
|
|
m_pLastAiming=pBest;
|
|
|
|
bestPoint3D.z-=1.5f;
|
|
Vec3 diff(bestPoint3D-m_vWpnPos);
|
|
Vec3 vCurrAng=pLocal->GetAngles();
|
|
Vec3 vNewAng=ConvertVectorToCameraAngles(diff);
|
|
//vCurrAng.z+=1.0f;
|
|
|
|
pLocal->SetAngles(vNewAng);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Updates the player-container. Should be called every frame.
|
|
*/
|
|
void CPlayer::Update()
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
bool bMyPlayer = IsMyPlayer();
|
|
bool bPlayerVisible = bMyPlayer || IsVisible();
|
|
|
|
SPlayerUpdateContext ctx;
|
|
ctx.bPlayerVisible = bPlayerVisible;
|
|
|
|
if (bMyPlayer)
|
|
{
|
|
// force physics proxy being updated in first person view, if somebody has a better idea
|
|
// I'm open to suggestions
|
|
m_pEntity->SetNeedUpdate(true);
|
|
}
|
|
|
|
if( !IsAlive() )
|
|
{
|
|
UpdateDead(ctx);
|
|
// [marco] even after the player dies, he can slide and fall into water -
|
|
// this call will create the splash sounds
|
|
UpdateSwimState(false);
|
|
return;
|
|
}
|
|
|
|
// fixme - remove this after artists done with animation params tweaking
|
|
if(m_pGame->pa_forcerelax->GetIVal())
|
|
{
|
|
GoRelaxed();
|
|
m_pEntity->StartAnimation(0, NULL, 1, .15f); // to stop all the fire animations
|
|
}
|
|
// fixme end
|
|
|
|
if(m_pGame->p_limp->GetIVal() == 0) // no limping
|
|
m_stats.bIsLimping = false;
|
|
else if(m_pGame->p_limp->GetIVal() == 1) // limp if wounded
|
|
{
|
|
if(m_stats.health<50&&(!m_stats.bIsLimping))
|
|
m_stats.bIsLimping = true;
|
|
}
|
|
else if(m_pGame->p_limp->GetIVal() == 2) // limp always
|
|
m_stats.bIsLimping = true;
|
|
|
|
if(bMyPlayer && m_pGame->m_bHideLocalPlayer)
|
|
{
|
|
FRAME_PROFILER( "CPlayerUpdate::UpdateCamera",GetISystem(),PROFILE_GAME );
|
|
|
|
m_AreaUser.SetEntity( GetEntity());
|
|
m_pGame->m_XAreaMgr.UpdatePlayer( m_AreaUser );
|
|
UpdateCamera();
|
|
///m_pEntity->DrawCharacter(0, ETY_DRAW_NONE);
|
|
//m_bFirstPerson = false;
|
|
//UpdateThirdPersonView();
|
|
return;
|
|
}
|
|
|
|
//if (bMyPlayer)
|
|
// AutoAiming();
|
|
|
|
m_bRotateHead = m_pEntity->GetCurrentAnimation(0, 3)<0 && m_pGame->p_RotateHead->GetIVal()!=0 &&
|
|
IsAlive() && !m_pEntity->IsBound()
|
|
&& !m_stats.onLadder // no rotatehead on ladders
|
|
&& !m_bIsFish // it's not a fish
|
|
// && m_pEntity->WasVisible() //Removed to fix BUG6238 (you always hear Valeries footsteps when she is behind you)
|
|
;
|
|
|
|
//if (!m_bIsAI) [Anton] moved to UpdatePhysics
|
|
// UpdateStamina();
|
|
|
|
// ladder stuff
|
|
// if(m_stats.onLadder)
|
|
// {
|
|
// SetGravityOverride(0.0f);
|
|
// }
|
|
|
|
// update and store player's current velocity
|
|
IPhysicalEntity *physEnt = m_pEntity->GetPhysics();
|
|
pe_status_living &status = ctx.status;
|
|
|
|
if (!physEnt || !physEnt->GetStatus(&status))
|
|
{
|
|
GameWarning( "Bad Phyics Entity for Player %s",m_pEntity->GetName() );
|
|
return;
|
|
}
|
|
|
|
Vec3d vel = (Vec3d)status.vel;
|
|
if (status.pGroundCollider)
|
|
vel -= status.velGround;
|
|
m_stats.fVel = vel.Length();
|
|
|
|
//fixme - remove this after done with lights tweaking
|
|
if(m_pGame->pl_force->GetIVal() && m_bIsAI && IsAlive())
|
|
SwitchFlashLight(true);
|
|
|
|
|
|
//fixme - this has to be done once - when model is loaded
|
|
UpdateBonesPtrs();
|
|
|
|
// Only updates when player have flash light on.
|
|
ProceedFLight();
|
|
|
|
UpdateLightBlinding();
|
|
|
|
//UpdateCollisionDamage(); [Anton] moved to UpdatePhysics
|
|
CounterUpdateAll( m_pTimer->GetFrameTime() );
|
|
|
|
//---------------------------------------------------------------
|
|
//Removed to fix BUG6238 (you always hear Valeries footsteps when she is behind you)
|
|
//As long as the character is NOT visible, the angles were not updated and that is the reason
|
|
// why the "aidle" animation doesn't start!
|
|
// if (bPlayerVisible)
|
|
UpdateRotateHead();
|
|
|
|
if (bPlayerVisible && !m_pVehicle)
|
|
{
|
|
FRAME_PROFILER( "CPlayerUpdate::RotateHead",GetISystem(),PROFILE_GAME );
|
|
if( m_CurStance != eProne )
|
|
{
|
|
//@FIXME remove this
|
|
pe_params_pos pp;
|
|
// if (m_pVehicle)
|
|
// {
|
|
// Vec3d angles = GetActualAngles();
|
|
// pp.q = GetRotationAA(angles.z*(gf_PI/180.0f),vectorf(0,0,1));
|
|
// }
|
|
if (m_bRotateHead)
|
|
pp.q = GetRotationAA(m_LegAngle*(gf_PI/180.0f),vectorf(0,0,1));
|
|
else
|
|
pp.q = GetRotationAA(m_pEntity->GetAngles().z*(gf_PI/180.0f),vectorf(0,0,1));
|
|
pp.bRecalcBounds = 0;
|
|
m_pEntity->GetPhysics()->SetParams(&pp);
|
|
}
|
|
}
|
|
|
|
//work in progress
|
|
//do this to prevent sliding when prone
|
|
if( m_CurStance == eProne )
|
|
{
|
|
// if( !m_stats.flying && !CanProne() )
|
|
if( !CanProne() )
|
|
GoStand();
|
|
else
|
|
{
|
|
m_EnvTangent = CalcTangentOnEnviroment( m_pEntity->GetAngles() );
|
|
m_pEntity->SetPhysAngles( m_EnvTangent ); // set angels for phisics (body is flat on surfece tangent space)
|
|
}
|
|
}
|
|
|
|
if (!m_bIsAI)
|
|
UpdateLean();
|
|
|
|
if (bPlayerVisible)
|
|
UpdateBonesRotation();
|
|
|
|
SetEyePos();
|
|
|
|
if (physEnt && physEnt->GetType()==PE_LIVING)
|
|
{
|
|
FRAME_PROFILER( "CPlayerUpdate::PostStep",GetISystem(),PROFILE_GAME );
|
|
pe_params_flags pf;
|
|
pf.flagsOR = pef_custom_poststep;
|
|
if (m_bIsAI)
|
|
pf.flagsOR |= lef_loosen_stuck_checks;
|
|
physEnt->SetParams(&pf);
|
|
}
|
|
|
|
//
|
|
// in water checks, swimming states updates
|
|
bool bPrevSweem = m_bSwimming;
|
|
UpdateSwimState(true);
|
|
if( m_bSwimming )
|
|
m_stats.swimTime +=m_pTimer->GetFrameTime();
|
|
else
|
|
m_stats.swimTime = 0.0f;
|
|
|
|
// update stances
|
|
if( !m_pVehicle )
|
|
{
|
|
if( m_bSwimming && m_CurStance!=eSwim )
|
|
GoSwim();
|
|
else if(bPrevSweem != m_bSwimming && !m_bSwimming)
|
|
{
|
|
if(!RestorePrevStence())
|
|
if(!GoCrouch())
|
|
GoProne();
|
|
}
|
|
}
|
|
|
|
// if(!m_bIsAI) // don't check/update areas for AI's
|
|
if(bMyPlayer) // areas are only used for the local player (they will not trigger things on the server)
|
|
{
|
|
FRAME_PROFILER( "CPlayerUpdate::XAreaMgrUpdatePlayer",GetISystem(),PROFILE_GAME );
|
|
|
|
m_AreaUser.SetEntity( GetEntity());
|
|
m_pGame->m_XAreaMgr.UpdatePlayer( m_AreaUser );
|
|
|
|
// used for camera transitions e.g. when entering a vehicle
|
|
UpdateAutoCenter();
|
|
|
|
// update the camera
|
|
UpdateCamera();
|
|
}
|
|
|
|
if (bPlayerVisible)
|
|
UpdateDrawAngles();
|
|
|
|
if (!m_bIsAI)
|
|
{
|
|
// Only for local player.
|
|
if (m_bFirstPerson)
|
|
{
|
|
m_pEntity->SetRegisterInSectors(false);
|
|
UpdateFirstPersonView();
|
|
}
|
|
else
|
|
{
|
|
m_pEntity->SetRegisterInSectors(true);
|
|
UpdateThirdPersonView();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//UPDATE THE WEAPON
|
|
|
|
if(m_stats.health>0)
|
|
{
|
|
if(m_stats.weapon_busy>0)
|
|
m_stats.weapon_busy-=m_pTimer->GetFrameTime();
|
|
|
|
UpdateMelee();
|
|
UpdateWeapon();
|
|
}
|
|
|
|
if(m_CurStance == eProne || m_bSwimming) // disable IK in prone mode and when swimming
|
|
{
|
|
FRAME_PROFILER( "CPlayerUpdate::DisableIK",GetISystem(),PROFILE_GAME );
|
|
pe_params_sensors ps;
|
|
ps.nSensors = 0;
|
|
physEnt->SetParams(&ps);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//UPDATE THE ANIMATION
|
|
// layer 0 is used for movement/stance animations (lower body)
|
|
// layer 1 is used for aiming/shooting animations
|
|
// layer 2 is used for jump/land animations
|
|
UpdateCharacterAnimations( ctx );
|
|
UpdateFireAnimations();
|
|
// UpdateJumpAnimations();
|
|
|
|
}
|
|
|
|
|
|
void CPlayer::UpdatePhysics(float fDeltaTime)
|
|
{
|
|
m_fLastDeltaTime = fDeltaTime;
|
|
|
|
IPhysicalEntity *physEnt = m_pEntity->GetPhysics();
|
|
float MIN_WALK_SPEED = m_WalkSpeed*.15f;
|
|
pe_status_living sl;
|
|
physEnt->GetStatus(&sl);
|
|
|
|
if (!m_bIsAI)
|
|
UpdateStamina(fDeltaTime);
|
|
UpdateCollisionDamage();
|
|
|
|
//keep count of the last groudheight
|
|
if (!sl.bFlying)
|
|
{
|
|
m_fLastGroundHeight = m_pEntity->GetPos(true).z;
|
|
m_bHasJumped = false;
|
|
}
|
|
|
|
// when on ladder - no gravity
|
|
// when using mounted weapon - no gravity
|
|
if(m_stats.onLadder || m_pMountedWeapon )
|
|
{
|
|
SetGravityOverride(0.0f);
|
|
}
|
|
|
|
// [Anton] - moved from ProcessMovements, since it should be called for remote clients in multiplayer
|
|
// float kwater;
|
|
// int bSwimming = IsSwimming( kwater );
|
|
pe_player_dynamics movedyn;
|
|
movedyn.kInertia = m_Dynamics.inertia*(1-m_stats.fKWater) + m_Dynamics.swimming_inertia*m_stats.fKWater;
|
|
|
|
movedyn.kAirControl = m_Dynamics.air_control*(1-m_stats.fKWater);
|
|
movedyn.bSwimming = m_bSwimming;
|
|
if (m_fGravityOverride!=1E10)
|
|
{
|
|
movedyn.gravity = m_fGravityOverride;
|
|
if (!m_fGravityOverride)
|
|
{
|
|
movedyn.kAirControl=1.0f;
|
|
movedyn.bSwimming=true;
|
|
}
|
|
m_fGravityOverride = 1E10;
|
|
}
|
|
else
|
|
{
|
|
float fgravity = m_Dynamics.gravity;
|
|
|
|
//if we are jumping and there is a special gravity for jump use it.
|
|
if (sl.bFlying && m_bHasJumped && m_Dynamics.jump_gravity!=1E10)
|
|
{
|
|
//use jump gravity only if we are over the jump starting pos.
|
|
if (m_pEntity->GetPos(true).z > m_fLastGroundHeight)
|
|
fgravity = m_Dynamics.jump_gravity;
|
|
}
|
|
|
|
//we land, in any case use standard gravity.
|
|
/*if (!sl.bFlying)
|
|
{
|
|
fgravity = m_Dynamics.gravity;
|
|
m_bHasJumped = false;
|
|
}*/
|
|
|
|
//GetISystem()->GetILog()->Log("%f",fgravity);
|
|
|
|
movedyn.gravity = fgravity*(1-m_stats.fKWater)*m_pGame->p_gravity_modifier->GetFVal()+m_Dynamics.swimming_gravity*m_stats.fKWater;
|
|
}
|
|
|
|
// 0 gravity behaves like swimming (up and down movement is possible)
|
|
if(movedyn.gravity==0.0f)
|
|
{
|
|
movedyn.bSwimming=true; // allow not only movements in ground plane
|
|
movedyn.kAirControl=m_Dynamics.air_control; // water should not affect control
|
|
}
|
|
|
|
Vec3 vAngles = ConvertToRad(m_pEntity->GetAngles()),
|
|
vDir(-cry_sinf(vAngles[YAW])*cry_sinf(vAngles[PITCH]),cry_cosf(vAngles[YAW])*cry_sinf(vAngles[PITCH]),-cry_cosf(vAngles[PITCH]));
|
|
// make underwater movement smoother
|
|
if (m_stats.fKWater>=1.0f && sl.velRequested.len2()>0 && sqr(sl.velRequested*vDir)>sl.velRequested.len2()*0.5f
|
|
&& m_stats.swimTime>1.0f)
|
|
movedyn.kAirControl = 1.0f;
|
|
|
|
if(m_bInertiaOverride)
|
|
{
|
|
if(movedyn.bSwimming)
|
|
movedyn.kAirControl = 1.0f;
|
|
else
|
|
movedyn.kInertia = 0; // the bigger value - the faster we can change speed (0 is special case, not warking in water)
|
|
}
|
|
|
|
physEnt->SetParams(&movedyn);
|
|
|
|
// if(movedyn.bSwimming && m_bSwimming)
|
|
// GoSwim();
|
|
// else if(m_bSwimming && !movedyn.bSwimming)
|
|
// RestorePrevStence();
|
|
// m_bSwimming = movedyn.bSwimming && (m_stats.fInWater>0.0f);
|
|
|
|
m_stats.moving = false;
|
|
m_stats.running = false;
|
|
|
|
// Calculate our current speed
|
|
Vec3 vel = sl.vel;
|
|
if (sl.pGroundCollider)
|
|
vel -= sl.velGround;
|
|
float speed = vel.Length();
|
|
|
|
m_walkParams.speed = speed;
|
|
m_walkParams.vertSpeed = vel.z;
|
|
// Calculate projected current speed
|
|
vel.z = 0.0f;
|
|
float speed2d = vel.Length();
|
|
|
|
|
|
if ((speed2d > .0f && m_NotRunTime>1.5f) || (speed2d > MIN_WALK_SPEED) )
|
|
{
|
|
// Have the player continue moving
|
|
m_stats.moving = true;
|
|
m_NotRunTime = 0;
|
|
}
|
|
//else
|
|
if (speed>0)
|
|
m_NotRunTime += fDeltaTime;
|
|
else
|
|
m_NotRunTime = 0;
|
|
|
|
if (m_stats.moving && (speed2d-m_WalkSpeed>0.1f || ((m_stats.flying||m_stats.landing)&&m_RunningTime>.5f)) ) // if jumping in air - slows down, not to change snimation
|
|
{
|
|
// Have the player start/continue running
|
|
m_stats.running = true;
|
|
}
|
|
|
|
if( m_stats.running )
|
|
m_RunningTime += fDeltaTime;
|
|
else
|
|
m_RunningTime = 0;
|
|
|
|
if( m_stats.moving )
|
|
m_WalkingTime += fDeltaTime;
|
|
else
|
|
m_WalkingTime = 0;
|
|
|
|
m_pGame->ConstrainToSandbox(GetEntity());
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
/*! Sets and loads the player-model.
|
|
@param model filename of the player-model
|
|
*/
|
|
void CPlayer::SetPlayerModel( const string &model )
|
|
{
|
|
|
|
//@FIXME: enable this later.
|
|
//if (m_pEntity->GetCharInterface()->LoadCharacter(PLAYER_MODEL_IDX,model.c_str()))
|
|
// m_strModel = model;
|
|
m_strModel = model;
|
|
if (m_nSelectedWeaponID == -1)
|
|
SelectWeapon(m_stats.weapon);
|
|
|
|
UpdateBonesPtrs();
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Retrieves a weapon-info-structure for a certain weapon
|
|
@param nWeaponIndex weapon-id to retrieve from (negative value will return info of current weapon)
|
|
@return WeaponInfo if the function succeeds, NULL otherwise
|
|
*/
|
|
WeaponInfo & CPlayer::GetWeaponInfo(int nWeaponIndex /* = -1 */)
|
|
{
|
|
if(nWeaponIndex == -1)
|
|
nWeaponIndex = m_nSelectedWeaponID;
|
|
|
|
PlayerWeaponsItor wi = m_mapPlayerWeapons.find(nWeaponIndex);
|
|
|
|
if (wi != m_mapPlayerWeapons.end())
|
|
{
|
|
return wi->second;
|
|
}
|
|
|
|
// this should NEVER EVER be reached
|
|
assert(false);
|
|
return m_mapPlayerWeapons.begin()->second;
|
|
}
|
|
|
|
void CPlayer::GetCurrentWeaponParams(WeaponParams& wp)
|
|
{
|
|
WeaponInfo wi = GetWeaponInfo();
|
|
GetSelectedWeapon()->GetModeParams(wi.iFireMode, wp);
|
|
}
|
|
|
|
/*! Executes the processing commands
|
|
@param ProcessingCmd structure of commands to process
|
|
*/
|
|
void CPlayer::ProcessCmd(unsigned int nPing,CXEntityProcessingCmd &ProcessingCmd)
|
|
{
|
|
ProcessMovements(ProcessingCmd);
|
|
|
|
// client in MP processes fire event differently
|
|
// here the server relays the fire event to the client, but due to
|
|
// heavier client-side simulation of firing (see XClient.cpp) we
|
|
// keep the state of our client-side calculation
|
|
bool bClientFire = false;
|
|
bool bPrevFiring = ProcessingCmd.CheckAction(ACTION_FIRE0);
|
|
bool bPrevFireGrenade = ProcessingCmd.CheckAction(ACTION_FIRE_GRENADE);
|
|
|
|
if (m_pGame->IsMultiplayer() && m_pGame->IsClient() && !m_pGame->IsServer() && IsMyPlayer())
|
|
{
|
|
bClientFire = true;
|
|
ProcessingCmd.RemoveAction(ACTION_FIRE0);
|
|
if (m_stats.firing)
|
|
ProcessingCmd.AddAction(ACTION_FIRE0);
|
|
|
|
ProcessingCmd.RemoveAction(ACTION_FIRE_GRENADE);
|
|
if (m_stats.firing_grenade)
|
|
ProcessingCmd.AddAction(ACTION_FIRE_GRENADE);
|
|
}
|
|
|
|
ProcessWeapons(ProcessingCmd);
|
|
|
|
if (bClientFire)
|
|
{
|
|
ProcessingCmd.RemoveAction(ACTION_FIRE0);
|
|
if (bPrevFiring)
|
|
ProcessingCmd.AddAction(ACTION_FIRE0);
|
|
|
|
ProcessingCmd.RemoveAction(ACTION_FIRE_GRENADE);
|
|
if (bPrevFireGrenade)
|
|
ProcessingCmd.AddAction(ACTION_FIRE_GRENADE);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
//claps angl to be within min-max range. Check fro special case when min>max -- for example min=350 max=40
|
|
inline float ClampAngle180( float min, float max, float angl )
|
|
{
|
|
|
|
if( angl>0 && angl<min )
|
|
return min;
|
|
else if( angl<0 && angl>max )
|
|
return max;
|
|
|
|
return angl;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Updates the orientation of the player
|
|
@param ProcessingCmd structure of commands to process
|
|
*/
|
|
void CPlayer::ProcessAngles(CXEntityProcessingCmd &ProcessingCmd)
|
|
{
|
|
if (IsMyPlayer() && !IsAlive())
|
|
return;
|
|
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
Vec3d Angles=ProcessingCmd.GetDeltaAngles();
|
|
|
|
if (IsMyPlayer() && m_pVehicle && !m_bFirstPerson && !m_pMountedWeapon)
|
|
{
|
|
// [marco] if this is the localplayer, and we are driving the vehicle,
|
|
// and we are in third person mode, AND we are not at mounted weapon
|
|
// then do not allow the player
|
|
// to mess around with the camera - he can switch
|
|
// to first person mode to shoot from inside the vehicle
|
|
// Angles.Set(0,0,180);
|
|
}
|
|
|
|
if(m_AngleLimitVFlag)
|
|
//check vertical limits
|
|
{
|
|
Angles.x = ClampAngle( Snap_s360(m_AngleLimitBase.x + m_MinVAngle),
|
|
Snap_s360(m_AngleLimitBase.x + m_MaxVAngle),
|
|
Snap_s360(Angles.x));
|
|
Angles.x = Snap_s180(Angles.x);
|
|
}
|
|
|
|
//
|
|
//probably not the best way. If we will have angle restriction (like mounted weapon) in prone - have to chage it
|
|
if( m_CurStance == eProne )
|
|
m_AngleLimitBase = m_EnvTangent;
|
|
|
|
if(m_AngleLimitHFlag)
|
|
{
|
|
//check horizontal limits
|
|
bool bClamped = false;
|
|
|
|
Angles.z = Snap_s180(Angles.z);
|
|
Angles.z = ClampAngle( Snap_s360(m_AngleLimitBase.z + m_MinHAngle),
|
|
Snap_s360(m_AngleLimitBase.z + m_MaxHAngle),
|
|
Snap_s360(Angles.z),bClamped);
|
|
if (m_bIsAI && bClamped)
|
|
m_pEntity->GetAI()->SetSignal(1,"RETURN_TO_NORMAL");
|
|
|
|
Angles.z = Snap_s180(Angles.z);
|
|
|
|
}
|
|
|
|
// if at the mounted weapon - check for collisions coz player position is forced bu the weapon
|
|
if( m_pMountedWeapon )
|
|
{
|
|
Vec3d pos2check = m_pEntity->GetPos();
|
|
if(!CanStand( pos2check ) )
|
|
{
|
|
// this position is bad (collides with something) - restore prev pos/angles
|
|
// float diff = Snap_s360(m_vSafeAngAtMountedWeapon.z) - Snap_s360(Angles.z);
|
|
float diff = Snap_s180(Snap_s180(m_vSafeAngAtMountedWeapon.z) - Snap_s180(Angles.z));
|
|
Angles.z += diff*.31f;
|
|
//GetISystem()->GetILog()->Log(">>> %.2f ", m_vSafeAngAtMountedWeapon.z);
|
|
}
|
|
else if(CanStand( pos2check ) )
|
|
{
|
|
// this position is good (no intersetion/collisions) - remember it
|
|
m_vSafeAngAtMountedWeapon = m_pEntity->GetAngles();
|
|
//GetISystem()->GetILog()->Log("<<<GD %.2f ", m_vSafeAngAtMountedWeapon.z);
|
|
}
|
|
}
|
|
|
|
ProcessingCmd.SetDeltaAngles(Angles);
|
|
if(IsMyPlayer())
|
|
{
|
|
float stanceRecoilModifier = 1.0f;
|
|
|
|
// process weapon specific recoil modifier based on stance
|
|
if (m_nSelectedWeaponID != -1)
|
|
{
|
|
CWeaponClass *pSelectedWeapon = GetSelectedWeapon();
|
|
|
|
WeaponParams wp;
|
|
GetCurrentWeaponParams(wp);
|
|
|
|
stanceRecoilModifier = wp.fRecoilModifierStanding;
|
|
if (m_CurStance == eCrouch)
|
|
{
|
|
stanceRecoilModifier = wp.fRecoilModifierCrouch;
|
|
}
|
|
else if (m_CurStance == eProne)
|
|
{
|
|
stanceRecoilModifier = wp.fRecoilModifierProne;
|
|
}
|
|
}
|
|
Vec3d vA=Angles;
|
|
|
|
//GetISystem()->GetILog()->Log("RECOIL: %f %f %f", m_fRecoilXUp, m_fRecoilZUp, m_fRecoilXDelta);
|
|
if((m_fRecoilXUp==0 && (m_fRecoilZUp==0)) && (m_fRecoilXDelta!=0) )//blend back recoil
|
|
{
|
|
//TRACE("RETURNING m_fRecoilXDelta=%f",m_fRecoilXDelta);
|
|
float multiplier=m_stats.firing?m_pGame->w_recoil_speed_down*0.2f:m_pGame->w_recoil_speed_down;
|
|
float m=min(1,m_pTimer->GetFrameTime()*multiplier);
|
|
float xdiff=m_fRecoilXDelta>m_fRecoilX*m?m_fRecoilX*m:m_fRecoilXDelta;
|
|
//float zdiff=m_fRecoilZDelta>0?min(m_fRecoilZDelta,m_fRecoilZ*m):-m_fRecoilZDelta;
|
|
|
|
xdiff *= stanceRecoilModifier;
|
|
|
|
if(m_fRecoilXDelta-xdiff<=0){
|
|
xdiff=m_fRecoilXDelta;
|
|
}
|
|
vA.x+=xdiff;
|
|
m_fRecoilXDelta-=xdiff;
|
|
|
|
//TRACE("m_fRecoilXDelta=%f xdiff=%f m_fRecoilZDelta=%f \n",m_fRecoilXDelta,xdiff,m_fRecoilZDelta);
|
|
ProcessingCmd.SetDeltaAngles(vA);
|
|
//TRACE("RETURNING ENDm_fRecoilXDelta=%f",m_fRecoilXDelta);
|
|
}
|
|
|
|
//APPLY RECOIL
|
|
if((m_fRecoilXUp!=0 || m_fRecoilZUp!=0) )//apply recoil
|
|
{
|
|
//GetISystem()->GetILog()->Log("APPLYING m_fRecoilXDelta=%f",m_fRecoilXDelta);
|
|
float deltatime=m_pTimer->GetFrameTime()*m_pGame->w_recoil_speed_up;
|
|
//GetISystem()->GetILog()->Log("deltatime=%f",deltatime);
|
|
float dx=m_fRecoilXUp>0?min(m_fRecoilXUp,m_fRecoilX*deltatime):max(m_fRecoilXUp,m_fRecoilX*deltatime);
|
|
float dz=m_fRecoilZUp>0?(float)min(m_fRecoilZUp,m_fRecoilZ*deltatime):(float)max(m_fRecoilZUp,-fabs(m_fRecoilZ*deltatime));
|
|
|
|
if(m_fRecoilXDelta+dx>=m_pGame->w_recoil_max_degree){
|
|
//GetISystem()->GetILog()->Log("w_recoil_max_degree=%f",m_pGame->w_recoil_max_degree);
|
|
dx=m_fRecoilXUp;
|
|
}
|
|
//GetISystem()->GetILog()->Log("m_fRecoilXDelta=%f dx=%f dz=%f m_fRecoilXUp=%f m_fRecoilZUp=%f\n",m_fRecoilXDelta,dx,dz,m_fRecoilXUp,m_fRecoilZUp);
|
|
|
|
m_fRecoilXUp-=dx;
|
|
if(m_fRecoilXUp<0)m_fRecoilXUp=0;
|
|
m_fRecoilZUp-=dz;
|
|
|
|
dx *= stanceRecoilModifier;
|
|
dz *= stanceRecoilModifier;
|
|
|
|
vA.x-=dx;
|
|
if(!m_pGame->w_recoil_vertical_only)
|
|
{
|
|
vA.z-=dz;
|
|
}
|
|
|
|
m_fRecoilXDelta+=dx;
|
|
ProcessingCmd.SetDeltaAngles(vA);
|
|
//TRACE("APPLYING END m_fRecoilXDelta=%f",m_fRecoilXDelta);
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
float fWaterPitch=m_pGame->p_waterbob_pitch->GetFVal();
|
|
float fWaterPitchSpeed=m_pGame->p_waterbob_pitchspeed->GetFVal();
|
|
float fWaterRoll=m_pGame->p_waterbob_roll->GetFVal();
|
|
float fWaterRollSpeed=m_pGame->p_waterbob_rollspeed->GetFVal();
|
|
float fWaterDepthWobble=m_pGame->p_waterbob_mindepth->GetFVal();
|
|
if (m_bEyesInWater) // wobble camera if in water
|
|
{
|
|
float fWobbleScale=(m_stats.fInWater-fWaterDepthWobble);
|
|
if (fWobbleScale<0.0f)
|
|
fWobbleScale=0.0f;
|
|
if (fWobbleScale>1.0f)
|
|
fWobbleScale=1.0f;
|
|
float fFrameTime=m_pTimer->GetFrameTime();
|
|
m_walkParams.fWaterPitchPhase+=fWaterPitchSpeed*fFrameTime;
|
|
if (m_walkParams.fWaterPitchPhase>=1.0f)
|
|
m_walkParams.fWaterPitchPhase-=1.0f;
|
|
m_walkParams.fWaterRollPhase+=fWaterRollSpeed*fFrameTime;
|
|
if (m_walkParams.fWaterRollPhase>=1.0f)
|
|
m_walkParams.fWaterRollPhase-=1.0f;
|
|
//Vec3d cangles = Angles;
|
|
vA.x += fWobbleScale*fWaterPitch*cry_sinf(m_walkParams.fWaterPitchPhase*gf_PI*2.0f);
|
|
vA.y = (fWaterRoll *cry_sinf(m_walkParams.fWaterRollPhase *gf_PI*2.0f))*fWobbleScale;
|
|
}else
|
|
{
|
|
//Vec3d cangles = vA;
|
|
vA.y=0.0f;
|
|
//ProcessingCmd.SetDeltaAngles(vA);
|
|
m_walkParams.fWaterPitchPhase=0.0f;
|
|
m_walkParams.fWaterRollPhase=0.0f;
|
|
}
|
|
ProcessingCmd.SetDeltaAngles(vA);
|
|
//////////////////////////////////////////////////////////////////////////
|
|
}
|
|
|
|
|
|
///
|
|
|
|
if (!m_pRedirected)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//if (!m_pVehicle)
|
|
m_pEntity->SetAngles( Angles,false, false );
|
|
|
|
m_vShake=Vec3d(0,0,0);
|
|
|
|
//
|
|
// so here goes wapon sway
|
|
if(m_Dynamics.gravity!=0.0f) // only if there is gravity
|
|
{
|
|
// add some swaying to the angles
|
|
m_vShake.x+=(cry_cosf(m_walkParams.swayOfs*15.9f+0.3f)*m_walkParams.swayAmp*0.1f+cry_sinf(m_walkParams.swayOfs*5.9f+0.0f)*m_walkParams.swayAmp*0.45f+cry_cosf(m_walkParams.swayOfs*0.95f+0.5f)*m_walkParams.swayAmp)*0.33333f;
|
|
m_vShake.z+=(cry_cosf(m_walkParams.swayOfs*14.9f+0.7f)*m_walkParams.swayAmp*0.12f+cry_sinf(m_walkParams.swayOfs*5.05f+0.6f)*m_walkParams.swayAmp*0.5f+cry_cosf(m_walkParams.swayOfs*1.0f+0.2f)*m_walkParams.swayAmp)*0.33333f;
|
|
m_walkParams.swayOfs+=m_walkParams.swayFreq*m_pTimer->GetFrameTime();
|
|
}
|
|
|
|
//
|
|
// after explosion camera shacking - not when in vehicle
|
|
// when proning - aligne on terrain
|
|
if (IsAlive() && !m_pEntity->IsBound() )
|
|
{
|
|
// add shaking
|
|
if (IsMyPlayer())
|
|
{
|
|
if((fabsf(m_walkParams.shakeDegree)>0.1f) && (m_walkParams.shakeTime>0.0f))
|
|
{
|
|
m_walkParams.shakeOffset += m_walkParams.shakeFreq * m_pTimer->GetFrameTime();
|
|
m_walkParams.shakeElapsedTime += m_pTimer->GetFrameTime();
|
|
if (m_walkParams.shakeElapsedTime>m_walkParams.shakeTime)
|
|
{
|
|
m_walkParams.shakeDegree=0.0f;
|
|
}else
|
|
{
|
|
float fDeg = m_walkParams.shakeDegree * ( 1 - ( m_walkParams.shakeElapsedTime / m_walkParams.shakeTime ) );
|
|
float fSinOfs = cry_sinf(m_walkParams.shakeOffset * 6.283185307179586476925286766559f);
|
|
// m_vShake.x += m_walkParams.shakeAxis.x * fSinOfs * fDeg;
|
|
// m_vShake.y += m_walkParams.shakeAxis.y * fSinOfs * fDeg;
|
|
// m_vShake.z += m_walkParams.shakeAxis.z * fSinOfs * fDeg;
|
|
|
|
// make it shake on camera roll axis
|
|
// create the matrix here
|
|
Matrix44 matWorld;
|
|
matWorld.SetIdentity();
|
|
|
|
matWorld=Matrix44::CreateRotationZYX(-gf_DEGTORAD*m_vEyeAngles)*matWorld; //NOTE: angles in radians and negated
|
|
|
|
CryQuat cxquat = Quat( GetTransposed44(matWorld) );
|
|
|
|
CryQuat rxquat;
|
|
Vec3d shake( 0, fSinOfs * fDeg, 0 );
|
|
rxquat.SetRotationXYZ(DEG2RAD(shake));
|
|
|
|
CryQuat result = cxquat*rxquat;
|
|
Vec3d finalangles = RAD2DEG(Ang3::GetAnglesXYZ(Matrix33(result)));
|
|
m_vShake += m_vEyeAngles - finalangles;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ProcessingCmd.SetDeltaAngles(Angles);
|
|
|
|
// m_pEntity->SetAngles( Angles );//,false, false );
|
|
if (m_pRedirected) // [marco] Kirill does this check make sense -
|
|
// this should never happens but it crashes with the helicopter
|
|
m_pRedirected->SetAngles(Angles);
|
|
// ProcessingCmd.Reset();
|
|
}
|
|
}
|
|
|
|
//#define UNDERWATER_SPEED 0.19f/8.0f
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Updates the position and stats of the player
|
|
@param ProcessingCmd structure of commands to process
|
|
*/
|
|
void CPlayer::ProcessMovements(CXEntityProcessingCmd &cmd, bool bScheduled)
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
IPhysicalEntity *pPhysEnt = (IPhysicalEntity *)m_pEntity->GetPhysics();
|
|
|
|
if(!pPhysEnt)
|
|
return;
|
|
|
|
//[kirill] need this to process autocentering
|
|
// no autocentering when moving mouse or fiering
|
|
m_bMouseMoved = cmd.CheckAction(ACTION_TURNLR) || cmd.CheckAction(ACTION_TURNUD) || cmd.CheckAction(ACTION_FIRE0);
|
|
|
|
PhysicsVars *physvars = m_pGame->GetSystem()->GetIPhysicalWorld()->GetPhysVars();
|
|
// [Anton] setting dynprops for the physics is moved to ::Update
|
|
pe_player_dynamics pd;
|
|
pPhysEnt->GetParams(&pd);
|
|
|
|
bool bSuperDesignerMode = pd.gravity==0 && pd.kInertia==0;
|
|
bool bNoGravity = !bSuperDesignerMode && (physvars->bFlyMode || IsSwimming() || m_stats.onLadder);
|
|
|
|
//return;
|
|
/* this blick would be needed only when designers tweak player's speeds
|
|
//FixME fix me FIXME!!!
|
|
//if(IsMyPlayer())
|
|
{
|
|
// m_RunSprintDecoyScale = m_pGame->p_sprint_decoy->GetFVal();
|
|
// m_RunSprintRestoreScaleRun = m_pGame->p_sprint_restore_run->GetFVal();
|
|
// m_RunSprintRestoreScaleIdle = m_pGame->p_sprint_restore_idle->GetFVal();
|
|
// m_RunSprintScale = m_pGame->p_sprint_scale->GetFVal();
|
|
|
|
m_RunSpeed = m_pGame->p_speed_run->GetFVal();
|
|
m_WalkSpeed = m_pGame->p_speed_walk->GetFVal();
|
|
m_CrouchSpeed = m_pGame->p_speed_crouch->GetFVal();
|
|
m_ProneSpeed = m_pGame->p_speed_prone->GetFVal();
|
|
m_JumpForce = m_pGame->p_jump_force->GetFVal();
|
|
m_LeanDegree = m_pGame->p_lean->GetFVal();
|
|
|
|
m_JTWalk = m_pGame->p_jump_walk_time->GetFVal();
|
|
m_JTRun = m_pGame->p_jump_run_time->GetFVal();
|
|
}
|
|
*/
|
|
m_StealthSpeed = (m_CrouchSpeed + m_WalkSpeed)*.5f;
|
|
|
|
|
|
IPhysicalWorld *pW=pPhysEnt->GetWorld();
|
|
|
|
float fTimeDelta=0;
|
|
CXClient *pClient=m_pGame->GetClient();
|
|
|
|
if(!pClient || pClient->GetPlayerId()!=m_pEntity->GetId())
|
|
fTimeDelta=cmd.GetServerPhysDelta();
|
|
|
|
if (!m_pVehicle && !m_pMountedWeapon && fTimeDelta>0)
|
|
{
|
|
pPhysEnt->StepBack(fTimeDelta);
|
|
|
|
m_NotRunTime = m_NotRunTimeClient;
|
|
m_RunningTime = m_RunningTimeClient;
|
|
m_WalkingTime = m_WalkingTimeClient;
|
|
m_stats.stamina = m_staminaClient;
|
|
// m_stats.breath = m_breathClient;
|
|
}
|
|
|
|
if (!IsAlive())
|
|
return;
|
|
|
|
if (cmd.CheckAction(ACTION_FLASHLIGHT))
|
|
{
|
|
if (m_pVehicle && m_stats.inVehicleState == PVS_DRIVER)
|
|
m_pVehicle->SwitchLights(5); // switch car's lights
|
|
else if (m_stats.has_flashlight)
|
|
SwitchFlashLight(!m_bLightOn);
|
|
// cmd.RemoveAction(ACTION_FLASHLIGHT);
|
|
}
|
|
|
|
// when in vehicle - use crouch key to toggle camera autocentering
|
|
if ((cmd.CheckAction(ACTION_MOVEMODE) || cmd.CheckAction(ACTION_MOVEMODE_TOGGLE)) && m_pVehicle)
|
|
{
|
|
StartAutoCenter( false );
|
|
|
|
cmd.RemoveAction(ACTION_MOVEMODE);
|
|
cmd.CheckAction(ACTION_MOVEMODE_TOGGLE);
|
|
}
|
|
|
|
// use button has been removed
|
|
m_stats.melee_attack=false;
|
|
if(cmd.CheckAction(ACTION_USE))
|
|
{
|
|
bool bUsed=false;
|
|
m_pEntity->SendScriptEvent(ScriptEvent_Use,0,&bUsed);
|
|
if (bUsed==false)
|
|
{
|
|
m_stats.use_pressed=true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_stats.use_pressed=false;
|
|
}
|
|
|
|
if (cmd.CheckAction(ACTION_CHANGE_VIEW))
|
|
{
|
|
//if (m_pGame->IsDevModeEnable())
|
|
{
|
|
m_pGame->SetViewMode(m_bFirstPerson);
|
|
}
|
|
cmd.RemoveAction(ACTION_CHANGE_VIEW);
|
|
}
|
|
|
|
if ( m_pVehicle )
|
|
{
|
|
//if (!m_pGame->IsMultiplayer() || !m_pGame->UseFixedStep() || bScheduled)
|
|
ProcessVehicleMovements(cmd); // so that we dont need any reference to vechile in this file
|
|
// can't sprint in vehicle
|
|
m_Sprinting = false;
|
|
return;
|
|
}
|
|
|
|
// if using mounted weapon - can't move
|
|
if(m_pMountedWeapon)
|
|
{
|
|
// can't sprint when useing mounted weapon
|
|
m_Sprinting = false;
|
|
return;
|
|
}
|
|
|
|
if (m_nSelectedWeaponID != -1)
|
|
{
|
|
WeaponParams wp;
|
|
GetCurrentWeaponParams(wp);
|
|
|
|
m_stats.holding_breath=false;
|
|
if (wp.bAllowHoldBreath && cmd.CheckAction(ACTION_HOLDBREATH) && m_stats.stamina>m_StaminaTable.BreathDecoyAim*.5f)
|
|
{
|
|
m_stats.holding_breath = true;
|
|
}
|
|
}
|
|
|
|
//lets remove the action flag every frame if in crouching mode.
|
|
if(m_pGame->IsServer())
|
|
{
|
|
//crouch toggle
|
|
if (cmd.CheckAction(ACTION_MOVEMODE_TOGGLE))
|
|
{
|
|
//apply the toggle crouch only if we are outside a vehicle
|
|
if (!m_pVehicle)
|
|
m_bStayCrouch = (m_bStayCrouch)?false:true;
|
|
|
|
cmd.RemoveAction(ACTION_MOVEMODE_TOGGLE);
|
|
}
|
|
|
|
bool bGoCrouch = cmd.CheckAction(ACTION_MOVEMODE) || m_bStayCrouch;
|
|
bool bGoProne = cmd.CheckAction(ACTION_MOVEMODE2);
|
|
|
|
if (m_stats.crouch && !m_bSwimming && !m_stats.onLadder)
|
|
{
|
|
//if it was crouching lets remove it otherwise the "onhold" will not work
|
|
if (!bGoCrouch)
|
|
RestorePrevStence();
|
|
// GoStand();
|
|
}
|
|
|
|
if (bGoCrouch || bGoProne)
|
|
{
|
|
if (!m_stats.onLadder)
|
|
{
|
|
if (m_stats.crouch)
|
|
{
|
|
if (bGoProne)
|
|
{
|
|
if (m_PrevStance == eProne)
|
|
GoStand(false);
|
|
else
|
|
GoProne( );
|
|
}
|
|
}
|
|
else
|
|
if (m_CurStance == eProne)
|
|
{
|
|
if (bGoProne)
|
|
// RestorePrevStence();
|
|
GoStand(false);
|
|
else
|
|
GoCrouch( );
|
|
}
|
|
else
|
|
if (m_CurStance == eSwim)
|
|
{
|
|
if (bGoProne)
|
|
// RestorePrevStence();
|
|
GoStand(false);
|
|
}
|
|
else
|
|
{
|
|
if (bGoProne)
|
|
GoProne( );
|
|
else
|
|
GoCrouch( );
|
|
}
|
|
}
|
|
cmd.RemoveAction(ACTION_MOVEMODE);
|
|
cmd.RemoveAction(ACTION_MOVEMODE2);
|
|
}
|
|
}
|
|
|
|
int bJump = 0;
|
|
|
|
if ( ( cmd.CheckAction(ACTION_WALK)^m_bAlwaysRun)&&
|
|
( cmd.CheckAction(ACTION_MOVE_RIGHT)||cmd.CheckAction(ACTION_MOVE_LEFT) ||
|
|
cmd.CheckAction(ACTION_MOVE_FORWARD)||cmd.CheckAction(ACTION_MOVE_BACKWARD) ) &&
|
|
!m_stats.bForceWalk )
|
|
{
|
|
if (!m_Running)
|
|
{
|
|
// cannot run if in crouch mode
|
|
if (!m_stats.crouch&&!m_stats.prone&&!m_bSwimming)
|
|
{
|
|
GoStand();
|
|
m_Running = true;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if( m_Running )
|
|
{
|
|
RestorePrevStence();
|
|
}
|
|
|
|
m_Running = false;
|
|
}
|
|
|
|
if (m_Running)
|
|
{
|
|
if ( cmd.CheckAction(ACTION_RUNSPRINT) && m_stats.stamina>m_StaminaTable.DecoyRun*.5f
|
|
|| cmd.CheckAction(ACTION_RUNSPRINT) && m_Sprinting && m_stats.stamina>1)
|
|
m_Sprinting = true;
|
|
else
|
|
m_Sprinting = false;
|
|
m_stats.running = true;
|
|
}
|
|
else
|
|
{
|
|
m_stats.running = false;
|
|
m_Sprinting = false;
|
|
}
|
|
|
|
m_walkParams.fLeanTarget=0;
|
|
// calculate leaning (if not proning and not at mounted weapon)
|
|
if (cmd.CheckAction(ACTION_LEANLEFT) && (!m_stats.lock_weapon) && (m_CurStance != eProne))
|
|
{
|
|
if(IsMyPlayer())
|
|
{
|
|
if (m_walkParams.leanEnd!=1.0f)
|
|
{
|
|
m_walkParams.leanStart=m_walkParams.leanAmount;
|
|
m_walkParams.leanEnd=1.0f;
|
|
m_walkParams.leanFactor=0.0f;
|
|
m_walkParams.leanDegree=m_LeanDegree;
|
|
}
|
|
m_walkParams.fLeanTarget=.5;
|
|
m_walkParams.leanSpeed=1.5f;
|
|
}
|
|
}else
|
|
if (cmd.CheckAction(ACTION_LEANRIGHT) && (!m_stats.lock_weapon) && (m_CurStance != eProne))
|
|
{
|
|
if(IsMyPlayer())
|
|
{
|
|
if (m_walkParams.leanEnd!=-1.0f)
|
|
{
|
|
m_walkParams.leanStart=m_walkParams.leanAmount;
|
|
m_walkParams.leanEnd=-1.0f;
|
|
m_walkParams.leanFactor=0.0f;
|
|
m_walkParams.leanDegree=m_LeanDegree;
|
|
|
|
|
|
}
|
|
m_walkParams.fLeanTarget=-1;
|
|
m_walkParams.leanSpeed=1.5f;
|
|
}
|
|
}else if (cmd.CheckAction(ACTION_MOVE_LEFT) )
|
|
{
|
|
if( !m_stats.onLadder )
|
|
{
|
|
if (m_walkParams.leanEnd!=0.1f)
|
|
{
|
|
m_walkParams.leanStart=m_walkParams.leanAmount;
|
|
m_walkParams.leanEnd=0.1f;
|
|
m_walkParams.leanFactor=0.0f;
|
|
m_walkParams.leanDegree=m_LeanDegree;
|
|
}
|
|
if ((m_walkParams.leanAmount>=0.0f) && (m_walkParams.leanAmount<=0.1f))
|
|
m_walkParams.leanSpeed=0.1f;
|
|
|
|
m_walkParams.fLeanTarget=0.05f;
|
|
|
|
if(m_walkParams.fCurrLean==0)
|
|
m_walkParams.leanSpeed=0.2f;
|
|
}
|
|
}else if (cmd.CheckAction(ACTION_MOVE_RIGHT) )
|
|
{
|
|
if( !m_stats.onLadder )
|
|
{
|
|
if (m_walkParams.leanEnd!=-0.1f)
|
|
{
|
|
m_walkParams.leanStart=m_walkParams.leanAmount;
|
|
m_walkParams.leanEnd=-0.1f;
|
|
m_walkParams.leanFactor=0.0f;
|
|
m_walkParams.leanDegree=m_LeanDegree;
|
|
}
|
|
if ((m_walkParams.leanAmount<=0.0f) && (m_walkParams.leanAmount>=-0.1f))
|
|
m_walkParams.leanSpeed=0.1f;
|
|
|
|
|
|
m_walkParams.fLeanTarget=-0.05f;
|
|
|
|
if(m_walkParams.fCurrLean==0)
|
|
m_walkParams.leanSpeed=0.2f;
|
|
}
|
|
}else if (m_walkParams.leanEnd!=0.0f)
|
|
{
|
|
m_walkParams.leanStart=m_walkParams.leanAmount;
|
|
m_walkParams.leanEnd=0.0f;
|
|
m_walkParams.leanFactor=0.0f;
|
|
}
|
|
|
|
//////////////////
|
|
//convert in the format used by physics
|
|
Vec3d tempangle = cmd.GetDeltaAngles();
|
|
Vec3d dirangle = tempangle;
|
|
dirangle=ConvertToRad(dirangle);
|
|
|
|
float m_pcos = cry_cosf(dirangle[YAW]);//*inputspeed;
|
|
float m_psin = cry_sinf(dirangle[YAW]);//*inputspeed;
|
|
|
|
float m_pcos2 = cry_cosf(dirangle[PITCH]);
|
|
float m_psin2 = cry_sinf(dirangle[PITCH]);
|
|
|
|
m_walkParams.dir.x = -m_psin;
|
|
m_walkParams.dir.y = m_pcos;
|
|
m_walkParams.dir.z = 0.0f;
|
|
|
|
Vec3d speedxyz(0.0f, 0.0f, 0.0f);
|
|
|
|
pe_status_dynamics dynStatus;
|
|
pPhysEnt->GetStatus((pe_status*)&dynStatus);
|
|
|
|
float fWaterMoveScale = m_SwimSpeed*0.5f*m_stats.fKWater + (1.0f-m_stats.fKWater);
|
|
|
|
if (cmd.CheckAction(ACTION_MOVE_FORWARD))
|
|
{
|
|
if(m_stats.onLadder) // when on ladder - move mostly UP/DOWN
|
|
{
|
|
speedxyz[0] += -m_psin*.3f;
|
|
speedxyz[1] += m_pcos*.3f;
|
|
}
|
|
else
|
|
{
|
|
speedxyz[0] += -m_psin;
|
|
speedxyz[1] += m_pcos;
|
|
}
|
|
if (bNoGravity)
|
|
{
|
|
speedxyz[0] *= m_psin2;
|
|
speedxyz[1] *= m_psin2;
|
|
//
|
|
//if swimming up - make sure not to go too fast to prevent jumping out of water
|
|
if(m_bSwimming && m_pcos2<0)
|
|
{
|
|
if( (m_stats.fInWater < m_PlayerDimSwim.heightEye &&
|
|
// m_walkParams.vertSpeed > .02f &&
|
|
!m_stats.onLadder) || dynStatus.v.z<-7.0f)
|
|
speedxyz[2] = -m_pcos2*fWaterMoveScale*m_stats.fKWater*.02f; // if close to surface - don't go up too fast - not to jump out of water
|
|
// or big vertical vel - falling down
|
|
else
|
|
speedxyz[2] = -m_pcos2*fWaterMoveScale; // deep enoght - can go up
|
|
}
|
|
else
|
|
speedxyz[2] = -m_pcos2;//*inputspeed;
|
|
}
|
|
else if(bSuperDesignerMode)
|
|
{
|
|
speedxyz[2] = -m_pcos2;//*inputspeed;
|
|
}
|
|
}
|
|
if (cmd.CheckAction(ACTION_MOVE_BACKWARD))
|
|
{
|
|
m_stats.back_pressed = true;
|
|
|
|
//FIXME: would be nice if backward key detach us from the ladder when we approach the ground (instead use the jump button), but for this
|
|
//more info about the ladder are needed, like the center position, to know if we are going up or down.
|
|
// if(m_stats.onLadder /*&& (m_fLastGroundHeight+1.0 <m_pEntity->GetPos(true).z)*/)// when on ladder - move mostly UP/DOWN
|
|
// {
|
|
// speedxyz[0] += -m_psin*.3f;
|
|
// speedxyz[1] -= m_pcos*.3f;
|
|
// }
|
|
// else
|
|
{
|
|
speedxyz[0] -= -m_psin;
|
|
speedxyz[1] -= m_pcos;
|
|
}
|
|
if ( bNoGravity )
|
|
{
|
|
speedxyz[0] *= m_psin2;
|
|
speedxyz[1] *= m_psin2;
|
|
//
|
|
//if swimming up - make sure not to go too fast to prevent jumping out of water
|
|
if(m_bSwimming && m_pcos2>0)
|
|
{
|
|
if( (m_stats.fInWater < m_PlayerDimSwim.heightEye &&
|
|
// m_walkParams.vertSpeed > .02f &&
|
|
!m_stats.onLadder) || dynStatus.v.z<-7.0f)
|
|
speedxyz[2] = m_pcos2*fWaterMoveScale*m_stats.fKWater*.02f; // if close to surface - don't go up too fast - not to jump out of water
|
|
else
|
|
speedxyz[2] = m_pcos2*fWaterMoveScale; // deep enoght - can go up
|
|
}
|
|
else
|
|
speedxyz[2] = m_pcos2;//*inputspeed;
|
|
}
|
|
else if(bSuperDesignerMode)
|
|
{
|
|
speedxyz[2] = m_pcos2;//*inputspeed;
|
|
}
|
|
}
|
|
else
|
|
m_stats.back_pressed = false;
|
|
|
|
bool bStrafe = false;
|
|
if (cmd.CheckAction(ACTION_MOVE_LEFT)) //&& !m_stats.onLadder)
|
|
{
|
|
/*if (m_stats.onLadder)
|
|
{
|
|
speedxyz[0] -= m_pcos*0.1f;
|
|
speedxyz[1] -= m_psin*0.1f;
|
|
}
|
|
else*/
|
|
{
|
|
speedxyz[0] -= m_pcos;
|
|
speedxyz[1] -= m_psin;
|
|
}
|
|
bStrafe = true;
|
|
}
|
|
|
|
if (cmd.CheckAction(ACTION_MOVE_RIGHT)) //&& !m_stats.onLadder)
|
|
{
|
|
/*if (m_stats.onLadder)
|
|
{
|
|
speedxyz[0] += m_pcos*0.1f;
|
|
speedxyz[1] += m_psin*0.1f;
|
|
}
|
|
else*/
|
|
{
|
|
speedxyz[0] += m_pcos;
|
|
speedxyz[1] += m_psin;
|
|
}
|
|
|
|
bStrafe = true;
|
|
}
|
|
|
|
if (GetLengthSquared(speedxyz)>0)
|
|
{
|
|
float fSpeedScale = m_stats.fSpeedScale*m_stats.dmgSpeedCoeff/100.0f;
|
|
float inputspeed;
|
|
|
|
if(m_stats.back_pressed && !m_stats.onLadder)
|
|
{
|
|
switch(m_CurStance)
|
|
{
|
|
case eStealth:
|
|
inputspeed = m_StealthSpeedBack;
|
|
break;
|
|
case eCrouch:
|
|
inputspeed = m_CrouchSpeedBack;
|
|
break;
|
|
case eProne:
|
|
inputspeed = m_ProneSpeedBack;
|
|
break;
|
|
case eSwim:
|
|
inputspeed = m_SwimSpeedBack;
|
|
break;
|
|
default:
|
|
inputspeed = m_WalkSpeedBack;
|
|
break;
|
|
}
|
|
|
|
if(m_Sprinting)
|
|
inputspeed = m_RunSpeedBack*m_StaminaTable.RunSprintScale;
|
|
else if(m_stats.running)
|
|
inputspeed = m_RunSpeedBack;
|
|
}
|
|
else if(!bStrafe || m_stats.onLadder)
|
|
{
|
|
switch(m_CurStance)
|
|
{
|
|
case eStealth:
|
|
inputspeed = m_StealthSpeed;
|
|
break;
|
|
case eCrouch:
|
|
inputspeed = m_CrouchSpeed;
|
|
break;
|
|
case eProne:
|
|
inputspeed = m_ProneSpeed;
|
|
break;
|
|
case eSwim:
|
|
inputspeed = m_SwimSpeed;
|
|
break;
|
|
default:
|
|
inputspeed = m_WalkSpeed;
|
|
break;
|
|
}
|
|
|
|
if(m_Sprinting)
|
|
inputspeed = m_RunSpeed*m_StaminaTable.RunSprintScale;
|
|
else if(m_stats.running)
|
|
inputspeed = m_RunSpeed;
|
|
}
|
|
else
|
|
{
|
|
switch(m_CurStance)
|
|
{
|
|
case eStealth:
|
|
inputspeed = m_StealthSpeedStrafe;
|
|
break;
|
|
case eCrouch:
|
|
inputspeed = m_CrouchSpeedStrafe;
|
|
break;
|
|
case eProne:
|
|
inputspeed = m_ProneSpeedStrafe;
|
|
break;
|
|
case eSwim:
|
|
inputspeed = m_SwimSpeedStrafe;
|
|
break;
|
|
default:
|
|
inputspeed = m_WalkSpeedStrafe;
|
|
break;
|
|
}
|
|
|
|
if(m_Sprinting)
|
|
inputspeed = m_RunSpeedStrafe*m_StaminaTable.RunSprintScale;
|
|
else if(m_stats.running)
|
|
inputspeed = m_RunSpeedStrafe;
|
|
}
|
|
|
|
if(bSuperDesignerMode)
|
|
{
|
|
if (m_Running)
|
|
inputspeed = m_pGame->p_speed_run->GetFVal();
|
|
else
|
|
inputspeed = m_pGame->p_speed_walk->GetFVal();
|
|
}
|
|
|
|
inputspeed *= fSpeedScale;
|
|
speedxyz.Normalize();
|
|
speedxyz*=inputspeed;
|
|
}
|
|
|
|
|
|
//Vec3 ppos=m_pEntity->GetPos(true);
|
|
|
|
// if player wants to jump AND proning - stand up
|
|
// otherwice if not crouching AND has enough stamina for jump
|
|
// AND not in air right now OR in water deep enough (go up then)
|
|
// AND not in landing animation
|
|
// do jump
|
|
if ((cmd.CheckAction(ACTION_JUMP)))
|
|
{
|
|
//if player is jumping when on ladder throw him back, to detach from the ladder.
|
|
if (m_stats.onLadder)
|
|
{
|
|
speedxyz[0] -= -m_psin;
|
|
speedxyz[1] -= m_pcos;
|
|
}
|
|
else if(m_CurStance == eProne)
|
|
{
|
|
GoStand(false);
|
|
cmd.RemoveAction(ACTION_JUMP);
|
|
}
|
|
else
|
|
if (m_CurStance != eCrouch
|
|
// && m_CurStance != eProne
|
|
&& ((!m_stats.flying) || IsSwimming())
|
|
&& ((m_stats.stamina>m_StaminaTable.DecoyJump&&!m_stats.flying) || IsSwimming())
|
|
&& m_JumpAniLenght<=0
|
|
)
|
|
{
|
|
m_JumpHeight[0] = m_pGame->p_jump_walk_h->GetFVal();
|
|
m_JumpHeight[1] = m_pGame->p_jump_walk_h->GetFVal();
|
|
m_JumpHeight[2] = m_pGame->p_jump_run_h->GetFVal();
|
|
|
|
m_JumpDist[0] = m_pGame->p_jump_walk_d->GetFVal();
|
|
m_JumpDist[1] = m_pGame->p_jump_walk_d->GetFVal();
|
|
m_JumpDist[2] = m_pGame->p_jump_run_d->GetFVal();
|
|
|
|
float jumpSpeedH, jumpSpeedV;
|
|
bJump = 1;
|
|
Vec3d horSpeed = speedxyz;
|
|
|
|
if(!IsSwimming())
|
|
{
|
|
if( m_RunningTime >= m_JTRun ) // if runs long enough - long jump
|
|
CalcJumpSpeed( m_JumpDist[2], m_JumpHeight[2], jumpSpeedH, jumpSpeedV );
|
|
else if( m_WalkingTime >= m_JTWalk ) // if runs long enough - long jump
|
|
CalcJumpSpeed( m_JumpDist[1], m_JumpHeight[1], jumpSpeedH, jumpSpeedV );
|
|
else
|
|
CalcJumpSpeed( m_JumpDist[0], m_JumpHeight[0], jumpSpeedH, jumpSpeedV );
|
|
|
|
horSpeed.z = 0;
|
|
horSpeed.Normalize();
|
|
speedxyz[0] = horSpeed.x*jumpSpeedH;
|
|
speedxyz[1] = horSpeed.y*jumpSpeedH;
|
|
speedxyz[2] = jumpSpeedV;
|
|
|
|
// decrease stamina - jumping is not for free!
|
|
if((m_stats.stamina-=m_StaminaTable.DecoyJump)<0)
|
|
m_stats.stamina = 0;
|
|
|
|
m_bHasJumped = true;
|
|
}
|
|
else
|
|
{
|
|
float depth = m_p3DEngine->GetWaterLevel(m_pEntity) - m_p3DEngine->GetTerrainElevation(m_pEntity->GetPos().x, m_pEntity->GetPos().y);
|
|
// if not deep and pressed jupm key - stand up, if can't stand (too deep) - push player up
|
|
if( depth<1.5f )
|
|
{
|
|
GoStand(false);
|
|
cmd.RemoveAction(ACTION_JUMP);
|
|
}
|
|
else
|
|
{
|
|
// if pressing jump in water - just push playet up
|
|
speedxyz[2] = 4.0f;
|
|
|
|
// when swimming underwater and goung up by press JUMP
|
|
// if too close to surface - don't aplpy much UP impulse
|
|
// to prevent jumping out of water
|
|
if(m_stats.fInWater<.75f)
|
|
speedxyz[2] = 0;
|
|
else if(m_stats.fInWater<2.25f)
|
|
speedxyz[2] *= (m_stats.fInWater/2.25f)*.2f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pe_status_living status;
|
|
pPhysEnt->GetStatus((pe_status*)&status);
|
|
m_stats.jumping = (bJump)?true:false;
|
|
|
|
pe_action_move hike;
|
|
hike.iJump = bJump && !bNoGravity;
|
|
hike.dir=speedxyz;
|
|
|
|
DampInputVector(hike.dir,m_input_accel,m_input_stop_accel,true,false);
|
|
|
|
pPhysEnt->Action(&hike);
|
|
|
|
float moveVel = speedxyz[0]*speedxyz[0] + speedxyz[1]*speedxyz[1];
|
|
// if the velosity is too low - not sprinting then
|
|
if(moveVel<2.0f)//|| (m_CurStance!=eStand && m_CurStance!=eRelaxed && m_CurStance!=eSwim))
|
|
m_Sprinting = false;
|
|
|
|
|
|
/*if(pPhysEnt) do
|
|
{
|
|
pPhysEnt->Step(min(fTimeDelta,0.02f));
|
|
fTimeDelta -= 0.02f;
|
|
} while(fTimeDelta>1E-4f);*/
|
|
float *pfSlices,sumSlice;
|
|
int i,nSlices = cmd.GetTimeSlices(pfSlices);
|
|
for(i=0,sumSlice=0; i<nSlices; i++)
|
|
sumSlice += pfSlices[i];
|
|
pPhysEnt->StartStep(sumSlice);
|
|
for(i=0; i<nSlices-1 && pPhysEnt; i++)
|
|
{
|
|
pPhysEnt->Step(pfSlices[i]);
|
|
pPhysEnt = m_pEntity->GetPhysics(); // update pPhysEnt since Step callback might change it (destroy/create new)
|
|
}
|
|
m_NotRunTimeClient = m_NotRunTime;
|
|
m_RunningTimeClient = m_RunningTime;
|
|
m_WalkingTimeClient = m_WalkingTime;
|
|
m_staminaClient = m_stats.stamina;
|
|
// m_breathClient = m_stats.breath;
|
|
if (nSlices>0 && pPhysEnt) // the last slice is teh 'server catch-up' slice, client doesn't have it
|
|
pPhysEnt->Step(pfSlices[nSlices-1]);
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Retrieves the currently selected weapon
|
|
@return selected weapon
|
|
*/
|
|
CWeaponClass* CPlayer::GetSelectedWeapon() const
|
|
{
|
|
CWeaponClass *pSelectedWeapon = m_pGame->GetWeaponSystemEx()->GetWeaponClassByID(m_nSelectedWeaponID);
|
|
|
|
// make sure the weapon class (models, scripts, etc..) is loaded ...
|
|
if (pSelectedWeapon && !pSelectedWeapon->IsLoaded())
|
|
{
|
|
pSelectedWeapon->Load();
|
|
}
|
|
return pSelectedWeapon;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::SelectNextWeapon()
|
|
{
|
|
int curr=0;
|
|
if(m_nSelectedWeaponID != -1)
|
|
curr = m_nSelectedWeaponID;
|
|
|
|
int slot=0;
|
|
|
|
while(slot<PLAYER_MAX_WEAPONS && m_vWeaponSlots[slot]!=curr)
|
|
slot++;
|
|
|
|
slot=(slot+1)%PLAYER_MAX_WEAPONS;
|
|
|
|
int iteration=0;
|
|
while(iteration<PLAYER_MAX_WEAPONS && (m_vWeaponSlots[slot]==0 || m_vWeaponSlots[slot]==curr))
|
|
{
|
|
iteration++;
|
|
slot=(slot+1)%PLAYER_MAX_WEAPONS;
|
|
}
|
|
if(m_vWeaponSlots[slot]!=0 && m_vWeaponSlots[slot]!=curr)
|
|
SelectWeapon(m_vWeaponSlots[slot]);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::SelectPrevWeapon()
|
|
{
|
|
int curr=0;
|
|
if(m_nSelectedWeaponID != -1)
|
|
curr=m_nSelectedWeaponID;
|
|
|
|
int slot=0;
|
|
|
|
while(slot<PLAYER_MAX_WEAPONS && m_vWeaponSlots[slot]!=curr)
|
|
slot++;
|
|
|
|
slot=(slot-1);
|
|
|
|
int iteration=0;
|
|
while(iteration<PLAYER_MAX_WEAPONS && (m_vWeaponSlots[slot]==0 || m_vWeaponSlots[slot]==curr))
|
|
{
|
|
iteration++;
|
|
slot=slot-1;
|
|
if(slot<0)
|
|
{
|
|
slot = PLAYER_MAX_WEAPONS-1;
|
|
while(slot>=0 && (m_vWeaponSlots[slot]==0))slot--;
|
|
if(slot<0)slot=0;
|
|
}
|
|
}
|
|
if(m_vWeaponSlots[slot]!=0 && m_vWeaponSlots[slot]!=curr)
|
|
SelectWeapon(m_vWeaponSlots[slot]);
|
|
}
|
|
|
|
/*! Updates the weapons of the player
|
|
@param ProcessingCmd structure of commands to process
|
|
*/
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::ProcessWeapons(CXEntityProcessingCmd &cmd)
|
|
{
|
|
// do not allow to use weapons and move when underwater or in a wtaer volume, and
|
|
// he is actively swimming
|
|
|
|
if(!IsMyPlayer())
|
|
m_walkParams.fCurrLean=cmd.GetLeaning();
|
|
|
|
if (cmd.CheckAction(ACTION_NEXT_WEAPON) && (!m_stats.lock_weapon))
|
|
{
|
|
SelectNextWeapon();
|
|
}
|
|
else if (cmd.CheckAction(ACTION_PREV_WEAPON) && (!m_stats.lock_weapon))
|
|
{
|
|
SelectPrevWeapon();
|
|
}
|
|
else
|
|
{
|
|
if(!m_stats.lock_weapon)
|
|
{
|
|
bool bSkip = false;
|
|
int w = 0;
|
|
int WeaponGroup=0;
|
|
if (cmd.CheckAction(ACTION_WEAPON_0))
|
|
{
|
|
WeaponGroup = 10;
|
|
cmd.RemoveAction(ACTION_WEAPON_0);
|
|
}
|
|
else if (cmd.CheckAction(ACTION_WEAPON_1))
|
|
{
|
|
WeaponGroup = 1;
|
|
cmd.RemoveAction(ACTION_WEAPON_1);
|
|
}
|
|
else if (cmd.CheckAction(ACTION_WEAPON_2))
|
|
{
|
|
WeaponGroup = 2;
|
|
cmd.RemoveAction(ACTION_WEAPON_2);
|
|
}
|
|
else if (cmd.CheckAction(ACTION_WEAPON_3))
|
|
{
|
|
WeaponGroup = 3;
|
|
cmd.RemoveAction(ACTION_WEAPON_3);
|
|
}
|
|
else if (cmd.CheckAction(ACTION_WEAPON_4))
|
|
{
|
|
WeaponGroup = 4;
|
|
cmd.RemoveAction(ACTION_WEAPON_4);
|
|
}
|
|
/* else if (cmd.CheckAction(ACTION_WEAPON_5))
|
|
{
|
|
WeaponGroup = 5;
|
|
cmd.RemoveAction(ACTION_WEAPON_5);
|
|
}
|
|
else if (cmd.CheckAction(ACTION_WEAPON_6))
|
|
{
|
|
WeaponGroup = 6;
|
|
cmd.RemoveAction(ACTION_WEAPON_6);
|
|
}
|
|
else if (cmd.CheckAction(ACTION_WEAPON_7))
|
|
{
|
|
WeaponGroup = 7;
|
|
cmd.RemoveAction(ACTION_WEAPON_7);
|
|
}
|
|
else if (cmd.CheckAction(ACTION_WEAPON_8))
|
|
{
|
|
WeaponGroup = 8;
|
|
cmd.RemoveAction(ACTION_WEAPON_8);
|
|
}
|
|
*/ else
|
|
bSkip = true;
|
|
|
|
if (!bSkip)
|
|
{
|
|
w = m_nSelectedWeaponID;
|
|
bool bFirstWeapon = true;
|
|
int iFirstID=-1;
|
|
WeaponGroup-=1;
|
|
if(WeaponGroup<PLAYER_MAX_WEAPONS)
|
|
{
|
|
if(m_vWeaponSlots[WeaponGroup])
|
|
{
|
|
SelectWeapon(m_vWeaponSlots[WeaponGroup]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// get the selected weapon
|
|
CWeaponClass *pSelectedWeapon = GetSelectedWeapon();
|
|
|
|
//uses this flag to affect the accuracy
|
|
if(!m_bFirstPerson)
|
|
m_stats.aiming=cmd.CheckAction(ACTION_ZOOM_TOGGLE);
|
|
|
|
if (cmd.CheckAction(ACTION_CYCLE_GRENADE))
|
|
{
|
|
m_pEntity->SendScriptEvent(ScriptEvent_CycleGrenade,0);
|
|
cmd.RemoveAction(ACTION_CYCLE_GRENADE);
|
|
}
|
|
|
|
if (cmd.CheckAction(ACTION_FIREMODE))
|
|
{
|
|
SwitchFiremode();
|
|
cmd.RemoveAction(ACTION_FIREMODE);
|
|
}
|
|
|
|
if (cmd.CheckAction(ACTION_RELOAD) && (!m_stats.lock_weapon) &&
|
|
(m_stats.underwater==0.0f) && !m_bSwimming)
|
|
{
|
|
if (pSelectedWeapon)
|
|
{
|
|
pSelectedWeapon->ScriptOnStopFiring(m_pEntity);
|
|
pSelectedWeapon->ScriptReload(m_pEntity);
|
|
}
|
|
|
|
cmd.RemoveAction(ACTION_RELOAD);
|
|
}
|
|
|
|
// Check if the player is dropping his weapon
|
|
if(cmd.CheckAction(ACTION_DROPWEAPON) && (!m_stats.lock_weapon))
|
|
{
|
|
|
|
if (pSelectedWeapon && (CountAvaliableWeapons()>1))
|
|
{
|
|
// Remove the current weapon from the player's inventory
|
|
PlayerWeaponsItor WeaponIterator = m_mapPlayerWeapons.find(m_nSelectedWeaponID);
|
|
if (WeaponIterator == m_mapPlayerWeapons.end())
|
|
{
|
|
// This should not ever happen
|
|
TRACE("Could not find dropped weapon in weapon list");
|
|
return;
|
|
}
|
|
|
|
// Notify the weapon that it has been dropped
|
|
_SmartScriptObject pTable(m_pScriptSystem);
|
|
pTable->SetValue("Player", m_pEntity->GetScriptObject());
|
|
pTable->SetValue("WeaponID", m_nSelectedWeaponID);
|
|
pSelectedWeapon->ScriptDrop(pTable);
|
|
}
|
|
|
|
// Remove the command
|
|
cmd.RemoveAction(ACTION_DROPWEAPON);
|
|
}
|
|
|
|
if (m_bWaitForFireRelease && !cmd.CheckAction(ACTION_FIRE0))
|
|
{
|
|
m_bWaitForFireRelease = false;
|
|
}
|
|
|
|
if (!m_bWaitForFireRelease)
|
|
{
|
|
m_stats.firing = (cmd.CheckAction(ACTION_FIRE0)) != 0;
|
|
}
|
|
else
|
|
m_stats.firing = false;
|
|
|
|
|
|
if(cmd.CheckAction(ACTION_FIRECANCEL))
|
|
m_stats.cancelFireFlag = true;
|
|
else
|
|
m_stats.cancelFireFlag = false;
|
|
|
|
if (!GetGame()->IsMultiplayer() || m_bWriteOccured)
|
|
m_stats.firing_grenade = false;
|
|
|
|
if ((cmd.CheckAction(ACTION_FIRE_GRENADE)))
|
|
{
|
|
if(m_stats.weapon_busy<=0)
|
|
{
|
|
m_stats.firing_grenade = true;
|
|
}
|
|
}
|
|
|
|
if (m_bWriteOccured) m_bWriteOccured = false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::FireGrenade(const Vec3d &origin, const Vec3d &angles, IEntity *pIShooter)
|
|
{
|
|
_SmartScriptObject pTable(m_pScriptSystem);
|
|
|
|
m_ssoHitPosVec=origin;
|
|
m_ssoHitNormVec=angles;//angles;
|
|
Vec3d dir=angles;
|
|
dir=ConvertToRadAngles(dir);
|
|
|
|
// projectiles (grenades, for ex) should inherit player's velocity
|
|
m_ssoHitDirVec=dir; //+(m_walkParams.dir.normalize()*(m_stats.fVel*0.125f));
|
|
//m_pGame->GetSystem()->GetILog()->LogToConsole("vel=%f,dir=%f,%f,%f",m_stats.fVel,m_walkParams.dir.x,m_walkParams.dir.y,m_walkParams.dir.z);
|
|
float fWaterLevel=m_p3DEngine->GetWaterLevel(m_pEntity);
|
|
pTable->SetValue("pos",m_ssoHitPosVec);
|
|
pTable->SetValue("angles",m_ssoHitNormVec);
|
|
pTable->SetValue("dir",m_ssoHitDirVec);
|
|
|
|
pTable->SetValue("lifetime",3000);
|
|
|
|
if(m_nSelectedWeaponID != -1 && m_stats.firing && !(m_stats.grenadetype!= 1 && m_stats.numofgrenades <= 0))
|
|
GetSelectedWeapon()->ScriptOnStopFiring(m_pEntity);
|
|
|
|
if (fWaterLevel>origin.z)
|
|
pTable->SetValue("underwater",0);
|
|
else
|
|
pTable->SetToNull("underwater");
|
|
m_pEntity->SendScriptEvent(ScriptEvent_FireGrenade, *pTable);
|
|
if(m_pMountedWeapon) // stop fire animation on mounted weapon
|
|
m_pMountedWeapon->SendScriptEvent(ScriptEvent_Fire,0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::SetFiring(bool bIsFiring)
|
|
{
|
|
eFireType lastft=m_stats.FiringType;
|
|
if (/*m_pSelectedWeapon &&*/ bIsFiring && IsAlive() && !m_stats.onLadder)
|
|
{
|
|
switch (m_stats.FiringType)
|
|
{
|
|
case ePressing: m_stats.FiringType=eHolding; break;
|
|
case eHolding: m_stats.FiringType=eHolding; break;
|
|
case eReleasing: m_stats.FiringType=ePressing; break;
|
|
case eNotFiring: m_stats.FiringType=ePressing; break;
|
|
default: m_stats.FiringType=eNotFiring;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
switch (m_stats.FiringType)
|
|
{
|
|
case ePressing: m_stats.FiringType=eNotFiring; break;
|
|
case eHolding: m_stats.FiringType=eReleasing; break;
|
|
case eReleasing: m_stats.FiringType=eNotFiring; break;
|
|
case eNotFiring: m_stats.FiringType=eNotFiring; break;
|
|
default: m_stats.FiringType=eNotFiring;
|
|
}
|
|
|
|
}
|
|
m_stats.LastFiringType=lastft;
|
|
/*if (m_stats.FiringType == PlayerStats::eFireType::ePressing)
|
|
m_stats.FiringType = PlayerStats::eFireType::eHolding;
|
|
else if (m_stats.FiringType == PlayerStats::eFireType::eReleasing)
|
|
m_stats.FiringType = PlayerStats::eFireType::eNotFiring;*/
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::DrawThirdPersonWeapon(bool bDraw)
|
|
{
|
|
ICryCharInstance *character = m_pEntity->GetCharInterface()->GetCharacter(PLAYER_MODEL_IDX);
|
|
if (character && m_nSelectedWeaponID != -1)
|
|
{
|
|
WeaponInfo &wi = GetWeaponInfo();
|
|
|
|
if(bDraw)
|
|
{
|
|
CWeaponClass* pSelectedWeapon = GetSelectedWeapon();
|
|
|
|
string sBone = pSelectedWeapon->GetBindBone();
|
|
if (!sBone.empty())
|
|
{
|
|
wi.hBindInfo = character->AttachObjectToBone( pSelectedWeapon->GetObject(), sBone.c_str() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wi.DetachBindingHandles(character);
|
|
character->AttachObjectToBone(NULL,NULL);
|
|
}
|
|
}
|
|
}
|
|
///////////////////////////////////////////////
|
|
/*! Selects a weapon the player should hold
|
|
@param weapon id of weapon to set
|
|
*/
|
|
bool CPlayer::SelectWeapon( int weapon, bool bCheckForAvailability )
|
|
{
|
|
PlayerWeaponsItor wi;
|
|
|
|
// if it's shooter from the vehicle - can't select weapons
|
|
if (m_nSelectedWeaponID>0 && m_pVehicle && m_pVehicle->GetWeaponUser()==this)
|
|
return false;
|
|
if (m_stats.onLadder)
|
|
return false;
|
|
|
|
if ((wi = m_mapPlayerWeapons.find(weapon)) == m_mapPlayerWeapons.end() && weapon != -1)
|
|
return false;
|
|
|
|
if (bCheckForAvailability && weapon != -1)
|
|
{
|
|
if ((* wi).second.owns == false)
|
|
return false;
|
|
}
|
|
|
|
m_pEntity->SendScriptEvent(ScriptEvent_SelectWeapon,0);
|
|
// deselect old weapon, if selected
|
|
if (m_nSelectedWeaponID != -1 && (weapon!=m_stats.weapon))
|
|
{
|
|
// unbind the entity from the player
|
|
WeaponInfo &info=GetWeaponInfo();
|
|
|
|
info.iFireMode=m_stats.firemode;
|
|
_SmartScriptObject cOnUpdateParam(m_pScriptSystem);
|
|
cOnUpdateParam->SetValue("shooter", m_pEntity->GetScriptObject());
|
|
GetSelectedWeapon()->ScriptOnDeactivate(m_pEntity);
|
|
}
|
|
|
|
SetWeapon(weapon);
|
|
|
|
// call OnActivate when the weapon changes
|
|
if (m_nSelectedWeaponID != -1 && (weapon != m_stats.weapon))
|
|
{
|
|
WeaponInfo &info=GetWeaponInfo();
|
|
m_stats.firemode=info.iFireMode;
|
|
m_bWaitForFireRelease = true;
|
|
GetSelectedWeapon()->ScriptOnActivate(m_pEntity);
|
|
|
|
// make sure that the firemode is correct on script side
|
|
_SmartScriptObject pObj(m_pScriptSystem);
|
|
pObj->SetValue( "firemode", m_stats.firemode);
|
|
pObj->SetValue( "ignoreammo", true);
|
|
|
|
bool bCanSwitch;
|
|
m_pEntity->SendScriptEvent(ScriptEvent_FireModeChange, *pObj, &bCanSwitch);
|
|
|
|
// force animation update on first person weapon
|
|
if (GetSelectedWeapon()->GetCharacter())
|
|
GetSelectedWeapon()->GetCharacter()->ForceUpdate();
|
|
}
|
|
m_stats.weapon = m_nSelectedWeaponID;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CPlayer::SetWeapon(int iClsID)
|
|
{
|
|
// ValidateHeap();
|
|
// check if we want to select the weapon we are holding
|
|
if(iClsID == m_nSelectedWeaponID)
|
|
return;
|
|
|
|
// we want to hide the currently selected weapon
|
|
if(m_nSelectedWeaponID != -1)
|
|
{
|
|
if (m_stats.LastFiringType!=eNotFiring)
|
|
GetSelectedWeapon()->ScriptOnStopFiring(m_pEntity);
|
|
|
|
SetWeaponPositionState(WEAPON_POS_UNDEFINED);
|
|
|
|
if (IsMyPlayer())
|
|
{
|
|
ICryCharInstance *pChar = GetEntity()->GetCharInterface()->GetCharacter(1);
|
|
if (pChar)
|
|
pChar->DetachAll();
|
|
|
|
GetEntity()->DrawCharacter(1,0);
|
|
GetEntity()->ResetAnimations(1);
|
|
}
|
|
}
|
|
|
|
// here we actually set the new weapon
|
|
m_nSelectedWeaponID = iClsID;
|
|
// returns the newly selected weapon!!!
|
|
CWeaponClass* pSelectedWeapon = GetSelectedWeapon();
|
|
|
|
|
|
if(pSelectedWeapon)
|
|
{
|
|
// attach to bone for third person view
|
|
HoldWeapon();
|
|
// set first person weapon
|
|
if (IsMyPlayer() || m_pGame->IsMultiplayer())
|
|
GetEntity()->GetCharInterface()->SetCharacter(1, pSelectedWeapon->GetCharacter());
|
|
|
|
m_pScriptObject->SetValue("weapon", pSelectedWeapon->GetScriptObject());
|
|
m_pScriptObject->SetValue("weaponid", m_nSelectedWeaponID);
|
|
} else {
|
|
GetEntity()->GetCharInterface()->SetCharacter(1, 0);
|
|
m_pScriptObject->SetToNull("weapon");
|
|
m_pScriptObject->SetToNull("weaponid");
|
|
m_stats.fSpeedScale = 1.0f;
|
|
m_nSelectedWeaponID = -1;
|
|
}
|
|
}
|
|
|
|
/*! return the position and orientation of the firepoint of a player
|
|
@param firePos position
|
|
@param fireAngles orientation(in degrees)
|
|
*/
|
|
void CPlayer::GetFirePosAngles(Vec3d& firePos, Vec3d& fireAngles)
|
|
{
|
|
if (!m_bIsAI)
|
|
{
|
|
//we must always take leaning into account!
|
|
fireAngles = m_vEyeAngles+m_vShake;
|
|
//fireAngles = m_pEntity->GetAngles()+m_vShake;
|
|
firePos = m_vEyePos;
|
|
|
|
/*
|
|
if (m_pMountedWeapon)
|
|
{
|
|
IEntityCharacter *pIChar = m_pMountedWeapon->GetCharInterface();
|
|
ICryCharInstance * cmodel = pIChar->GetCharacter(0);
|
|
|
|
if (!cmodel)
|
|
return;
|
|
|
|
ICryBone * pBone = cmodel->GetBoneByName("spitfire");
|
|
if(!pBone)
|
|
return;
|
|
|
|
Vec3 vBonePos = pBone->GetBonePosition();
|
|
Vec3 angles = m_pMountedWeapon->GetAngles();
|
|
Matrix44 m=Matrix34::GetRotationXYZ34( Deg2Rad(angles), m_pMountedWeapon->GetPos() ); //set rotation and translation in one function call
|
|
m = GetTransposed44(m); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
|
|
// get result
|
|
firePos = m.TransformPointOLD(vBonePos);
|
|
}
|
|
else
|
|
*/
|
|
if (m_pVehicle)
|
|
{
|
|
// if we are in vehicle, the cam offset seems to be wrong -
|
|
// move to the exact camera position
|
|
//[kirill] - coz camera is offseted a bit for gunner - away from weapon
|
|
// if gunner's camera moved - add same offset here - now it's eyePos
|
|
// firePos=m_pEntity->GetCamera()->GetPos();
|
|
// if driver - using vehicle's autoveapon
|
|
// - just get current weapon pos/angles from the vehicle
|
|
// if (m_stats.inVehicleState==PVS_DRIVER && m_pVehicle->GetWeaponUser()==this )
|
|
if (m_stats.inVehicleState==PVS_DRIVER )
|
|
{
|
|
string vehicleWeaponName = m_pVehicle->GetWeaponName( m_stats.inVehicleState );
|
|
if(!vehicleWeaponName.empty() && vehicleWeaponName != m_pVehicle->m_sNoWeaponName)
|
|
m_pVehicle->GetFirePosAngles( firePos, fireAngles );
|
|
else if(IsMyPlayer()) // use vehicle camera position only for local player
|
|
firePos = m_pVehicle->GetCamPos();
|
|
else
|
|
firePos += Vec3(0.0f, 0.0f, -1.04f); // UGLY FIX FOR THE INFLATABLE BOAT!
|
|
// firePos on the server was 0.6 meters less than the client
|
|
}
|
|
// if passenger - get camera position from vehicle, it's smoothed with some spring simulation
|
|
else if (m_stats.inVehicleState == PVS_PASSENGER)
|
|
{
|
|
if(IsMyPlayer()) // use vehicle camera position only for local player
|
|
firePos = m_pVehicle->GetCamPos();
|
|
else // in MP on server use eye helper position
|
|
m_pVehicle->GetEntity()->GetHelperPosition(m_sVehicleEyeHelper.c_str(), firePos);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_pEntity->GetAI())
|
|
{
|
|
//<<FIXME>> this code will go - testing purposes
|
|
firePos = m_pEntity->GetAI()->GetPos();
|
|
// Vec3d angles = m_pEntity->GetAI()->GetState()->vFireDir;
|
|
// angles=ConvertVectorToCameraAngles(angles);
|
|
if(!m_pMountedWeapon) // normal weapon - shoot wherever
|
|
fireAngles = m_vDEBUGAIFIREANGLES;
|
|
// fireAngles = angles;
|
|
else // if using mounted weapon - angles are restricted
|
|
fireAngles = m_pEntity->GetAngles();
|
|
}
|
|
}
|
|
}
|
|
|
|
float CPlayer::CalculateAccuracyFactor(float accuracy)
|
|
{
|
|
if(m_nSelectedWeaponID == -1) return 0.0f;
|
|
|
|
CWeaponClass *pSelectedWeapon = GetSelectedWeapon();
|
|
WeaponParams wp;
|
|
|
|
GetCurrentWeaponParams(wp);
|
|
|
|
float factor = (wp.fMaxAccuracy - wp.fMinAccuracy) * (1.0f-accuracy) + wp.fMinAccuracy;
|
|
|
|
// factor 0 = bad, 1 = good
|
|
if (m_stats.aiming)
|
|
{
|
|
factor = factor + wp.fAimImprovement;
|
|
}
|
|
|
|
// apply sprinting if the sprint button is pressed and the player is moving
|
|
if (m_Sprinting && m_stats.moving)
|
|
{
|
|
factor = factor - wp.fSprintPenalty;
|
|
}
|
|
|
|
factor = 1 - factor;
|
|
factor = __max(factor, 0.000f);
|
|
|
|
float stanceAccuracyModifier = 1.0f;
|
|
|
|
// process weapon specific accuracy modifier based on stance
|
|
stanceAccuracyModifier = wp.fAccuracyModifierStanding;
|
|
if (m_CurStance == eCrouch)
|
|
{
|
|
stanceAccuracyModifier = wp.fAccuracyModifierCrouch;
|
|
}
|
|
else if (m_CurStance == eProne)
|
|
{
|
|
stanceAccuracyModifier = wp.fAccuracyModifierProne;
|
|
}
|
|
|
|
return factor * stanceAccuracyModifier;
|
|
}
|
|
|
|
void CPlayer::UpdateMelee()
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
//MELEE ATTACK/////////////////////////////////////
|
|
if(m_stats.melee_attack && (m_stats.weapon_busy<=0) && (m_stats.melee_distance > 0.0f))
|
|
{
|
|
//TRACE("UATTATATATATATATATA!");
|
|
_SmartScriptObject so(m_pScriptSystem);
|
|
Vec3d firePos;
|
|
Vec3d fireAngles;
|
|
|
|
GetFirePosAngles(firePos, fireAngles);
|
|
|
|
Vec3d dir(0,-1,0);
|
|
Matrix44 tm = Matrix44::CreateRotationZYX(-fireAngles*gf_DEGTORAD); //NOTE: angles in radians and negated ;
|
|
|
|
dir = GetTransposed44(tm)*(dir);
|
|
|
|
m_ssoHitPosVec = firePos;
|
|
m_ssoHitDirVec = dir;
|
|
|
|
so->BeginSetGetChain();
|
|
so->SetValueChain("pos",m_ssoHitPosVec);
|
|
so->SetValueChain("dir",m_ssoHitDirVec);
|
|
so->SetValueChain("distance", m_stats.melee_distance);
|
|
so->SetValueChain("shooter",m_pEntity->GetScriptObject());
|
|
|
|
_SmartScriptObject soTarget(m_pScriptSystem,true);
|
|
if (GetScriptObject()->GetValue("melee_target", soTarget))
|
|
{
|
|
so->SetValueChain("melee_target", *soTarget);
|
|
}
|
|
so->EndSetGetChain();
|
|
|
|
m_pEntity->SendScriptEvent(ScriptEvent_MeleeAttack,so);
|
|
m_stats.melee_attack = false;
|
|
m_pEntity->GetScriptObject()->SetToNull("melee_target");
|
|
}
|
|
}
|
|
///////////////////////////////////////////////
|
|
/*! Updates the selected weapon
|
|
*/
|
|
void CPlayer::UpdateWeapon()
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
float frametime=m_pTimer->GetFrameTime();
|
|
|
|
if(m_stats.firing_grenade)
|
|
{
|
|
FRAME_PROFILER( "UpdateWeapon::Grenade",GetISystem(),PROFILE_GAME );
|
|
Vec3d firePos;
|
|
Vec3d fireAngles;
|
|
GetFirePosAngles(firePos, fireAngles);
|
|
|
|
if(m_stats.weapon_busy<=0)
|
|
FireGrenade(firePos, fireAngles, m_pEntity);
|
|
|
|
if (!GetGame()->IsMultiplayer())
|
|
m_stats.firing_grenade = false;
|
|
}
|
|
|
|
|
|
if(m_nSelectedWeaponID == -1) return;
|
|
|
|
WeaponParams wp;
|
|
CWeaponClass* pSelectedWeapon = GetSelectedWeapon();
|
|
|
|
GetCurrentWeaponParams(wp);
|
|
m_fAccuracyMod=1;
|
|
if(m_pGame->IsServer())
|
|
{
|
|
// make sure that the AI is always using the right firemode
|
|
if(m_bIsAI)
|
|
{
|
|
FRAME_PROFILER( "UpdateWeapon::SwitchFiremode",GetISystem(),PROFILE_GAME );
|
|
SwitchFiremode(pSelectedWeapon->GetAIFireMode());
|
|
}
|
|
|
|
if(m_stats.firing){
|
|
m_fAccuracy=m_fAccuracy-(frametime);
|
|
}else{
|
|
m_fAccuracy=m_fAccuracy-(m_pGame->w_accuracy_gain_scale*frametime);
|
|
}
|
|
m_fAccuracy=__max(m_fAccuracy, 0.1f);
|
|
|
|
if(!m_pMountedWeapon && !m_pVehicle)
|
|
{
|
|
if(m_stats.running)
|
|
{
|
|
if(m_fAccuracy<wp.accuracy_decay_on_run)
|
|
{
|
|
m_fAccuracy=min(wp.accuracy_decay_on_run,m_fAccuracy+(frametime*6));
|
|
}
|
|
}
|
|
else if(m_stats.moving)
|
|
{
|
|
if(m_fAccuracy<(wp.accuracy_decay_on_run))
|
|
{
|
|
m_fAccuracy=min(wp.accuracy_decay_on_run,m_fAccuracy+(frametime*3));
|
|
}
|
|
}
|
|
}
|
|
if(m_stats.crouch || m_stats.prone){
|
|
m_fAccuracyMod-=0.2f;
|
|
}
|
|
|
|
if(m_stats.aiming)
|
|
{
|
|
m_fAccuracyMod-=0.3f;
|
|
}
|
|
|
|
//TRACE("m_stats.accuracy=%f",m_stats.accuracy);
|
|
//clamp accuracy to 1 byte
|
|
BYTE acc=(BYTE)((m_fAccuracy*m_fAccuracyMod)/(1.f/255));
|
|
m_stats.accuracy=(float)((acc)*(1.f/255));
|
|
}
|
|
|
|
WeaponInfo &wi=GetWeaponInfo();
|
|
|
|
if(m_stats.weapon_busy>0)
|
|
{
|
|
m_stats.firing=false;
|
|
}
|
|
else{
|
|
if(m_stats.weapon_busy!=0)
|
|
{
|
|
FRAME_PROFILER( "UpdateWeapon::ScriptWeaponReady",GetISystem(),PROFILE_GAME );
|
|
wi.fireTime=m_pTimer->GetCurrTime();
|
|
//wi->fireFirstBulletTime=0;
|
|
pSelectedWeapon->ScriptWeaponReady(m_pEntity);
|
|
}
|
|
m_stats.weapon_busy=0;
|
|
}
|
|
|
|
|
|
//Update the weapon entity
|
|
if (IsMyPlayer() || (m_pGame->cl_scope_flare->GetIVal() == 1 && m_weaponPositionState == WEAPON_POS_HOLD ))
|
|
pSelectedWeapon->Update(this);
|
|
|
|
if (m_stats.cancelFireFlag)
|
|
pSelectedWeapon->CancelFire();
|
|
|
|
if((m_stats.ammo_in_clip<=0 && m_stats.ammo>0 && (!m_stats.reloading) && (m_stats.weapon_busy<=0)) && (!m_stats.firing) &&
|
|
(m_stats.underwater==0.0f) && !m_bSwimming)
|
|
{
|
|
pSelectedWeapon->ScriptOnStopFiring(m_pEntity);
|
|
pSelectedWeapon->ScriptReload(m_pEntity);
|
|
wi.fireTime=m_pTimer->GetCurrTime();
|
|
}
|
|
else if(!m_stats.reloading && m_stats.weapon_busy<=0)
|
|
{
|
|
if(m_stats.ammo_in_clip>0 || wp.no_ammo)
|
|
{
|
|
if ((m_pTimer->GetCurrTime() - wi.fireLastShot) < pSelectedWeapon->GetFireRate(m_stats.FiringType))
|
|
m_stats.fire_rate_busy = true;
|
|
else
|
|
m_stats.fire_rate_busy = false;
|
|
|
|
m_stats.canfire = true;
|
|
}
|
|
else
|
|
{
|
|
if(m_stats.canfire)
|
|
pSelectedWeapon->ScriptOnStopFiring(m_pEntity);
|
|
|
|
m_stats.canfire=false;
|
|
}
|
|
|
|
SetFiring(m_stats.firing);
|
|
|
|
if (m_stats.FiringType != eNotFiring)
|
|
{
|
|
float fFireRate = pSelectedWeapon->GetFireRate(m_stats.FiringType);
|
|
//is in the right state for firing
|
|
if( wp.fire_activation&m_stats.FiringType)
|
|
{
|
|
Vec3d firePos;
|
|
Vec3d fireAngles;
|
|
|
|
GetFirePosAngles(firePos, fireAngles);
|
|
|
|
if(!(m_stats.LastFiringType&wp.fire_activation))
|
|
{
|
|
wi.fireTime=m_pTimer->GetCurrTime();
|
|
wi.fireFirstBulletTime=wi.fireTime;
|
|
m_fRecoilXDelta=0;
|
|
}
|
|
float deltatime=max(0.001f,m_pTimer->GetCurrTime()-wi.fireFirstBulletTime);
|
|
|
|
int bullets=0;
|
|
//[kirill] - can't shoot if using mounted vehicle weapon and weapon is off of angle limits
|
|
if (m_pGame->m_nDEBUG_TIMING==1)
|
|
{
|
|
m_pGame->m_nDEBUG_TIMING = 2;
|
|
//[Michael Glueck] has nothing to do with AI
|
|
if(m_bIsAI)
|
|
{
|
|
float fTime = m_pGame->GetSystem()->GetITimer()->GetAsyncCurTime();
|
|
m_pGame->m_pLog->Log(" Time between loading and having AI shooting is %.3f seconds",fTime-m_pGame->m_fDEBUG_STARTTIMER);
|
|
}
|
|
}
|
|
if(m_stats.crosshairOnScreen)
|
|
if(bullets = pSelectedWeapon->Fire( firePos,fireAngles, this, wi, GetRedirected() ? GetRedirected()->GetPhysics() : NULL))
|
|
{
|
|
FRAME_PROFILER( "UpdateWeapon::ScriptEvent_Fire",GetISystem(),PROFILE_GAME );
|
|
|
|
if(m_pMountedWeapon) // start fire animation on mounted weapon
|
|
m_pMountedWeapon->SendScriptEvent(ScriptEvent_Fire,1);
|
|
else if( m_pVehicle )
|
|
{
|
|
WeaponInfo &wi = GetWeaponInfo();
|
|
m_pVehicle->WeaponState( m_pEntity->GetId(), true, wi.iFireMode);
|
|
}
|
|
|
|
if(m_pGame->IsServer())
|
|
{
|
|
m_stats.last_accuracy=(BYTE)(m_stats.accuracy/(1.f/255));
|
|
m_fAccuracy=min(1,m_fAccuracy+((deltatime*(m_pGame->w_accuracy_decay_speed*fFireRate)*bullets)));
|
|
BYTE acc=(BYTE)((m_fAccuracy*m_fAccuracyMod)/(1.f/255));
|
|
m_stats.accuracy=(float)((acc)*(1.f/255));
|
|
}
|
|
|
|
//add recoil
|
|
if(!IsAI()) //IsMyPlayer()) // every player should have recoil
|
|
{
|
|
//pseudo realistic recoil
|
|
if((m_fRecoilXDelta+1)<m_pGame->w_recoil_max_degree)
|
|
{
|
|
float delta=min(1, (m_pTimer->GetCurrTime()-wi.fireFirstBulletTime)+wp.fFireRate);
|
|
float recoilx=wp.max_recoil*((delta*2)*2);
|
|
float recoilz=recoilx;
|
|
|
|
uint8 ucSeed = m_SynchedRandomSeed.GetRandomSeedC();
|
|
|
|
m_SynchedRandomSeed.IncreaseRandomSeedC();
|
|
|
|
// GetISystem()->GetILog()->Log(">> Recoil Recoil %d %d",(int)GetEntity()->GetId(),(int)(ucSeed)); // debug
|
|
|
|
float fRandA = m_SynchedRandomSeed.GetRandTable(ucSeed);
|
|
float fRandB = m_SynchedRandomSeed.GetRandTable(ucSeed+13);
|
|
|
|
m_fRecoilXUp=m_fRecoilX=(min(wp.max_recoil,wp.min_recoil+recoilx+(recoilx*fRandA)))*bullets;
|
|
m_fRecoilZUp=m_fRecoilZ=((m_fRecoilXUp)-(m_fRecoilXUp*fRandA)*2)*bullets;
|
|
if (m_stats.aiming)
|
|
{
|
|
m_fRecoilX *= wp.fAimRecoilModifier;
|
|
m_fRecoilXUp *= wp.fAimRecoilModifier;
|
|
m_fRecoilZ *= wp.fAimRecoilModifier;
|
|
m_fRecoilZUp *= wp.fAimRecoilModifier;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//m_fRecoilXUp=0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
}
|
|
else if(m_stats.LastFiringType!=eNotFiring)
|
|
{
|
|
FRAME_PROFILER( "UpdateWeapon::ScriptOnStopFiring",GetISystem(),PROFILE_GAME );
|
|
//was firing and now stoppped
|
|
//sending an event for stooping various effects
|
|
wi.fireFirstBulletTime=0;
|
|
pSelectedWeapon->ScriptOnStopFiring(m_pEntity);
|
|
|
|
if(m_pMountedWeapon) // stop fire animation on mounted weapon
|
|
m_pMountedWeapon->SendScriptEvent(ScriptEvent_Fire,0);
|
|
else if( m_pVehicle ) // stop fire animation on weapon on wehicle
|
|
m_pVehicle->WeaponState( m_pEntity->GetId(), false );
|
|
}
|
|
}
|
|
}
|
|
|
|
// returns ACTUAL plaerys direction angle - the one it's shooting/looking at
|
|
Vec3d CPlayer::GetActualAngles()
|
|
{
|
|
Vec3d angles;
|
|
|
|
if( m_pGame->p_EyeFire->GetIVal()==0)
|
|
{
|
|
if(m_aimLook)
|
|
{
|
|
Vec3d pos;
|
|
GetFirePosAngles( pos, angles );
|
|
}
|
|
else
|
|
angles = m_pEntity->GetAngles();
|
|
}
|
|
else
|
|
angles = m_pEntity->GetAngles();
|
|
|
|
angles.x = Snap_s180(angles.x);
|
|
angles.y = Snap_s180(angles.y);
|
|
angles.z = Snap_s180(angles.z);
|
|
return angles;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Updates procedural animation of character
|
|
*/
|
|
void CPlayer::UpdateBonesRotation( )
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
//m_pGame->m_pLog->LogToConsole("\003 %.2f %.2f ",m_LegAngle,m_LegDeltaAngle);
|
|
|
|
//also when on ladder we have to rotate some bones (head)
|
|
if (m_LegRotation || m_stats.onLadder)
|
|
{
|
|
// apply lean angles to player character
|
|
ICryCharInstance *pChar = m_pEntity->GetCharInterface()->GetCharacter(0);
|
|
Vec3d angles = GetActualAngles();
|
|
|
|
if (pChar)
|
|
{
|
|
CryQuat qtH;
|
|
CryQuat qtV;
|
|
CryQuat qtR;
|
|
CryQuat qtTotal;
|
|
CryQuat qtParent;
|
|
CryQuat qtParentCnj;
|
|
float xAngle = -angles.x;
|
|
// float xAngle = Snap180(-angles.x);
|
|
/*
|
|
if( xAngle>180 )
|
|
xAngle = xAngle - 360.0f;
|
|
else if( xAngle<-180 )
|
|
xAngle = 360.0f+xAngle;
|
|
*/
|
|
// float leanBodyAngle = -(180.0f - (180 - m_walkParams.fCurrLean*m_pGame->p_lean->GetFVal()*2.0f));
|
|
float leanBodyAngle = -(180.0f - (180 - m_walkParams.fCurrLean*m_LeanDegree*2.0f));
|
|
// leanBodyAngle = 0;
|
|
leanBodyAngle *= 2.0f;
|
|
// leanBodyAngle *= 5.0f;
|
|
|
|
// float zAngle = m_LegDeltaAngle + m_LegMovingAngle;
|
|
float zAngle = m_LegDeltaAngle;
|
|
|
|
/*
|
|
if(m_pBoneSpine1)
|
|
qtParent = m_pBoneSpine1->GetParentWQuat();
|
|
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
|
|
|
|
qtH.SetRotationAA( DEG2RAD(m_LegDeltaAngle), Vec3(0.0f, 0.0f, 1.0f) );
|
|
//qtH.SetRotationAA( DEG2RAD(45), Vec3(0.0f, 0.0f, 1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(xAngle), Vec3(1.0f, 0.0f, 0.0f) );
|
|
qtR.SetRotationAA( DEG2RAD(leanBodyAngle), Vec3(0.0f, 1.0f, 0.0f) );
|
|
qtTotal = qtR*qtV*qtH;
|
|
|
|
qtTotal = qtParent*qtR*qtV*qtH*qtParentCnj;
|
|
|
|
|
|
if(m_pBoneSpine1)
|
|
m_pBoneSpine1->SetPlusRotation( qtTotal );
|
|
return;
|
|
//*/
|
|
|
|
//on ladder we rotate just the head bone to follow the player view.
|
|
if (m_stats.onLadder)
|
|
{
|
|
if(m_pBoneNeck)
|
|
m_pBoneNeck->ResetPlusRotation();
|
|
if(m_pBoneSpine1)
|
|
m_pBoneSpine1->ResetPlusRotation();
|
|
if(m_pBoneSpine2)
|
|
m_pBoneSpine2->ResetPlusRotation();
|
|
|
|
if (m_stats.onLadder)
|
|
{
|
|
zAngle = Snap_s180(m_vLadderAngles.z - m_pEntity->GetAngles().z);
|
|
//m_pGame->GetSystem()->GetILog()->Log("head:%.1f,body:%.1f",zAngle,m_vLadderAngles.z);
|
|
}
|
|
|
|
//limit the head angle in a 120 degree range.
|
|
if (zAngle > 60.0f)
|
|
zAngle = 60.0f;
|
|
|
|
if (zAngle < -60.0f)
|
|
zAngle = -60.0f;
|
|
|
|
//smooth the head rotation.
|
|
Ang3 delta = Ang3(xAngle*0.5f,0,zAngle) - m_vHeadAngles;
|
|
m_vHeadAngles = m_vHeadAngles + delta*min(1.0f,m_pTimer->GetFrameTime()*10.0f);
|
|
|
|
m_vHeadAngles.Snap180();
|
|
|
|
//apply rotation
|
|
qtH.SetRotationAA( DEG2RAD(m_vHeadAngles.z), Vec3(0.0f, 0.0f, 1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(m_vHeadAngles.x), Vec3(1.0f, 0.0f, 0.0f) );
|
|
|
|
qtParent = m_pBoneHead->GetParentWQuat();
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
qtTotal = qtParent*qtV*qtH*qtParentCnj;
|
|
|
|
m_pBoneHead->SetPlusRotation( qtTotal );
|
|
}
|
|
else if(m_CurStance == eProne)
|
|
{
|
|
m_LegADeltaLimit = 0;
|
|
if(m_pBoneHead)
|
|
m_pBoneHead->SetPlusRotation(0,0,angles.x);
|
|
if(m_pBoneNeck)
|
|
m_pBoneNeck->ResetPlusRotation();
|
|
if(m_pBoneSpine1)
|
|
m_pBoneSpine1->ResetPlusRotation();
|
|
if(m_pBoneSpine2)
|
|
m_pBoneSpine2->ResetPlusRotation();
|
|
}
|
|
// else if(m_aimLook) //aiming
|
|
else if(m_CurStance == eCrouch || m_CurStance == eStealth || m_CurStance == eStand)
|
|
{
|
|
//force weapon (shoulders) be same direction as ent direstion
|
|
//m_LegADeltaLimit = 60;
|
|
m_LegADeltaLimit = m_pGame->pa_leg_limitaim->GetFVal();// 60;
|
|
if(m_pBoneHead)
|
|
m_pBoneHead->ResetPlusRotation();
|
|
if(m_pBoneNeck)
|
|
m_pBoneNeck->ResetPlusRotation();
|
|
|
|
float amountSpine = m_pGame->pa_spine->GetFVal();
|
|
float amountSpine1 = m_pGame->pa_spine1->GetFVal();
|
|
float amountSpine2;
|
|
|
|
amountSpine2 = 1.0f - (amountSpine1 + amountSpine);
|
|
|
|
if(m_pBoneSpine)
|
|
{
|
|
qtH.SetRotationAA( DEG2RAD(zAngle*amountSpine), Vec3(0.0f,0.0f,1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(xAngle*.2f), Vec3(1.0f,0.0f,0.0f) );
|
|
qtR.SetRotationAA( DEG2RAD(leanBodyAngle*.2f), Vec3(0.0f,1.0f,0.0f) );
|
|
// qtTotal = qtR*qtV*qtH;
|
|
qtParent = m_pBoneSpine->GetParentWQuat();
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
qtTotal = qtParent*qtR*qtV*qtH*qtParentCnj;
|
|
m_pBoneSpine->SetPlusRotation( qtTotal );
|
|
}
|
|
if(m_pBoneSpine1)
|
|
{
|
|
qtH.SetRotationAA( DEG2RAD(zAngle*amountSpine1), Vec3(0.0f,0.0f,1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(xAngle*.4f), Vec3(1.0f,0.0f,0.0f) );
|
|
qtR.SetRotationAA( DEG2RAD(leanBodyAngle*.4f), Vec3(0.0f,1.0f,0.0f) );
|
|
// qtTotal = qtR*qtV*qtH;
|
|
qtParent = m_pBoneSpine1->GetParentWQuat();
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
qtTotal = qtParent*qtR*qtV*qtH*qtParentCnj;
|
|
m_pBoneSpine1->SetPlusRotation( qtTotal );
|
|
}
|
|
if(m_pBoneSpine2)
|
|
{
|
|
qtH.SetRotationAA( DEG2RAD(zAngle*amountSpine2), Vec3(0.0f,0.0f,1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(xAngle*.4f), Vec3(1.0f,0.0f,0.0f) );
|
|
qtR.SetRotationAA( DEG2RAD(leanBodyAngle*.4f), Vec3(0.0f,1.0f,0.0f) );
|
|
// qtTotal = qtR*qtV*qtH;
|
|
qtParent = m_pBoneSpine2->GetParentWQuat();
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
qtTotal = qtParent*qtR*qtV*qtH*qtParentCnj;
|
|
m_pBoneSpine2->SetPlusRotation( qtTotal );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//m_LegADeltaLimit = 110;
|
|
m_LegADeltaLimit = m_pGame->pa_leg_limitidle->GetFVal();
|
|
if(m_pBoneHead)
|
|
{
|
|
qtH.SetRotationAA( DEG2RAD(zAngle*.3f), Vec3(0.0f, 0.0f, 1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(xAngle*.5f), Vec3(1.0f, 0.0f, 0.0f) );
|
|
// qtTotal = qtV*qtH;
|
|
qtParent = m_pBoneHead->GetParentWQuat();
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
qtTotal = qtParent*qtV*qtH*qtParentCnj;
|
|
m_pBoneHead->SetPlusRotation( qtTotal );
|
|
}
|
|
if(m_pBoneNeck)
|
|
{
|
|
qtH.SetRotationAA( DEG2RAD(zAngle*.3f), Vec3(0.0f, 0.0f, 1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(xAngle*.2f), Vec3(1.0f, 0.0f, 0.0f) );
|
|
// qtTotal = qtV*qtH;
|
|
qtParent = m_pBoneNeck->GetParentWQuat();
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
qtTotal = qtParent*qtV*qtH*qtParentCnj;
|
|
m_pBoneNeck->SetPlusRotation( qtTotal );
|
|
}
|
|
if(m_pBoneSpine)
|
|
{
|
|
qtH.SetRotationAA( DEG2RAD(zAngle*.1f), Vec3(0.0f, 0.0f, 1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(xAngle*.1f), Vec3(1.0f, 0.0f, 0.0f) );
|
|
qtR.SetRotationAA( DEG2RAD(leanBodyAngle*.1f), Vec3(0.0f, 1.0f, 0.0f) );
|
|
// qtTotal = qtR*qtV*qtH;
|
|
qtParent = m_pBoneSpine->GetParentWQuat();
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
qtTotal = qtParent*qtR*qtV*qtH*qtParentCnj;
|
|
m_pBoneSpine->SetPlusRotation( qtTotal );
|
|
}
|
|
if(m_pBoneSpine1)
|
|
{
|
|
qtH.SetRotationAA( DEG2RAD(zAngle*.1f), Vec3(0.0f, 0.0f, 1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(xAngle*.1f), Vec3(1.0f, 0.0f, 0.0f) );
|
|
qtR.SetRotationAA( DEG2RAD(leanBodyAngle*.5f), Vec3(0.0f, 1.0f, 0.0f) );
|
|
// qtTotal = qtR*qtV*qtH;
|
|
qtParent = m_pBoneSpine1->GetParentWQuat();
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
qtTotal = qtParent*qtR*qtV*qtH*qtParentCnj;
|
|
m_pBoneSpine1->SetPlusRotation( qtTotal );
|
|
}
|
|
if(m_pBoneSpine2)
|
|
{
|
|
qtH.SetRotationAA( DEG2RAD(zAngle*.2f), Vec3(0.0f, 0.0f, 1.0f) );
|
|
qtV.SetRotationAA( DEG2RAD(xAngle*.1f), Vec3(1.0f, 0.0f, 0.0f) );
|
|
qtR.SetRotationAA( DEG2RAD(leanBodyAngle*.4f), Vec3(0.0f, 1.0f, 0.0f) );
|
|
// qtTotal = qtR*qtV*qtH;
|
|
qtParent = m_pBoneSpine2->GetParentWQuat();
|
|
qtParentCnj = qtParent;
|
|
qtParentCnj.w = -qtParentCnj.w;
|
|
qtTotal = qtParent*qtR*qtV*qtH*qtParentCnj;
|
|
m_pBoneSpine2->SetPlusRotation( qtTotal );
|
|
}
|
|
//m_pBoneSpine1->SetPlusRotation(-m_LegDeltaAngle*.10f, -leanBodyAngle*.5f,
|
|
// -xAngle*.1f);//GetAngleDifference360(0, -angles.x)*.5f);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ResetRotateHead();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
///////////////////////////////////////////////
|
|
/*!
|
|
*/
|
|
void CPlayer::ResetRotateHead()
|
|
{
|
|
if(m_pBoneHead)
|
|
m_pBoneHead->ResetPlusRotation();
|
|
if(m_pBoneNeck)
|
|
m_pBoneNeck->ResetPlusRotation();
|
|
if(m_pBoneSpine)
|
|
m_pBoneSpine->ResetPlusRotation();
|
|
if(m_pBoneSpine1)
|
|
m_pBoneSpine1->ResetPlusRotation();
|
|
if(m_pBoneSpine2)
|
|
m_pBoneSpine2->ResetPlusRotation();
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
///////////////////////////////////////////////
|
|
/*!
|
|
*/
|
|
void CPlayer::UpdateFireAnimations()
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
//fixme - when dead - needs different update
|
|
if(!IsAlive())
|
|
return;
|
|
|
|
if( m_pGame->pa_blend1->GetFVal()<0.0f )
|
|
return;
|
|
|
|
// stop fire animation when
|
|
// in relaxed stance
|
|
// swimming
|
|
// on ladder
|
|
if(!m_AnimationSystemEnabled || m_CurStance == eRelaxed || m_bSwimming || m_stats.onLadder)
|
|
{
|
|
// m_pEntity->GetCurrentAnimation(0, 1)
|
|
m_sPrevAniNameLayer1.clear();
|
|
m_pEntity->StartAnimation(0, NULL, 1, .15f);
|
|
return;
|
|
}
|
|
|
|
|
|
const char *weaponShoot = "_utshoot"; // two hands animations
|
|
const char *weaponAim = "_utaim";
|
|
char aniName[64];
|
|
if (!GenerateAnimationName( aniName ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
char aniName0[64]; // store the base layer0 animation name
|
|
memcpy( aniName0, aniName, strlen(aniName) );
|
|
|
|
|
|
// fixme - has to be changed for multyplayer
|
|
//m_stats.weapon_busy<=0
|
|
//check for melee attack/reloading/whatever
|
|
|
|
CWeaponClass *pSelectedWeapon = GetSelectedWeapon();
|
|
|
|
if(m_JumpStage==1)
|
|
{
|
|
m_pEntity->StartAnimation(0, NULL, 1, .15f);
|
|
//m_pEntity->StartAnimation(0, "aidle", 1, .15f);
|
|
m_sPrevAniNameLayer1 = "";
|
|
return;
|
|
}
|
|
if(m_JumpStage!=0)
|
|
return;
|
|
|
|
if(!pSelectedWeapon ) // no weapon in hands - use machete animations
|
|
{
|
|
weaponShoot = "_umshoot";
|
|
weaponAim = "_umaim";
|
|
}
|
|
else if(pSelectedWeapon->m_HoldingType == 2) // pistol animations
|
|
{
|
|
weaponShoot = "_upshoot";
|
|
weaponAim = "_upaim";
|
|
}
|
|
else if(pSelectedWeapon->m_HoldingType == 3) // machete animations
|
|
{
|
|
weaponShoot = "_umshoot";
|
|
weaponAim = "_umaim";
|
|
}
|
|
else if(pSelectedWeapon->m_HoldingType == 4) // building tool animations
|
|
{
|
|
weaponShoot = "_ubshoot";
|
|
weaponAim = "_ubaim";
|
|
}
|
|
else if(pSelectedWeapon->m_HoldingType == 5) // scouttool/healthpack animations
|
|
{
|
|
weaponShoot = "_usshoot";
|
|
weaponAim = "_usaim";
|
|
}
|
|
|
|
if ( m_stats.firing_grenade)
|
|
m_bGrenadeAnimation = true;
|
|
|
|
|
|
if ( m_bGrenadeAnimation )
|
|
{
|
|
if(m_stats.weapon_busy<=0)
|
|
m_bGrenadeAnimation = false;
|
|
else
|
|
{
|
|
const char *grenadeAim = "grenade_mp";
|
|
if(m_sPrevAniNameLayer1 != grenadeAim)
|
|
if(m_pEntity->StartAnimation(0, grenadeAim, 1, .2f, true)) //.2f
|
|
m_sPrevAniNameLayer1 = grenadeAim;
|
|
}
|
|
}
|
|
else
|
|
if( m_aimLook && m_stats.canfire )
|
|
{
|
|
|
|
m_fShootAniLength -= m_pTimer->GetFrameTime();
|
|
|
|
if(m_bWeaponJustFired) // do fire animation
|
|
{
|
|
m_bWeaponJustFired = false;
|
|
strcat( aniName,weaponShoot );
|
|
m_fShootAniLength = m_pEntity->GetAnimationLength( aniName );
|
|
}
|
|
else if( m_fShootAniLength<=0 ) // fire animation over - do aim animation
|
|
{
|
|
strcat( aniName,weaponAim );
|
|
}
|
|
else
|
|
{
|
|
// still playing fire animation
|
|
strcat( aniName,weaponShoot );
|
|
//return;
|
|
}
|
|
|
|
if(m_sPrevAniNameLayer1 == aniName)
|
|
return;
|
|
|
|
// float blendTime = m_pGame->pa_blend1->GetFVal();
|
|
// GetBlendTime( aniName, blendTime );
|
|
|
|
// blend time has to be the same as for base animation in layer 0
|
|
// float blendTime = m_pGame->pa_blend1->GetFVal();
|
|
// GetBlendTime( aniName0, blendTime );
|
|
|
|
float blendTime = m_pGame->pa_blend0->GetFVal();
|
|
|
|
// if animation is shorter than blend time - it blands to base animation ( which is bad )
|
|
float aniLenght = m_pEntity->GetAnimationLength(aniName);
|
|
if( blendTime>aniLenght )
|
|
blendTime = aniLenght; //0;
|
|
|
|
|
|
if(m_pEntity->StartAnimation(0, aniName, 1, blendTime, true)) //.2f
|
|
m_sPrevAniNameLayer1 = aniName;
|
|
}
|
|
else // not shooting/aiming - weapon down animation
|
|
{
|
|
if(pSelectedWeapon && pSelectedWeapon->m_HoldingType == 2) // pistol animations
|
|
{
|
|
strcat( aniName,"_upidle" );
|
|
// PETAR no animations for all stances - temporary HACK
|
|
strcpy(aniName,"aidle_upidle");
|
|
//--------------------
|
|
if(m_sPrevAniNameLayer1 == aniName)
|
|
return;
|
|
// float blendTime = m_pGame->pa_blend1->GetFVal();
|
|
// GetBlendTime( aniName, blendTime );
|
|
|
|
// blend time has to be the same as for base animation in layer 0
|
|
float blendTime = m_pGame->pa_blend0->GetFVal();
|
|
GetBlendTime( aniName0, blendTime );
|
|
|
|
// if animation is shorter than blend time - it blands to base animation ( which is bad )
|
|
float aniLenght = m_pEntity->GetAnimationLength(aniName);
|
|
if( blendTime>aniLenght )
|
|
blendTime = aniLenght; //0;
|
|
// try to start pistol idle for current stance/movement
|
|
if(m_pEntity->StartAnimation(0, aniName, 1, blendTime, true))
|
|
{
|
|
m_sPrevAniNameLayer1 = aniName;
|
|
return;
|
|
}
|
|
strcpy( aniName,"aidle_upidle" );
|
|
if(m_sPrevAniNameLayer1 == aniName)
|
|
return;
|
|
// if animation is shorter than blend time - it blands to base animation ( which is bad )
|
|
aniLenght = m_pEntity->GetAnimationLength(aniName);
|
|
if( blendTime>aniLenght )
|
|
blendTime = aniLenght; //0;
|
|
|
|
// use aim aidle stance
|
|
if(m_pEntity->StartAnimation(0, aniName, 1, blendTime, true))
|
|
{
|
|
m_sPrevAniNameLayer1 = aniName;
|
|
return;
|
|
}
|
|
}
|
|
if(m_sPrevAniNameLayer1.empty())
|
|
return;
|
|
m_pEntity->StartAnimation(0, NULL, 1, .15f);
|
|
m_sPrevAniNameLayer1 = "";
|
|
m_fShootAniLength = 0.0f;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
///////////////////////////////////////////////
|
|
/*!
|
|
*/
|
|
void CPlayer::UpdateJumpAnimations()
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
if( m_pGame->pa_blend2->GetFVal()<0.0f )
|
|
return;
|
|
if(!m_AnimationSystemEnabled)
|
|
return;
|
|
|
|
const char *aniName;
|
|
|
|
// if(m_FlyTime<.15f && !m_stats.landing)
|
|
if( m_FlyTime<.35f )
|
|
{
|
|
if( m_sPrevAniNameLayer2 == "jump_air" )
|
|
{
|
|
m_pEntity->StartAnimation(0, NULL, 2, .1f);
|
|
m_sPrevAniNameLayer2.clear();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if( m_stats.flying )
|
|
aniName = "jump_air";
|
|
if(m_stats.landing)
|
|
aniName = "jump_land";
|
|
|
|
if(m_pEntity->GetCurrentAnimation(0, 2)<0)
|
|
m_sPrevAniNameLayer2.clear();
|
|
if (strlen(aniName) == 0 || m_sPrevAniNameLayer2 == aniName )
|
|
return;
|
|
|
|
float blendTime = m_pGame->pa_blend2->GetFVal();
|
|
GetBlendTime( aniName, blendTime );
|
|
if(m_pEntity->StartAnimation(0, aniName, 2, blendTime))
|
|
m_sPrevAniNameLayer2 = aniName;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
///////////////////////////////////////////////
|
|
/*! Updates walking-flags for the player so the correct animation can be played back
|
|
|
|
*/
|
|
void CPlayer::UpdateCharacterAnimations( SPlayerUpdateContext &ctx )
|
|
{
|
|
if(!IsAlive()) // if dead - deadBodyPhysics takes over
|
|
return;
|
|
|
|
if(m_pMountedWeapon)
|
|
{
|
|
UpdateCharacterAnimationsMounted( ctx );
|
|
return;
|
|
}
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
//float MIN_WALK_SPEED = m_WalkSpeed*.15f;
|
|
// float LEFT_RIGHT_COS = .8f;
|
|
// float LEFT_RIGHT_COS_TRH = 0.91f;
|
|
float MIN_CROUCH_SPEED = m_CrouchSpeed*.17f;
|
|
float MIN_PRONE_SPEED = m_ProneSpeed*.17f;
|
|
|
|
//bool moving = false;
|
|
bool flying = false;
|
|
//bool running = false;
|
|
bool forward = false;
|
|
|
|
// New variables for script based version
|
|
int nStanding = 0; // 0 = Standing( combat ), 1 = Crouching, 2 = Prone, 3 = Stealth, 4 = Standing( relaxed )
|
|
int nStrafe = 0;
|
|
int nForward = 0;
|
|
int nMode = 0; // 0 = Idle, 1 = Walking, 2 = Running, 3 = Jump, 4 = Flying, 6 = Turning, 7 = sprinting
|
|
|
|
// Create a new status object. The fields are initialized for us
|
|
pe_status_living &status = ctx.status;
|
|
|
|
// Get a pointer to the physics engine
|
|
IPhysicalEntity *physEnt = m_pEntity->GetPhysics();
|
|
PhysicsVars *physvars = m_pGame->GetSystem()->GetIPhysicalWorld()->GetPhysVars();
|
|
|
|
m_stats.landing = false;
|
|
|
|
// If the physics says the player is flying, set the flag
|
|
if (status.bFlying)
|
|
{
|
|
flying = true;
|
|
m_FlyTime += m_pTimer->GetFrameTime();
|
|
m_LandTime = 0;
|
|
|
|
// Calculate our current Vertical speed - to use for falling damage
|
|
Vec3 vel = status.vel;
|
|
if (status.pGroundCollider)
|
|
vel -= status.velGround;
|
|
m_walkParams.vertSpeedFalling = vel.z;
|
|
}
|
|
else
|
|
{
|
|
// If we were flying previously, but have stopped, set the flag
|
|
if (m_stats.flying)
|
|
{
|
|
if(m_FlyTime>.5f) // if more than .5 sec in air - play land animation
|
|
m_stats.landing = true;
|
|
|
|
// m_pEntity->SendScriptEvent(ScriptEvent_AnimationKey,1);
|
|
|
|
if(m_Dynamics.gravity!=0.0f) // in 0 gravity landing is not possible
|
|
if(m_walkParams.vertSpeedFalling<0.0f ) // falling down
|
|
m_pEntity->SendScriptEvent(ScriptEvent_Land, (int)(-m_walkParams.vertSpeedFalling*100));
|
|
}
|
|
m_FlyTime = 0;
|
|
m_LandTime += m_pTimer->GetFrameTime();
|
|
}
|
|
|
|
// Store the current flying and landing states
|
|
m_stats.flying = flying;
|
|
|
|
// [Anton] a piece of code moved to UpdatePhysics
|
|
|
|
// here goes stance determination -stuff
|
|
// Check if the player is stealth
|
|
if (m_CurStance == eStealth)
|
|
{
|
|
nStanding = 3;
|
|
|
|
|
|
// Check if the player is moving
|
|
// This is true if the player is running, moving left, moving right, or moving at all
|
|
if (m_stats.fVel > MIN_CROUCH_SPEED)
|
|
{
|
|
if (m_stats.running)
|
|
nMode = 2;
|
|
else
|
|
nMode = 1;
|
|
}
|
|
|
|
|
|
}
|
|
// Check if the player is crouching
|
|
else if (m_CurStance == eCrouch)
|
|
{
|
|
nStanding = 1;
|
|
|
|
// Check if the player is moving
|
|
// This is true if the player is running, moving left, moving right, or moving at all
|
|
if (m_stats.fVel > MIN_CROUCH_SPEED)
|
|
{
|
|
// Crouching movement.
|
|
nMode = 1;
|
|
}
|
|
}
|
|
else if(m_CurStance == eProne)
|
|
{
|
|
if (m_stats.fVel > MIN_PRONE_SPEED)
|
|
nMode = 1;
|
|
|
|
nStanding = 2;
|
|
}
|
|
else // must be standing
|
|
{
|
|
if (m_CurStance == eRelaxed) //Standing( relaxed ), otherwise - standing combat
|
|
nStanding = 4;
|
|
|
|
|
|
// Check if the player is moving
|
|
// This is true if the player is running, moving left, moving right, or moving at all
|
|
if (m_stats.moving)
|
|
{
|
|
// Check if the player is running
|
|
if (m_stats.running)
|
|
{
|
|
nMode = 2;
|
|
if( m_Sprinting )
|
|
nMode = 7;
|
|
}
|
|
else
|
|
{
|
|
// Walking
|
|
nMode = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nMode = 0;
|
|
}
|
|
}
|
|
// stance stuff over
|
|
// here goes movement direction/type determination -stuff
|
|
if(m_stats.moving)
|
|
{
|
|
Ang3 playerLookAngles = GetActualAngles();
|
|
Ang3 playerMoveAngles = (Ang3)status.vel;
|
|
playerMoveAngles.normalize();
|
|
playerMoveAngles=ConvertUnitVectorToCameraAngles(playerMoveAngles);
|
|
playerMoveAngles.Snap180();
|
|
|
|
// float moveDeltaAngle = playerLookAngles.DifferenceZ( playerMoveAngles );
|
|
float moveDeltaAngle = Snap_s180(playerLookAngles.z-playerMoveAngles.z);
|
|
|
|
if(m_bSwimming)
|
|
{
|
|
// if( moveDeltaAngle<120 && moveDeltaAngle>-80 )
|
|
if( Ffabs(moveDeltaAngle)<120 )
|
|
{
|
|
// forward
|
|
nForward = 1;
|
|
forward = true;
|
|
|
|
m_LegAngleDesired = Snap_s180(playerMoveAngles.z);
|
|
m_LegAngleVel = m_LegAngleVelMoving;
|
|
}
|
|
else
|
|
{
|
|
// backwards
|
|
m_LegAngleDesired = Snap_s180(playerMoveAngles.z-180);
|
|
m_LegAngleVel = m_LegAngleVelMoving;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if( moveDeltaAngle<120 && moveDeltaAngle>-80 )
|
|
// if( Ffabs(moveDeltaAngle)<120 )
|
|
{
|
|
// forward
|
|
nForward = 1;
|
|
forward = true;
|
|
|
|
m_LegAngleDesired = Snap_s180(playerMoveAngles.z);
|
|
m_LegAngleVel = m_LegAngleVelMoving;
|
|
}
|
|
else
|
|
{
|
|
// backwards
|
|
m_LegAngleDesired = Snap_s180(playerMoveAngles.z-180);
|
|
m_LegAngleVel = m_LegAngleVelMoving;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_stats.moving) // if was moving - just stopped stop rotating legs in movement direction
|
|
m_LegAngleDesired = m_LegAngle;
|
|
}
|
|
|
|
// [Anton] a piece of code moved to UpdatePhysics
|
|
|
|
if(nMode==0) // do rotation if needed
|
|
{
|
|
float aDir = Snap_s180(m_LegAngle - m_LegAngleDesired);
|
|
if( Ffabs(aDir)>.2 )
|
|
{
|
|
nMode = 6;
|
|
if( aDir<0 )
|
|
nStrafe = 1; // rotate left
|
|
else
|
|
nStrafe = 2; // rotate right
|
|
}
|
|
}
|
|
|
|
//if(speed>0.0f)
|
|
//m_pGame->m_pLog->LogToConsole("\001 %.2f %.2f ",speed, m_WalkSpeed);
|
|
|
|
|
|
m_nStanding = nStanding;
|
|
m_nMode = nMode;
|
|
m_nStrafe = nStrafe;
|
|
m_nForward = nForward;
|
|
|
|
Vec3 vel = status.vel;
|
|
if (status.pGroundCollider)
|
|
vel -= status.velGround;
|
|
float speed2d = Vec2(vel).len();
|
|
|
|
if(m_AnimationSystemEnabled ) // if enabled
|
|
{
|
|
if( m_stats.moving )
|
|
{
|
|
ScaleAnimationSpeed( speed2d );
|
|
}
|
|
else
|
|
{
|
|
m_pEntity->SetAnimationSpeed( 1.0f );
|
|
}
|
|
StartAnimation( ctx );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::ScaleAnimationSpeed( const float speed2d )
|
|
{
|
|
float curAniRefSpeed = -1;
|
|
|
|
//if is jumping/flying use a normal anim speed
|
|
if (m_stats.flying || m_JumpAniLenght>0)
|
|
{
|
|
curAniRefSpeed = -1;
|
|
}
|
|
else if(m_stats.bIsLimping )
|
|
{
|
|
curAniRefSpeed = -1;
|
|
}
|
|
else if(m_nMode==7) // run sprint - don't scale it now
|
|
{
|
|
curAniRefSpeed = -1;
|
|
}
|
|
else if(m_nMode==3) // jump
|
|
{
|
|
curAniRefSpeed = -1;
|
|
}
|
|
else if(m_nMode==2) // run
|
|
{
|
|
if( m_nStanding==3 ) // stealth
|
|
{
|
|
if( m_nForward )
|
|
curAniRefSpeed = m_AniSpeedXRun[0];
|
|
else
|
|
curAniRefSpeed = m_AniSpeedXRun[2];
|
|
}
|
|
else
|
|
{
|
|
if( m_nForward )
|
|
curAniRefSpeed = m_AniSpeedRun[0];
|
|
else
|
|
curAniRefSpeed = m_AniSpeedRun[2];
|
|
}
|
|
}
|
|
else if( m_nStanding==0 ) // walking
|
|
{
|
|
if( m_CurStance == eRelaxed )
|
|
{
|
|
if( m_nForward )
|
|
curAniRefSpeed = m_AniSpeedWalkRelaxed[0];
|
|
else
|
|
curAniRefSpeed = m_AniSpeedWalkRelaxed[2];
|
|
}
|
|
else
|
|
{
|
|
if( m_nForward )
|
|
curAniRefSpeed = m_AniSpeedWalk[0];
|
|
else
|
|
curAniRefSpeed = m_AniSpeedWalk[2];
|
|
}
|
|
}
|
|
else if( m_nStanding==3 ) // stealth
|
|
{
|
|
if( m_nForward )
|
|
curAniRefSpeed = m_AniSpeedXWalk[0];
|
|
else
|
|
curAniRefSpeed = m_AniSpeedXWalk[2];
|
|
}
|
|
else if( m_nStanding==1 ) //crouch
|
|
{
|
|
if( m_nForward )
|
|
curAniRefSpeed = m_AniSpeedCrouch[0];
|
|
else
|
|
curAniRefSpeed = m_AniSpeedCrouch[2];
|
|
}
|
|
else if( m_nStanding==4 ) // walking relaxed
|
|
{
|
|
if( m_nForward )
|
|
curAniRefSpeed = m_AniSpeedWalkRelaxed[0];
|
|
else
|
|
curAniRefSpeed = m_AniSpeedWalkRelaxed[2];
|
|
}
|
|
|
|
|
|
if(curAniRefSpeed>0.0f)
|
|
m_pEntity->SetAnimationSpeed( speed2d/curAniRefSpeed );
|
|
else
|
|
m_pEntity->SetAnimationSpeed( 1.0f );
|
|
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CPlayer::StartAnimation( const SPlayerUpdateContext &ctx )
|
|
{
|
|
if( m_pGame->pa_blend0->GetFVal()<0.0f )
|
|
return;
|
|
|
|
if (!IsAlive())
|
|
return;
|
|
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
char aniName[32];
|
|
if( m_stats.onLadder)
|
|
{
|
|
strcpy( aniName,"ladder_loop" );
|
|
m_JumpStage=0;
|
|
m_JumpAniLenght=0;
|
|
|
|
//play ladder animation at a speed between 0.001 and 1, depending on the palyer velocity.
|
|
//we cant use a speed = 0 because it would be impossible to rotate the head bone, fix this in the anim sys?
|
|
float aspeed = max(0.001f,min(1.0f,fabs(ctx.status.vel.z)));
|
|
m_pEntity->SetAnimationSpeed( aspeed );
|
|
|
|
/*if( fabs(ctx.status.vel.z) > .1f )
|
|
m_pEntity->SetAnimationSpeed( 1.0f );
|
|
else
|
|
m_pEntity->SetAnimationSpeed( 0.0f );*/
|
|
}
|
|
else if(m_bSwimming)
|
|
// m_stats.fInWater>1.0f)
|
|
{
|
|
// the idle animation should depend on current depth
|
|
float depth = m_p3DEngine->GetWaterLevel(m_pEntity) - m_p3DEngine->GetTerrainElevation(m_pEntity->GetPos().x, m_pEntity->GetPos().y);
|
|
|
|
ray_hit hit;
|
|
Vec3 pos = m_pEntity->GetPos();
|
|
pos.z = m_p3DEngine->GetWaterLevel(m_pEntity);
|
|
if (m_pGame->GetSystem()->GetIPhysicalWorld()->RayWorldIntersection( pos, vectorf(0,0,-1.5f), ent_all,
|
|
rwi_stop_at_pierceable,&hit,1, GetEntity()->GetPhysics()))
|
|
depth = hit.dist;
|
|
|
|
if( ctx.status.vel.len2()>.3f || depth<1.5f)
|
|
{
|
|
if(GetSelectedWeapon())
|
|
strcpy( aniName,"swim_weapon" );
|
|
else
|
|
strcpy( aniName,"swim" );
|
|
|
|
}
|
|
else
|
|
{
|
|
if(GetSelectedWeapon())
|
|
strcpy( aniName,"swim_weapon_idle" );
|
|
else
|
|
strcpy( aniName,"swim_idle" );
|
|
}
|
|
m_JumpStage=0;
|
|
m_JumpAniLenght=0;
|
|
m_pEntity->SetAnimationSpeed( 1.0f );
|
|
}
|
|
else
|
|
{
|
|
|
|
GenerateAnimationName( aniName );
|
|
|
|
if (!m_bIsAI)
|
|
{
|
|
|
|
if(m_JumpStage==2 && !m_stats.flying)
|
|
m_JumpStage=0;
|
|
|
|
if(m_JumpAniLenght>0)
|
|
{
|
|
m_JumpAniLenght-=m_pTimer->GetFrameTime();
|
|
|
|
if(m_JumpStage==2)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(m_JumpAniLenght<=0)
|
|
{
|
|
if(m_JumpStage==1)
|
|
{
|
|
m_JumpStage=2;
|
|
}
|
|
}
|
|
else if (m_JumpStage==1 || m_JumpStage==3)
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
if( m_stats.flying )
|
|
{
|
|
if(m_JumpStage==0 || m_JumpStage==1
|
|
|| m_JumpStage==3 ) // if jumping immidiately after prev jump - still in landing state
|
|
{
|
|
//strcat( aniName,"_jump_start" );
|
|
if (m_nForward /*|| m_stats.fVel<0.1f*/)
|
|
strcpy( aniName,"jump_forward" );
|
|
else
|
|
strcpy( aniName,"jump_back" );
|
|
|
|
m_JumpStage=1;
|
|
}
|
|
else//flying? dont play anything but the jump start animation. So return.
|
|
{
|
|
return;
|
|
//strcat( aniName,"_jump_air" );
|
|
}
|
|
}
|
|
|
|
if(m_stats.landing)
|
|
{
|
|
strcat( aniName,"_jump_land" );
|
|
|
|
if (m_JumpStage!=3)
|
|
{
|
|
m_JumpStage=3;
|
|
m_JumpAniLenght = 0;
|
|
}
|
|
}
|
|
}
|
|
// else
|
|
// m_JumpStage=0;
|
|
}
|
|
|
|
if(m_sPrevAniName == aniName)
|
|
return;
|
|
|
|
if(m_stats.landing && !m_bIsAI)
|
|
{
|
|
if(m_JumpAniLenght>0)
|
|
return;
|
|
m_JumpAniLenght = m_pEntity->GetAnimationLength( aniName );
|
|
}
|
|
else if(m_JumpStage==1)
|
|
{
|
|
//we dont care anymore about the length of jumpin animations, because after this we keep the last frame until land.
|
|
m_JumpAniLenght = 0;
|
|
//m_JumpAniLenght = m_pEntity->GetAnimationLength( aniName );
|
|
}
|
|
else if(m_JumpAniLenght>0)
|
|
return; // don't start other anims before jump landing animation is over
|
|
|
|
// float blendTime = m_pGame->pa_blend0->GetFVal();
|
|
// GetBlendTime( aniName, blendTime );
|
|
|
|
float blendTime = m_pGame->pa_blend0->GetFVal();
|
|
|
|
//use a different bleding for the jump start anim
|
|
if (m_JumpStage==1)
|
|
{
|
|
//when jump start reset current animations, so when the jump anim will finish player will keep its the last frame.
|
|
m_pEntity->ResetAnimations(0);
|
|
//blendTime = 0.15f;
|
|
|
|
//set jumpstage directly to 2 (inair)
|
|
m_JumpStage = 2;
|
|
}
|
|
|
|
if(m_JumpStage==3 && m_JumpAniLenght<=0)
|
|
{
|
|
// m_sPrevAniNameLayer1 = "";
|
|
m_JumpStage=0;
|
|
blendTime = 0.15f;
|
|
//blendTime = 0.05f;
|
|
}
|
|
m_pEntity->StartAnimation(0, aniName, 0, blendTime );//.3f);
|
|
m_sPrevAniName = aniName;
|
|
/*
|
|
if(m_pEntity->StartAnimation(0, aniName, 0, blendTime ))//.3f))
|
|
{
|
|
m_sPrevAniName = aniName;
|
|
//m_pGame->m_pLog->LogToConsole("\002 %s ",aniName.c_str());
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
/*
|
|
-- generates string with appropriate animation name, according to naming convention
|
|
-- depending on parametrs
|
|
--
|
|
-- m_nForward: 0 = Backward, 1 = Forward
|
|
-- m_nStrafe: 0 = None, 1 = Left, 2 = Right
|
|
-- m_nStanding: 0 = Standing, 1 = Crouching, 2 = Prone, 3 = Stealth,
|
|
-- m_nMode: 0 = Idle, 1 = Walking, 2 = Running, 3 = Jump, 4 = Flying, 5 = Dead, 6 = Turning,
|
|
*/
|
|
|
|
bool CPlayer::GenerateAnimationName( char *aniName )
|
|
{
|
|
strcpy( aniName,"" );
|
|
|
|
//aniName = "aidle";
|
|
//return;
|
|
|
|
if(m_stats.bIsLimping)
|
|
strcpy( aniName,"l" );
|
|
else
|
|
switch(m_nStanding)
|
|
{
|
|
case 0: // standing combat
|
|
strcpy( aniName,"a" );
|
|
break;
|
|
case 1: // crouching combat
|
|
strcpy( aniName,"c" );
|
|
break;
|
|
case 2: // proning combat
|
|
strcpy( aniName,"p" );
|
|
break;
|
|
case 3: // stealth combat
|
|
strcpy( aniName,"x" );
|
|
break;
|
|
case 4: // standing relaxed
|
|
strcpy( aniName,"s" );
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
switch(m_nMode)
|
|
{
|
|
case 0:
|
|
strcat( aniName,"idle" );
|
|
return true;
|
|
case 1:
|
|
strcat( aniName,"walk" );
|
|
break;
|
|
case 2:
|
|
strcat( aniName,"run" );
|
|
break;
|
|
case 6:
|
|
strcat( aniName,"rotate" );
|
|
break;
|
|
case 7:
|
|
strcat( aniName,"sprint" );
|
|
break;
|
|
default:
|
|
return true;
|
|
}
|
|
|
|
if(m_nStrafe)
|
|
{
|
|
if(m_nStrafe == 1)
|
|
strcat( aniName,"left" );
|
|
else
|
|
strcat( aniName,"right" );
|
|
}
|
|
else if(m_nForward)
|
|
strcat( aniName,"fwd" );
|
|
else
|
|
strcat( aniName,"back" );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Let the player die by playing the animation and disabling physics
|
|
*/
|
|
/*
|
|
void CPlayer::Die()
|
|
{
|
|
m_pEntity->KillTimer();
|
|
// m_deathTime = GetCurrTime();
|
|
|
|
|
|
IEntityCharacter *ichar = m_pEntity->GetCharInterface();
|
|
// UpdateCharacterAnimations();
|
|
|
|
ICryCharInstance *character = ichar->GetCharacter(PLAYER_MODEL_IDX);
|
|
if (character)
|
|
{
|
|
// Hide weapon.
|
|
character->EnableLastIdleAnimationRestart(0,false);
|
|
character->EnableLastIdleAnimationRestart(1,false);
|
|
character->AttachObjectToBone(NULL,NULL);
|
|
|
|
if (m_bIsAI)
|
|
character->ResetAnimations();
|
|
}
|
|
|
|
m_pEntity->EnableAI(false);
|
|
|
|
if (m_pEntity->GetPhysics()->GetType()==PE_ARTICULATED)
|
|
return;
|
|
|
|
// Disable physics on this player.
|
|
m_pEntity->EnablePhysics(false);
|
|
|
|
}
|
|
*/
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Respawns the player by enabling physics and calling the script
|
|
*/
|
|
void CPlayer::Respawn()
|
|
{
|
|
// Exit all areas to turn off water sound.
|
|
//m_pGame->m_XAreaMgr.ExitAllAreas( this );
|
|
|
|
m_walkParams.shakeDegree=0.0f;
|
|
m_walkParams.leanAmount = 0.0f;
|
|
m_walkParams.leanStart = 0.0f;
|
|
m_walkParams.leanEnd = 0.0f;
|
|
m_walkParams.leanFactor = 0.0f;
|
|
|
|
// Call game rules and try to revive this player.
|
|
CXServerRules *rules = m_pGame->GetRules();
|
|
// If no server rules, ignore this function.
|
|
if (rules)
|
|
{
|
|
rules->OnPlayerRespawn( m_pEntity );
|
|
}
|
|
|
|
// m_physicsEnabled = true;
|
|
m_pEntity->EnablePhysics(true);
|
|
m_pEntity->EnableAI(true);
|
|
|
|
|
|
// SetTime2Respawn( -1 );
|
|
|
|
m_bStayCrouch = false;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Retrieves if this player is mine
|
|
@return returns true if it is my player, false otherwise
|
|
*/
|
|
bool CPlayer::IsMyPlayer() const
|
|
{
|
|
if(!m_pGame->m_pClient) return false;
|
|
return (m_pEntity->GetId()==m_pGame->m_pClient->GetPlayerId());
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Retrieves if we are in 1st person view
|
|
@return returns true if we are in 1st person view, false otherwise
|
|
*/
|
|
bool CPlayer::IsFirstPerson() const
|
|
{
|
|
return m_bFirstPerson;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Writes all data which needs to be synchronized to the network-stream
|
|
@param stream stream to write to
|
|
@param cs state of the entity per serverslot
|
|
@return true if the function succeeds, false otherwise
|
|
*/
|
|
bool CPlayer::Write( CStream &stream,EntityCloneState *cs)
|
|
{
|
|
bool bLocalHostEntity=true;
|
|
|
|
if(cs)
|
|
bLocalHostEntity=cs->m_bLocalplayer;
|
|
|
|
WRITE_COOKIE(stream);
|
|
|
|
stream.Write(bLocalHostEntity);
|
|
|
|
if(bLocalHostEntity)
|
|
{
|
|
assert(m_stats.health>=0);
|
|
if(m_stats.health>255)
|
|
{
|
|
GameWarning(" Player health=%d is bigger than 255 (name %s). Change properties", m_stats.health,m_pEntity->GetName());
|
|
m_stats.health = 255;
|
|
}
|
|
// assert(m_stats.health<=255);
|
|
assert(m_stats.armor>=0);
|
|
assert(m_stats.armor<=255);
|
|
if(m_stats.numofgrenades<0)
|
|
{
|
|
GameWarning(" Player numofgrenades=%d is less than 0 (name %s). Change properties", m_stats.numofgrenades,m_pEntity->GetName());
|
|
m_stats.numofgrenades = 0;
|
|
}
|
|
if(m_stats.numofgrenades>255)
|
|
{
|
|
GameWarning(" Player numofgrenades=%d is bigger than 255 (name %s). Change properties", m_stats.numofgrenades,m_pEntity->GetName());
|
|
m_stats.numofgrenades = 255;
|
|
}
|
|
|
|
assert(m_stats.stamina>=0 && m_stats.stamina<255);
|
|
stream.WritePkd( (BYTE)m_stats.stamina );
|
|
// assert(m_stats.breath>=0 && m_stats.breath<255);
|
|
// stream.WritePkd( (BYTE)m_stats.breath );
|
|
|
|
stream.WritePkd( (BYTE)m_stats.health );
|
|
stream.WritePkd( (BYTE)m_stats.armor );
|
|
|
|
if((unsigned int)(m_stats.ammo_in_clip)>1023)
|
|
{
|
|
m_pGame->GetSystem()->GetILog()->LogError("Ammo in clip (%d) is more than 1023, Value will not be restored correctly",m_stats.ammo_in_clip);
|
|
if(m_stats.ammo_in_clip>0)
|
|
m_stats.ammo_in_clip=1023;
|
|
}
|
|
|
|
stream.WriteNumberInBits(m_stats.ammo_in_clip,10);
|
|
|
|
if((unsigned int)(m_stats.ammo)>1023)
|
|
{
|
|
m_pGame->GetSystem()->GetILog()->LogError("Ammo (%d) is more than 1023, Value will not be restored correctly",m_stats.ammo);
|
|
if(m_stats.ammo>0)
|
|
m_stats.ammo=1023;
|
|
}
|
|
|
|
stream.WriteNumberInBits(m_stats.ammo,10);
|
|
stream.WritePkd((BYTE)m_stats.numofgrenades);
|
|
stream.WriteNumberInBits(m_stats.grenadetype, 4);
|
|
stream.Write(m_stats.holding_breath);
|
|
for(int i=0;i<sizeof(m_vWeaponSlots)/sizeof(int);i++)
|
|
{
|
|
stream.Write(m_vWeaponSlots[i]!=0);
|
|
if(m_vWeaponSlots[i]!=0)
|
|
{
|
|
assert(m_vWeaponSlots[i]>=0);
|
|
assert(m_vWeaponSlots[i]<=255);
|
|
|
|
stream.WritePkd((BYTE)m_vWeaponSlots[i]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
stream.Write((bool)(m_stats.ammo_in_clip!=0));
|
|
stream.Write((bool)(m_stats.ammo!=0));
|
|
|
|
stream.Write( m_stats.firing );
|
|
stream.Write(m_walkParams.fCurrLean!=0);
|
|
if(m_walkParams.fCurrLean!=0)
|
|
{
|
|
stream.Write(m_walkParams.fCurrLean>0); //sign
|
|
stream.WritePkd(((BYTE)(fabs(m_walkParams.fCurrLean)/(1.0f/255))));
|
|
}
|
|
|
|
}
|
|
WRITE_COOKIE(stream);
|
|
|
|
bool bSendFireGrenade = m_stats.firing_grenade;
|
|
|
|
if((m_stats.grenadetype != 1 && m_stats.numofgrenades<=0))
|
|
bSendFireGrenade = false;
|
|
|
|
stream.Write(bSendFireGrenade);
|
|
// [kirill]
|
|
// this is needed to be able to keep PrevWeapon when doing quicksave/quickload
|
|
// while on ladder - so when player gets out of ladder after QuickLoad he has
|
|
// correct weapon
|
|
//[filippo]
|
|
//in MP we need to send always the right "m_stats.weapon" value, otherwise the ladders would not works correctly.
|
|
if( m_stats.onLadder && !m_pGame->IsMultiplayer())
|
|
stream.WritePkd((BYTE)m_PrevWeaponID);
|
|
else
|
|
stream.WritePkd((BYTE)m_stats.weapon);
|
|
stream.WritePkd((BYTE)m_stats.firemode);
|
|
// stream.Write( m_stats.onLadder );
|
|
stream.WriteNumberInBits((unsigned int)m_CurStance,3);
|
|
stream.Write( m_stats.jumping );
|
|
|
|
// sync player random seed value to the clients
|
|
{
|
|
bool bSyncToClients=m_SynchedRandomSeed.GetSynchToClientsS();
|
|
stream.Write(bSyncToClients);
|
|
|
|
if(bSyncToClients)
|
|
stream.Write(m_SynchedRandomSeed.GetStartRandomSeedS());
|
|
}
|
|
|
|
|
|
stream.Write( m_stats.reloading );
|
|
|
|
BYTE acc=(BYTE)(m_stats.firing?m_stats.last_accuracy:m_stats.accuracy/(1.f/255.f));
|
|
stream.WritePkd(acc);
|
|
WRITE_COOKIE(stream);
|
|
|
|
if (m_pRedirected && m_pRedirected->GetId()<50000)
|
|
{
|
|
stream.Write(true);
|
|
stream.Write(m_pRedirected->GetId());
|
|
}
|
|
else
|
|
stream.Write(false);
|
|
|
|
stream.Write(m_bFirstPerson);
|
|
|
|
m_bWriteOccured = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Reads all data which needs to be synchronized from the network-stream
|
|
@param stream stream to read from
|
|
@return true if the function succeeds, false otherwise
|
|
*/
|
|
bool CPlayer::Read( CStream &stream )
|
|
{
|
|
unsigned short dirty = 0;
|
|
PlayerStats &stats=m_stats;
|
|
// GetPlayerStats( stats );
|
|
BYTE health,armor,weapon,firemode,staminaBuff;
|
|
//int weaponid = stats.weaponid;
|
|
bool bLocalHostEntity;
|
|
|
|
VERIFY_COOKIE(stream);
|
|
stream.Read(bLocalHostEntity);
|
|
|
|
if(bLocalHostEntity)
|
|
{
|
|
stream.ReadPkd( staminaBuff );
|
|
m_stats.stamina = staminaBuff;
|
|
// stream.ReadPkd( staminaBuff );
|
|
// m_stats.breath = staminaBuff;
|
|
stream.ReadPkd( health );
|
|
stats.health=health;
|
|
stream.ReadPkd( armor );
|
|
stats.armor=armor;
|
|
unsigned int ammo_in_clip;
|
|
stream.ReadNumberInBits(ammo_in_clip,10);
|
|
stats.ammo_in_clip=ammo_in_clip;
|
|
unsigned int ammo;
|
|
stream.ReadNumberInBits(ammo,10);
|
|
stats.ammo=ammo;
|
|
BYTE b;
|
|
stream.ReadPkd(b);
|
|
stats.numofgrenades=b;
|
|
stream.ReadNumberInBits(stats.grenadetype, 4);
|
|
stream.Read(stats.holding_breath);
|
|
|
|
bool isnotzero;
|
|
for(int i=0;i<sizeof(m_vWeaponSlots)/sizeof(int);i++)
|
|
{
|
|
stream.Read(isnotzero);
|
|
if(isnotzero)
|
|
{
|
|
stream.ReadPkd(b);
|
|
m_vWeaponSlots[i]=b;
|
|
}else
|
|
{
|
|
m_vWeaponSlots[i]=0;
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool val;
|
|
stream.Read(val);
|
|
stats.ammo_in_clip = val;
|
|
stream.Read(val);
|
|
stats.ammo = val;
|
|
stream.Read(val);
|
|
stats.firing = val;
|
|
|
|
bool t;
|
|
stream.Read(t);
|
|
if(t)
|
|
{
|
|
bool sign;
|
|
BYTE lean;
|
|
stream.Read(sign);
|
|
stream.ReadPkd(lean);
|
|
m_walkParams.fCurrLean=sign?(lean*(1.0f/255)):-(lean*(1.0f/255));
|
|
}
|
|
else
|
|
{
|
|
m_walkParams.fCurrLean=0;
|
|
}
|
|
}
|
|
VERIFY_COOKIE(stream);
|
|
stream.Read(stats.firing_grenade);
|
|
stream.ReadPkd(weapon);
|
|
if (weapon!=stats.weapon)
|
|
{
|
|
SelectWeapon(weapon, false);
|
|
stats.weapon = weapon;
|
|
stats.firing = false;
|
|
}
|
|
stream.ReadPkd(firemode);
|
|
if(firemode!=stats.firemode)
|
|
{
|
|
stats.firemode=firemode;
|
|
SwitchFiremode(stats.firemode);
|
|
}
|
|
|
|
//stream.Read(stats.firing);
|
|
// stream.Read(stats.onLadder);
|
|
eStance stance;
|
|
stream.ReadNumberInBits(*((unsigned int *)&stance),3);
|
|
|
|
// no stances in vehicle
|
|
if(stance!=m_CurStance && !m_pVehicle)
|
|
{
|
|
switch(stance)
|
|
{
|
|
case eRelaxed:
|
|
GoRelaxed();
|
|
break;
|
|
case eStand:
|
|
GoStand();
|
|
break;
|
|
// case eAimLook:
|
|
// GoAim();
|
|
// break;
|
|
case eStealth:
|
|
GoStealth();
|
|
break;
|
|
case eCrouch:
|
|
GoCrouch();
|
|
break;
|
|
case eProne:
|
|
GoProne();
|
|
break;
|
|
case eSwim:
|
|
GoSwim();
|
|
break;
|
|
default:
|
|
//DEBUG_BREAK;
|
|
::OutputDebugString("INVALID STANCE\n");
|
|
m_CurStance=(eStance)stance;
|
|
break;
|
|
}
|
|
}
|
|
stream.Read(stats.jumping);
|
|
|
|
if(stream.GetStreamVersion()>=PATCH1_SAVEVERSION) // to be backward compatible with old samegames
|
|
{
|
|
bool bSyncToAllClients;
|
|
|
|
stream.Read(bSyncToAllClients);
|
|
|
|
if(bSyncToAllClients)
|
|
{
|
|
uint8 ucStartRandomSeedCS;
|
|
|
|
stream.Read(ucStartRandomSeedCS);
|
|
|
|
m_SynchedRandomSeed.SetStartRandomSeedC(ucStartRandomSeedCS);
|
|
}
|
|
}
|
|
|
|
|
|
//TRIGGER REALOAD ON CLIENT ONLY (think if can be done better)
|
|
bool bReloading;
|
|
stream.Read(bReloading);
|
|
|
|
if(bReloading && (stats.reloading==false) && m_nSelectedWeaponID != -1)
|
|
{
|
|
CWeaponClass *pSelectedWeapon = GetSelectedWeapon();
|
|
pSelectedWeapon->ScriptOnStopFiring(m_pEntity);
|
|
pSelectedWeapon->ScriptReload(m_pEntity);
|
|
}
|
|
stats.reloading=bReloading;
|
|
|
|
|
|
BYTE acc;
|
|
stream.ReadPkd(acc);
|
|
stats.accuracy=acc*(1.f/255.f);
|
|
|
|
VERIFY_COOKIE(stream);
|
|
|
|
|
|
if(stats.firing_grenade)
|
|
{
|
|
//invoke script event (client)
|
|
m_bGrenadeAnimation = true;
|
|
m_pEntity->SendScriptEvent(ScriptEvent_FireGrenade,0,NULL);
|
|
}
|
|
|
|
bool bRedirected;
|
|
EntityId nID;
|
|
stream.Read(bRedirected);
|
|
if (bRedirected)
|
|
stream.Read(nID);
|
|
if ((m_pRedirected!=0)!=bRedirected || m_pRedirected && m_pRedirected->GetId()!=nID)
|
|
{
|
|
if (m_pRedirected)
|
|
{
|
|
m_pRedirected->OnUnBind(m_pEntity,0);
|
|
m_pRedirected = 0;
|
|
}
|
|
if (bRedirected && (m_pRedirected=m_pGame->GetSystem()->GetIEntitySystem()->GetEntity(nID)))
|
|
m_pRedirected->OnBind(m_pEntity,0);
|
|
}
|
|
if (m_pRedirected && !bLocalHostEntity)
|
|
m_pRedirected->SetAngles(m_pEntity->GetAngles());
|
|
|
|
stream.Read(m_bFirstPersonLoaded);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CPlayer::Save( CStream &stream)
|
|
{
|
|
EntityCloneState cs;
|
|
|
|
cs.m_bSyncYAngle = false;
|
|
cs.m_bOffSync = false;
|
|
cs.m_bLocalplayer = true;
|
|
|
|
//[PETAR] Serialize flashlight for singleplayer
|
|
stream.Write(m_bLightOn);
|
|
bool bRet=Write(stream,&cs);
|
|
|
|
ASSERT(bRet);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CPlayer::Load( CStream &stream)
|
|
{
|
|
bool bPrevLightStatus;
|
|
stream.Read(bPrevLightStatus);
|
|
if (bPrevLightStatus!=m_bLightOn)
|
|
SwitchFlashLight(bPrevLightStatus);
|
|
return Read(stream);
|
|
}
|
|
|
|
// these two functions save and load the player state which is NOT already saved using read/write
|
|
|
|
bool CPlayer::SaveGame(CStream &stm)
|
|
{
|
|
for(PlayerWeaponsItor itor=m_mapPlayerWeapons.begin(); itor!=m_mapPlayerWeapons.end(); ++itor)
|
|
{
|
|
WeaponInfo &wi = itor->second;
|
|
if(wi.owns)
|
|
{
|
|
stm.Write(itor->first);
|
|
ASSERT(itor->first>=0 && itor->first<50);
|
|
stm.Write(wi.iFireMode);
|
|
}
|
|
}
|
|
stm.Write((int)0);
|
|
for(int i=0;i<sizeof(m_vWeaponSlots)/sizeof(int);i++)
|
|
{
|
|
stm.Write(m_vWeaponSlots[i]);
|
|
}
|
|
|
|
Save(stm);
|
|
|
|
return true;
|
|
};
|
|
|
|
bool CPlayer::LoadGame(CStream &stm)
|
|
{
|
|
RemoveAllWeapons();
|
|
|
|
// [Petar] preserve the original health in case we need to use it
|
|
// to restore the health of special AI on a checkpoint
|
|
int nStartHealth = m_stats.health;
|
|
if (!m_bIsAI)
|
|
DeselectWeapon();
|
|
|
|
for(int cl = 0; (stm.Read(cl),cl); )
|
|
{
|
|
WeaponInfo &wi = m_mapPlayerWeapons[cl];
|
|
wi.owns = true;
|
|
stm.Read(wi.iFireMode);
|
|
}
|
|
for(int i=0;i<sizeof(m_vWeaponSlots)/sizeof(int);i++)
|
|
{
|
|
stm.Read(m_vWeaponSlots[i]);
|
|
}
|
|
|
|
Load(stm);
|
|
|
|
|
|
SelectWeapon(m_stats.weapon);
|
|
|
|
if (m_nSelectedWeaponID != -1)
|
|
{
|
|
WeaponInfo &wi = GetWeaponInfo();
|
|
|
|
CWeaponClass *pSelectedWeapon = GetSelectedWeapon();
|
|
pSelectedWeapon->ScriptOnStopFiring(m_pEntity);
|
|
|
|
_SmartScriptObject pObj(m_pScriptSystem);
|
|
pObj->SetValue( "firemode", m_stats.firemode);
|
|
pObj->SetValue( "ignoreammo", true);
|
|
|
|
bool bCanSwitch;
|
|
m_pEntity->SendScriptEvent(ScriptEvent_FireModeChange, *pObj, &bCanSwitch);
|
|
|
|
wi.iFireMode = m_stats.firemode;
|
|
}
|
|
|
|
if (m_bIsAI)
|
|
{
|
|
IPuppet *pPuppet=0;
|
|
if (m_pEntity->GetAI()->CanBeConvertedTo(AIOBJECT_PUPPET,(void**)&pPuppet))
|
|
{
|
|
if (pPuppet->GetPuppetParameters().m_bSpecial)
|
|
m_stats.health = nStartHealth;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
void CPlayer::SetScriptObject(IScriptObject *pObject)
|
|
{
|
|
m_pScriptObject=pObject;
|
|
m_pUpdateAnimation=NULL;
|
|
}
|
|
/*! Retrieves the ScriptObject of this container
|
|
@return pointer to the ScriptObject
|
|
*/
|
|
IScriptObject *CPlayer::GetScriptObject()
|
|
{
|
|
return m_pScriptObject;
|
|
}
|
|
|
|
int CPlayer::MakeWeaponAvailable(int nWeaponID, bool bAvailable)
|
|
{
|
|
//make sure that we don't remove the currently selected weapon
|
|
if (nWeaponID == m_nSelectedWeaponID && !bAvailable)
|
|
{
|
|
DeselectWeapon();
|
|
SelectFirstWeapon();
|
|
}
|
|
|
|
CWeaponClass* pWC = GetGame()->GetWeaponSystemEx()->GetWeaponClassByID(nWeaponID);
|
|
if (pWC && !pWC->IsLoaded())
|
|
{
|
|
pWC->Load();
|
|
}
|
|
|
|
PlayerWeaponsItor it;
|
|
|
|
if ((it = m_mapPlayerWeapons.find(nWeaponID)) == m_mapPlayerWeapons.end())
|
|
{
|
|
TRACE("ERROR: Trying to make invalid weapon ID %i available", nWeaponID);
|
|
return -1;
|
|
}
|
|
bool bWasOwning=(* it).second.owns;
|
|
|
|
(* it).second.owns = bAvailable;
|
|
|
|
int slot=0;
|
|
if(bAvailable && (!bWasOwning))
|
|
{
|
|
(* it).second.iFireMode = 0;
|
|
slot=0;
|
|
while(slot<PLAYER_MAX_WEAPONS){if(m_vWeaponSlots[slot]==nWeaponID)return slot;slot++;}
|
|
slot=0;
|
|
while(slot<PLAYER_MAX_WEAPONS && m_vWeaponSlots[slot]!=0) slot++;
|
|
|
|
if(slot<PLAYER_MAX_WEAPONS && m_vWeaponSlots[slot]==0)
|
|
{
|
|
m_vWeaponSlots[slot]=nWeaponID;
|
|
return slot;
|
|
}
|
|
}else if(!bAvailable && (bWasOwning))
|
|
{
|
|
while(slot<PLAYER_MAX_WEAPONS){if(m_vWeaponSlots[slot]==nWeaponID){m_vWeaponSlots[slot]=0;return -1;} slot;slot++;}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
CWeaponClass *CPlayer::DeselectWeapon()
|
|
{
|
|
|
|
if (m_nSelectedWeaponID != -1)
|
|
{
|
|
CWeaponClass *pSelectedWeapon = GetSelectedWeapon();
|
|
//this script event is called only for the local client
|
|
if(IsMyPlayer() || m_pGame->IsMultiplayer())
|
|
{
|
|
pSelectedWeapon->ScriptOnDeactivate(m_pEntity);
|
|
}
|
|
|
|
// detach from bone ?
|
|
if (!pSelectedWeapon->GetBindBone().empty())
|
|
m_pEntity->DetachObjectToBone(pSelectedWeapon->GetBindBone().c_str());
|
|
|
|
SetWeapon(-1);
|
|
|
|
return pSelectedWeapon;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*ridirect the input of a player to another entity
|
|
@param id the id of the entity that will receive the input
|
|
@param angleDelta
|
|
*/
|
|
void CPlayer::RedirectInputToEntity(EntityId id, int angleDelta)
|
|
{
|
|
if (!id)
|
|
{
|
|
if (m_pRedirected)
|
|
m_pRedirected = NULL;
|
|
if(IsMyPlayer())
|
|
m_pGame->m_pClient->m_PlayerProcessingCmd.SetDeltaAngles(Vec3d(0.0f, 0.0f, 0.0f));
|
|
}
|
|
else
|
|
{
|
|
IEntity *pEntity = m_pGame->GetSystem()->GetIEntitySystem()->GetEntity(id);
|
|
if (pEntity)
|
|
{
|
|
m_pRedirected = pEntity;
|
|
//[PETAR]
|
|
// m_pGame->m_pClient->m_PlayerProcessingCmd.SetDeltaAngles(pEntity->GetAngles());
|
|
//[KIRILL] make turret point in right direction /statmounted - ONLY for local player
|
|
if(IsMyPlayer())
|
|
{
|
|
if(angleDelta>=0)
|
|
m_pGame->m_pClient->m_PlayerProcessingCmd.SetDeltaAngles(Vec3d(0.0f, 0.0f, (float)angleDelta));
|
|
else
|
|
m_pGame->m_pClient->m_PlayerProcessingCmd.SetDeltaAngles(pEntity->GetAngles(1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CPlayer::QueryContainerInterface(ContainerInterfaceType desired_interface, void **ppInterface )
|
|
{
|
|
|
|
if (desired_interface == CIT_IPLAYER)
|
|
{
|
|
*ppInterface = (void *) this;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
*ppInterface = 0;
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
IEntity * CPlayer::GetRedirected()
|
|
{
|
|
return m_pRedirected;
|
|
}
|
|
|
|
/*! set the offset of the camera from the player position.
|
|
usually is the height of the player
|
|
*/
|
|
void CPlayer::SetCameraOffset(const Vec3d& Offset)
|
|
{
|
|
m_pEntity->GetCamera()->SetCameraOffset(Offset);
|
|
}
|
|
|
|
/*! retreive the offset of the camera relative to the player position
|
|
@param Offset the offset in meters
|
|
*/
|
|
void CPlayer::GetCameraOffset(Vec3d& Offset)
|
|
{
|
|
m_pEntity->GetCamera()->GetCameraOffset(Offset);
|
|
}
|
|
|
|
void CPlayer::UpdateDrawAngles( )
|
|
{
|
|
ICryCharInstance *pChar = m_pEntity->GetCharInterface()->GetCharacter(0);
|
|
|
|
if (!pChar)
|
|
return;
|
|
|
|
float timeScale = 20.1f*m_pTimer->GetFrameTime();
|
|
|
|
if (timeScale>1.0f)
|
|
timeScale = 1.0f;
|
|
|
|
Vec3d angles = GetActualAngles();
|
|
Vec3d vAngles;
|
|
|
|
//on ladder orient the player so he always look at the center of the ladder.
|
|
if (m_stats.onLadder)
|
|
{
|
|
m_vLadderAngles = m_pEntity->GetPos() - m_vLadderPosition;
|
|
m_vLadderAngles.z = 0;
|
|
|
|
m_vLadderAngles.Normalize();
|
|
|
|
m_vLadderAngles.z = -atan2(m_vLadderAngles.x,m_vLadderAngles.y)*(180.0f/gf_PI);
|
|
m_vLadderAngles.x = 0;
|
|
m_vLadderAngles.y = 0;
|
|
|
|
vAngles = m_vLadderAngles;
|
|
}
|
|
else if (m_pEntity->IsBound())
|
|
vAngles = angles;
|
|
else if (m_CurStance == eProne )
|
|
vAngles = m_EnvTangent;
|
|
else
|
|
{
|
|
if(m_LegRotation)
|
|
vAngles = Vec3d(0, 0, m_LegAngle);
|
|
else
|
|
vAngles = Vec3d(0,0,angles.z);
|
|
}
|
|
|
|
//[kirill] smooth here Character angles (all but Z)
|
|
// to make it not jurk when proning on some bumpy enviroment
|
|
vAngles.x = Snap_s180(vAngles.x);
|
|
vAngles.y = Snap_s180(vAngles.y);
|
|
m_vCurEntAngle.x = Snap_s180(m_vCurEntAngle.x);
|
|
m_vCurEntAngle.y = Snap_s180(m_vCurEntAngle.y);
|
|
|
|
Vec3d delta = (vAngles - m_vCurEntAngle);
|
|
delta.x = Snap_s180(delta.x);
|
|
delta.y = Snap_s180(delta.y);
|
|
|
|
m_vCurEntAngle += (delta*timeScale);
|
|
m_vCurEntAngle.z = vAngles.z;
|
|
m_vCharacterAngles = m_vCurEntAngle;
|
|
|
|
// CheckIfNAN( vAngles );
|
|
// m_vCharacterAngles = vAngles;
|
|
}
|
|
|
|
/*!drawn the player
|
|
called by the engine when the player has to be drawn
|
|
*/
|
|
void CPlayer::OnDraw(const SRendParams & _RendParams)
|
|
{
|
|
//return;
|
|
|
|
OnDrawMountedWeapon( _RendParams );
|
|
|
|
// if nRecursionLevel is not 0 - use only 3tp person view ( for reflections )
|
|
int nRecursionLevel = (int)m_pGame->GetSystem()->GetIRenderer()->EF_Query(EFQ_RecurseLevel) - 1;
|
|
|
|
// draw first person weapon
|
|
if(m_bFirstPerson && !nRecursionLevel && m_stats.drawfpweapon && m_nSelectedWeaponID != -1)
|
|
{
|
|
CWeaponClass* pWeapon = GetSelectedWeapon();
|
|
ICryCharInstance *pInst = pWeapon->GetCharacter();
|
|
|
|
if (pInst && pInst->GetFlags()&CS_FLAG_DRAW_MODEL)
|
|
{
|
|
SRendParams RendParams = _RendParams;
|
|
RendParams.vPos = pWeapon->GetPos();
|
|
RendParams.vAngles = pWeapon->GetAngles();
|
|
|
|
if (RendParams.pShadowVolumeLightSource)
|
|
{
|
|
if(m_pEntity->GetRndFlags()&ERF_CASTSHADOWVOLUME && !IsMyPlayer())
|
|
pInst->RenderShadowVolumes(&RendParams);
|
|
}
|
|
else {
|
|
pInst->Draw(RendParams,m_pEntity->GetPos());
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
ICryCharInstance *pChar = m_pEntity->GetCharInterface()->GetCharacter(0);
|
|
if (!pChar)
|
|
return;
|
|
|
|
if (!(pChar->GetFlags() & CS_FLAG_DRAW_MODEL) && !nRecursionLevel)
|
|
return;
|
|
|
|
SRendParams RendParams = _RendParams;
|
|
// RendParams.vPos = m_pEntity->GetPos(); // position is not always entity position
|
|
|
|
if(m_pVehicle ) // it' gunner in vehicle
|
|
{
|
|
// create the matrix here
|
|
Matrix44 matParent;
|
|
matParent.SetIdentity();
|
|
|
|
matParent=Matrix44::CreateRotationZYX(-gf_DEGTORAD*m_pVehicle->GetEntity()->GetAngles())*matParent; //NOTE: angles in radians and negated
|
|
|
|
CryQuat cxquat = Quat( GetTransposed44(matParent) );
|
|
|
|
CryQuat rxquat;
|
|
Vec3d gunnerAngle;
|
|
// if(m_pMountedWeapon) // it' gunner in vehicle
|
|
if(m_stats.inVehicleState == PVS_GUNNER) // it' gunner in vehicle
|
|
gunnerAngle = GetEntity()->GetAngles(1);
|
|
else // it' driver/passenger
|
|
gunnerAngle.Set(0,0,180);
|
|
gunnerAngle.x=0;
|
|
gunnerAngle.y=0;
|
|
rxquat.SetRotationXYZ(DEG2RAD(gunnerAngle));
|
|
|
|
CryQuat result = cxquat*rxquat;
|
|
Vec3d finalangles = Ang3::GetAnglesXYZ(Matrix33(result));
|
|
RendParams.vAngles = RAD2DEG(finalangles);
|
|
m_pEntity->SetPhysAngles( RendParams.vAngles );
|
|
}
|
|
else
|
|
// if (!m_pVehicle || m_bIsAI )
|
|
{
|
|
if( IsAlive())
|
|
RendParams.vAngles = m_vCharacterAngles;
|
|
else
|
|
RendParams.vAngles.Set(0, 0, m_pEntity->GetAngles().z);
|
|
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
// if the player is bound to the vehicle and in 3rd person mode,
|
|
// force the character's angles to the correct direction
|
|
RendParams.vAngles = m_pVehicle->GetEntity()->GetAngles();
|
|
// RendParams.vAngles.z+=180;
|
|
// RendParams.vAngles.x=-RendParams.vAngles.x;
|
|
}
|
|
*/
|
|
|
|
if (_RendParams.pShadowVolumeLightSource)
|
|
{
|
|
if(m_pEntity->GetRndFlags()&ERF_CASTSHADOWVOLUME)
|
|
pChar->RenderShadowVolumes(&RendParams, (m_pEntity->GetRndFlags()&ERF_SELFSHADOW) ? 0 : 10);
|
|
}
|
|
else
|
|
pChar->Draw(RendParams,m_pEntity->GetPos());
|
|
}
|
|
|
|
|
|
/*!sets the animation speed of the player - used to scale animation playback speed
|
|
depending on actuall movement speed (to awoid skeiting)
|
|
*/
|
|
void CPlayer::SetAnimationRefSpeedRunRelaxed(const float fwd, const float side, const float back )
|
|
{
|
|
m_AniSpeedRunRelaxed[0] = fwd;
|
|
m_AniSpeedRunRelaxed[1] = side;
|
|
m_AniSpeedRunRelaxed[2] = back;
|
|
}
|
|
/*!sets the animation speed of the player - used to scale animation playback speed
|
|
depending on actuall movement speed (to awoid skeiting)
|
|
*/
|
|
void CPlayer::SetAnimationRefSpeedWalkRelaxed(const float fwd, const float side, const float back )
|
|
{
|
|
m_AniSpeedWalkRelaxed[0] = fwd;
|
|
m_AniSpeedWalkRelaxed[1] = side;
|
|
m_AniSpeedWalkRelaxed[2] = back;
|
|
}
|
|
|
|
/*!sets the animation speed of the player - used to scale animation playback speed
|
|
depending on actuall movement speed (to awoid skeiting)
|
|
*/
|
|
void CPlayer::SetAnimationRefSpeedWalk(const float fwd, const float side, const float back )
|
|
{
|
|
m_AniSpeedWalk[0] = fwd;
|
|
m_AniSpeedWalk[1] = side;
|
|
m_AniSpeedWalk[2] = back;
|
|
}
|
|
|
|
/*!sets the animation speed of the player - used to scale animation playback speed
|
|
depending on actuall movement speed (to awoid skeiting)
|
|
*/
|
|
void CPlayer::SetAnimationRefSpeedXRun(const float fwd, const float side, const float back )
|
|
{
|
|
m_AniSpeedXRun[0] = fwd;
|
|
m_AniSpeedXRun[1] = side;
|
|
m_AniSpeedXRun[2] = back;
|
|
}
|
|
|
|
|
|
/*!sets the animation speed of the player - used to scale animation playback speed
|
|
depending on actuall movement speed (to awoid skeiting)
|
|
*/
|
|
void CPlayer::SetAnimationRefSpeedRun(const float fwd, const float side, const float back )
|
|
{
|
|
m_AniSpeedRun[0] = fwd;
|
|
m_AniSpeedRun[1] = side;
|
|
m_AniSpeedRun[2] = back;
|
|
}
|
|
|
|
/*!sets the animation speed of the player - used to scale animation playback speed
|
|
depending on actuall movement speed (to awoid skeiting)
|
|
*/
|
|
void CPlayer::SetAnimationRefSpeedXWalk(const float fwd, const float side, const float back )
|
|
{
|
|
m_AniSpeedXWalk[0] = fwd;
|
|
m_AniSpeedXWalk[1] = side;
|
|
m_AniSpeedXWalk[2] = back;
|
|
}
|
|
|
|
/*!sets the animation speed of the player - used to scale animation playback speed
|
|
depending on actuall movement speed (to awoid skeiting)
|
|
*/
|
|
void CPlayer::SetAnimationRefSpeedCrouch(const float fwd, const float side, const float back )
|
|
{
|
|
m_AniSpeedCrouch[0] = fwd;
|
|
m_AniSpeedCrouch[1] = side;
|
|
m_AniSpeedCrouch[2] = back;
|
|
}
|
|
|
|
|
|
|
|
/*!sets the running speed of the player
|
|
@param speed the running speed
|
|
*/
|
|
void CPlayer::SetRunSpeed(const float speed)
|
|
{
|
|
m_RunSpeed = speed;
|
|
if(!m_bIsAI)
|
|
// if(IsMyPlayer())
|
|
m_pGame->p_speed_run->Set(m_RunSpeed);
|
|
}
|
|
|
|
/*!sets the walk speed of the player
|
|
@param speed the walk speed
|
|
*/
|
|
void CPlayer::SetWalkSpeed(const float speed)
|
|
{
|
|
m_WalkSpeed = speed;
|
|
if(!m_bIsAI)
|
|
// if(IsMyPlayer())
|
|
m_pGame->p_speed_walk->Set(m_WalkSpeed);
|
|
}
|
|
|
|
/*!sets the walk speed of the player when is croching
|
|
@param speed the croching speed
|
|
*/
|
|
void CPlayer::SetCrouchSpeed(const float speed)
|
|
{
|
|
m_CrouchSpeed = speed;
|
|
if(!m_bIsAI)
|
|
// if(IsMyPlayer())
|
|
m_pGame->p_speed_crouch->Set(m_CrouchSpeed);
|
|
}
|
|
|
|
/*!sets the walk speed of the player when is proning
|
|
@param speed the proning speed
|
|
*/
|
|
void CPlayer::SetProneSpeed(const float speed)
|
|
{
|
|
m_ProneSpeed = speed;
|
|
if(!m_bIsAI)
|
|
// if(IsMyPlayer())
|
|
m_pGame->p_speed_prone->Set(m_ProneSpeed);
|
|
}
|
|
|
|
/*!sets the walk speed of the player when is proning
|
|
@param speed the proning speed
|
|
*/
|
|
void CPlayer::SetSwimSpeed(const float speed)
|
|
{
|
|
m_SwimSpeed = speed;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
/*!sets the camera bob
|
|
@param pitch
|
|
@param roll
|
|
@param length
|
|
*/
|
|
void CPlayer::SetCameraBob(const float pitch, const float roll, const float length)
|
|
{
|
|
m_walkParams.runRoll = roll;
|
|
m_walkParams.runPitch = pitch;
|
|
m_walkParams.stepLength = length;
|
|
|
|
if (!m_bIsAI)
|
|
{
|
|
m_pGame->p_bob_pitch->Set(m_walkParams.runPitch);
|
|
m_pGame->p_bob_roll->Set(m_walkParams.runRoll);
|
|
m_pGame->p_bob_length->Set(m_walkParams.stepLength);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
//
|
|
/*!sets the weapon bob
|
|
*/
|
|
void CPlayer::SetWeaponBob(const float ampl)
|
|
{
|
|
m_walkParams.weaponCycle = ampl;
|
|
if (!m_bIsAI)
|
|
m_pGame->p_bob_weapon->Set(m_walkParams.weaponCycle);
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
/*!sets the amount of force applied to the player when he jump
|
|
@param force the amount of force
|
|
*/
|
|
void CPlayer::SetJumpForce(const float force)
|
|
{
|
|
m_JumpForce = force;
|
|
if (!m_bIsAI)
|
|
m_pGame->p_jump_force->Set(m_JumpForce);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
//
|
|
/*!set the player's lean angle
|
|
@param lean angle in degrees
|
|
*/
|
|
void CPlayer::SetLean(const float lean)
|
|
{
|
|
m_LeanDegree = lean;
|
|
|
|
//[KIRILL] this console variable makes lean global - it has to be player's per-instance property
|
|
// to fix bug in MP with leaning
|
|
// if (!m_bIsAI)
|
|
// m_pGame->p_lean->Set(m_LeanDegree);
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
/*!sets the player dimension in stealth mode
|
|
@param pDim struct containing the player dimensions
|
|
@see pe_player_dimensions
|
|
*/
|
|
void CPlayer::SetDimStealth(const pe_player_dimensions* const pDim)
|
|
{
|
|
if(!pDim)
|
|
{
|
|
m_PlayerDimStealth.heightEye = (m_PlayerDimNormal.heightEye + m_PlayerDimCrouch.heightEye)*.5f;
|
|
m_PlayerDimStealth.heightCollider = (m_PlayerDimNormal.heightCollider + m_PlayerDimCrouch.heightCollider)*.5f;
|
|
m_PlayerDimStealth.sizeCollider = (m_PlayerDimNormal.sizeCollider+m_PlayerDimCrouch.sizeCollider)*.5f;
|
|
return;
|
|
}
|
|
m_PlayerDimStealth = *pDim;
|
|
m_CurStance = eNone;
|
|
GoStand( );
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
/*!sets the player dimension in normal(standing) mode
|
|
@param pDim struct containing the player dimensions
|
|
@see pe_player_dimensions
|
|
*/
|
|
void CPlayer::SetDimNormal(const pe_player_dimensions* const pDim)
|
|
{
|
|
if(!pDim)
|
|
{
|
|
m_PlayerDimNormal.heightEye = 1.7f;
|
|
m_PlayerDimNormal.heightCollider = 1.1f;
|
|
m_PlayerDimNormal.sizeCollider.Set(0.4f,0.4f,0.7f);
|
|
return;
|
|
}
|
|
m_PlayerDimNormal = *pDim;
|
|
SetDimStealth();
|
|
m_CurStance = eNone;
|
|
GoStand( );
|
|
|
|
// m_PlayerDimSwim = m_PlayerDimNormal;
|
|
// m_PlayerDimSwim.sizeCollider.z = .55f;
|
|
// m_PlayerDimSwim.heightEye = .65f;
|
|
|
|
|
|
// m_PlayerDimSwim = m_PlayerDimNo;
|
|
// m_PlayerDimSwim.sizeCollider.z = .55f;
|
|
// m_PlayerDimSwim.heightEye = .65f;
|
|
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
/*!sets the player dimension in crouch mode
|
|
@param pDim struct containing the player dimensions
|
|
@see pe_player_dimensions
|
|
*/
|
|
void CPlayer::SetDimCrouch(const pe_player_dimensions* const pDim)
|
|
{
|
|
if(!pDim)
|
|
{
|
|
m_PlayerDimCrouch.heightEye = 1.0f;
|
|
m_PlayerDimCrouch.heightCollider = 0.6f;
|
|
m_PlayerDimCrouch.sizeCollider.Set(0.4f,0.4f,0.5f);
|
|
return;
|
|
}
|
|
m_PlayerDimCrouch = *pDim;
|
|
SetDimStealth();
|
|
m_CurStance = eNone;
|
|
GoStand( );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
/*!sets the player dimension in prone mode
|
|
@param pDim struct containing the player dimensions
|
|
@see pe_player_dimensions
|
|
*/
|
|
void CPlayer::SetDimProne(const pe_player_dimensions* const pDim)
|
|
{
|
|
if(!pDim)
|
|
{
|
|
m_PlayerDimProne.heightEye = 0.5f;
|
|
m_PlayerDimProne.heightCollider = 0.3f;
|
|
m_PlayerDimProne.sizeCollider.Set(0.4f,0.4f,0.2f);
|
|
return;
|
|
}
|
|
m_PlayerDimProne = *pDim;
|
|
m_PlayerDimSwim = m_PlayerDimProne;
|
|
m_PlayerDimSwim.sizeCollider.z = .55f;
|
|
m_PlayerDimSwim.heightCollider = .75f;
|
|
m_PlayerDimSwim.heightEye = .70f;
|
|
m_CurStance = eNone;
|
|
GoStand( );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CPlayer::GetBoneHitZone( int boneIdx ) const
|
|
{
|
|
return m_pEntity->GetBoneHitZone(boneIdx);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
Vec3d CPlayer::CalcTangentOnEnviroment( const Vec3d &angle )
|
|
{
|
|
Vec3d forward = angle;
|
|
Vec3d tangent=forward;
|
|
if(!m_pEntity->GetPhysics())
|
|
return tangent;
|
|
pe_status_living pStat;
|
|
m_pEntity->GetPhysics()->GetStatus(&pStat);
|
|
|
|
// Vec3d forward = m_pEntity->GetAngles();
|
|
// Vec3d normal = (Vec3d)pStat.groundSlope;
|
|
Vec3d normal = m_vProneEnvNormal;
|
|
|
|
forward=ConvertToRadAngles(forward);
|
|
forward = normal.Cross( forward );
|
|
forward = forward.Cross( normal );
|
|
|
|
forward.Normalize();
|
|
normal.Normalize();
|
|
|
|
Vec3d vA[3];
|
|
|
|
vA[1] = -forward;
|
|
vA[0] = normal.Cross(forward);
|
|
vA[2] = normal;
|
|
|
|
|
|
matrix3x3RMf &mtrx((matrix3x3RMf&)(*(float*)vA));
|
|
mtrx.Transpose();
|
|
|
|
tangent = Ang3::GetAnglesXYZ(mtrx);
|
|
|
|
Ang3 angles=tangent;
|
|
angles.Rad2Deg();
|
|
tangent=angles;
|
|
|
|
return tangent;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
//
|
|
//! returns arm damage in percent 100 - (arm_health/max_arm_health)*100
|
|
int CPlayer::GetArmDamage(void) const
|
|
{
|
|
//TRACE("ARM damage %d", 100 - ((float)m_stats.armHealth/(float)m_stats.maxArmHealth)*100.0f);
|
|
return 100 - (int)(((float)m_stats.armHealth/(float)m_stats.maxArmHealth)*100.0f);
|
|
}
|
|
|
|
//! returns leg damage in percent 100 - (leg_health/max_leg_health)*100
|
|
int CPlayer::GetLegDamage(void) const
|
|
{
|
|
return 100 - (int)((m_stats.legHealth/m_stats.maxLegHealth)*100.0f);
|
|
}
|
|
|
|
|
|
//
|
|
//!return true if the player is colliding with something
|
|
bool CPlayer::HasCollided( )
|
|
{
|
|
IPhysicalEntity *pent = m_pEntity->GetPhysics();
|
|
if(!pent)
|
|
return false;
|
|
|
|
if (pent->GetType()==PE_LIVING)
|
|
{
|
|
// Create a new status object. The fields are initialized for us
|
|
pe_status_living status;
|
|
|
|
// Get new player status from physics engine
|
|
pent->GetStatus(&status);
|
|
if (!status.bFlying)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
pe_status_dynamics sd;
|
|
pent->GetStatus(&sd);
|
|
float fMassTot=sd.mass, fMassColl=0;
|
|
int nColls,i,j;
|
|
|
|
coll_history_item item[8];
|
|
pe_status_collisions sc;
|
|
sc.pHistory = item;
|
|
sc.len = 8;
|
|
sc.age = 0.5f;
|
|
nColls = pent->GetStatus(&sc);
|
|
for(i=0; i<nColls; i++)
|
|
{
|
|
for(j=0;j<i && item[j].partid[0]!=item[i].partid[0];j++);
|
|
if (j==i)
|
|
{
|
|
sd.partid = item[i].partid[0];
|
|
pent->GetStatus(&sd);
|
|
fMassColl += sd.mass;
|
|
}
|
|
}
|
|
return fMassColl>fMassTot*0.3f;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CPlayer::StartDie( const Vec3d& hitImpuls, const Vec3d hitPoint, int hitpartid, const int deathType )
|
|
{
|
|
//
|
|
|
|
if(!m_pGame->IsMultiplayer())
|
|
{
|
|
float deathTimer=m_pGame->p_deathtime->GetFVal();
|
|
m_fDeathTimer = deathTimer;
|
|
} else
|
|
m_pGame->m_DeadPlayers.push_back(this);
|
|
|
|
//*/
|
|
|
|
if(IsMyPlayer())
|
|
{
|
|
|
|
/*
|
|
// if it was first person view - go to third person
|
|
if(m_bFirstPerson)
|
|
m_pGame->SetViewMode(true);
|
|
|
|
Vec3d camPos = m_pEntity->GetCamera()->GetPos();
|
|
float fWaterLevel=m_p3DEngine->GetWaterLevel(&camPos);
|
|
if( fWaterLevel>m_pEntity->GetCamera()->GetPos().z )
|
|
{
|
|
camPos.z = fWaterLevel + 1;
|
|
m_pEntity->GetCamera()->SetPos( camPos );
|
|
}
|
|
*/
|
|
|
|
InitCameraTransition( PCM_CASUAL );
|
|
|
|
IAISystem *pAISystem =m_pGame->GetSystem()->GetAISystem();
|
|
if (pAISystem)
|
|
{
|
|
if (pAISystem->GetAutoBalanceInterface())
|
|
pAISystem->GetAutoBalanceInterface()->RegisterPlayerDeath();
|
|
}
|
|
}
|
|
|
|
m_sPrevAniName.clear();
|
|
m_sPrevAniNameLayer1.clear();
|
|
m_sPrevAniNameLayer2.clear();
|
|
m_pEntity->ResetAnimations( 0 );
|
|
SwitchFlashLight( false ); // turn off flashlight
|
|
|
|
IPhysicalEntity *pent = m_pEntity->GetPhysics();
|
|
IEntityCharacter *ichar = m_pEntity->GetCharInterface();
|
|
ICryCharInstance *character = ichar->GetCharacter(PLAYER_MODEL_IDX);
|
|
|
|
// Hide weapon.
|
|
DeselectWeapon();
|
|
if (character)
|
|
{
|
|
hitpartid = character->TranslatePartIdToDeadBody(hitpartid);
|
|
}
|
|
|
|
if (pent)
|
|
{
|
|
if (pent->GetType()==PE_LIVING)
|
|
{
|
|
pe_action_move am;
|
|
am.dir = hitImpuls/100.0f;
|
|
am.iJump = 2;
|
|
pent->Action(&am);
|
|
}
|
|
else if (hitpartid>=0)
|
|
{
|
|
pe_action_impulse ai;
|
|
ai.partid = hitpartid;
|
|
if (hitPoint.len2()>0)
|
|
ai.point = hitPoint;
|
|
ai.impulse = hitImpuls;
|
|
pent->Action(&ai);
|
|
}
|
|
}
|
|
|
|
// m_deathTime = GetCurrTime();
|
|
// UpdateCharacterAnimations();
|
|
m_pEntity->EnableAI(false);
|
|
|
|
m_pEntity->KillTimer();
|
|
|
|
/*
|
|
// m_deathTime = GetCurrTime();
|
|
|
|
|
|
IEntityCharacter *ichar = m_pEntity->GetCharInterface();
|
|
// UpdateCharacterAnimations();
|
|
|
|
ICryCharInstance *character = ichar->GetCharacter(PLAYER_MODEL_IDX);
|
|
if (character)
|
|
{
|
|
// Hide weapon.
|
|
character->EnableLastIdleAnimationRestart(0,false);
|
|
character->EnableLastIdleAnimationRestart(1,false);
|
|
character->AttachObjectToBone(NULL,NULL);
|
|
|
|
if (m_bIsAI)
|
|
character->ResetAnimations();
|
|
}
|
|
|
|
|
|
if (m_pEntity->GetPhysics()->GetType()==PE_ARTICULATED)
|
|
return;
|
|
|
|
// Disable physics on this player.
|
|
m_pEntity->EnablePhysics(false);
|
|
*/
|
|
|
|
|
|
|
|
}
|
|
|
|
/*! sets the player dynamics parameters
|
|
@param pDyn a structure containing the dynamics parameters
|
|
air_control
|
|
gravity
|
|
swimming_gravity
|
|
inertia
|
|
swimming_inertia
|
|
*/
|
|
void CPlayer::SetDynamics(const PlayerDynamics *pDyn)
|
|
{
|
|
if (pDyn->air_control!=1E10f) m_Dynamics.air_control = pDyn->air_control;
|
|
if (pDyn->gravity!=1E10f) m_Dynamics.gravity = pDyn->gravity;
|
|
if (pDyn->swimming_gravity!=1E10f) m_Dynamics.swimming_gravity = pDyn->swimming_gravity;
|
|
if (pDyn->inertia!=1E10f) m_Dynamics.inertia = pDyn->inertia;
|
|
if (pDyn->swimming_inertia!=1E10f) m_Dynamics.swimming_inertia = pDyn->swimming_inertia;
|
|
if (pDyn->jump_gravity!=1E10f) m_Dynamics.jump_gravity = pDyn->jump_gravity;
|
|
}
|
|
|
|
void CPlayer::RemoveAllWeapons()
|
|
{
|
|
// Takes away the owns flag of all weapons in the player's weapon map
|
|
PlayerWeaponsItor it;
|
|
for (it=m_mapPlayerWeapons.begin(); it!=m_mapPlayerWeapons.end(); it++)
|
|
(* it).second.owns = false;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
// returns true if can stand in given position
|
|
bool CPlayer::CanStand( const Vec3& pos)
|
|
{
|
|
bool result=true;
|
|
IPhysicalEntity* phys = m_pEntity->GetPhysics();
|
|
|
|
pe_player_dynamics pd;
|
|
phys->GetParams(&pd);
|
|
bool bActive = pd.bActive;
|
|
m_pEntity->ActivatePhysics( true );
|
|
|
|
Vec3 curPos=m_pEntity->GetPos();
|
|
pe_params_pos ppos;
|
|
ppos.pos = pos;
|
|
phys->SetParams(&ppos);
|
|
|
|
if(!phys->SetParams( &m_PlayerDimCrouch ))
|
|
result=false;
|
|
if(result && !phys->SetParams( &m_PlayerDimNormal ))
|
|
result=false;
|
|
|
|
// restore active/position
|
|
m_pEntity->ActivatePhysics( bActive );
|
|
ppos.pos = curPos;
|
|
phys->SetParams(&ppos);
|
|
phys->SetParams( &m_PlayerDimNormal );
|
|
// m_CurStance = eNone;
|
|
// GoStand( );
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
// returns true if switch to stance or already in stance, otherwise return false
|
|
bool CPlayer::GoStand(bool ignoreSpam)
|
|
{
|
|
//prevent prone-standing position spamming
|
|
if (!ignoreSpam && m_fLastProneTime > m_pTimer->GetCurrTime())
|
|
return false;
|
|
|
|
IPhysicalEntity* phys = m_pEntity->GetPhysics();
|
|
if ( phys && m_CurStance != eStand ) //m_currDimensions!=eDimNormal)
|
|
{
|
|
// Use normal physics dimensions.
|
|
if( m_CurStance == eProne )
|
|
m_pEntity->SetPhysAngles( Vec3(0,0,0) ); // reset angle if proning
|
|
|
|
|
|
if(phys->SetParams( &m_PlayerDimNormal ))
|
|
{
|
|
//InitCameraTransition( PCM_CASUAL ,true );
|
|
m_AngleLimitBase.Set(0,0,0);
|
|
if(m_pEntity->GetAI())
|
|
{
|
|
m_pEntity->GetAI()->SetEyeHeight(m_PlayerDimNormal.heightEye);
|
|
}
|
|
m_currDimensions = eDimNormal;
|
|
m_PrevStance = m_CurStance;
|
|
m_CurStance = eStand;
|
|
|
|
m_stats.aim = false;
|
|
m_stats.crouch = false;
|
|
m_stats.prone = false;
|
|
// [kirill] need this to use only z component of entity angles (same as for drawing)
|
|
// when calculating BBox
|
|
GetEntity()->SetFlags( ETY_FLAG_CALCBBOX_ZROTATE );
|
|
|
|
#if defined(LINUX64)
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, 0);
|
|
#else
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, NULL);
|
|
#endif
|
|
m_bStayCrouch = false;
|
|
|
|
m_fLastProneTime = m_pTimer->GetCurrTime() + 0.5f;
|
|
|
|
return true;
|
|
}
|
|
|
|
// could not change - restore angle
|
|
if( m_CurStance == eProne )
|
|
m_pEntity->SetPhysAngles( m_EnvTangent );
|
|
|
|
return false;
|
|
}
|
|
else // was standing already
|
|
m_PrevStance = eStand;
|
|
|
|
m_bStayCrouch = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
// returns true if switch to stance or already in stance, otherwise return false
|
|
bool CPlayer::GoStealth( )
|
|
{
|
|
IPhysicalEntity* phys = m_pEntity->GetPhysics();
|
|
if ( phys && m_CurStance != eStealth ) //m_currDimensions!=eDimStealth)
|
|
{
|
|
if( m_CurStance == eProne )
|
|
m_pEntity->SetPhysAngles( Vec3(0,0,0) ); // reset angle if proning
|
|
|
|
// Use stealth physics dimensions.
|
|
if(phys->SetParams( &m_PlayerDimStealth )) //if can stealth here
|
|
{
|
|
//InitCameraTransition( PCM_CASUAL );
|
|
m_AngleLimitBase.Set(0,0,0);
|
|
if(m_pEntity->GetAI())
|
|
{
|
|
m_pEntity->GetAI()->SetEyeHeight(m_PlayerDimStealth.heightEye);
|
|
}
|
|
m_currDimensions = eDimStealth;
|
|
m_PrevStance = m_CurStance;
|
|
m_CurStance = eStealth;
|
|
|
|
m_stats.aim = false;
|
|
m_stats.crouch = false;
|
|
m_stats.prone = false;
|
|
// [kirill] need this to use only z component of entity angles (same as for drawing)
|
|
// when calculating BBox
|
|
GetEntity()->SetFlags( ETY_FLAG_CALCBBOX_ZROTATE );
|
|
|
|
m_Running = false;
|
|
#if defined(LINUX64)
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, 0);
|
|
#else
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, NULL);
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
// could not change - restore angle if proning
|
|
if( m_CurStance == eProne )
|
|
m_pEntity->SetPhysAngles( m_EnvTangent );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
// returns true if switch to stance or already in stance, otherwise return false
|
|
bool CPlayer::GoCrouch( )
|
|
{
|
|
// don't go to crouch mode if using mounted weapon
|
|
if(m_pMountedWeapon)
|
|
return false;
|
|
// don't change stance in water
|
|
if( m_bSwimming )
|
|
return false;
|
|
|
|
IPhysicalEntity* phys = m_pEntity->GetPhysics();
|
|
if ( phys && m_CurStance != eCrouch ) //m_currDimensions!=eDimCrouch)
|
|
{
|
|
if( m_CurStance == eProne )
|
|
m_pEntity->SetPhysAngles( Vec3(0,0,0) ); // reset angle if proning
|
|
|
|
// Use crouching physics dimensions.
|
|
if(phys->SetParams( &m_PlayerDimCrouch ))
|
|
{
|
|
//InitCameraTransition( PCM_CASUAL, true );
|
|
m_AngleLimitBase.Set(0,0,0);
|
|
if(m_pEntity->GetAI())
|
|
{
|
|
m_pEntity->GetAI()->SetEyeHeight(m_PlayerDimCrouch.heightEye);
|
|
}
|
|
m_currDimensions = eDimCrouch;
|
|
m_PrevStance = m_CurStance;
|
|
m_CurStance = eCrouch;
|
|
|
|
m_stats.aim = false;
|
|
m_stats.crouch = true;
|
|
m_stats.prone = false;
|
|
// [kirill] need this to use only z component of entity angles (same as for drawing)
|
|
// when calculating BBox
|
|
GetEntity()->SetFlags( ETY_FLAG_CALCBBOX_ZROTATE );
|
|
|
|
m_Running = false;
|
|
#if defined(LINUX64)
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, 0);
|
|
#else
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, NULL);
|
|
#endif
|
|
return true;
|
|
}
|
|
// could not change - restore angle if proning
|
|
if( m_CurStance == eProne )
|
|
m_pEntity->SetPhysAngles( m_EnvTangent );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
// returns true if switch to stance or already in stance, otherwise returns false
|
|
bool CPlayer::GoProne( )
|
|
{
|
|
IPhysicalEntity* phys = m_pEntity->GetPhysics();
|
|
|
|
if(!CanProne(false))
|
|
return false;
|
|
|
|
if ( phys && m_CurStance != eProne) //!=eDimProne)
|
|
{
|
|
|
|
// Use proning physics dimensions.
|
|
// if can't change dimentions at current position - put player little up
|
|
// and try again
|
|
if(!phys->SetParams( &m_PlayerDimProne ))
|
|
{
|
|
Vec3d pos = m_pEntity->GetPos();
|
|
pos.z += .5f;
|
|
m_pEntity->SetPos( pos );
|
|
if(!phys->SetParams( &m_PlayerDimProne ))
|
|
{
|
|
// restore position
|
|
pos.z -= .5f;
|
|
m_pEntity->SetPos( pos );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//
|
|
Vec3d ang = m_pEntity->GetAngles();
|
|
m_EnvTangent = CalcTangentOnEnviroment( m_pEntity->GetAngles() );
|
|
m_pEntity->SetPhysAngles( m_EnvTangent ); // set angels for phisics (body is flat on surfece tangent space)
|
|
|
|
//InitCameraTransition( PCM_CASUAL, true );
|
|
if(m_pEntity->GetAI())
|
|
{
|
|
m_pEntity->GetAI()->SetEyeHeight(m_PlayerDimProne.heightEye);
|
|
}
|
|
m_currDimensions = eDimProne;
|
|
m_PrevStance = m_CurStance;
|
|
m_CurStance = eProne;
|
|
|
|
m_stats.aim = false;
|
|
m_stats.crouch = false;
|
|
m_stats.prone = true;
|
|
// [kirill] when in prone - use all the rotations (same as for drawing)
|
|
// when calculating BBox
|
|
GetEntity()->ClearFlags( ETY_FLAG_CALCBBOX_ZROTATE );
|
|
|
|
m_Running = false;
|
|
#if defined(LINUX64)
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, 0);
|
|
#else
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, NULL);
|
|
#endif
|
|
}
|
|
|
|
m_bStayCrouch = false;
|
|
|
|
m_fLastProneTime = m_pTimer->GetCurrTime() + 0.5f;
|
|
|
|
return true;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
// returns true if switch to stance or already in stance, otherwise returns false
|
|
bool CPlayer::GoSwim( )
|
|
{
|
|
IPhysicalEntity* phys = m_pEntity->GetPhysics();
|
|
|
|
if ( phys && m_CurStance != eSwim) //!=eDimProne)
|
|
{
|
|
//
|
|
// Vec3d ang = m_pEntity->GetAngles();
|
|
// m_EnvTangent = CalcTangentOnEnviroment( m_pEntity->GetAngles() );
|
|
// m_pEntity->SetPhysAngles( m_EnvTangent ); // set angels for phisics (body is flat on surfece tangent space)
|
|
|
|
// Use proning physics dimensions for swimming.
|
|
if(phys->SetParams( &m_PlayerDimSwim ))
|
|
{
|
|
|
|
InitCameraTransition( PCM_CASUAL, true );
|
|
m_AngleLimitBase.Set(0,0,0);
|
|
if(m_pEntity->GetAI())
|
|
{
|
|
m_pEntity->GetAI()->SetEyeHeight(m_PlayerDimProne.heightEye);
|
|
}
|
|
m_currDimensions = eDimProne;
|
|
m_PrevStance = m_CurStance;
|
|
m_CurStance = eSwim;
|
|
|
|
// m_stats.aim = false;
|
|
// m_stats.crouch = false;
|
|
// m_stats.prone = true;
|
|
|
|
m_stats.aim = false;
|
|
m_stats.crouch = false;
|
|
m_stats.prone = false;
|
|
m_stats.prone = false;
|
|
// [kirill] need this to use only z component of entity angles (same as for drawing)
|
|
// when calculating BBox
|
|
GetEntity()->SetFlags( ETY_FLAG_CALCBBOX_ZROTATE );
|
|
|
|
m_Running = false;
|
|
#if defined(LINUX64)
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, 0);
|
|
#else
|
|
m_pEntity->SendScriptEvent(ScriptEvent_StanceChange, NULL);
|
|
#endif
|
|
m_bStayCrouch = false;
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
m_bStayCrouch = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
// returns true if slope angle is ok to be in prone (not too steep) AND not falling/jumping
|
|
bool CPlayer::CanProne(bool ignoreSpam)
|
|
{
|
|
float slopeProneLimit=.7f;
|
|
|
|
// don't go to prone mode if using mounted weapon
|
|
if(m_pMountedWeapon)
|
|
return false;
|
|
|
|
//prevent prone-standing position spamming
|
|
if (!ignoreSpam && m_fLastProneTime > m_pTimer->GetCurrTime())
|
|
return false;
|
|
|
|
// don't go to prone mode if falling/jumping
|
|
if(m_FlyTime>.5f && m_CurStance!=eSwim)
|
|
return false;
|
|
|
|
if(!m_pEntity->GetPhysics())
|
|
return false;
|
|
|
|
pe_status_living pStat;
|
|
m_pEntity->GetPhysics()->GetStatus(&pStat);
|
|
m_vProneEnvNormal = (Vec3d)pStat.groundSlope;
|
|
ray_hit hit;
|
|
Vec3d pos=m_pEntity->GetPos();
|
|
int hitCount=0;
|
|
float fHitCount=1.0f;
|
|
if( m_vProneEnvNormal.z>slopeProneLimit )
|
|
++hitCount;
|
|
|
|
pos.z += .3f;
|
|
pos.x += .1f;
|
|
if (m_pGame->GetSystem()->GetIPhysicalWorld()->RayWorldIntersection( pos, vectorf(0,0,-1.5f),
|
|
ent_all-ent_independent, rwi_stop_at_pierceable | geom_colltype_player<<rwi_colltype_bit,&hit,
|
|
1, GetEntity()->GetPhysics()))
|
|
{
|
|
m_vProneEnvNormal += hit.n;
|
|
++fHitCount;
|
|
if( hit.n.z>slopeProneLimit )
|
|
++hitCount;
|
|
}
|
|
pos.x -= .2f;
|
|
if (m_pGame->GetSystem()->GetIPhysicalWorld()->RayWorldIntersection( pos, vectorf(0,0,-1.5f),
|
|
ent_all-ent_independent, rwi_stop_at_pierceable | geom_colltype_player<<rwi_colltype_bit,&hit,
|
|
1, GetEntity()->GetPhysics()))
|
|
{
|
|
m_vProneEnvNormal += hit.n;
|
|
++fHitCount;
|
|
if( hit.n.z>slopeProneLimit )
|
|
++hitCount;
|
|
}
|
|
pos.x += .1f;
|
|
pos.y += .1f;
|
|
if (m_pGame->GetSystem()->GetIPhysicalWorld()->RayWorldIntersection( pos, vectorf(0,0,-1.5f),
|
|
ent_all-ent_independent, rwi_stop_at_pierceable | geom_colltype_player<<rwi_colltype_bit,&hit,
|
|
1, GetEntity()->GetPhysics()))
|
|
{
|
|
m_vProneEnvNormal += hit.n;
|
|
++fHitCount;
|
|
if( hit.n.z>slopeProneLimit )
|
|
++hitCount;
|
|
}
|
|
pos.y -= .2f;
|
|
if (m_pGame->GetSystem()->GetIPhysicalWorld()->RayWorldIntersection( pos, vectorf(0,0,-1.5f),
|
|
ent_all-ent_independent, rwi_stop_at_pierceable | geom_colltype_player<<rwi_colltype_bit,&hit,
|
|
1, GetEntity()->GetPhysics()))
|
|
{
|
|
m_vProneEnvNormal += hit.n;
|
|
++fHitCount;
|
|
if( hit.n.z>slopeProneLimit )
|
|
++hitCount;
|
|
}
|
|
|
|
// there are no points with allowed slope around - can't prone here
|
|
if( hitCount<1 )
|
|
return false;
|
|
|
|
m_vProneEnvNormal = m_vProneEnvNormal/fHitCount;
|
|
|
|
// can't prone when standing on boat/car
|
|
IPhysicalEntity *physEnt = m_pEntity->GetPhysics();
|
|
if (physEnt)
|
|
{
|
|
pe_status_living status;
|
|
if (physEnt->GetStatus(&status))
|
|
{
|
|
if(status.pGroundCollider)
|
|
{
|
|
IEntity* pEnt=(IEntity*)status.pGroundCollider->GetForeignData();
|
|
if(pEnt && pEnt->GetContainer())
|
|
{
|
|
CVehicle* pVehicleBelow;
|
|
if(pEnt->GetContainer()->QueryContainerInterface(CIT_IVEHICLE,(void**)&pVehicleBelow))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
// returns true if switch to stance or already in stance, otherwise return false
|
|
bool CPlayer::GoRelaxed( )
|
|
{
|
|
if(!GoStand())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_PrevStance = m_CurStance;
|
|
m_CurStance = eRelaxed;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
bool CPlayer::RestorePrevStence()
|
|
{
|
|
switch( m_PrevStance )
|
|
{
|
|
case eStand:
|
|
case eSwim:
|
|
return GoStand();
|
|
case eStealth:
|
|
return GoStealth();
|
|
case eCrouch:
|
|
return GoCrouch();
|
|
case eProne:
|
|
return GoProne();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
// for debug/test purposes -
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::StartFire()
|
|
{
|
|
Vec3d pos = m_pEntity->GetPos();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
/*void CPlayer::PlaySound(ISound * pSound, float fSoundScale, Vec3d &Offset)
|
|
{
|
|
if(IsMyPlayer())
|
|
{
|
|
m_lstAttachedSounds.push_back(SAttachedSound(pSound, Offset));
|
|
pSound->SetPosition(CalcSoundPos());
|
|
}
|
|
else
|
|
{
|
|
pSound->SetPosition(m_pEntity->GetPos());
|
|
}
|
|
pSound->Play(fSoundScale);
|
|
}*/
|
|
|
|
Vec3d CPlayer::CalcSoundPos()
|
|
{
|
|
IEntityCamera *pEC;
|
|
if (IsMyPlayer() && (pEC=m_pEntity->GetCamera()))
|
|
{
|
|
CCamera &cam=pEC->GetCamera();
|
|
Vec3d vPos=cam.GetPos();
|
|
vPos+=cam.m_vOffset;
|
|
Vec3d vAngles=cam.GetAngles();
|
|
Vec3d vTrans=vPos-cam.GetPos();
|
|
Matrix44 vRot;
|
|
vRot.SetIdentity();
|
|
//rotate the matrix ingnoring the Y rotation
|
|
//vRot.RotateMatrix(Vec3d(vAngles.x,0,vAngles.z));
|
|
vRot=Matrix44::CreateRotationZYX(-Vec3d(vAngles.x,0,vAngles.z)*gf_DEGTORAD)*vRot; //NOTE: angles in radians and negated
|
|
vPos=vRot.TransformPointOLD(vTrans);
|
|
//translate back
|
|
vPos+=cam.GetPos();
|
|
return vPos;
|
|
}
|
|
return m_pEntity->GetPos();
|
|
}
|
|
|
|
|
|
// calculates vertical and horizontal speed to make player jump on dist and height
|
|
void CPlayer::CalcJumpSpeed( float dist, float height, float &horV, float &vertV )
|
|
{
|
|
assert(height>=0.0f);
|
|
// vz = srtq(2*g*h)
|
|
// vx = len*g/(2*vz)
|
|
float fGravity;
|
|
|
|
//we are using a different gravity for jump? use it to calculate jump speeds.
|
|
if (m_Dynamics.jump_gravity!=1E10)
|
|
fGravity = m_Dynamics.jump_gravity;
|
|
else
|
|
fGravity = m_Dynamics.gravity;
|
|
|
|
fGravity *= m_pGame->p_gravity_modifier->GetFVal();
|
|
|
|
vertV = cry_sqrtf( 2.0f*fGravity*height );
|
|
// horV = dist*m_Dynamics.gravity/( 2.0f*vertV );
|
|
|
|
if(height!=0.0f) horV=(dist*cry_sqrtf(fGravity)) / (2*cry_sqrtf(2*height));
|
|
else horV=0.0f;
|
|
}
|
|
|
|
void CPlayer::SetViewMode(bool bThirdPerson)
|
|
{
|
|
if(!IsMyPlayer())
|
|
return;
|
|
|
|
if( !bThirdPerson )
|
|
{
|
|
m_pEntity->DrawCharacter(0, 0);
|
|
m_pEntity->NeedsUpdateCharacter(0, true);
|
|
}
|
|
else
|
|
{
|
|
if (m_stats.bModelHidden)
|
|
m_pEntity->DrawCharacter(0, 0);
|
|
else
|
|
m_pEntity->DrawCharacter(0, 1);
|
|
}
|
|
|
|
|
|
// if( !bThirdPerson && IsMyPlayer() )
|
|
// {
|
|
// m_pEntity->DrawCharacter(0, 0);
|
|
// m_pEntity->NeedsUpdateCharacter(0, true);
|
|
// }
|
|
}
|
|
|
|
|
|
/*
|
|
// calcualtes aproximate point of lending for granade on terrain
|
|
// firePos - start point
|
|
// dir - normolized direction
|
|
// vel - velocity
|
|
// timeStep - time interval for iteration
|
|
// timeLimit - time to stop iterations if no collision with terrain is detected
|
|
Vec3d CPlayer::TraceGrenade( const Vec3d& firePos, const Vec3d& dir, const float vel,
|
|
const float timeStep, const float timeLimit)
|
|
{
|
|
Vec3d curPos;
|
|
float time = 0.0f;
|
|
curPos = firePos;
|
|
while( curPos.z > m_p3DEngine->GetTerrainElevation(curPos.x, curPos.y) && time<timeLimit)
|
|
{
|
|
curPos.x = time*dir.x*vel + firePos.x;
|
|
curPos.y = time*dir.y*vel + firePos.y;
|
|
curPos.z = m_Dynamics.gravity*time*time/2.0f + dir.z*vel*time + firePos.z;
|
|
time += timeStep;
|
|
}
|
|
|
|
curPos.z = m_p3DEngine->GetTerrainElevation(curPos.x, curPos.y);
|
|
return curPos;
|
|
}
|
|
*/
|
|
|
|
void CPlayer::SwitchFiremode(int nforce)
|
|
{
|
|
if (m_nSelectedWeaponID != -1)
|
|
{
|
|
WeaponParams temp;
|
|
bool bChanged = true, bCanSwitch;
|
|
int iNewFireMode;
|
|
CWeaponClass* pSelectedWeapon = GetSelectedWeapon();
|
|
WeaponInfo &wi = GetWeaponInfo();
|
|
|
|
if(nforce==-1)
|
|
{
|
|
// Check what the next firemode would be, bChanged will be false in case
|
|
// we can't switch to another mode
|
|
iNewFireMode = pSelectedWeapon->GetNextFireMode(wi.iFireMode, m_bIsAI);
|
|
}
|
|
else
|
|
{
|
|
iNewFireMode=nforce;
|
|
}
|
|
|
|
bChanged = (wi.iFireMode != iNewFireMode);
|
|
|
|
if (bChanged && (!m_stats.reloading) && (!m_stats.weapon_busy))
|
|
{
|
|
// Call the script to find out if we can switch
|
|
_SmartScriptObject pObj(m_pScriptSystem);
|
|
pObj->SetValue( "firemode",iNewFireMode);
|
|
pSelectedWeapon->ScriptOnStopFiring(m_pEntity);
|
|
m_stats.firemode=iNewFireMode;
|
|
m_pEntity->SendScriptEvent(ScriptEvent_FireModeChange, *pObj, &bCanSwitch);
|
|
|
|
// Apply the change to the C++ state
|
|
wi.iFireMode = iNewFireMode;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPlayer::CounterAdd( const string name, const float timeScale )
|
|
{
|
|
CountersMap::iterator counter = m_UpdatedCounters.find( name );
|
|
if( counter == m_UpdatedCounters.end() )
|
|
{
|
|
couterEntry newEntry;
|
|
newEntry.scale = timeScale;
|
|
m_UpdatedCounters[name] = newEntry;
|
|
}
|
|
else
|
|
{
|
|
(counter->second).scale = timeScale;
|
|
}
|
|
}
|
|
|
|
void CPlayer::CounterIncrement( const string name, const float value )
|
|
{
|
|
CountersMap::iterator counter = m_UpdatedCounters.find( name );
|
|
if( counter == m_UpdatedCounters.end() )
|
|
return;
|
|
(counter->second).value += value;
|
|
}
|
|
|
|
float CPlayer::CounterGetValue( const string name )
|
|
{
|
|
CountersMap::iterator counter = m_UpdatedCounters.find( name );
|
|
if( counter == m_UpdatedCounters.end() )
|
|
return 0.0f;
|
|
|
|
return (counter->second).value;
|
|
|
|
}
|
|
|
|
void CPlayer::CounterUpdateAll( const float dt )
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
CountersMap::iterator counter = m_UpdatedCounters.begin( );
|
|
for(; counter!=m_UpdatedCounters.end(); counter++ )
|
|
{
|
|
float prevValue = (counter->second).value;
|
|
(counter->second).value += (counter->second).scale*dt;
|
|
|
|
if( prevValue<(counter->second).eventTrhld && (counter->second).value>(counter->second).eventTrhld )
|
|
{
|
|
IAIObject *pObject = m_pEntity->GetAI();
|
|
if (pObject)
|
|
{
|
|
pObject->SetSignal(1, (counter->second).eventToCall.c_str());
|
|
}
|
|
}
|
|
if((counter->second).value < 0.0f)
|
|
(counter->second).value = 0.0f;
|
|
}
|
|
}
|
|
|
|
void CPlayer::CounterSetValue( const string name, const float value )
|
|
{
|
|
CountersMap::iterator counter = m_UpdatedCounters.find( name );
|
|
if( counter == m_UpdatedCounters.end() )
|
|
return;
|
|
|
|
(counter->second).value = value;
|
|
}
|
|
|
|
void CPlayer::CounterSetEvent( const string name, const float thrhld, const string eventName )
|
|
{
|
|
CountersMap::iterator counter = m_UpdatedCounters.find( name );
|
|
if( counter == m_UpdatedCounters.end() )
|
|
return;
|
|
(counter->second).eventToCall = eventName;
|
|
(counter->second).eventTrhld = thrhld;
|
|
}
|
|
|
|
// attaches weapon to weapon bone on character's back
|
|
void CPlayer::HolsterWeapon(void)
|
|
{
|
|
SetWeaponPositionState(WEAPON_POS_HOLSTER);
|
|
}
|
|
|
|
// rebinds weapon to be bound to the weapon bone in the characters hands
|
|
void CPlayer::HoldWeapon(void)
|
|
{
|
|
SetWeaponPositionState(WEAPON_POS_HOLD);
|
|
}
|
|
|
|
void CPlayer::SetWeaponPositionState(EWeaponPositionState weaponPositionState)
|
|
{
|
|
assert (IsHeapValid());
|
|
|
|
// attach to bone ?
|
|
if (m_nSelectedWeaponID != -1 && m_weaponPositionState != weaponPositionState)
|
|
{
|
|
CWeaponClass* pSelectedWeapon = GetSelectedWeapon();
|
|
m_weaponPositionState = weaponPositionState;
|
|
ICryCharInstance *character = m_pEntity->GetCharInterface()->GetCharacter(PLAYER_MODEL_IDX);
|
|
WeaponInfo &wi = GetWeaponInfo();
|
|
|
|
assert (IsHeapValid());
|
|
if (character)
|
|
{
|
|
wi.DetachBindingHandles(character);
|
|
|
|
if (weaponPositionState == WEAPON_POS_UNDEFINED)
|
|
return;
|
|
|
|
// ValidateHeap();
|
|
string sBone = pSelectedWeapon->GetBindBone();
|
|
// ValidateHeap();
|
|
|
|
if (!sBone.empty())
|
|
{
|
|
// ValidateHeap();
|
|
if (weaponPositionState == WEAPON_POS_HOLSTER)
|
|
sBone+="02";
|
|
|
|
// ValidateHeap();
|
|
wi.hBindInfo = character->AttachObjectToBone( pSelectedWeapon->GetObject(), sBone.c_str() );
|
|
// ValidateHeap();
|
|
|
|
// if there is an auxilary weapon bone, attach to that as well
|
|
string sAuxBone = "aux_" + sBone;
|
|
if (character->GetModel()->GetBoneByName(sAuxBone.c_str())>=0)
|
|
{
|
|
wi.hAuxBindInfo = character->AttachObjectToBone( pSelectedWeapon->GetObject(), sAuxBone.c_str() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
character->DetachAll();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
void CPlayer::SetBlendTime(const char *sAniName, float fBlendTime)
|
|
{
|
|
if(strlen(sAniName)<3) // it has to be some name
|
|
return;
|
|
m_AniBlendTimes[sAniName] = fBlendTime;
|
|
}
|
|
|
|
void CPlayer::GetBlendTime(const char *sAniName, float&fBlendTime)
|
|
{
|
|
BlendTimesMap::iterator curAni=m_AniBlendTimes.find(sAniName);
|
|
if( curAni == m_AniBlendTimes.end() )
|
|
return;
|
|
fBlendTime = (curAni->second);
|
|
}
|
|
|
|
void CPlayer::UpdateCollisionDamage( )
|
|
{
|
|
// Get a pointer to the physics engine
|
|
IPhysicalEntity *physEnt = m_pEntity->GetPhysics();
|
|
if (!physEnt)
|
|
return;
|
|
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
// Create a new status object.
|
|
pe_status_collisions status;
|
|
coll_history_item history[4];
|
|
memset( history, 0, sizeof(history) );
|
|
status.pHistory = history;
|
|
status.len = 4;
|
|
status.bClearHistory = true;
|
|
status.age = .1f;
|
|
int colN=0,imax;
|
|
float massLimitMin=50.0f;
|
|
float massLimitMax=80.0f;
|
|
float velLimit=3;//10;//6.5f;
|
|
if ((m_timeDmgCollision+=m_pTimer->GetFrameTime())>2.0f)
|
|
{
|
|
m_timeDmgCollision = 0; m_pPrevDmgCollider = 0;
|
|
}
|
|
|
|
// Get new player status from physics engine
|
|
if (colN=physEnt->GetStatus(&status))
|
|
{
|
|
float damageValue = 0.0f;
|
|
//find the most damaging collision in history
|
|
|
|
for(imax=-1 ; colN>0; colN--)
|
|
{
|
|
float curVel = max(0.0f,history[colN-1].v[1]*history[colN-1].n);
|
|
if(history[colN-1].mass[1]<=massLimitMin || curVel<velLimit)
|
|
continue;
|
|
float curDamage = (history[colN-1].mass[1]<massLimitMax ? history[colN-1].mass[1] : massLimitMax)*curVel;
|
|
IPhysicalEntity *pCollider = m_pPhysicalWorld->GetPhysicalEntityById(history[colN-1].idCollider);
|
|
if (pCollider==m_pPrevDmgCollider && curDamage<m_prevCollDamage*1.2f)
|
|
continue;
|
|
if(damageValue < curDamage)
|
|
damageValue = curDamage, imax = colN-1;
|
|
}
|
|
//m_pGame->GetSystem()->GetILog()->Log( "\002 %d collision %s %.2f %.2f ", colN, GetName(), history[0].collMass, history[0].vrel.len() );
|
|
if(damageValue>=1.0f)
|
|
{
|
|
_SmartScriptObject pTable(m_pScriptSystem,false);
|
|
CScriptObjectVector oDir(m_pScriptSystem); oDir=history[imax].n;
|
|
pTable->SetValue("dir",*oDir);
|
|
pTable->SetValue("damage",damageValue);
|
|
pTable->SetValue("collider_mass",history[imax].mass[1]);
|
|
pTable->SetValue("collider_velocity",-history[imax].v[1]*history[imax].n);
|
|
IPhysicalEntity *pCollider = m_pPhysicalWorld->GetPhysicalEntityById(history[imax].idCollider);
|
|
if (pCollider)
|
|
{
|
|
IEntity *pEntCollider = (IEntity*)pCollider->GetForeignData();
|
|
if (pEntCollider)
|
|
pTable->SetValue("collider",pEntCollider->GetScriptObject());
|
|
}
|
|
|
|
m_pEntity->SendScriptEvent( ScriptEvent_PhysCollision , pTable);
|
|
//m_pGame->GetSystem()->GetILog()->Log( "\002 collision %s %.1f %d %.1f ", GetName(), damageValue, m_stats.health, maxVel);
|
|
m_pPrevDmgCollider = pCollider;
|
|
m_prevCollDamage = damageValue;
|
|
m_timeDmgCollision = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CPlayer::SetSpeedMult( float run, float crouch, float prone, float xrun, float xwalk, float rrun, float rwalk )
|
|
{
|
|
m_RunSpeedScale = run;
|
|
m_CrouchSpeedScale = crouch;
|
|
m_ProneSpeedScale = prone;
|
|
m_XRunSpeedScale = xrun; // stealth
|
|
m_XWalkSpeedScale = xwalk;
|
|
m_RRunSpeedScale = rrun; // relaxed
|
|
m_RWalkSpeedScale = rwalk;
|
|
}
|
|
|
|
|
|
//
|
|
//-----------------------------------------------------------------
|
|
|
|
|
|
void CPlayer::OnDrawMountedWeapon( const SRendParams & RendParams )
|
|
{
|
|
if(m_nSelectedWeaponID == -1)
|
|
return;
|
|
|
|
// if the localplayer is using the mounted weapon, only then do we disable the first person weapon drawing
|
|
if( m_pMountedWeapon && IsMyPlayer())
|
|
{
|
|
m_pMountedWeapon->DrawObject(0,ETY_DRAW_NORMAL);
|
|
m_pMountedWeapon->DrawCharacter(0,ETY_DRAW_NORMAL);
|
|
|
|
Vec3d apos, aang;
|
|
GetFirePosAngles( apos, aang );
|
|
|
|
apos = m_pMountedWeapon->GetAngles(1);
|
|
// if(IsMyPlayer())
|
|
m_pMountedWeapon->SetAngles( aang, false, false, true );
|
|
// else
|
|
// m_pMountedWeapon->SetAngles( m_pEntity->GetAngles(), false, false, true );
|
|
|
|
m_pMountedWeapon->ForceCharacterUpdate(0);
|
|
m_pMountedWeapon->DrawEntity(RendParams);
|
|
|
|
m_pMountedWeapon->SetAngles( apos );
|
|
m_pMountedWeapon->DrawObject(0,ETY_DRAW_NONE); // we don't want to draw it (already drawn by player)
|
|
m_pMountedWeapon->DrawCharacter(0,ETY_DRAW_NONE);
|
|
m_pMountedWeapon->NeedsUpdateCharacter( 0, true); // but we want to update animation for it
|
|
|
|
GetEntity()->DrawCharacter(1, ETY_DRAW_NONE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void CPlayer::UpdateCharacterAnimationsMounted( SPlayerUpdateContext &ctx )
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
|
|
m_pEntity->SetAnimationSpeed( 1.0f );
|
|
if( m_pVehicle ) // mounted weapon on vehicle - don't do any animation
|
|
return;
|
|
|
|
float diff = m_pEntity->GetAngles().z - m_vPrevMntPos.z;
|
|
float vel = diff/m_pTimer->GetFrameTime();
|
|
|
|
//if(diff!=0)
|
|
//m_pGame->m_pLog->Log(" %.2f %.2f %.2f\n", diff, vel, m_pEntity->GetAngles().z );
|
|
|
|
string aniName;
|
|
/*
|
|
if(fabsf(vel)>50.6f) // too slow - no animations
|
|
{
|
|
m_RunningTime += m_pTimer->GetFrameTime();
|
|
}
|
|
else
|
|
{
|
|
m_RunningTime = 0;
|
|
}
|
|
*/
|
|
// if( m_RunningTime<.1f )
|
|
if( fabsf(vel)<60.6f )
|
|
aniName = "mount_fwd";
|
|
else
|
|
{
|
|
if( diff<0 )
|
|
aniName = "mount_left";//"arotateright";
|
|
else
|
|
// aniName = "srotateleft";
|
|
aniName = "mount_right";//"arotateleft";
|
|
|
|
// float speedScale = 1 + (fabsf(vel)-60)*.5f;
|
|
// m_pEntity->SetAnimationSpeed( speedScale );
|
|
}
|
|
|
|
m_RunningTime += m_pTimer->GetFrameTime();
|
|
if(m_sPrevAniName != aniName)
|
|
{
|
|
if(aniName == "mount_fwd")
|
|
{
|
|
if( m_MntWeaponStandTime>.3f )
|
|
{
|
|
if(m_pEntity->StartAnimation(0, aniName.c_str(), 0, .25f ))
|
|
m_sPrevAniName = aniName;
|
|
// m_RunningTime = 0;
|
|
}
|
|
m_MntWeaponStandTime += m_pTimer->GetFrameTime();
|
|
}
|
|
else
|
|
{
|
|
if(m_pEntity->StartAnimation(0, aniName.c_str(), 0, .25f ))
|
|
m_sPrevAniName = aniName;
|
|
m_MntWeaponStandTime = 0.0f;
|
|
}
|
|
}
|
|
m_vPrevMntPos = m_pEntity->GetAngles();
|
|
return;
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
//m_pEntity->StartAnimation(0, "awalkback", 0, .1 );
|
|
//return;
|
|
Vec3d diff = m_pEntity->GetPos() - m_vPrevMntPos;
|
|
//Ang3 playerDir = GetActualAngles();
|
|
Vec3d playerDir = m_pEntity->GetAngles();
|
|
|
|
playerDir = ConvertToRadAngles(playerDir);
|
|
playerDir.z=0;
|
|
playerDir.normalize();
|
|
diff.z=0;
|
|
float dist = diff.len();
|
|
float vel = dist/m_pTimer->GetFrameTime();
|
|
diff.normalize();
|
|
|
|
float dotz = playerDir.x*diff.x + playerDir.y*diff.y;
|
|
float crossz = playerDir.x * diff.y - playerDir.y * diff.x;
|
|
string aniName;
|
|
|
|
if(vel<.6f) // too slow - no animations
|
|
{
|
|
m_NotRunTime += m_pTimer->GetFrameTime();
|
|
}
|
|
else
|
|
{
|
|
m_NotRunTime = 0;
|
|
}
|
|
|
|
|
|
if( m_NotRunTime>.2f )//|| fabsf(crossz)<.3 )
|
|
aniName = "sidle";
|
|
else if( crossz<0 )
|
|
aniName = "awalkfwd";//"arotateright";
|
|
else
|
|
aniName = "srotateleft";
|
|
// aniName = "swalkback";//"arotateleft";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(m_sPrevAniNameLayer1 != aniName)
|
|
if(m_pEntity->StartAnimation(0, aniName.c_str(), 0, .1 ))
|
|
m_sPrevAniNameLayer1 = aniName;
|
|
|
|
m_vPrevMntPos = m_pEntity->GetPos();
|
|
return;
|
|
*/
|
|
}
|
|
|
|
void CPlayer::GiveBinoculars(bool val)
|
|
{
|
|
if (m_stats.has_binoculars == val)
|
|
return;
|
|
|
|
m_stats.has_binoculars = val;
|
|
|
|
// FIXME ... if the binoculars are take away, then we should reset the viewlayer (must be done
|
|
// on the script side
|
|
}
|
|
|
|
void CPlayer::PreloadInstanceResources(Vec3d vPrevPortalPos, float fPrevPortalDistance, float fTime)
|
|
{
|
|
int nRecursionLevel = (int)m_pGame->GetSystem()->GetIRenderer()->EF_Query(EFQ_RecurseLevel) - 1;
|
|
if(m_bFirstPerson && !nRecursionLevel && m_stats.drawfpweapon && m_nSelectedWeaponID != -1)
|
|
return;
|
|
|
|
ICryCharInstance *pChar = m_pEntity->GetCharInterface()->GetCharacter(0);
|
|
if (!pChar)
|
|
return;
|
|
|
|
if (!(pChar->GetFlags() & CS_FLAG_DRAW_MODEL) && !nRecursionLevel)
|
|
return;
|
|
|
|
float fDist = fPrevPortalDistance + vPrevPortalPos.GetDistance(m_pEntity->GetPos());
|
|
pChar->PreloadResources(fDist, 1.f, 0);
|
|
}
|
|
|
|
void CPlayer::SetStaminaTable( const StaminaTable& stTable )
|
|
{
|
|
m_StaminaTable = stTable;
|
|
}
|
|
|
|
|
|
void CPlayer::UpdateStamina( float dTime )
|
|
{
|
|
// stamina (for sprint run) update
|
|
// update breath (blue bar)
|
|
if(m_stats.underwater>0.0f) //we are under water - decrease breath level
|
|
{
|
|
if(m_stats.stamina>0) // if there is some stamina -
|
|
{
|
|
if((m_stats.stamina-=dTime*m_StaminaTable.BreathDecoyUnderwater)<0)
|
|
m_stats.stamina = 0;
|
|
}
|
|
}
|
|
else if( m_stats.holding_breath ) // we are sniping/holding breath - decrease breath level
|
|
{
|
|
if((m_stats.stamina-=dTime*m_StaminaTable.BreathDecoyAim)<1.0f)
|
|
m_stats.stamina = 1.0f;
|
|
}
|
|
// update stamina (yellow bar)
|
|
else if( m_Sprinting )
|
|
{
|
|
if((m_stats.stamina -= dTime*m_StaminaTable.DecoyRun)<1.0f)
|
|
m_stats.stamina = 1.0f;
|
|
}
|
|
// restore stamina - player is resting
|
|
else if(m_stats.stamina<100 && (!m_stats.flying || m_bSwimming&&m_stats.underwater<=0.0f ))
|
|
{
|
|
if(m_Running)
|
|
m_stats.stamina += dTime*m_StaminaTable.RestoreRun;
|
|
else
|
|
m_stats.stamina += dTime*m_StaminaTable.RestoreWalk;
|
|
if(m_stats.stamina>100)
|
|
m_stats.stamina = 100;
|
|
}
|
|
// to indicate stamina on HUD
|
|
m_StaminaTable.StaminaHUD = m_stats.stamina*0.01f;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CPlayer::IsVisible() const
|
|
{
|
|
if(m_pGame->IsServer() && m_pGame->IsMultiplayer())
|
|
return true;
|
|
|
|
if (m_pEntity)
|
|
{
|
|
// If was rendered recently.
|
|
int nCurrRenderFrame = (int)m_pGame->GetSystem()->GetIRenderer()->GetFrameID();
|
|
if (abs(nCurrRenderFrame-m_pEntity->GetDrawFrame(0)) < 3)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CPlayer::UpdateSwimState(bool bAlive)
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(),PROFILE_GAME );
|
|
// check if the player goes underwater.
|
|
//if (m_p3DEngine->GetWaterLevel(&m_vEyePos)>m_vEyePos.z)
|
|
float fWaterLevel=m_p3DEngine->GetWaterLevel(m_pEntity);
|
|
m_stats.fInWater=fWaterLevel-m_pEntity->GetPos().z;
|
|
if (m_stats.fInWater<0.0f)
|
|
m_stats.fInWater=0.0f;
|
|
Vec3 vPos=m_vEyePos;
|
|
if (!bAlive && !IsMyPlayer())
|
|
{
|
|
SetEyePosBone();
|
|
vPos=m_vEyePos;
|
|
//vPos=m_pEntity->GetPos();
|
|
}
|
|
|
|
if (fWaterLevel>vPos.z)
|
|
{
|
|
// if that is the case, start the EAX underwater effect
|
|
// plus increase the underwater time
|
|
m_stats.underwater+=m_pTimer->GetFrameTime();
|
|
if (!m_bIsAI)
|
|
if(m_pGame->GetSystem()->GetISoundSystem())
|
|
m_pGame->GetSystem()->GetISoundSystem()->SetEaxListenerEnvironment(EAX_PRESET_UNDERWATER);
|
|
|
|
// also call the script function to play the water splash sounds and
|
|
// other stuff it this is the first time it goes underwater
|
|
if (!m_bEyesInWater)
|
|
{
|
|
m_pEntity->SendScriptEvent(ScriptEvent_EnterWater,0);
|
|
m_bEyesInWater=true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// remove EAX underwater, if he was in the water before
|
|
if ((m_stats.underwater>0.001f) && (!m_bIsAI)) // epsilon
|
|
if(m_pGame->GetSystem()->GetISoundSystem())
|
|
m_pGame->GetSystem()->GetISoundSystem()->SetEaxListenerEnvironment(EAX_PRESET_OFF);
|
|
m_stats.underwater=0.0f;
|
|
m_bEyesInWater=false;
|
|
}
|
|
m_stats.fKWater = 0;
|
|
// no need for anymore checks if dead - only eyesInWater updated
|
|
if(!IsAlive())
|
|
{
|
|
m_bSwimming = false;
|
|
return;
|
|
}
|
|
// ladder is priority to swim
|
|
if(m_stats.onLadder)
|
|
{
|
|
m_bSwimming = false;
|
|
return;
|
|
}
|
|
|
|
// in vehicle is priority to swim
|
|
if(m_pVehicle)
|
|
{
|
|
m_bSwimming = false;
|
|
return;
|
|
}
|
|
|
|
// not in water
|
|
if(fWaterLevel < -500)
|
|
{
|
|
m_bSwimming = false;
|
|
return;
|
|
}
|
|
|
|
|
|
// if(m_stats.fInWater<)
|
|
/*
|
|
//[kirill]
|
|
//fixme
|
|
//remove this
|
|
//the check is for cathching strange positon outorrange problem
|
|
//if( m_pGame->pa_blend2->GetFVal()>0.0f )
|
|
{
|
|
Vec3d pos = m_pEntity->GetPos();
|
|
if(pos.z<-100 || pos.z>500 ||
|
|
pos.x<=0 || pos.x>10000 ||
|
|
pos.y<=0 || pos.y>10000
|
|
)
|
|
{
|
|
if(IsAlive())
|
|
m_pGame->m_pLog->Log("\006 alive player < %s > position is invalid %.2f %.2f %.2f \n", m_pEntity->GetName(), pos.x, pos.y, pos.z );
|
|
else
|
|
m_pGame->m_pLog->Log("\006 dead player < %s > position is invalid %.2f %.2f %.2f \n", m_pEntity->GetName(), pos.x, pos.y, pos.z );
|
|
}
|
|
}
|
|
//remove this over
|
|
*/
|
|
|
|
// to use value depending on current stance
|
|
float depthOffset;// = GetEntity()->GetCamera()->GetCamOffset().z;
|
|
//AIs don't have camera offset - use fixed value (could use eyeHeight)
|
|
if( m_bIsAI )
|
|
depthOffset = 1.5f;
|
|
else
|
|
{
|
|
switch( m_CurStance )
|
|
{
|
|
case eProne:
|
|
case eSwim:
|
|
depthOffset = .45f;
|
|
break;
|
|
// case eStand:
|
|
default:
|
|
depthOffset = 1.5f;
|
|
break;
|
|
}
|
|
}
|
|
//check if we are standing on something
|
|
pe_status_living status;
|
|
IPhysicalEntity *physEnt = m_pEntity->GetPhysics();
|
|
if (!physEnt || !physEnt->GetStatus(&status))
|
|
{
|
|
GameWarning( "Bad Phyics Entity for Player %s",m_pEntity->GetName() );
|
|
return;
|
|
}
|
|
if (status.pGroundCollider)
|
|
{
|
|
if( status.groundHeight+depthOffset > fWaterLevel )
|
|
{
|
|
m_bSwimming = false;
|
|
return;
|
|
}
|
|
}
|
|
//
|
|
if(m_pEntity->GetEntityVisArea()==0) // if outdoors - check how deep we are
|
|
{
|
|
Vec3 rPos = m_pEntity->GetPos();
|
|
bool bChanged = false;
|
|
if(_isnan(rPos.x))
|
|
{
|
|
bChanged = true;
|
|
rPos.x = 0;
|
|
}
|
|
if(_isnan(rPos.y))
|
|
{
|
|
bChanged = true;
|
|
rPos.y = 0;
|
|
}
|
|
if(_isnan(rPos.z))
|
|
{
|
|
bChanged = true;
|
|
rPos.z = 0;
|
|
}
|
|
if(bChanged)
|
|
m_pEntity->SetPos(rPos);
|
|
|
|
float fTerrainLevel=m_p3DEngine->GetTerrainElevation(m_pEntity->GetPos().x, m_pEntity->GetPos().y);
|
|
|
|
if(fWaterLevel - fTerrainLevel < depthOffset )//1.5f)
|
|
{
|
|
m_bSwimming = false;
|
|
return;
|
|
}
|
|
}
|
|
// else
|
|
if(fWaterLevel - m_pEntity->GetPos().z < depthOffset )//1.5f) // check if it's deep enough to sweem
|
|
{
|
|
vectorf pos = m_pEntity->GetPos();
|
|
pos.z = fWaterLevel;
|
|
ray_hit hit;
|
|
|
|
if (m_pGame->GetSystem()->GetIPhysicalWorld()->RayWorldIntersection( pos, vectorf(0,0,-1.5f), ent_all,
|
|
rwi_stop_at_pierceable,&hit,1, GetEntity()->GetPhysics()))
|
|
{
|
|
m_bSwimming = false;
|
|
return;
|
|
}
|
|
}
|
|
m_stats.fKWater = min(1.0f,m_stats.fInWater*(1.0f/.60f));
|
|
m_bSwimming = m_stats.fKWater>0.0f;
|
|
m_stats.fKWater*=m_stats.fKWater;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void CPlayer::DampInputVector(vectorf &vec ,float speed ,float stopspeed ,bool only2d ,bool linear)
|
|
{
|
|
if (speed<=0.0f)
|
|
return;
|
|
|
|
float spd = speed;
|
|
float saveZ = vec.z;
|
|
|
|
if (only2d)
|
|
vec.z = 0;
|
|
|
|
float goallen = vec.len();
|
|
|
|
if (goallen<0.001f)
|
|
spd = stopspeed;
|
|
|
|
vectorf delta = vec - m_vLastMotionDir;
|
|
|
|
if (linear)//if linear cap the delta to "ai_smoothvel"
|
|
{
|
|
float deltalen = delta.len();
|
|
|
|
if (deltalen>spd)
|
|
delta = delta * (deltalen==0?0.001f:1.0f/deltalen) * spd;
|
|
}
|
|
|
|
float dt = m_fLastDeltaTime;//m_pTimer->GetFrameTime();//m_pGame->GetSystem()->GetITimer()->GetFrameTime();
|
|
|
|
vec = m_vLastMotionDir + delta*min(dt*spd,1.0f);
|
|
|
|
if (vec.len()<0.001f)
|
|
vec.Set(0,0,0);
|
|
|
|
m_vLastMotionDir = vec;
|
|
|
|
if (only2d)
|
|
vec.z = saveZ;
|
|
}
|
|
|
|
void CPlayer::SaveAIState(CStream & stm, CScriptObjectStream & scriptStream)
|
|
{
|
|
IScriptSystem *pScriptSystem = m_pGame->GetSystem()->GetIScriptSystem();
|
|
HSCRIPTFUNCTION saveOverallFunction=NULL;
|
|
if( m_pEntity->GetScriptObject() && m_pEntity->GetScriptObject()->GetValue("OnSaveOverall", saveOverallFunction) )
|
|
{
|
|
pScriptSystem->BeginCall(saveOverallFunction);
|
|
pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject());
|
|
pScriptSystem->PushFuncParam(scriptStream.GetScriptObject());
|
|
pScriptSystem->EndCall();
|
|
}
|
|
|
|
if (!m_bIsAI)
|
|
return;
|
|
|
|
IAIObject *pObject = m_pEntity->GetAI();
|
|
|
|
pObject->Save(stm);
|
|
IPipeUser *pUser =0;
|
|
|
|
// save weapon state
|
|
int nGunOut = 0;
|
|
m_pEntity->GetScriptObject()->GetValue("AI_GunOut",nGunOut);
|
|
stm.Write(nGunOut);
|
|
|
|
ICryCharInstance *pCharacter = m_pEntity->GetCharInterface()->GetCharacter(0);
|
|
bool bAnimWritten = false;
|
|
if (pCharacter)
|
|
{
|
|
int nAnimID = pCharacter->GetCurrentAnimation(3);
|
|
if (nAnimID>=0)
|
|
{
|
|
ICryCharModel *pModel = pCharacter->GetModel();
|
|
if (pModel)
|
|
{
|
|
const char *szAnimName = pModel->GetAnimationSet()->GetName(nAnimID);
|
|
stm.Write(szAnimName);
|
|
bAnimWritten = true;
|
|
}
|
|
}
|
|
}
|
|
if (!bAnimWritten)
|
|
stm.Write("NA");
|
|
|
|
// save any conversation that this guy may be in
|
|
_SmartScriptObject pCurrentConversation(m_pScriptSystem,true);
|
|
if (m_pEntity->GetScriptObject()->GetValue("CurrentConversation",pCurrentConversation))
|
|
{
|
|
const char *szName;
|
|
pCurrentConversation->GetValue("NAME",szName);
|
|
stm.Write(szName);
|
|
int iProgress,conv_id;
|
|
pCurrentConversation->GetValue("CONV_ID",conv_id);
|
|
stm.Write(conv_id);
|
|
pCurrentConversation->GetValue("Progress",iProgress);
|
|
stm.Write(iProgress);
|
|
|
|
// save all the actors in the conversation
|
|
_SmartScriptObject pActors(m_pScriptSystem,true);
|
|
pCurrentConversation->GetValue("Actor",pActors);
|
|
int i=1;
|
|
stm.Write(pActors->Count());
|
|
while (i<=pActors->Count())
|
|
{
|
|
_SmartScriptObject pActorEntity(m_pScriptSystem,true);
|
|
if (pActors->GetAt(i,pActorEntity))
|
|
{
|
|
int Actor_ID;
|
|
pActorEntity->GetValue("id",Actor_ID);
|
|
stm.Write(Actor_ID);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
else
|
|
stm.Write("NA");
|
|
|
|
}
|
|
|
|
void CPlayer::LoadAIState(CStream & stm, CScriptObjectStream & scriptStream)
|
|
{
|
|
IScriptSystem *pScriptSystem = m_pGame->GetSystem()->GetIScriptSystem();
|
|
HSCRIPTFUNCTION loadOverallFunction=NULL;
|
|
if( m_pEntity->GetScriptObject() && m_pEntity->GetScriptObject()->GetValue("OnLoadOverall", loadOverallFunction) )
|
|
{
|
|
pScriptSystem->BeginCall(loadOverallFunction);
|
|
pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject());
|
|
pScriptSystem->PushFuncParam(scriptStream.GetScriptObject());
|
|
pScriptSystem->EndCall();
|
|
}
|
|
|
|
if (!m_bIsAI)
|
|
return;
|
|
|
|
IAIObject *pObject = m_pEntity->GetAI();
|
|
pObject->Load(stm);
|
|
|
|
int nGunOut=0;
|
|
stm.Read(nGunOut);
|
|
if (nGunOut)
|
|
{
|
|
SetWeaponPositionState(WEAPON_POS_HOLD);
|
|
m_pEntity->GetScriptObject()->SetValue("AI_GunOut",1);
|
|
|
|
m_pScriptSystem->BeginCall("BasicAI","MakeAlerted");
|
|
m_pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject());
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
char str[255];
|
|
stm.Read(str,255);
|
|
|
|
if (stricmp(str,"NA"))
|
|
{
|
|
ICryCharInstance *pCharacter = m_pEntity->GetCharInterface()->GetCharacter(0);
|
|
if (pCharacter)
|
|
{
|
|
CryCharAnimationParams ccap;
|
|
ccap.fBlendInTime = 0;
|
|
ccap.fBlendOutTime = 0;
|
|
ccap.nLayerID = 3;
|
|
pCharacter->StartAnimation(str,ccap);
|
|
}
|
|
}
|
|
|
|
|
|
stm.Read(str,255);
|
|
if (stricmp(str,"NA"))
|
|
{
|
|
_SmartScriptObject pCurrentConversation(m_pScriptSystem,true);
|
|
if (!m_pEntity->GetScriptObject()->GetValue("CurrentConversation",pCurrentConversation))
|
|
{
|
|
// get the saved conversation
|
|
int conv_id;
|
|
stm.Read(conv_id);
|
|
_SmartScriptObject pNewConversation(m_pScriptSystem,true);
|
|
_SmartScriptObject pConvManager(m_pScriptSystem,true);
|
|
m_pScriptSystem->GetGlobalValue("AI_ConvManager",pConvManager);
|
|
m_pScriptSystem->BeginCall("AI_ConvManager","GetSpecificConversation");
|
|
m_pScriptSystem->PushFuncParam(pConvManager);
|
|
m_pScriptSystem->PushFuncParam(str);
|
|
m_pScriptSystem->PushFuncParam(conv_id);
|
|
m_pScriptSystem->EndCall(pNewConversation);
|
|
|
|
// remember how far we were
|
|
stm.Read(conv_id);
|
|
// go back one line
|
|
if (conv_id>0)
|
|
conv_id--;
|
|
pNewConversation->SetValue("Progress",conv_id);
|
|
|
|
// now loop through all the actors and make them join this conversation
|
|
int nrActors,curr_actor=0;
|
|
stm.Read(nrActors);
|
|
while (curr_actor<nrActors)
|
|
{
|
|
int ActorID;
|
|
stm.Read(ActorID);
|
|
|
|
// get the entity
|
|
IEntity *pActorEntity = m_pGame->GetSystem()->GetIEntitySystem()->GetEntity(ActorID);
|
|
if (pActorEntity)
|
|
{
|
|
IScriptObject *pActorScriptObject = pActorEntity->GetScriptObject();
|
|
pActorScriptObject->SetValue("CurrentConversation",pNewConversation);
|
|
unsigned int funcHandle;
|
|
pNewConversation->GetValue("Join",funcHandle);
|
|
m_pScriptSystem->BeginCall(funcHandle);
|
|
m_pScriptSystem->PushFuncParam(pNewConversation);
|
|
m_pScriptSystem->PushFuncParam(pActorEntity->GetScriptObject());
|
|
m_pScriptSystem->EndCall();
|
|
|
|
}
|
|
curr_actor++;
|
|
}
|
|
|
|
// if joined is equal to amount of participants, continue the conversation
|
|
int iJoined,iParticipants;
|
|
pNewConversation->GetValue("Joined",iJoined);
|
|
pNewConversation->GetValue("Participants",iParticipants);
|
|
if (iJoined == iParticipants)
|
|
{
|
|
unsigned int funcHandle;
|
|
pNewConversation->GetValue("Continue",funcHandle);
|
|
m_pScriptSystem->BeginCall(funcHandle);
|
|
m_pScriptSystem->PushFuncParam(pNewConversation);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
int dummy;
|
|
stm.Read(dummy); //conv_id
|
|
stm.Read(dummy); //progress
|
|
int nrActors;
|
|
stm.Read(nrActors);
|
|
while (nrActors--)
|
|
stm.Read(dummy);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void CPlayer::LoadAIState_RELEASE(CStream & stm)
|
|
{
|
|
if (!m_bIsAI)
|
|
return;
|
|
|
|
IAIObject *pObject = m_pEntity->GetAI();
|
|
//AIObject Load is empty in release version
|
|
// pObject->Load(stm);
|
|
|
|
int nGunOut=0;
|
|
stm.Read(nGunOut);
|
|
if (nGunOut)
|
|
{
|
|
SetWeaponPositionState(WEAPON_POS_HOLD);
|
|
m_pEntity->GetScriptObject()->SetValue("AI_GunOut",1);
|
|
|
|
m_pScriptSystem->BeginCall("BasicAI","MakeAlerted");
|
|
m_pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject());
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
|
|
/*
|
|
if (!m_bIsAI)
|
|
return;
|
|
|
|
IAIObject *pObject = m_pEntity->GetAI();
|
|
//pObject->Load(stm);
|
|
|
|
IPipeUser *pUser =0;
|
|
if (pObject->CanBeConvertedTo(AIOBJECT_PIPEUSER,(void**)&pUser))
|
|
{
|
|
int nId;
|
|
stm.Read(nId);
|
|
if (nId)
|
|
{
|
|
if (nId<0)
|
|
{
|
|
// player is the target
|
|
IEntity *pMyPlayer = m_pGame->GetMyPlayer();
|
|
if (pMyPlayer)
|
|
{
|
|
SAIEVENT event;
|
|
event.bFuzzySight = false;
|
|
event.fThreat = 1000000.f;
|
|
event.pSeen = pMyPlayer->GetAI();
|
|
pObject->Event(AIEVENT_ONVISUALSTIMULUS,&event);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// some puppet or vehicle is the target
|
|
IEntity *pMyTarget = m_pGame->GetSystem()->GetIEntitySystem()->GetEntity(nId);
|
|
if (pMyTarget)
|
|
{
|
|
SAIEVENT event;
|
|
event.bFuzzySight = false;
|
|
event.fThreat = 1000000.f;
|
|
event.pSeen = pMyTarget->GetAI();
|
|
pObject->Event(AIEVENT_ONVISUALSTIMULUS,&event);
|
|
|
|
}
|
|
}
|
|
SetWeaponPositionState(WEAPON_POS_HOLD);
|
|
m_pEntity->GetScriptObject()->SetValue("AI_GunOut",1);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
void CPlayer::LoadAIState_PATCH_1(CStream & stm)
|
|
{
|
|
|
|
if (!m_bIsAI)
|
|
return;
|
|
|
|
IAIObject *pObject = m_pEntity->GetAI();
|
|
pObject->Load_PATCH_1(stm);
|
|
|
|
int nGunOut=0;
|
|
stm.Read(nGunOut);
|
|
if (nGunOut)
|
|
{
|
|
SetWeaponPositionState(WEAPON_POS_HOLD);
|
|
m_pEntity->GetScriptObject()->SetValue("AI_GunOut",1);
|
|
|
|
m_pScriptSystem->BeginCall("BasicAI","MakeAlerted");
|
|
m_pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject());
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
}
|
|
|
|
|
|
void CPlayer::OnEntityNetworkUpdate( const EntityId &idViewerEntity, const Vec3d &v3dViewer, uint32 &inoutPriority,
|
|
EntityCloneState &inoutCloneState) const
|
|
{
|
|
inoutPriority+=100000;
|
|
|
|
if(m_stats.moving)
|
|
inoutPriority+=10000;
|
|
|
|
if(m_stats.firing)
|
|
inoutPriority+=20000;
|
|
|
|
// if(m_stats.reloading)
|
|
// inoutPriority-=10000;
|
|
|
|
inoutCloneState.m_bSyncYAngle=false;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------------------
|
|
bool CPlayer::LoadGame_PATCH_1(CStream &stm)
|
|
{
|
|
RemoveAllWeapons();
|
|
|
|
// [Petar] preserve the original health in case we need to use it
|
|
// to restore the health of special AI on a checkpoint
|
|
int nStartHealth = m_stats.health;
|
|
if (!m_bIsAI)
|
|
DeselectWeapon();
|
|
|
|
for(int cl = 0; (stm.Read(cl),cl); )
|
|
{
|
|
WeaponInfo &wi = m_mapPlayerWeapons[cl];
|
|
wi.owns = true;
|
|
stm.Read(wi.iFireMode);
|
|
}
|
|
for(int i=0;i<sizeof(m_vWeaponSlots)/sizeof(int);i++)
|
|
{
|
|
stm.Read(m_vWeaponSlots[i]);
|
|
}
|
|
|
|
Load_PATCH_1(stm);
|
|
|
|
|
|
SelectWeapon(m_stats.weapon);
|
|
|
|
if (m_nSelectedWeaponID != -1)
|
|
{
|
|
WeaponInfo &wi = GetWeaponInfo();
|
|
|
|
CWeaponClass *pSelectedWeapon = GetSelectedWeapon();
|
|
pSelectedWeapon->ScriptOnStopFiring(m_pEntity);
|
|
|
|
_SmartScriptObject pObj(m_pScriptSystem);
|
|
pObj->SetValue( "firemode", m_stats.firemode);
|
|
pObj->SetValue( "ignoreammo", true);
|
|
|
|
bool bCanSwitch;
|
|
m_pEntity->SendScriptEvent(ScriptEvent_FireModeChange, *pObj, &bCanSwitch);
|
|
|
|
wi.iFireMode = m_stats.firemode;
|
|
}
|
|
|
|
if (m_bIsAI)
|
|
{
|
|
IPuppet *pPuppet=0;
|
|
if (m_pEntity->GetAI()->CanBeConvertedTo(AIOBJECT_PUPPET,(void**)&pPuppet))
|
|
{
|
|
if (pPuppet->GetPuppetParameters().m_bSpecial)
|
|
m_stats.health = nStartHealth;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
bool CPlayer::Load_PATCH_1( CStream &stream)
|
|
{
|
|
// bool bPrevLightStatus;
|
|
// stream.Read(bPrevLightStatus);
|
|
// if (bPrevLightStatus!=m_bLightOn)
|
|
// SwitchFlashLight(bPrevLightStatus);
|
|
return Read_PATCH_1(stream);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
/*! Reads all data which needs to be synchronized from the network-stream
|
|
@param stream stream to read from
|
|
@return true if the function succeeds, false otherwise
|
|
*/
|
|
bool CPlayer::Read_PATCH_1( CStream &stream )
|
|
{
|
|
unsigned short dirty = 0;
|
|
PlayerStats &stats=m_stats;
|
|
// GetPlayerStats( stats );
|
|
BYTE health,armor,weapon,firemode,staminaBuff;
|
|
//int weaponid = stats.weaponid;
|
|
bool bHostEntity;
|
|
|
|
VERIFY_COOKIE(stream);
|
|
stream.Read(bHostEntity);
|
|
|
|
if(bHostEntity)
|
|
{
|
|
stream.ReadPkd( staminaBuff );
|
|
m_stats.stamina = staminaBuff;
|
|
// stream.ReadPkd( staminaBuff );
|
|
// m_stats.breath = staminaBuff;
|
|
stream.ReadPkd( health );
|
|
stats.health=health;
|
|
stream.ReadPkd( armor );
|
|
stats.armor=armor;
|
|
unsigned int ammo_in_clip;
|
|
stream.ReadNumberInBits(ammo_in_clip,10);
|
|
stats.ammo_in_clip=ammo_in_clip;
|
|
unsigned int ammo;
|
|
stream.ReadNumberInBits(ammo,10);
|
|
stats.ammo=ammo;
|
|
BYTE b;
|
|
stream.ReadPkd(b);
|
|
stats.numofgrenades=b;
|
|
stream.ReadNumberInBits(stats.grenadetype, 4);
|
|
stream.Read(stats.holding_breath);
|
|
|
|
bool isnotzero;
|
|
for(int i=0;i<sizeof(m_vWeaponSlots)/sizeof(int);i++)
|
|
{
|
|
stream.Read(isnotzero);
|
|
if(isnotzero)
|
|
{
|
|
stream.ReadPkd(b);
|
|
m_vWeaponSlots[i]=b;
|
|
}else
|
|
{
|
|
m_vWeaponSlots[i]=0;
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool val;
|
|
stream.Read(val);
|
|
stats.ammo_in_clip = val;
|
|
stream.Read(val);
|
|
stats.ammo = val;
|
|
stream.Read(val);
|
|
stats.firing = val;
|
|
|
|
bool t;
|
|
stream.Read(t);
|
|
if(t)
|
|
{
|
|
bool sign;
|
|
BYTE lean;
|
|
stream.Read(sign);
|
|
stream.ReadPkd(lean);
|
|
m_walkParams.fCurrLean=sign?(lean*(1.0f/255)):-(lean*(1.0f/255));
|
|
}
|
|
else
|
|
{
|
|
m_walkParams.fCurrLean=0;
|
|
}
|
|
}
|
|
VERIFY_COOKIE(stream);
|
|
stream.Read(stats.firing_grenade);
|
|
stream.ReadPkd(weapon);
|
|
if (weapon!=stats.weapon)
|
|
{
|
|
SelectWeapon(weapon, false);
|
|
stats.weapon = weapon;
|
|
stats.firing = false;
|
|
}
|
|
stream.ReadPkd(firemode);
|
|
if(firemode!=stats.firemode)
|
|
{
|
|
stats.firemode=firemode;
|
|
SwitchFiremode(stats.firemode);
|
|
}
|
|
|
|
//stream.Read(stats.firing);
|
|
// stream.Read(stats.onLadder);
|
|
eStance stance;
|
|
stream.ReadNumberInBits(*((unsigned int *)&stance),3);
|
|
|
|
// no stances in vehicle
|
|
if(stance!=m_CurStance && !m_pVehicle)
|
|
{
|
|
switch(stance)
|
|
{
|
|
case eRelaxed:
|
|
GoRelaxed();
|
|
break;
|
|
case eStand:
|
|
GoStand();
|
|
break;
|
|
// case eAimLook:
|
|
// GoAim();
|
|
// break;
|
|
case eStealth:
|
|
GoStealth();
|
|
break;
|
|
case eCrouch:
|
|
GoCrouch();
|
|
break;
|
|
case eProne:
|
|
GoProne();
|
|
break;
|
|
case eSwim:
|
|
GoSwim();
|
|
break;
|
|
default:
|
|
//DEBUG_BREAK;
|
|
::OutputDebugString("INVALID STANCE\n");
|
|
m_CurStance=(eStance)stance;
|
|
break;
|
|
}
|
|
}
|
|
stream.Read(stats.jumping);
|
|
|
|
if(stream.GetStreamVersion()>=PATCH1_SAVEVERSION) // to be backward compatible with old samegames
|
|
{
|
|
bool bSyncToAllClients;
|
|
|
|
stream.Read(bSyncToAllClients);
|
|
|
|
if(bSyncToAllClients)
|
|
{
|
|
uint8 ucStartRandomSeedCS;
|
|
|
|
stream.Read(ucStartRandomSeedCS);
|
|
|
|
// if(!bHostEntity)
|
|
m_SynchedRandomSeed.SetStartRandomSeedC(ucStartRandomSeedCS);
|
|
|
|
// GetISystem()->GetILog()->Log(">> Player Read %d %d",(int)(this->GetEntity()->GetId()),(int)ucStartRandomSeedCS); // debug
|
|
}
|
|
}
|
|
|
|
|
|
//TRIGGER REALOAD ON CLIENT ONLY (think if can be done better)
|
|
bool bReloading;
|
|
stream.Read(bReloading);
|
|
|
|
if(bReloading && (stats.reloading==false) && m_nSelectedWeaponID != -1)
|
|
{
|
|
CWeaponClass *pSelectedWeapon = GetSelectedWeapon();
|
|
pSelectedWeapon->ScriptOnStopFiring(m_pEntity);
|
|
pSelectedWeapon->ScriptReload(m_pEntity);
|
|
}
|
|
stats.reloading=bReloading;
|
|
|
|
|
|
BYTE acc;
|
|
stream.ReadPkd(acc);
|
|
stats.accuracy=acc*(1.f/255.f);
|
|
|
|
VERIFY_COOKIE(stream);
|
|
|
|
|
|
if(stats.firing_grenade)
|
|
{
|
|
//invoke script event (client)
|
|
m_bGrenadeAnimation = true;
|
|
m_pEntity->SendScriptEvent(ScriptEvent_FireGrenade,0,NULL);
|
|
}
|
|
|
|
bool bRedirected;
|
|
EntityId nID;
|
|
stream.Read(bRedirected);
|
|
if (bRedirected)
|
|
stream.Read(nID);
|
|
if ((m_pRedirected!=0)!=bRedirected || m_pRedirected && m_pRedirected->GetId()!=nID)
|
|
{
|
|
if (m_pRedirected)
|
|
{
|
|
m_pRedirected->OnUnBind(m_pEntity,0);
|
|
m_pRedirected = 0;
|
|
}
|
|
if (bRedirected && (m_pRedirected=m_pGame->GetSystem()->GetIEntitySystem()->GetEntity(nID)))
|
|
m_pRedirected->OnBind(m_pEntity,0);
|
|
}
|
|
if (m_pRedirected && !bHostEntity)
|
|
m_pRedirected->SetAngles(m_pEntity->GetAngles());
|
|
|
|
stream.Read(m_bFirstPersonLoaded);
|
|
|
|
return true;
|
|
}
|