-- Update. Called every frame after the camera movement step

function Invisicam:Update()
	-- Make sure we still have a Torso
	if not Torso then
		local humanoid = Character:FindFirstChildOfClass("Humanoid")
		if humanoid and humanoid.Torso then
			Torso = humanoid.Torso
		else
			-- Not set up with Humanoid? Try and see if there's one in the Character at all:
			Torso = Character:FindFirstChild("HumanoidRootPart")
			if not Torso then
				-- Bail out, since we're relying on Torso existing
				return
			end
		end
		local ancestryChangedConn;
		ancestryChangedConn = Torso.AncestryChanged:connect(function(child, parent)
			if child == Torso and not parent then 
				Torso = nil
				if ancestryChangedConn and ancestryChangedConn.Connected then
					ancestryChangedConn:Disconnect()
					ancestryChangedConn = nil
				end
			end
		end)
	end

	-- Make a list of world points to raycast to
	local castPoints = {}
	BehaviorFunction(castPoints)
	
	-- Cast to get a list of objects between the camera and the cast points
	local currentHits = {}
	local ignoreList = {Character}
	local function add(hit)
		currentHits[hit] = true
		if not SavedHits[hit] then
			SavedHits[hit] = hit.LocalTransparencyModifier
		end
	end

	local hitParts = Camera:GetPartsObscuringTarget(castPoints, ignoreList)
	for i = 1, #hitParts do
		local hitPart = hitParts[i]
		add(hitPart)
		for _, child in pairs(hitPart:GetChildren()) do
			if child:IsA('Decal') or child:IsA('Texture') then
				add(child)
			end
		end
	end
	
	-- Fade out objects that are in the way, restore those that aren't anymore
	for hit, originalFade in pairs(SavedHits) do
		local currentFade = hit.LocalTransparencyModifier
		if currentHits[hit] then -- Fade
			if currentFade < FADE_TARGET then
				hit.LocalTransparencyModifier = math_min(currentFade + FADE_RATE, FADE_TARGET)
			end
		else -- Restore
			if currentFade > originalFade then
				hit.LocalTransparencyModifier = math_max(originalFade, currentFade - FADE_RATE)
			else
				SavedHits[hit] = nil
			end
		end
	end
end

function Invisicam:SetMode(newMode)
	AssertTypes(newMode, 'number')
	for modeName, modeNum in pairs(MODE) do
		if modeNum == newMode then
			Mode = newMode
			BehaviorFunction = Behaviors[Mode]
			return
		end
	end
	error("Invalid mode number")
end

function Invisicam:SetCustomBehavior(func)
	AssertTypes(func, 'function')
	Behaviors[MODE.CUSTOM] = func
	if Mode == MODE.CUSTOM then
		BehaviorFunction = func
	end
end
