--------------------------------------------------------------------------------------------------

if Module.DualEnabled then
	Handle2 = Tool:WaitForChild("Handle2",2)
	if Handle2 == nil and Module.DualEnabled then error("\"Dual\" setting is enabled but \"Handle2\" is missing!") end
end

local Equipped = false
local Enabled = true
local Down = false
local HoldDown = false
local Reloading = false
local AimDown = false
local Scoping = false
local Mag = MagValue.Value
local Ammo = AmmoValue.Value
local MaxAmmo = Module.MaxAmmo

if Module.IdleAnimationID ~= nil or Module.DualEnabled then
	IdleAnim = Tool:WaitForChild("IdleAnim")
	IdleAnim = Humanoid:LoadAnimation(IdleAnim)
end
if Module.FireAnimationID ~= nil then
	FireAnim = Tool:WaitForChild("FireAnim")
	FireAnim = Humanoid:LoadAnimation(FireAnim)
end
if Module.ReloadAnimationID ~= nil then
	ReloadAnim = Tool:WaitForChild("ReloadAnim")
	ReloadAnim = Humanoid:LoadAnimation(ReloadAnim)
end
if Module.ShotgunClipinAnimationID ~= nil then
	ShotgunClipinAnim = Tool:WaitForChild("ShotgunClipinAnim")
	ShotgunClipinAnim = Humanoid:LoadAnimation(ShotgunClipinAnim)
end
if Module.HoldDownAnimationID ~= nil then
	HoldDownAnim = Tool:WaitForChild("HoldDownAnim")
	HoldDownAnim = Humanoid:LoadAnimation(HoldDownAnim)
end
if Module.EquippedAnimationID ~= nil then
	EquippedAnim = Tool:WaitForChild("EquippedAnim")
	EquippedAnim = Humanoid:LoadAnimation(EquippedAnim)
end

function wait(TimeToWait)
	if TimeToWait ~= nil then
		local TotalTime = 0
		TotalTime = TotalTime + game:GetService("RunService").Heartbeat:wait()
		while TotalTime < TimeToWait do
			TotalTime = TotalTime + game:GetService("RunService").Heartbeat:wait()
		end
	else
		game:GetService("RunService").Heartbeat:wait()
	end
end

function numLerp(A, B, Alpha)
	return A + (B - A) * Alpha
end

function RAND(Min, Max, Accuracy)
	local Inverse = 1 / (Accuracy or 1)
	return (math.random(Min * Inverse, Max * Inverse) / Inverse)
end

function GetFireDirection(CurrentPosOnScreen, FirePointObject)
	local X = CurrentPosOnScreen.X + math.random(-Module.SpreadX * 2, Module.SpreadX * 2) * (AimDown and 1-Module.SpreadRedutionIS and 1-Module.SpreadRedutionS or 1)
	local Y = CurrentPosOnScreen.Y + math.random(-Module.SpreadY * 2, Module.SpreadY * 2) * (AimDown and 1-Module.SpreadRedutionIS and 1-Module.SpreadRedutionS or 1)
	local RayMag1 = Camera:ScreenPointToRay(X, Y) --Hence the var name, the magnitude of this is 1.
	local NewRay = Ray.new(RayMag1.Origin, RayMag1.Direction * 5000)
	local Target, Position = workspace:FindPartOnRay(NewRay, Character)
	--NOTE: This ray is from camera to object's position. This is why I check for a position value - With that value, I can get the proper direction
	return (Position - FirePointObject.WorldPosition).Unit
end

MarkerEvent.Event:connect(function(IsHeadshot)
	pcall(function()
	    if Module.HitmarkerEnabled then
		    if IsHeadshot then
			    GUI.Crosshair.Hitmarker.ImageColor3 = Module.HitmarkerColorHS
                GUI.Crosshair.Hitmarker.ImageTransparency = 0
                TweeningService:Create(GUI.Crosshair.Hitmarker, TweenInfo.new(Module.HitmarkerFadeTimeHS, Enum.EasingStyle.Linear, Enum.EasingDirection.Out), {ImageTransparency = 1}):Play()
	            local markersound = GUI.Crosshair.MarkerSound:Clone()
	            markersound.PlaybackSpeed = Module.HitmarkerSoundPitchHS
	            markersound.Parent = Player.PlayerGui
	            markersound:Play()
	            game:GetService("Debris"):addItem(markersound,markersound.TimeLength)
		    else
			    GUI.Crosshair.Hitmarker.ImageColor3 = Module.HitmarkerColor
			    GUI.Crosshair.Hitmarker.ImageTransparency = 0
			    TweeningService:Create(GUI.Crosshair.Hitmarker, TweenInfo.new(Module.HitmarkerFadeTime, Enum.EasingStyle.Linear, Enum.EasingDirection.Out), {ImageTransparency = 1}):Play()
	            local markersound = GUI.Crosshair.MarkerSound:Clone()
	            markersound.PlaybackSpeed = Module.HitmarkerSoundPitch
	            markersound.Parent = Player.PlayerGui
	            markersound:Play()
	            game:GetService("Debris"):addItem(markersound,markersound.TimeLength)
			end
	    end
	end)
end)

function EjectShell(ShootingHandle)
	if Module.BulletShellEnabled then
		local ShellPos = (ShootingHandle.CFrame * CFrame.new(Module.BulletShellOffset.X,Module.BulletShellOffset.Y,Module.BulletShellOffset.Z)).p
		local Chamber = Instance.new("Part")
		Chamber.Name = "Chamber"
		Chamber.Size = Vector3.new(0.01,0.01,0.01)
		Chamber.Transparency = 1
		Chamber.Anchored = false
		Chamber.CanCollide = false
		Chamber.TopSurface = Enum.SurfaceType.SmoothNoOutlines
		Chamber.BottomSurface = Enum.SurfaceType.SmoothNoOutlines
		local Weld = Instance.new("Weld",Chamber)
		Weld.Part0 = ShootingHandle
		Weld.Part1 = Chamber
		Weld.C0 = CFrame.new(Module.BulletShellOffset.X,Module.BulletShellOffset.Y,Module.BulletShellOffset.Z)
		Chamber.Position = ShellPos
		Chamber.Parent = workspace.CurrentCamera
		local function spawner()
	        local Shell = Instance.new("Part")
	        Shell.CFrame = Chamber.CFrame * CFrame.fromEulerAnglesXYZ(-2.5,1,1)
	        Shell.Size = Module.ShellSize
	        Shell.CanCollide = Module.AllowCollide
	        Shell.Name = "Shell"
	        --VVV Edit here VVV--
		    Shell.Velocity = Chamber.CFrame.lookVector * 20 + Vector3.new(math.random(-10,10),20,math.random(-10,10))
	        Shell.RotVelocity = Vector3.new(0,200,0)
	        --^^^ Edit here ^^^--
	        Shell.Parent = workspace.CurrentCamera
	        local shellmesh = Instance.new("SpecialMesh")
	        shellmesh.Scale = Module.ShellScale
	        shellmesh.MeshId = "rbxassetid://"..Module.ShellMeshID
	        shellmesh.TextureId = "rbxassetid://"..Module.ShellTextureID
	        shellmesh.MeshType = "FileMesh"
	        shellmesh.Parent = Shell
	        game:GetService("Debris"):addItem(Shell,Module.DisappearTime)
		end	
		spawn(spawner)
		game.Debris:AddItem(Chamber,10)									
	end
end

function RecoilCamera()
	if Module.CameraRecoilingEnabled then
	    local CurrentRecoil = Module.Recoil*(AimDown and 1-Module.RecoilRedution or 1)
        local RecoilX = math.rad(CurrentRecoil * RAND(Module.AngleX_Min, Module.AngleX_Max, Module.Accuracy))
	    local RecoilY = math.rad(CurrentRecoil * RAND(Module.AngleY_Min, Module.AngleY_Max, Module.Accuracy))
	    local RecoilZ = math.rad(CurrentRecoil * RAND(Module.AngleZ_Min, Module.AngleZ_Max, Module.Accuracy))
	    CameraModule:accelerate(RecoilX,RecoilY,RecoilZ)	    
		delay(0.05, function()
		    CameraModule:accelerateXY(-RecoilX,-RecoilY)
	    end)
	end
end

function Fire(ShootingHandle, InputPos)
	if FireAnim then FireAnim:Play(nil,nil,Module.FireAnimationSpeed) end
	if not ShootingHandle.FireSound.Playing or not ShootingHandle.FireSound.Looped then ShootingHandle.FireSound:Play() end
	local FireDirection = GetFireDirection(InputPos, ShootingHandle:FindFirstChild("GunFirePoint"))
	Player.PlayerScripts.BulletVisualizerScript.Visualize:Fire(nil,Tool,ShootingHandle,FireDirection,
		                                                        ShootingHandle:FindFirstChild("GunFirePoint"),
																{Module.HitEffectEnabled,Module.HitSoundIDs,Module.HitSoundPitch,Module.HitSoundVolume,script:WaitForChild("HitEffect"),Module.CustomHitEffect},
																{Module.BloodEnabled,Module.HitCharSndIDs,Module.HitCharSndPitch,Module.HitCharSndVolume,script:WaitForChild("BloodEffect")},
																{Module.BulletHoleEnabled,Module.BulletHoleSize,Module.BulletHoleTexture,Module.PartColor,Module.BulletHoleVisibleTime,Module.BulletHoleFadeTime},
													            {Module.FleshHole,Module.FleshHoleSize,Module.FleshHoleTexture,Module.FleshHoleColor,Module.FleshHoleVisibleTime,Module.FleshHoleFadeTime},
																{Module.ExplosiveEnabled,Module.ExplosionRadius,Module.ExplosionSoundEnabled,Module.ExplosionSoundIDs,Module.ExplosionSoundPitch,Module.ExplosionSoundVolume,Module.CustomExplosion,script:WaitForChild("ExplosionEffect")},
													            {Module.BulletTracerEnabled,Module.BulletTracerOffset0,Module.BulletTracerOffset1,script:WaitForChild("TracerEffect"),Module.BulletParticleEnaled,script:WaitForChild("ParticleEffect"),Module.Range,Module.BulletSpeed,Module.DropGravity,Module.WindOffset,Module.BulletSize,Module.BulletColor,Module.BulletTransparency,Module.BulletMaterial,Module.BulletShape,Module.BulletMeshEnabled,Module.BulletMeshID,Module.BulletTextureID,Module.BulletMeshScale},
													            {Module.BaseDamage,Module.HeadshotDamageMultiplier,Module.HeadshotEnabled},
	                                                            {Module.WhizSoundEnabled,Module.WhizSoundID,Module.WhizSoundVolume,Module.WhizSoundPitch},
	                                                            {Module.BulletLightEnabled,Module.BulletLightBrightness,Module.BulletLightColor,Module.BulletLightRange,Module.BulletLightShadows},
	                                                            {Module.Knockback, Module.Lifesteal, Module.FlamingBullet})
	VisualizeBullet:FireServer(Tool,ShootingHandle,FireDirection,
		                                            ShootingHandle:FindFirstChild("GunFirePoint"),
													{Module.HitEffectEnabled,Module.HitSoundIDs,Module.HitSoundPitch,Module.HitSoundVolume,script:WaitForChild("HitEffect"),Module.CustomHitEffect},
													{Module.BloodEnabled,Module.HitCharSndIDs,Module.HitCharSndPitch,Module.HitCharSndVolume,script:WaitForChild("BloodEffect")},
													{Module.BulletHoleEnabled,Module.BulletHoleSize,Module.BulletHoleTexture,Module.PartColor,Module.BulletHoleVisibleTime,Module.BulletHoleFadeTime},
													{Module.FleshHole,Module.FleshHoleSize,Module.FleshHoleTexture,Module.FleshHoleColor,Module.FleshHoleVisibleTime,Module.FleshHoleFadeTime},
													{Module.ExplosiveEnabled,Module.ExplosionRadius,Module.ExplosionSoundEnabled,Module.ExplosionSoundIDs,Module.ExplosionSoundPitch,Module.ExplosionSoundVolume,Module.CustomExplosion,script:WaitForChild("ExplosionEffect")},
													{Module.BulletTracerEnabled,Module.BulletTracerOffset0,Module.BulletTracerOffset1,script:WaitForChild("TracerEffect"),Module.BulletParticleEnaled,script:WaitForChild("ParticleEffect"),Module.Range,Module.BulletSpeed,Module.DropGravity,Module.WindOffset,Module.BulletSize,Module.BulletColor,Module.BulletTransparency,Module.BulletMaterial,Module.BulletShape,Module.BulletMeshEnabled,Module.BulletMeshID,Module.BulletTextureID,Module.BulletMeshScale},
													{Module.BaseDamage,Module.HeadshotDamageMultiplier,Module.HeadshotEnabled},
	                                                {Module.WhizSoundEnabled,Module.WhizSoundID,Module.WhizSoundVolume,Module.WhizSoundPitch},
	                                                {Module.BulletLightEnabled,Module.BulletLightBrightness,Module.BulletLightColor,Module.BulletLightRange,Module.BulletLightShadows},
	                                                {Module.Knockback, Module.Lifesteal, Module.FlamingBullet})
													
end

function Reload()
	if Enabled and not Reloading and (Ammo > 0 or not Module.LimitedAmmoEnabled) and Mag < Module.AmmoPerMag then
		Reloading = true
		if AimDown then
            TweeningService:Create(Camera, TweenInfo.new(Module.TweenLengthNAD, Module.EasingStyleNAD, Module.EasingDirectionNAD), {FieldOfView = 70}):Play()
			CrosshairModule:setcrossscale(1)
			--[[local GUI = game:GetService("Players").LocalPlayer.PlayerGui:FindFirstChild("ZoomGui")
			if GUI then GUI:Destroy() end]]
			Scoping = false
			game:GetService("Players").LocalPlayer.CameraMode = Enum.CameraMode.Classic
			UserInputService.MouseDeltaSensitivity = InitialSensitivity
			AimDown = false
		end
		UpdateGUI()
		if Module.ShotgunReload then
			for i = 1,(Module.AmmoPerMag - Mag) do
				if ShotgunClipinAnim then ShotgunClipinAnim:Play(nil,nil,Module.ShotgunClipinAnimationSpeed) end
				Handle.ShotgunClipin:Play()
				wait(Module.ShellClipinSpeed)
			end
		end
		if ReloadAnim then ReloadAnim:Play(nil,nil,Module.ReloadAnimationSpeed) end
		Handle.ReloadSound:Play()
		wait(Module.ReloadTime)
		if Module.LimitedAmmoEnabled then
		local ammoToUse = math.min(Module.AmmoPerMag - Mag, Ammo)
		Mag = Mag + ammoToUse
		Ammo = Ammo - ammoToUse
		else
	    Mag = Module.AmmoPerMag
		end
		ChangeMagAndAmmo:FireServer(Mag,Ammo)
		Reloading = false
		UpdateGUI()
	end
end

function UpdateGUI()
	GUI.Frame.Mag.Fill:TweenSizeAndPosition(UDim2.new(Mag/Module.AmmoPerMag,0,1,0), UDim2.new(0,0,0,0), Enum.EasingDirection.Out, Enum.EasingStyle.Quint, 0.25, true)
	GUI.Frame.Ammo.Fill:TweenSizeAndPosition(UDim2.new(Ammo/Module.MaxAmmo,0,1,0), UDim2.new(0,0,0,0), Enum.EasingDirection.Out, Enum.EasingStyle.Quint, 0.25, true)
	GUI.Frame.Mag.Current.Text = Mag
	GUI.Frame.Mag.Max.Text = Module.AmmoPerMag
	GUI.Frame.Ammo.Current.Text = Ammo
	GUI.Frame.Ammo.Max.Text = Module.MaxAmmo

	GUI.Frame.Mag.Current.Visible = not Reloading
	GUI.Frame.Mag.Max.Visible = not Reloading
	GUI.Frame.Mag.Frame.Visible = not Reloading
	GUI.Frame.Mag.Reloading.Visible = Reloading

	GUI.Frame.Ammo.Current.Visible = not (Ammo <= 0)
	GUI.Frame.Ammo.Max.Visible = not (Ammo <= 0)
	GUI.Frame.Ammo.Frame.Visible = not (Ammo <= 0)
	GUI.Frame.Ammo.NoMoreAmmo.Visible = (Ammo <= 0)
	
	GUI.Frame.Ammo.Visible = Module.LimitedAmmoEnabled
	GUI.Frame.Size = Module.LimitedAmmoEnabled and UDim2.new(0,250,0,100) or UDim2.new(0,250,0,55)
	GUI.Frame.Position = Module.LimitedAmmoEnabled and UDim2.new(2,0,1,0)or UDim2.new(2,0,1,0)
	GUI.MobileButtons.Visible = UserInputService.TouchEnabled --For mobile version
	GUI.MobileButtons.AimButton.Visible = Module.SniperEnabled or Module.IronsightEnabled
	GUI.MobileButtons.HoldDownButton.Visible = Module.HoldDownEnabled
end