//Advanced Raycasting

//Helper functions
function NewCast(%start,%end,%mask,%exclude) {
	%id = new ScriptObject(ContainerRayCast) {
        	class = ContainerRayCast;
		start = %start;
		next = %start;
	        end   = %end;
	        mask = %mask;
	        exclude = %exclude;
		};
	return %id;
}

function ContainerRayCast::NewCast(%id,%start,%end,%mask,%exclude) {
	%id.next = %start;%id.end = %end;%id.mask = %mask;%id.exclude = %exclude;
}

function RayInfo::NewCast(%ray,%start,%end,%mask,%exclude) {
	if (%start $= "") 
		%next = %ray.cast.point;	
	%type = getWordCount(%end);
	if (%type == 0) 
		%end = %ray.cast.end;
	else if (%type == 1) 
   		%end = VectorAdd(%ray.point,VectorScale(%ray.normal,%end));
	%mask = %mask | %ray.cast.mark;
	%exclude = trim(%ray.cast.exclude SPC %exclude);
	return NewCast(%ray.point,%end,%mask,%exclude);
}

function ContainerRayCast::DoCast(%id) {
	return containerRayCast(%id.next,%id.end,%id.mask,%id.exclude); 
}

//Fast Raycasting functions.
function castRay(%start,%end,%mask,%exclude) {
	%cast = NewCast(%start,%end,%mask,%exclude);
	return %cast.castRay();
}

function ContainerRayCast::castRay(%cast) {
%res = %cast.docast();
if (%res) {
	%id = new ScriptObject(RayInfo) {
        	class = RayInfo;
		object = getWord(%res,0);
		point = getWords(%res,1,3);
        	normal = getWords(%res,4,6);
	        t = getWords(%res,8);
        	cast = %cast;
	        distance = getWords(%res,8) * VectorDist(%start,%end);
		};
	return %id;
	}
else	{
	%cast.delete();
	return false;
	}
}

function RayDist(%start,%dir,%min,%max,%norm,%mask,%exclude) {
	%res = containerRayCast(%start,VectorAdd(%start,VectorScale(%dir,%max)),%mask,%exclude);    
        if (%res) {
		%dist = VectorDist(%start,getWords(%res,1,3));
		%dist = %dist < %min ? %min : %dist;
        }
	else
		%dist = %norm;
	return %dist;
}

//Raygun casting.

//Starts a Raycast from [position] %start to [position] %end.
function InitContainerRayCast(%start,%end,%mask,%exclude) {
	%id = NewCast(%start,%end,%mask,%exclude);
	$currentContainerRayCast = %id;
        return %id;
}

//Returns next [object] %res, colliding with the RayCast.
function ContainerRayCastNext(%id) {
	%id = %id ? %id : $currentContainerRayCast;
        if (!isObject(%id))
		return;
        %ray = %id.castRay();
        if (%ray) {
                %id.newCast("","","",%ray.object);
        }
	else {
		%id.delete();
	}
	return %ray;
}

//Returns the last colission distance of the RayCast.
function ContainerRayCastDist(%id) {
	%id = %id ? %id : $currentContainerRayCast;
	return VectorDist(%id.start,%id.next);
}