function getBaseDamage(N)local U=S.damageSettings.Start.Damage local F=S.damageSettings.Start.Dist local J=S.damageSettings.End.Damage local O=S.damageSettings.End.Dist return N<F*S.bulletSettings.Range and U or(N>=F*S.bulletSettings.Range and N<O*S.bulletSettings.Range)and numLerp(U,J,Map(N/S.bulletSettings.Range,F,O,0,1))or N>=O*S.bulletSettings.Range and J end function Damage(N,U,F,J,O,M)local z=S.damageSettings.Multipliers.Head local e=S.damageSettings.Multipliers.Chest local v=S.damageSettings.Multipliers.Limbs local w=getBaseDamage(O)if Humanoid.Health~=0 then local F=nil if N.Parent:IsA("\072\097\116")then table.insert(M,N)local z=Ray.new(U-J*.1,J*((S.bulletSettings.Range-O)+.1))local e,v,w=workspace:FindPartOnRayWithIgnoreList(z,M)if e then F=Damage(e,v,w,J,O+(v-U).magnitude,M)end else F=findFirstClass(N.Parent,"\072\117\109\097\110\111\105\100")if F and(F.Health>0 and isEnemy(F))then local U=Instance.new("\079\098\106\101\099\116\086\097\108\117\101")U.Value=Player U.Name="\099\114\101\097\116\111\114"U.Parent=F DS:AddItem(U,.3)local J=0 if N.Name=="\072\101\097\100"then J=w*RAND(z,z+.1,.01)elseif N.Name=="\084\111\114\115\111"then J=w*RAND(e,e+.1,.01)else J=w*RAND(v,v+.1,.01)end F:TakeDamage(J)markHit()end end return F end end function isWallIgnored(N)return N.Transparency>=S.penetrationSettings.transparencyThreshold or S.penetrationSettings.ignoreNonCanCollide and not N.CanCollide or isIgnored(N,S.penetrationSettings.ignoreCustom)end function penetrateWall(N,U,F,J,O,M,z,e)local v=isWallIgnored(N)local w=N.Parent:IsA("\072\097\116")and findFirstClass(N.Parent.Parent,"\072\117\109\097\110\111\105\100")or findFirstClass(N.Parent,"\072\117\109\097\110\111\105\100")local b=nil if w and w~=e then e=w b=Damage(N,U,J,F,z,{Char,ignoreModel})else e=nil end local s=w and(N.Parent:IsA("\072\097\116")and N.Parent.Parent or N.Parent)or N table.insert(O,s)local a=S.bulletSettings.Range-z local Y=Ray.new(U,F*(S.bulletSettings.Range-z))local j,C,W=workspace:FindPartOnRayWithIgnoreList(Y,O)local g=removeElement(O,s)local B=Ray.new(C+F*.1,-F*(a+1))local t,X,m=workspace:FindPartOnRayWithIgnoreList(B,O)local x=M+(v and 0 or(getNearestPoint(C,X,U)-U).magnitude)local I=z+(C-U).magnitude local G=Round(x,.001)>S.penetrationSettings.Dist or Round(I,.001)>S.bulletSettings.Range if not v then createBulletImpact:FireServer(N,U,J,F,w,gunIgnore,S)if not w then createShockwave:FireServer(U,S.shockwaveSettings.Radius,gunIgnore,S)end end if w and(w.Health>0 and(isEnemy(w)and w==b))then createBlood:FireServer(N,X,F,gunIgnore,S)end if G or not j then if not G and not v then createBulletImpact:FireServer(N,X,m,F,w,gunIgnore,S)if not w then createShockwave:FireServer(X,S.shockwaveSettings.Radius,gunIgnore,S)end end return N,U else if N==t and not v then createBulletImpact:FireServer(N,X,m,F,w,gunIgnore,S)if not w then createShockwave:FireServer(X,S.shockwaveSettings.Radius,gunIgnore,S)end end return penetrateWall(j,C,F,W,O,x,I,e)end end function PenetrateWall(N,U,F,J,O,M)local z=(N-J).magnitude local e,v=nil,nil local w,b=nil,nil local s={unpack(Ignore)}for F=1,10,1 do local J=Ray.new(N-U*.1,U*S.Penetration)local O,M=game.Workspace:FindPartOnRayWithIgnoreList(J,s)if O then local N=nil if O.Parent.ClassName=="\072\097\116"then N=findFirstClass(O.Parent.Parent,"\072\117\109\097\110\111\105\100")else N=findFirstClass(O.Parent,"\072\117\109\097\110\111\105\100")end if N and F~=1 then w,b=O,M break else e,v=O,M table.insert(s,O)end else break end end if e then if S.InstantHit then if w then Damage(w.Parent:FindFirstChild("\072\101\097\100"),b)return b else local w,b=nil,nil if F then w,b=AdvRayCast(v,U,S.BulletRange-z,{e,F.Parent,unpack(Ignore)})else w,b=AdvRayCast(v,U,S.BulletRange-z,{e;unpack(Ignore)})end Damage(w,b)local s=M+(v-N).magnitude local a=b if s<S.Penetration and w then a=PenetrateWall(b,U,F,J,O,M+s)end return a end else local s=v local a=0 spawn(function()if w then Damage(w.Parent:FindFirstChild("\072\101\097\100"),b)return b else while true do RS.RenderStepped:wait()if a>=S.BulletRange-z then O:Destroy()break end local w=(O.Position-s).magnitude local b=(O.Position-s).unit local Y,j=nil,nil if F then Y,j=AdvRayCast(s,b,w,{e;F.Parent;unpack(Ignore)})else Y,j=AdvRayCast(s,b,w,{e;unpack(Ignore)})end if Y then Damage(Y,j)local z=M+(v-N).magnitude local e=j if z<S.Penetration and Y then e=PenetrateWall(j,U,F,J,O,M+z)else O:Destroy()end return e else s=O.Position a=a+w end end end end)end else if O then O:Destroy()end return N end end function isEnemy(N)local U=game.Players:GetPlayerFromCharacter(N.Parent)if not U then return S.CanDamageNPCs end return S.AllowFriendlyFire or U.TeamColor~=Player.TeamColor or U.Neutral end
--------------------[ HIT HANDLING FUNCTIONS ]----------------------------------------

function getBaseDamage(Dist)
	local startDmg = S.damageSettings.Start.Damage
	local startDist = S.damageSettings.Start.Dist
	local endDmg = S.damageSettings.End.Damage
	local endDist = S.damageSettings.End.Dist
	return (
		(Dist < startDist * S.bulletSettings.Range) and startDmg
		or (Dist >= startDist * S.bulletSettings.Range and Dist < endDist * S.bulletSettings.Range) and numLerp(
			startDmg,
			endDmg,
			Map(Dist / S.bulletSettings.Range, startDist, endDist, 0, 1)
		)
		or (Dist >= endDist * S.bulletSettings.Range) and endDmg
	)
end

function Damage(H, P, N, D, Dist, customIgnore)
	local hVal = S.damageSettings.Multipliers.Head
	local cVal = S.damageSettings.Multipliers.Chest
	local lVal = S.damageSettings.Multipliers.Limbs
	local baseDamage = getBaseDamage(Dist)
	if Humanoid.Health ~= 0 then
		local hitHumanoid = nil
		if H.Parent:IsA("Hat") then
			table.insert(customIgnore, H)
			local newRay = Ray.new(P - D * 0.1, D * (S.bulletSettings.Range - Dist + 0.1))
			local newH, newP, newN = workspace:FindPartOnRayWithIgnoreList(newRay, customIgnore)
			if newH then
				hitHumanoid = Damage(newH, newP, newN, D, Dist + (newP - P).magnitude, customIgnore)
			end
		else
			hitHumanoid = findFirstClass(H.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)
				local chosenDamage = 0
				if H.Name == "Head" then
					chosenDamage = baseDamage * RAND(hVal, hVal + 0.1, 0.01)
				elseif H.Name == "Torso" then
					chosenDamage = baseDamage * RAND(cVal, cVal + 0.1, 0.01)
				else
					chosenDamage = baseDamage * RAND(lVal, lVal + 0.1, 0.01)
				end
				hitHumanoid:TakeDamage(chosenDamage)
				markHit()
			end
		end
		return hitHumanoid
	end
end

function isWallIgnored(Wall)
	return (
		Wall.Transparency >= S.penetrationSettings.transparencyThreshold
		or (S.penetrationSettings.ignoreNonCanCollide and not Wall.CanCollide)
		or isIgnored(Wall, S.penetrationSettings.ignoreCustom)
	)
end

function penetrateWall(Wall, hitPos, Direction, Normal, Ignore, totalPDist, totalBDist, lastDamagedHumanoid)
	local wallIgnore = isWallIgnored(Wall)
	local hitHumanoid = (
		Wall.Parent:IsA("Hat") and findFirstClass(Wall.Parent.Parent, "Humanoid")
		or findFirstClass(Wall.Parent, "Humanoid")
	)
	local damagedHumanoid = nil
	if hitHumanoid and hitHumanoid ~= lastDamagedHumanoid then
		lastDamagedHumanoid = hitHumanoid
		damagedHumanoid = Damage(Wall, hitPos, Normal, Direction, totalBDist, { Char, ignoreModel })
	else
		lastDamagedHumanoid = nil
	end
	local ignoreObject = hitHumanoid and (Wall.Parent:IsA("Hat") and Wall.Parent.Parent or Wall.Parent) or Wall
	table.insert(Ignore, ignoreObject)
	local rayLength = S.bulletSettings.Range - totalBDist
	local testRay = Ray.new(hitPos, Direction * (S.bulletSettings.Range - totalBDist))
	local H1, P1, N1 = workspace:FindPartOnRayWithIgnoreList(testRay, Ignore)
	local newIgnore = removeElement(Ignore, ignoreObject)
	local wallRay = Ray.new(P1 + Direction * 0.1, -Direction * (rayLength + 1))
	local H2, P2, N2 = workspace:FindPartOnRayWithIgnoreList(wallRay, Ignore)
	local newPDist = totalPDist + (wallIgnore and 0 or (getNearestPoint(P1, P2, hitPos) - hitPos).magnitude)
	local newBDist = totalBDist + (P1 - hitPos).magnitude
	local outOfRange = Round(newPDist, 0.001) > S.penetrationSettings.Dist
		or Round(newBDist, 0.001) > S.bulletSettings.Range
	if not wallIgnore then
		createBulletImpact:FireServer(Wall, hitPos, Normal, Direction, hitHumanoid, gunIgnore, S)
		if not hitHumanoid then
			createShockwave:FireServer(hitPos, S.shockwaveSettings.Radius, gunIgnore, S)
		end
	end
	if hitHumanoid and hitHumanoid.Health > 0 and isEnemy(hitHumanoid) and hitHumanoid == damagedHumanoid then
		createBlood:FireServer(Wall, P2, Direction, gunIgnore, S)
	end
	if outOfRange or not H1 then
		if (not outOfRange) and not wallIgnore then
			createBulletImpact:FireServer(Wall, P2, N2, Direction, hitHumanoid, gunIgnore, S)
			if not hitHumanoid then
				createShockwave:FireServer(P2, S.shockwaveSettings.Radius, gunIgnore, S)
			end
		end
		return Wall, hitPos
	else
		if Wall == H2 and not wallIgnore then
			createBulletImpact:FireServer(Wall, P2, N2, Direction, hitHumanoid, gunIgnore, S)
			if not hitHumanoid then
				createShockwave:FireServer(P2, S.shockwaveSettings.Radius, gunIgnore, S)
			end
		end
		return penetrateWall(H1, P1, Direction, N1, Ignore, newPDist, newBDist, lastDamagedHumanoid)
	end
end

function PenetrateWall(HitPos, Direction, HitHumanoid, OriginPos, Bullet, CurrentPDist)
	local HitDist = (HitPos - OriginPos).magnitude
	local Wall, WallHitPos = nil, nil
	local Hum, HumHitPos = nil, nil
	local CustomIgnore = { unpack(Ignore) }
	for i = 1, 10 do
		local WallRay = Ray.new(HitPos - (Direction * 0.1), Direction * S.Penetration)
		local H, P = game.Workspace:FindPartOnRayWithIgnoreList(WallRay, CustomIgnore)
		if H then
			local HitHumanoid = nil
			if H.Parent.ClassName == "Hat" then
				HitHumanoid = findFirstClass(H.Parent.Parent, "Humanoid")
			else
				HitHumanoid = findFirstClass(H.Parent, "Humanoid")
			end
			if HitHumanoid and i ~= 1 then
				Hum, HumHitPos = H, P
				break
			else
				Wall, WallHitPos = H, P
				table.insert(CustomIgnore, H)
			end
		else
			break
		end
	end
	if Wall then
		if S.InstantHit then
			if Hum then
				Damage(Hum.Parent:FindFirstChild("Head"), HumHitPos)
				return HumHitPos
			else
				local HitObj2, HitPos2 = nil, nil
				if HitHumanoid then
					HitObj2, HitPos2 = AdvRayCast(
						WallHitPos,
						Direction,
						S.BulletRange - HitDist,
						{ Wall, HitHumanoid.Parent, unpack(Ignore) }
					)
				else
					HitObj2, HitPos2 =
						AdvRayCast(WallHitPos, Direction, S.BulletRange - HitDist, { Wall, unpack(Ignore) })
				end
				Damage(HitObj2, HitPos2)

				local NewPDist = CurrentPDist + (WallHitPos - HitPos).magnitude
				local NewHitPos2 = HitPos2
				if NewPDist < S.Penetration and HitObj2 then
					NewHitPos2 =
						PenetrateWall(HitPos2, Direction, HitHumanoid, OriginPos, Bullet, CurrentPDist + NewPDist)
				end
				return NewHitPos2
			end
		else
			local LastPos = WallHitPos
			local TotalDistTraveled = 0
			spawn(function()
				if Hum then
					Damage(Hum.Parent:FindFirstChild("Head"), HumHitPos)
					return HumHitPos
				else
					while true do
						RS.RenderStepped:wait()
						if TotalDistTraveled >= S.BulletRange - HitDist then
							Bullet:Destroy()
							break
						end
						local DistTraveled = (Bullet.Position - LastPos).magnitude
						local NewDirection = (Bullet.Position - LastPos).unit
						local TempHitObj, TempHitPos = nil, nil
						if HitHumanoid then
							TempHitObj, TempHitPos = AdvRayCast(
								LastPos,
								NewDirection,
								DistTraveled,
								{ Wall, HitHumanoid.Parent, unpack(Ignore) }
							)
						else
							TempHitObj, TempHitPos =
								AdvRayCast(LastPos, NewDirection, DistTraveled, { Wall, unpack(Ignore) })
						end
						if TempHitObj then
							Damage(TempHitObj, TempHitPos)

							local NewPDist = CurrentPDist + (WallHitPos - HitPos).magnitude
							local NewTempPos = TempHitPos
							if NewPDist < S.Penetration and TempHitObj then
								NewTempPos = PenetrateWall(
									TempHitPos,
									Direction,
									HitHumanoid,
									OriginPos,
									Bullet,
									CurrentPDist + NewPDist
								)
							else
								Bullet:Destroy()
							end
							return NewTempPos
						else
							LastPos = Bullet.Position
							TotalDistTraveled = TotalDistTraveled + DistTraveled
						end
					end
				end
			end)
		end
	else
		if Bullet then
			Bullet:Destroy()
		end
		return HitPos
	end
end

function isEnemy(Human)
	local Plyr = game.Players:GetPlayerFromCharacter(Human.Parent)
	if not Plyr then
		return S.CanDamageNPCs
	end
	return S.AllowFriendlyFire or (Plyr.TeamColor ~= Player.TeamColor or Plyr.Neutral)
end
