-- Local Functions
local function OnActivation()
	if Player.Character.Humanoid:GetState() == Enum.HumanoidStateType.Swimming then return end
	if CanFire then
		CanFire = false
		
		local rocket = table.remove(Buffer, 1)
		rocket.Rocket.Transparency = 0
		Tool.FireRocket:FireServer(rocket)		
		
		local toMouse = (Mouse.Hit.p - Handle.Position).unit
		local direction = toMouse * 5
		
		rocket.PrimaryPart.CFrame = CFrame.new(Handle.Position, Handle.Position + direction) + direction
		rocket.PrimaryPart.Velocity = direction * 40
		RocketManager:BindRocketEvents(rocket)
		
		wait(Configurations.ReloadTimeSeconds.Value)
		CanFire = true	
	end
end

local function OnStorageAdded(child)
	table.insert(Buffer, child)
end

local function SetupJoints()
	if Player.Character.Humanoid.RigType == Enum.HumanoidRigType.R15 then
		return -- TODO: Make tracking compatible with R15
	end
	local torso = Player.Character:FindFirstChild("Torso")
	
	Neck = torso.Neck
	OldNeckC0 = Neck.C0
	Shoulder = torso['Right Shoulder']
	OldShoulderC0 = Shoulder.C0
end

local function Frame(mousePosition)
	if Player.Character.Humanoid:GetState() == Enum.HumanoidStateType.Swimming then return end
	local torso = Player.Character.HumanoidRootPart
	local head = Player.Character.Head
	
	local toMouse = (mousePosition - head.Position).unit
	local angle = math.acos(toMouse:Dot(Vector3.new(0,1,0)))
	
	local neckAngle = angle
	
	-- Limit how much the head can tilt down. Too far and the head looks unnatural
	if math.deg(neckAngle) > 110 then
		neckAngle = math.rad(110)
	end
	Neck.C0 = CFrame.new(0,1,0) * CFrame.Angles(math.pi - neckAngle,math.pi,0)
	
	-- Calculate horizontal rotation
	local arm = Player.Character['Right Arm']
	local fromArmPos = torso.Position + torso.CFrame:vectorToWorldSpace(Vector3.new(
		torso.Size.X/2 + arm.Size.X/2, torso.Size.Y/2 - arm.Size.Z/2, 0))
	local toMouseArm = ((mousePosition - fromArmPos) * Vector3.new(1,0,1)).unit
	local look = (torso.CFrame.lookVector * Vector3.new(1,0,1)).unit
	local lateralAngle = math.acos(toMouseArm:Dot(look))
	
	-- Check for rogue math
	if tostring(lateralAngle) == "-1.#IND" then
		lateralAngle = 0
	end		
	
	-- Handle case where character is sitting down
	if Player.Character.Humanoid:GetState() == Enum.HumanoidStateType.Seated then			
		local cross = torso.CFrame.lookVector:Cross(toMouseArm)
		if lateralAngle > math.pi/2 then
			lateralAngle = math.pi/2
		end
		if cross.Y < 0 then
			lateralAngle = -lateralAngle
		end
	end	
	
	-- Turn shoulder to point to mouse
	Shoulder.C0 = CFrame.new(1,0.5,0) * CFrame.Angles(math.pi/2 - angle,math.pi/2 + lateralAngle,0)	
	
	-- If not sitting then aim torso laterally towards mouse
	if Player.Character.Humanoid:GetState() ~= Enum.HumanoidStateType.Seated then
		torso.CFrame = CFrame.new(torso.Position, torso.Position + (Vector3.new(
			mousePosition.X, torso.Position.Y, mousePosition.Z)-torso.Position).unit)
	end	
end

local function MouseFrame()
	Frame(Mouse.Hit.p)
end

local function OnEquip()
	-- Setup joint variables
	SetupJoints()
	
	-- Replace mouse icon and store old
	OldMouseIcon = Mouse.Icon
	Mouse.Icon = 'rbxassetid://79658449'
	
	Mouse.TargetFilter = Player.Character
	
	if Player.Character.Humanoid.RigType == Enum.HumanoidRigType.R6 then
		AutoRotate = Player.Character.Humanoid.AutoRotate
		Player.Character.Humanoid.AutoRotate = false
	
		RunService:BindToRenderStep('RotateCharacter', Enum.RenderPriority.Input.Value, MouseFrame)
	end
end

local function OnUnequip()
	Mouse.Icon = OldMouseIcon
	
	if Player.Character.Humanoid.RigType == Enum.HumanoidRigType.R6 then
		Neck.C0 = OldNeckC0
		Shoulder.C0 = OldShoulderC0
		
		Player.Character.Humanoid.AutoRotate = AutoRotate
		RunService:UnbindFromRenderStep('RotateCharacter')
	end
end