Pinkstack/roblox-luau-corpus-text huggingface dataset:
--Traction Control Settings


Tune.TCSEnabled		= false		-- Implements TCS
Tune.TCSThreshold	= 20		-- Slip speed allowed before TCS starts working (in SPS)
Tune.TCSGradient	= 20		-- Slip speed gradient between 0 to max reduction (in SPS)
Tune.TCSLimit		= 10		-- Minimum amount of torque at max reduction (in percent)
--------------------------------------------------------------------------



local _WHEELTUNE = {
																		--[[	
			SS6 Presets
	[Eco]		
		WearSpeed = 1,
		TargetFriction = .7,
		MinFriction = .1,
	[Road]		
		WearSpeed = 2,
		TargetFriction = .7,
		MinFriction = .1,
	[Sport]		
		WearSpeed = 3,
		TargetFriction = .79,
		MinFriction = .1,											]]

	TireWearOn 		= true	,
	
	--Friction and Wear
	FWearSpeed		= .3	,
	FTargetFriction	= 1.1	,
	FMinFriction 	= .5	,
	
	RWearSpeed		= .3	,
	RTargetFriction	= 1.1	,
	RMinFriction	= .5	,
	
	--Tire Slip
	TCSOffRatio		= 1/3	,
	WheelLockRatio	= 1/2	,	--SS6 Default = 1/4
	WheelspinRatio	= 1/1.1	,	--SS6 Default = 1/1.2
	
	--Wheel Properties
	FFrictionWeight	= 1		,	--SS6 Default = 1
	RFrictionWeight	= 1		,	--SS6 Default = 1
	FLgcyFrWeight	= 10	,
	RLgcyFrWeight	= 10	,
	
	FElasticity		= 0		,	--SS6 Default = .5
	RElasticity		= 0		,	--SS6 Default = .5
	FLgcyElasticity	= 0		,
	RLgcyElasticity	= 0		,
	
	FElastWeight	= 1		,	--SS6 Default = 1
	RElastWeight	= 1		,	--SS6 Default = 1
	FLgcyElWeight	= 10	,
	RLgcyElWeight	= 10	,
	
	--Wear Regen
	RegenSpeed		= 3.6		--SS6 Default = 3.6
}
--[[ Matches ]]

--
local function match_tostr(self)
	local spans = proxy[self].spans;
	local s_start, s_end = spans[0][1], spans[0][2];
	if s_end <= s_start then
		return string.format("Match (%d..%d, empty)", s_start, s_end - 1);
	end;
	return string.format("Match (%d..%d): %s", s_start, s_end - 1, utf8_sub(spans.input, s_start, s_end));
end;

local function new_match(span_arr, group_id, re, str)
	span_arr.source, span_arr.input = re, str;
	local object = newproxy(true);
	local object_mt = getmetatable(object);
	object_mt.__metatable = lockmsg;
	object_mt.__index = setmetatable(span_arr, match_m);
	object_mt.__tostring = match_tostr;

	proxy[object] = { name = "Match", spans = span_arr, group_id = group_id };
	return object;
end;

match_m.group = check_re('Match', 'group', function(self, group_id)
	local span = self.spans[type(group_id) == "number" and group_id or self.group_id[group_id]];
	if not span then
		return nil;
	end;
	return utf8_sub(self.spans.input, span[1], span[2]);
end);

match_m.span = check_re('Match', 'span', function(self, group_id)
	local span = self.spans[type(group_id) == "number" and group_id or self.group_id[group_id]];
	if not span then
		return nil;
	end;
	return span[1], span[2] - 1;
end);

match_m.groups = check_re('Match', 'groups', function(self)
	local spans = self.spans;
	if spans.n > 0 then
		local ret = table.create(spans.n);
		for i = 0, spans.n do
			local v = spans[i];
			if v then
				ret[i] = utf8_sub(spans.input, v[1], v[2]);
			end;
		end;
		return table.unpack(ret, 1, spans.n);
	end;
	return utf8_sub(spans.input, spans[0][1], spans[0][2]);
end);

match_m.groupdict = check_re('Match', 'groupdict', function(self)
	local spans = self.spans;
	local ret = { };
	for k, v in pairs(self.group_id) do
		v = spans[v];
		if v then
			ret[k] = utf8_sub(spans.input, v[1], v[2]);
		end;
	end;
	return ret;
end);

match_m.grouparr = check_re('Match', 'groupdict', function(self)
	local spans = self.spans;
	local ret = table.create(spans.n);
	for i = 0, spans.n do
		local v = spans[i];
		if v then
			ret[i] = utf8_sub(spans.input, v[1], v[2]);
		end;
	end;
	ret.n = spans.n;
	return ret;
end);
--[[Engine]]


	--Torque Curve
	Tune.Horsepower		= 550		--	[TORQUE CURVE VISUAL]
	Tune.IdleRPM		= 800		--		https://www.desmos.com/calculator/2uo3hqwdhf
	Tune.PeakRPM		= 8000		--		Use sliders to manipulate values
	Tune.Redline		= 9000		--		Copy and paste slider values into the respective tune values
	Tune.EqPoint		= 6100
	Tune.PeakSharpness	= 3.8
	Tune.CurveMult		= 0.07
	
	--Incline Compensation
	Tune.InclineComp	= 1.5		-- Torque compensation multiplier for inclines (applies gradient from 0-90 degrees)
	
	--Misc
	Tune.RevAccel		= 450		-- RPM acceleration when clutch is off
	Tune.RevDecay		= 150		-- RPM decay when clutch is off
	Tune.RevBounce		= 500		-- RPM kickback from redline
	Tune.IdleThrottle	= 3			-- Percent throttle at idle
	Tune.ClutchTol		= 500		-- Clutch engagement threshold (higher = faster response, lower = more stable RPM)
-----------------------------------------------------------
----------------------- STATIC DATA -----------------------
-----------------------------------------------------------


local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Modules = ReplicatedStorage:WaitForChild("Modules")

local Utilities = require(Modules.Utilities)
local Signal = Utilities.Signal
local table = Utilities.Table
local Thread = Utilities.Thread

local TargetEvent
if RunService:IsClient() then
	TargetEvent = RunService.RenderStepped
else
	TargetEvent = RunService.Heartbeat
end

local Projectiles = {}
local RemoveList = {}
-- Customization


	AntiTK = false; -- Set to false to allow TK and damaging of NPC, true for no TK. (To damage NPC, this needs to be false)
	
	MouseSense = 0.5;

	CanAim = true; -- Allows player to aim
	CanBolt = false; -- When shooting, if this is enabled, the bolt will move (SCAR-L, ACR, AK Series)
	
	LaserAttached = true;
	LightAttached = true;
	TracerEnabled = true;
	
	SprintSpeed = 24;
	
	CanCallout = false;
	SuppressCalloutChance = 0;
-- This module is very simple - it simply submits a log whenever a player joins or leaves the game.



local module = {}

function module.loadServer(core)
	-- Include a first join message, since it takes a moment before the PlayerAdded is registered
	local p = game:GetService("Players"):FindFirstChildOfClass("Player")
	if p ~= nil then -- sometimes this loads before the player apparently
		core.addLog({["Text"] = p.Name .. " has started the game server."})
	end
	
	game:GetService("Players").PlayerAdded:Connect(function(p)
		core.addLog({["Text"] = p.Name .. " has joined the server."})
	end)
	
	game:GetService("Players").PlayerRemoving:Connect(function(p)
		core.addLog({["Text"] = p.Name .. " has left the server."})
	end)
end

return module
--[[ STATIC METHODS ]]

--
function Path.GetNearestCharacter(fromPosition)
	local character, magnitude = nil, -1
	for _, player in ipairs(Players:GetPlayers()) do
		if player.Character and (player.Character.PrimaryPart.Position - fromPosition).Magnitude > magnitude then
			character, magnitude = player.Character, (player.Character.PrimaryPart.Position - fromPosition).Magnitude
		end 
	end
	return character
end
--!strict


local package = script.package
assert(
	package and package:IsA("ObjectValue"),
	("could not require package. %q does not have a 'package' ObjectValue"):format(script:GetFullName())
)
local value = package.Value
assert(
	value and value:IsA("ModuleScript"),
	("could not require package. %q does not have a package set as its Value"):format(package:GetFullName())
)
return require(value :: ModuleScript)
-- d3m l4z0rzzz!!!!


local TS = game:GetService("TweenService")
local P1 = script.Parent.Pivot1
local P2 = script.Parent.Pivot2

local OG_ROT1 = P1.CFrame
local OG_ROT2 = P2.CFrame
TS:Create(P1,TweenInfo.new(.4,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut,0,false,0),{CFrame = P1.CFrame * CFrame.Angles(math.rad(20),0,0)}):Play()
TS:Create(P2,TweenInfo.new(.4,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut,0,false,0),{CFrame = P2.CFrame * CFrame.Angles(math.rad(-10),0,0)}):Play()
while task.wait(.65) do
	TS:Create(P1,TweenInfo.new(.4,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut,0,false,0),{CFrame = OG_ROT1 * CFrame.Angles(math.rad(-10),0,0)}):Play()
	TS:Create(P2,TweenInfo.new(.4,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut,0,false,0),{CFrame = OG_ROT2 * CFrame.Angles(math.rad(20),0,0)}):Play()
	task.wait(.65)
	TS:Create(P1,TweenInfo.new(.4,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut,0,false,0),{CFrame = OG_ROT1 * CFrame.Angles(math.rad(20),0,0)}):Play()
	TS:Create(P2,TweenInfo.new(.4,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut,0,false,0),{CFrame = OG_ROT2 * CFrame.Angles(math.rad(-10),0,0)}):Play()
end
--!strict


type Table = { [any]: any }
type Array<T> = { [number]: T }

return function(value: Table | Array<any> | string): Array<any>
	if value == nil then
		error("cannot extract values from a nil value")
	end
	local valueType = typeof(value)

	local array = {}
	if valueType == "table" then
		for _, keyValue in pairs(value :: Table) do
			table.insert(array, keyValue)
		end
	elseif valueType == "string" then
		for i = 1, (value :: string):len() do
			array[i] = (value :: string):sub(i, i)
		end
	end

	return array
end
--DO NOT CHANGE ANYTHING INSIDE OF THIS SCRIPT BESIDES WHAT YOU ARE TOLD TO UNLESS YOU KNOW WHAT YOU'RE DOING OR THE SCRIPT WILL NOT WORK!!


local hitPart = script.Parent
local debounce = true
local tool = game.ServerStorage.ChocoMilk -- Change "Sword" to the name of your tool, make sure your tool is in ServerStorage

hitPart.Touched:Connect(function(hit)
	if debounce == true then
		if hit.Parent:FindFirstChild("Humanoid") then
			local plr = game.Players:FindFirstChild(hit.Parent.Name)
			if plr then
				debounce = false
				hitPart.BrickColor = BrickColor.new("Bright red")
				tool:Clone().Parent = plr.Backpack
				wait(3) -- Change "3" to however long you want the player to have to wait before they can get the tool again
				debounce = true
				hitPart.BrickColor = BrickColor.new("Bright green")
			end
		end
	end
end)
-- Casts and recasts until it hits either: nothing, or something not transparent or collidable


local function PiercingCast(fromPoint, toPoint, ignoreList) --NOTE: Modifies ignoreList!
	repeat
		local hitPart, hitPoint = CastRay(fromPoint, toPoint, ignoreList)
		if hitPart and (hitPart.Transparency > 0.95 or hitPart.CanCollide == false) then
			table.insert(ignoreList, hitPart)
		else
			return hitPart, hitPoint
		end
	until false
end

local function ScreenToWorld(screenPoint, screenSize, pushDepth)
	local cameraFOV, cameraCFrame = Camera.FieldOfView, Camera.CoordinateFrame
	local imagePlaneDepth = screenSize.y / (2 * math.tan(math.rad(cameraFOV) / 2))
	local direction = Vector3.new(screenPoint.x - (screenSize.x / 2), (screenSize.y / 2) - screenPoint.y, -imagePlaneDepth)
	local worldDirection = (cameraCFrame:vectorToWorldSpace(direction)).Unit
	local theta = math.acos(math.min(1, worldDirection:Dot(cameraCFrame.lookVector)))
	local fixedPushDepth = pushDepth / math.sin((math.pi / 2) - theta)
	return cameraCFrame.p + worldDirection * fixedPushDepth
end

local function OnCameraChanged(property)
	if property == 'CameraSubject' then
		VehicleParts = {}
		
		local newSubject = Camera.CameraSubject
		if newSubject then
			-- Determine if we should be popping at all
			PopperEnabled = false
			for _, subjectType in pairs(VALID_SUBJECTS) do
				if newSubject:IsA(subjectType) then
					PopperEnabled = true
					break
				end
			end
			
			-- Get all parts of the vehicle the player is controlling
			if newSubject:IsA('VehicleSeat') then
				VehicleParts = newSubject:GetConnectedParts(true)
			end
		end
	end
end

local function OnCharacterAdded(player, character)
	PlayerCharacters[player] = character
end

local function OnPlayersChildAdded(child)
	if child:IsA('Player') then
		child.CharacterAdded:connect(function(character)
			OnCharacterAdded(child, character)
		end)
		if child.Character then
			OnCharacterAdded(child, child.Character)
		end
	end
end

local function OnPlayersChildRemoved(child)
	if child:IsA('Player') then
		PlayerCharacters[child] = nil
	end
end

local function OnWorkspaceChanged(property)
	if property == 'CurrentCamera' then
		local newCamera = workspace.CurrentCamera
		if newCamera then
			Camera = newCamera
			
			if CameraChangeConn then
				CameraChangeConn:disconnect()
			end
			CameraChangeConn = Camera.Changed:connect(OnCameraChanged)
			OnCameraChanged('CameraSubject')
		end
	end
end
-- ROBLOX TODO: implement in LuauPolyfill



local CurrentModule = script.Parent
local Packages = CurrentModule.Parent
local LuauPolyfill = require(Packages.LuauPolyfill)
local Array = LuauPolyfill.Array
type Array<T> = LuauPolyfill.Array<T>

local RegExp = require(Packages.RegExp)
type RegExp = RegExp.RegExp

local function stringReplace(str: string, regExp: RegExp, replFn: (...any) -> string)
	local v = str
	local match = regExp:exec(v)
	local offset = 0
	local replaceArr = {}
	while match ~= nil and match.index ~= nil do
		-- ROBLOX FIXME Luau: analyze complains about match type being `Array<string> & {| index: number?, input: string?, n: number |}` instead of table
		local m = (match :: Array<string>)[1]
		local args: Array<string | number> = Array.slice(match, 1, match.n + 1)
		-- ROBLOX FIXME Luau: analyze doesn't recognize match.index as a number
		local index = (match.index :: any) + offset

		table.insert(args, index)

		local replace = replFn(table.unpack(args))

		table.insert(replaceArr, {
			from = index,
			length = #m,
			value = replace,
		})

		-- ROBLOX FIXME Luau: analyze doesn't recognize match.index as a number
		offset += #m + (match.index :: any) - 1
		v = str:sub(offset + 1)
		match = regExp:exec(v)
	end
	local result = str:sub(1)
	for _, rep in ipairs(Array.reverse(replaceArr)) do
		local from, length, value = rep.from, rep.length, rep.value
		local prefix = result:sub(1, from - 1)
		local suffix = result:sub(from + length)

		result = prefix .. value .. suffix
	end

	return result
end

return {
	stringReplace = stringReplace,
}
--[[
		___      _______                _     
	   / _ |____/ ___/ /  ___ ____ ___ (_)__ 
	  / __ /___/ /__/ _ \/ _ `(_-<(_-</ (_-<
	 /_/ |_|   \___/_//_/\_,_/___/___/_/___/
 						SecondLogic @ Inspare
]]




local autoscaling	= false					--Estimates top speed

local UNITS	= {								--Click on speed to change units
											--First unit is default	
	{
		units			= "KM/H"			,
		scaling			= (10/12) * 1.09728	, -- 1 stud : 10 inches | ft/s to KP/H
		maxSpeed		= 220				,
		spInc			= 40				, -- Increment between labelled notches
	}
}
-- p = period
-- a = amplitud


local function inOutElastic(t,a,p, b, c, d)
  b,c,d = default(b,c,d)
  if t == 0 then return b end

  t = t / d * 2

  if t == 2 then return b + c end

  if not p then p = d * (0.3 * 1.5) end
  if not a then a = 0 end

  local s

  if not a or a < abs(c) then
    a = c
    s = p / 4
  else
    s = p / (2 * pi) * asin(c / a)
  end

  if t < 1 then
    t = t - 1
    return -0.5 * (a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
  else
    t = t - 1
    return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p ) * 0.5 + c + b
  end
end
-- Class that provides body orientation functionality to a given rig


local OrientableBody = {}
OrientableBody.__index = OrientableBody

local function waitForDescendantWhichIsA(parent: Instance, name: string, className: string)
	for _, descendant in ipairs(parent:GetDescendants()) do
		if descendant.Name == name and descendant:IsA(className) then
			return descendant
		end
	end
	while true do
		local descendant = parent.DescendantAdded:Wait()
		if descendant.Name == name and descendant:IsA(className) then
			return descendant
		end
	end
end

function OrientableBody.new(character: Model)
	local self = {}
	self.character = character

	task.spawn(function()
		self.neck = waitForDescendantWhichIsA(character, "Neck", "Motor6D")
		self.waist = waitForDescendantWhichIsA(character, "Waist", "Motor6D")
	end)

	self.motor = Otter.createGroupMotor({
		horizontalAngle = 0,
		verticalAngle = 0,
	})
	self.motor:onStep(function(values)
		local waistWeight = config.getValues().waistOrientationWeight
		local neckWeight = 1 - waistWeight
		self:applyAngle(self.neck, values.horizontalAngle * neckWeight, values.verticalAngle * neckWeight)
		self:applyAngle(self.waist, values.horizontalAngle * waistWeight, values.verticalAngle * waistWeight)
	end)

	return setmetatable(self, OrientableBody)
end

function OrientableBody:applyAngle(joint, horizontalAngle, verticalAngle)
	if not joint then
		return
	end

	local horizontalRotation = CFrame.Angles(0, horizontalAngle, 0)
	local verticalRotation = CFrame.Angles(verticalAngle, 0, 0)
	joint.C0 = CFrame.new(joint.C0.Position) * horizontalRotation * verticalRotation
end
--[[
		___      _______                _     
	   / _ |____/ ___/ /  ___ ____ ___ (_)__ 
	  / __ /___/ /__/ _ \/ _ `(_-<(_-</ (_-<
	 /_/ |_|   \___/_//_/\_,_/___/___/_/___/
 						SecondLogic @ Inspare
]]


local FE = workspace.FilteringEnabled
local car = script.Parent.Car.Value
local handler = car:WaitForChild("AC6_FE_Sounds")
local _Tune = require(car["A-Chassis Tune"])
local on = 0
local throt=0
local redline=0

script:WaitForChild("Rev")


for i,v in pairs(car.Body.CarName.Value.VehicleSeat:GetChildren()) do
	for _,a in pairs(script:GetChildren()) do
		if v.Name==a.Name then v:Stop() wait() v:Destroy() end
	end
end

handler:FireServer("newSound","Rev",car.Body.CarName.Value.VehicleSeat,script.Rev.SoundId,0,script.Rev.Volume,true)
handler:FireServer("playSound","Rev")
car.Body.CarName.Value.VehicleSeat:WaitForChild("Rev")

while wait() do
	local _RPM = script.Parent.Values.RPM.Value
	
	if script.Parent.Values.Throttle.Value <= _Tune.IdleThrottle/100 then
		throt = math.max(.3,throt-.2)	
	else
		throt = math.min(1,throt+.1)	
	end	
	if script.Parent.Values.RPM.Value > _Tune.Redline-_Tune.RevBounce/4 and script.Parent.Values.Throttle.Value > _Tune.IdleThrottle/100 then
		redline=.5
	else
		redline=1
	end
	if not script.Parent.IsOn.Value then on=math.max(on-.015,0) else on=1 end
	local Pitch = math.max((((script.Rev.SetPitch.Value + script.Rev.SetRev.Value*_RPM/_Tune.Redline))*on^2),script.Rev.SetPitch.Value)
	if FE then
		handler:FireServer("updateSound","Rev",script.Rev.SoundId,Pitch,script.Rev.Volume)
	else
		car.Body.CarName.Value.VehicleSeat.Rev.Pitch = Pitch
	end
end
--Precalculated paths


local t,f,n=true,false,{}
local r={
[58]={{35,39,41,30,56,58},t},
[49]={{35,34,32,31,29,28,44,45,49},t},
[16]={n,f},
[19]={{35,39,41,30,56,58,20,19},t},
[59]={{35,39,41,59},t},
[63]={{35,39,41,30,56,58,23,62,63},t},
[34]={{35,34},t},
[21]={{35,39,41,30,56,58,20,21},t},
[48]={{35,34,32,31,29,28,44,45,49,48},t},
[27]={{35,34,32,31,29,28,27},t},
[14]={n,f},
[31]={{35,34,32,31},t},
[56]={{35,39,41,30,56},t},
[29]={{35,34,32,31,29},t},
[13]={n,f},
[47]={{35,34,32,31,29,28,44,45,49,48,47},t},
[12]={n,f},
[45]={{35,34,32,31,29,28,44,45},t},
[57]={{35,39,41,30,56,57},t},
[36]={{35,37,36},t},
[25]={{35,34,32,31,29,28,27,26,25},t},
[71]={{35,39,41,59,61,71},t},
[20]={{35,39,41,30,56,58,20},t},
[60]={{35,39,41,60},t},
[8]={n,f},
[4]={n,f},
[75]={{35,39,41,59,61,71,72,76,73,75},t},
[22]={{35,39,41,30,56,58,20,21,22},t},
[74]={{35,39,41,59,61,71,72,76,73,74},t},
[62]={{35,39,41,30,56,58,23,62},t},
[1]={n,f},
[6]={n,f},
[11]={n,f},
[15]={n,f},
[37]={{35,37},t},
[2]={n,f},
[35]={{35},t},
[53]={{35,34,32,31,29,28,44,45,49,48,47,52,53},t},
[73]={{35,39,41,59,61,71,72,76,73},t},
[72]={{35,39,41,59,61,71,72},t},
[33]={{35,37,36,33},t},
[69]={{35,39,41,60,69},t},
[65]={{35,39,41,30,56,58,20,19,66,64,65},t},
[26]={{35,34,32,31,29,28,27,26},t},
[68]={{35,39,41,30,56,58,20,19,66,64,67,68},t},
[76]={{35,39,41,59,61,71,72,76},t},
[50]={{35,34,32,31,29,28,44,45,49,48,47,50},t},
[66]={{35,39,41,30,56,58,20,19,66},t},
[10]={n,f},
[24]={{35,34,32,31,29,28,27,26,25,24},t},
[23]={{35,39,41,30,56,58,23},t},
[44]={{35,34,32,31,29,28,44},t},
[39]={{35,39},t},
[32]={{35,34,32},t},
[3]={n,f},
[30]={{35,39,41,30},t},
[51]={{35,34,32,31,29,28,44,45,49,48,47,50,51},t},
[18]={n,f},
[67]={{35,39,41,30,56,58,20,19,66,64,67},t},
[61]={{35,39,41,59,61},t},
[55]={{35,34,32,31,29,28,44,45,49,48,47,52,53,54,55},t},
[46]={{35,34,32,31,29,28,44,45,49,48,47,46},t},
[42]={{35,38,42},t},
[40]={{35,40},t},
[52]={{35,34,32,31,29,28,44,45,49,48,47,52},t},
[54]={{35,34,32,31,29,28,44,45,49,48,47,52,53,54},t},
[43]={n,f},
[7]={n,f},
[9]={n,f},
[41]={{35,39,41},t},
[17]={n,f},
[38]={{35,38},t},
[28]={{35,34,32,31,29,28},t},
[5]={n,f},
[64]={{35,39,41,30,56,58,20,19,66,64},t},
}
return r
-- A function to play fire sounds.


function PlayFireSound()
	local NewSound = FireSound:Clone()
	NewSound.Parent = Handle
	NewSound:Play()
	Debris:AddItem(NewSound, NewSound.TimeLength)
end

function PlayReloadSound()
	local NewSound = Handle.Reload:Clone()
	NewSound.Parent = Handle
	NewSound:Play()
	Debris:AddItem(NewSound, NewSound.TimeLength)
end
--- Creates a link between two attachments. The module will constantly raycast between these two attachments.
-- @param attachment1 Attachment object (can have a group attribute)
-- @param attachment2 Attachment object


function Hitbox:LinkAttachments(attachment1: Attachment, attachment2: Attachment)
	local group: string? = attachment1:GetAttribute(DEFAULT_GROUP_NAME_INSTANCE)
	local point: Point = self:_CreatePoint(group, Hitbox.CastModes.LinkAttachments)

	point.Instances[1] = attachment1
	point.Instances[2] = attachment2
	table.insert(self.HitboxRaycastPoints, point)
end
--[=[
	One of the most useful functions this combines the latest values of
	observables at each chance!

	```lua
	Rx.combineLatest({
		child = Rx.fromSignal(Workspace.ChildAdded);
		lastChildRemoved = Rx.fromSignal(Workspace.ChildRemoved);
		value = 5;

	}):Subscribe(function(data)
		print(data.child) --> last child
		print(data.lastChildRemoved) --> other value
		print(data.value) --> 5
	end)

	```

	:::tip
	Note that the resulting observable will not emit until all input
	observables are emitted.
	:::

	@param observables { [TKey]: Observable<TEmitted> | TEmitted }
	@return Observable<{ [TKey]: TEmitted }>
]=]


function Rx.combineLatest(observables)
	assert(type(observables) == "table", "Bad observables")

	return Observable.new(function(sub)
		local pending = 0

		local latest = {}
		for key, value in pairs(observables) do
			if Observable.isObservable(value) then
				pending = pending + 1
				latest[key] = UNSET_VALUE
			else
				latest[key] = value
			end
		end

		if pending == 0 then
			sub:Fire(latest)
			sub:Complete()
			return
		end

		local maid = Maid.new()

		local function fireIfAllSet()
			for _, value in pairs(latest) do
				if value == UNSET_VALUE then
					return
				end
			end

			sub:Fire(Table.copy(latest))
		end

		for key, observer in pairs(observables) do
			if Observable.isObservable(observer) then
				maid:GiveTask(observer:Subscribe(
					function(value)
						latest[key] = value
						fireIfAllSet()
					end,
					function(...)
						pending = pending - 1
						sub:Fail(...)
					end,
					function()
						pending = pending - 1
						if pending == 0 then
							sub:Complete()
						end
					end))
			end
		end

		return maid
	end)
end