local SW = {}

SW.Enabled = false
SW.ViewOrigin = Vector( 0, 0, 0 )
SW.ViewAngle = Angle( 0, 0, 0 )
SW.Velocity = Vector( 0, 0, 0 )

function SW.CalcView( ply, origin, angles, fov )
	if ( !SW.Enabled ) then return end
	if ( SW.SetView ) then
		SW.ViewOrigin = origin
		SW.ViewAngle = angles
		
		SW.SetView = false
	end
	return { origin = SW.ViewOrigin, angles = SW.ViewAngle }
end
hook.Add( "CalcView", "SpiritWalk", SW.CalcView )

function SW.CreateMove( cmd )
	if ( !SW.Enabled ) then return end
	
	// Add and reduce the old velocity.
	local time = FrameTime()
	SW.ViewOrigin = SW.ViewOrigin + ( SW.Velocity * time )
	SW.Velocity = SW.Velocity * 0.95
	
	// Rotate the view when the mouse is moved.
	local sensitivity = 0.022
	SW.ViewAngle.p = math.Clamp( SW.ViewAngle.p + ( cmd:GetMouseY() * sensitivity ), -89, 89 )
	SW.ViewAngle.y = SW.ViewAngle.y + ( cmd:GetMouseX() * -1 * sensitivity )
	
	// What direction we're going to move in.
	local add = Vector( 0, 0, 0 )
	local ang = SW.ViewAngle
	if ( cmd:KeyDown( IN_FORWARD ) ) then add = add + ang:Forward() end
	if ( cmd:KeyDown( IN_BACK ) ) then add = add - ang:Forward() end
	if ( cmd:KeyDown( IN_MOVERIGHT ) ) then add = add + ang:Right() end
	if ( cmd:KeyDown( IN_MOVELEFT ) ) then add = add - ang:Right() end
	if ( cmd:KeyDown( IN_JUMP ) ) then add = add + ang:Up() end
	if ( cmd:KeyDown( IN_DUCK ) ) then add = add - ang:Up() end
	
	// Speed.
	add = add:GetNormal() * time * 500
	if ( cmd:KeyDown( IN_SPEED ) ) then add = add * 2 end
	
	SW.Velocity = SW.Velocity + add
	
	// This stops us looking around crazily while spiritwalking.
	if ( SW.LockView == true ) then
		SW.LockView = cmd:GetViewAngles()
	end
	if ( SW.LockView ) then
		cmd:SetViewAngles( SW.LockView )
	end
	
	// This stops us moving while spiritwalking.
	cmd:SetForwardMove( 0 )
	cmd:SetSideMove( 0 )
	cmd:SetUpMove( 0 )
end
hook.Add( "CreateMove", "SpiritWalk", SW.CreateMove )

function SW.Toggle()
	SW.Enabled = !SW.Enabled
	SW.LockView = SW.Enabled
	SW.SetView = true
	
	local status = { [ true ] = "ON", [ false ] = "OFF" }
	print( "SpiritWalk " .. status[ SW.Enabled ] )
end
concommand.Add( "sw_toggle", SW.Toggle )

concommand.Add( "sw_pos", function() print( SW.ViewOrigin ) end )