local E=settings.MusicFadeoutTime function PlaySound(E)if E==nil then return end local S=Instance.new("\083\111\117\110\100")S.Looped=true S.SoundId=E.SoundId S.Volume=musicon and E.Volume or 0 local c=Instance.new("\078\117\109\098\101\114\086\097\108\117\101",S)c.Name="\079\114\105\103\105\110\097\108\086\111\108\117\109\101"c.Value=E.Volume S.Pitch=E.Pitch S.Name="\066\071\077"S.Parent=script S:Play()end function FadeOutSound(S)local c=S.Volume local o=math.ceil(30*E)if o<1 then o=1 end for E=1,o,1 do if S then S.Volume=S.Volume-c/o wait(.033333333333333)end end if S then S:Stop()S:Destroy()end end if settings.UseGlobalBackgroundMusic==true and settings.UseMusicZones==false then if#music[globali]==1 then PlaySound(music[1][1])return elseif#music[globali]==0 then return end end local S={}math.randomseed(tick())local c local o function CheckIfRecent(E)for S,c in pairs(S)do if c==E then return true end end return false end function SelectRandomMusic(E)if E==nil or#E==0 then return end local c={}local o for E=1,#E,1 do if not CheckIfRecent(E)then table.insert(c,E)end end local C=c[math.random(1,#c)]table.insert(S,C)if#S>math.ceil(#E/2)then table.remove(S,1)end return E[C]end function IsInZone(E)if torso and torso.Parent~=nil then local S=torso.Position for E,c in pairs(E.Parts)do if c.Coordinates then local E=c.Coordinates if S.x>E.lx and(S.x<E.mx and(S.y>E.ly and(S.y<E.my and(S.z>E.lz and S.z<E.mz))))then return true end elseif c.Part then local E=c.Part:clone()E.Anchored=true E.Parent=workspace.CurrentCamera or workspace E.CanCollide=true local S=E:GetTouchingParts()E:Destroy()for E,S in pairs(S)do if S==torso then return true end end end end return false end end function CalculateCurrentZone()local E=-math.huge local o=c local C if c then if IsInZone(c)then C=c E=c.Priority end end for S,c in pairs(zones)do if c.Priority>E and IsInZone(c)then E=c.Priority C=c end end c=C if c~=o and(c~=nil or settings.UseGlobalBackgroundMusic==true)then S={}end return c,o end function RunCycle()local S=script:FindFirstChild("\066\071\077")if settings.UseMusicZones==true then local E,c=CalculateCurrentZone()if E~=c and(E~=o and S)then if E==nil and(settings.UseGlobalBackgroundMusic==true or settings.MusicOnlyPlaysWithinZones==true)or E~=nil then FadeOutSound(S)return end elseif E and S==nil then PlaySound(SelectRandomMusic(E.Music))o=E return elseif E==nil and(c and(settings.MusicOnlyPlaysWithinZones==false and(settings.UseGlobalBackgroundMusic==false and S==nil)))then PlaySound(SelectRandomMusic(c.Music))o=c return elseif o and(settings.MusicOnlyPlaysWithinZones==false and(settings.UseGlobalBackgroundMusic==false and S==nil))then PlaySound(SelectRandomMusic(o.Music))return elseif settings.UseGlobalBackgroundMusic==true and S==nil then PlaySound(SelectRandomMusic(music[globali]))o=nil return end elseif S==nil and settings.UseGlobalBackgroundMusic==true then PlaySound(SelectRandomMusic(music[globali]))return end if S and(settings.UseGlobalBackgroundMusic==true and(o==nil and#music[globali]>1))or o and#o.Music>1 then local c=S.TimeLength local o=S.TimePosition if c~=0 and c-o<E+.5 then FadeOutSound(S)end end end while wait(.5)do RunCycle()end


local FadeoutTime = settings.MusicFadeoutTime

function PlaySound(sounddata)
	if sounddata == nil then return end
	local sound = Instance.new("Sound")
	sound.Looped = true
	sound.SoundId = sounddata.SoundId
	sound.Volume = musicon and sounddata.Volume or 0
	local v = Instance.new("NumberValue",sound)
	v.Name = "OriginalVolume"
	v.Value = sounddata.Volume
	sound.Pitch = sounddata.Pitch
	sound.Name = "BGM"
	sound.Parent = script
	sound:Play()
end

function FadeOutSound(sound)
	local basevol = sound.Volume
	local count = math.ceil(30*FadeoutTime)
	if count < 1 then
		count = 1
	end
	for i=1,count do
		if sound then
			sound.Volume = sound.Volume - (basevol / count)
			wait(1/30)
		end
	end
	if sound then
		sound:Stop()
		sound:Destroy()
	end
end


if settings.UseGlobalBackgroundMusic == true and settings.UseMusicZones == false then
	if #music[globali] == 1 then --global BGM with just 1 song? ez pz
		PlaySound(music[1][1])
		return
	elseif #music[globali] == 0 then --there's no music to play...?
		return
	end
end



local recentindices = {} --keeps track of recently selected indicies, so as not to play repeat music tracks
math.randomseed(tick())
local currentzone
local zoneplayingmusic

function CheckIfRecent(i)
	for _,v in pairs(recentindices) do
		if v == i then
			return true
		end
	end
	return false
end

function SelectRandomMusic(musiclist) --select a random number, excluding ones that were already used recently
	if musiclist == nil or #musiclist == 0 then return end
	local possiblenumbers = {}
	local selectedindex
	for i=1,#musiclist do
		if not CheckIfRecent(i) then
			table.insert(possiblenumbers,i)
		end
	end
	local selectedindex = possiblenumbers[math.random(1,#possiblenumbers)]
	table.insert(recentindices,selectedindex)
	if #recentindices > math.ceil(#musiclist / 2) then
		table.remove(recentindices,1)
	end
	return musiclist[selectedindex]
end

function IsInZone(zonedata)
	if torso and torso.Parent ~= nil then
		local p = torso.Position
		for _,data in pairs(zonedata["Parts"]) do
			if data["Coordinates"] then
				local t = data["Coordinates"]
				if (p.x > t.lx and p.x < t.mx and p.y > t.ly and p.y < t.my and p.z > t.lz and p.z < t.mz) then --is the character within all the coordinates of the zone?
					return true
				end
			elseif data["Part"] then --complex part? create a clone of the part and check if it's touching the character's torso
				local part = data["Part"]:clone()
				part.Anchored = true
				part.Parent = workspace.CurrentCamera or workspace
				part.CanCollide = true
				local touching = part:GetTouchingParts()
				part:Destroy()
				for _,v in pairs(touching) do
					if v == torso then
						return true
					end
				end
			end
		end
		return false
	end
end

function CalculateCurrentZone()
	local priority = -math.huge
	local oldzone = currentzone
	local selectedzone
	if currentzone then
		if IsInZone(currentzone) then
			selectedzone = currentzone
			priority = currentzone["Priority"]
		end
	end
	for _,zone in pairs(zones) do
		if zone["Priority"] > priority and IsInZone(zone) then
			priority = zone["Priority"]
			selectedzone = zone
		end
	end
	currentzone = selectedzone
	if currentzone ~= oldzone and (currentzone ~= nil or settings.UseGlobalBackgroundMusic == true) then
		recentindices = {}
	end
	return currentzone,oldzone
end


function RunCycle() --the main cycle which will continuously run, checking which zones (if any) the character is in and playing new music when necessary
	local bgm = script:FindFirstChild("BGM")
	if settings.UseMusicZones == true then
		local zone,oldzone = CalculateCurrentZone()
		if zone ~= oldzone and zone ~= zoneplayingmusic and bgm then
			if (zone == nil and (settings.UseGlobalBackgroundMusic == true or settings.MusicOnlyPlaysWithinZones == true)) or zone ~= nil then
				FadeOutSound(bgm)
				return
			end
		elseif zone and bgm == nil then
			PlaySound(SelectRandomMusic(zone["Music"]))
			zoneplayingmusic = zone
			return
		elseif zone == nil and oldzone and settings.MusicOnlyPlaysWithinZones == false and settings.UseGlobalBackgroundMusic == false and bgm == nil then
			PlaySound(SelectRandomMusic(oldzone["Music"]))
			zoneplayingmusic = oldzone
			return
		elseif zoneplayingmusic and settings.MusicOnlyPlaysWithinZones == false and settings.UseGlobalBackgroundMusic == false and bgm == nil then
			PlaySound(SelectRandomMusic(zoneplayingmusic["Music"]))
			return
		elseif settings.UseGlobalBackgroundMusic == true and bgm == nil then
			PlaySound(SelectRandomMusic(music[globali]))
			zoneplayingmusic = nil
			return
		end
	elseif bgm == nil and settings.UseGlobalBackgroundMusic == true then
		PlaySound(SelectRandomMusic(music[globali]))
		return
	end
	
	if bgm and (settings.UseGlobalBackgroundMusic == true and zoneplayingmusic == nil and #music[globali] > 1) or (zoneplayingmusic and #zoneplayingmusic["Music"] > 1) then
		local length = bgm.TimeLength
		local pos = bgm.TimePosition
		if length ~= 0 and length - pos < FadeoutTime + .5 then
			FadeOutSound(bgm)
		end
	end
end

while wait(.5) do
	RunCycle()
end

