local D={}D.CollisionMode=CollisionMode function D.Enable(V,D)if D~=nil and typeof(D)~="\084\119\101\101\110\073\110\102\111"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\069\110\097\098\108\101\' \040\084\119\101\101\110\073\110\102\111 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)end disconnectLoop()Emitter.RainStraight.Enabled=true Emitter.RainTopDown.Enabled=true Emitter.Parent=workspace.CurrentCamera for D=1,RAIN_SPLASH_NUM,1 do splashAttachments[D].Parent=workspace.Terrain rainAttachments[D].Parent=workspace.Terrain end if RunService:IsRunning()then SoundGroup.Parent=game:GetService("\083\111\117\110\100\083\101\114\118\105\099\101")end connectLoop()if D then(TweenService:Create(GlobalModifier,D,{Value=0})):Play()else GlobalModifier.Value=0 end if not Sound.Playing then Sound:Play()Sound.TimePosition=math.random()*Sound.TimeLength end disabled=false end function D.Disable(V,D)if D~=nil and typeof(D)~="\084\119\101\101\110\073\110\102\111"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\068\105\115\097\098\108\101\' \040\084\119\101\101\110\073\110\102\111 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)end if D then local V=TweenService:Create(GlobalModifier,D,{Value=1})V.Completed:connect(function(D)if D==Enum.PlaybackState.Completed then disable()end V:Destroy()end)V:Play()disableSound(D)else GlobalModifier.Value=1 disable()end disabled=true end function D.SetColor(x,D,V)if typeof(D)~="\067\111\108\111\114\051"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\067\111\108\111\114\' \040\067\111\108\111\114\051 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)elseif V~=nil and typeof(V)~="\084\119\101\101\110\073\110\102\111"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\067\111\108\111\114\' \040\084\119\101\101\110\073\110\102\111 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(V).."\041"),2)end if V then(TweenService:Create(Color,V,{Value=D})):Play()else Color.Value=D end end local function V(D,V)return function(x,k,u)if typeof(k)~="\110\117\109\098\101\114"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'"..(D..("\' \040\110\117\109\098\101\114 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(k).."\041"))),2)elseif u~=nil and typeof(u)~="\084\119\101\101\110\073\110\102\111"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'"..(D..("\' \040\084\119\101\101\110\073\110\102\111 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(u).."\041"))),2)end k=math.clamp(k,0,1)if u then(TweenService:Create(V,u,{Value=k})):Play()else V.Value=k end end end D.SetTransparency=V("\083\101\116\084\114\097\110\115\112\097\114\101\110\099\121",Transparency)D.SetSpeedRatio=V("\083\101\116\083\112\101\101\100\082\097\116\105\111",SpeedRatio)D.SetIntensityRatio=V("\083\101\116\073\110\116\101\110\115\105\116\121\082\097\116\105\111",IntensityRatio)D.SetLightEmission=V("\083\101\116\076\105\103\104\116\069\109\105\115\115\105\111\110",LightEmission)D.SetLightInfluence=V("\083\101\116\076\105\103\104\116\073\110\102\108\117\101\110\099\101",LightInfluence)function D.SetVolume(x,D,V)if typeof(D)~="\110\117\109\098\101\114"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\086\111\108\117\109\101\' \040\110\117\109\098\101\114 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)elseif V~=nil and typeof(V)~="\084\119\101\101\110\073\110\102\111"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\086\111\108\117\109\101\' \040\084\119\101\101\110\073\110\102\111 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(V).."\041"),2)end if V then(TweenService:Create(SoundGroup,V,{Volume=D})):Play()else SoundGroup.Volume=D end end function D.SetDirection(x,D,V)if typeof(D)~="\086\101\099\116\111\114\051"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\068\105\114\101\099\116\105\111\110\' \040\086\101\099\116\111\114\051 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)elseif V~=nil and typeof(V)~="\084\119\101\101\110\073\110\102\111"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\068\105\114\101\099\116\105\111\110\' \040\084\119\101\101\110\073\110\102\111 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(V).."\041"),2)end if not(D.unit.magnitude>0)then warn("\065\116\116\101\109\112\116 \116\111 \115\101\116 \114\097\105\110 \100\105\114\101\099\116\105\111\110 \116\111 \097 \122\101\114\111-\108\101\110\103\116\104 \118\101\099\116\111\114\044 \102\097\108\108\105\110\103 \098\097\099\107 \111\110 \100\101\102\097\117\108\116 \100\105\114\101\099\116\105\111\110 \061 \040"..(tostring(RAIN_DEFAULT_DIRECTION).."\041"))D=RAIN_DEFAULT_DIRECTION end if V then(TweenService:Create(RainDirection,V,{Value=D})):Play()else RainDirection.Value=D end end function D.SetCeiling(V,D)if D~=nil and typeof(D)~="\110\117\109\098\101\114"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\067\101\105\108\105\110\103\' \040\110\117\109\098\101\114 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)end currentCeiling=D end function D.SetStraightTexture(V,D)if typeof(D)~="\115\116\114\105\110\103"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\083\116\114\097\105\103\104\116\084\101\120\116\117\114\101\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)end Emitter.RainStraight.Texture=D for V,x in pairs(rainAttachments)do x.RainStraight.Texture=D end end function D.SetTopDownTexture(V,D)if typeof(D)~="\115\116\114\105\110\103"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\083\116\114\097\105\103\104\116\084\101\120\116\117\114\101\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)end Emitter.RainTopDown.Texture=D for V,x in pairs(rainAttachments)do x.RainTopDown.Texture=D end end function D.SetSplashTexture(V,D)if typeof(D)~="\115\116\114\105\110\103"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\083\116\114\097\105\103\104\116\084\101\120\116\117\114\101\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)end for V,x in pairs(splashAttachments)do x.RainSplash.Texture=D end end function D.SetSoundId(V,D)if typeof(D)~="\115\116\114\105\110\103"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\083\111\117\110\100\073\100\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(D).."\041"),2)end Sound.SoundId=D end function D.SetCollisionMode(x,D,V)if D==CollisionMode.None then collisionList=nil collisionFunc=nil elseif D==CollisionMode.Blacklist then if typeof(V)=="\073\110\115\116\097\110\099\101"then collisionList={V,Emitter}elseif typeof(V)=="\116\097\098\108\101"then for D=1,#V,1 do if typeof(V[D])~="\073\110\115\116\097\110\099\101"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\067\111\108\108\105\115\105\111\110\077\111\100\101\' \040\098\108\097\099\107\108\105\115\116 \099\111\110\116\097\105\110\101\100 \097 "..(typeof(V[D])..(" \111\110 \105\110\100\101\120 "..(tostring(D).." \119\104\105\099\104 \105\115 \110\111\116 \097\110 \073\110\115\116\097\110\099\101\041"))),2)end end collisionList={Emitter}for D=1,#V,1 do table.insert(collisionList,V[D])end else error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\067\111\108\108\105\115\105\111\110\077\111\100\101 \040\073\110\115\116\097\110\099\101 \111\114 \097\114\114\097\121 \111\102 \073\110\115\116\097\110\099\101 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(V).."\041\'"),2)end collisionFunc=nil elseif D==CollisionMode.Whitelist then if typeof(V)=="\073\110\115\116\097\110\099\101"then collisionList={V}elseif typeof(V)=="\116\097\098\108\101"then for D=1,#V,1 do if typeof(V[D])~="\073\110\115\116\097\110\099\101"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\067\111\108\108\105\115\105\111\110\077\111\100\101\' \040\119\104\105\116\101\108\105\115\116 \099\111\110\116\097\105\110\101\100 \097 "..(typeof(V[D])..(" \111\110 \105\110\100\101\120 "..(tostring(D).." \119\104\105\099\104 \105\115 \110\111\116 \097\110 \073\110\115\116\097\110\099\101\041"))),2)end end collisionList={}for D=1,#V,1 do table.insert(collisionList,V[D])end else error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\067\111\108\108\105\115\105\111\110\077\111\100\101 \040\073\110\115\116\097\110\099\101 \111\114 \097\114\114\097\121 \111\102 \073\110\115\116\097\110\099\101 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(V).."\041\'"),2)end collisionFunc=nil elseif D==CollisionMode.Function then if typeof(V)~="\102\117\110\099\116\105\111\110"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \'\083\101\116\067\111\108\108\105\115\105\111\110\077\111\100\101\' \040\102\117\110\099\116\105\111\110 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(V).."\041"),2)end collisionList=nil collisionFunc=V else error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\067\111\108\108\105\115\105\111\110\077\111\100\101 \040\082\097\105\110\046\067\111\108\108\105\115\105\111\110\077\111\100\101 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(V).."\041\'"),2)end collisionMode=D raycast=raycastFunctions[D]end return D


local Rain = {}

Rain.CollisionMode = CollisionMode

function Rain:Enable(tweenInfo)
	
	if tweenInfo ~= nil and typeof(tweenInfo) ~= "TweenInfo" then
		error("bad argument #1 to 'Enable' (TweenInfo expected, got " .. typeof(tweenInfo) .. ")", 2)
	end
	
	disconnectLoop() -- Just in case :Enable(..) is called multiple times on accident
	
	Emitter.RainStraight.Enabled = true
	Emitter.RainTopDown.Enabled = true
	Emitter.Parent = workspace.CurrentCamera
	
	for i = 1, RAIN_SPLASH_NUM do
		splashAttachments[i].Parent = workspace.Terrain
		rainAttachments[i].Parent = workspace.Terrain
	end
	
	if RunService:IsRunning() then -- don't need sound in studio preview, it won't work anyway
		SoundGroup.Parent = game:GetService("SoundService")
	end
	
	connectLoop()
	
	if tweenInfo then
		TweenService:Create(GlobalModifier, tweenInfo, {Value = 0}):Play()
	else
		GlobalModifier.Value = 0
	end
	
	if not Sound.Playing then
		Sound:Play()
		Sound.TimePosition = math.random()*Sound.TimeLength
	end
	
	disabled = false
	
end

function Rain:Disable(tweenInfo)
	
	if tweenInfo ~= nil and typeof(tweenInfo) ~= "TweenInfo" then
		error("bad argument #1 to 'Disable' (TweenInfo expected, got " .. typeof(tweenInfo) .. ")", 2)
	end
	
	if tweenInfo then
		local tween = TweenService:Create(GlobalModifier, tweenInfo, {Value = 1})
		tween.Completed:connect(function(state)
			if state == Enum.PlaybackState.Completed then
				-- Only disable the rain completely once the visual effects are faded out
				disable()
			end
			tween:Destroy()
		end)
		tween:Play()
		-- Start tweening out sound now as well
		disableSound(tweenInfo)
	else
		GlobalModifier.Value = 1
		disable()
	end
	
	disabled = true
	
end

function Rain:SetColor(value, tweenInfo)
		
	if typeof(value) ~= "Color3" then
		error("bad argument #1 to 'SetColor' (Color3 expected, got " .. typeof(value) .. ")", 2)
	elseif tweenInfo ~= nil and typeof(tweenInfo) ~= "TweenInfo" then
		error("bad argument #2 to 'SetColor' (TweenInfo expected, got " .. typeof(tweenInfo) .. ")", 2)
	end
	
	if tweenInfo then
		TweenService:Create(Color, tweenInfo, {Value = value}):Play()
	else
		Color.Value = value
	end
	
end

local function makeRatioSetter(methodName, valueObject)
	-- Shorthand because most of the remaining property setters are very similar
	return function(_, value, tweenInfo)
		
		if typeof(value) ~= "number" then
			error("bad argument #1 to '" .. methodName .. "' (number expected, got " .. typeof(value) .. ")", 2)
		elseif tweenInfo ~= nil and typeof(tweenInfo) ~= "TweenInfo" then
			error("bad argument #2 to '" .. methodName .. "' (TweenInfo expected, got " .. typeof(tweenInfo) .. ")", 2)
		end
		
		value = math.clamp(value, 0, 1)
		
		if tweenInfo then
			TweenService:Create(valueObject, tweenInfo, {Value = value}):Play()
		else
			valueObject.Value = value
		end
		
	end
end

Rain.SetTransparency = makeRatioSetter("SetTransparency", Transparency)
Rain.SetSpeedRatio = makeRatioSetter("SetSpeedRatio", SpeedRatio)
Rain.SetIntensityRatio = makeRatioSetter("SetIntensityRatio", IntensityRatio)
Rain.SetLightEmission = makeRatioSetter("SetLightEmission", LightEmission)
Rain.SetLightInfluence = makeRatioSetter("SetLightInfluence", LightInfluence)

function Rain:SetVolume(volume, tweenInfo)
	
	if typeof(volume) ~= "number" then
		error("bad argument #1 to 'SetVolume' (number expected, got " .. typeof(volume) .. ")", 2)
	elseif tweenInfo ~= nil and typeof(tweenInfo) ~= "TweenInfo" then
		error("bad argument #2 to 'SetVolume' (TweenInfo expected, got " .. typeof(tweenInfo) .. ")", 2)
	end
	
	if tweenInfo then
		TweenService:Create(SoundGroup, tweenInfo, {Volume = volume}):Play()
	else
		SoundGroup.Volume = volume
	end
	
end

function Rain:SetDirection(direction, tweenInfo)
	
	if typeof(direction) ~= "Vector3" then
		error("bad argument #1 to 'SetDirection' (Vector3 expected, got " .. typeof(direction) .. ")", 2)
	elseif tweenInfo ~= nil and typeof(tweenInfo) ~= "TweenInfo" then
		error("bad argument #2 to 'SetDirection' (TweenInfo expected, got " .. typeof(tweenInfo) .. ")", 2)
	end
	
	if not (direction.unit.magnitude > 0) then -- intentional statement formatting since NaN comparison
		warn("Attempt to set rain direction to a zero-length vector, falling back on default direction = (" .. tostring(RAIN_DEFAULT_DIRECTION) .. ")")
		direction = RAIN_DEFAULT_DIRECTION
	end
	
	if tweenInfo then
		TweenService:Create(RainDirection, tweenInfo, {Value = direction}):Play()
	else
		RainDirection.Value = direction
	end
	
end

function Rain:SetCeiling(ceiling)
	
	if ceiling ~= nil and typeof(ceiling) ~= "number" then
		error("bad argument #1 to 'SetCeiling' (number expected, got " .. typeof(ceiling) .. ")", 2)
	end
	
	currentCeiling = ceiling
	
end

function Rain:SetStraightTexture(asset)
	
	if typeof(asset) ~= "string" then
		error("bad argument #1 to 'SetStraightTexture' (string expected, got " .. typeof(asset) .. ")", 2)
	end
	
	Emitter.RainStraight.Texture = asset
	
	for _,v in pairs(rainAttachments) do
		v.RainStraight.Texture = asset
	end
	
end

function Rain:SetTopDownTexture(asset)
	
	if typeof(asset) ~= "string" then
		error("bad argument #1 to 'SetStraightTexture' (string expected, got " .. typeof(asset) .. ")", 2)
	end
	
	Emitter.RainTopDown.Texture = asset
	
	for _,v in pairs(rainAttachments) do
		v.RainTopDown.Texture = asset
	end
	
end

function Rain:SetSplashTexture(asset)
	
	if typeof(asset) ~= "string" then
		error("bad argument #1 to 'SetStraightTexture' (string expected, got " .. typeof(asset) .. ")", 2)
	end
	
	for _,v in pairs(splashAttachments) do
		v.RainSplash.Texture = asset
	end
	
end

function Rain:SetSoundId(asset)
	
	if typeof(asset) ~= "string" then
		error("bad argument #1 to 'SetSoundId' (string expected, got " .. typeof(asset) .. ")", 2)
	end
	
	Sound.SoundId = asset
	
end

function Rain:SetCollisionMode(mode, param)
	
	if mode == CollisionMode.None then
		
		-- Regular mode needs no white/blacklist or test function
		collisionList = nil
		collisionFunc = nil
		
	elseif mode == CollisionMode.Blacklist then
		
		if typeof(param) == "Instance" then
			-- Add Emitter anyway, since users will probably not expect collisions with emitter block regardless
			collisionList = {param, Emitter}
		elseif typeof(param) == "table" then
			for i = 1, #param do
				if typeof(param[i]) ~= "Instance" then
					error("bad argument #2 to 'SetCollisionMode' (blacklist contained a " .. typeof(param[i]) .. " on index " .. tostring(i) .. " which is not an Instance)", 2)
				end
			end
			collisionList = {Emitter} -- see above
			for i = 1, #param do
				table.insert(collisionList, param[i])
			end
		else
			error("bad argument #2 to 'SetCollisionMode (Instance or array of Instance expected, got " .. typeof(param) .. ")'", 2)
		end
		
		-- Blacklist does not need a test function
		collisionFunc = nil
		
	elseif mode == CollisionMode.Whitelist then
		
		if typeof(param) == "Instance" then
			collisionList = {param}
		elseif typeof(param) == "table" then
			for i = 1, #param do
				if typeof(param[i]) ~= "Instance" then
					error("bad argument #2 to 'SetCollisionMode' (whitelist contained a " .. typeof(param[i])  .. " on index " .. tostring(i) .. " which is not an Instance)", 2)
				end
			end
			collisionList = {}
			for i = 1, #param do
				table.insert(collisionList, param[i])
			end
		else
			error("bad argument #2 to 'SetCollisionMode (Instance or array of Instance expected, got " .. typeof(param) .. ")'", 2)
		end
		
		-- Whitelist does not need a test function
		collisionFunc = nil
		
	elseif mode == CollisionMode.Function then
		
		if typeof(param) ~= "function" then
			error("bad argument #2 to 'SetCollisionMode' (function expected, got " .. typeof(param) .. ")", 2)
		end
		
		-- Test function does not need a list
		collisionList = nil
		
		collisionFunc = param
		
	else
		error("bad argument #1 to 'SetCollisionMode (Rain.CollisionMode expected, got " .. typeof(param) .. ")'", 2)
	end
	
	collisionMode = mode
	raycast = raycastFunctions[mode]
	
end

return Rain
