--			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)
		if type(Velocity) == "number" then
			Velocity = Direction.Unit * Velocity
		end
		
		local Distance = Direction.Magnitude
		local NormalizedDir = Direction / Distance
		
		local LastPoint = Origin
		local DistanceTravelled = 0
		while DistanceTravelled <= Distance do
			local Delta = RunService.Heartbeat:Wait()
			local UpgradedDir = (NormalizedDir + Velocity).Unit
			local Start = Origin + (UpgradedDir.Unit * DistanceTravelled)
			local RayDir = UpgradedDir * Velocity.Magnitude * 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 cosmetic bullet that got 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, BulletAcceleration)
		--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")
		
		spawn(function ()
			if UsingPhysics() or BulletAcceleration then
				MainCastFire(Origin, Direction, Velocity, Cast, CosmeticBulletObject, nil, BulletAcceleration)
			else
				MainCastFireNoPhys(Origin, Direction, Velocity, Cast, CosmeticBulletObject)
			end
		end)
	end
	
	--Identical to above, but with a whitelist.
	function Caster:FireWithWhitelist(Origin, Direction, Velocity, Whitelist, CosmeticBulletObject, BulletAcceleration)
		--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")
		spawn(function ()
			if UsingPhysics() or BulletAcceleration then
				MainCastFire(Origin, Direction, Velocity, CastWhitelist, CosmeticBulletObject, Whitelist, BulletAcceleration)
			else
				MainCastFireNoPhys(Origin, Direction, Velocity, CastWhitelist, CosmeticBulletObject, Whitelist)
			end
		end)
	end
	
	--Identical to above, but with a blacklist.
	function Caster:FireWithBlacklist(Origin, Direction, Velocity, Blacklist, CosmeticBulletObject, BulletAcceleration)
		--Note to unaware 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")
		spawn(function ()
			if UsingPhysics() or BulletAcceleration then
				MainCastFire(Origin, Direction, Velocity, CastBlacklist, CosmeticBulletObject, Blacklist, BulletAcceleration)
			else
				MainCastFireNoPhys(Origin, Direction, Velocity, CastBlacklist, CosmeticBulletObject, Blacklist)
			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 that 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 == "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
			elseif Index == "RayHit" or Index == "LengthChanged" or Index == "HasPhysics" then
				error("Can't set value", 0)
			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