/***********************************************************************/
/** 	© 2015 CD PROJEKT S.A. All rights reserved.
/** 	THE WITCHER® is a trademark of CD PROJEKT S. A.
/** 	The Witcher game is based on the prose of Andrzej Sapkowski.
/***********************************************************************/




state Sailing in CR4Player extends UseGenericVehicle
{
	private var boatLogic : CBoatComponent;
	private var remainingSlideDuration : float;
	private var vehicleCombatMgr : W3VehicleCombatManager;
	private var dismountRequest : bool;
	
	private const var angleToSeatFromBack : float;
	private const var angleToSeatFromForward : float;	
	
	default remainingSlideDuration = 0.f;
	default angleToSeatFromBack	= 150.0f;
	default angleToSeatFromForward = 30.0f;
	
	
	
	
	
	protected function Init()
	{
		super.Init();

		if( !vehicleCombatMgr )
		{
			vehicleCombatMgr = new W3VehicleCombatManager in this;
		}
		
		parent.UnblockAction( EIAB_Crossbow, 'DismountVehicle2' );	
		dismountRequest = false;
		
		vehicleCombatMgr.Setup( parent, vehicle );
		vehicleCombatMgr.GotoStateAuto();
		vehicle.SetCombatManager( vehicleCombatMgr );
		
		parent.SetOrientationTarget( OT_Camera );
		
		boatLogic = (CBoatComponent)vehicle; 
		ProcessBoatSailing();
	}
	
	event OnEnterState( prevStateName : name )
	{
		var commonMapManager : CCommonMapManager = theGame.GetCommonMapManager();
		
		super.OnEnterState( prevStateName );
		
		theTelemetry.LogWithName( TE_STATE_SAILING );
		
		parent.SetBehaviorVariable( 'keepSpineUpright', 0.f );	
		commonMapManager.NotifyPlayerMountedBoat();
		
		InitCamera();
	}
	
	event OnLeaveState( nextStateName : name )
	{ 
		var commonMapManager : CCommonMapManager = theGame.GetCommonMapManager();
		
		theInput.SetContext( parent.GetExplorationInputContext() );	
		
		parent.SetBehaviorVariable( 'keepSpineUpright', 1.f );
		commonMapManager.NotifyPlayerDismountedBoat();		
		
		super.OnLeaveState( nextStateName );
		
		theInput.GetContext();
	}
	
	
	
	
	
	entry function ProcessBoatSailing()
	{
		var axis : float;
		
		parent.SetCleanupFunction( 'SailingCleanup' );
		
		LogAssert( vehicle, "Sailing::ProcessBoatSailing - vehicle is null" );
				
		while( !dismountRequest )
		{
			FindTarget();
			
			Sleep( 0.2f );
			
			
			
			
			
		}
		
		parent.ClearCleanupFunction();
		
		((CPlayerStateDismountBoat)parent.GetState('DismountBoat')).SetupState( boatLogic, DT_normal );
		((CPlayerStateDismountBoat)parent.GetState('DismountBoat')).DismountFromPassenger( false );
		parent.GotoState( 'DismountBoat', true );
	}
	
	cleanup function SailingCleanup()
	{
		vehicle.ToggleVehicleCamera( false );
		
		vehicle.OnDismountStarted( parent );
		vehicle.OnDismountFinished( parent, thePlayer.GetRiderData().sharedParams.vehicleSlot );	
		
		parent.EnableCollisions( true );		
		parent.RegisterCollisionEventsListener();
	}
	
	function DismountVehicle()
	{
		dismountRequest = true;
	}
	
	event OnReactToBeingHit( damageAction : W3DamageAction )
	{
		var boatHitDirection : int;
		var angleDistance : float;
		var target : CNode;
		
		target = damageAction.attacker;
		
		if ( target )
		{
			angleDistance = NodeToNodeAngleDistance(target,parent);
			if ( AbsF(angleDistance) < 45 )
				boatHitDirection = 0; 
			else if ( AbsF(angleDistance) > 135 )
				boatHitDirection = 1; 
			else if ( angleDistance > 45 )
				boatHitDirection = 3; 
			else if ( angleDistance < -45 )
				boatHitDirection = 2; 
			else
				boatHitDirection = 0; 
			
		}
		else
		{
			boatHitDirection = 0;
		}
		
		parent.SetBehaviorVariable( 'boatHitDirection', boatHitDirection);
		
		virtual_parent.OnReactToBeingHit( damageAction );
	}
	
	
	
	
	
	
	
	
	private var angleDamper	: float;
	private var offsetDamper : float;
	private var rudderDamper : float;
	private var cameraSide : float;
	
	default rudderDamper = 0.f;
	default cameraSide = 1.f;
	
	private function InitCamera()
	{
		
		camera.ChangePivotRotationController( 'Boat_RC' );
		camera.ChangePivotDistanceController( 'Boat_DC' );
	}
	
	
	private final function GetGearRatio( gear : int ) : float
	{
		if( ( gear == 1 ) || ( gear == -1 ) )
		{
			return 1.0f;
		}
		
		if( gear == 2 )
		{
			return 1.5f;
		}
		
		if( gear == 3 )
		{
			return 2.2f;
		}
		
		return 0.0f;
	}
	
	private var m_shouldEnableAutoRotation : bool;
	
	event OnGameCameraTick( out moveData : SCameraMovementData, dt : float )
	{
		var turnFactor  : float;
		var velocityRatio : float;		
		var sailCameraOffset : float;
		
		var fovDistPitch : Vector;
		var offsetZ : float;
		var offsetUp : Vector;
		var sailOffset : float;
		var boatComponent: CBoatComponent;
		
		var boatPPC : CCustomCameraBoatPPC;
		var cameraToBoatDot : float;
		var turnFactorSum : float;
		
		var camera : CCustomCamera;
		var angleDist : float;
		
		parent.UpdateLookAtTarget();
		
		
		camera = (CCustomCamera)theCamera.GetTopmostCameraObject();
		
		if( theInput.LastUsedGamepad() )
		{
			angleDist = AngleDistance( parent.GetHeading(), camera.GetHeading() );
			
			if( thePlayer.GetAutoCameraCenter() || ( !m_shouldEnableAutoRotation && AbsF(angleDist) <= 30.0f ) )
			{
				m_shouldEnableAutoRotation = true;
			}
			else if( m_shouldEnableAutoRotation && !thePlayer.GetAutoCameraCenter() && camera.IsManualControledHor() )
			{
				m_shouldEnableAutoRotation = false;
			}
		}
		else
		{
			m_shouldEnableAutoRotation = thePlayer.GetAutoCameraCenter();
		}
		
		camera.SetAllowAutoRotation( m_shouldEnableAutoRotation );
		
		
		
		boatComponent = (CBoatComponent)vehicle;
		if( boatComponent )
		{
			boatComponent.localSpaceCameraTurnPercent = VecDot2D( camera.GetHeadingVector(), VecCross( boatComponent.GetHeadingVector(), Vector( 0.0f, 0.0f, 1.0f ) ) );
			
			
			if( AbsF( boatComponent.localSpaceCameraTurnPercent ) < 0.1f )
			{
				boatComponent.localSpaceCameraTurnPercent = 0.0f;
			}
			
			
			if( VecDot2D( camera.GetHeadingVector(), boatComponent.GetHeadingVector() ) < 0.0f )
			{
				boatComponent.localSpaceCameraTurnPercent = SgnF( boatComponent.localSpaceCameraTurnPercent );
			}
		}
		
		ShouldEnableBoatMusic();

		turnFactor	= theInput.GetActionValue( 'GI_AxisLeftX' );		
		
		turnFactorSum = AbsF( turnFactor + boatComponent.localSpaceCameraTurnPercent );		
		if( turnFactorSum > 1.0f )
		{
			turnFactorSum = AbsF( turnFactor * 2.0f + boatComponent.localSpaceCameraTurnPercent );
			turnFactor = ( turnFactor * 2.0f ) / turnFactorSum + boatComponent.localSpaceCameraTurnPercent / turnFactorSum;
		}
		else
		{
			turnFactor = turnFactor + boatComponent.localSpaceCameraTurnPercent;
		}	
		
		//LogChannel('Boat', "Rudder turn factor: " + turnFactor ); // modFasterBoat
		
		
		rudderDamper = rudderDamper + dt * 6.f * ( turnFactor - rudderDamper );	
		//LogChannel('Boat', "Rudder damper: " + rudderDamper ); // modFasterBoat
		
		boatLogic.SetRudderDir( virtual_parent, rudderDamper );
		
		if( this.vehicleCombatMgr.IsInCombatAction() )
		{
			moveData.pivotRotationController.SetDesiredHeading( moveData.pivotRotationValue.Yaw );	
		}
		else
		{
			moveData.pivotRotationController.SetDesiredHeading( parent.GetHeading() - rudderDamper * 20.f );		
		}

		if( vehicleCombatMgr.OnGameCameraTick( moveData, dt ) )
		{
			return true;
		}
		
		theGame.GetGameCamera().ChangePivotDistanceController( 'Boat_DC' );
		theGame.GetGameCamera().ChangePivotRotationController( 'Boat_RC' );
		
		
		
		moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController();
		moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController();
		moveData.pivotPositionController = theGame.GetGameCamera().GetActivePivotPositionController();
		
		
		if( boatLogic.GameCameraTick( fovDistPitch, offsetZ, sailOffset, dt, false ) )
		{
			boatPPC = ( CCustomCameraBoatPPC )moveData.pivotPositionController;
			if( boatPPC )
			{
				offsetUp = Vector( 0.0f, 0.0f, offsetZ );
				boatPPC.SetPivotOffset( offsetUp );
			}

			moveData.pivotRotationController.SetDesiredPitch( fovDistPitch.Z );
			moveData.pivotDistanceController.SetDesiredDistance( fovDistPitch.Y );
			
			sailCameraOffset = boatLogic.GetSailTilt() * sailOffset;
			DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( sailCameraOffset, 0.f, 0.f ), 0.5f, dt );
		}
		
		return true;
	}
	
	event OnGameCameraPostTick( out moveData : SCameraMovementData, dt : float )
	{
		if ( super.OnGameCameraPostTick( moveData, dt ) )
			return true;
	}
	
	
	
	
	
	function CanAccesFastTravel( target : W3FastTravelEntity ) : bool 
	{
		return target.canBeReachedByBoat;
	}
	
	public function TriggerDrowning()
	{
		if( vehicleCombatMgr )
		{
			vehicleCombatMgr.OnForceItemActionAbort();
		}
	}
}





state SailingPassive in CR4Player extends UseGenericVehicle
{
	private var boatLogic : CBoatComponent;
	private var dismountRequest : bool;
	private var vehicleCombatMgr : W3VehicleCombatManager;
	private var rudderDamper : float;
	
	default rudderDamper = 0.f;
	default dismountRequest = false;
	
	protected function Init()
	{
		super.Init();
		boatLogic = (CBoatComponent)vehicle;
	}
	
	event OnEnterState( prevStateName : name )
	{
		var commonMapManager : CCommonMapManager = theGame.GetCommonMapManager();
		
		super.OnEnterState(prevStateName);
		
		if( !vehicleCombatMgr )
		{
			vehicleCombatMgr = new W3VehicleCombatManager in this;
		}
	
		dismountRequest = false;
		
		vehicleCombatMgr.Setup( parent, vehicle );
		vehicleCombatMgr.GotoStateAuto();
		vehicle.SetCombatManager( vehicleCombatMgr );		
		
		ProcessBoatSailingPassive();
				
		theGame.GetGameCamera().SetAllowAutoRotation( false );
		commonMapManager.NotifyPlayerMountedBoat();
	}
	
	event OnLeaveState( nextStateName : name )
	{
		var commonMapManager : CCommonMapManager = theGame.GetCommonMapManager();
		
		super.OnLeaveState( nextStateName );
		theGame.GetGameCamera().SetAllowAutoRotation( true );
		commonMapManager.NotifyPlayerDismountedBoat();
	}	
	
	entry function ProcessBoatSailingPassive()
	{
		var axis : float;
		
		parent.EnableCollisions( false );
		
		
		theSound.SoundEvent( "boat_sail_temp_loop" );
		theSound.EnterGameState(ESGS_Boat);	
		parent.CreateAttachment( boatLogic.GetEntity(), 'seat_passenger' );	

		
		while( !dismountRequest )
		{
			FindTarget();
			Sleep( 0.2f );
		}
				
		parent.ClearCleanupFunction();
		
		((CPlayerStateDismountBoat)parent.GetState('DismountBoat')).SetupState( boatLogic, DT_normal );
		((CPlayerStateDismountBoat)parent.GetState('DismountBoat')).DismountFromPassenger( true );
		parent.GotoState( 'DismountBoat', true );
	}
	function DismountVehicle()
	{
		dismountRequest = true;
	}
	
	event OnGameCameraTick( out moveData : SCameraMovementData, dt : float )
	{
		var turnFactor  : float;
		var velocityRatio : float;		
		var sailCameraOffset : float;
		
		var fovDistPitch : Vector;
		var offsetZ : float;
		var offsetUp : Vector;
		var sailOffset : float;
		
		var boatPPC : CCustomCameraBoatPPC;
		
		parent.UpdateLookAtTarget();
		
		ShouldEnableBoatMusic();
		
		
		rudderDamper = rudderDamper + dt * 6.f * ( turnFactor - rudderDamper );	
		boatLogic.SetRudderDir( virtual_parent, rudderDamper );
		
		if ( this.vehicleCombatMgr.IsInCombatAction() )
		{
			moveData.pivotRotationController.minPitch = -55.f;
			moveData.pivotRotationController.maxPitch = theGame.GetGameplayConfigFloatValue( 'debugA' );
			moveData.pivotRotationController.SetDesiredHeading( moveData.pivotRotationValue.Yaw );
		}
		else
		{
			moveData.pivotRotationController.minPitch = -55.f;
			moveData.pivotRotationController.maxPitch = -3;
			moveData.pivotRotationController.SetDesiredHeading( parent.GetHeading() - rudderDamper * 20.f );
		}
		
		if( vehicleCombatMgr.OnGameCameraTick( moveData, dt ) )
		{
			return true;
		}
		
		theGame.GetGameCamera().ChangePivotDistanceController( 'Boat_DC' );
		theGame.GetGameCamera().ChangePivotRotationController( 'Boat_RC' );
		
		
		
		moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController();
		moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController();
		moveData.pivotPositionController = theGame.GetGameCamera().GetActivePivotPositionController();
		
		
		if( boatLogic.GameCameraTick( fovDistPitch, offsetZ, sailOffset, dt, true ) )
		{
			camera.fov = fovDistPitch.X;
			
			boatPPC = ( CCustomCameraBoatPPC )moveData.pivotPositionController;
			if( boatPPC )
			{
				offsetUp = Vector( 0.0f, 0.0f, offsetZ );
				boatPPC.SetPivotOffset( offsetUp );
			}

			moveData.pivotRotationController.SetDesiredPitch( fovDistPitch.Z );
			moveData.pivotDistanceController.SetDesiredDistance( fovDistPitch.Y );
			
			sailCameraOffset = boatLogic.GetSailTilt() * sailOffset;
			DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( sailCameraOffset, 0.f, 0.f ), 0.5f, dt );
		}
		
		return true;
	}
	
	event OnGameCameraPostTick( out moveData : SCameraMovementData, dt : float )
	{
		if ( super.OnGameCameraPostTick( moveData, dt ) )
			return true;
	}
	
	
	
}
