function setHumanoidControl(a)local V=localPlayer.Character if V and V.Parent then local D=V:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")if not a then D.WalkSpeed=0 if D.UseJumpPower then D.JumpPower=0 else D.JumpHeight=0 end D.AutoRotate=false else D.WalkSpeed=StarterPlayer.CharacterWalkSpeed if D.UseJumpPower then D.JumpPower=StarterPlayer.CharacterJumpPower else D.JumpHeight=StarterPlayer.CharacterJumpHeight end D.AutoRotate=true end end if UserInputService.TouchEnabled then local V=localPlayer:FindFirstChild("\080\108\097\121\101\114\071\117\105")if V then local D=V:FindFirstChild("\084\111\117\099\104\071\117\105")if D then local V=D:FindFirstChild("\084\111\117\099\104\067\111\110\116\114\111\108\070\114\097\109\101")if V then local W=V:FindFirstChild("\074\117\109\112\066\117\116\116\111\110")if W then(TweenService:Create(D.TouchControlFrame.JumpButton,TweenInfo.new(.5),{ImageTransparency=a and 0 or 1})):Play()end end end end end end function setCameraCF(a)local V=math.rad(camera.FieldOfView/2)local D=a.Size.Y/2 local W=D/math.tan(V)local Q=camera.ViewportSize.X/camera.ViewportSize.Y local F=a.Size.X/a.Size.Y if Q<F then W=W/(Q/F)end local O=a.CFrame*CFrame.new(0,0,-(W+a.Size.Z/2))return CFrame.new(O.Position,a.Position)end function getCharacterPart()local a=localPlayer.Character if a and(a.Parent and a:IsA("\077\111\100\101\108"))then return a.PrimaryPart end end function updateButtonVisuals()if button and button.Parent then if fullscreenModule.FocusedScreen==buttonTargetScreen then button.Image=ZOOM_OUT_ICON button.GamepadPrompt.Image=BACKOUT_GAMEPAD_BUTTON_ICON else button.Image=ZOOM_IN_ICON button.GamepadPrompt.Image=FULLSCREEN_GAMEPAD_BUTTON_ICON end end end function fullscreenModule.FocusScreen(a,V)if a and a==localPlayer.Character then a=nil end if fullscreenModule.FocusedScreen==a then return end fullscreenModule.FocusedScreen=a transitionCount+=1 local D=transitionCount updateButtonVisuals()local W=nil local Q=nil if a then if V then setHumanoidControl(false)end if not characterCamCF then local a=getCharacterPart()if a then characterCamCF=(CFrame.new(a.Position)):ToObjectSpace(camera.CFrame)characterCamCFIsRelative=true else characterCamCF=camera.CFrame characterCamCFIsRelative=false end end camera.CameraType=Enum.CameraType.Scriptable W=setCameraCF(a)else W=characterCamCF if characterCamCFIsRelative then Q=getCharacterPart()end end if W then local a=Instance.new("\067\070\114\097\109\101\086\097\108\117\101")if Q and Q.Parent then a.Value=CFrame.new(Q.Position*-1)*camera.CFrame else a.Value=camera.CFrame end local V=TweenService:Create(a,TweenInfo.new(1,Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),{Value=W})local F=a.Changed:connect(function()if transitionCount==D then camera.CameraType=Enum.CameraType.Scriptable if Q and Q.Parent then camera.CFrame=CFrame.new(Q.Position)*a.Value else camera.CFrame=a.Value end end end)V:Play()V.Completed:Wait()F:Disconnect()F=nil a=nil end if transitionCount==D then if a then if lockCameraConnection then lockCameraConnection:Disconnect()lockCameraConnection=nil end lockCameraConnection=RunService.RenderStepped:Connect(function()if transitionCount==D then camera.CFrame=setCameraCF(a)end end)else camera.CameraType=Enum.CameraType.Custom characterCamCF=nil characterCamCFIsRelative=false local a=localPlayer.Character if a and a.Parent then local V=a:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")if V then camera.CameraSubject=V end end if V then setHumanoidControl(true)end end end end function toggleFullscreen()if button then if fullscreenModule.FocusedScreen~=buttonTargetScreen then fullscreenModule.FocusScreen(buttonTargetScreen)else fullscreenModule.FocusScreen()end end end function backoutFullscreen()if button and fullscreenModule.FocusedScreen==buttonTargetScreen then fullscreenModule.FocusScreen()end end function updateGamepadPromptVisibility()if button and button.Parent then local a=button:FindFirstChild("\071\097\109\101\112\097\100\080\114\111\109\112\116")if a then if UserInputService.GamepadEnabled then button.GamepadPrompt.Visible=false button.Active=false else button.GamepadPrompt.Visible=true button.Active=true end end end end UserInputService.GamepadConnected:connect(updateGamepadPromptVisibility)UserInputService.GamepadDisconnected:connect(updateGamepadPromptVisibility)function fullscreenModule.RemoveButton()if buttonConnection then buttonConnection:Disconnect()buttonConnection=nil end if gamepadButtonConnection then gamepadButtonConnection:Disconnect()gamepadButtonConnection=nil end if button and button.Parent then button:Destroy()end if buttonGui and buttonGui.Parent then buttonGui:Destroy()end button=nil buttonGui=nil buttonTargetScreen=nil end function fullscreenModule.CreateButtonToFocusScreen(a)local V=localPlayer:FindFirstChild("\080\108\097\121\101\114\071\117\105")if V then if button or buttonGui then fullscreenModule.RemoveButton()end buttonTargetScreen=a buttonGui=buttonGuiTemplate:clone()button=buttonGui.Button buttonConnection=button.Activated:connect(toggleFullscreen)gamepadButtonConnection=UserInputService.InputBegan:Connect(function(a)if a.UserInputType==Enum.UserInputType.Gamepad1 then if a.KeyCode==FULLSCREEN_GAMEPAD_BUTTON then toggleFullscreen()elseif a.KeyCode==BACKOUT_GAMEPAD_BUTTON then backoutFullscreen()end end end)updateButtonVisuals()buttonGui.Parent=V end end return fullscreenModule
--[[feature ideas:
	- setting to auto-focus screen when character is close to a screen
]]

function setHumanoidControl(hasControl)
	local character = localPlayer.Character
	if character and character.Parent then
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		if not hasControl then
			humanoid.WalkSpeed = 0
			if humanoid.UseJumpPower then
				humanoid.JumpPower = 0
			else
				humanoid.JumpHeight = 0
			end
			humanoid.AutoRotate = false
		else
			humanoid.WalkSpeed = StarterPlayer.CharacterWalkSpeed
			if humanoid.UseJumpPower then
				humanoid.JumpPower = StarterPlayer.CharacterJumpPower
			else
				humanoid.JumpHeight = StarterPlayer.CharacterJumpHeight
			end
			humanoid.AutoRotate = true
		end
	end

	-- Find the jump button and adjust it's visibility
	if UserInputService.TouchEnabled then
		local playerGui = localPlayer:FindFirstChild("PlayerGui")
		if playerGui then
			local touchGui = playerGui:FindFirstChild("TouchGui")
			if touchGui then
				local controlFrame = touchGui:FindFirstChild("TouchControlFrame")
				if controlFrame then
					local jumpButton = controlFrame:FindFirstChild("JumpButton")
					if jumpButton then
						TweenService:Create(
							touchGui.TouchControlFrame.JumpButton,
							TweenInfo.new(0.5),
							{ ImageTransparency = hasControl and 0 or 1 }
						):Play()
					end
				end
			end
		end
	end
end

function setCameraCF(screenPart)
	local halfFOV = math.rad(camera.FieldOfView / 2)
	local halfScreenHeight = screenPart.Size.Y / 2
	local distanceOffset = halfScreenHeight / math.tan(halfFOV)
	local cameraAspectRatio = (camera.ViewportSize.X / camera.ViewportSize.Y)
	local screenAspectRatio = screenPart.Size.X / screenPart.Size.Y
	if cameraAspectRatio < screenAspectRatio then
		distanceOffset = distanceOffset / (cameraAspectRatio / screenAspectRatio)
	end
	local targetCF = screenPart.CFrame * CFrame.new(0, 0, -(distanceOffset + screenPart.Size.Z / 2))

	return CFrame.new(targetCF.Position, screenPart.Position)
end

function getCharacterPart()
	local character = localPlayer.Character
	if character and character.Parent and character:IsA("Model") then
		return character.PrimaryPart
	end
end

function updateButtonVisuals()
	if button and button.Parent then
		if fullscreenModule.FocusedScreen == buttonTargetScreen then
			button.Image = ZOOM_OUT_ICON
			button.GamepadPrompt.Image = BACKOUT_GAMEPAD_BUTTON_ICON
		else
			button.Image = ZOOM_IN_ICON
			button.GamepadPrompt.Image = FULLSCREEN_GAMEPAD_BUTTON_ICON
		end
	end
end

function fullscreenModule.FocusScreen(screenPart, manageLockingCharacterControl)
	-- If screenPart is nil or the character, the camera will return to the character
	if screenPart and screenPart == localPlayer.Character then
		screenPart = nil
	end

	if fullscreenModule.FocusedScreen == screenPart then
		return
	end
	fullscreenModule.FocusedScreen = screenPart

	transitionCount += 1
	local thisTransitionCount = transitionCount

	updateButtonVisuals()

	-- Tween camera into position
	local targetCF = nil
	local camTweenRelativeTargetPart = nil
	if screenPart then
		if manageLockingCharacterControl then
			setHumanoidControl(false)
		end

		-- If focusing a screen, and no currently saved relative info for the character, then capture relative character info.
		if not characterCamCF then
			local cameraSubjectPart = getCharacterPart()
			if cameraSubjectPart then
				characterCamCF = CFrame.new(cameraSubjectPart.Position):ToObjectSpace(camera.CFrame)
				characterCamCFIsRelative = true
			else
				characterCamCF = camera.CFrame
				characterCamCFIsRelative = false
			end
		end

		camera.CameraType = Enum.CameraType.Scriptable
		targetCF = setCameraCF(screenPart)
	else
		targetCF = characterCamCF
		if characterCamCFIsRelative then
			camTweenRelativeTargetPart = getCharacterPart()
		end
	end

	if targetCF then
		-- Tweening an object so that we can apply the tweened cframe overtop a camera subject
		local cfObject = Instance.new("CFrameValue")
		if camTweenRelativeTargetPart and camTweenRelativeTargetPart.Parent then
			cfObject.Value = CFrame.new(camTweenRelativeTargetPart.Position * -1) * camera.CFrame
		else
			cfObject.Value = camera.CFrame
		end
		local cameraTween = TweenService:Create(
			cfObject,
			TweenInfo.new(1, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut),
			{ Value = targetCF }
		)
		local cfChangedConn = cfObject.Changed:connect(function()
			if transitionCount == thisTransitionCount then
				camera.CameraType = Enum.CameraType.Scriptable
				if camTweenRelativeTargetPart and camTweenRelativeTargetPart.Parent then
					camera.CFrame = CFrame.new(camTweenRelativeTargetPart.Position) * cfObject.Value
				else
					camera.CFrame = cfObject.Value
				end
			end
		end)
		cameraTween:Play()
		cameraTween.Completed:Wait()
		cfChangedConn:Disconnect()
		cfChangedConn = nil
		cfObject = nil
	end

	-- Camera finished tweening
	if transitionCount == thisTransitionCount then
		if screenPart then
			-- Lock camera to screen
			if lockCameraConnection then
				lockCameraConnection:Disconnect()
				lockCameraConnection = nil
			end
			lockCameraConnection = RunService.RenderStepped:Connect(function()
				if transitionCount == thisTransitionCount then
					camera.CFrame = setCameraCF(screenPart)
				end
			end)
		else
			-- Return camera to character
			camera.CameraType = Enum.CameraType.Custom
			characterCamCF = nil
			characterCamCFIsRelative = false
			local character = localPlayer.Character
			if character and character.Parent then
				local humanoid = character:FindFirstChildOfClass("Humanoid")
				if humanoid then
					camera.CameraSubject = humanoid
				end
			end
			if manageLockingCharacterControl then
				setHumanoidControl(true)
			end
		end
	end
end

function toggleFullscreen()
	if button then -- Only toggle if button exists, as a user control
		if fullscreenModule.FocusedScreen ~= buttonTargetScreen then
			fullscreenModule.FocusScreen(buttonTargetScreen)
		else
			fullscreenModule.FocusScreen()
		end
	end
end

function backoutFullscreen()
	if button and fullscreenModule.FocusedScreen == buttonTargetScreen then
		-- Only backout if there is a button for usercontrol and it is hooked up to the current screen
		fullscreenModule.FocusScreen()
	end
end

function updateGamepadPromptVisibility()
	if button and button.Parent then
		local gamepadPrompt = button:FindFirstChild("GamepadPrompt")
		if gamepadPrompt then
			if UserInputService.GamepadEnabled then
				button.GamepadPrompt.Visible = false
				button.Active = false
			else
				button.GamepadPrompt.Visible = true
				button.Active = true
			end
		end
	end
end
UserInputService.GamepadConnected:connect(updateGamepadPromptVisibility)
UserInputService.GamepadDisconnected:connect(updateGamepadPromptVisibility)

function fullscreenModule.RemoveButton()
	if buttonConnection then
		buttonConnection:Disconnect()
		buttonConnection = nil
	end
	if gamepadButtonConnection then
		gamepadButtonConnection:Disconnect()
		gamepadButtonConnection = nil
	end
	if button and button.Parent then
		button:Destroy()
	end
	if buttonGui and buttonGui.Parent then
		buttonGui:Destroy()
	end
	button = nil
	buttonGui = nil
	buttonTargetScreen = nil
end

function fullscreenModule.CreateButtonToFocusScreen(screenPart)
	local playerGui = localPlayer:FindFirstChild("PlayerGui")
	if playerGui then
		if button or buttonGui then
			fullscreenModule.RemoveButton()
		end
		buttonTargetScreen = screenPart
		buttonGui = buttonGuiTemplate:clone()
		button = buttonGui.Button
		buttonConnection = button.Activated:connect(toggleFullscreen)

		gamepadButtonConnection = UserInputService.InputBegan:Connect(function(input)
			if input.UserInputType == Enum.UserInputType.Gamepad1 then
				if input.KeyCode == FULLSCREEN_GAMEPAD_BUTTON then
					toggleFullscreen()
				elseif input.KeyCode == BACKOUT_GAMEPAD_BUTTON then
					backoutFullscreen()
				end
			end
		end)

		updateButtonVisuals()
		buttonGui.Parent = playerGui
	end
end

return fullscreenModule
