//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pPlayer - 
//			*pObject - 
//-----------------------------------------------------------------------------
void CPlayerPickupController::Init( CBasePlayer *pPlayer, CBaseEntity *pObject )
{
	// Holster player's weapon
	if ( pPlayer->GetActiveWeapon() )
	{
		if ( !pPlayer->GetActiveWeapon()->CanHolster() || !pPlayer->GetActiveWeapon()->Holster() )
		{
			Shutdown();
			return;
		}
	}

	// If the target is debris, convert it to non-debris
	if ( pObject->GetCollisionGroup() == COLLISION_GROUP_DEBRIS )
	{
		// Interactive debris converts back to debris when it comes to rest
		pObject->SetCollisionGroup( COLLISION_GROUP_INTERACTIVE_DEBRIS );
	}

	// done so I'll go across level transitions with the player
	SetParent( pPlayer );
	m_grabController.SetIgnorePitch( true );
	m_grabController.SetAngleAlignment( DOT_30DEGREE );
	m_pPlayer = pPlayer;
	IPhysicsObject *pPhysics = pObject->VPhysicsGetObject();
	
	Pickup_OnPhysGunPickup( pObject, m_pPlayer, PICKED_UP_BY_PLAYER );
	
	m_grabController.AttachEntity( pPlayer, pObject, pPhysics, false, vec3_origin, false );
	
	m_pPlayer->m_Local.m_iHideHUD |= HIDEHUD_WEAPONSELECTION;
	m_pPlayer->SetUseEntity( this );
}
void CPlayerPickupController::Init( CBasePlayer *pPlayer, CBaseEntity *pObject )
{
	m_pPlayer = pPlayer;

	IPhysicsObject *pPhysics = pObject->VPhysicsGetObject();
	Vector position;
	QAngle angles;
	pPhysics->GetPosition( &position, &angles );
	m_grabController.SetMaxImpulse( Vector(20*100,20*100,20*100), AngularImpulse(20*180,20*180,20*180) );
	m_grabController.AttachEntity( pObject, pPhysics, position, angles );
	// Holster player's weapon
	if ( m_pPlayer->GetActiveWeapon() )
	{
		if ( !m_pPlayer->GetActiveWeapon()->Holster() )
		{
			Shutdown();
			return;
		}
	}

	m_pPlayer->m_Local.m_iHideHUD |= HIDEHUD_WEAPONS;
	m_pPlayer->SetUseEntity( this );
	matrix3x4_t tmp;
	ComputePlayerMatrix( tmp );
	VectorITransform( position, tmp, m_positionPlayerSpace );

	// UNDONE: This algorithm needs a bit more thought.  REVISIT.
	// put the bottom of the object arms' length below eye level
	// get bottommost point of object
	Vector bottom = physcollision->CollideGetExtent( pPhysics->GetCollide(), vec3_origin, angles, Vector(0,0,-1) );

	// get the real eye origin
	Vector playerEye = pPlayer->EyePosition();

	// move target up so that bottom of object is at PLAYER_HOLD_LEVEL z in local space
//	float delta = PLAYER_HOLD_LEVEL_EYES - bottom.z - m_positionPlayerSpace.z;
	float delta = 0;

	// player can reach down 2ft below his feet
	float maxPickup = (playerEye.z + PLAYER_HOLD_LEVEL_EYES) - (pPlayer->GetAbsMins().z - PLAYER_REACH_DOWN_DISTANCE);

	delta = clamp( delta, pPlayer->WorldAlignMins().z, maxPickup );
	m_positionPlayerSpace.z += delta;
	m_anglesPlayerSpace = TransformAnglesToLocalSpace( angles, tmp );

	m_anglesPlayerSpace = AlignAngles( m_anglesPlayerSpace, DOT_30DEGREE );
	
	// re-transform and check
	angles = TransformAnglesToWorldSpace( m_anglesPlayerSpace, tmp );
	VectorTransform( m_positionPlayerSpace, tmp, position );
	// hackhack: Move up to eye position for the check
	float saveZ = position.z;
	position.z = playerEye.z;
	CheckObjectPosition( position, angles, position );
	
	// move back to original position
	position.z = saveZ;

	VectorITransform( position, tmp, m_positionPlayerSpace );
}
void CPlayerPickupController::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	if ( ToBasePlayer(pActivator) == m_pPlayer )
	{
		CBaseEntity *pAttached = m_grabController.GetAttached();

		// UNDONE: Use vphysics stress to decide to drop objects
		// UNDONE: Must fix case of forcing objects into the ground you're standing on (causes stress) before that will work
		if ( !pAttached || useType == USE_OFF || (m_pPlayer->m_nButtons & IN_ATTACK2) || m_grabController.ComputeError() > 12 )
		{
			Shutdown();
			return;
		}
		
		//Adrian: Oops, our object became motion disabled, let go!
		IPhysicsObject *pPhys = pAttached->VPhysicsGetObject();
		if ( pPhys && pPhys->IsMoveable() == false )
		{
			Shutdown();
			return;
		}

#if STRESS_TEST
		vphysics_objectstress_t stress;
		CalculateObjectStress( pPhys, pAttached, &stress );
		if ( stress.exertedStress > 250 )
		{
			Shutdown();
			return;
		}
#endif

#ifndef PLAYER_DISABLE_THROWING
		// +ATTACK will throw phys objects
		if ( m_pPlayer->m_nButtons & IN_ATTACK )
		{
			Shutdown( true );
			Vector vecLaunch;
			m_pPlayer->EyeVectors( &vecLaunch );
			// JAY: Scale this with mass because some small objects really go flying
			float massFactor = clamp( pPhys->GetMass(), 0.5, 15 );
			massFactor = RemapVal( massFactor, 0.5, 15, 0.5, 4 );
			vecLaunch *= player_throwforce.GetFloat() * massFactor;

			pPhys->ApplyForceCenter( vecLaunch );
			AngularImpulse aVel = RandomAngularImpulse( -10, 10 ) * massFactor;
			pPhys->ApplyTorqueCenter( aVel );
			return;
		}
#endif
		if ( useType == USE_SET )
		{
			// update position
			m_grabController.UpdateObject( m_pPlayer, 12 );
		}
	}
}
void CPlayerPickupController::CheckObjectPosition( Vector &position, const QAngle &angles, const Vector &oldPosition )
{
	CBaseEntity *pAttached = m_grabController.GetAttached();
	trace_t tr;
	// move radially away from the player and check for space
	Vector offsetDir = position - m_pPlayer->GetAbsOrigin();
	offsetDir.z = 0;
	VectorNormalize(offsetDir);
	Vector startSweep = position + offsetDir * pAttached->EntitySpaceSize().Length();

	TraceCollideAgainstBBox( pAttached->VPhysicsGetObject()->GetCollide(), startSweep, position, angles, 
			m_pPlayer->GetAbsOrigin(), m_pPlayer->WorldAlignMins(), m_pPlayer->WorldAlignMaxs(), &tr );

	if ( tr.fraction != 1.0 )
	{
		// if you hit, back off 4 inches and set that as the target
		// otherwise, you made it all the way and the position is fine
		if ( tr.startsolid )
		{
			position = oldPosition;
		}
		else
		{
			position = tr.endpos + offsetDir * 2;
		}
	}
}
void CPlayerPickupController::Shutdown()
{
	m_pPlayer->SetUseEntity( NULL );
	m_grabController.DetachEntity();
	if ( m_pPlayer->GetActiveWeapon() )
	{
		m_pPlayer->GetActiveWeapon()->Deploy();
	}

	m_pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONS;
	Remove();
}
void CPlayerPickupController::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	if ( ToBasePlayer(pActivator) == m_pPlayer )
	{
		CBaseEntity *pAttached = m_grabController.GetAttached();

		if ( !pAttached || useType == USE_OFF || m_grabController.ComputeError() > 12 || (m_pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2)) )
		{
			Shutdown();
			return;
		}
		else if ( useType == USE_SET )
		{
			// update position
			matrix3x4_t tmp;
			ComputePlayerMatrix( tmp );
			Vector position;
			QAngle angles;
			VectorTransform( m_positionPlayerSpace, tmp, position );
			angles = TransformAnglesToWorldSpace( m_anglesPlayerSpace, tmp );
			CheckObjectPosition( position, angles, pAttached->GetAbsOrigin() );

			// check to see if object is still sitting on something
			trace_t tr;
			Vector down = Vector( 0, 0, -6 );
			UTIL_TraceEntity( pAttached, position, position + down, MASK_SOLID, &tr );
			// if trace made it then there's nothing left to sit on, break the tie
			if ( tr.fraction == 1 )
			{
				Shutdown();
				return;
			}
			else
			{
				m_grabController.SetTargetPosition( position, angles );
			}
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : bool - 
//-----------------------------------------------------------------------------
void CPlayerPickupController::Shutdown( bool bThrown )
{
	CBaseEntity *pObject = m_grabController.GetAttached();

	bool bClearVelocity = false;
	if ( !bThrown && pObject && pObject->VPhysicsGetObject() && pObject->VPhysicsGetObject()->GetContactPoint(NULL,NULL) )
	{
		bClearVelocity = true;
	}

	CSDKPlayer *pOwner = (CSDKPlayer *)To_SDKPlayer( m_pPlayer );
	pOwner->ClearUsePickup();

	m_grabController.DetachEntity( bClearVelocity );

	if ( pObject != NULL )
	{
		Pickup_OnPhysGunDrop( pObject, m_pPlayer, bThrown ? THROWN_BY_PLAYER : DROPPED_BY_PLAYER );
	}

	if ( m_pPlayer )
	{
		m_pPlayer->SetUseEntity( NULL );
		if ( m_pPlayer->GetActiveWeapon() )
		{
			if ( !m_pPlayer->GetActiveWeapon()->Deploy() )
			{
				// We tried to restore the player's weapon, but we couldn't.
				// This usually happens when they're holding an empty weapon that doesn't
				// autoswitch away when out of ammo. Switch to next best weapon.
				m_pPlayer->SwitchToNextBestWeapon( NULL );
			}
		}

		m_pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION;
	}
	Remove();
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pEnt - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CPlayerPickupController::IsHoldingEntity( CBaseEntity *pEnt )
{
	return ( m_grabController.GetAttached() == pEnt );
}