motors = {}
modes = {}
cframes = {}
targets = {}
c0s = {}
c1s = {}
torso = nil
head = nil
model = nil
humanoid = nil
running = false
cameraOffset = Vector3.new(0,0,0)
run = game:GetService("RunService")
input = game:GetService("UserInputService")
motorsEnabled = true
function getMotor(name)
	motors[name] = torso:WaitForChild(name)
	cframes[name] = CFrame.new(0,0,0) -- need to change this to a {} for each motor, not globals
	targets[name] = CFrame.new(0,0,0)
	c0s[name] = motors[name].C0
	c1s[name] = motors[name].C1
	return motors[name]
end
function check(...)
	for _,item in pairs({...}) do
		if not item or not item.Parent then return false end
	end
	return true
end
local alpha = 0.1 * (1/60)
function setArm(name,delta)
	if not delta then delta = 1/60 end
	if not check(model,head,torso,motors[name]) or motorsEnabled or humanoid.SeatPart then return end
	local origin = (game.Workspace.CurrentCamera.CFrame.Rotation + head.Position)
	if modes[name] ~= 1 then cframes[name] = origin:ToObjectSpace(motors[name].Part1.CFrame)  * CFrame.Angles(-1.57,0,0) end
	modes[name] = 1
	cframes[name] = cframes[name]:Lerp(targets[name],alpha/delta)
	motors[name].Part1.CFrame = origin:ToWorldSpace(cframes[name] * CFrame.Angles(1.57,0,0))	
end
function restArm(name,delta)
	if not delta then delta = 1/60 end
	if not check(model,head,torso,motors[name]) or motorsEnabled or humanoid.SeatPart then return end
	local origin = (torso.CFrame)
	if modes[name] ~= 2 then cframes[name] = origin:ToObjectSpace(motors[name].Part1.CFrame)  * CFrame.Angles(-1.57,0,0) end
	modes[name] = 2
	cframes[name] = cframes[name]:Lerp(targets[name],alpha/delta)
	motors[name].Part1.CFrame = origin:ToWorldSpace(cframes[name] * CFrame.Angles(1.57,0,0))
end
function resetMotors()
	for name,motor in pairs(motors) do
		if motor and motor.Parent then
			motor.C0 = c0s[name]
			motor.C1 = c1s[name]
		end
	end
end
function rotateCharacter()
	if not model or not model.Parent or not model.PrimaryPart or not humanoid then return end
	local state = humanoid:GetState()
	local statetype = Enum.HumanoidStateType
	if state == statetype.Ragdoll or state == statetype.FallingDown or state == statetype.GettingUp then return end
	model.HumanoidRootPart.CFrame = 
		CFrame.new(model.HumanoidRootPart.Position,
			model.HumanoidRootPart.Position 
			+ Vector3.new(
				game.Workspace.CurrentCamera.CFrame.LookVector.X,0,
				game.Workspace.CurrentCamera.CFrame.LookVector.Z))
end
function lookArm(name,position)
	
end
function rotateHead()
	if not motors["Neck"] or not torso then return end
	local target = torso.CFrame:ToObjectSpace(game.Workspace.Camera.CFrame).LookVector
	motors["Neck"].C0 = CFrame.new(0, 1, 0, -1, 0, 0, 0, 0, 1, 0, 1, -0) * CFrame.Angles(math.acos(target.Y)+math.rad(-105),0,math.acos(target.X)+math.rad(-90))
end
function disableMotors()
	if not motorsEnabled then return end
	motorsEnabled = false
	getMotor("Left Shoulder").Enabled = false
	local leftArm = motors["Left Shoulder"].Part1
	leftArm.CanCollide = false
	leftArm.Anchored = true
	getMotor("Right Shoulder").Enabled = false
	local rightArm = motors["Right Shoulder"].Part1
	rightArm.CanCollide = false
	rightArm.Anchored = true
end
function enableMotors()
	if motorsEnabled then return end
	motorsEnabled = true
	motors["Left Shoulder"].Enabled = true
	local leftArm = motors["Left Shoulder"].Part1
	leftArm.CanCollide = true
	leftArm.Anchored = false
	motors["Right Shoulder"].Enabled = true
	local rightArm = motors["Right Shoulder"].Part1
	rightArm.CanCollide = true
	rightArm.Anchored = false
end
function setRunning(value)
	if value then
		running = true
		humanoid.WalkSpeed = 30
	else
		running = false
		humanoid.WalkSpeed = 15
	end
end
run:BindToRenderStep("CharacterMotorReset",1,function() resetMotors() rotateHead()
	game.Players.LocalPlayer.CameraMode = Enum.CameraMode.Classic	
	if humanoid then humanoid.CameraOffset = cameraOffset end cameraOffset = Vector3.new(0,0,0)
end)
run:BindToRenderStep("CharacterHeadRotate",Enum.RenderPriority.Last.Value+1,function()
	rotateHead()
end)

function init(character)
	torso = character:WaitForChild("Torso")
	head = character:WaitForChild("Head")
	humanoid = character:WaitForChild("Humanoid")
	humanoid.BreakJointsOnDeath = false
	motors = {}
	model = character
	enableMotors()
	getMotor("Neck").Enabled = true
	getMotor("Left Shoulder").Enabled = true
	getMotor("Right Shoulder").Enabled = true
	spawn(function() while wait(.1) do
		local event = _G.Remotes.MotorMoveClient
		event:FireServer(motors["Neck"],motors["Neck"].C0,motors["Neck"].C1)
		event:FireServer(motors["Left Shoulder"],motors["Left Shoulder"].C0,motors["Left Shoulder"].C1)
		event:FireServer(motors["Right Shoulder"],motors["Right Shoulder"].C0,motors["Right Shoulder"].C1)
	end end)
	input.InputBegan:Connect(function(object,irrelevant)
		if not irrelevant then
			if object.KeyCode == Enum.KeyCode.LeftShift or object.KeyCode == Enum.KeyCode.ButtonL1 then
				humanoid.WalkSpeed = 30
				running = true
			end
		end
	end)
	input.InputEnded:Connect(function(object,irrelevant)
		if not irrelevant then
			if object.KeyCode == Enum.KeyCode.LeftShift or object.KeyCode == Enum.KeyCode.ButtonL1 then
				humanoid.WalkSpeed = 15
				running = false
			end
		end
	end)
	game.Workspace.CurrentCamera.CameraSubject = humanoid
end
return getfenv()