--------------------[ HIT HANDLING FUNCTIONS ]----------------------------------------

function Damage(HitObj, HitPos)
	local HeadVal = S.Multipliers.Head
	local ChestVal = S.Multipliers.Chest
	local LimbsVal = S.Multipliers.Limbs
	if Humanoid.Health ~= 0 then
		if HitObj and HitObj.Parent then
			local HumanoidFound = false
			local HitHumanoid = nil
			if HitObj.Parent.ClassName == "Hat" then
				if FindFirstClass(HitObj.Parent.Parent, "Humanoid") then
					HitHumanoid = FindFirstClass(HitObj.Parent.Parent, "Humanoid")
					HumanoidFound = true
					if HitHumanoid.Health > 0 then
						if IsEnemy(HitHumanoid) then
							local CreatorTag = Instance.new("ObjectValue")
							CreatorTag.Value = Player
							CreatorTag.Name = "creator"
							CreatorTag.Parent = HitHumanoid
							HitHumanoid:TakeDamage(S.Damage * RAND(HeadVal, HeadVal + 0.1, 0.01))
							MarkHit()
						end
					end
				end
			else
				if FindFirstClass(HitObj.Parent, "Humanoid") then
					HitHumanoid = FindFirstClass(HitObj.Parent, "Humanoid")
					HumanoidFound = true
					if HitHumanoid.Health > 0 then
						if IsEnemy(HitHumanoid) then
							local CreatorTag = Instance.new("ObjectValue")
							CreatorTag.Value = Player
							CreatorTag.Name = "creator"
							CreatorTag.Parent = HitHumanoid
							local ChosenDamage = 0
							if HitObj.Name == "Head" then
								ChosenDamage = S.Damage * RAND(HeadVal, HeadVal + 0.1, 0.01)
							elseif HitObj.Name == "Torso" then
								ChosenDamage = S.Damage * RAND(ChestVal, ChestVal + 0.1, 0.01)
							else
								ChosenDamage = S.Damage * RAND(LimbsVal, LimbsVal + 0.1, 0.01)
							end
							HitHumanoid:TakeDamage(ChosenDamage)
							MarkHit()
						end
					end
				end
			end
			if (not HumanoidFound) then
				if S.BulletHoles then
					CreateBulletHole(HitPos, HitObj)
				end
				if S.Shockwaves then
					CreateShockwave(HitPos, S.ShockwaveRadius)
				end
			end
			return HitHumanoid
		end
	end
end

function PenetrateWall(HitPos, Direction, HitHumanoid, OriginPos, Bullet)
	local HitDist = (HitPos - OriginPos).magnitude
	local Thickness, Wall, WallHitPos = 0, nil, nil
	for i = 0.1, S.Penetration, 0.1 do
		local WallRay = Ray.new(HitPos + (Direction * i), -Direction)
		local TempWall, TempWallHitPos = game.Workspace:FindPartOnRayWithIgnoreList(WallRay, Ignore)
		if TempWall then
			Thickness = i
			Wall, WallHitPos = TempWall, TempWallHitPos
			break
		end
	end
	if Wall then
		CreateBulletHole(WallHitPos, Wall)
		if S.InstantHit then
			local HitObj2, HitPos2 = nil, nil
			if HitHumanoid then
				HitObj2, HitPos2 = AdvRayCast(WallHitPos, Direction, S.BulletRange - HitDist, {HitHumanoid.Parent,unpack(Ignore)})
			else
				HitObj2, HitPos2 = AdvRayCast(WallHitPos, Direction, S.BulletRange - HitDist)
			end
			Damage(HitObj2, HitPos2)
			return HitPos2
		else
			local LastPos = WallHitPos
			local TotalDistTraveled = 0
			spawn(function()
				while true do
					RS: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, {HitHumanoid.Parent,unpack(Ignore)})
					else
						TempHitObj, TempHitPos = AdvRayCast(LastPos, NewDirection, DistTraveled)
					end
					if TempHitObj then
						Damage(TempHitObj, TempHitPos)
						Bullet:Destroy()
						return TempHitPos
					else
						LastPos = Bullet.Position
						TotalDistTraveled = TotalDistTraveled + DistTraveled
					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