示例#1
0
//--------------------------------------------------------------------
bool CWeapon::PreActionAttack(bool startFire)
{
	// Melee while pressing SHIFT for SP
	CPlayer *pPlayer = static_cast<CPlayer*>(GetOwnerActor());
	if(!pPlayer)
		return false;

	//if(gEnv->bMultiplayer)
	{
		if(startFire && pPlayer->IsSprinting())
		{
			//Stop sprinting, start firing
			SPlayerStats *pStats = static_cast<SPlayerStats*>(pPlayer->GetActorStats());
			if(pStats)
			{
				pStats->bSprinting = false;
				pStats->bIgnoreSprinting = true;
			}
		}
		else if(!startFire)
		{
			//Stop firing, continue sprinting
			SPlayerStats *pStats = static_cast<SPlayerStats*>(pPlayer->GetActorStats());
			if(pStats)
				pStats->bIgnoreSprinting = false;

		}
	}

	return false;
}
示例#2
0
bool CPlayerStateUtil::ShouldJump( CPlayer& player, const SActorFrameMovementParams& movement )
{
	const bool allowJump = movement.jump && !player.IsJumping(); //m_playerStateJump.IsJumping();
 	if (allowJump)
	{
		// TODO: We need a TryJump (stephenn).

		// This is needed when jumping while standing directly under something that causes an immediate land,
		// before and without even being airborne for one frame.
		// PlayerMovement set m_stats.onGround=0.0f when the jump is triggered,
		// which prevents the on ground timer from before the jump to be inherited
		// and incorrectly and prematurely used to identify landing in MP.

		const SPlayerStats& stats = *player.GetActorStats();
		const SActorPhysics& actorPhysics = player.GetActorPhysics();
		const float fUnconstrainedZ = actorPhysics.velocityUnconstrained.z;
		bool jumpFailed = (stats.onGround > 0.0f) && (fUnconstrainedZ <= 0.0f);

		const float onGroundTime = 0.2f;
		if( ((stats.onGround > onGroundTime) || player.IsRemote()) ) // && !jumpFailed )
		{
			return true;
		}
		else
		{
			CCCPOINT_IF(true, PlayerMovement_PressJumpWhileNotAllowedToJump);
		}
	}
	return false;
}
示例#3
0
//--------------------------------------------------------------------
bool CWeapon::OnActionSprint(EntityId actorId, const ActionId& actionId, int activationMode, float value)
{
	//If zoomed, you can not sprint (in SP only)
	if ((gEnv->bMultiplayer == false) && IsZoomed())
		return false;

	CActor* pOwnerActor = GetOwnerActor();
	CPlayer *pPlayer = 0;
	SPlayerStats *pStats = 0;
	if (pOwnerActor && pOwnerActor->IsPlayer())
	{
		pPlayer = static_cast<CPlayer*>(pOwnerActor);
		pStats = static_cast<SPlayerStats*>(pPlayer->GetActorStats());
	}

	if (activationMode == eAAM_OnPress)
	{
		if (pPlayer)
		{
			if (pStats && pStats->bIgnoreSprinting && !m_isFiring && m_delayedFireActionTimeOut <= 0.f && m_delayedMeleeActionTimeOut <= 0.f)
				pStats->bIgnoreSprinting = false;
		}
	}

	return false;
}
示例#4
0
bool CWeapon::CheckSprint()
{
	CPlayer *pPlayer = static_cast<CPlayer*>(GetOwnerActor());
	if(!pPlayer || pPlayer->IsSliding())
		return false;

	SPlayerStats *pStats = static_cast<SPlayerStats*>(pPlayer->GetActorStats());
	assert(pStats);

	if(pPlayer->IsSprinting())
	{
		pStats->bIgnoreSprinting = true;

		float delayScale = pPlayer->GetModifiableValues().GetValue(kPMV_WeaponFireFromSprintTimeScale);
		m_delayedFireActionTimeOut = GetParams().sprintToFireDelay * delayScale;

		return true;
	}
	else if (m_delayedFireActionTimeOut > 0.f)
	{
		return true;
	}

	return false;
}
示例#5
0
void CPlayerStateGround::OnEnter( CPlayer& player )
{
	player.GetActorStats()->inAir = 0.0f;

	// Ensure inertia is set!
	CPlayerStateUtil::RestorePlayerPhysics( player );

}
示例#6
0
void CCameraTracking::UpdateAutoFollow(const SViewParams &viewParams, const CPlayer &hero)
{
	if(g_pGameCVars->cl_cam_auto_follow_rate > 0.0f) //auto-tracking
	{
		//if there is an obstacle nearby, don't try to rotate into it
		float lastObstacleDist = (m_vLastObstaclePos - viewParams.position).len();

		if(lastObstacleDist < g_fAutoTrackObstacleDistance)
			return;

		if(hero.GetActorStats()->speedFlat < g_pGameCVars->cl_cam_auto_follow_movement_speed)
		{
			//only rotate when player moves
			m_fAutoRotateSpeed = 0.0f;
			return;
		}

		//get camera direction
		Vec3 camDir = -m_pCamRayScan->GetRayDir(eRAY_CENTER);
		camDir.z = 0.0f;
		camDir.Normalize();
		//get Player direction
		Vec3 heroDirection = (hero.GetAnimatedCharacter()->GetAnimLocation().q * FORWARD_DIRECTION);

		//compute angle between directions
		float dt = camDir.Dot(heroDirection);
		dt = clamp(dt, -1.0f, 1.0f);
		float angle = cry_acosf(dt);

		//check angle being bigger than threshold
		if(angle > g_pGameCVars->cl_cam_auto_follow_threshold)
		{
			float moveSpeed = max(0.002f, gf_PI*m_fFrameTime*g_pGameCVars->cl_cam_auto_follow_rate);
			m_fAutoRotateSpeed = InterpolateTo(max(0.002f, m_fAutoRotateSpeed), moveSpeed, 0.2f);

			//compute rotation direction by taking height part of cross-prod
			float dirVal = camDir.x * heroDirection.y - camDir.y * heroDirection.x;

			CCameraInputHelper *const pCamHelper = hero.GetCameraInputHelper();
			CRY_ASSERT(pCamHelper);

			if(dirVal > 0) //rotate right
				pCamHelper->SetTrackingDelta(-m_fAutoRotateSpeed, 0.0f);
			else //rotate left
				pCamHelper->SetTrackingDelta(m_fAutoRotateSpeed, 0.0f);
		}
		else
			m_fAutoRotateSpeed = 0.0f;
	}
}
void CPlayerStateSwim_WaterTestProxy::DebugDraw(const CPlayer& player, const Vec3& referencePosition)
{
	// DEBUG RENDERING
	const SPlayerStats& stats = *player.GetActorStats();
	const bool debugSwimming = (g_pGameCVars->cl_debugSwimming != 0);
	if (debugSwimming && (m_playerWaterLevel > -10.0f) && (m_playerWaterLevel < 10.0f))
	{
		const Vec3 surfacePosition(referencePosition.x, referencePosition.y, m_waterLevel);

		const Vec3 vRight(player.GetBaseQuat().GetColumn0());

		const static ColorF referenceColor(1,1,1,1);
		const static ColorF surfaceColor1(0,0.5f,1,1);
		const static ColorF surfaceColor0(0,0,0.5f,0);
		const static ColorF bottomColor(0,0.5f,0,1);

		gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(referencePosition, 0.1f, referenceColor);

		gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(referencePosition, surfaceColor1, surfacePosition, surfaceColor1, 2.0f);
		gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(surfacePosition, 0.2f, surfaceColor1);
		gEnv->pRenderer->DrawLabel(referencePosition + vRight * 0.5f, 1.5f, "WaterLevel %3.2f (Head underwater: %d)", m_playerWaterLevel, m_headUnderwater ? 1 : 0);

		const static int lines = 16;
		const static float radius0 = 0.5f;
		const static float radius1 = 1.0f;
		const static float radius2 = 2.0f;
		for (int i = 0; i < lines; ++i)
		{
			float radians = ((float)i / (float)lines) * gf_PI2;
			Vec3 offset0(radius0 * cos_tpl(radians), radius0 * sin_tpl(radians), 0);
			Vec3 offset1(radius1 * cos_tpl(radians), radius1 * sin_tpl(radians), 0);
			Vec3 offset2(radius2 * cos_tpl(radians), radius2 * sin_tpl(radians), 0);
			gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(surfacePosition+offset0, surfaceColor0, surfacePosition+offset1, surfaceColor1, 2.0f);
			gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(surfacePosition+offset1, surfaceColor1, surfacePosition+offset2, surfaceColor0, 2.0f);
		}

		if (m_bottomLevel > 0.0f)
		{
			const Vec3 bottomPosition(referencePosition.x, referencePosition.y, m_bottomLevel);

			gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(referencePosition, bottomColor, bottomPosition, bottomColor, 2.0f);
			gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(bottomPosition, 0.2f, bottomColor);
			gEnv->pRenderer->DrawLabel(bottomPosition + Vec3(0,0,0.5f) - vRight * 0.5f, 1.5f, "BottomDepth %3.3f", m_waterLevel - m_bottomLevel);
		}
	}
}
示例#8
0
//--------------------------------------------------------------------
bool CWeapon::PreMeleeAttack()
{
	CPlayer *pPlayer = static_cast<CPlayer*>(GetOwnerActor());
	if(!pPlayer)
		return false;

	SPlayerStats* pStats = static_cast<SPlayerStats*>(pPlayer->GetActorStats());
	assert(pStats);

	if (!pPlayer->IsSprinting())
		return true;

	pStats->bIgnoreSprinting = true;
	float delayScale = pPlayer->GetModifiableValues().GetValue(kPMV_WeaponFireFromSprintTimeScale);
	m_delayedMeleeActionTimeOut = GetParams().sprintToMeleeDelay * delayScale;

	return (m_delayedMeleeActionTimeOut <= 0.f);
}
示例#9
0
bool CPlayerStateUtil::IsMovingForward( const CPlayer& player, const SActorFrameMovementParams& movement )
{
	const float fSpeedFlatSelector = player.GetActorStats()->speedFlat - 0.1f;
	bool movingForward = (fSpeedFlatSelector > 0.1f);

	if (!gEnv->bMultiplayer || player.IsClient())
	{
		// IsMovingForward() doesn't return particularly reliable results for client players in MP, I think because of interpolation innacuracies on the Y velocity. this was causing client players to
		// incorrectly report that they're no longer moving forwards, whereas all that had happened was they had stopped sprinting - and this in turn was messing up the MP sprint stamina regeneration delays.
		// client players have also been seen to stop sprinting due to turning lightly, whereas on their local machine they were still sprinting fine...
		// so i've tried changing it so IsMovingForward() is only taken into account on local clients (and in SP!).  [tlh]
		const float thresholdSinAngle = sin_tpl((3.141592f * 0.5f) - DEG2RAD(g_pGameCVars->pl_power_sprint.foward_angle));
		const float currentSinAngle = movement.desiredVelocity.y;

		movingForward = movingForward && (currentSinAngle > thresholdSinAngle);
	}

	return movingForward;
}
示例#10
0
void CPlayerStateUtil::UpdatePlayerPhysicsStats( CPlayer& player, SActorPhysics& actorPhysics, float frameTime )
{
	const int currentFrameID = gEnv->pRenderer->GetFrameID();
	if( actorPhysics.lastFrameUpdate < currentFrameID )
	{
		pe_status_living livStat;
		if( !CPlayerStateUtil::GetPhysicsLivingStat( player, &livStat ) )
		{
			return;
		}

		SPlayerStats& stats = *player.GetActorStats();

		const Vec3 newVelocity = livStat.vel-livStat.velGround;
		actorPhysics.velocityDelta = newVelocity - actorPhysics.velocity;
		actorPhysics.velocity = newVelocity;
		actorPhysics.velocityUnconstrainedLast = actorPhysics.velocityUnconstrained;
		actorPhysics.velocityUnconstrained = livStat.velUnconstrained;
		actorPhysics.flags.SetFlags( SActorPhysics::EActorPhysicsFlags_WasFlying, actorPhysics.flags.AreAnyFlagsActive(SActorPhysics::EActorPhysicsFlags_Flying) );
		actorPhysics.flags.SetFlags( SActorPhysics::EActorPhysicsFlags_Flying, livStat.bFlying > 0 );
		actorPhysics.flags.SetFlags( SActorPhysics::EActorPhysicsFlags_Stuck, livStat.bStuck > 0 );

		Vec3 flatVel(player.m_pPlayerRotation->GetBaseQuat().GetInverted()*newVelocity);
		flatVel.z = 0;
		stats.speedFlat = flatVel.len();

		if(player.IsInAir())
		{
			stats.maxAirSpeed = max(stats.maxAirSpeed, newVelocity.GetLengthFast());
		}
		else
		{
			stats.maxAirSpeed = 0.f;
		}
		float fSpeedFlatSelector = stats.speedFlat - 0.1f;


		const float groundNormalBlend = clamp(frameTime * 6.666f, 0.0f, 1.0f);
		actorPhysics.groundNormal = LERP(actorPhysics.groundNormal, livStat.groundSlope, groundNormalBlend);

		if (livStat.groundSurfaceIdxAux > 0)
			actorPhysics.groundMaterialIdx = livStat.groundSurfaceIdxAux;
		else
			actorPhysics.groundMaterialIdx = livStat.groundSurfaceIdx;

		actorPhysics.groundHeight = livStat.groundHeight;

		EntityId newGroundColliderId = 0;
		if (livStat.pGroundCollider)
		{
			IEntity* pEntity = gEnv->pEntitySystem->GetEntityFromPhysics(livStat.pGroundCollider);
			newGroundColliderId = pEntity ? pEntity->GetId() : 0;
		}

		if( newGroundColliderId != actorPhysics.groundColliderId )
		{
			if( actorPhysics.groundColliderId )
			{
				if( IGameObject* pGameObject = gEnv->pGame->GetIGameFramework()->GetGameObject( actorPhysics.groundColliderId ) )
				{
					SGameObjectEvent event( eGFE_StoodOnChange, eGOEF_ToExtensions );
					event.ptr = &player;
					event.paramAsBool  = false;
					pGameObject->SendEvent(event);
				}
			}

			if( newGroundColliderId )
			{
				if( IGameObject* pGameObject = gEnv->pGame->GetIGameFramework()->GetGameObject( newGroundColliderId ) )
				{
					SGameObjectEvent event( eGFE_StoodOnChange, eGOEF_ToExtensions );
					event.ptr = &player;
					event.paramAsBool  = true;
					pGameObject->SendEvent(event);
				}
			}

			actorPhysics.groundColliderId = newGroundColliderId;
		}

		IPhysicalEntity *pPhysEnt = player.GetEntity()->GetPhysics();
		if( pPhysEnt )
		{
			pe_status_dynamics dynStat;
			pPhysEnt->GetStatus(&dynStat);

			actorPhysics.angVelocity = dynStat.w;
			actorPhysics.mass = dynStat.mass;

			pe_player_dynamics simPar;
			if (pPhysEnt->GetParams(&simPar) != 0)
			{
				actorPhysics.gravity = simPar.gravity;
			}
		}

		actorPhysics.lastFrameUpdate = currentFrameID;

#ifdef PLAYER_MOVEMENT_DEBUG_ENABLED
	player.GetMovementDebug().DebugGraph_AddValue("PhysVelo", livStat.vel.GetLength());
	player.GetMovementDebug().DebugGraph_AddValue("PhysVeloX", livStat.vel.x);
	player.GetMovementDebug().DebugGraph_AddValue("PhysVeloY", livStat.vel.y);
	player.GetMovementDebug().DebugGraph_AddValue("PhysVeloZ", livStat.vel.z);

	player.GetMovementDebug().DebugGraph_AddValue("PhysVeloUn", livStat.velUnconstrained.GetLength());
	player.GetMovementDebug().DebugGraph_AddValue("PhysVeloUnX", livStat.velUnconstrained.x);
	player.GetMovementDebug().DebugGraph_AddValue("PhysVeloUnY", livStat.velUnconstrained.y);
	player.GetMovementDebug().DebugGraph_AddValue("PhysVeloUnZ", livStat.velUnconstrained.z);

	player.GetMovementDebug().DebugGraph_AddValue("PhysVelReq", livStat.velRequested.GetLength());
	player.GetMovementDebug().DebugGraph_AddValue("PhysVelReqX", livStat.velRequested.x);
	player.GetMovementDebug().DebugGraph_AddValue("PhysVelReqY", livStat.velRequested.y);
	player.GetMovementDebug().DebugGraph_AddValue("PhysVelReqZ", livStat.velRequested.z);

	player.GetMovementDebug().LogVelocityStats(player.GetEntity(), livStat, stats.downwardsImpactVelocity, stats.fallSpeed);
#endif
	}
}
//--------------------------------------
void CThrow::DoDrop()
{
	m_pWeapon->HideItem(true);

	if (m_throwableId)
	{
		IEntity *pEntity = gEnv->pEntitySystem->GetEntity(m_throwableId);

		if (pEntity)
		{
			IPhysicalEntity *pPE = pEntity->GetPhysics();

			if (pPE && (pPE->GetType() == PE_RIGID || pPE->GetType() == PE_PARTICLE))
			{
				Vec3 hit = GetProbableHit(WEAPON_HIT_RANGE);
				Vec3 pos = GetFiringPos(hit);
				CActor *pActor = m_pWeapon->GetOwnerActor();
				IMovementController *pMC = pActor ? pActor->GetMovementController() : 0;

				if (pMC)
				{
					SMovementState info;
					pMC->GetMovementState(info);
					float speed = 2.5f;
					CPlayer *pPlayer = static_cast<CPlayer *>(m_pWeapon->GetOwnerActor());

					if(info.aimDirection.z < -0.1f)
					{
						if(pPlayer)
						{
							if(SPlayerStats *pStats = static_cast<SPlayerStats *>(pPlayer->GetActorStats()))
							{
								if(pStats->grabbedHeavyEntity)
								{
									speed = 4.0f;
								}
							}
						}
					}

					if(CheckForIntersections(pPE, info.eyeDirection))
					{
						Matrix34 newTM = pEntity->GetWorldTM();
						newTM.SetTranslation(newTM.GetTranslation() - (info.eyeDirection * 0.4f));
						pEntity->SetWorldTM(newTM, ENTITY_XFORM_POS);
						pe_action_set_velocity asv;
						asv.v = (-info.eyeDirection * speed);
						pPE->Action(&asv);
					}
					else
					{
						pe_action_set_velocity asv;
						asv.v = (info.eyeDirection * speed);
						pPE->Action(&asv);
					}

					SEntityEvent entityEvent;
					entityEvent.event = ENTITY_EVENT_PICKUP;
					entityEvent.nParam[0] = 0;

					if (pPlayer)
					{
						entityEvent.nParam[1] = pPlayer->GetEntityId();
					}

					entityEvent.fParam[0] = speed;
					pEntity->SendEvent( entityEvent );
				}
			}
		}

		if (m_throwableAction)
		{
			m_throwableAction->execute(m_pWeapon);
		}
	}
}
bool CCameraTracking::IdentifyObstacle(const Vec3 &vCamDir, const CPlayer &hero)
{
	//check player direction
	Vec3 newDir = -hero.GetEntity()->GetForwardDir();
	newDir.z += vCamDir.z;
	newDir.normalize();

	//compute rotation speed
	const float fHeroSpeedModifier = clamp(hero.GetActorStats()->speedFlat / 4.0f, 0.3f, 1.0f);
	const float fNewSpeed = g_pGameCVars->cl_cam_tracking_rotation_speed * m_fFrameTime * fHeroSpeedModifier;
	m_fSpeed = InterpolateTo(m_fSpeed, fNewSpeed, (fNewSpeed>m_fSpeed)?0.1f:0.3f); 
	//m_fSpeed = (g_fInterpolationRate * m_fSpeed + speed) * g_fInterpolationWeight;

	//get ray data from camera ray tests
	ray_hit *pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_RIGHT);
	if(!pRayHit || pRayHit->dist == 0.0f)
		pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_RIGHT);
	bool bHitsRight = (pRayHit && pRayHit->dist > 0.0f);
	Vec3 dirRight = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_RIGHT)):Vec3(ZERO);

	//ray data left side
	pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_LEFT);
	if(!pRayHit || pRayHit->dist == 0.0f)
		pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_LEFT);
	bool bHitsLeft = (pRayHit && pRayHit->dist > 0.0f);
	Vec3 dirLeft = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_LEFT)):Vec3(ZERO);

	//left or right
	if(bHitsRight ^ bHitsLeft)
	{
		//find rotation direction
		if(!bHitsRight && !bHitsLeft)
		{
			if(m_eLastDirYaw == eTD_LEFT) //continue last direction
				newDir = dirLeft;
			else
				newDir = dirRight;
		}
		else if(!bHitsRight)
		{
			m_eLastDirYaw = eTD_RIGHT;
			newDir = dirRight;
		}
		else
		{
			m_eLastDirYaw = eTD_LEFT;
			newDir = dirLeft;
		}

		//compute yaw/pitch for target position
		float newYaw = 0.0f;
		float newPitch = 0.0f;
		float newDist = 0.0f;
		CartesianToSpherical(newDir * m_curCamOrientation.m_fDist, newYaw, newPitch, newDist);

		newYaw += gf_PI;

		//now interpolate to target

		//compute delta yaw
		m_fYawDelta = (newYaw - m_curCamOrientation.m_fYaw) * m_fSpeed;
		if(m_eLastDirYaw == eTD_RIGHT && m_fYawDelta < 0.0f || m_eLastDirYaw == eTD_LEFT && m_fYawDelta > 0.0f)
			m_fYawDelta *= -1.0f;
	}

	//compute top/bottom rotation

	//ray data top side
	pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_CENTER);
	bool bHitsTop = (pRayHit && pRayHit->dist > 0.0f)?true:false;
	Vec3 vDirTop = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_CENTER)):Vec3(ZERO);

	//ray data bottom side
	pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_CENTER);
	bool bHitsBottom = (pRayHit && pRayHit->dist > 0.0f)?true:false;
	Vec3 vDirBottom = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_BOTTOM_CENTER)):Vec3(ZERO);

	//top or bottom (if not left or right)
	if(g_pGameCVars->cl_cam_tracking_allow_pitch && (bHitsTop ^ bHitsBottom) && !(bHitsRight ^ bHitsLeft))
	{
		//find rotation direction
		if(!bHitsTop && !bHitsBottom)
		{
			if(m_eLastDirPitch == eTD_TOP) //continue last direction
				newDir = vDirTop;
			else
				newDir = vDirBottom;
		}
		else if(!bHitsBottom)
		{
			m_eLastDirPitch = eTD_BOTTOM;
			newDir = vDirBottom;
		}
		else
		{
			m_eLastDirPitch = eTD_TOP;
			newDir = vDirTop;
		}

		//compute yaw/pitch for target position
		float newYaw = 0.0f;
		float newPitch = 0.0f;
		float newDist = 0.0f; //newdist (raydist) will be ignored
		CartesianToSpherical(newDir, newYaw, newPitch, newDist);

		//compute delta pitch
		m_fPitchDelta = (newPitch - m_curCamOrientation.m_fPitch) * m_fSpeed * 10.0f;
	}

	//if all rays hit - don't bother!
	//this is a termination condition when the camera is pulled through geometry
	if(bHitsLeft & bHitsRight & bHitsBottom & bHitsTop)
	{
		if(m_bViewCovered)
		{
			//if obstacle behind player
			//if(g_rHit.dist > 0.0f)
			//this is a strange fix, but it's working better and is much cheaper than a raycast
			if(fabsf(m_fYawDelta) < 0.01f && fabsf(m_fPitchDelta) > 0.001f)
				return false;
		}
		m_bViewCovered = true;
	}
	else
		m_bViewCovered = false;

	return true;
}
//------------------------------------------------------------------------
// returns true if entity is killed, false if it is not
bool CGameRulesMPDamageHandling::SvOnHit( const HitInfo &hitInfo )
{
	const HitTypeInfo * pHitTypeInfo = m_pGameRules->GetHitTypeInfo(hitInfo.type);

#if !defined(_RELEASE)
	if(!pHitTypeInfo)
		CryFatalError("By ::SvOnHit() all hit info should have a hit type that is valid and registered in the GameRules. This isn't true of type %d!", hitInfo.type);
#endif

	SDamageHandling damageHandling(&hitInfo, 1.0f);

	float damage = hitInfo.damage;

	IActorSystem* pActorSystem = g_pGame->GetIGameFramework()->GetIActorSystem();
	CActor *pTargetActor = static_cast<CActor*>(pActorSystem->GetActor(hitInfo.targetId));
	CActor *pShooterActor = static_cast<CActor*>(pActorSystem->GetActor(hitInfo.shooterId));
	CPlayer* pShooterPlayer = (pShooterActor && pShooterActor->IsPlayer()) ? static_cast<CPlayer*>(pShooterActor) : NULL ;

	bool isPlayer = pTargetActor != NULL && pTargetActor->IsPlayer();

#ifndef _RELEASE
	//--- Fix to allow the damage handling to work for these entity classes in the same way as for Players
	static IEntityClass* sDamEntClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass("DamageTestEnt");
	isPlayer |= pTargetActor != NULL && pTargetActor->GetEntity()->GetClass() == sDamEntClass;
#endif

	CPlayer* pPlayer = isPlayer ? static_cast<CPlayer*>(pTargetActor) : NULL;
	const bool isMelee = ((pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::IsMeleeAttack) != 0);
	const bool checkHeadshots = ((pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::IgnoreHeadshots) == 0);

	bool bIsHeadShot = false;
	if(pPlayer && hitInfo.partId >= 0 && checkHeadshots)
	{
		bIsHeadShot = pPlayer->IsHeadShot(hitInfo);

		if (!bIsHeadShot && g_pGameCVars->g_mpHeadshotsOnly)
		{
			damage = 0.f;
		}
	}

	//If the player has died more than kTimeToAllowKillsAfterDeath seconds ago, we disallow any damage they apply, unless the hit type is flagged as allowing it.
	static const float kTimeToAllowKillsAfterDeath = 0.05f;
	if(pTargetActor && pShooterPlayer && !hitInfo.hitViaProxy
		&& ((pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::AllowPostDeathDamage) == 0) && pShooterActor->IsDead()
		&& (gEnv->pTimer->GetFrameStartTime().GetSeconds() - pShooterPlayer->GetDeathTime()) > kTimeToAllowKillsAfterDeath)
	{
		damage = 0.0f;
	}

	IGameRulesStateModule *stateModule = m_pGameRules->GetStateModule();
	IGameRulesRoundsModule* pRoundsModule = m_pGameRules->GetRoundsModule();

	if ( (stateModule != NULL && (stateModule->GetGameState() == IGameRulesStateModule::EGRS_PostGame)) || 
		   (pRoundsModule!= NULL && !pRoundsModule->IsInProgress() ))
	{
		// No damage allowed once the game has ended, except in cases where it would cause graphical glitches
		if (hitInfo.type != CGameRules::EHitType::PunishFall)
		{
			damage = 0.0f;
		}
	}

	IEntity *pTarget = gEnv->pEntitySystem->GetEntity(hitInfo.targetId);

#if defined(SERVER_CHECKS)

	if(damage != 0.0f)
	{
		int nNewCheckCounter = m_checkCounter + 1;
		
		if (CItem *pItem = static_cast<CItem *>(g_pGame->GetIGameFramework()->GetIItemSystem()->GetItem(hitInfo.weaponId)))
		{
			if(CWeapon * pWeapon = static_cast<CWeapon*>(pItem->GetIWeapon()))
			{
				int nFireModeFromShotId = GetFireModeFromShotId(hitInfo.shotId);

				static const int kCheckFreq = 7;

				if(pShooterActor &&	nNewCheckCounter == kCheckFreq)
				{
					float fDamageAtXMeters = 0.0f;

					float fDistance2D, fDistanceMax, fNetLagSeconds;
					CServerCheatMonitor::GetHitValidationInfo(*pShooterActor, hitInfo, fDistance2D, fDistanceMax, fNetLagSeconds);

					bool bDoDamageValidation = false;

					if(isMelee)
					{
						if(CMelee * pMelee = pWeapon->GetMelee())
						{
							//This check can't be used for everything because the default firemode returns '0.f' for range and only CMelee extends it
							//	the horizontal player speed is x 2.0f as the players could have potentially immediately turned and run away from each other
							float fMeleeRangeError = fDistance2D - (pMelee->GetRange() + (CServerCheatMonitor::kMaxHorizontalPlayerSpeed * fNetLagSeconds * 2.0f));
							if(fMeleeRangeError > 0.1f)
							{
								g_pGame->GetAntiCheatManager()->FlagActivity(eCT_MeleeRange, pShooterActor->GetChannelId(), fMeleeRangeError);
							}

							fDamageAtXMeters = pMelee->GetDamageAmountAtXMeters(fDistance2D);

							bDoDamageValidation = true;
						}
					}
					else
					{
						//////////////////////////////////////////////////////////////////////
						// Verify that the hit is from a valid shot

						DoShotValidation(hitInfo, pHitTypeInfo, pShooterActor);

						//////////////////////////////////////////////////////////////////////


						CFireMode * pFireMode = static_cast<CFireMode*>(pWeapon->GetFireMode(nFireModeFromShotId));

						if(pFireMode)
						{
							const SFireModeParams * pParams = pFireMode->GetShared();

							char projectileClassName[128];
							g_pGame->GetIGameFramework()->GetNetworkSafeClassName(projectileClassName, sizeof(projectileClassName), hitInfo.projectileClassId);
							IEntityClass * pProjectileClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(projectileClassName);

							if((pProjectileClass && (pProjectileClass == pParams->fireparams.ammo_type_class ||	pProjectileClass == pParams->plantparams.ammo_type_class)))
							{
								float fBulletSpeed = 100.f;
								const SAmmoParams * pAmmoParams = g_pGame->GetWeaponSystem()->GetAmmoParams(pFireMode->GetAmmoType());
								if(pAmmoParams)
								{
									fBulletSpeed = pAmmoParams->speed;
								}

								//Might have been closer when the shot was fired
								const float fMaxTimeSinceShot	= ((fDistanceMax / fBulletSpeed) * 2.0f) + fNetLagSeconds; //Should be less than this. Laaaaarge fudge factor
								float fDistance_Conservative	= fDistance2D - (fMaxTimeSinceShot * CServerCheatMonitor::kMaxHorizontalPlayerSpeed);

								fDamageAtXMeters = pFireMode->GetDamageAmountAtXMeters(fDistance_Conservative); 
							}
						}
						else if(pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::ValidationRequired)
						{
							CryStackStringT<char, 256> invalidFireModeMessage;
							invalidFireModeMessage.Format("Invalid fire mode, weapon: '%s', firemode: %d", pWeapon->GetEntity()->GetName(), nFireModeFromShotId);
							g_pGame->GetAntiCheatManager()->FlagActivity(eCT_ValidHitInfo, pShooterActor->GetChannelId(), invalidFireModeMessage.c_str());
						}
					}

					float fDamageFromWeapon = hitInfo.damage;			

					if(fDamageFromWeapon > fDamageAtXMeters && fDamageAtXMeters > 0.0f)
					{
						//Log the ratio of actual damage to expected damage, e.g. 1.2 x expected
						CryStackStringT<char, 256> excessiveDamageMessage;
						excessiveDamageMessage.Format("Weapon '%s', firemode %d", pWeapon->GetEntity()->GetName(), nFireModeFromShotId);
						g_pGame->GetAntiCheatManager()->FlagActivity(eCT_WeaponDamage, pShooterActor->GetChannelId(), fDamageFromWeapon / fDamageAtXMeters, excessiveDamageMessage.c_str());
					}


					if(pTargetActor)
					{
						CServerCheatMonitor::ValidateTargetActorPositionAgainstHit(*pTargetActor, hitInfo, fNetLagSeconds);
					}
					
					nNewCheckCounter = 0;
				}
				else
				{
					nNewCheckCounter = kCheckFreq - 1;
				}
			}
		}
		m_checkCounter = nNewCheckCounter;
	}

	// Update the shotcounter for tracking headshots and traversal times
	if(pShooterPlayer && (pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::ValidationRequired))
	{
		char netName[128];
		g_pGame->GetIGameFramework()->GetNetworkSafeClassName(netName, sizeof(netName), hitInfo.projectileClassId);
		IEntityClass * pProjectileClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(netName);
		if (pProjectileClass)
		{
			CShotCounter* pShotCounter = pShooterPlayer->GetShotCounter();
			pShotCounter->RecordHit(hitInfo, bIsHeadShot);
		}
	}
	
#endif // SERVER_CHECKS

	IEntityClass* pTargetClass = pTarget ? pTarget->GetClass() : NULL;

	// Check for friendly fire
	if( bool bCheckFriendlyFire = ((hitInfo.targetId!=hitInfo.shooterId) && (hitInfo.type!=CGameRules::EHitType::EventDamage)) )
	{
		if(IVehicle* pTargetVehicle = g_pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(hitInfo.targetId))
		{
			if(IActor* pDriverTargetVehicle = pTargetVehicle->GetDriver())
			{
				// Vehicle driver shot own vehicle (same as shooting yourself), don't do friendly fire.
				bCheckFriendlyFire = pDriverTargetVehicle->GetEntityId()!=hitInfo.shooterId;
			}
		}
		if(bCheckFriendlyFire)
		{
			if (m_pGameRules->GetTeamCount() > 1)
			{
				int shooterTeamId = m_pGameRules->GetTeam(hitInfo.shooterId);
				int targetTeamId = m_pGameRules->GetTeam(hitInfo.targetId);

				if (shooterTeamId && (shooterTeamId == targetTeamId))
				{
					damage = GetFriendlyFireDamage(damage, hitInfo, pTargetActor);
				}
			}
		}
	}

	if (damage <= 0.f)
	{
		// If the hit isn't doing anything bail, this means any hit that gets past here has damage associated with it and thus wants to
		// display a hit indicator
		return false;
	}

	if (pPlayer)
	{
		if(hitInfo.partId >= 0 && !isMelee)
		{
			damageHandling.damageMultiplier *= pPlayer->GetBodyDamageMultiplier(hitInfo);
		}

		if (isMelee)
		{
			damageHandling.damageMultiplier *= g_pGameCVars->pl_melee.damage_multiplier_mp;
		}
	}

	damage *= damageHandling.damageMultiplier;

	HitInfo hitInfoWithDamage = hitInfo;
	hitInfoWithDamage.damage = damage;

	if(pPlayer)
	{
		SActorStats* pStats = pPlayer->GetActorStats();
		float actorHealth = pPlayer->GetHealth();

		if(pStats)
		{
#ifndef _RELEASE
			if (g_pGameCVars->g_LogDamage)
			{
				char weaponClassName[64], projectileClassName[64];

				CryLog ("[DAMAGE] %s '%s' took %.3f '%s' damage (%.3f x %.3f) weapon=%s projectile=%s",
						pPlayer->GetEntity()->GetClass()->GetName(), pPlayer->GetEntity()->GetName(),
						damage, m_pGameRules->GetHitType(hitInfo.type),
						hitInfo.damage, damageHandling.damageMultiplier,
						g_pGame->GetIGameFramework()->GetNetworkSafeClassName(weaponClassName, sizeof(weaponClassName), hitInfo.weaponClassId) ? weaponClassName : "none",
						g_pGame->GetIGameFramework()->GetNetworkSafeClassName(projectileClassName, sizeof(projectileClassName), hitInfo.projectileClassId) ? projectileClassName : "none");
			}
#endif

			if(pStats->bStealthKilling && actorHealth <= damage)
			{
				if(pPlayer->GetStealthKill().GetTargetId() != hitInfoWithDamage.shooterId)
				{
					pPlayer->StoreDelayedKillingHitInfo(hitInfoWithDamage);
				}
				
				hitInfoWithDamage.damage = 0;
			}
			else if (pStats->bStealthKilled && hitInfoWithDamage.type != CGameRules::EHitType::StealthKill)
			{
				hitInfoWithDamage.damage = 0;
			}
		}
	}
		
	bool bKilled = SvOnHitScaled(hitInfoWithDamage);

	return bKilled;
}
示例#14
0
void CPlayerStateJump::StartJump( CPlayer& player, const bool isHeavyWeapon, const float fVerticalSpeedModifier )
{
	const SActorPhysics& actorPhysics = player.GetActorPhysics();
	const SPlayerStats& stats = *player.GetActorStats();
	const float onGroundTime = 0.2f;

	float g = actorPhysics.gravity.len();

	const float jumpHeightScale = 1.0f;
	const float jumpHeight = player.GetActorParams().jumpHeight * jumpHeightScale;

	float playerZ = player.GetEntity()->GetWorldPos().z;
	float expectedJumpEndHeight = playerZ + jumpHeight;

	pe_player_dimensions dimensions;
	IPhysicalEntity *pPhysics = player.GetEntity()->GetPhysics();
	if (pPhysics && pPhysics->GetParams(&dimensions))
	{
		float physicsBottom = dimensions.heightCollider - dimensions.sizeCollider.z;
		if (dimensions.bUseCapsule)
		{
			physicsBottom -= dimensions.sizeCollider.x;
		}
		expectedJumpEndHeight += physicsBottom;
	}

	float jumpSpeed = 0.0f;

 	if (g > 0.0f)
	{
		jumpSpeed = sqrt_tpl(2.0f*jumpHeight*(1.0f/g)) * g;

		if( isHeavyWeapon )
		{
			jumpSpeed *= g_pGameCVars->pl_movement.nonCombat_heavy_weapon_speed_scale;
		}
	}

	//this is used to easily find steep ground
	float slopeDelta = (Vec3Constants<float>::fVec3_OneZ - actorPhysics.groundNormal).len();

	SetJumpState(player, JState_Jump);

	Vec3 jumpVec(ZERO);

	bool bNormalJump = true;
	
	player.PlaySound(CPlayer::ESound_Jump);

	OnSpecialMove(player, IPlayerEventListener::eSM_Jump);

	CCCPOINT_IF( player.IsClient(),   PlayerMovement_LocalPlayerNormalJump);
	CCCPOINT_IF(!player.IsClient(), PlayerMovement_NonLocalPlayerNormalJump);

	{
		// This was causing the vertical jumping speed to be much slower.
		float verticalMult = max(1.0f - m_jumpLock, 0.3f);

		const Quat baseQuat = player.GetBaseQuat();
		jumpVec += baseQuat.GetColumn2() * jumpSpeed * verticalMult;
		jumpVec.z += fVerticalSpeedModifier;

#ifdef STATE_DEBUG
		if (g_pGameCVars->pl_debugInterpolation > 1)
		{
			CryWatch("Jumping: vec from player BaseQuat only = (%f, %f, %f)", jumpVec.x, jumpVec.y, jumpVec.z);
		}
#endif
		
		if (g_pGameCVars->pl_adjustJumpAngleWithFloorNormal && actorPhysics.groundNormal.len2() > 0.0f)
		{
			float vertical = clamp_tpl((actorPhysics.groundNormal.z - 0.25f) / 0.5f, 0.0f, 1.0f);
			Vec3 modifiedJumpDirection = LERP(actorPhysics.groundNormal, Vec3(0,0,1), vertical);
			jumpVec = modifiedJumpDirection * jumpVec.len();
		}

#ifdef STATE_DEBUG
		if (g_pGameCVars->pl_debugInterpolation > 1)
		{
			CryWatch("Jumping (%f, %f, %f)", jumpVec.x, jumpVec.y, jumpVec.z);
		}
#endif
	}

	NETINPUT_TRACE(player.GetEntityId(), jumpVec);

	FinalizeVelocity( player, jumpVec );

	if (!player.IsRemote())
	{
		player.HasJumped(player.GetMoveRequest().velocity);
	}

	IPhysicalEntity* pPhysEnt = player.GetEntity()->GetPhysics();
	if (pPhysEnt != NULL)
	{
		SAnimatedCharacterParams params = player.m_pAnimatedCharacter->GetParams();
		pe_player_dynamics pd;
		pd.kAirControl = player.GetAirControl()* g_pGameCVars->pl_jump_control.air_control_scale;
		pd.kAirResistance = player.GetAirResistance() * g_pGameCVars->pl_jump_control.air_resistance_scale;

		params.inertia = player.GetInertia() * g_pGameCVars->pl_jump_control.air_inertia_scale;

		if(player.IsRemote() && (g_pGameCVars->pl_velocityInterpAirControlScale > 0))
		{
			pd.kAirControl = g_pGameCVars->pl_velocityInterpAirControlScale;
		}

		pPhysEnt->SetParams(&pd);

		// Let Animated character handle the inertia
		player.SetAnimatedCharacterParams(params);
	}

#if 0
	if (debugJumping)
	{
		Vec3 entityPos = m_player.GetEntity()->GetWorldPos();
		gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entityPos, ColorB(255,255,255,255), entityPos, ColorB(255,255,0,255), 2.0f);
		gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entityPos+Vec3(0,0,2), ColorB(255,255,255,255), entityPos+Vec3(0,0,2) + desiredVel, ColorB(0,255,0,255), 2.0f);
		gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entityPos, ColorB(255,255,255,255), entityPos + jumpVec, ColorB(0,255,255,255), 2.0f);
		gEnv->pRenderer->DrawLabel(entityPos - entityRight * 1.0f + Vec3(0,0,3.0f), 1.5f, "Velo[%2.3f = %2.3f, %2.3f, %2.3f]", m_request.velocity.len(), m_request.velocity.x, m_request.velocity.y, m_request.velocity.z);
	}
#endif

	m_expectedJumpEndHeight = expectedJumpEndHeight;
	m_bSprintJump = player.IsSprinting();
}
示例#15
0
//-------------------------------------------------------------------------
bool CWeapon::OnActionModify(EntityId actorId, const ActionId& actionId, int activationMode, float value)
{
	if (IsZoomed() || IsZoomingInOrOut())
		return false;

	if (CanModify() && ((!IsReloading() && !IsBusy()) || AreAnyItemFlagsSet(eIF_Modifying)))
	{
		if (m_fm)
			m_fm->StopFire();

		if (AreAnyItemFlagsSet(eIF_Modifying))
		{
			m_enterModifyAction = 0;
			PlayAction(GetFragmentIds().leave_modify, 0);
			s_dofSpeed = fres(-g_pGameCVars->i_weapon_customisation_transition_time);
			s_dofValue = 1.0f;
			s_focusValue = -1.0f;

			GetScheduler()->TimerAction(g_pGameCVars->i_weapon_customisation_transition_time, CSchedulerAction<ScheduleLayer_Leave>::Create(this), false);

			SetItemFlags( eIF_Transitioning );
			ClearItemFlags( eIF_Modifying );

			GetGameObject()->InvokeRMI(CItem::SvRequestLeaveModify(), CItem::EmptyParams(), eRMI_ToServer);
		}
		else
		{
			gEnv->p3DEngine->SetPostEffectParam("Dof_Active", 1.0f);
			gEnv->p3DEngine->SetPostEffectParam("Dof_UseMask", 0.f);
			gEnv->p3DEngine->SetPostEffectParam("Dof_FocusRange", -1.f);
			gEnv->p3DEngine->SetPostEffectParam("Dof_FocusMin", 0.5f);
			gEnv->p3DEngine->SetPostEffectParam("Dof_FocusMax", 1.0f);
			gEnv->p3DEngine->SetPostEffectParam("Dof_FocusLimit", 1.5f);
			gEnv->p3DEngine->SetPostEffectParam("Dof_FocusMinZ", 0.0f);
			gEnv->p3DEngine->SetPostEffectParam("Dof_FocusMinZScale", 0.0f);

			m_itemLowerMode = eILM_Raised;

			TagState tagState = TAG_STATE_EMPTY;
			m_enterModifyAction = new CItemAction(PP_PlayerAction, GetFragmentIds().enter_modify, tagState);
			PlayFragment(m_enterModifyAction);
			s_dofSpeed = fres(g_pGameCVars->i_weapon_customisation_transition_time);
			s_dofValue = 0.0f;

			SetItemFlags(eIF_Transitioning);

			GetScheduler()->TimerAction(g_pGameCVars->i_weapon_customisation_transition_time, CSchedulerAction<ScheduleLayer_Enter>::Create(this), false);
			
			SetItemFlags(eIF_Modifying);

			CPlayer *pPlayer = static_cast<CPlayer*>(GetOwnerActor());
			if (pPlayer)
			{
				SPlayerStats *pStats = static_cast<SPlayerStats*>(pPlayer->GetActorStats());
				assert(pStats);
				pStats->bIgnoreSprinting = true;
			}

			GetGameObject()->InvokeRMI(CItem::SvRequestEnterModify(), CItem::EmptyParams(), eRMI_ToServer);
		}
	}

	return true;
}
示例#16
0
void CPlayerStateUtil::ApplyFallDamage( CPlayer& player, const float startFallingHeight, const float fHeightofEntity )
{
	CRY_ASSERT(player.IsClient());

	// Zero downwards impact velocity used for fall damage calculations if player was in water within the last 0.5 seconds.
	// Strength jumping straight up and down should theoretically land with a safe velocity, 
	// but together with the water surface stickyness the velocity can sometimes go above the safe impact velocity threshold.

	// DEPRECATED: comment left for prosterity in case dedicated server problems re-appear (author cannot test it).
	// On dedicated server the player can still be flying this frame as well, 
	// since synced pos from client is interpolated/smoothed and will not land immediately,
	// even though the velocity is set to zero.
	// Thus we need to use the velocity change instead of landing to identify impact.

	// DT: 12475: Falling a huge distance to a ledge grab results in no damage.
	// Now using the last velocity because when ledge grabbing the velocity is unchanged for this frame, thus zero damage is applied.
	// Assuming this a physics lag issue, using the last good velocity should be more-or-less ok.
	const float downwardsImpactSpeed = -(float)__fsel(-(player.m_playerStateSwim_WaterTestProxy.GetSwimmingTimer() + 0.5f), player.GetActorPhysics().velocityUnconstrainedLast.z, 0.0f);

	const SPlayerStats& stats = *player.GetActorStats();

	CRY_ASSERT(NumberValid(downwardsImpactSpeed));
	const float MIN_FALL_DAMAGE_DISTANCE = 3.0f;
	const float fallDist = startFallingHeight - fHeightofEntity;
	if ((downwardsImpactSpeed > 0.0f) && (fallDist > MIN_FALL_DAMAGE_DISTANCE))
	{
		const SPlayerHealth& healthCVars = g_pGameCVars->pl_health;

		float velSafe = healthCVars.fallDamage_SpeedSafe;
		float velFatal = healthCVars.fallDamage_SpeedFatal;
		float velFraction = (float)__fsel(-(velFatal - velSafe), 1.0f , (downwardsImpactSpeed - velSafe) * (float)__fres(velFatal - velSafe));

		CRY_ASSERT(NumberValid(velFraction));

		if (velFraction > 0.0f)
		{
			//Stop crouching after taking falling damage
			if(player.GetStance() == STANCE_CROUCH)
			{
				static_cast<CPlayerInput*>(player.GetPlayerInput())->ClearCrouchAction();
			}

			velFraction = powf(velFraction, gEnv->bMultiplayer ? healthCVars.fallDamage_CurveAttackMP : healthCVars.fallDamage_CurveAttack);

			const float maxHealth = player.GetMaxHealth();
			const float currentHealth  = player.GetHealth();

			HitInfo hit;
			hit.dir.zero();
			hit.type = CGameRules::EHitType::Fall;
			hit.shooterId = hit.targetId = hit.weaponId = player.GetEntityId();

			const float maxDamage = (float)__fsel(velFraction - 1.0f, maxHealth, max(0.0f, (gEnv->bMultiplayer?maxHealth:currentHealth) - healthCVars.fallDamage_health_threshold));

			hit.damage = velFraction * maxDamage;

			g_pGame->GetGameRules()->ClientHit(hit);

#ifdef PLAYER_MOVEMENT_DEBUG_ENABLED
			player.GetMovementDebug().LogFallDamage(player.GetEntity(), velFraction, downwardsImpactSpeed, hit.damage);
		}
		else
		{
			player.GetMovementDebug().LogFallDamageNone(player.GetEntity(), downwardsImpactSpeed);
		}
#else
		}
#endif
	}
示例#17
0
//--------------------------------------------------------------------------------------------------
// Name: SpawnScreenExplosionEffect
// Desc: Spawns screen explosion effect
//--------------------------------------------------------------------------------------------------
void CExplosionGameEffect::SpawnScreenExplosionEffect(const SExplosionContainer &explosionContainer)
{
	// Disclaimer: this code was originally from GameRulesClientServer::ProcessClientExplosionScreenFX()

	const ExplosionInfo& explosionInfo = explosionContainer.m_explosionInfo;

	if(explosionInfo.pressure < 1.0f)
		return;

	IActor *pClientActor = g_pGame->GetIGameFramework()->GetClientActor();
	if(pClientActor != NULL && !pClientActor->IsDead())
	{
		CPlayer* pPlayer = static_cast<CPlayer*>(pClientActor);
		bool hasFlashBangEffect = explosionInfo.blindAmount > 0.0f;

		// Flashbang friends and self?...
		if(hasFlashBangEffect)
		{
			bool flashBangSelf = true;
			bool flashBangFriends = false;
#ifndef _RELEASE
			flashBangSelf = g_pGameCVars->g_flashBangSelf != 0;
			flashBangFriends = g_pGameCVars->g_flashBangFriends != 0;
#endif
			bool ownFlashBang = pPlayer->GetEntityId() == explosionInfo.shooterId;
			if((!flashBangSelf && ownFlashBang) || // FlashBang self?
				((g_pGame->GetGameRules()->GetFriendlyFireRatio()<=0.0f) && (!flashBangFriends) && (!ownFlashBang) && pPlayer->IsFriendlyEntity(explosionInfo.shooterId))) // FlashBang friends?
			{
				return;
			}
		}

		// Distance
		float dist = (pClientActor->GetEntity()->GetWorldPos() - explosionInfo.pos).len();

		// Is the explosion in Player's FOV (let's suppose the FOV a bit higher, like 80)
		SMovementState state;
		if(IMovementController *pMV = pClientActor->GetMovementController())
		{
			pMV->GetMovementState(state);
		}

		Vec3 eyeToExplosion = explosionInfo.pos - state.eyePosition;
		Vec3 eyeDir = pClientActor->GetLinkedVehicle() ? pPlayer->GetVehicleViewDir() : state.eyeDirection;
		eyeToExplosion.Normalize();
		float eyeDirectionDP = eyeDir.Dot(eyeToExplosion);
		bool inFOV = (eyeDirectionDP > 0.68f);

		// All explosions have radial blur (default 30m radius)
		const float maxBlurDistance = (explosionInfo.maxblurdistance >0.0f) ? explosionInfo.maxblurdistance : 30.0f;
		if((maxBlurDistance > 0.0f) && (g_pGameCVars->g_radialBlur > 0.0f) && (explosionInfo.radius > 0.5f))
		{		
			if (inFOV && (dist < maxBlurDistance))
			{
				const int intersectionObjTypes = ent_static | ent_terrain;
				const unsigned int intersectionFlags = rwi_stop_at_pierceable|rwi_colltype_any;

				m_deferredScreenEffects.RequestRayCast(CDeferredExplosionEffect::eDET_RadialBlur, 
														explosionInfo.pos, -eyeToExplosion, dist, maxBlurDistance, intersectionObjTypes, intersectionFlags, NULL, 0);
			}
		}

		// Flashbang effect 
		if(hasFlashBangEffect && ((dist < (explosionInfo.radius*g_pGameCVars->g_flashBangNotInFOVRadiusFraction)) 
			|| (inFOV && (dist < explosionInfo.radius))))
		{
			ray_hit hit;
			const int intersectionObjTypes = ent_static | ent_terrain;
			const unsigned int intersectionFlags = rwi_stop_at_pierceable|rwi_colltype_any;
			const int intersectionMaxHits = 1;

			int collision = gEnv->pPhysicalWorld->RayWorldIntersection(	explosionInfo.pos, 
																																	-eyeToExplosion*dist, 
																																	intersectionObjTypes, 
																																	intersectionFlags, 
																																	&hit, 
																																	intersectionMaxHits);

			// If there was no obstacle between flashbang grenade and player
			if(!collision)
			{
				bool enabled = true;
				if(enabled)
				{
					CCCPOINT (FlashBang_Explode_BlindLocalPlayer);
					float timeScale = max(0.0f, 1 - (dist/explosionInfo.radius));
					float lookingAt = max(g_pGameCVars->g_flashBangMinFOVMultiplier, (eyeDirectionDP + 1)*0.5f);

					float time = explosionInfo.flashbangScale * timeScale *lookingAt;	// time is determined by distance to explosion		

					CRY_ASSERT_MESSAGE(pClientActor->IsPlayer(),"Effect shouldn't be spawned if not a player");

					SPlayerStats* pStats = static_cast<SPlayerStats*>(pPlayer->GetActorStats());

					NET_BATTLECHATTER(BC_Blinded, pPlayer);

					if(pClientActor->GetEntityId() == explosionInfo.shooterId)
					{
						g_pGame->GetPersistantStats()->IncrementClientStats(EIPS_BlindSelf);
					}
					else
					{
						g_pGame->GetGameRules()->SuccessfulFlashBang(explosionInfo, time);
					}

					pPlayer->StartFlashbangEffects(time, explosionInfo.shooterId);

					gEnv->p3DEngine->SetPostEffectParam("Flashbang_Time", time);
					gEnv->p3DEngine->SetPostEffectParam("FlashBang_BlindAmount", explosionInfo.blindAmount);
					gEnv->p3DEngine->SetPostEffectParam("Flashbang_DifractionAmount", time);
					gEnv->p3DEngine->SetPostEffectParam("Flashbang_Active", 1.0f);

					CRecordingSystem *pRecordingSystem = g_pGame->GetRecordingSystem();
					if (pRecordingSystem)
					{
						pRecordingSystem->OnPlayerFlashed(time, explosionInfo.blindAmount);
					}
				}
			}
			else
			{
				CCCPOINT (FlashBang_Explode_NearbyButBlockedByGeometry);
			}
		}
		else if(inFOV && (dist < explosionInfo.radius))
		{
			if(explosionInfo.damage>10.0f || explosionInfo.pressure>100.0f)
			{
				// Add some angular impulse to the client actor depending on distance, direction...
				float dt = (1.0f - dist/explosionInfo.radius);
				dt = dt * dt;
				float angleZ = gf_PI*0.15f*dt;
				float angleX = gf_PI*0.15f*dt;

				if (pClientActor)
				{
					static_cast<CActor*>(pClientActor)->AddAngularImpulse(Ang3(cry_random(-angleX*0.5f,angleX),0.0f,cry_random(-angleZ,angleZ)),0.0f,dt*2.0f);
				}
			}
		}
	}
}//-------------------------------------------------------------------------------------------------
示例#18
0
void CPlayerStateGround::OnPrePhysicsUpdate( CPlayer& player, const SActorFrameMovementParams &movement, float frameTime, const bool isHeavyWeapon, const bool isPlayer )
{
	const Matrix34A baseMtx = Matrix34A(player.GetBaseQuat());
	Matrix34A baseMtxZ(baseMtx * Matrix33::CreateScale(Vec3Constants<float>::fVec3_OneZ));
	baseMtxZ.SetTranslation(Vec3Constants<float>::fVec3_Zero);

	const CAutoAimManager& autoAimManager = g_pGame->GetAutoAimManager();
	const EntityId closeCombatTargetId = autoAimManager.GetCloseCombatSnapTarget();
	const IActor* pCloseCombatTarget = isPlayer && closeCombatTargetId && player.IsClient() ? g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(closeCombatTargetId) : NULL;

	if (pCloseCombatTarget)
	{
		ProcessAlignToTarget(autoAimManager, player, pCloseCombatTarget);
	}
	else
	{
		// This is to restore inertia if the ProcessAlignToTarget set it previously.
		if( m_inertiaIsZero )
		{
			CPlayerStateUtil::RestorePlayerPhysics( player );

			m_inertiaIsZero = false;
		}

		//process movement
		const bool isRemote = isPlayer && !player.IsClient();

		Vec3 move(ZERO);
		CPlayerStateUtil::CalculateGroundOrJumpMovement( player, movement, isHeavyWeapon, move );
		player.GetMoveRequest().type = eCMT_Normal;






		//apply movement
		Vec3 desiredVel(ZERO);
		Vec3 entityPos = player.GetEntity()->GetWorldPos();
		Vec3 entityRight(player.GetBaseQuat().GetColumn0());

		hwvec3 xmDesiredVel = HWV3Zero();

		hwmtx33 xmBaseMtxZ;
		HWMtx33LoadAligned(xmBaseMtxZ, baseMtxZ);
		hwmtx33 xmBaseMtxZOpt = HWMtx33GetOptimized(xmBaseMtxZ);

		hwvec3 xmMove					= HWVLoadVecUnaligned(&move);	
		simdf fGroundNormalZ;

#ifdef STATE_DEBUG
		bool debugJumping = (g_pGameCVars->pl_debug_jumping != 0);
#endif

		const SPlayerStats& stats = *player.GetActorStats();

		{
			xmDesiredVel = xmMove;

			Vec3 groundNormal = player.GetActorPhysics().groundNormal;

			if(!gEnv->bMultiplayer)
			{
				if (player.IsAIControlled())
					fGroundNormalZ = SIMDFLoadFloat(square(groundNormal.z));
				else
					fGroundNormalZ = SIMDFLoadFloat(groundNormal.z);
			}
			else
			{
				//If the hill steepness is greater than our minimum threshold
				if(groundNormal.z > 1.f - cosf(g_pGameCVars->pl_movement.mp_slope_speed_multiplier_minHill))
				{
					//Check if we are trying to move up or downhill
					groundNormal.z = 0.f;
					groundNormal.Normalize();

					Vec3 moveDir = move;
					moveDir.z = 0.f;
					moveDir.Normalize();

					float normalDotMove = groundNormal.Dot(moveDir);
					//Apply speed multiplier based on moving up/down hill and hill steepness
					float multiplier = normalDotMove < 0.f ? g_pGameCVars->pl_movement.mp_slope_speed_multiplier_uphill : g_pGameCVars->pl_movement.mp_slope_speed_multiplier_downhill;
					fGroundNormalZ = SIMDFLoadFloat(1.f - (1.f - player.GetActorPhysics().groundNormal.z) * multiplier);
				}
				else
				{
					fGroundNormalZ = SIMDFLoadFloat(1.0f);
				}
			}

			const float depthHi = g_pGameCVars->cl_shallowWaterDepthHi;
			const float depthLo = g_pGameCVars->cl_shallowWaterDepthLo;
			const float relativeBottomDepth = player.m_playerStateSwim_WaterTestProxy.GetRelativeBottomDepth();

			if( relativeBottomDepth > depthLo )
			{ // Shallow water speed slowdown
				float shallowWaterMultiplier = 1.0f;

				shallowWaterMultiplier = isPlayer
					? g_pGameCVars->cl_shallowWaterSpeedMulPlayer
					: g_pGameCVars->cl_shallowWaterSpeedMulAI;

				shallowWaterMultiplier = max(shallowWaterMultiplier, 0.1f);
				assert(shallowWaterMultiplier <= 1.0f);


				float shallowWaterDepthSpan = (depthHi - depthLo);
				shallowWaterDepthSpan = max(0.1f, shallowWaterDepthSpan);

				float slowdownFraction = (relativeBottomDepth - depthLo) / shallowWaterDepthSpan;
				slowdownFraction = clamp_tpl(slowdownFraction, 0.0f, 1.0f);
				shallowWaterMultiplier = LERP(1.0f, shallowWaterMultiplier, slowdownFraction);

				//avoid branch if m_stats.relativeBottomDepth <= 0.0f;
				shallowWaterMultiplier = (float)__fsel(-relativeBottomDepth, 1.0f, shallowWaterMultiplier);

				simdf vfShallowWaterMultiplier = SIMDFLoadFloat(shallowWaterMultiplier);

				xmDesiredVel = HWVMultiplySIMDF(xmDesiredVel, vfShallowWaterMultiplier);
			}
		}





		// Slow down on sloped terrain, simply proportional to the slope. 
		xmDesiredVel = HWVMultiplySIMDF(xmDesiredVel, fGroundNormalZ);

		//be sure desired velocity is flat to the ground
		hwvec3 vDesiredVelVert = HWMtx33RotateVecOpt(xmBaseMtxZOpt, xmDesiredVel);

		xmDesiredVel = HWVSub(xmDesiredVel, vDesiredVelVert);

		HWVSaveVecUnaligned(&desiredVel, xmDesiredVel);

		if (isPlayer)
		{
			Vec3 modifiedSlopeNormal = player.GetActorPhysics().groundNormal;
			float h = Vec2(modifiedSlopeNormal.x, modifiedSlopeNormal.y).GetLength(); // TODO: OPT: sqrt(x*x+y*y)
			float v = modifiedSlopeNormal.z;
			float slopeAngleCur = RAD2DEG(atan2_tpl(h, v));

			const float divisorH = (float)__fsel(-h, 1.0f, h);
			const float divisorV = (float)__fsel(-v, 1.0f, v);

			const float invV = __fres(divisorV);
			const float invH = __fres(divisorH);

			const float slopeAngleHor = 10.0f;
			const float slopeAngleVer = 50.0f;
			float slopeAngleFraction = clamp_tpl((slopeAngleCur - slopeAngleHor) * __fres(slopeAngleVer - slopeAngleHor), 0.0f, 1.0f);

			slopeAngleFraction = slopeAngleFraction * slopeAngleFraction * slopeAngleFraction;

			float slopeAngleMod = LERP(0.0f, 90.0f, slopeAngleFraction);

			float s, c;

			sincos_tpl(DEG2RAD(slopeAngleMod), &s, &c);

			const float hMultiplier = (float)__fsel(-h, 1.0f, s * invH);
			const float vMultiplier = (float)__fsel(-v, 1.0f, c * invV);

			modifiedSlopeNormal.x *= hMultiplier;
			modifiedSlopeNormal.y *= hMultiplier;
			modifiedSlopeNormal.z *= vMultiplier;

			//Normalize the slope normal if possible
			const float fSlopeNormalLength = modifiedSlopeNormal.len();
			const float fSlopeNormalLengthSafe = (float)__fsel(fSlopeNormalLength - 0.000001f, fSlopeNormalLength, 1.0f);
			modifiedSlopeNormal = modifiedSlopeNormal * __fres(fSlopeNormalLengthSafe);

			float alignment = min(modifiedSlopeNormal * desiredVel, 0.0f);

			// Also affect air control (but not as much), to prevent jumping up against steep slopes.

			alignment *= (float)__fsel(-fabsf(stats.onGround), LERP(0.7f, 1.0f, 1.0f - clamp_tpl(modifiedSlopeNormal.z * 100.0f, 0.0f, 1.0f)), 1.0f);

			modifiedSlopeNormal.z = modifiedSlopeNormal.z;

			desiredVel -= modifiedSlopeNormal * alignment;


#ifdef STATE_DEBUG
			if (debugJumping)
			{
				player.DebugGraph_AddValue("GroundSlope", slopeAngleCur);
				player.DebugGraph_AddValue("GroundSlopeMod", slopeAngleMod);
			}
#endif
		}





		Vec3 newVelocity = desiredVel;

		const float fNewSpeed = newVelocity.len();

		const float fVelocityMultiplier = (float)__fsel(fNewSpeed - 22.0f, __fres(fNewSpeed+FLT_EPSILON) * 22.0f, 1.0f);

		// TODO: Maybe we should tell physics about this new velocity ? Or maybe SPlayerStats::velocity ? (stephenn).
		player.GetMoveRequest().velocity = newVelocity * (stats.flashBangStunMult * fVelocityMultiplier);

#ifdef STATE_DEBUG
		if(g_pGameCVars->pl_debug_movement > 0)
		{
			const char* filter = g_pGameCVars->pl_debug_filter->GetString();
			const char* name = player.GetEntity()->GetName();
			if ((strcmp(filter, "0") == 0) || (strcmp(filter, name) == 0))
			{
				float white[] = {1.0f,1.0f,1.0f,1.0f};
				gEnv->pRenderer->Draw2dLabel(20, 450, 2.0f, white, false, "Speed: %.3f m/s", player.GetMoveRequest().velocity.len());

				if(g_pGameCVars->pl_debug_movement > 1)
				{
					gEnv->pRenderer->Draw2dLabel(35, 470, 1.8f, white, false, "Stance Speed: %.3f m/s - (%sSprinting)", player.GetStanceMaxSpeed(player.GetStance()), player.IsSprinting() ? "" : "Not ");
				}
			}
		}
#endif


























	}

	if( isPlayer )
	{
		CheckForVaultTrigger(player, frameTime);
	}
}