Esempio n. 1
0
void CDeflectorShield::ShootDeflectedEnergy(const CDeflectorShield::SDeflectedEnergy& energy)
{
	if (!m_pAmmoClass)
		return;
	CProjectile* pEnergyBlast = g_pGame->GetWeaponSystem()->SpawnAmmo(m_pAmmoClass, false);
	if (!pEnergyBlast)
		return;

	const Matrix34& worldTransform = GetEntity()->GetWorldTM();

	const float positionBias = 0.05f;

	const Vec3 worldReflectPos = worldTransform.TransformPoint(energy.m_localPosition);
	const Vec3 worldReflectDir = worldTransform.TransformVector(energy.m_localDirection);

	const Vec3 worldSpreadU = worldReflectDir.GetOrthogonal();
	const Vec3 worldSpreadV = worldReflectDir.Cross(worldSpreadU);

	const float spreadOffset = cry_random(0.0f, m_spread);
	
	const Vec3 position = worldReflectPos + worldReflectDir * positionBias;
	Vec3 direction = 
		worldReflectDir + 
		(worldSpreadU * cry_random(0.0f, m_spread)) + 
		(worldSpreadV * cry_random(0.0f, m_spread));
	direction.Normalize();

	CProjectile::SProjectileDesc projectileDesc(
		0, 0, 0, energy.m_damage, m_dropMinDistance, m_dropPerMeter, float(m_minDamage), m_hitTypeId,
		0, false);
	pEnergyBlast->SetParams(projectileDesc);
	pEnergyBlast->Launch(position, direction, Vec3(ZERO));
}
Esempio n. 2
0
void CView::GetRandomVector( Vec3 &vec, SShake* pShake )
{
	vec = pShake->amountVector;
	float randomAmt(pShake->randomness);
	float len = fabs(pShake->amountVector.x) + fabs(pShake->amountVector.y) + fabs(pShake->amountVector.z);
	len /= 3.f;
	float r = len * randomAmt;
	vec += Vec3(cry_random(-r, r), cry_random(-r, r), cry_random(-r, r));
}
Esempio n. 3
0
void CView::GetRandomQuat( Quat &quat, SShake* pShake )
{
	quat.SetRotationXYZ(pShake->amount);
	float randomAmt(pShake->randomness);
	float len(fabs(pShake->amount.x) + fabs(pShake->amount.y) + fabs(pShake->amount.z));
	len /= 3.f;
	float r = len * randomAmt;
	quat *= Quat::CreateRotationXYZ(Ang3(cry_random(-r, r), cry_random(-r, r), cry_random(-r, r)));
}
	void UpdateLookTarget()
	{
		const SLookAroundParams& params = GetParams();

		//--- TODO! Context use of random number generator!
		float yaw   = cry_random(params.yawMin, params.yawMax);
		float pitch = cry_random(params.pitchMin, params.pitchMax);
		m_lookOffset.Set(sin_tpl(yaw), cos_tpl(yaw), 0.0f);
		m_lookAroundTime = cry_random(params.timeMin, params.timeMax);
	}
Esempio n. 5
0
	void CalcFiringPosition(SActivationInfo* pActInfo, IWeapon* pWeapon)
	{
		Vec3 realTargetPos = GetTargetPos( pActInfo );
		m_firingPos = realTargetPos;
		
		float acc = GetPortFloat( pActInfo, IN_ACCURACY );
		if (acc<1)
		{
			bool itHits = cry_random(0.0f, 1.0f) < acc;
			if (!itHits)
			{
				// what this code does is: 
				// - in the plane perpendicular to the shooting vector, and located at the target, it builds a vector, centered in the target, and rotates it to point in a random direction, but always in the plane
				// - then it moves along that vector, a random distance (error distance)
				// - and that is the final to-fire position
			
				const float MAX_ERROR_LENGTH = 6.f;  // meters
				const float MIN_ERROR_ANGLE = 2.f; // degrees
				const float MAX_ERROR_ANGLE = 5.f; // degrees

				// error angle from weapon to target				
				float errorAngle = cry_random(MIN_ERROR_ANGLE, MAX_ERROR_ANGLE);
				
				// 2d angle, in the plane normal to the vector from weapon to target.
				float dirErrorAngle = cry_random(0.0f, 360.0f);
				
				// could be done with just 1 sqrt instead 2, but is not really worth it here.
				Vec3 vecToTarget = pActInfo->pEntity->GetPos() - realTargetPos;
				Vec3 vecToTargetNorm = vecToTarget.GetNormalizedSafe();
				Vec3 dirError2D = vecToTargetNorm.GetOrthogonal();
				dirError2D = dirError2D.GetRotated( vecToTargetNorm, DEG2RAD(dirErrorAngle) );
				
				float dist = vecToTarget.len();
				float errorLen = std::min( dist * tanf( DEG2RAD(errorAngle) ), MAX_ERROR_LENGTH );
				
				m_firingPos = realTargetPos + ( dirError2D * errorLen );
				
				#ifdef DEBUG_NODEFIREWEAPON
				posTarget = realTargetPos;
				posOrig = pActInfo->pEntity->GetPos();
				posShot = m_firingPos;
				#endif
			}
		}
		if (GetPortBool( pActInfo, IN_ALIGNTOTARGET ))
		{     
			UpdateWeaponTM( pActInfo, m_firingPos );
			m_lastPos = pActInfo->pEntity->GetWorldPos();
			m_lastRotation = pActInfo->pEntity->GetWorldRotation();
		}
		pWeapon->SetDestination( m_firingPos );
	}
//------------------------------------------------------------------------
void CVehicleDamageBehaviorImpulse::OnDamageEvent(EVehicleDamageBehaviorEvent event, const SVehicleDamageBehaviorEventParams& behaviorParams)
{
	if (event == eVDBE_Hit || event == eVDBE_VehicleDestroyed || event == eVDBE_ComponentDestroyed)  
	{
		IEntity* pEntity = m_pVehicle->GetEntity();
		CRY_ASSERT(pEntity);

		IPhysicalEntity* pPhysEntity = pEntity->GetPhysics();
		if (!pPhysEntity)
			return;

		pe_status_dynamics dyn;
		pPhysEntity->GetStatus(&dyn);
		float vehicleMass = dyn.mass;

		float r = cry_random(0.0f, 2.f);
		float impulseForce = cry_random(m_forceMin, m_forceMax) * vehicleMass;		

    Vec3 impulseDir(m_impulseDir);
    if (!m_worldSpace)
      impulseDir = m_pVehicle->GetEntity()->GetWorldTM().TransformVector(impulseDir);

		pe_action_impulse actionImpulse;
		Vec3& impulse = actionImpulse.impulse;
		Vec3& angImpulse = actionImpulse.angImpulse;

		impulse = impulseDir * impulseForce;
		angImpulse = m_pVehicle->GetEntity()->GetWorldTM().TransformVector(m_angImpulse);

		if (r <= 0.75f)
		{
			float r1 = cry_random(-0.35f, 0.35f);

			angImpulse += dyn.v * r1 * max(1.0f, dyn.w.GetLength());
			angImpulse *= vehicleMass;
		}
		else
		{
			float r1 = cry_random(-0.25f, 0.25f);
			float r2 = cry_random(-0.5f, 0.5f);

			impulse.z += abs(dyn.v.y) * r1 * vehicleMass;
			angImpulse.x += dyn.v.y * r2 * vehicleMass * max(1.0f, dyn.w.GetLength() * 1.5f);
		}

		if (m_pImpulseLocation)
			actionImpulse.point = m_pImpulseLocation->GetWorldSpaceTranslation();

		pPhysEntity->Action(&actionImpulse);
	}
}
Esempio n. 7
0
	virtual void ProcessEvent( EFlowEvent event, SActivationInfo * pActInfo )
	{
		switch (event)
		{
		case eFE_Initialize:
		case eFE_Activate:
			if (IsPortActive(pActInfo, 0))
			{
				int minOut = GetPortInt(pActInfo,1);
				int maxOut = GetPortInt(pActInfo,2);

				minOut = CLAMP(minOut, 0, NUM_OUTPUTS);
				maxOut = CLAMP(maxOut, 0, NUM_OUTPUTS);
				if (maxOut < minOut) 
					std::swap(minOut, maxOut);

				int n = cry_random(minOut, maxOut);

				// Collect the outputs to use
				static int	out[NUM_OUTPUTS];
				for (unsigned i = 0; i < NUM_OUTPUTS; i++)
					out[i] = -1;
				int nout = 0;
				for (int i = 0; i < NUM_OUTPUTS; i++)
				{
					if (IsOutputConnected(pActInfo, i))
					{
						out[nout] = i;
						nout++;
					}
				}
				if (n > nout)
					n = nout;

				// Shuffle
				for (int i = 0; i < n; i++)
					std::swap(out[i], out[cry_random(0, nout - 1)]);

				// Set outputs.
				for (int i = 0; i < n; i++)
				{
					if (out[i] == -1)
						continue;
					ActivateOutput(pActInfo,out[i],GetPortAny(pActInfo, 0));
				}

			}
			break;
		}
	}
Esempio n. 8
0
//-----------------------------------------------------------------------
bool CSpectacularKill::GetValidAnim(const CActor* pTarget, SSpectacularKillAnimation& anim) const
{
	CRY_ASSERT(pTarget);

	bool bSuccess = false;

	const SSpectacularKillParams* pTargetClassParams = GetParamsForClass(pTarget->GetEntity()->GetClass());
	if (pTargetClassParams)
	{
		TSpectacularKillAnimVector validAnims;
		std::remove_copy_if(pTargetClassParams->animations.begin(), pTargetClassParams->animations.end(), std::back_inserter(validAnims), SPredNotValidAnim(*this, pTarget));
		int iNumValidAnims = static_cast<int>(validAnims.size());
		if (iNumValidAnims > 0)
		{
			anim = validAnims[cry_random(0, iNumValidAnims - 1)];
			bSuccess = true;
		}
		else
		{
			DebugLog("Can't start from %s to %s: no animation matches current context", m_pOwner->GetEntity()->GetName(), pTarget->GetEntity()->GetName());
		}
	}
	else
	{
		DebugLog("Can't start from %s to %s: no parameters for target class %s", m_pOwner->GetEntity()->GetName(), pTarget->GetEntity()->GetName(), pTarget->GetEntity()->GetClass()->GetName());
	}

	return bSuccess;
}
Esempio n. 9
0
TMFXEffectBasePtr CMFXRandomizerContainer::ChooseCandidate( const SMFXRunTimeEffectParams& params ) const
{
	const size_t nEffects = m_effects.size();
	if (nEffects == 0)
		return TMFXEffectBasePtr(NULL);

	CryFixedArray<TMFXEffectBasePtr, 16> candidatesArray;

	TMFXEffects::const_iterator it    = m_effects.begin();
	TMFXEffects::const_iterator itEnd = m_effects.end();
	while ((it != itEnd) && !candidatesArray.isfull())
	{
		const TMFXEffectBasePtr& pEffect = *it;
		if (pEffect->CanExecute(params))
		{
			candidatesArray.push_back(pEffect);
		}
		++it;
	}

	TMFXEffectBasePtr pChosenEffect = NULL;
	if (!candidatesArray.empty())
	{
		const uint32 randChoice = cry_random(0U, candidatesArray.size() - 1);
		pChosenEffect = candidatesArray[randChoice];
	}

	return pChosenEffect;
}
Esempio n. 10
0
void CView::ProcessShakeNormal_DoShaking( SShake* pShake, float frameTime)
{
	float t;
	if (pShake->nextShake <= 0.0f)
	{
		//angular
		pShake->goalShake.SetRotationXYZ(pShake->amount);
		if (pShake->flip)
			pShake->goalShake.Invert();

		//translational
		pShake->goalShakeVector = pShake->amountVector;
		if (pShake->flip)
			pShake->goalShakeVector = -pShake->goalShakeVector;

		if (pShake->doFlip)
			pShake->flip = !pShake->flip;

		//randomize it a little
		float randomAmt(pShake->randomness);
		float len(fabs(pShake->amount.x) + fabs(pShake->amount.y) + fabs(pShake->amount.z));
		len /= 3.0f;
		float r = len * randomAmt;
		pShake->goalShake *= Quat::CreateRotationXYZ(Ang3(cry_random(-r, r), cry_random(-r, r), cry_random(-r, r)));

		//translational randomization
		len                      = fabs(pShake->amountVector.x) + fabs(pShake->amountVector.y) + fabs(pShake->amountVector.z);
		len                     /= 3.0f;
		r                        = len * randomAmt;
		pShake->goalShakeVector += Vec3(cry_random(-r, r), cry_random(-r, r), cry_random(-r, r));

		//damp & bounce it in a non linear fashion
		t                       = 1.0f - (pShake->ratio * pShake->ratio);
		pShake->goalShake       = Quat::CreateSlerp(pShake->goalShake,IDENTITY,t);
		pShake->goalShakeVector = Vec3::CreateLerp(pShake->goalShakeVector,ZERO,t);

		pShake->nextShake = pShake->frequency;
	}

	pShake->nextShake = max(0.0f,pShake->nextShake - frameTime);

	t                 = min(1.0f,frameTime * (1.0f / pShake->frequency));
	pShake->shakeQuat = Quat::CreateSlerp(pShake->shakeQuat,pShake->goalShake,t);
	pShake->shakeQuat.Normalize();
	pShake->shakeVector = Vec3::CreateLerp(pShake->shakeVector,pShake->goalShakeVector,t);
}
Esempio n. 11
0
Vec3 CRateOfDeathSimple::CalculateTargetOffset( const float minRange, const float maxRange ) const
{
	// TODO: Change this later!
	const float randomRange = cry_random( minRange, maxRange );

	const Vec3 randomOffset = cry_random_unit_vector<Vec3>() * randomRange;

	return randomOffset;
}
Esempio n. 12
0
// Description:
//
// Arguments:
//
// Return:
//
void CPersonalSignalTimer::Reset( bool bAlsoEnable )
{
  CRY_ASSERT( m_bInit == true );

  if( m_fRateMin < m_fRateMax )
  {
    m_fTimer = cry_random( m_fRateMin, m_fRateMax );
  }
  else
  {
    m_fTimer = m_fRateMin;
  }

  SetEnabled( bAlsoEnable );
}
//------------------------------------------------------------------------
void CVehicleDamageBehaviorDetachPart::AttachParticleEffect(IEntity* pDetachedEntity, IParticleEffect* pEffect)
{
  if (pEffect)
	{
		int slot = pDetachedEntity->LoadParticleEmitter(-1, pEffect, NULL, false, true);

		if (IParticleEmitter* pParticleEmitter = pDetachedEntity->GetParticleEmitter(slot))
		{
			SpawnParams spawnParams;
			spawnParams.fSizeScale = cry_random(0.5f, 1.0f);

			pParticleEmitter->SetSpawnParams(spawnParams);
		}
	}
}
//------------------------------------------------------------------------
void CVehicleDamageBehaviorEffect::UpdateEffect(float randomness, float damageRatio)
{
	CRY_ASSERT(m_pDamageEffect);

	if(m_pDamageEffect)
	{
		if(IParticleEmitter *pParticleEmitter = m_pVehicle->GetEntity()->GetParticleEmitter(m_slot))
		{
			SpawnParams	spawnParams;

			spawnParams.fPulsePeriod = m_pDamageEffect->pulsePeriod * ((1.0f - randomness) * cry_random(0.0f, 1.0f));

			pParticleEmitter->SetSpawnParams(spawnParams);
		}
	}
}
Esempio n. 15
0
void CAntiCheatManager::KickPlayerDelayed(uint16 channelId, EDisconnectionCause reason, int nConfidence)
{
	if (CGameLobby* pGameLobby = g_pGame->GetGameLobby())
	{
		CryUserID userId = pGameLobby->GetUserIDFromChannelID(channelId);

		SDelayedKickData kickData;
		const float fMinDelay = GetAntiCheatVar(eAV_KD_Min, 5.0f);
		kickData.fKickCountdown = (cry_random(0.0f, 1.0f) * (GetAntiCheatVar(eAV_KD_Max, 25.0f) - fMinDelay)) + fMinDelay;	
		kickData.userId = userId;
		kickData.channelId = channelId;
		kickData.reason = reason;

		m_DelayedKickData.push_back(kickData);
	}
}
//------------------------------------------------------------------------
void CVehicleMovementStdBoat::Reset()
{
  CVehicleMovementBase::Reset();

  Lift(false);    
  m_waveTimer = cry_random(0.0f, gf_PI);

  m_prevAngle = 0.0f;
  m_diving = false;  
  m_wakeSlot = -1;
  m_rpmPitchDir = 0;
  m_waveSoundPitch = 0.f;
  m_inWater = false;  
	m_factorMaxSpeed = 1.f;
	m_factorAccel = 1.f;
}
Esempio n. 17
0
void CBoidBug::UpdateBugsBehavior( float dt,SBoidContext &bc )
{
	if (cry_random(0, 9) == 0)
	{
		// Randomally modify heading vector.
		m_heading.x += Boid::Frand()*0.2f*bc.factorAlignment; // Used as random movement.
		m_heading.y += Boid::Frand()*0.2f*bc.factorAlignment;
		m_heading.z += Boid::Frand()*0.1f*bc.factorAlignment;
		m_heading = m_heading.GetNormalized();
		if (bc.behavior == EBUGS_DRAGONFLY)
			m_speed = bc.MinSpeed + (bc.MaxSpeed - bc.MinSpeed)*Boid::Frand();
	}

	// Avoid player.
	Vec3 fromPlayerVec = Vec3( m_pos.x-bc.playerPos.x, m_pos.y-bc.playerPos.y, 0 );
	if ((fromPlayerVec).GetLengthSquared() < BUGS_SCARE_DISTANCE*BUGS_SCARE_DISTANCE) // 2 meters.
	{
		float d = (BUGS_SCARE_DISTANCE - fromPlayerVec.GetLength());
		m_accel += 5.0f * fromPlayerVec * d;
	}

	// Maintain average speed.
	float targetSpeed = (bc.MaxSpeed + bc.MinSpeed)/2;
	m_accel -= m_heading*(m_speed-targetSpeed)*0.5f;

	//m_accel = (m_targetPos - m_pos)*bc.factorAttractToOrigin;

	if (m_pos.z < bc.terrainZ+bc.MinHeight)
	{
		m_accel.z = (bc.terrainZ+bc.MinHeight-m_pos.z)*bc.factorAttractToOrigin;
	}
	else if (m_pos.z > bc.terrainZ+bc.MaxHeight)
	{
		m_accel.z = -(m_pos.z-bc.terrainZ+bc.MinHeight)*bc.factorAttractToOrigin;
	}
	else
	{
		// Always try to accelerate in direction oposite to current in Z axis.
		m_accel.z += -m_heading.z * 0.2f;
	}
}
Esempio n. 18
0
void CVTOLVehicleManager::CreateExplosion(IParticleEffect *inParticleEffect, const Vec3& pos, const float inEffectScale, TAudioSignalID inAudioSignal/*=INVALID_AUDIOSIGNAL_ID*/)
{
#if !defined(DEDICATED_SERVER)
	CRY_ASSERT_MESSAGE(inParticleEffect, "CreateExplosion() passsed a NULL inParticleEffect");
#endif

	if (gEnv->bServer)
	{
		// server wants to create actual explosions
		CGameRules *pGameRules = g_pGame->GetGameRules();

		ExplosionInfo explosionInfo;
		explosionInfo.pParticleEffect = inParticleEffect;
		explosionInfo.effect_name = s_explosionEffectName;// needed so the explosion can be synced to clients
		explosionInfo.type = pGameRules->GetHitTypeId("explosion");
		explosionInfo.effect_scale = inEffectScale; // this is likely not connected up in the particle effect but should be able to be so that the effect can be adjusted dynamically
		explosionInfo.pos = pos; 
		explosionInfo.dir.Set(0.0f,-1.0f,0.0f);
		explosionInfo.effect_scale = cry_random(0.9f,1.1f);
		explosionInfo.pressure = 1000.0f;
		explosionInfo.maxblurdistance = 10.0;
		explosionInfo.radius = 12.0f;
		explosionInfo.blindAmount = 0.0f;
		explosionInfo.flashbangScale = 8.0f;
		explosionInfo.damage = 0.0f;
		explosionInfo.hole_size = 0.0f;

		pGameRules->QueueExplosion(explosionInfo);
	}
	// the gamerules SHOULD be syncing the server queued ones above to clients!

	if (inAudioSignal != INVALID_AUDIOSIGNAL_ID)
	{
		CAudioSignalPlayer::JustPlay(inAudioSignal, pos);
	}
}
Esempio n. 19
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);
				}
			}
		}
	}
}//-------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------
bool CVehicleMovementStdBoat::Init(IVehicle* pVehicle, const CVehicleParams& table)
{
  if (!CVehicleMovementBase::Init(pVehicle, table))
    return false;
  
  MOVEMENT_VALUE("velMax", m_velMax);      
  MOVEMENT_VALUE("velMaxReverse", m_velMaxReverse);
  MOVEMENT_VALUE("acceleration", m_accel);      
  MOVEMENT_VALUE("accelerationVelMax", m_accelVelMax);      
  MOVEMENT_VALUE("accelerationMultiplier", m_accelCoeff);         
  MOVEMENT_VALUE("pushTilt", m_pushTilt);     
  MOVEMENT_VALUE("turnRateMax", m_turnRateMax);
  MOVEMENT_VALUE("turnAccel", m_turnAccel);      
  MOVEMENT_VALUE("cornerForce", m_cornerForceCoeff);      
  MOVEMENT_VALUE("cornerTilt", m_cornerTilt);    
  MOVEMENT_VALUE("turnDamping", m_turnDamping); 
  MOVEMENT_VALUE("turnAccelMultiplier", m_turnAccelCoeff);
  MOVEMENT_VALUE_OPT("rollAccel", m_rollAccel, table);
  MOVEMENT_VALUE_OPT("pedalLimitReverse", m_pedalLimitReverse, table);
  MOVEMENT_VALUE_OPT("turnVelocityMult", m_turnVelocityMult, table);
  MOVEMENT_VALUE_OPT("velLift", m_velLift, table);
  MOVEMENT_VALUE_OPT("lateralDamping", m_lateralDamping, table);
  
  table.getAttr("waveIdleStrength", m_waveIdleStrength);
  table.getAttr("waveSpeedMult", m_waveSpeedMult);
  
  if (table.haveAttr("cornerHelper"))
	{
		if (IVehicleHelper* pHelper = m_pVehicle->GetHelper(table.getAttr("cornerHelper")))
			m_cornerOffset = pHelper->GetVehicleSpaceTranslation();
	}

  if (table.haveAttr("pushHelper"))
	{
		if (IVehicleHelper* pHelper = m_pVehicle->GetHelper(table.getAttr("pushHelper")))
			m_pushOffset = pHelper->GetVehicleSpaceTranslation();
	}

  // compute inertia [assumes box]
  AABB bbox;	
  
  IVehiclePart* pMassPart = pVehicle->GetPart("mass");
  if (!pMassPart)
    pMassPart = pVehicle->GetPart("massBox");
	
  if (pMassPart)
	{
		bbox = pMassPart->GetLocalBounds();
	}
	else
	{
		GameWarning("[CVehicleMovementStdBoat]: initialization: No \"mass\" geometry found!");
		m_pEntity->GetLocalBounds(bbox);
	}

  m_maxSpeed = m_velMax;
	float mass = pVehicle->GetMass();
  
  float width = bbox.max.x - bbox.min.x;
  float length = bbox.max.y - bbox.min.y;
  float height = bbox.max.z - bbox.min.z;
  m_Inertia.x = mass * (sqr(length)+ sqr(height)) / 12;
  m_Inertia.y = mass * (sqr(width) + sqr(height)) / 12;
  m_Inertia.z = mass * (sqr(width) + sqr(length)) / 12;
  
  m_massOffset = bbox.GetCenter();

  //CryLog("[StdBoat movement]: got mass offset (%f, %f, %f)", m_massOffset.x, m_massOffset.y, m_massOffset.z);

	m_pSplashPos = m_pVehicle->GetHelper("splashPos");

	if (m_pSplashPos)
		m_lastWakePos = m_pSplashPos->GetWorldSpaceTranslation();
	else
		m_lastWakePos = m_pVehicle->GetEntity()->GetWorldTM().GetTranslation();

	const char* waveEffect = "";
	MOVEMENT_VALUE_OPT("waveEffect", &waveEffect, table);
	m_pWaveEffect = gEnv->pParticleManager->FindEffect(waveEffect, "MovementStdBoat");

  m_waveTimer = cry_random(0.0f, gf_PI);
  m_diving = false;
  m_wakeSlot = -1;   
  m_waveSoundPitch = 0.f;
  m_rpmPitchDir = 0;
  m_waveSoundAmount = 0.1f;

  // AI related
  m_prevAngle = 0.0f;
  
	m_factorMaxSpeed = 1.f;
	m_factorAccel = 1.f;

  return true;
}
Esempio n. 21
0
//--------------------------------------------------------------------------------------------------
// Name: SpawnParticlesOnSkeleton
// Desc: Spawn particles on Skeleton
//--------------------------------------------------------------------------------------------------
void CGameEffect::SpawnParticlesOnSkeleton(IEntity* pEntity, IParticleEmitter* pParticleEmitter, uint32 numParticles,float maxHeightScale) const
{
	if((pEntity) && (numParticles>0) && (pParticleEmitter) && (maxHeightScale>0.0f))
	{
		ICharacterInstance* pCharacter = pEntity->GetCharacter(0);
		if(pCharacter)
		{
			IDefaultSkeleton& rIDefaultSkeleton = pCharacter->GetIDefaultSkeleton();
			ISkeletonPose* pPose = pCharacter->GetISkeletonPose();
			if(pPose)
			{
				Vec3 animPos;
				Quat animRot;

				IActor* pActor = gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pEntity->GetId());
				if(pActor) // First try to get animation data
				{
					QuatT animLoc = pActor->GetAnimatedCharacter()->GetAnimLocation();
					animPos = animLoc.t;
					animRot = animLoc.q;
				}
				else // If no actor, then use entity data
				{
					animPos = pEntity->GetWorldPos();
					animRot = pEntity->GetWorldRotation();
				}

				animRot.Invert();

				AABB bbox;
				pEntity->GetLocalBounds(bbox);
				float bbHeight = bbox.max.z - bbox.min.z;
				// Avoid division by 0
				if(bbHeight == 0)
				{
					bbHeight = 0.0001f;
				}

				const uint32 numJoints = rIDefaultSkeleton.GetJointCount();

				for (uint32 i = 0; i < numParticles; ++i)
				{
					int id = cry_random(0U, numJoints - 1);
					int parentId = rIDefaultSkeleton.GetJointParentIDByID(id);

					if(parentId>0)
					{
						QuatT boneQuat = pPose->GetAbsJointByID(id);
						QuatT parentBoneQuat= pPose->GetAbsJointByID(parentId);
						float lerpScale = cry_random(0.0f, 1.0f);

						QuatTS loc(IDENTITY);
						loc.t = LERP(boneQuat.t,parentBoneQuat.t,lerpScale);

						float heightScale = ((loc.t.z - bbox.min.z) / bbHeight);
						if(heightScale < maxHeightScale)
						{
							loc.t = loc.t * animRot;
							loc.t = loc.t + animPos;

							pParticleEmitter->EmitParticle(NULL, NULL, &loc);
						}
					}
				}
			}
		}
	}
}//-------------------------------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// NOTE: This function must be thread-safe. Before adding stuff contact MarcoC.
void CVehicleMovementStdBoat::ProcessMovement(const float deltaTime)
{  
  FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

  static const float fWaterLevelMaxDiff = 0.15f; // max allowed height difference between propeller center and water level
  static const float fSubmergedMin = 0.01f;
  static const float fMinSpeedForTurn = 0.5f; // min speed so that turning becomes possible
  
  if (m_bNetSync)
    m_netActionSync.UpdateObject(this);

  CryAutoCriticalSection lk(m_lock);

  CVehicleMovementBase::ProcessMovement(deltaTime);

  IEntity* pEntity = m_pVehicle->GetEntity();
  IPhysicalEntity* pPhysics = pEntity->GetPhysics(); 
  SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread];
  assert(pPhysics);

  float frameTime = min(deltaTime, 0.1f); 

  if (abs(m_movementAction.power) < 0.001f)
    m_movementAction.power = 0.f;
  if (abs(m_movementAction.rotateYaw) < 0.001f)
    m_movementAction.rotateYaw = 0.f;

  Matrix34 wTM( physStatus->q );
  wTM.AddTranslation( physStatus->pos );

  Matrix34 wTMInv = wTM.GetInvertedFast();
    
  Vec3 localVel = wTMInv.TransformVector( physStatus->v );
  Vec3 localW = wTMInv.TransformVector( physStatus->w );   

  const Vec3 xAxis = wTM.GetColumn0();
  const Vec3 yAxis = wTM.GetColumn1();
  const Vec3 zAxis = wTM.GetColumn2();
  
  // check if propeller is in water
  Vec3 worldPropPos = wTM * m_pushOffset;  
  float waterLevelWorld = gEnv->p3DEngine->GetWaterLevel( &worldPropPos );
  float fWaterLevelDiff = worldPropPos.z - waterLevelWorld;  
  
  bool submerged = physStatus->submergedFraction > fSubmergedMin;
  m_inWater = submerged && fWaterLevelDiff < fWaterLevelMaxDiff;
    
  float speed = physStatus->v.len2() > 0.001f ? physStatus->v.len() : 0.f;    
  float speedRatio = min(1.f, speed/(m_maxSpeed*m_factorMaxSpeed));  
  float absPedal = abs(m_movementAction.power);
  float absSteer = abs(m_movementAction.rotateYaw);
 
  // wave stuff 
  float waveFreq = 1.f;
  waveFreq += 3.f*speedRatio;

  float waveTimerPrev = m_waveTimer;
  m_waveTimer += frameTime*waveFreq;

  // new randomized amount for this oscillation
  if (m_waveTimer >= gf_PI && waveTimerPrev < gf_PI) 
    m_waveRandomMult = cry_random(0.0f, 1.0f);  
  
  if (m_waveTimer >= 2*gf_PI)  
    m_waveTimer -= 2*gf_PI;    

  float kx = m_waveIdleStrength.x*(m_waveRandomMult+0.3f) * (1.f-speedRatio + m_waveSpeedMult*speedRatio);
  float ky = m_waveIdleStrength.y * (1.f - 0.5f*absPedal - 0.5f*absSteer);

  Vec3 waveLoc = m_massOffset;
  waveLoc.y += speedRatio*min(0.f, m_pushOffset.y-m_massOffset.y);
  waveLoc = wTM * waveLoc;

  bool visible = m_pVehicle->GetGameObject()->IsProbablyVisible();
  bool doWave = visible && submerged && physStatus->submergedFraction < 0.99f;
    
  if (doWave && !m_isEnginePowered)
    m_pVehicle->NeedsUpdate(IVehicle::eVUF_AwakePhysics);
  
  if (m_isEnginePowered || (visible && !m_pVehicle->IsProbablyDistant()))
  {
    if (doWave && (m_isEnginePowered || g_pGameCVars->v_rockBoats))
    { 
      pe_action_impulse waveImp;
      waveImp.angImpulse.x = Boosting() ? 0.f : sinf(m_waveTimer) * frameTime * m_Inertia.x * kx;
      
      if (isneg(waveImp.angImpulse.x))
        waveImp.angImpulse.x *= (1.f - min(1.f, 2.f*speedRatio)); // less amplitude for negative impulse      

      waveImp.angImpulse.y = sinf(m_waveTimer-0.5f*gf_PI) * frameTime * m_Inertia.y * ky;  
      waveImp.angImpulse.z = 0.f;
      waveImp.angImpulse = wTM.TransformVector(waveImp.angImpulse);
      waveImp.point = waveLoc;
      if (!m_movementAction.isAI)
	      pPhysics->Action(&waveImp, 1);      
    }
  }
  // ~wave stuff 

	if (!m_isEnginePowered)
		return;

  pe_action_impulse linearImp, angularImp, dampImp, liftImp; 
  float turnAccel = 0, turnAccelNorm = 0;

	if (m_inWater)
	{     
    // Lateral damping
    if (m_lateralDamping>0.f)
    {
    		pe_action_impulse impulse;
    		impulse.impulse = - physStatus->mass * xAxis * (localVel.x * (frameTime * m_lateralDamping)/(1.f + frameTime*m_lateralDamping));
    		pPhysics->Action(&impulse, 1);
    }
    // optional lifting (catamarans)
    if (m_velLift > 0.f)
    {
      if (localVel.y > m_velLift && !IsLifted())
        Lift(true);
      else if (localVel.y < m_velLift && IsLifted())
        Lift(false);
    }

    if (Boosting() && IsLifted())
    {
      // additional lift force      
      liftImp.impulse = Vec3(0,0,physStatus->mass*frameTime*(localVel.y/(m_velMax*m_factorMaxSpeed))*3.f);
      liftImp.point = wTM * m_massOffset;
      pPhysics->Action(&liftImp, 1);
    }
    
    // apply driving force         
    float a = m_movementAction.power;

    if (sgn(a)*sgn(localVel.y) > 0)
    {
      // reduce acceleration with increasing speed
      float ratio = (localVel.y > 0.f) ? localVel.y/(m_velMax*m_factorMaxSpeed) : -localVel.y/(m_velMaxReverse*m_factorMaxSpeed);      
      a = (ratio>1.f) ? 0.f : sgn(a)*min(abs(a), 1.f-((1.f-m_accelVelMax)*sqr(ratio))); 
    }
    
    if (a != 0)
    {
      if (sgn(a) * sgn(localVel.y) < 0) // "braking"
        a *= m_accelCoeff;    
      else
        a = max(a, -m_pedalLimitReverse);

      Vec3 pushDir(FORWARD_DIRECTION);                
      
      // apply force downwards a bit for more realistic response  
      if (a > 0)
        pushDir = Quat_tpl<float>::CreateRotationAA( DEG2RAD(m_pushTilt), Vec3(-1,0,0) ) * pushDir;

      pushDir = wTM.TransformVector( pushDir );  
      linearImp.impulse = pushDir * physStatus->mass * a * m_accel * m_factorAccel * frameTime;

      linearImp.point = m_pushOffset;
      linearImp.point.x = m_massOffset.x;
      linearImp.point = wTM * linearImp.point;
			pPhysics->Action(&linearImp, 1);
    } 
    
    float roll = (float)__fsel(zAxis.z - 0.2f, xAxis.z / (frameTime + frameTime*frameTime), 0.f);		// Roll damping (with a exp. time constant of 1 sec)

    // apply steering           
    if (m_movementAction.rotateYaw != 0)
    { 
      if (abs(localVel.y) < fMinSpeedForTurn){ // if forward speed too small, no turning possible
        turnAccel = 0; 
      }
      else 
      {
        int iDir = m_movementAction.power != 0.f ? sgn(m_movementAction.power) : sgn(localVel.y);
        turnAccelNorm = m_movementAction.rotateYaw * iDir * max(1.f, m_turnVelocityMult * speedRatio);    

        // steering and current w in same direction?
        int sgnSteerW = sgn(m_movementAction.rotateYaw) * iDir * sgn(-localW.z);

        if (sgnSteerW < 0)
        { 
          // "braking"
          turnAccelNorm *= m_turnAccelCoeff; 
        }
        else 
        {    
          // reduce turn vel towards max
          float maxRatio = 1.f - 0.15f*min(1.f, abs(localW.z)/m_turnRateMax);
          turnAccelNorm = sgn(turnAccelNorm) * min(abs(turnAccelNorm), maxRatio);
        }

        turnAccel = turnAccelNorm * m_turnAccel;
        //roll = 0.2f * turnAccel; // slight roll        
      }        
    }   

		// Use the centripetal acceleration to determine the amount of roll
		float centripetalAccel = clamp_tpl(speed * localW.z, -10.f, +10.f);
		roll -= (1.f - 2.f*fabsf(xAxis.z)) * m_rollAccel * centripetalAccel;

		// Always damp rotation!
		turnAccel += localW.z * m_turnDamping;
    
    if (turnAccel != 0)
    {
      Vec3& angImp = angularImp.angImpulse; 
      
      angImp.x = 0.f;
      angImp.y = roll * frameTime * m_Inertia.y;
      angImp.z = -turnAccel * frameTime * m_Inertia.z;      
      
      angImp = wTM.TransformVector( angImp );
      pPhysics->Action(&angularImp, 1);
    }   
    
    if (abs(localVel.x) > 0.01f)  
    { 
      // lateral force         
      Vec3& cornerForce = dampImp.impulse;
      
      cornerForce.x = -localVel.x * m_cornerForceCoeff * physStatus->mass * frameTime;
      cornerForce.y = 0.f;
      cornerForce.z = 0.f;
      
      if (m_cornerTilt != 0)
        cornerForce = Quat_tpl<float>::CreateRotationAA( sgn(localVel.x)*DEG2RAD(m_cornerTilt), Vec3(0,1,0) ) * cornerForce;

      dampImp.impulse = wTM.TransformVector(cornerForce);

      dampImp.point = m_cornerOffset;
      dampImp.point.x = m_massOffset.x;
      dampImp.point = wTM.TransformPoint( dampImp.point );
      pPhysics->Action(&dampImp, 1);         
    }  
  }

  EjectionTest(deltaTime);
  
	if (!m_pVehicle->GetStatus().doingNetPrediction)
	{
		if (m_bNetSync && m_netActionSync.PublishActions( CNetworkMovementStdBoat(this) ))
			CHANGED_NETWORK_STATE(m_pVehicle, CNetworkMovementStdBoat::CONTROLLED_ASPECT );
	}
}
Esempio n. 23
0
	virtual void ProcessEvent( EFlowEvent event, SActivationInfo * pActInfo )
	{
		switch (event)
		{
		case eFE_ConnectOutputPort:
			if (pActInfo->connectPort < NUM_OUTPUTS)
			{
				++m_nConnectionCounts[pActInfo->connectPort];
				// check if already connected
				for (int i=0; i<m_nOutputCount; ++i)
				{
					if (m_nConnectedPorts[i] == pActInfo->connectPort) 
						return;
				}
				m_nConnectedPorts[m_nOutputCount++] = pActInfo->connectPort;
				Reset();
			}
			break;
		case eFE_DisconnectOutputPort:
			if (pActInfo->connectPort < NUM_OUTPUTS)
			{
				for (int i=0; i<m_nOutputCount; ++i)
				{
					// check if really connected
					if (m_nConnectedPorts[i] == pActInfo->connectPort)
					{
						if (m_nConnectionCounts[pActInfo->connectPort] == 1)
						{
							m_nConnectedPorts[i] = m_nPorts[m_nOutputCount - 1]; // copy last value to here
							m_nConnectedPorts[m_nOutputCount - 1] = -1;
							--m_nOutputCount;
							Reset();
						}
						--m_nConnectionCounts[pActInfo->connectPort];
						return;
					}
				}
			}
			break;
		case eFE_Initialize:
			Reset();
			break;

		case eFE_Activate:
			if (IsPortActive(pActInfo, EIP_Reset))
			{
				Reset();
			}
			if (IsPortActive(pActInfo, EIP_Input))
			{
				int numCandidates = m_nOutputCount - m_nTriggered;
				if (numCandidates <= 0)
					return;
				const int cand = cry_random(0, numCandidates - 1);
				const int whichPort = m_nPorts[cand];
				m_nPorts[cand] = m_nPorts[numCandidates-1];
				m_nPorts[numCandidates-1] = -1;
				++m_nTriggered;
				assert (whichPort >= 0 && whichPort < NUM_OUTPUTS);
				// CryLogAlways("CFlowNode_RandomTrigger: Activating %d", whichPort);
				ActivateOutput(pActInfo, whichPort, GetPortAny(pActInfo, EIP_Input));
				assert (m_nTriggered > 0 && m_nTriggered <= m_nOutputCount);
				if (m_nTriggered == m_nOutputCount)
				{
					// CryLogAlways("CFlowNode_RandomTrigger: Done.");
					// Done
					ActivateOutput(pActInfo, NUM_OUTPUTS, true);
					Reset();
				}
			}
			break;
		}
	}
Esempio n. 24
0
bool CShotgun::Shoot(bool resetAnimation, bool autoreload/* =true */, bool isRemote)
{
	CCCPOINT(Shotgun_TryShoot);

	m_firePending = false;
	m_shotIndex++;

	IEntityClass* ammo = m_fireParams->fireparams.ammo_type_class;
	int ammoCount = m_pWeapon->GetAmmoCount(ammo);

	int clipSize = GetClipSize();
	if (clipSize == 0)
		ammoCount = m_pWeapon->GetInventoryAmmoCount(ammo);

	CActor *pActor = m_pWeapon->GetOwnerActor();
	bool playerIsShooter = pActor ? pActor->IsPlayer() : false;
	bool shooterIsClient = pActor ? pActor->IsClient() : false;

	if (!CanFire(true))
	{
		if ((ammoCount <= 0) && (!m_reloading))
		{
			m_pWeapon->PlayAction(GetFragmentIds().empty_clip);
			m_pWeapon->OnFireWhenOutOfAmmo();
			CCCPOINT(Shotgun_TryShootWhileOutOfAmmo);
		}
		else
		{
			CCCPOINT(Shotgun_TryShootWhileCannotBeFired);
		}
		return false;
	}

	if (m_reloading)
	{
		if(m_pWeapon->IsBusy())
			m_pWeapon->SetBusy(false);
		
		if(CanFire(true) && !m_break_reload)
		{
			m_break_reload = true;
			m_pWeapon->RequestCancelReload();
		}
		CCCPOINT(Shotgun_TryShootWhileReloading);
		return false;
	}

	uint32 flags = CItem::eIPAF_Default;
	if (IsProceduralRecoilEnabled() && pActor)
	{
		pActor->ProceduralRecoil(m_fireParams->proceduralRecoilParams.duration, m_fireParams->proceduralRecoilParams.strength, m_fireParams->proceduralRecoilParams.kickIn, m_fireParams->proceduralRecoilParams.arms);
	}

	float speedOverride = -1.f;

	m_pWeapon->PlayAction(GetFragmentIds().fire, 0, false, flags, speedOverride);

	Vec3 hit = GetProbableHit(WEAPON_HIT_RANGE);
	Vec3 pos = GetFiringPos(hit);
	Vec3 fdir = GetFiringDir(hit, pos);
	Vec3 vel = GetFiringVelocity(fdir);
	Vec3 dir;
	const float hitDist = hit.GetDistance(pos);

	CheckNearMisses(hit, pos, fdir, WEAPON_HIT_RANGE, m_fireParams->shotgunparams.spread);
	
	CRY_ASSERT_MESSAGE(m_fireParams->fireparams.hitTypeId, string().Format("Invalid hit type '%s' in fire params for '%s'", m_fireParams->fireparams.hit_type.c_str(), m_pWeapon->GetEntity()->GetName()));
	CRY_ASSERT_MESSAGE(m_fireParams->fireparams.hitTypeId == g_pGame->GetGameRules()->GetHitTypeId(m_fireParams->fireparams.hit_type.c_str()), "Sanity Check Failed: Stored hit type id does not match the type string, possibly CacheResources wasn't called on this weapon type");

	int quad = cry_random(0, 3);
	const int numPellets = m_fireParams->shotgunparams.pellets;

	std::vector<CProjectile*> projList;
	projList.reserve(numPellets);

	int ammoCost = (m_fireParams->fireparams.fake_fire_rate && playerIsShooter) ? m_fireParams->fireparams.fake_fire_rate : 1;
	ammoCost = min(ammoCost, ammoCount);

	EntityId firstAmmoId = 0;

	// SHOT HERE
	for (int i = 0; i < numPellets; i++)
	{
		CProjectile *pAmmo = m_pWeapon->SpawnAmmo(m_fireParams->fireparams.spawn_ammo_class, false);
		if (pAmmo)
		{
			if(!firstAmmoId)
			{
				firstAmmoId = pAmmo->GetEntityId();
			}

			projList.push_back(pAmmo);

			dir = ApplySpread(fdir, m_fireParams->shotgunparams.spread, quad);  
			quad = (quad+1)%4;
			
			int pelletDamage = m_fireParams->shotgunparams.pelletdamage;
			if (!playerIsShooter)
				pelletDamage += m_fireParams->shotgunparams.npc_additional_damage;

			const bool canOvercharge = m_pWeapon->GetSharedItemParams()->params.can_overcharge;
			const float overchargeModifier = pActor ? pActor->GetOverchargeDamageScale() : 1.0f;
			if (canOvercharge)
			{
				pelletDamage = int(pelletDamage * overchargeModifier);
			}

			CProjectile::SProjectileDesc projectileDesc(
				m_pWeapon->GetOwnerId(), m_pWeapon->GetHostId(), m_pWeapon->GetEntityId(), pelletDamage, m_fireParams->fireparams.damage_drop_min_distance,
				m_fireParams->fireparams.damage_drop_per_meter, m_fireParams->fireparams.damage_drop_min_damage, m_fireParams->fireparams.hitTypeId, m_fireParams->fireparams.bullet_pierceability_modifier, m_pWeapon->IsZoomed());
			projectileDesc.pointBlankAmount = m_fireParams->fireparams.point_blank_amount;
			projectileDesc.pointBlankDistance = m_fireParams->fireparams.point_blank_distance;
			projectileDesc.pointBlankFalloffDistance = m_fireParams->fireparams.point_blank_falloff_distance;
			if (m_fireParams->fireparams.ignore_damage_falloff)
				projectileDesc.damageFallOffAmount = 0.0f;
			
			const Vec3 pelletDestination = pos + (dir * hitDist);

			pAmmo->SetParams(projectileDesc);
			pAmmo->SetDestination(m_pWeapon->GetDestination());
			pAmmo->Launch(pos, dir, vel);
			pAmmo->CreateBulletTrail( pelletDestination );
			pAmmo->SetKnocksTargetInfo( GetShared() );

			if ((!m_fireParams->tracerparams.geometry.empty() || !m_fireParams->tracerparams.effect.empty()) && ((ammoCount == clipSize) || (ammoCount%m_fireParams->tracerparams.frequency==0)))
			{
				EmitTracer(pos, pelletDestination, &m_fireParams->tracerparams, pAmmo);
			}

			if(shooterIsClient)
			{
				pAmmo->RegisterLinkedProjectile(m_shotIndex);
				
				if(gEnv->bMultiplayer)
				{
					float damageCap = g_pGameCVars->pl_shotgunDamageCap;
					pAmmo->SetDamageCap(damageCap);
				}
			}
			
			m_projectileId = pAmmo->GetEntity()->GetId();

			pAmmo->SetAmmoCost(ammoCost);
		}
	}

	if (m_pWeapon->IsServer())
	{
		const char *ammoName = ammo != NULL ? ammo->GetName() : NULL;
		g_pGame->GetIGameFramework()->GetIGameplayRecorder()->Event(m_pWeapon->GetOwner(), GameplayEvent(eGE_WeaponShot, ammoName, m_fireParams->shotgunparams.pellets, (void *)(EXPAND_PTR)m_pWeapon->GetEntityId()));
	}

	m_muzzleEffect.Shoot(this, hit, m_barrelId);

	m_fired = true;
	SetNextShotTime(m_next_shot + m_next_shot_dt);

	ammoCount -= ammoCost;

	if (ammoCount < m_fireParams->fireparams.minimum_ammo_count)
		ammoCount = 0;

	if (clipSize != -1)
	{
		if (clipSize != 0)
			m_pWeapon->SetAmmoCount(ammo, ammoCount);
		else
			m_pWeapon->SetInventoryAmmoCount(ammo, ammoCount);
	}

	OnShoot(m_pWeapon->GetOwnerId(), firstAmmoId, ammo, pos, dir, vel);

	const SThermalVisionParams& thermalParams = m_fireParams->thermalVisionParams;
	m_pWeapon->AddShootHeatPulse(pActor, thermalParams.weapon_shootHeatPulse, thermalParams.weapon_shootHeatPulseTime,
		thermalParams.owner_shootHeatPulse, thermalParams.owner_shootHeatPulseTime);

	if (OutOfAmmo())
	{
		m_pWeapon->OnOutOfAmmo(ammo);
		if (autoreload)
		{
			uint32 scheduleTime = max(m_pWeapon->GetCurrentAnimationTime(eIGS_Owner), (uint)(m_next_shot*1000));
			m_pWeapon->GetScheduler()->TimerAction(scheduleTime, CSchedulerAction<ScheduleReload>::Create(ScheduleReload(this, m_pWeapon)), false);
			m_autoReloading = true;
		}
	}

	m_pWeapon->RequestShoot(ammo, pos, dir, vel, hit, 1.0f, 0, false);

#if defined(ANTI_CHEAT)
	const int numProjectiles = projList.size();
	uint32 shotId	= m_pWeapon->GetLastShotId();
	for(int i = 0; i < numProjectiles; i++)
	{
		CProjectile * pAmmo = projList[i];
		pAmmo->SetShotId(shotId);
		shotId -= (1 << CWeapon::GetShotIdCountOffset());
	}
#endif

	CCCPOINT(Shotgun_Fired);

	return true;
}
Esempio n. 25
0
//------------------------------------------------------------------------
void CShotgun::NetShootEx(const Vec3 &pos, const Vec3 &dir, const Vec3 &vel, const Vec3 &hit, float extra, int ph)
{
	CCCPOINT(Shotgun_NetShoot);

	assert(0 == ph);
	
	IEntityClass* ammo = m_fireParams->fireparams.ammo_type_class;
	FragmentID action = m_fireParams->fireparams.no_cock ? GetFragmentIds().fire : GetFragmentIds().fire_cock;

	CActor *pActor = m_pWeapon->GetOwnerActor();
	bool playerIsShooter = pActor?pActor->IsPlayer():false;

	int ammoCount = m_pWeapon->GetAmmoCount(ammo);
	int clipSize = GetClipSize();
	if (clipSize == 0)
		ammoCount = m_pWeapon->GetInventoryAmmoCount(ammo);

	if (ammoCount == 1)
		action = GetFragmentIds().fire;

	if (IsProceduralRecoilEnabled() && pActor)
	{
		pActor->ProceduralRecoil(m_fireParams->proceduralRecoilParams.duration, m_fireParams->proceduralRecoilParams.strength, m_fireParams->proceduralRecoilParams.kickIn,m_fireParams->proceduralRecoilParams.arms);
	}

	m_pWeapon->PlayAction(action, 0, false, CItem::eIPAF_Default);

	Vec3 pdir;

	int quad = cry_random(0, 3);

	CRY_ASSERT_MESSAGE(m_fireParams->fireparams.hitTypeId, string().Format("Invalid hit type '%s' in fire params for '%s'", m_fireParams->fireparams.hit_type.c_str(), m_pWeapon->GetEntity()->GetName()));
	CRY_ASSERT_MESSAGE(m_fireParams->fireparams.hitTypeId == g_pGame->GetGameRules()->GetHitTypeId(m_fireParams->fireparams.hit_type.c_str()), "Sanity Check Failed: Stored hit type id does not match the type string, possibly CacheResources wasn't called on this weapon type");

	int ammoCost = m_fireParams->fireparams.fake_fire_rate ? m_fireParams->fireparams.fake_fire_rate : 1;
	ammoCost = min(ammoCost, ammoCount);

	// SHOT HERE
	for (int i = 0; i < m_fireParams->shotgunparams.pellets; i++)
	{
		CProjectile *pAmmo = m_pWeapon->SpawnAmmo(m_fireParams->fireparams.spawn_ammo_class, true);
		if (pAmmo)
		{
			pdir = ApplySpread(dir, m_fireParams->shotgunparams.spread, quad);
			quad = (quad+1)%4;
		
			CProjectile::SProjectileDesc projectileDesc(
				m_pWeapon->GetOwnerId(), m_pWeapon->GetHostId(), m_pWeapon->GetEntityId(), m_fireParams->shotgunparams.pelletdamage, m_fireParams->fireparams.damage_drop_min_distance,
				m_fireParams->fireparams.damage_drop_min_damage, m_fireParams->fireparams.damage_drop_per_meter, m_fireParams->fireparams.hitTypeId, m_fireParams->fireparams.bullet_pierceability_modifier, m_pWeapon->IsZoomed());
			projectileDesc.pointBlankAmount = m_fireParams->fireparams.point_blank_amount;
			projectileDesc.pointBlankDistance = m_fireParams->fireparams.point_blank_distance;
			projectileDesc.pointBlankFalloffDistance = m_fireParams->fireparams.point_blank_falloff_distance;
			if (m_fireParams->fireparams.ignore_damage_falloff)
				projectileDesc.damageFallOffAmount = 0.0f;
			pAmmo->SetParams(projectileDesc);
			pAmmo->SetDestination(m_pWeapon->GetDestination());
			pAmmo->SetRemote(true);
			pAmmo->Launch(pos, pdir, vel);

			bool emit = false;
			if(m_pWeapon->GetStats().fp)
				emit = (!m_fireParams->tracerparams.geometryFP.empty() || !m_fireParams->tracerparams.effectFP.empty()) && ((ammoCount == clipSize) || (ammoCount%m_fireParams->tracerparams.frequency==0));
			else
				emit = (!m_fireParams->tracerparams.geometry.empty() || !m_fireParams->tracerparams.effect.empty()) && ((ammoCount == clipSize) || (ammoCount%m_fireParams->tracerparams.frequency==0));

			if (emit)
			{
				EmitTracer(pos, hit, &m_fireParams->tracerparams, pAmmo);
			}

			m_projectileId = pAmmo->GetEntity()->GetId();

			pAmmo->SetAmmoCost(ammoCost);
		}
	}

	if (m_pWeapon->IsServer())
	{
		const char *ammoName = ammo != NULL ? ammo->GetName() : NULL;
		g_pGame->GetIGameFramework()->GetIGameplayRecorder()->Event(m_pWeapon->GetOwner(), GameplayEvent(eGE_WeaponShot, ammoName, m_fireParams->shotgunparams.pellets, (void *)(EXPAND_PTR)m_pWeapon->GetEntityId()));
	}

	m_muzzleEffect.Shoot(this, hit, m_barrelId);

	m_fired = true;
	m_next_shot = 0.0f;

	ammoCount -= ammoCost;

	if (m_pWeapon->IsServer())
	{
		if (clipSize != -1)
		{
			if (clipSize != 0)
				m_pWeapon->SetAmmoCount(ammo, ammoCount);
			else
				m_pWeapon->SetInventoryAmmoCount(ammo, ammoCount);
		}
	}

	OnShoot(m_pWeapon->GetOwnerId(), 0, ammo, pos, dir, vel);

	m_pWeapon->RequireUpdate(eIUS_FireMode);
}
//------------------------------------------------------------------------
void CVehicleDamageBehaviorDetachPart::OnDamageEvent(EVehicleDamageBehaviorEvent event, const SVehicleDamageBehaviorEventParams& behaviorParams)
{
	if (event == eVDBE_Repair)
		return;

	if (!m_detachedEntityId && behaviorParams.componentDamageRatio >= 1.0f)
	{
    CVehiclePartBase* pPart = (CVehiclePartBase*)m_pVehicle->GetPart(m_partName.c_str());
    if (!pPart || !pPart->GetStatObj())
      return;

		if (max(1.f-behaviorParams.randomness, pPart->GetDetachProbability()) < cry_random(0.0f, 1.0f)) 
			return;

		IEntity* pDetachedEntity = SpawnDetachedEntity();
		if (!pDetachedEntity)
			return;

		m_detachedEntityId = pDetachedEntity->GetId();

    const Matrix34& partWorldTM = pPart->GetWorldTM();
    pDetachedEntity->SetWorldTM(partWorldTM);
		
    MovePartToTheNewEntity(pDetachedEntity, pPart);
		
		SEntityPhysicalizeParams physicsParams;
		physicsParams.mass = pPart->GetMass();
		physicsParams.type = PE_RIGID;    		    
		physicsParams.nSlot = 0;
		pDetachedEntity->Physicalize(physicsParams);
  
    IPhysicalEntity* pPhysics = pDetachedEntity->GetPhysics();
    if (pPhysics)
    {
      pe_params_part params;      
      params.flagsOR = geom_collides|geom_floats;
      params.flagsColliderAND = ~geom_colltype3;
      params.flagsColliderOR = geom_colltype0;
      pPhysics->SetParams(&params);

      pe_action_add_constraint ac;
      ac.flags = constraint_inactive|constraint_ignore_buddy;
      ac.pBuddy = m_pVehicle->GetEntity()->GetPhysics();
      ac.pt[0].Set(0,0,0);
      pPhysics->Action(&ac);
			
			// after 1s, remove the constraint again
			m_pVehicle->SetTimer(-1, 1000, this);
    
		  // set the impulse
		  const Vec3& velocity = m_pVehicle->GetStatus().vel;  				  		  
		  Vec3 baseForce = m_pVehicle->GetEntity()->GetWorldTM().TransformVector(pPart->GetDetachBaseForce());
		  baseForce *= cry_random(6.0f, 10.0f);
  		
      pe_action_impulse actionImpulse;
		  actionImpulse.impulse = physicsParams.mass * (velocity + baseForce);
      actionImpulse.angImpulse = physicsParams.mass * Vec3(cry_random(-1.0f,1.0f), cry_random(-1.0f,1.0f), cry_random(-1.0f,1.0f));
      actionImpulse.iApplyTime = 1;
		  
      pPhysics->Action(&actionImpulse);		
    }

		// copy vehicle's material to new entity (fixes detaching parts from vehicles with different paints),
		// or specify the destroyed material if it exists

		IStatObj* pExternalStatObj = pPart->GetExternalGeometry(false);	// Get undamaged external geometry (if any)
		IMaterial *pMaterial = pExternalStatObj ? pExternalStatObj->GetMaterial() : m_pVehicle->GetEntity()->GetMaterial();

		if(event == eVDBE_VehicleDestroyed || event == eVDBE_Hit)
		{
			if (pExternalStatObj)
			{
				if (IStatObj* pStatObj = pPart->GetExternalGeometry(true))     // Try to get the destroyed, external geometry material
					pMaterial = pStatObj->GetMaterial();
			}
			else if (m_pVehicle->GetDestroyedMaterial())  // If there is no external geometry, try the vehicle's destroyed material
			{
				pMaterial = m_pVehicle->GetDestroyedMaterial();
			}
		}

		pDetachedEntity->SetMaterial(pMaterial);
		
		AttachParticleEffect(pDetachedEntity, m_pEffect);

		if (m_notifyMovement)
		{
			SVehicleMovementEventParams params;
			params.iValue = pPart->GetIndex();
			m_pVehicle->GetMovement()->OnEvent(IVehicleMovement::eVME_PartDetached, params);
		}
	}
}
Esempio n. 27
0
void CBoidBug::UpdateFrogsBehavior( float dt,SBoidContext &bc )
{
	if (m_onGround)
	{
		if ((cry_random(0, 99) == 1) ||
			((Vec3(bc.playerPos.x-m_pos.x,bc.playerPos.y-m_pos.y,0).GetLengthSquared()) < BUGS_SCARE_DISTANCE*BUGS_SCARE_DISTANCE))
		{
			// Sacred by player or random jump.
			m_onGround = false;
			m_heading = m_pos - bc.playerPos;
			if (m_heading != Vec3(0,0,0))
				m_heading = m_heading.GetNormalized();
			else
				m_heading = Vec3(Boid::Frand(),Boid::Frand(),Boid::Frand()).GetNormalized();
			m_heading.z = 0.2f + (Boid::Frand()+1.0f)*0.5f;
			m_heading += Vec3(Boid::Frand()*0.3f,Boid::Frand()*0.3f,0 );
			if (m_heading != Vec3(0,0,0))
				m_heading = m_heading.GetNormalized();
			else
				m_heading = Vec3(Boid::Frand(),Boid::Frand(),Boid::Frand()).GetNormalized();
			m_speed = bc.MaxSpeed;
		}
	}

	bc.terrainZ = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y);

	float range = bc.MaxAttractDistance;

	Vec3 origin = bc.flockPos;

	if (bc.followPlayer)
	{
		origin = bc.playerPos;
	}

	// Keep in range.
	if (bc.followPlayer)
	{
		if (m_pos.x < origin.x - range)
			m_pos.x = origin.x + range;
		if (m_pos.y < origin.y - range)
			m_pos.y = origin.y + range;
		if (m_pos.x > origin.x + range)
			m_pos.x = origin.x - range;
		if (m_pos.y > origin.y + range)
			m_pos.y = origin.y - range;
	}
	else
	{
		/*
		if (bc.behavior == EBUGS_BUG || bc.behavior == EBUGS_DRAGONFLY)
		{
			if (m_pos.x < origin.x-range)
				m_accel = (origin - m_pos)*bc.factorAttractToOrigin;
			if (m_pos.y < origin.y-range)
				m_accel = (origin - m_pos)*bc.factorAttractToOrigin;
			if (m_pos.x > origin.x+range)
				m_accel = (origin - m_pos)*bc.factorAttractToOrigin;
			if (m_pos.y > origin.y+range)
				m_accel = (origin - m_pos)*bc.factorAttractToOrigin;
		}
		*/
	}
	m_accel.Set( 0,0,-10 );

	bool bBanking = m_object != 0;
	CalcMovement( dt,bc,bBanking );
	
	UpdateAnimationSpeed(bc);

	if (m_pos.z < bc.terrainZ+0.1f)
	{
		// Land.
		m_pos.z = bc.terrainZ+0.1f;
		m_onGround = true;
		m_speed = 0;
	}
}
Esempio n. 28
0
void CBoidBug::Update( float dt,SBoidContext &bc )
{
	if (bc.behavior == EBUGS_FROG)
	{
		UpdateFrogsBehavior( dt,bc );
		return;
	}

	if (m_onGround)
	{
		if ((Vec3(bc.playerPos.x-m_pos.x,bc.playerPos.y-m_pos.y,0).GetLengthSquared()) < BUGS_SCARE_DISTANCE*BUGS_SCARE_DISTANCE)
		{
			// Sacred by player, fast takeoff.
			m_onGround = false;
			m_heading = (m_pos - bc.playerPos).GetNormalized();
			m_heading.z = 0.3f;
			m_heading = (m_heading).GetNormalized();
			m_speed = 1;
		}
		else if (cry_random(0, 49) == 0)
		{
			// take off.
			m_onGround = false;
			m_heading.z = 0.2f;
			m_heading = (m_heading).GetNormalized();
		}
		return;
	}
	// Keep in range.
	bc.terrainZ = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y);

	float range = bc.MaxAttractDistance;

	Vec3 origin = bc.flockPos;

	if (bc.followPlayer)
	{
		origin = bc.playerPos;
	}
	
	if (bc.followPlayer)
	{
		if (m_pos.x < origin.x - range)
			m_pos.x = origin.x + range;
		if (m_pos.y < origin.y - range)
			m_pos.y = origin.y + range;
		if (m_pos.x > origin.x + range)
			m_pos.x = origin.x - range;
		if (m_pos.y > origin.y + range)
			m_pos.y = origin.y - range;
	}
	else
	{
		if (bc.behavior == EBUGS_BUG || bc.behavior == EBUGS_DRAGONFLY)
		{
			if (m_pos.x < origin.x-range)
				m_accel = (origin - m_pos)*bc.factorAttractToOrigin;
			if (m_pos.y < origin.y-range)
				m_accel = (origin - m_pos)*bc.factorAttractToOrigin;
			if (m_pos.x > origin.x+range)
				m_accel = (origin - m_pos)*bc.factorAttractToOrigin;
			if (m_pos.y > origin.y+range)
				m_accel = (origin - m_pos)*bc.factorAttractToOrigin;
		}
	}

	if (bc.behavior == EBUGS_BUG)
	{
		UpdateBugsBehavior( dt,bc );
	}
	else 	if (bc.behavior == EBUGS_DRAGONFLY)
	{
		UpdateDragonflyBehavior( dt,bc );
	}
	else 	if (bc.behavior == EBUGS_FROG)
	{
		UpdateFrogsBehavior( dt,bc );
	}
	else
	{
		UpdateBugsBehavior( dt,bc );
	}

	bool bBanking = m_object != 0;
	CalcMovement( dt,bc,bBanking );
	
	UpdateAnimationSpeed(bc);

	if (m_pos.z < bc.terrainZ+0.1f)
	{
		// Land.
		m_pos.z = bc.terrainZ+0.1f;
		if (!bc.noLanding && cry_random(0, 9) == 0)
		{
			m_onGround = true;
			m_speed = 0;
			m_accel.Set(0,0,0);
		}
	}

	if (m_pos.z < bc.waterLevel)
		m_pos.z = bc.waterLevel;
}
//------------------------------------------------------------------------
void CVehicleDamageBehaviorBlowTire::Activate(bool activate)
{
  if (activate == m_isActive)
    return;

  if (activate && m_pVehicle->IsDestroyed())
    return;

  IVehicleComponent* pComponent = m_pVehicle->GetComponent(m_component.c_str());
  if (!pComponent)
    return;

  IVehiclePart* pPart = pComponent->GetPart(0);
  if (!pPart)
    return;

  // if IVehicleWheel available, execute full damage behavior. if null, only apply effects
  IVehicleWheel* pWheel = pPart->GetIWheel();
  
  if (activate)
  {
    IEntity* pEntity = m_pVehicle->GetEntity();
    IPhysicalEntity* pPhysics = pEntity->GetPhysics();
    const Matrix34& wheelTM = pPart->GetLocalTM(false);
    const SVehicleStatus& status = m_pVehicle->GetStatus();

    if (pWheel)
    { 
      const pe_cargeomparams* pParams = pWheel->GetCarGeomParams();  
            
      // handle destroyed wheel
      pe_params_wheel wheelParams;
      wheelParams.iWheel = pWheel->GetWheelIndex();            
      wheelParams.minFriction = wheelParams.maxFriction = 0.5f * pParams->maxFriction;      
      pPhysics->SetParams(&wheelParams); 
      
      if (IVehicleMovement* pMovement = m_pVehicle->GetMovement())
      { 
        SVehicleMovementEventParams params;
        params.pComponent = pComponent;
        params.iValue = pWheel->GetWheelIndex();
        pMovement->OnEvent(IVehicleMovement::eVME_TireBlown, params);
      }

      if (status.speed > 0.1f)
      {
        // add angular impulse
        pe_action_impulse angImp;
        float amount = m_pVehicle->GetMass() * status.speed * cry_random(0.25f, 0.45f) * -sgn(wheelTM.GetTranslation().x);
        angImp.angImpulse = pEntity->GetWorldTM().TransformVector(Vec3(0,0,amount));    
        pPhysics->Action(&angImp);
      }
 
			m_pVehicle->SetTimer(-1, AI_IMMOBILIZED_TIME*1000, this);  
    }

    if (!gEnv->pSystem->IsSerializingFile())
    {
      // add linear impulse       
      pe_action_impulse imp;
      imp.point = pPart->GetWorldTM().GetTranslation();

      float amount = m_pVehicle->GetMass() * cry_random(0.1f, 0.15f);

      if (pWheel)
      {
        amount *= max(0.5f, min(10.f, status.speed));

        if (status.speed < 0.1f)
          amount = -0.5f*amount;
      }
      else    
        amount *= 0.5f;

      imp.impulse = pEntity->GetWorldTM().TransformVector(Vec3(0,0,amount));
      pPhysics->Action(&imp);     

			// remove affected decals
			{
				Vec3 pos = pPart->GetWorldTM().GetTranslation();
				AABB aabb = pPart->GetLocalBounds();
				float radius = aabb.GetRadius();
				Vec3 vRadius(radius,radius,radius);
        AABB areaBox(pos-vRadius, pos+vRadius);
        
        IRenderNode * pRenderNode = NULL;				
        if (IComponentRender *pRenderProxy = (IComponentRender*)pEntity->GetComponent<IComponentRender>().get())
					pRenderNode = pRenderProxy->GetRenderNode();

        gEnv->p3DEngine->DeleteDecalsInRange(&areaBox, pRenderNode);
			}
    }    
  }
  else
  { 
    if (pWheel)
    {
      // restore wheel properties        
      IPhysicalEntity* pPhysics = m_pVehicle->GetEntity()->GetPhysics();    
      pe_params_wheel wheelParams;

      for (int i=0; i<m_pVehicle->GetWheelCount(); ++i)
      { 
        const pe_cargeomparams* pParams = m_pVehicle->GetWheelPart(i)->GetIWheel()->GetCarGeomParams();

        wheelParams.iWheel = i;
        wheelParams.bBlocked = 0;
        wheelParams.suspLenMax = pParams->lenMax;
        wheelParams.bDriving = pParams->bDriving;      
        wheelParams.minFriction = pParams->minFriction;
        wheelParams.maxFriction = pParams->maxFriction;
        pPhysics->SetParams(&wheelParams);
      }

			if (IVehicleMovement* pMovement = m_pVehicle->GetMovement())
			{ 
				SVehicleMovementEventParams params;
				params.pComponent = pComponent;
				params.iValue = pWheel->GetWheelIndex();
				// reset the particle status
				pMovement->OnEvent(IVehicleMovement::eVME_TireRestored, params);
			}
    }  
  }

  m_isActive = activate;      
}
//------------------------------------------------------------------------
void CVehicleMovementStdBoat::UpdateSurfaceEffects(const float deltaTime)
{
  FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

  if (0 == g_pGameCVars->v_pa_surface)
  {
    ResetParticles();
    return;
  }
  
  IEntity* pEntity = m_pVehicle->GetEntity();
  const Matrix34& worldTM = pEntity->GetWorldTM();
  
  float distSq = worldTM.GetTranslation().GetSquaredDistance(gEnv->pRenderer->GetCamera().GetPosition());
  if (distSq > sqr(300.f) || (distSq > sqr(50.f) && !m_pVehicle->GetGameObject()->IsProbablyVisible()))
    return;

  Matrix34 worldTMInv = worldTM.GetInverted();
  const SVehicleStatus& status = m_pVehicle->GetStatus();    
  float velDot = status.vel * worldTM.GetColumn1();  
  float powerNorm = min(abs(m_movementAction.power), 1.f);

  SEnvironmentParticles* envParams = m_pPaParams->GetEnvironmentParticles();

  SEnvParticleStatus::TEnvEmitters::iterator end = m_paStats.envStats.emitters.end();
  for (SEnvParticleStatus::TEnvEmitters::iterator emitterIt = m_paStats.envStats.emitters.begin(); emitterIt!=end; ++emitterIt)  
  { 
    if (emitterIt->layer < 0)
    {
      assert(0);
      continue;
    }

    const SEnvironmentLayer& layer = envParams->GetLayer(emitterIt->layer);
    
    SEntitySlotInfo info;        
    info.pParticleEmitter = 0;
    pEntity->GetSlotInfo(emitterIt->slot, info);        

    float countScale = 1.f;
    float sizeScale = 1.f;
		float speedScale = 1.f;
    float speed = 0.f;

    // check if helper position is beneath water level      
                
    Vec3 emitterWorldPos = worldTM * emitterIt->quatT.t;
    float waterLevel = gEnv->p3DEngine->GetWaterLevel(&emitterWorldPos);
    int matId = 0;
    
    if (emitterWorldPos.z <= waterLevel+0.1f && m_physStatus[k_mainThread].submergedFraction<0.999f)
    {
      matId = gEnv->pPhysicalWorld->GetWaterMat();
      speed = status.speed;

      bool spray = !strcmp(layer.GetName(), "spray");        
      
      if (spray)
      {
        // slip based          
        speed -= abs(velDot);
      }

      GetParticleScale(layer, speed, powerNorm, countScale, sizeScale, speedScale);
    }
    else
    {
      countScale = 0.f;
    }
    
    if (matId && matId != emitterIt->matId)
    {
      // change effect       
      IParticleEffect* pEff = 0;                
      const char* effect = GetEffectByIndex( matId, layer.GetName() );

      if (effect && (pEff = gEnv->pParticleManager->FindEffect(effect)))
      {  
#if ENABLE_VEHICLE_DEBUG
        if (DebugParticles())              
					CryLog("%s changes water sfx to %s (slot %i)", pEntity->GetName(), effect, emitterIt->slot);
#endif

        if (info.pParticleEmitter)
        {
          info.pParticleEmitter->Activate(false);
          pEntity->FreeSlot(emitterIt->slot);                  
        }

        emitterIt->slot = pEntity->LoadParticleEmitter(emitterIt->slot, pEff);

        if (emitterIt->slot != -1)
          pEntity->SetSlotLocalTM(emitterIt->slot, Matrix34(emitterIt->quatT));

        info.pParticleEmitter = 0;
        pEntity->GetSlotInfo(emitterIt->slot, info);
      }
      else
        countScale = 0.f;
    }

    if (matId)
      emitterIt->matId = matId;

    if (info.pParticleEmitter)
    {
      SpawnParams sp;
      sp.fSizeScale = sizeScale;
      sp.fCountScale = countScale;    
			sp.fSpeedScale = speedScale;
      info.pParticleEmitter->SetSpawnParams(sp);

      if (layer.alignToWater && countScale > 0.f)
      {          
        Vec3 worldPos(emitterWorldPos.x, emitterWorldPos.y, waterLevel+0.05f);

        Matrix34 localTM(emitterIt->quatT);
        localTM.SetTranslation(worldTMInv * worldPos);
        pEntity->SetSlotLocalTM(emitterIt->slot, localTM);           
      }
    }

#if ENABLE_VEHICLE_DEBUG
    if (DebugParticles() && m_pVehicle->IsPlayerDriving())
    {          
      float color[] = {1,1,1,1};
      ColorB red(255,0,0,255);
      IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom();
      
      const char* effect = info.pParticleEmitter ? info.pParticleEmitter->GetName() : "";
      const Matrix34& slotTM = m_pEntity->GetSlotWorldTM(emitterIt->slot);
      Vec3 ppos = slotTM.GetTranslation();
      
      pAuxGeom->DrawSphere(ppos, 0.2f, red);
      pAuxGeom->DrawCone(ppos, slotTM.GetColumn1(), 0.1f, 0.5f, red);
      gEnv->pRenderer->Draw2dLabel(50.f, (float)(400+10*emitterIt->slot), 1.2f, color, false, "<%s> water fx: slot %i [%s], speed %.1f, sizeScale %.2f, countScale %.2f (pos %.0f,%0.f,%0.f)", pEntity->GetName(), emitterIt->slot, effect, speed, sizeScale, countScale, ppos.x, ppos.y, ppos.z);        
    }  
#endif
  }

  // generate water splashes
	Vec3 wakePos;
	if(m_pSplashPos)
	{
		wakePos = m_pSplashPos->GetWorldSpaceTranslation();
	}
	else
	{
		wakePos = worldTM.GetTranslation();
	}
  float wakeWaterLevel = gEnv->p3DEngine->GetWaterLevel(&wakePos);

  const Vec3& localW = m_localSpeed;
  if (localW.x >= 0.f)
    m_diving = false;
      
  if (!m_diving && localW.x < -0.03f && status.speed > 10.f && wakePos.z < m_lastWakePos.z && wakeWaterLevel+0.1f >= wakePos.z)
  {
    float speedRatio = min(1.f, status.speed/(m_maxSpeed*m_factorMaxSpeed)); 
    m_diving = true;              
    
    if (m_pWaveEffect)
    {
      if (IParticleEmitter* pEmitter = pEntity->GetParticleEmitter(m_wakeSlot))
      {
        pEmitter->Activate(false);
        pEntity->FreeSlot(m_wakeSlot);
        m_wakeSlot = -1;
      }

      SpawnParams spawnParams;
      spawnParams.fSizeScale = spawnParams.fCountScale = 0.5f + 0.25f*speedRatio;
      spawnParams.fSizeScale  += 0.4f*m_waveRandomMult;
      spawnParams.fCountScale += cry_random(0.0f, 0.4f);

      m_wakeSlot = pEntity->LoadParticleEmitter(m_wakeSlot, m_pWaveEffect, &spawnParams);        
    }

    // handle splash sound  
    ExecuteTrigger(eSID_Splash);
    SetSoundParam(eSID_Splash, "intensity", 0.2f*speedRatio + 0.5f*m_waveRandomMult);     

    if (m_rpmPitchDir == 0)
    {
      m_rpmPitchDir = -1;
      m_waveSoundPitch = 0.f;
      m_waveSoundAmount = 0.02f + m_waveRandomMult*0.08f;
    }      
  }  

  if (m_wakeSlot != -1)
  { 
    // update emitter local pos to short above waterlevel
    Matrix34 tm;
		if(m_pSplashPos)
			m_pSplashPos->GetVehicleTM(tm);
		else
			tm.SetIdentity();

    Vec3 pos = tm.GetTranslation();
    pos.z = worldTMInv.TransformPoint(Vec3(wakePos.x,wakePos.y,wakeWaterLevel)).z + 0.2f;
    tm.SetTranslation(pos);
    pEntity->SetSlotLocalTM(m_wakeSlot, tm);

#if ENABLE_VEHICLE_DEBUG
    if (IsProfilingMovement())
    {
      Vec3 wPos = worldTM * tm.GetTranslation();
      ColorB col(128, 128, 0, 200);
      gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(wPos, 0.4f, col);
      gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(wPos, col, wPos+Vec3(0,0,1.5f), col);
    }          
#endif
  } 

  m_lastWakePos = wakePos;
}