Actually, it was a simple oversight
Here is the corrected version from my first post.
y#=object position y(1) + intersect object(2, object position x(1), object position y(1)-100.0, object position z(1), object position x(1), object position y(1)+100.0, object position z(1))-100.0
position object 1, object position x(1), y#, object position z(1)
Here's a complete demo

Just substitute your terrain object for object 1.
autocam off
sync on
sync rate 0
` Make a flat surface
make object plain 1,100.0,100.0
rotate object 1,90.0,0.0,0.0
fix object pivot 1
position object 1,0.0,10.0,0.0
color object 1, rgb(0,255,0)
` Make a movable object
make object sphere 2,5.0
color object 2, rgb(255,0,0)
` Position the camera
position camera 0.0, 50.0, -100.0
point camera 0.0, 0.0, +100.0
while spacekey() = 0
if leftkey() then move object left 2,1.0
if rightkey() then move object right 2,1.0
if upkey() then move object 2,1.0
if downkey() then move object 2,-1.0
` The first argument is the object number of the terrain
` The second arg is the object number of the movable object
` The third argument is an offset to add to make the movable object sit on the surface - in this case, the radius of the sphere
PositionObjectAtGround(1, 2, 5.0)
text 0,0,str$( int( object position y(2) ) )
sync
endwhile
end
function PositionObjectAtGround(TerrainObj as integer, MoveObj as integer, Offset as float)
local x as float
local y as float
local z as float
x=object position x(MoveObj)
y=object position y(MoveObj)
z=object position z(MoveObj)
y= y + ( intersect object(TerrainObj, x, y-100.0, z, x, y+100.0, z) - 100.0 ) + Offset
position object MoveObj, x, y, z
endfunction