class sampleBullet extends BaseProjectile
{
	private var m_meshComponent : IComponent;
	private var m_countTime : Float;
	private editable var m_startVelocity : Float;
	private editable var m_lifetime : Float;
	private var m_BulletCollisionEvaluator : BulletCollisionEvaluator;
	private var m_alive : Bool;
	default m_alive = true;

	protected event OnRequestComponents( ri : EntityRequestComponentsInterface )
	{
		super.OnRequestComponents( ri );
		EntityRequestComponentsInterface.RequestComponent( ri, 'MeshComponent', 'IComponent', true );
	}

	protected event OnTakeControl( ri : EntityResolveComponentsInterface )
	{
		super.OnTakeControl( ri );
		m_meshComponent = EntityResolveComponentsInterface.GetComponent( ri, 'MeshComponent' );
	}

	private function Reset()
	{
		m_countTime = 0.0;
		m_alive = true;
		m_meshComponent.Toggle( true );
	}

	protected event OnProjectileInitialize( eventData : gameprojectileSetUpEvent )
	{
		var linearParams : LinearTrajectoryParams;
		linearParams = new LinearTrajectoryParams;
		super.OnProjectileInitialize( eventData );
		linearParams.startVel = m_startVelocity;
		m_projectileComponent.AddLinear( linearParams );
		m_BulletCollisionEvaluator = new BulletCollisionEvaluator;
		m_projectileComponent.SetCollisionEvaluator( m_BulletCollisionEvaluator );
		m_BulletCollisionEvaluator.SetUser( m_user );
	}

	private function StartTrailEffect()
	{
		m_projectileComponent.SpawnTrailVFX();
		GameObject.PlaySoundEvent( this, 'Time_Dilation_Bullet_Trails_bullets_normal' );
	}

	protected event OnShoot( eventData : gameprojectileShootEvent )
	{
		m_BulletCollisionEvaluator.SetWeaponParams( eventData.params );
		Reset();
		StartTrailEffect();
	}

	protected event OnShootTarget( eventData : gameprojectileShootTargetEvent )
	{
		m_BulletCollisionEvaluator.SetWeaponParams( eventData.params );
		Reset();
		StartTrailEffect();
	}

	protected event OnTick( eventData : gameprojectileTickEvent )
	{
		m_countTime += eventData.deltaTime;
		if( ( m_countTime > m_lifetime ) || !( m_alive ) )
		{
			Release();
		}
		m_projectileComponent.LogDebugVariable( 'Lifetime', FloatToString( m_countTime ) );
	}

	protected event OnCollision( projectileHitEvent : gameprojectileHitEvent )
	{
		var object : GameObject;
		var isUserPlayer : Bool;
		var damageHitEvent : gameprojectileHitEvent;
		var hitInstance : gameprojectileHitInstance;
		var i : Int32;
		damageHitEvent = new gameprojectileHitEvent;
		isUserPlayer = m_user == GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject();
		for( i = 0; i < projectileHitEvent.hitInstances.Size(); i += 1 )
		{
			hitInstance = projectileHitEvent.hitInstances[ i ];
			object = ( ( GameObject )( hitInstance.hitObject ) );
			if( m_alive && !( ( isUserPlayer && object.HasTag( 'ignore_player_bullets' ) ) ) )
			{
				damageHitEvent.hitInstances.PushBack( hitInstance );
				if( ( !( object.HasTag( 'bullet_no_destroy' ) ) && m_BulletCollisionEvaluator.HasReportedStopped() ) && hitInstance.position == m_BulletCollisionEvaluator.GetStoppedPosition() )
				{
					m_countTime = 0.0;
					m_alive = false;
					m_meshComponent.Toggle( false );
					m_projectileComponent.ClearTrajectories();
					break;
				}
			}
		}
		if( damageHitEvent.hitInstances.Size() > 0 )
		{
			DealDamage( damageHitEvent );
		}
	}

	private function DealDamage( eventData : gameprojectileHitEvent )
	{
		var damageEffect : EffectInstance;
		damageEffect = m_projectileComponent.GetGameEffectInstance();
		EffectData.SetVariant( damageEffect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.projectileHitEvent, eventData );
		damageEffect.Run();
	}

}

class BulletCollisionEvaluator extends gameprojectileScriptCollisionEvaluator
{
	protected var m_user : weak< GameObject >;
	private var m_hasStopped : Bool;
	default m_hasStopped = false;
	private var m_stoppedPosition : Vector4;
	private var m_weaponParams : gameprojectileWeaponParams;
	private var m_isExplodingBullet : Bool;
	default m_isExplodingBullet = false;
	private var m_isSmartBullet : Bool;
	default m_isSmartBullet = false;

	public function SetIsExplodingBullet( isExplodingBullet : Bool )
	{
		m_isExplodingBullet = isExplodingBullet;
	}

	public function SetIsSmartBullet( isSmartBullet : Bool )
	{
		m_isSmartBullet = isSmartBullet;
	}

	public function SetWeaponParams( const params : ref< gameprojectileWeaponParams > )
	{
		m_weaponParams = params;
	}

	public function SetUser( user : weak< GameObject > )
	{
		m_user = user;
	}

	public function HasReportedStopped() : Bool
	{
		return m_hasStopped;
	}

	public function GetStoppedPosition() : Vector4
	{
		return m_stoppedPosition;
	}

	protected export override function EvaluateCollision( defaultOnCollisionAction : gameprojectileOnCollisionAction, params : CollisionEvaluatorParams ) : gameprojectileOnCollisionAction
	{
		var validAngle : Bool;
		var validBounces : Bool;
		var validRand : Bool;
		validAngle = false;
		validBounces = false;
		validRand = false;
		if( !( m_isExplodingBullet ) && params.isPiercableSurface )
		{
			return gameprojectileOnCollisionAction.Pierce;
		}
		if( m_isExplodingBullet && ( params.projectilePenetration == 'Any' || ( params.isTechPiercing && params.isPiercableSurface ) ) )
		{
			return gameprojectileOnCollisionAction.Pierce;
		}
		if( params.target.IsVehicle() && ( VehicleComponent.GetDriverMounted( m_user.GetGame(), params.target.GetEntityID() ) == m_user ) )
		{
			return gameprojectileOnCollisionAction.Pierce;
		}
		if( ( ( !( m_isExplodingBullet ) && !( m_isSmartBullet ) ) && params.isAutoBounceSurface ) && ( params.numBounces < 5 ) )
		{
			return gameprojectileOnCollisionAction.Bounce;
		}
		if( ( ( ScriptedPuppet )( params.target ) ) || ( ( Device )( params.target ) ) )
		{
			m_hasStopped = true;
			m_stoppedPosition = params.position;
			return gameprojectileOnCollisionAction.Stop;
		}
		validAngle = ( m_weaponParams.ricochetData.minAngle < params.angle ) && ( m_weaponParams.ricochetData.maxAngle > params.angle );
		validBounces = params.numBounces < ( ( Uint32 )( m_weaponParams.ricochetData.count ) );
		validRand = RandRangeF( 0.0, 1.0 ) < m_weaponParams.ricochetData.chance;
		if( ( !( validAngle ) || !( validBounces ) ) || !( validRand ) )
		{
			m_hasStopped = true;
			m_stoppedPosition = params.position;
			return gameprojectileOnCollisionAction.Stop;
		}
		return gameprojectileOnCollisionAction.Bounce;
	}

}

