--------------------[ FIRING FUNCTIONS ]----------------------------------------------

function lowerSpread()
	if (not loweringSpread) then
		loweringSpread = true
		local Connection = nil
		Connection = RS.Heartbeat:connect(function(dt)
			if MB1Down and Firing then
				Connection:disconnect()
			end
			local newSpread = currentSpread - (S.spreadSettings.Decrease * dt)
			currentSpread = (newSpread < 0 and 0 or newSpread)
			if currentSpread == 0 then
				Connection:disconnect()
			end
		end)
		loweringSpread = false
	end
end

local function autoFire()
	if (not canFire) then return end
	canFire = false
	
	if (not Knifing) then
		Firing = true
		while MB1Down and (not Reloading) and (not isCrawling) and (not Knifing) do
			if Modes[((rawFireMode - 1) % numModes) + 1] ~= "AUTO" then break end
			if Humanoid.Health == 0 then break end
			if Ammo.Value > 0 then
				Ammo.Value = Ammo.Value - 1
				if Aimed and steadyKeyPressed and S.scopeSettings.unSteadyOnFire then
					steadyKeyPressed = false
					currentSteadyTime = 0
				end
				newMag = false
				fireGun()
			end
			if S.reloadSettings.magIsBullet then
				for _, Mag in pairs(Gun:GetChildren()) do
					if Mag.Name:sub(1, 3) == "Mag" then
						Mag.Transparency = 1
					end
				end
			end
			if Ammo.Value == 0 and S.reloadSettings.autoReload then
				wait(0.2)
				Reload()
			end
			wait(60 / S.roundsPerMin)
		end
	end
	
	Firing = false
	canFire = true
end

local function semiFire()
	if (not canFire) then return end
	canFire = false
	
	if (not Knifing) and (not isCrawling) and Humanoid.Health ~= 0 then
		Firing = true
		if Ammo.Value > 0 then
			Ammo.Value = Ammo.Value - 1
			if Aimed and steadyKeyPressed and S.scopeSettings.unSteadyOnFire then
				steadyKeyPressed = false
				currentSteadyTime = 0
			end
			newMag = false
			fireGun()
		end
		if S.reloadSettings.magIsBullet then
			for _, Mag in pairs(Gun:GetChildren()) do
				if Mag.Name:sub(1, 3) == "Mag" then
					Mag.Transparency = 1
				end
			end
		end
		if Ammo.Value == 0 and S.reloadSettings.autoReload then
			wait(0.2)
			Reload()
		end
		wait(60 / S.roundsPerMin)
	end
	
	Firing = false
	canFire = true
end

local function burstFire()
	if (not canFire) then return end
	canFire = false
	
	local burstTime = 60 / S.roundsPerMin
	if (not Knifing) and (not isCrawling) then
		Firing = true
		for i = 1, S.burstSettings.Amount do
			if Ammo.Value > 0 then
				Ammo.Value = Ammo.Value - 1
				if Humanoid.Health ~= 0 then
					if Aimed and steadyKeyPressed and S.scopeSettings.unSteadyOnFire then
						steadyKeyPressed = false
						currentSteadyTime = 0
					end
					newMag = false
					fireGun()
				end
			end
			if Ammo.Value == 0 and S.reloadSettings.autoReload then
				wait(0.2)
				Reload()
				break
			end
			wait(S.burstSettings.fireRateBurst and burstTime or S.burstSettings.Time / S.burstSettings.Amount)
		end
	end
	if S.reloadSettings.magIsBullet then
		for _, Mag in pairs(Gun:GetChildren()) do
			if Mag.Name:sub(1, 3) == "Mag" then
				Mag.Transparency = 1
			end
		end
	end
	
	Firing = false
	
	wait(S.burstSettings.fireRateBurst and burstTime or S.burstSettings.Wait)
	
	canFire = true
end

function fireGun()
	local fireSound = Handle:FindFirstChild("Fire")
	if fireSound then fireSound:Play() end
	----------------------------------------------------------------------------------
	for _ = 1, (S.gunType.Shot and S.ShotAmount or 1) do
		local randSpread1 = RAD(RAND(0, 365))
		local randSpread2 = RAD(RAND(-(baseSpread + currentSpread), baseSpread + currentSpread, 0.01))
		local spreadDir = CFrame.fromAxisAngle(V3(0, 0, 1), randSpread1) * CFANG(randSpread2, 0, 0)
		
		local originCF = ((Aimed and S.guiScope) and Head.CFrame or Handle.CFrame) * spreadDir
		local bulletDirection = CF(originCF.p, originCF.p + originCF.lookVector).lookVector
		
		if S.bulletSettings.instantHit then
			local newRay = Ray.new(Main.CFrame.p, bulletDirection * S.bulletSettings.Range)
			local H, P, N = workspace:FindPartOnRayWithIgnoreList(newRay, Ignore)
			local finalP = P
			if H then
				if S.gunType.Explosive then
					if S.explosionSettings.soundId ~= "" then
						local soundPart = Instance.new("Part")
						soundPart.Transparency = 1
						soundPart.Anchored = true
						soundPart.CanCollide = false
						soundPart.Size = V3(1, 1, 1)
						soundPart.CFrame = CFrame.new(P)
						soundPart.Parent = gunIgnore
						
						local Sound = Instance.new("Sound")
						Sound.Pitch = S.explosionSettings.Pitch
						Sound.SoundId = S.explosionSettings.soundId
						Sound.Volume = S.explosionSettings.Volume
						Sound.Parent = soundPart
						Sound:Play()
						
						DS:AddItem(soundPart, Sound.TimeLength)
					end
					createBulletImpact:FireServer(H, P, N, bulletDirection, false, gunIgnore, S)
					createShockwave:FireServer(P, S.explosionSettings.Radius, gunIgnore, S)
					local E = Instance.new("Explosion")
					E.BlastPressure = S.explosionSettings.Pressure
					E.BlastRadius = S.explosionSettings.Radius
					E.DestroyJointRadiusPercent = (S.explosionSettings.rangeBasedDamage and 0 or 1)
					E.ExplosionType = S.explosionSettings.Type
					E.Position = P
					E.Hit:connect(function(Obj, Dist)
						if Obj.Name == "Torso" and (not Obj:IsDescendantOf(Char)) then
							if S.explosionSettings.rangeBasedDamage then
								local Dir = (Obj.Position - P).unit
								local expH, _ = workspace:FindPartOnRayWithIgnoreList(
									Ray.new(P - Dir * 0.1, Dir * 999),
									Ignore
								)
								local rayHitHuman = expH:IsDescendantOf(Obj.Parent)
								if (S.explosionSettings.rayCastExplosions and rayHitHuman) or (not S.explosionSettings.rayCastExplosions) then
									local hitHumanoid = findFirstClass(Obj.Parent, "Humanoid")
									if hitHumanoid and hitHumanoid.Health > 0 and isEnemy(hitHumanoid) then
										local distFactor = Dist / S.explosionSettings.Radius
										local distInvert = math.max(1 - distFactor,0)
										local newDamage = distInvert * getBaseDamage((P - Main.CFrame.p).magnitude)
										
										local Tag = Instance.new("ObjectValue")
										Tag.Value = Player
										Tag.Name = "creator"
										Tag.Parent = hitHumanoid
										DS:AddItem(Tag, 0.3)
										hitHumanoid:TakeDamage(newDamage)
										markHit()
									end
								end
							else
								local hitHumanoid = findFirstClass(Obj.Parent, "Humanoid")
								if hitHumanoid and hitHumanoid.Health > 0 and isEnemy(hitHumanoid) then
									local Tag = Instance.new("ObjectValue")
									Tag.Value = Player
									Tag.Name = "creator"
									Tag.Parent = hitHumanoid
									DS:AddItem(Tag, 0.3)
									markHit()
								end
							end
						end
					end)
					E.Parent = game.Workspace
				else
					_, finalP = penetrateWall(H, P, bulletDirection, N, {Char, ignoreModel}, 0, (P - Main.CFrame.p).magnitude, nil)
				end
			end
			if S.bulletTrail and S.trailSettings.Transparency ~= 1 then
				createTrail:FireServer(Main.CFrame.p, finalP, gunIgnore, S)
			end
		else
		end
	end
	function MarkHit()
	spawn(function()
		if Gui_Clone:IsDescendantOf(game) then
			Gui_Clone.HitMarker.Visible = true
			local StartMark = tick()
			LastMark = StartMark
			wait(0.5)
			if LastMark <= StartMark then
				Gui_Clone.HitMarker.Visible = false
			end
		end
	end)
end
	
	----------------------------------------------------------------------------------
	
	currentSpread = currentSpread + S.spreadSettings.Increase
	
	for _, Plugin in pairs(Plugins.Firing) do
		spawn(function()
			Plugin()
		end)
	end
	
	local backRecoil = RAND(S.recoilSettings.Recoil.Back.Min, S.recoilSettings.Recoil.Back.Max, 0.01) --Get the kickback recoil
	local upRecoil = RAND(S.recoilSettings.Recoil.Up.Min, S.recoilSettings.Recoil.Up.Max, 0.01) --Get the up recoil
	local sideRecoilAlpha = 0
	if lastSideRecoil[1] < 0 and lastSideRecoil[2] < 0 then --This conditional basically makes sure the gun tilt isn't in the same direction for more than 2 shots
		sideRecoilAlpha = RAND(0, 1, 0.1)
	elseif lastSideRecoil[1] > 0 and lastSideRecoil[2] > 0 then
		sideRecoilAlpha = RAND(-1, 0, 0.1)
	else
		sideRecoilAlpha = RAND(-1, 1, 0.1)
	end
	local sideRecoil = numLerp(S.recoilSettings.Recoil.Side.Left, S.recoilSettings.Recoil.Side.Right, sideRecoilAlpha / 2 + 0.5) --Get the side recoil
	local tiltRecoil = numLerp(S.recoilSettings.Recoil.Tilt.Left, S.recoilSettings.Recoil.Tilt.Right, sideRecoilAlpha / 2 + 0.5) --Get the tilt recoil
	local recoilPos = V3(
		0,---sideRecoil,
		0,
		-backRecoil
	) * (Aimed and S.recoilSettings.aimedMultiplier or 1)
	local recoilRot = V3(
		(Aimed and 0 or (-RAD(upRecoil * 10) * (firstShot and S.recoilSettings.firstShotMultiplier or 1))),
		RAD(sideRecoil * 10),
		RAD(tiltRecoil * 10)
	) * (Aimed and S.recoilSettings.aimedMultiplier or 1)
	local camRecoilRot = V3(
		-RAD(sideRecoil * 10),
		RAD(upRecoil * 10) * (firstShot and S.recoilSettings.firstShotMultiplier or 1) * S.recoilSettings.camMultiplier,
		0
	) * (Aimed and S.recoilSettings.aimedMultiplier or 1) * stanceSway
	tweenRecoil(recoilPos, recoilRot, Sine, 0.2)
	tweenCam("Recoil", camRecoilRot, Sine, 0.15 * (firstShot and S.recoilSettings.firstShotMultiplier or 1))
	
	for _, v in pairs(Main:GetChildren()) do
		if v.Name:sub(1, 7) == "FlashFX" then
			v.Enabled = true
		end
	end
		local shell = Instance.new("Part")
	shell.CFrame = Gun.Chamber.CFrame * CFrame.fromEulerAnglesXYZ(-2.5,1,1)
	shell.Size = Vector3.new(0.2,0.5,0.2)
	shell.CanCollide = false	
	shell.Name = "Shell"
	shell.Velocity = Gun.Chamber.CFrame.lookVector * 10 + Vector3.new(math.random(-10,10),20,math.random(-10,10))
	shell.RotVelocity = Vector3.new(0,200,0)
	shell.Parent = game.Workspace
	game:GetService("Debris"):addItem(shell,2)
	local shellmesh = Instance.new("SpecialMesh")
	shellmesh.Scale = Vector3.new(2,2,2)
	shellmesh.MeshId = "http://www.roblox.com/asset/?id=94295100"
	shellmesh.TextureId = "http://www.roblox.com/asset/?id=94287792"
	shellmesh.MeshType = "FileMesh"
	shellmesh.Parent = shell
	delay(1 / 20, function()
		tweenRecoil(V3(), V3(), Sine, 0.2)
		tweenCam("Recoil", V3(), Sine, 0.2)
		for _, v in pairs(Main:GetChildren()) do
			if v.Name:sub(1, 7) == "FlashFX" then
				v.Enabled = false
			end
		end
	end)
	
	updateClipAmmo()
	firstShot = false
	shotCount = shotCount + 1
	lastSideRecoil[(shotCount % 2) + 1] = sideRecoilAlpha
end

function markHit()
	spawn(function()
		if mainGUI:IsDescendantOf(game) then
			hitMarker.Visible = true
			local startMark = tick()
			hitMarker.lastMark.Value = startMark
			
			wait(0.5)
			
			if hitMarker.lastMark.Value <= startMark then
				hitMarker.Visible = false
			end
		end
	end)
end