RoboCatz.com
About FLL | Navigation | Playbook | Strategy | Models | Techniques | RobotC | Programming | Robot News |

-- drones ModuleScript in the ReplicatedStorage area

-- drones ModuleScript in the ReplicatedStorage area
local drones = {}
drones.__index = drones
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local s = require(ReplicatedStorage.genericShapes)
local TweenService = game:GetService("TweenService") 

local defaultColor = Color3.new(0.0117647, 0.984314, 1)
local defaultBorderThickness = 0.5

drones.zDirection = -1

-- collection {}
-- This is an array used to store the collection of drones.
--   When the moveDrones() function is called, a collection of drones is passed into the function.
--   Only those drones in the collection are moved.
--   Each element of the array stores an Instance of a "union" created by joining the two parts of the drone together.
drones.collection = {}
drones.actions = {}

-- forwardSpeedAdjustment --------------------------
-- This number is multiplied to the speed requested.  Because of the algorithm used and the scale of units in Roblox, 
--   it is desireable to adjust the speed to 1/5th of what was requested.  This will allow the user to more clearly
--   see the movement of the drone.
drones.forwardSpeedAdjustment = 0.1   

-- allGyroSensorsOffset -------------------
-- A variable used to keep track of the difference between the Roblox world and the orientation used for the compass shown under the Avatar
drones.allVectorsOffset = 270;

local blockSize = 64
local halfBlock = 32


local colorName={
	["pink"]={["RGB"]="FFC0CB", ["DEC"]={255,192,203}},
	["lightpink"]={["RGB"]="FFB6C1", ["DEC"]={255,182,193}},
	["hotpink"]={["RGB"]="FF69B4", ["DEC"]={255,105,180}},
	["deeppink"]={["RGB"]="FF1493", ["DEC"]={255,20,147}},
	["palevioletred"]={["RGB"]="DB7093", ["DEC"]={219,112,147}},
	["mediumvioletred"]={["RGB"]="C71585", ["DEC"]={199,21,133}},
	["lightsalmon"]={["RGB"]="FFA07A", ["DEC"]={255,160,122}},
	["salmon"]={["RGB"]="FA8072", ["DEC"]={250,128,114}},
	["darksalmon"]={["RGB"]="E9967A", ["DEC"]={233,150,122}},
	["lightcoral"]={["RGB"]="F08080", ["DEC"]={240,128,128}},
	["indianred"]={["RGB"]="CD5C5C", ["DEC"]={205,92,92}},
	["crimson"]={["RGB"]="DC143C", ["DEC"]={220,20,60}},
	["firebrick"]={["RGB"]="B22222", ["DEC"]={178,34,34}},
	["darkred"]={["RGB"]="8B0000", ["DEC"]={139,0,0}},
	["red"]={["RGB"]="FF0000", ["DEC"]={255,0,0}},
	["orangered"]={["RGB"]="FF4500", ["DEC"]={255,69,0}},
	["tomato"]={["RGB"]="FF6347", ["DEC"]={255,99,71}},
	["coral"]={["RGB"]="FF7F50", ["DEC"]={255,127,80}},
	["darkorange"]={["RGB"]="FF8C00", ["DEC"]={255,140,0}},
	["orange"]={["RGB"]="FFA500", ["DEC"]={255,165,0}},
	["yellow"]={["RGB"]="FFFF00", ["DEC"]={255,255,0}},
	["lightyellow"]={["RGB"]="FFFFE0", ["DEC"]={255,255,224}},
	["lemonchiffon"]={["RGB"]="FFFACD", ["DEC"]={255,250,205}},
	["lightgoldenrodyellow"]={["RGB"]="FAFAD2", ["DEC"]={250,250,210}},
	["papayawhip"]={["RGB"]="FFEFD5", ["DEC"]={255,239,213}},
	["moccasin"]={["RGB"]="FFE4B5", ["DEC"]={255,228,181}},
	["peachpuff"]={["RGB"]="FFDAB9", ["DEC"]={255,218,185}},
	["palegoldenrod"]={["RGB"]="EEE8AA", ["DEC"]={238,232,170}},
	["khaki"]={["RGB"]="F0E68C", ["DEC"]={240,230,140}},
	["darkkhaki"]={["RGB"]="BDB76B", ["DEC"]={189,183,107}},
	["gold"]={["RGB"]="FFD700", ["DEC"]={255,215,0}},
	["cornsilk"]={["RGB"]="FFF8DC", ["DEC"]={255,248,220}},
	["blanchedalmond"]={["RGB"]="FFEBCD", ["DEC"]={255,235,205}},
	["bisque"]={["RGB"]="FFE4C4", ["DEC"]={255,228,196}},
	["navajowhite"]={["RGB"]="FFDEAD", ["DEC"]={255,222,173}},
	["wheat"]={["RGB"]="F5DEB3", ["DEC"]={245,222,179}},
	["burlywood"]={["RGB"]="DEB887", ["DEC"]={222,184,135}},
	["tan"]={["RGB"]="D2B48C", ["DEC"]={210,180,140}},
	["rosybrown"]={["RGB"]="BC8F8F", ["DEC"]={188,143,143}},
	["sandybrown"]={["RGB"]="F4A460", ["DEC"]={244,164,96}},
	["goldenrod"]={["RGB"]="DAA520", ["DEC"]={218,165,32}},
	["darkgoldenrod"]={["RGB"]="B8860B", ["DEC"]={184,134,11}},
	["peru"]={["RGB"]="CD853F", ["DEC"]={205,133,63}},
	["chocolate"]={["RGB"]="D2691E", ["DEC"]={210,105,30}},
	["saddlebrown"]={["RGB"]="8B4513", ["DEC"]={139,69,19}},
	["sienna"]={["RGB"]="A0522D", ["DEC"]={160,82,45}},
	["brown"]={["RGB"]="A52A2A", ["DEC"]={165,42,42}},
	["maroon"]={["RGB"]="800000", ["DEC"]={128,0,0}},
	["darkolivegreen"]={["RGB"]="556B2F", ["DEC"]={85,107,47}},
	["olive"]={["RGB"]="808000", ["DEC"]={128,128,0}},
	["olivedrab"]={["RGB"]="6B8E23", ["DEC"]={107,142,35}},
	["yellowgreen"]={["RGB"]="9ACD32", ["DEC"]={154,205,50}},
	["limegreen"]={["RGB"]="32CD32", ["DEC"]={50,205,50}},
	["lime"]={["RGB"]="00FF00", ["DEC"]={0,255,0}},
	["lawngreen"]={["RGB"]="7CFC00", ["DEC"]={124,252,0}},
	["chartreuse"]={["RGB"]="7FFF00", ["DEC"]={127,255,0}},
	["greenyellow"]={["RGB"]="ADFF2F", ["DEC"]={173,255,47}},
	["springgreen"]={["RGB"]="00FF7F", ["DEC"]={0,255,127}},
	["mediumspringgreen"]={["RGB"]="00FA9A", ["DEC"]={0,250,154}},
	["lightgreen"]={["RGB"]="90EE90", ["DEC"]={144,238,144}},
	["palegreen"]={["RGB"]="98FB98", ["DEC"]={152,251,152}},
	["darkseagreen"]={["RGB"]="8FBC8F", ["DEC"]={143,188,143}},
	["mediumaquamarine"]={["RGB"]="66CDAA", ["DEC"]={102,205,170}},
	["mediumseagreen"]={["RGB"]="3CB371", ["DEC"]={60,179,113}},
	["seagreen"]={["RGB"]="2E8B57", ["DEC"]={46,139,87}},
	["forestgreen"]={["RGB"]="228B22", ["DEC"]={34,139,34}},
	["green"]={["RGB"]="008000", ["DEC"]={0,128,0}},
	["darkgreen"]={["RGB"]="006400", ["DEC"]={0,100,0}},
	["aqua"]={["RGB"]="00FFFF", ["DEC"]={0,255,255}},
	["cyan"]={["RGB"]="00FFFF", ["DEC"]={0,255,255}},
	["lightcyan"]={["RGB"]="E0FFFF", ["DEC"]={224,255,255}},
	["paleturquoise"]={["RGB"]="AFEEEE", ["DEC"]={175,238,238}},
	["aquamarine"]={["RGB"]="7FFFD4", ["DEC"]={127,255,212}},
	["turquoise"]={["RGB"]="40E0D0", ["DEC"]={64,224,208}},
	["mediumturquoise"]={["RGB"]="48D1CC", ["DEC"]={72,209,204}},
	["darkturquoise"]={["RGB"]="00CED1", ["DEC"]={0,206,209}},
	["lightseagreen"]={["RGB"]="20B2AA", ["DEC"]={32,178,170}},
	["cadetblue"]={["RGB"]="5F9EA0", ["DEC"]={95,158,160}},
	["darkcyan"]={["RGB"]="008B8B", ["DEC"]={0,139,139}},
	["teal"]={["RGB"]="008080", ["DEC"]={0,128,128}},
	["lightsteelblue"]={["RGB"]="B0C4DE", ["DEC"]={176,196,222}},
	["powderblue"]={["RGB"]="B0E0E6", ["DEC"]={176,224,230}},
	["lightblue"]={["RGB"]="ADD8E6", ["DEC"]={173,216,230}},
	["skyblue"]={["RGB"]="87CEEB", ["DEC"]={135,206,235}},
	["lightskyblue"]={["RGB"]="87CEFA", ["DEC"]={135,206,250}},
	["deepskyblue"]={["RGB"]="00BFFF", ["DEC"]={0,191,255}},
	["dodgerblue"]={["RGB"]="1E90FF", ["DEC"]={30,144,255}},
	["cornflowerblue"]={["RGB"]="6495ED", ["DEC"]={100,149,237}},
	["steelblue"]={["RGB"]="4682B4", ["DEC"]={70,130,180}},
	["royalblue"]={["RGB"]="041690", ["DEC"]={65,105,225}},
	["blue"]={["RGB"]="0000FF", ["DEC"]={0,0,255}},
	["mediumblue"]={["RGB"]="0000CD", ["DEC"]={0,0,205}},
	["darkblue"]={["RGB"]="00008B", ["DEC"]={0,0,139}},
	["navy"]={["RGB"]="000080", ["DEC"]={0,0,128}},
	["midnightblue"]={["RGB"]="191970", ["DEC"]={25,25,112}},
	["lavender"]={["RGB"]="E6E6FA", ["DEC"]={230,230,250}},
	["thistle"]={["RGB"]="D8BFD8", ["DEC"]={216,191,216}},
	["plum"]={["RGB"]="DDA0DD", ["DEC"]={221,160,221}},
	["violet"]={["RGB"]="EE82EE", ["DEC"]={238,130,238}},
	["orchid"]={["RGB"]="DA70D6", ["DEC"]={218,112,214}},
	["fuchsia"]={["RGB"]="FF00FF", ["DEC"]={255,0,255}},
	["magenta"]={["RGB"]="FF00FF", ["DEC"]={255,0,255}},
	["mediumorchid"]={["RGB"]="BA55D3", ["DEC"]={186,85,211}},
	["mediumpurple"]={["RGB"]="9370DB", ["DEC"]={147,112,219}},
	["blueviolet"]={["RGB"]="8A2BE2", ["DEC"]={138,43,226}},
	["darkviolet"]={["RGB"]="9400D3", ["DEC"]={148,0,211}},
	["darkorchid"]={["RGB"]="9932CC", ["DEC"]={153,50,204}},
	["darkmagenta"]={["RGB"]="8B008B", ["DEC"]={139,0,139}},
	["purple"]={["RGB"]="800080", ["DEC"]={128,0,128}},
	["indigo"]={["RGB"]="4B0082", ["DEC"]={75,0,130}},
	["darkslateblue"]={["RGB"]="483D8B", ["DEC"]={72,61,139}},
	["slateblue"]={["RGB"]="6A5ACD", ["DEC"]={106,90,205}},
	["mediumslateblue"]={["RGB"]="7B68EE", ["DEC"]={123,104,238}},
	["white"]={["RGB"]="FFFFFF", ["DEC"]={255,255,255}},
	["snow"]={["RGB"]="FFFAFA", ["DEC"]={255,250,250}},
	["honeydew"]={["RGB"]="F0FFF0", ["DEC"]={240,255,240}},
	["mintcream"]={["RGB"]="F5FFFA", ["DEC"]={245,255,250}},
	["azure"]={["RGB"]="F0FFFF", ["DEC"]={240,255,255}},
	["aliceblue"]={["RGB"]="F0F8FF", ["DEC"]={240,248,255}},
	["ghostwhite"]={["RGB"]="F8F8FF", ["DEC"]={248,248,255}},
	["whitesmoke"]={["RGB"]="F5F5F5", ["DEC"]={245,245,245}},
	["seashell"]={["RGB"]="FFF5EE", ["DEC"]={255,245,238}},
	["beige"]={["RGB"]="F5F5DC", ["DEC"]={245,245,220}},
	["oldlace"]={["RGB"]="FDF5E6", ["DEC"]={253,245,230}},
	["floralwhite"]={["RGB"]="FFFAF0", ["DEC"]={255,250,240}},
	["ivory"]={["RGB"]="FFFFF0", ["DEC"]={255,255,240}},
	["antiquewhite"]={["RGB"]="FAEBD7", ["DEC"]={250,235,215}},
	["linen"]={["RGB"]="FAF0E6", ["DEC"]={250,240,230}},
	["lavenderblush"]={["RGB"]="FFF0F5", ["DEC"]={255,240,245}},
	["mistyrose"]={["RGB"]="FFE4E1", ["DEC"]={255,228,225}},
	["gainsboro"]={["RGB"]="DCDCDC", ["DEC"]={220,220,220}},
	["lightgrey"]={["RGB"]="D3D3D3", ["DEC"]={211,211,211}},
	["silver"]={["RGB"]="C0C0C0", ["DEC"]={192,192,192}},
	["darkgray"]={["RGB"]="A9A9A9", ["DEC"]={169,169,169}},
	["gray"]={["RGB"]="808080", ["DEC"]={128,128,128}},
	["dimgray"]={["RGB"]="696969", ["DEC"]={105,105,105}},
	["lightslategray"]={["RGB"]="778899", ["DEC"]={119,136,153}},
	["slategray"]={["RGB"]="708090", ["DEC"]={112,128,144}},
	["darkslategray"]={["RGB"]="2F4F4F", ["DEC"]={47,79,79}},
	["black"]={["RGB"]="000000", ["DEC"]={0,0,0}}
}

local materialNames = {
	"Plastic",
	"Wood",
	"Slate",
	"Concrete",
	"CorrodedMetal",
	"DiamondPlate",
	"Foil",
	"Grass",
	"Ice",
	"Marble",
	"Granite",
	"Brick",
	"Pebble",
	"Sand",
	"Fabric",
	"SmoothPlastic",
	"Metal",
	"WoodPlanks",
	"Cobblestone",
	"Air",
	"Water",
	"Rock",
	"Glacier",
	"Snow",
	"Sandstone",
	"Mud",
	"Basalt",
	"Ground",
	"CrackedLava",
	"Neon",
	"Glass",
	"Asphalt",
	"LeafyGrass",
	"Salt",
	"Limestone",
	"Pavement",
	"ForceField"
}

print("Clearing the droneActions array")
drones.actions = {}
drones.collection = {}


function drones.moveTo2(compassParts, updatedPosition)
	--print("Updating position.  Has a type of: "..typeof(updatedPosition))
	local difference = updatedPosition - (compassParts[1]:GetPivot()).p  -- Calculate the difference between the current avatar and the compass
	compassParts[1]:PivotTo(compassParts[1]:GetPivot() + difference)             -- Add the difference to the compass's CFrame.
	compassParts[2]:PivotTo(compassParts[2]:GetPivot() + difference)             -- Add the difference to the compass's CFrame.
end

function drones.moveDrones(droneCollection)
	-- move the drones that need moved
	--print("There are "..tostring(#droneCollection).." drones in the collection")
	--print(typeof(droneCollection[1]))
	for i=1,#droneCollection do
		-- look to see if there is an action required
		--print("checking drone " .. tostring(i) .. " droneActions has a length of " .. tostring(#drones.actions))
		if drones.actions[i] then
			--print("Prior to TweenService:Play(): droneCollection[i] is an "..typeof(droneCollection[i]).." Position: "..tostring(drones.actions[i].Position))
			--print("droneActions[i] is of a type: "..typeof(drones.actions[i]).. " " .. tostring(drones.actions[i]))
			if drones.actions[i].Action == "MoveTo" then
				local deltaX = droneCollection[i].Position.x - droneCollection[i]:GetAttribute("lastPositionX")
				local deltaZ = droneCollection[i].Position.z - droneCollection[i]:GetAttribute("lastPositionZ")
				local distanceTraveled = math.sqrt((deltaX*deltaX)+(deltaZ*deltaZ))
				droneCollection[i]:SetAttribute("encoderValue", droneCollection[i]:GetAttribute("encoderValue") + distanceTraveled)
				droneCollection[i]:SetAttribute("lastPositionX", droneCollection[i].Position.x)
				droneCollection[i]:SetAttribute("lastPositionZ", droneCollection[i].Position.z)
				drones.actions[i].Completed = true
			end
			if drones.actions[i].Action == "Forward" and drones.actions[i].Speed ~= 0 then
				local MoveInfo = TweenInfo.new(1, Enum.EasingStyle.Sine,Enum.EasingDirection.Out, 0, false, 0)  -- parameters here include repeatCount and Reversible
				-- get the current orientation in degrees from the CFrame
				-- use sine and cosine to determine the deltaX and deltaZ needed for the new position
				-- add to the current position to get the new position
				local currentOrientation = droneCollection[i]:GetPivot()
				local cfa = droneCollection[i].CFrame.LookVector
				local arcTangent = (math.atan2(cfa.x, cfa.z)*180/math.pi) - 90
				local deltaX = math.sin(math.rad((currentOrientation.Rotation.Y-arcTangent) + 90)) * drones.actions[i].Speed
				local deltaZ = math.cos(math.rad((currentOrientation.Rotation.Y-arcTangent) + 90)) * drones.actions[i].Speed * -1   -- Multiplying z by -1 to correct the axis to make it more like a cartesian coordinate system
				local newPosition = Vector3.new(currentOrientation.Position.X + deltaX, currentOrientation.Position.Y, currentOrientation.Position.Z + deltaZ)
				local MovePart = TweenService:Create(droneCollection[i], MoveInfo, {Position = newPosition})
				MovePart:Play()
				MovePart.Completed:Connect(function()
					drones.actions[i].Completed = true
				end)
				-- Add to the encoder value
				local deltaX = droneCollection[i].Position.x - droneCollection[i]:GetAttribute("lastPositionX")
				local deltaZ = droneCollection[i].Position.z - droneCollection[i]:GetAttribute("lastPositionZ")
				local distanceTraveled = math.sqrt((deltaX*deltaX)+(deltaZ*deltaZ))
				droneCollection[i]:SetAttribute("encoderValue", droneCollection[i]:GetAttribute("encoderValue") + distanceTraveled)
				droneCollection[i]:SetAttribute("lastPositionX", droneCollection[i].Position.x)
				droneCollection[i]:SetAttribute("lastPositionZ", droneCollection[i].Position.z)
			end
			if drones.actions[i].Action == "RotateBy" and drones.actions[i].Rotation ~= 0 then   -- The ~= is "not equal to"
				local newCFrame = drones.collection[i].CFrame * CFrame.Angles(0, math.rad(drones.actions[i].Rotation), 0) -- A positive value for Rotation means counter-clockwise
				--droneCollection[i].CFrame = drones.collection[i].CFrame * CFrame.Angles(0, math.rad(drones.actions[i].Rotation), 0)
				local MoveInfo = TweenInfo.new(1, Enum.EasingStyle.Sine,Enum.EasingDirection.Out, 0, false, 0)  -- parameters here include repeatCount and Reversible
				local MovePart = TweenService:Create(droneCollection[i], MoveInfo, {CFrame = newCFrame })
				MovePart:Play()
				MovePart.Completed:Connect(function()
					drones.actions[i].Completed = true
				end)
				local axis, angle = droneCollection[i].CFrame:ToAxisAngle()
				local x,y,z = drones.collection[i]:GetPivot():ToOrientation()
				-- Going to make an adjustment to the value of the gyro.
				-- Only going to change the value by the change in vectors observed in the drone.
				-- The change in vectors observed in the drone is the difference from the previous vector value and the current vector value
				-- Add this difference to the current gyro value to obtain a new gyro value which will represent the amount that the drone has rotated
				local lastGyroSensorValue = droneCollection[i]:GetAttribute("gyroSensor")
				local lastVectorValue = droneCollection[i]:GetAttribute("lastVectorValue")
				local currentVectorValue = drones.vectorValue(i)
				local changeInVectors = currentVectorValue - lastVectorValue
				if drones.actions[i].Rotation > 0 then
					if currentVectorValue < lastVectorValue then
						-- looped past the zero point, subtract 360 from lastVectorValue
						changeInVectors = currentVectorValue - (lastVectorValue - 360)
					end
				else -- turning clockwise
					if currentVectorValue > lastVectorValue then
						-- looped past the zero point, add 360 to lastVectorValue
						changeInVectors = (lastVectorValue + 360) - currentVectorValue
					end
				end
				local newGyroSensorValue = lastGyroSensorValue + changeInVectors
				droneCollection[i]:SetAttribute("gyroSensor", newGyroSensorValue)
				droneCollection[i]:SetAttribute("lastVectorValue", currentVectorValue) -- Update with the current value
				--print("drone[" .. tostring(i) .. "].gyroSensor is: " .. tostring(droneCollection[i]:GetAttribute("gyroSensor")) .. " Drone vector is: " .. tostring(drones.vectorValue(i)) .. ";  " .. tostring(drones.actions[i].Rotation/2))
				--print(tostring(((270+math.abs((axis.Y*180)+(angle*180/math.pi)))%360)))

			end
			--print("Post to TweenService:Play()")
		end
	end
end
--[[
 stopMoving()
 This function will stop the drone from turning or moving.
 Parameters (optional): drone index
 Examples:  d.stopMoving(droneN)
]]
function drones.stopMoving(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1  -- Default value
	if #arguments > 0 then targetDroneIndex = arguments[1] end
	--print("Stopping the drone")
	drones.rotateBy(targetDroneIndex, 0)      -- stops turning
	drones.moveForward(targetDroneIndex, 0)   -- stops moving forward
	drones.actions[targetDroneIndex] = {Action = "Stop"}
	--print("All stopped")
end
--[[
 rotateBy()
 This low-level function causes the drone to start rotating either clockwise or counter-clockwise at a speed set by the specified parameter.
 Parameters are: drone index, and rotation speed
 Parameters passed should be a scalar numeric variable.  The rotation speed parameter has a range from -20 to +20.
 A rotation value of zero causes the drone to stop rotating.
 Negative values cause the drone to rotate clockwise.
 Positive values cause the drone to rotate counter-clockwise.
 Examples:  d.rotateBy(droneN, 20)     d.rotateBy(droneN, -20)
 Examples:  d.rotateBy(20)     d.rotateBy(-20)   -- Rotate the default drone
]]
function drones.rotateBy(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1  -- Default value
	local targetDroneRotationSpeed = 20 -- Default value
	if #arguments == 1 then targetDroneRotationSpeed = arguments[1]	end  -- If only one argument is supplied, use that as the speed
	if #arguments >= 2 then
		targetDroneIndex = arguments[1]
		targetDroneRotationSpeed = arguments[2]
	end
	--print("Setting the rotation to: " .. tostring(targetDroneRotationSpeed))
	drones.actions[targetDroneIndex] = {Action = "RotateBy", Rotation = targetDroneRotationSpeed, Completed = false}
end

--[[
 gyroSensorValue()
 This function will get the gyro value.
 Parameter: drone index (optional)
 Examples:  d.gyroSensorValue()       -- Get the gyroSensorValue from the default drone (#1)
 Examples:  d.gyroSensorValue(droneN) -- Get the gyroSensorValue from the specified drone
]]
function drones.gyroSensorValue(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1  -- Default value
	if #arguments >= 1 then targetDroneIndex = arguments[1] end
	return drones.collection[targetDroneIndex]:GetAttribute("gyroSensor")
end
-- ------------------------------------------------------------------------
--[[
 vectorValue()
 This function will get the vector value for the drone (i.e., where it is pointing from 0-359 degrees.
 Parameter: drone index (optional)
 Examples:  d.vectorValue()
 Examples:  d.vectorValue(droneN)
]]
function drones.vectorValue(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1  -- Default value
	if #arguments >= 1 then targetDroneIndex = arguments[1] end
	local currentOrientation = drones.collection[targetDroneIndex]:GetPivot()
	local cfa = drones.collection[targetDroneIndex].CFrame.LookVector
	local currentVector = (math.atan2(cfa.x, cfa.z)*180/math.pi) + drones.allVectorsOffset
	--print("curr vector 1: "..tostring(currentVector))
	--print("curr vector 2: "..tostring(currentVector%360))
	return currentVector % 360
end
-- ------------------------------------------------------------------------
--[[
 resetGyroSensor()
 This function will reset the gyro to zero.
 Parameters required: drone index
 Parameter: Gyro value (optional) - You can initialize the gyro to a specific value by specifying it as the second argument
 Examples:  d.resetGyroSensor(1)      -- Reset the gyro for drone #1
 Examples:  d.resetGyroSensor(1, 90)  -- Set drone #1's gyro to 90 degrees.
]]
function drones.resetGyroSensor(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1          -- Default value
	if #arguments > 0 then targetDroneIndex = arguments[1] end
	drones.collection[targetDroneIndex]:SetAttribute("gyroSensor", 0)
	if #arguments >= 2 then drones.collection[targetDroneIndex]:SetAttribute("gyroSensor", arguments[2]) end
	local currentOrientation = drones.collection[targetDroneIndex]:GetPivot()
	local cfa = drones.collection[targetDroneIndex].CFrame.LookVector
	local degreeOffsetFromZero = (math.atan2(cfa.x, cfa.z)*180/math.pi)
	print("Resetting gyro.  Difference from absolute zero is: ".. tostring(drones.collection[targetDroneIndex]:GetAttribute("gyroSensorOffsetFromTrueZero")))
	--if degreeOffsetFromZero < 0 then degreeOffsetFromZero = degreeOffsetFromZero + 360 end
	drones.collection[targetDroneIndex]:SetAttribute("gyroSensorOffsetFromTrueZero", degreeOffsetFromZero)
end
-- ------------------------------------------------------------------------
--[[
 moveForward()
 This function will reset start the drone moving forward.
 Parameters (optional): droneIndex, speed
 Examples:  d.moveForward(40)           -- Move the default drone forward at 40% power
 Examples:  d.moveForward(1, 50)        -- Move drone #1 forward at 50% power
 Examples:  d.moveForward(4, 80)        -- Move drone #4 forward at 80% power
]]
function drones.moveForward(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1          -- Default value
	local targetDroneForwardSpeed = 20  -- Default value
	if #arguments == 1 then targetDroneForwardSpeed = arguments[1] end
	if #arguments >= 2 then
		targetDroneIndex = arguments[1]
		targetDroneForwardSpeed = arguments[2] 
	end
	--print("Setting the speed to: " .. tostring(targetDroneForwardSpeed))
	drones.actions[targetDroneIndex] = {Action = "Forward", Speed = targetDroneForwardSpeed * drones.forwardSpeedAdjustment, Completed = false}
end
-- ------------------------------------------------------------------------
--[[
 encoderValue()
 This function will return the drone's encoderValue.
 Parameters (optional): drone index
 Examples:  d.encoderValue(droneN)
]]
function drones.encoderValue(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1  -- Default value
	if #arguments > 0 then targetDroneIndex = arguments[1] end
	return drones.collection[targetDroneIndex]:GetAttribute("encoderValue")
end
-- ------------------------------------------------------------------------
--[[
 resetEncoder()
 This function will reset the drone's encoderValue.
 Parameters (optional): drone index
 Examples:  d.resetEncoder(droneN)
]]
function drones.resetEncoder(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1  -- Default value
	if #arguments > 0 then targetDroneIndex = arguments[1] end
	drones.collection[targetDroneIndex]:SetAttribute("encoderValue", 0)
end
-- ------------------------------------------------------------------------
--[[
 getPosition()
 This function will return the position of the drone
 Parameters (optional): drone index
 Examples:  d.resetEncoder(droneN)
]]
function drones.getPosition(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1  -- Default value
	if #arguments > 0 then targetDroneIndex = arguments[1] end
	return drones.collection[targetDroneIndex].Position
end
-- ------------------------------------------------------------------------

--[[
 moveTo()
 This function will move the drone to a coordinate.
 Parameter: drone index (optional)
 Parameter: Vector3 coordinate (required)
 Examples:  d.moveTo(droneN, Vector3.new(0, 4, 0))   -- Move specified drone to coordinates 0, 0
 Examples:  d.moveTo(Vector3.new(0, 4, 0))           -- Move default drone (1) to coordinates 0, 0
]]
function drones.moveTo(...)
	--print("In the moveTo()")
	local arguments = table.pack(...)
	local targetDroneIndex = 1  -- Default value
	local xCoordinate = 0
	local targetY = 0
	local zCoordinate = 0
	local targetLocation = Vector3.new(xCoordinate,targetY,zCoordinate)
	for i = 1, #arguments do
		if typeof(arguments[i]) == "Vector3" then targetLocation = Vector3.new(arguments[i].X, arguments[i].Y, arguments[i].Z * drones.zDirection) end
		if i == 1 and typeof(arguments[i]) == "number" then targetDroneIndex = arguments[i] end
		if i == 2 and typeof(arguments[i]) == "number" then 
			xCoordinate = arguments[i] 
			targetLocation = Vector3.new(xCoordinate,targetY,zCoordinate)
		end
		if i == 3 and typeof(arguments[i]) == "number" then 
			targetY = arguments[i] 
			targetLocation = Vector3.new(xCoordinate,targetY,zCoordinate)
		end
		if i == 4 and typeof(arguments[i]) == "number" then 
			zCoordinate = arguments[i] 
			targetLocation = Vector3.new(xCoordinate,targetY,zCoordinate * drones.zDirection)
		end
	end
	--print("Setting up action for drone at: "..tostring(targetDroneIndex))
	drones.actions[targetDroneIndex] = {Action = "MoveTo", Position = targetLocation, Completed = false}
	--print("Position is going to be "..tostring(drones.actions[targetDroneIndex].Position))
	--print("droneActions has a length of: " .. tostring(#drones.actions))
	local MoveInfo = TweenInfo.new(1, Enum.EasingStyle.Sine,Enum.EasingDirection.Out, 0, false, 0)  --Parameters showin here include RepeatCount and Reversible 
	local MovePart = TweenService:Create(drones.collection[targetDroneIndex], MoveInfo, {Position = drones.actions[targetDroneIndex].Position})

	drones.actions[targetDroneIndex].MovePart = MovePart
	drones.actions[targetDroneIndex].MovePart:Play()

	MovePart.Completed:Connect(function()
		drones.actions[targetDroneIndex].Completed = true
	end)

	while drones.actions[targetDroneIndex].Completed == false do
		task.wait(0.1)
	end
	drones.actions[targetDroneIndex] = {Action = "None"}
	MovePart:Destroy()
	task.wait(0.1)
end
-- ------------------------------------------------------------------------

--[[
 roadSensor()
 This function will return the distance to the nearest road piece.
]]
function drones.roadSensor(...)
	local arguments = table.pack(...)
	local targetDroneIndex = 1  -- Default value
	for i = 1, #arguments do
		if i == 1 and typeof(arguments[i]) == "number" then targetDroneIndex = arguments[i] end
	end

	local Children = game.Workspace:GetChildren()

	local droneCoordinate = { X=drones.collection[targetDroneIndex].Position.x, Z=drones.collection[targetDroneIndex].Position.z }

	local lineWidth = 20  -- The width of the imaginary line
	local lineBlur = 20    -- Added to the width is a gradient.   This gradient is added to each side of the line
	-- For line following, the target value of 50% would be obtained at the 50% point in the lineBlur 
	for i = 1, #Children do
		if (Children[i].name == "StraightRoad" or Children[i].name == "CornerRoad") then
			local roadPosition = Children[i]:GetBoundingBox().Position
			local rx, ry, rz = Children[i]:GetPivot():ToOrientation()
			local dx, dy, dz = math.deg(rx), math.deg(ry), math.deg(rz)
			local roadOrientation = Vector3.new(dx, dy, dz)
			--print(roadPosition.X, "  ", roadPosition.Z, "  ", roadOrientation.Y )
			if math.abs(roadPosition.X - droneCoordinate.X) < halfBlock and math.abs(roadPosition.Z - droneCoordinate.Z) < halfBlock then
				-- We have found the road part that the drone is on
				-- Now determine the orientation of the road part
				if Children[i].name == "StraightRoad" then
					-- local point1 = { X=0, Z=0 }
					-- local point2 = { X=0, Z=0 }
					-- Is the current coordinates inside the object
					--print("Straight road y-orientation: " .. tostring(roadOrientation.Y))
					if roadOrientation.Y == 0 or roadOrientation.Y == 180 then
						-- point1 = { X=roadPosition.X - halfBlock, Z=roadPosition.Z }
						-- point2 = { X=roadPosition.X + halfBlock, Z=roadPosition.Z }
						-- Road part is moving along x axis
						-- Sensor value is related to the distance on Z between math.abs(Children[i].Position.Z - droneCoordinate.Z)
						if droneCoordinate.Z*drones.zDirection > (roadPosition.Z*drones.zDirection - lineWidth/2) and droneCoordinate.Z*drones.zDirection < (roadPosition.Z*drones.zDirection + lineWidth/2) then 
							print("H")
							return 0 
						end
						if droneCoordinate.Z*drones.zDirection > ((roadPosition.Z*drones.zDirection - lineWidth/2) - lineBlur) and droneCoordinate.Z*drones.zDirection <= (roadPosition.Z*drones.zDirection - lineWidth/2) then 
							print("I: " .. tostring(roadPosition.Z*drones.zDirection) .. "  " .. tostring(droneCoordinate.Z*drones.zDirection))
							return 100 * (droneCoordinate.Z*drones.zDirection - (roadPosition.Z*drones.zDirection - lineWidth/2)) / lineBlur
						end
						if droneCoordinate.Z*drones.zDirection > (roadPosition.Z*drones.zDirection + lineWidth/2) and droneCoordinate.Z*drones.zDirection <= (roadPosition.Z*drones.zDirection + lineWidth/2 + lineBlur) then 
							print("J")
							return 100 * (droneCoordinate.Z*drones.zDirection - (roadPosition.Z*drones.zDirection + lineWidth/2)) / lineBlur
						end
						return 100
						--return math.min( math.abs((roadPosition.Z - lineWidth/2) - droneCoordinate.Z), math.abs((roadPosition.Z + lineWidth/2) - droneCoordinate.Z))
					else
						-- point1 = { X=roadPosition.X, Z=roadPosition.Z - halfBlock }
						-- point2 = { X=roadPosition.X, Z=roadPosition.Z + halfBlock }
						-- Road part is moving along z axis
						-- Sensor value is related to the distance on X between math.abs(Children[i].Position.X - droneCoordinate.X)
						if droneCoordinate.X > (roadPosition.X - lineWidth/2) and droneCoordinate.X < (roadPosition.X + lineWidth/2) then return 0 end
						if droneCoordinate.X > ((roadPosition.X - lineWidth/2) - lineBlur) and droneCoordinate.X <= (roadPosition.X - lineWidth/2) then 
							return 100 * (droneCoordinate.X - (roadPosition.X - lineWidth/2)) / lineBlur
						end
						if droneCoordinate.X > (roadPosition.X + lineWidth/2) and droneCoordinate.X <= (roadPosition.X + lineWidth/2 + lineBlur) then 
							return 100 * (droneCoordinate.X - (roadPosition.X + lineWidth/2)) / lineBlur
						end
						return 100
						--return math.min( math.abs((roadPosition.X - lineWidth/2) - droneCoordinate.X), math.abs((roadPosition.X + lineWidth/2) - droneCoordinate.X))
					end
					--s.cube({X=point1.X, Z=point1.Z*-1, Y=2, size=4, color=Color3.new(1, 0.666667, 0)})
					--s.cube({X=point2.X, Z=point2.Z*-1, Y=2, size=4, color=Color3.new(0, 1, 1)})
				end
				if Children[i].name == "CornerRoad" then
					local cornerOrigin = { X=0, Z=0 }
					if math.abs(roadOrientation.Y) < 5 then
						cornerOrigin = { X=roadPosition.X + halfBlock, Z=roadPosition.Z - halfBlock }
					elseif math.abs(roadOrientation.Y - 90) < 5 or math.abs(roadOrientation.Y + 270) < 5 then
						cornerOrigin = { X=roadPosition.X - halfBlock, Z=roadPosition.Z - halfBlock }
					elseif math.abs(roadOrientation.Y - 180) < 5 or math.abs(roadOrientation.Y + 180) < 5 then
						cornerOrigin = { X=roadPosition.X - halfBlock, Z=roadPosition.Z + halfBlock }
					elseif math.abs(roadOrientation.Y - 270) < 5 or math.abs(roadOrientation.Y + 90) < 5 then
						cornerOrigin = { X=roadPosition.X + halfBlock, Z=roadPosition.Z + halfBlock }
					else
					end
					s.cube({X=cornerOrigin.X, Z=cornerOrigin.Z*-1, Y=2, size=4, color=Color3.new(0, 0.666667, 0)})
					local deltaX = cornerOrigin.X - droneCoordinate.X  -- Distance from the corner
					local deltaZ = cornerOrigin.Z - droneCoordinate.Z  -- Distance from the corner
					local droneDistanceFromCorner = math.sqrt(deltaX*deltaX + deltaZ*deltaZ)
					if droneDistanceFromCorner >= 32 - lineWidth/2 and droneDistanceFromCorner <= 32 + lineWidth/2 then
						return 0
					end
					if droneDistanceFromCorner < (32 - lineWidth/2) - lineBlur or droneDistanceFromCorner > 32 + lineWidth/2 + lineBlur then
						return 100
					end
					if droneDistanceFromCorner >= (32 - lineWidth/2) - lineBlur and droneDistanceFromCorner <= 32 then
						return 100 * ((32 - lineWidth/2) - droneDistanceFromCorner) / lineBlur
					end
					if droneDistanceFromCorner >= (32 + lineWidth/2) and droneDistanceFromCorner <= 32 + lineWidth/2 + lineBlur then
						return 100 * ( droneDistanceFromCorner - (32 + lineWidth/2)) / lineBlur
					end
					return 100
					-- Sensor value is the math.sqrt(deltaX*deltaX + deltaZ*deltaZ)
					--return math.abs(32 - math.sqrt(deltaX*deltaX + deltaZ*deltaZ))

				end
			else
				-- Off the grid.  Just go straight
			end
		end
	end
	return 100

end
-- ------------------------------------------------------------------------
function drones.new(...) 
	local arguments = table.pack(...)
	local x, y, z = 0, 0, 0
	local needToCreateYvalue = true
	local color = defaultColor
	local material = Enum.Material.Plastic
	local mainPart = Instance.new("Part")
	local enginePart = Instance.new("Part")
	local leftRotorPart = Instance.new("Part")
	local rightRotorPart = Instance.new("Part")
	local leftRearRotorPart = Instance.new("Part")
	local rightRearRotorPart = Instance.new("Part")
	local luminosityValue = 30
	local luminosityHue = Color3.new(1, 1, 1)
	local luminosityType = "PointLight"
	local luminosityRange = 20
	mainPart.Anchored = true
	mainPart.Shape = Enum.PartType.Block
	mainPart.TopSurface = Enum.SurfaceType.Smooth
	mainPart.BottomSurface = Enum.SurfaceType.Smooth
	mainPart.Transparency = 0
	mainPart.Reflectance = 0.6
	mainPart.Parent = workspace
	enginePart.Shape = Enum.PartType.Block
	enginePart.Material = Enum.Material.Glass
	enginePart.Transparency = 0.9
	enginePart.Parent = workspace
	enginePart.Anchored = true
	enginePart.Color = Color3.new(1,0,0)
	leftRotorPart.Anchored = true
	leftRotorPart.Shape = Enum.PartType.Cylinder
	leftRotorPart.TopSurface = Enum.SurfaceType.Smooth
	leftRotorPart.BottomSurface = Enum.SurfaceType.Smooth
	leftRotorPart.Transparency = 0.99
	leftRotorPart.Reflectance = 0.4
	leftRotorPart.Parent = workspace
	rightRotorPart.Anchored = true
	rightRotorPart.Shape = Enum.PartType.Cylinder
	rightRotorPart.TopSurface = Enum.SurfaceType.Smooth
	rightRotorPart.BottomSurface = Enum.SurfaceType.Smooth
	rightRotorPart.Transparency = 0.99
	rightRotorPart.Reflectance = 0.4
	rightRotorPart.Parent = workspace
	leftRearRotorPart.Anchored = true
	leftRearRotorPart.Shape = Enum.PartType.Cylinder
	leftRearRotorPart.TopSurface = Enum.SurfaceType.Smooth
	leftRearRotorPart.BottomSurface = Enum.SurfaceType.Smooth
	leftRearRotorPart.Transparency = 0.99
	leftRearRotorPart.Reflectance = 0.4
	leftRearRotorPart.Parent = workspace
	rightRearRotorPart.Anchored = true
	rightRearRotorPart.Shape = Enum.PartType.Cylinder
	rightRearRotorPart.TopSurface = Enum.SurfaceType.Smooth
	rightRearRotorPart.BottomSurface = Enum.SurfaceType.Smooth
	rightRearRotorPart.Transparency = 0.99
	rightRearRotorPart.Reflectance = 0.4
	rightRearRotorPart.Parent = workspace

	local numNumericArguments = 0
	for i = 1, #arguments do
		if typeof(arguments[i]) == "number" then numNumericArguments += 1 end
	end
	local workingNumber = 0
	for i = 1, #arguments do
		if typeof(arguments[i]) == "table" then
			for key, value in pairs(arguments[i]) do
				--print(key)
				local lkey = string.lower(key)
				if lkey == "anchored" then mainPart.Anchored = value end
				if lkey == "x" then x = value end
				if lkey == "y" then	y,needToCreateYvalue = value, false	end
				if lkey == "z" then z = value end
				if lkey == "position" and typeof(value) == "Vector3" then x,y,z,needToCreateYvalue=value.X,value.Y,value.Z,false end
				if lkey == "transparency" then mainPart.Transparency = value end
				if lkey == "opacity" then mainPart.Transparency = 1 - value end
				if lkey == "reflectance" then mainPart.Reflectance = value end
				if lkey == "rotateby" then mainPart.Orientation = value end
				if lkey == "material" then material = value end
				if lkey == "luminosityvalue" or lkey == "luminosity" then luminosityValue = value end
				if lkey == "luminosityrange" then luminosityRange = value end
				if lkey == "luminosityhue" then 
					if typeof(value) == "Color3" then luminosityHue = value end
					if typeof(value) == "string" then
						local luminosityColor = string.lower(value)
						local red = colorName[luminosityColor]["DEC"][1]/255    --rescale from 0-255 to 0-1
						local green = colorName[luminosityColor]["DEC"][2]/255  --rescale from 0-255 to 0-1
						local blue = colorName[luminosityColor]["DEC"][3]/255   --rescale from 0-255 to 0-1
						luminosityHue = Color3.new(red, green, blue)
					end
				end
				if lkey == "luminositytype" then luminosityType = value	end
				if lkey == "color" then
					if typeof(value) == "Color3" then color = value end
					if typeof(value) == "string" then
						color = string.lower(value)
						local red = colorName[color]["DEC"][1]/255    --rescale from 0-255 to 0-1
						local green = colorName[color]["DEC"][2]/255  --rescale from 0-255 to 0-1
						local blue = colorName[color]["DEC"][3]/255   --rescale from 0-255 to 0-1
						color = Color3.new(red, green, blue)
					end
				end
			end
			for key, value in pairs(arguments[i]) do  -- Check to see if there is any luminosity to this object
				local lkey = string.lower(key)
				if lkey == "luminosity" or lkey == "luminosityvalue" or lkey == "luminosityhue" or lkey == "luminosityrange" or lkey == "luminositytype" then -- If there is luminosity, then install the surface light
					--print(`Creating luminosity: {luminosityType} {luminosityHue} {luminosityValue}`)
					local lightOfPart = Instance.new(luminosityType)
					lightOfPart.Color = luminosityHue
					lightOfPart.Brightness = luminosityValue
					lightOfPart.Range = luminosityRange
					lightOfPart.Parent = mainPart
				end
			end
		end
		if typeof(arguments[i]) == "Color3" then 
			color = arguments[i] 
		end
		if typeof(arguments[i]) == "string" then
			local color = string.lower(arguments[i])
			local red = colorName[color]["DEC"][1]/255    --rescale from 0-255 to 0-1
			local green = colorName[color]["DEC"][2]/255  --rescale from 0-255 to 0-1
			local blue = colorName[color]["DEC"][3]/255   --rescale from 0-255 to 0-1
			color = Color3.new(red, green, blue)
		end
		if typeof(arguments[i]) == "EnumItem" then mainPart.Material = arguments[i] end
		if typeof(arguments[i]) == "number" then
			if numNumericArguments > 1 then
				workingNumber += 1
				if workingNumber == 1 then x = arguments[i] end
				if workingNumber == 2 then y,needToCreateYvalue = arguments[i],false end
				if workingNumber == 3 then z = arguments[i] end
			end
		end
	end
	mainPart.Color = color
	mainPart.Size = Vector3.new(0.8, 0.2, 3)  -- fixed size of the drone
	mainPart.Position = Vector3.new(x,y,z+1)
	enginePart.Size = Vector3.new(0.4, 0.4, 0.03)  -- fixed size of the drone
	enginePart.Position = Vector3.new(x, y, z+0.2)

	leftRotorPart.Size = Vector3.new(0.02,1.5,1.5) -- must stay thickness, size, size
	leftRotorPart.Position = Vector3.new(x-1.2,y,z)
	leftRotorPart.Orientation = Vector3.new(0,0,90)
	leftRotorPart.Material = Enum.Material.Glass
	leftRotorPart.Color = Color3.new(1, 0, 0.498039)

	rightRotorPart.Size = Vector3.new(0.02,1.5,1.5) -- must stay thickness, size, size
	rightRotorPart.Position = Vector3.new(x+1.2,y,z)
	rightRotorPart.Orientation = Vector3.new(0,0,90)
	rightRotorPart.Material = Enum.Material.Glass
	rightRotorPart.Color = Color3.new(1, 0, 0.498039)


	leftRearRotorPart.Size = Vector3.new(0.02,1.5,1.5) -- must stay thickness, size, size
	leftRearRotorPart.Position = Vector3.new(x-1.2,y,z+2)
	leftRearRotorPart.Orientation = Vector3.new(0,0,90)
	leftRearRotorPart.Material = Enum.Material.Glass
	leftRearRotorPart.Color = Color3.new(1, 0, 0.498039)

	rightRearRotorPart.Size = Vector3.new(0.02,1.5,1.5) -- must stay thickness, size, size
	rightRearRotorPart.Position = Vector3.new(x+1.2,y,z+2)
	rightRearRotorPart.Orientation = Vector3.new(0,0,90)
	rightRearRotorPart.Material = Enum.Material.Glass
	rightRearRotorPart.Color = Color3.new(1, 0, 0.498039)

	local otherParts = { enginePart, leftRotorPart, rightRotorPart, leftRearRotorPart, rightRearRotorPart }

	local success, newDrone = pcall(function()
		return mainPart:UnionAsync(otherParts)
	end)
	-- If operation succeeds, position it at the same location and parent it to the workspace
	if success and newDrone then
		newDrone.Position = mainPart.Position
		newDrone.Parent = workspace
		newDrone:SetAttribute("gyroSensor", 0)      -- Keeps track of the degrees rotated
		local currentOrientation = newDrone:GetPivot()
		local cfa = newDrone.CFrame.LookVector
		local degreeOffsetFromZero = (math.atan2(cfa.x, cfa.z)*180/math.pi)+270
		print("Initial degree offset from zero: "..tostring(degreeOffsetFromZero))
		newDrone:SetAttribute("gyroSensorOffsetFromTrueZero", degreeOffsetFromZero)
		newDrone:SetAttribute("lastVectorValue", degreeOffsetFromZero)
		newDrone:SetAttribute("encoderValue", 0)    -- Keeps track of the distances travelled
		newDrone:SetAttribute("lastPositionX", newDrone.Position.x)   -- Keeps track of the distances travelled
		newDrone:SetAttribute("lastPositionZ", newDrone.Position.z)   -- Keeps track of the distances travelled
	end
	-- Destroy original parts which remain intact after operation
	mainPart:Destroy()
	for i = 1, #otherParts do
		otherParts[i]:Destroy()
	end

	return newDrone
	--return completeDrone

	--[[]]

end

function objectWrapper(Instance)


end
-- ---------------------------------------------------------------------------------------------------------------------------------
-- Compass Functions
--
local showCompass = true                                                              -- This variable is local to this module
function drones.showingCompass(...)
	local arguments = table.pack(...)												   -- If any arguments were passed, put them into an array
	if #arguments == 0 then return showCompass end                                     -- If no argument is passed, then just return the current value.  Similar to a .get() method
	print("In ShowingCompass " .. tostring(#arguments) .. "  " )
	if typeof(arguments[1]) == "boolean" then                                          -- If there is an argument and it is boolean, then 
		showCompass = arguments[1]                                                     --    set the current value to the boolean that was passed
		local Children = game.Workspace:GetChildren()                                  -- While you're at it, let's get all the child elements and set their Transparency property
		if showCompass then                                                            -- If you're supposed to show the compass, then Search the workspace for Compass models and turn them visible 
			for i = 1, #Children do                                                    -- For each child in "workspace"
				if Children[i].name == "Compass" then                                  
					toggleTransparency(Children[i], 0)                                 -- A transparency of zero means they are visible
				end  
			end
		else                                                                           -- Search the workspace for Compass models and turn them transparent
			for i = 1, #Children do
				if Children[i].name == "Compass" then
					toggleTransparency(Children[i], 1)                                 -- A transparency of one means invisible
				end  
			end	

		end
	end
	return false
end
function toggleTransparency(model, transparency)
	for i, part in pairs (model:GetChildren()) do                                     -- Loop through each part in this model 
		if hasProperty(part,"Transparency") then part.Transparency = transparency end -- only set the transparency if there is a property called "Transparency".  This is similar to JavaScript's hasOwnProerty()
		if part:GetChildren() then toggleTransparency(part, transparency) end         -- Uses recursion if there are children in this part
	end
end
function hasProperty(object, propertyName)                                            -- Does this part have a specific property
	local success, _ = pcall(function()                                               -- create a function to return true or false depending if the propertyName exists
		object[propertyName] = object[propertyName]
	end)
	return success
end
function drones.newCompass(...)
	local compassGroup = Instance.new("Model")
	compassGroup.Name = "Compass"
	local compassLabelsGroup = Instance.new("Model")
	for j = 1, 36 do
		local xCoordinate = 20 * math.cos((j*10) * math.pi/180)
		local zCoordinate = 20 * math.sin((j*10) * math.pi/180)
		local hashMark = Instance.new("Part")
		hashMark.Size = Vector3.new(4,.2,.3)
		hashMark.Position = Vector3.new(xCoordinate, 0.1, zCoordinate)
		hashMark.Rotation =  Vector3.new(0, j*-10, 0)
		hashMark.Anchored = true
		hashMark.CanCollide = false
		hashMark.Color = Color3.new(0, 0, 0)
		hashMark.Name = "Hash" .. tostring(j)
		hashMark:SetAttribute("xOffset", xCoordinate)
		hashMark:SetAttribute("zOffset", zCoordinate)
		hashMark.Parent = compassGroup
	end
	for j = 0, 359, 30 do
		local xCoordinate = 20 * math.cos((j) * math.pi/180)
		local zCoordinate = 20 * math.sin((j) * math.pi/180)
		local valLabel = s.drawText({ x=xCoordinate*-0.8, y=2, z=zCoordinate*0.8, width=1.8, height=1, text=tostring((j+180)%360), fontSize=20, font=Enum.Font.Code, Opacity=0.9, color="red", backgroundColor=Color3.new(1, 1, 1), RotateBy=Vector3.new(0, j-90, 0), textRotate=0 })
		valLabel.Parent = compassLabelsGroup			
	end
	compassLabelsGroup.Name = "Compass"
	compassLabelsGroup.Parent = workspace
	local aCompass = s.disc( {radius=50, color="white", x=0, y=0, z=0, RotateBy=Vector3.new(0, 0, 90)} )
	aCompass.Parent = compassGroup
	aCompass:SetAttribute("numHashes", 36)
	compassGroup.Parent = workspace
	compassGroup:PivotTo(compassGroup:GetPivot() * CFrame.Angles( math.rad(0), math.rad(0), math.rad(0)))
	toggleTransparency(compassGroup, 1)
	toggleTransparency(compassLabelsGroup, 1)
	drones.showCompass = false
	local retVal = {compassGroup, compassLabelsGroup}
	return retVal  -- You are returning a Model called Compass
end
function drones.moveCompassTo(...)
	local arguments = table.pack(...)
	local x, y, z = 0, 0, 0
	local locationValue = 0
	local mainPart = arguments[1]
	if #arguments == 2 then
		mainPart = arguments[1]
		locationValue = arguments[1]
	elseif #arguments == 4 then locationValue = Vector3.new(arguments[2],arguments[3],arguments[4])
	else
	end
	if typeof(locationValue) == "Vector3" then
		mainPart.Position = locationValue
	else
		print("Error in the moveTo method.  You need to pass a Vector3.  You passed a: "..typeof(locationValue))
	end
	return mainPart
end



return drones