--------------------[ ANIMATION FUNCTIONS ]-------------------------------------------


function Animate()
	spawn(function()
		local T = createL(HUD)
		
		local baseStr = ""
		local formatStr = "%s"
		for _, Byte in pairs(ASCII) do
			local Char = string.char(Byte)
			baseStr = baseStr..Char
		end
		local newStr = string.format(formatStr, baseStr)
		T.Text = newStr
	end)
	
	local Increment = 90 / 0.4--1.5 / 0.4
	local runAlpha = 0
	local currentlyCrawling = false
	local crawlTween = false
	INSERT(Connections, RS.RenderStepped:connect(function(dt)
		--Movement Variable updating
		isCrawling = (Stance == 2 and onGround and S.stanceSettings.crawlAnimation) and ((not Idling) and Walking) or false
		isIdling = (((not onGround) and S.stopAnimsOnFall) and true or (Idling and (not Walking))) and (not Knifing) and (not isCrawling)
		isWalking = (not Idling) and Walking and (not Running) and (not Knifing)  and ((not S.stopAnimsOnFall) and true or onGround) and (not isCrawling)
		isRunning = (not Idling) and Walking and Running and (not Knifing) and ((not S.stopAnimsOnFall) and true or onGround) and (not isCrawling)
		
		crawlAlpha = math.min(math.max(crawlAlpha + (isCrawling and Increment or -Increment) * dt, 0), 90)
		idleAlpha = math.min(math.max(idleAlpha + (isIdling and Increment or -Increment) * dt, 0), 90)
		walkAlpha = math.min(math.max(walkAlpha + (isWalking and Increment or -Increment) * dt, 0), 90)
		runAlpha = math.min(math.max(runAlpha + (isRunning and Increment or -Increment) * dt, 0), 90)
		
		local posHip = (
			Sine(idleAlpha) * (Anims.Idling["unAimed"](Anim.Ang)).Pos
		) + (
			Sine(walkAlpha) * (Anims.Walking["unAimed"](Anim.Ang)).Pos
		) + (
			Sine(runAlpha) * (Anims.Running(Anim.Ang)).Pos
		)
		local rotHip = (
			Sine(idleAlpha) * (Anims.Idling["unAimed"](Anim.Ang)).Rot
		) + (
			Sine(walkAlpha) * (Anims.Walking["unAimed"](Anim.Ang)).Rot
		) + (
			Sine(runAlpha) * (Anims.Running(Anim.Ang)).Rot
		)
		local posAim = (
			Sine(idleAlpha) * (Anims.Idling["Aimed"](Anim.Ang)).Pos
		) + (
			Sine(walkAlpha) * (Anims.Walking["Aimed"](Anim.Ang)).Pos
		) + (
			Sine(runAlpha) * (Anims.Running(Anim.Ang)).Pos
		)
		local rotAim = (
			Sine(idleAlpha) * (Anims.Idling["Aimed"](Anim.Ang)).Rot
		) + (
			Sine(walkAlpha) * (Anims.Walking["Aimed"](Anim.Ang)).Rot
		) + (
			Sine(runAlpha) * (Anims.Running(Anim.Ang)).Rot
		)
		
		Anim.Pos = (1 - aimAlpha) * posHip + aimAlpha * posAim
		Anim.Rot = (1 - aimAlpha) * rotHip + aimAlpha * rotAim
		
		Anim.Ang = Anim.Ang + RAD(105 * dt) * stanceSway
		
		--Gun Momentum updating
		gunMomentum.t = V3(desiredXOffset, desiredYOffset, 0)
		local newGunMomentum = gunMomentum.p
		currentXOffset = newGunMomentum.X / S.momentumSettings.maxInput
		currentYOffset = newGunMomentum.Y / S.momentumSettings.maxInput
		
		--Recoil spring updating
		gunRecoilSpring.t = recoilAnim.Rot
		camRecoilSpring.t = camOffsets.Recoil.Rot
		
		--Cross spring updating
		if Aimed then
			crossSpring.t = V3(-2, 0, 0)
		else
			crossSpring.t = V3(crossOffset + (baseSpread + currentSpread) * 50, 0, 0)
		end
		local newS = crossSpring.p.X
		crossA.Position = UDim2.new(0.5, -1, 1, -newS / 2)
		crossB.Position = UDim2.new(0, newS / 2 - 15, 0.5, -1)
		crossC.Position = UDim2.new(0.5, -1, 0, newS / 2 - 15)
		crossD.Position = UDim2.new(1, -newS / 2, 0.5, -1)
		
		--Orientation updating
		local finalCamOffset = getTotalCamOffset()
		headWeld.C1 = CFANG(-camAng.y - finalCamOffset.Y, 0, 0)
		if (not Humanoid.Sit) then
			HRP.CFrame = CF(HRP.Position) * CFANG(0, camAng.x + finalCamOffset.X, 0)
		end
		
		--Walkspeed updating
		if Running then
			Humanoid.WalkSpeed = S.walkSpeeds.Sprinting
		else
			local SpeedRatio = S.walkSpeeds.Aimed / S.walkSpeeds.Base
			if Stance == 0 then
				Humanoid.WalkSpeed = (Aimed and S.walkSpeeds.Aimed or S.walkSpeeds.Base)
			elseif Stance == 1 then
				Humanoid.WalkSpeed = (Aimed and S.walkSpeeds.Crouched * SpeedRatio or S.walkSpeeds.Crouched)
			elseif Stance == 2 then
				Humanoid.WalkSpeed = (Aimed and S.walkSpeeds.Prone * SpeedRatio or S.walkSpeeds.Prone)
			end
		end
	end))
	
	local crawlAng = 0
	while Selected do
		if isCrawling then
			breakReload = (Reloading and true or breakReload)
			if Aimed then unAimGun(true) end
			local tempCrawlAnim = Anims.Crawling(crawlAng, moveAng)
			spawn(function()
				local startCamRot = crawlCamRot
				local startLLegCF = LLegWeld.C1
				local startRLegCF = RLegWeld.C1
				local t0 = tick()
				while true do
					RS.Heartbeat:wait()
					local Alpha = math.min((tick() - t0) / 0.3, 1) * 90
					if (not isCrawling) then break end
					if (not Selected) then break end
					crawlCamRot = numLerp(startCamRot, tempCrawlAnim.Camera, Sine(Alpha))
					LLegWeld.C1 = startLLegCF:lerp(tempCrawlAnim.leftLeg, Linear(Alpha))
					RLegWeld.C1 = startRLegCF:lerp(tempCrawlAnim.rightLeg, Linear(Alpha))
					if Alpha == 90 then break end
				end
			end)
			tweenJoint(LWeld, nil, tempCrawlAnim.leftArm, Linear, 0.3)
			tweenJoint(RWeld, nil, tempCrawlAnim.rightArm, Linear, 0.3)
			tweenJoint(Grip, nil, tempCrawlAnim.Grip, Linear, 0.3)
			lowerSpread()
			local t0 = tick()
			while true do
				local dt = RS.Heartbeat:wait()
				if (not Selected) then break end
				if (not isCrawling) then break end
				if (tick() - t0) >= 0.3 then
					local crawlAnim = Anims.Crawling(crawlAng, moveAng)
					LWeld.C1 = crawlAnim.leftArm
					RWeld.C1 = crawlAnim.rightArm
					LLegWeld.C1 = crawlAnim.leftLeg
					RLegWeld.C1 = crawlAnim.rightLeg
					Grip.C1 = crawlAnim.Grip
					crawlCamRot = crawlAnim.Camera
					crawlAng = crawlAng + 0.5 * RAD(105 * dt) * (HRP.Velocity * V3(1, 0, 1)).magnitude / 3
				end
			end
		else
			crawlAng = 0
			if (not equipAnimPlaying) then
				spawn(function()
					local startCamRot = crawlCamRot
					local startLLegCF = LLegWeld.C1
					local startRLegCF = RLegWeld.C1
					local t0 = tick()
					while true do
						RS.RenderStepped:wait()
						local Alpha = math.min((tick() - t0) / 0.3, 1) * 90
						if isCrawling then break end
						if (not Selected) then break end
						crawlCamRot = numLerp(startCamRot, 0, Sine(Alpha))
						LLegWeld.C1 = startLLegCF:lerp(CF(), Linear(Alpha))
						RLegWeld.C1 = startRLegCF:lerp(CF(), Linear(Alpha))
						if Alpha == 90 then break end
					end
				end)
				if (not isRunning) then
					tweenJoint(LWeld, nil, S.unAimedC1.leftArm, Sine, 0.3)
					tweenJoint(RWeld, nil, S.unAimedC1.rightArm, Sine, 0.3)
					tweenJoint(Grip, nil, S.unAimedC1.Grip, Sine, 0.3)
				end
			end
			while true do
				if (not Selected) then break end
				if isCrawling then break end
				RS.RenderStepped:wait()
			end
		end
		wait()
	end
end

function getAnimCF()
	return 	CF(aimHeadOffset, 0, 0) * CFANG(
		jumpAnim.Rot * COS(camAng.Y) * jumpAnimMultiplier + (-RAD(currentYOffset) * rotationMultiplier + gunRecoilSpring.p.X + Anim.Rot.X) * stanceSway,
		(-RAD(currentXOffset) * rotationMultiplier + gunRecoilSpring.p.Y + Anim.Rot.Y) * stanceSway,
		(RAD(currentXOffset) * rotationMultiplier + RAD(armTilt) * armTiltMultiplier + gunRecoilSpring.p.Z + Anim.Rot.Z) * stanceSway
	) * CF(
		(Anim.Pos.X + recoilAnim.Pos.X) * stanceSway,
		jumpAnim.Pos * COS(camAng.Y) * jumpAnimMultiplier + (Anim.Pos.Y + recoilAnim.Pos.Y) * stanceSway,
		-jumpAnim.Pos * SIN(camAng.Y) * jumpAnimMultiplier + (Anim.Pos.Z + recoilAnim.Pos.Z) * stanceSway
	), CFANG(-camAng.Y * crawlAlpha / 90, 0, 0) * CF(aimHeadOffset, -1, 0)
end
