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


function Fire_Gun()
	local FireSound = Handle:FindFirstChild("FireSound")
	local FlashGui = Main:FindFirstChild("FlashGui")
	local FlashFX = Main:FindFirstChild("FlashFX")
				
	if FireSound then FireSound:Play() end
	
	local MockSpread = (
		((not Aimed) and CurrentSpread <= S.Spread.Max and Idleing)
		and CurrentSpread * S.Spread.Multiplier or CurrentSpread
	)
	CurrentSpread = (MockSpread >= S.Spread.Max and S.Spread.Max or MockSpread)
	
	----------------------------------------------------------------------------------
	for _ = 1, (S.GunType.Shot and S.ShotAmount or 1) do
		local BSpread = CFANG(
			RAD(RAND(-CurrentSpread, CurrentSpread) / 20),
			RAD(RAND(-CurrentSpread, CurrentSpread) / 20),
			RAD(RAND(-CurrentSpread, CurrentSpread) / 20)
		)
		local OriginCF = (Aimed and (S.GuiScope and Head.CFrame or Handle.CFrame) or Head.CFrame)
		local OriginPos = Main.CFrame.p
		local Direction = (CF(OriginCF.p, OriginCF.p + OriginCF.lookVector) * BSpread).lookVector
		
		if S.InstantHit then
			local HitObj, HitPos = AdvRayCast(Main.CFrame.p, Direction, S.BulletRange)
			local HitHumanoid = nil
			if HitObj then
				if S.GunType.Explosive then
					if S.ExplosionSound ~= "" then
						local SoundPart = Instance.new("Part")
						SoundPart.Transparency = 1
						SoundPart.Anchored = true
						SoundPart.CanCollide = false
						SoundPart.CFrame = CFrame.new(HitPos)
						SoundPart.Parent = game.Workspace
						
						local Sound = Instance.new("Sound")
						Sound.Pitch = S.ExplosionSoundPitch
						Sound.SoundId = S.ExplosionSound
						Sound.Volume = S.ExplosionSoundVolume
						Sound.Parent = SoundPart
						Sound:Play()
						
						delay(1 / 20, function()
							SoundPart:Destroy()
						end)
					end
					CreateBulletHole(HitPos, HitObj)
					CreateShockwave(HitPos, S.ExplosionRadius)
					local E = Instance.new("Explosion")
					E.BlastPressure = S.ExplosionPressure
					E.BlastRadius = S.ExplosionRadius
					E.DestroyJointRadiusPercent = (S.RangeBasedDamage and 0 or 1)
					E.ExplosionType = S.ExplosionType
					E.Position = HitPos
					E.Hit:connect(function(HObj, HDist)
						if HObj.Name == "Torso" and (not HObj:IsDescendantOf(Character)) then
							if S.RangeBasedDamage then
								local Dir = (HObj.Position - HitPos).unit
								local H, P = AdvRayCast(HitPos - Dir, Dir, 999)
								local RayHitHuman = H:IsDescendantOf(HObj.Parent)
								if (S.RayCastExplosions and RayHitHuman) or (not S.RayCastExplosions) then
									local HitHumanoid = FindFirstClass(HObj.Parent, "Humanoid")
									if HitHumanoid and HitHumanoid.Health > 0 and IsEnemy(HitHumanoid) then
										local DistFactor = HDist / S.ExplosionRadius
										local DistInvert = math.max(1 - DistFactor,0)
										local NewDamage = DistInvert * S.Damage
										
										local CreatorTag = Instance.new("ObjectValue")
										CreatorTag.Value = Player
										CreatorTag.Name = "creator"
										CreatorTag.Parent = HitHumanoid
										HitHumanoid:TakeDamage(NewDamage)
										MarkHit()
									end
								end
							else
								local HitHumanoid = FindFirstClass(HObj.Parent, "Humanoid")
								if HitHumanoid and HitHumanoid.Health > 0 and IsEnemy(HitHumanoid) then
									local CreatorTag = Instance.new("ObjectValue")
									CreatorTag.Value = Player
									CreatorTag.Name = "creator"
									CreatorTag.Parent = HitHumanoid
									MarkHit()
								end
							end
						end
					end)
					E.Parent = game.Workspace
				else
					HitHumanoid = Damage(HitObj, HitPos)
				end
			end
			local FinalHitPos = HitPos
			if S.Penetration > 0 and (not S.GunType.Explosive) then
				FinalHitPos = PenetrateWall(HitPos, Direction, HitHumanoid, OriginPos)
			end
			if S.BulletTrail and S.TrailTransparency ~= 1 then
				local Trail = Instance.new("Part")
				Trail.BrickColor = S.TrailColor
				Trail.Transparency = S.TrailTransparency
				Trail.Anchored = true
				Trail.CanCollide = false
				Trail.Size = VEC3(1, 1, 1)
				local Mesh = Instance.new("BlockMesh")
				Mesh.Offset = VEC3(0, 0, -(FinalHitPos - OriginPos).magnitude / 2)
				Mesh.Scale = VEC3(S.TrailThickness, S.TrailThickness, (FinalHitPos - OriginPos).magnitude)
				Mesh.Parent = Trail
				Trail.Parent = Gun_Ignore
				Trail.CFrame = CF(OriginPos, FinalHitPos)
				delay(S.TrailVisibleTime, function()
					if S.TrailDisappearTime > 0 then
						local X = 0
						while true do
							if X == 90 then break end
							if (not Selected) then break end
							local NewX = X + (1.5 / S.TrailDisappearTime)
							X = (NewX > 90 and 90 or NewX)
							local Alpha = X / 90
							Trail.Transparency = NumLerp(S.TrailTransparency, 1, Alpha)
							RS:wait()
						end
						Trail:Destroy()
					else
						Trail:Destroy()
					end
				end)
			end
		else
			local Bullet = CreateBullet(Direction)
			local LastPos = Main.CFrame.p
			local TotalDistTraveled = 0
			local HitHumanoid = nil
			spawn(function()
				while true do
					RS:wait()
					if TotalDistTraveled >= S.BulletRange then
						Bullet:Destroy()
						break
					end
					local DistTraveled = (Bullet.Position - LastPos).magnitude
					local HitObj, HitPos = AdvRayCast(LastPos, (Bullet.Position - LastPos).unit, DistTraveled)
					if HitObj then
						if S.GunType.Explosive then
							if S.ExplosionSound ~= "" then
								local Sound = Instance.new("Sound")
								Sound.Pitch = S.ExplosionSoundPitch
								Sound.SoundId = S.ExplosionSound
								Sound.Volume = S.ExplosionSoundVolume
								Sound.Parent = Bullet
								Sound:Play()
							end
							CreateBulletHole(HitPos, HitObj)
							CreateShockwave(HitPos, S.ExplosionRadius)
							local E = Instance.new("Explosion")
							E.BlastPressure = S.ExplosionPressure
							E.BlastRadius = S.ExplosionRadius
							E.DestroyJointRadiusPercent = (S.RangeBasedDamage and 0 or 1)
							E.ExplosionType = S.ExplosionType
							E.Position = HitPos
							E.Hit:connect(function(HObj, HDist)
								if HObj.Name == "Torso" and (not HObj:IsDescendantOf(Character)) then
									if S.RangeBasedDamage then
										local Dir = (HObj.Position - HitPos).unit
										local H, P = AdvRayCast(HitPos - Dir, Dir, 999)
										local RayHitHuman = H:IsDescendantOf(HObj.Parent)
										if (S.RayCastExplosions and RayHitHuman) or (not S.RayCastExplosions) then
											local HitHumanoid = FindFirstClass(HObj.Parent, "Humanoid")
											if HitHumanoid and HitHumanoid.Health > 0 and IsEnemy(HitHumanoid) then
												local DistFactor = HDist / S.ExplosionRadius
												local DistInvert = math.max(1 - DistFactor,0)
												local NewDamage = DistInvert * S.Damage
												
												local CreatorTag = Instance.new("ObjectValue")
												CreatorTag.Value = Player
												CreatorTag.Name = "creator"
												CreatorTag.Parent = HitHumanoid
												HitHumanoid:TakeDamage(NewDamage)
												MarkHit()
											end
										end
									else
										local HitHumanoid = FindFirstClass(HObj.Parent, "Humanoid")
										if HitHumanoid and HitHumanoid.Health > 0 and IsEnemy(HitHumanoid) then
											local CreatorTag = Instance.new("ObjectValue")
											CreatorTag.Value = Player
											CreatorTag.Name = "creator"
											CreatorTag.Parent = HitHumanoid
											MarkHit()
										end
									end
								end
							end)
							E.Parent = game.Workspace
						else
							HitHumanoid = Damage(HitObj, HitPos)
						end
						if S.Penetration > 0 and (not S.GunType.Explosive) then
							PenetrateWall(HitPos, (Bullet.Position - LastPos).unit, HitHumanoid, OriginPos, Bullet)
						else
							Bullet:Destroy()
						end
						break
					else
						LastPos = Bullet.Position
						TotalDistTraveled = TotalDistTraveled + DistTraveled
					end
				end
			end)
			
			if S.BulletTrail and S.TrailTransparency ~= 1 then
				spawn(function()
					local LastPos2 = nil
					while true do
						if LastPos2 then
							if (not Bullet:IsDescendantOf(game)) then break end
							Bullet.CFrame = CFrame.new(Bullet.CFrame.p, Bullet.CFrame.p + Bullet.Velocity)
							local Trail = Instance.new("Part")
							Trail.BrickColor = S.TrailColor
							Trail.Transparency = S.TrailTransparency
							Trail.Anchored = true
							Trail.CanCollide = false
							Trail.Size = VEC3(1, 1, 1)
							local Mesh = Instance.new("BlockMesh")
							Mesh.Offset = VEC3(0, 0, -(Bullet.Position - LastPos2).magnitude / 2)
							Mesh.Scale = VEC3(S.TrailThickness, S.TrailThickness, (Bullet.Position - LastPos2).magnitude)
							Mesh.Parent = Trail
							Trail.Parent = Gun_Ignore
							Trail.CFrame = CF(LastPos2, Bullet.Position)
							delay(S.TrailVisibleTime, function()
								if S.TrailDisappearTime > 0 then
									local X = 0
									while true do
										if X == 90 then break end
										if (not Selected) then break end
										local NewX = X + (1.5 / S.TrailDisappearTime)
										X = (NewX > 90 and 90 or NewX)
										local Alpha = X / 90
										Trail.Transparency = NumLerp(S.TrailTransparency, 1, Alpha)
										RS:wait()
									end
									Trail:Destroy()
								else
									Trail:Destroy()
								end
							end)
							LastPos2 = Bullet.Position
						else
							LastPos2 = Main.CFrame.p
						end
						RS:wait()
					end
				end)
			end
		end
	end
	
	----------------------------------------------------------------------------------
	
	local RecoilX = RAD(CurrentRecoil * RAND(1, 1.5, 0.1)) * StanceSway
	local RecoilY = RAD(CurrentRecoil * RAND(-2, 2, 0.1)) * StanceSway
	RotCamera(RecoilX, RecoilY, true, 0.06)
	delay(0.05, function()
		RotCamera(-RecoilX / 5, -RecoilY / 5, true, 0.1)
	end)
	if Idleing and (not Walking) and (not Aimed) then
		local SpreadScale = (CurrentSpread / S.Spread.Max) * 50
		Gui_Clone.CrossHair.Box:TweenSizeAndPosition(
			UDim2.new(0, 70 + 2 * SpreadScale, 0, 70 + 2 * SpreadScale),
			UDim2.new(0, -35 - SpreadScale, 0, -35 - SpreadScale),
			"Out", "Linear", 0.1, true
		)
	end
	
	local KickSide = (
		(
			{
				CurrentRecoil * (RAND(1, 5, 1) / 150);
				CurrentRecoil * (RAND(1, 5, 1) / -150)
			}
		)[math.random(1, 2)]
	) * StanceSway
	local KickBack = CurrentRecoil * StanceSway * 0.3
	local KickUp = RAD(90 + (CurrentRecoil * RAND(1.3, 1.4, 0.01) * StanceSway))
	TweenJoint(AnimWeld, CF(KickSide, 1, -KickBack), CFANG(KickUp - RAD(90), 0, 0), Linear, 1 / 12)
	
	if FlashFX then FlashFX.Enabled = true end
	if FlashGui then
		FlashGui.Enabled = true
		FlashGui.Label.Rotation = RAND(0, 360)
	end
	
	delay(1 / 30, function()
		if Idleing and (not Walking) and (not Aimed) then
			Gui_Clone.CrossHair.Box:TweenSizeAndPosition(
				UDim2.new(0, 70, 0, 70),
				UDim2.new(0, -35, 0, -35),
				"Out", "Linear", S.AimSpeed, (not Aimed)
			)
		end
		if (not Aiming) and (not RunTween) then
			TweenJoint(AnimWeld, CF(0, 1, 0), CF(), Linear, 0.15)
		end
		if FlashFX then FlashFX.Enabled = false end
		if FlashGui then FlashGui.Enabled = false end
	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
