--			local EndToCurrent_Distance = (At - Point).Magnitude
--			local Change = (LastToCurrent_Distance - EndToCurrent_Distance)

			
			LengthChanged:Fire(Origin, LastPoint, RayDir.Unit, LastToCurrent_Distance, CosmeticBulletObject)
			LastPoint = At
			if Hit then
				--V5: WAIT! Test if the cosmetic bullet was hit!
				if Hit ~= CosmeticBulletObject then
					--Hit something, stop the function and fire the hit event.
					RayHit:Fire(Hit, Point, Normal, Material, CosmeticBulletObject)
					return
				end
				--If we make it here, then the bullet isn't nil, and it was the hit.(The above code exits the function)
				--This will ignore the bullet. For this function, no changes need to be made.
			end
			DistanceTravelled = DistanceTravelled + LastToCurrent_Distance
		end
		--If we make it here, then we have exceeded the maximum distance.
		--As part of Ver. 4, the hit function will fire here.
		--V5: Changed below to return all nil values aside from the point
		RayHit:Fire(nil, LastPoint, nil, nil, CosmeticBulletObject)
	end
	
	--Fire without physics
	local function MainCastFireNoPhys(Origin, Direction, Velocity, Function, CosmeticBulletObject, List)
		local Distance = Direction.Magnitude
		local NormalizedDir = Direction / Distance
		local Direction = NormalizedDir * Distance

		local LastPoint = Origin
		local DistanceTravelled = 0
		while DistanceTravelled <= Distance do
			local Delta = RunService.Heartbeat:Wait() 
			local Start = Origin + (NormalizedDir * DistanceTravelled)
			local RayDir = NormalizedDir * Velocity * Delta
			local Hit, Point, Normal, Material = Function(Start, RayDir, List)
			
			local ExtraDistance = (Start - Point).Magnitude
			local ModifiedDistance = DistanceTravelled + ExtraDistance
			
			--Note to self: ExtraDistance will be identical to RayDir.Magnitude unless something is hit.	
			LengthChanged:Fire(Origin, LastPoint, RayDir.Unit, ExtraDistance, CosmeticBulletObject)
			LastPoint = Point
			if Hit then
				--V5: WAIT! Test if the cosmetic bullet was hit!
				if Hit ~= CosmeticBulletObject then
					--Hit something, stop the function and fire the hit event.
					RayHit:Fire(Hit, Point, Normal, Material, CosmeticBulletObject)
					return
				end
				--If we make it here, then the bullet isn't nil, and it was the hit.(The above code exits the function)
				--In this case, we will kindly ignore the bullet.
				--We will also set ExtraDistance to RayDir.Magnitude (See above - These two values are identical if nothing is hit, so we need to force that behavior)
				ExtraDistance = RayDir.Magnitude
			end
			DistanceTravelled = DistanceTravelled + ExtraDistance
		end
		--V5: Changed below to return all nil values aside from the point
		RayHit:Fire(nil, LastPoint, nil, nil, CosmeticBulletObject)
	end
	
	--Fire a ray from origin -> direction at the specified velocity.
	function Caster:Fire(Origin, Direction, Velocity, CosmeticBulletObject, NoThread)
		--Note to scripters: 'self' is a variable lua creates when a method like ^ is run. It's an alias to the table that the function is part of (in this case, Caster)
		assert(Caster == self, "Expected ':' not '.' calling member function Fire")
		
		if NoThread then
			if UsingPhysics() then
				MainCastFire(Origin, Direction, Velocity, Cast, CosmeticBulletObject)
			else
				MainCastFireNoPhys(Origin, Direction, Velocity, Cast, CosmeticBulletObject)
			end
		else
			spawn(function ()
				if UsingPhysics() then
					MainCastFire(Origin, Direction, Velocity, Cast, CosmeticBulletObject)
				else
					MainCastFireNoPhys(Origin, Direction, Velocity, Cast, CosmeticBulletObject)
				end
			end)
		end
	end
	
	--Identical to above, but with a whitelist.
	function Caster:FireWithWhitelist(Origin, Direction, Velocity, Whitelist, CosmeticBulletObject, NoThread)
		--Note to scripters: 'self' is a variable lua creates when a method like ^ is run. It's an alias to the table that the function is part of (in this case, Caster)
		assert(Caster == self, "Expected ':' not '.' calling member function FireWithWhitelist")
		if NoThread then
			if UsingPhysics() then
				MainCastFire(Origin, Direction, Velocity, CastWhitelist, CosmeticBulletObject, Whitelist)
			else
				MainCastFireNoPhys(Origin, Direction, Velocity, CastWhitelist, CosmeticBulletObject, Whitelist)
			end
		else
			spawn(function ()
				if UsingPhysics() then
					MainCastFire(Origin, Direction, Velocity, CastWhitelist, CosmeticBulletObject, Whitelist)
				else
					MainCastFireNoPhys(Origin, Direction, Velocity, CastWhitelist, CosmeticBulletObject, Whitelist)
				end
			end)
		end
	end
	
	--Identical to above, but with a blacklist.
	function Caster:FireWithBlacklist(Origin, Direction, Velocity, Blacklist, CosmeticBulletObject, NoThread)
		--Note to scripters: 'self' is a variable lua creates when a method like ^ is run. It's an alias to the table that the function is part of (in this case, Caster)
		assert(Caster == self, "Expected ':' not '.' calling member function FireWithBlacklist")
		if NoThread then
			if UsingPhysics() then
				MainCastFire(Origin, Direction, Velocity, CastBlacklist, CosmeticBulletObject, Blacklist)
			else
				MainCastFireNoPhys(Origin, Direction, Velocity, CastBlacklist, CosmeticBulletObject, Blacklist)
			end
		else
			spawn(function ()
				if UsingPhysics() then
					MainCastFire(Origin, Direction, Velocity, CastBlacklist, CosmeticBulletObject, Blacklist)
				else
					MainCastFireNoPhys(Origin, Direction, Velocity, CastBlacklist, CosmeticBulletObject, Blacklist)
				end
			end)
		end
	end
	
	
	--Indexing stuff here.
	--For those scripters new to Metatables, they allow you to fake information in tables by controlling how it works.
	--This function will be run when you try to index anything of the fastcaster.
	--If I were to do Caster["CoolIndex"], this function would fire, table being Caster, and Index being "CoolIndex".
	--This means that I can return my own value, even if "CoolIndex" isn't valid.
	--Neat, huh?
	CMeta.__index = function (Table, Index)
		if Table == Caster then
			if Index == "IgnoreDescendantsInstance" then
				return IgnoreDescendantsInstance
			elseif Index == "RayHit" then
				return RayHit
			elseif Index == "LengthChanged" then
				return LengthChanged
			elseif Index == "Gravity" then
				return Gravity
			elseif Index == "ExtraForce" then
				return ExtraForce
			elseif Index == "HasPhysics" then
				return UsingPhysics()
			end
		end
	end
	
	local IgnoreMode = false -- This is used so I can do some tricks below 
	--Same thing as above, just tha this fires writing to the table (e.g. Caster["CoolIndex"] = "CoolValue")
	CMeta.__newindex = function (Table, Index, Value)
		if IgnoreMode then return end
		if Table == Caster then
			if Index == "IgnoreDescendantsInstance" then
				assert(Value == nil or typeof(Value) == "Instance", "Bad argument \"" .. Index .. "\" (Instance expected, got " .. typeof(Value) .. ")")
				IgnoreDescendantsInstance = Value
			elseif Index == "RayHit" or Index == "LengthChanged" or Index == "HasPhysics" then
				error("Can't set value", 0)
			elseif Index == "Gravity" then
				assert(typeof(Value) == "number", "Bad argument \"" .. Index .. "\" (number expected, got " .. typeof(Value) .. ")")
				Gravity = Value			
			elseif Index == "ExtraForce" then
				assert(typeof(Value) == "Vector3", "Bad argument \"" .. Index .. "\" (Vector3 expected, got " .. typeof(Value) .. ")")
				ExtraForce = Value
			end
		end
	end

	--TRICK: I'm going to make dummy values for the properties and events.
	--Roblox will show these in intellesence (the thing that suggests what to type in as you go)
	IgnoreMode = true
	Caster.RayHit = RayHit
	Caster.LengthChanged = LengthChanged
	Caster.IgnoreDescendantsInstance = IgnoreDescendantsInstance
	Caster.Gravity = Gravity
	Caster.ExtraForce = ExtraForce
	Caster.HasPhysics = UsingPhysics()
	IgnoreMode = false
	--Better yet, while these values are just in the open, they will still be managed by the metatables.
	
	CMeta.__metatable = "FastCaster"
	
	return Caster
end

return FastCast
