local function V(V,n)return math_atan2(n.X*V.Z-n.Z*V.X,n.X*V.X+n.Z*V.Z)end local function n(V,n)local v=script:FindFirstChild(V)if v then return v.Value end return n end local function v(V,n,v)local S=script:FindFirstChild(V)if S and S:isA(n)then externalProperties[V]=S.Value elseif externalProperties[V]~=nil then S=Instance.new(n)S.Name=V S.Parent=script S.Value=externalProperties[V]else print("\101\120\116\101\114\110\097\108\080\114\111\112\101\114\116\105\101\115 \116\097\098\108\101 \104\097\115 \110\111 \101\110\116\114\121 \102\111\114 ",V)return end if v then if changedSignalConnections[V]then changedSignalConnections[V]:disconnect()end changedSignalConnections[V]=S.Changed:connect(function(n)externalProperties[V]=n v()end)end end local function S()minAzimuthAbsoluteRad=math.rad(externalProperties.ReferenceAzimuth)-math.abs(math.rad(externalProperties.CWAzimuthTravel))maxAzimuthAbsoluteRad=math.rad(externalProperties.ReferenceAzimuth)+math.abs(math.rad(externalProperties.CCWAzimuthTravel))useAzimuthLimits=externalProperties.UseAzimuthLimits if useAzimuthLimits then curAzimuthRad=math.max(curAzimuthRad,minAzimuthAbsoluteRad)curAzimuthRad=math.min(curAzimuthRad,maxAzimuthAbsoluteRad)end end local function i()local V=math.max(externalProperties.MinElevation,MIN_ALLOWED_ELEVATION_DEG)local n=math.min(externalProperties.MaxElevation,MAX_ALLOWED_ELEVATION_DEG)minElevationRad=math.rad(math.min(V,n))maxElevationRad=math.rad(math.max(V,n))curElevationRad=math.max(curElevationRad,minElevationRad)curElevationRad=math.min(curElevationRad,maxElevationRad)end local function P()minDistance=externalProperties.MinDistance maxDistance=externalProperties.MaxDistance curDistance=math.max(curDistance,minDistance)curDistance=math.min(curDistance,maxDistance)end

local function findAngleBetweenXZVectors(vec2, vec1)
	return math_atan2(vec1.X*vec2.Z-vec1.Z*vec2.X, vec1.X*vec2.X + vec1.Z*vec2.Z)
end

local function GetValueObject(name, defaultValue)
	local valueObj = script:FindFirstChild(name)
	if valueObj then
		return valueObj.Value
	end
	return defaultValue
end

local function LoadOrCreateNumberValueParameter(name, valueType, updateFunction)
	local valueObj = script:FindFirstChild(name)
	
	if valueObj and valueObj:isA(valueType) then
		-- Value object exists and is the correct type, use its value
		externalProperties[name] = valueObj.Value
	elseif externalProperties[name] ~= nil then
		-- Create missing (or replace incorrectly-typed) valueObject with default value
		valueObj = Instance.new(valueType)
		valueObj.Name = name
		valueObj.Parent = script
		valueObj.Value = externalProperties[name]
	else
		print("externalProperties table has no entry for ",name)
		return
	end
	
	if updateFunction then
		if changedSignalConnections[name] then
			changedSignalConnections[name]:disconnect()
		end
		changedSignalConnections[name] = valueObj.Changed:connect(function(newValue)
			externalProperties[name] = newValue
			updateFunction()
		end)
	end
end

local function SetAndBoundsCheckAzimuthValues()
	minAzimuthAbsoluteRad = math.rad(externalProperties["ReferenceAzimuth"]) - math.abs(math.rad(externalProperties["CWAzimuthTravel"]))
	maxAzimuthAbsoluteRad = math.rad(externalProperties["ReferenceAzimuth"]) + math.abs(math.rad(externalProperties["CCWAzimuthTravel"]))
	useAzimuthLimits = externalProperties["UseAzimuthLimits"]
	if useAzimuthLimits then
		curAzimuthRad = math.max(curAzimuthRad, minAzimuthAbsoluteRad)
		curAzimuthRad = math.min(curAzimuthRad, maxAzimuthAbsoluteRad)
	end
end

local function SetAndBoundsCheckElevationValues()
	-- These degree values are the direct user input values. It is deliberate that they are
	-- ranged checked only against the extremes, and not against each other. Any time one
	-- is changed, both of the internal values in radians are recalculated. This allows for
	-- A developer to change the values in any order and for the end results to be that the
	-- internal values adjust to match intent as best as possible.
	local minElevationDeg = math.max(externalProperties["MinElevation"], MIN_ALLOWED_ELEVATION_DEG)
	local maxElevationDeg = math.min(externalProperties["MaxElevation"], MAX_ALLOWED_ELEVATION_DEG)
	
	-- Set internal values in radians
	minElevationRad = math.rad(math.min(minElevationDeg, maxElevationDeg))
	maxElevationRad = math.rad(math.max(minElevationDeg, maxElevationDeg))
	curElevationRad = math.max(curElevationRad, minElevationRad)
	curElevationRad = math.min(curElevationRad, maxElevationRad)
end

local function SetAndBoundsCheckDistanceValues()
	minDistance = externalProperties["MinDistance"]
	maxDistance = externalProperties["MaxDistance"]
	curDistance = math.max(curDistance, minDistance)
	curDistance = math.min(curDistance, maxDistance)
end
