if (type (Require) ~= 'function') then loadstring(exports['nc_libraries']:extend('Extend'), 'Require')() end require 'Element' require 'Events' require 'File' require 'Thread' require 'String' require 'Table' require 'Math' local _playSFX = playSFX; local _playSound = playSound; local SFX = {} SFX.SoundsByName = { ['Highlight_1'] = 'button_highlight_01' } function SFX:IsSoundArchive(Path) if type(Path) ~= 'string' then return false end for i, v in ipairs({'.mp3', '.ogg', '.wav', '.opus'}) do if Path:find(v) then return Path:gsub(v, '') end end end function SFX:Constructor() self.SoundsPath = {}; self.SoundsRunning = {}; self.SoundsOnHover = {}; local Path = ':'..(LIBRARY_NAME or 'nc_libraries')..('/Assets/Sfx') local Files = pathListDir(Path) or {} for _, v in ipairs(Files) do if pathIsFile(Path .. '/' .. v) then self.SoundsPath[SFX:IsSoundArchive(v)] = Path .. '/' .. v end end return self; end function SFX:Play(SoundName, Volume, Ms, IgnoreRunning) local SoundName = SoundName and (self.SoundsByName[SoundName] or SoundName) or nil; local SoundPath = SoundName and self.SoundsPath[SoundName] or nil; if not SoundPath then return false end if isMTAWindowActive() then return false end if not isMTAWindowFocused() then return false end if not self.SoundsRunning[SoundName] then self.SoundsRunning[SoundName] = {}; end local Thread = self.SoundsRunning[SoundName]; -- if next(Thread) then -- if IgnoreRunning then -- if isElement(Thread.Element) and getTickCount() - Thread.StartTick < 50 then -- destroyElement(Thread.Element) -- else -- return false; -- end -- else -- return false -- end -- end local Sound = playSound(SoundPath, false, true); if isElement(Sound) then setSoundVolume(Sound, Volume or 1) Thread.Name = SoundName; Thread.Element = Sound; Thread.Length = getSoundLength(Sound) * 1000; Thread.Ms = Ms or 0; Thread.Volume = Volume or 1; Thread.StartTick = getTickCount(); if Ms and tonumber(Ms) and Thread.Length > 0 then local Speed = Thread.Length / Ms local SampleRate, Tempo, Pitch, IsReversed = getSoundProperties(Sound) Tempo = math.max(50, math.min(Speed * 100, 200)) setSoundSpeed(Sound, Speed) setSoundProperties(Sound, SampleRate, Tempo, Pitch, IsReversed) end local Id = tostring(getTickCount()); self.SoundsRunning[SoundName][Id] = Thread; (AddEventHandler or addEventHandler)('onClientElementDestroy', Sound, function() (RemoveEventHandler or removeEventHandler)('onClientElementDestroy', Sound, debug.getinfo(1).func) self.SoundsRunning[SoundName][Id] = nil if next(self.SoundsRunning[SoundName]) == nil then self.SoundsRunning[SoundName] = nil end end) return Sound end return false end function SFX:PlayOnHover(Id, isHovering, SoundName, Ms) if isHovering and not self.SoundsOnHover[Id] then self.SoundsOnHover[Id] = true return self:Play(SoundName, 0.3, Ms or false, true) elseif not isHovering and self.SoundsOnHover[Id] then self.SoundsOnHover[Id] = nil return true; end return false; end function SFX:Stop(SoundName) if SFX.SoundsRunning[SoundName] then for Id, Thread in pairs(SFX.SoundsRunning[SoundName]) do destroyElement(Thread.Element) end self.SoundsRunning[SoundName] = nil return true end return false end function SFX:StopAll() for SoundName, Sound in pairs(SFX.SoundsRunning) do for Id, Thread in pairs(Sound) do destroyElement(Thread.Element) end end end function SFX:GetSound(SoundName) local Sounds = {} if SFX.SoundsRunning[SoundName] then for Id, Thread in pairs(SFX.SoundsRunning[SoundName]) do table.insert(Sounds, Thread.Element) end end return Sounds end function SFX:GetSounds() return SFX.SoundsRunning; end function SFX:GetSoundsPath() return SFX.SoundsPath end function SFX:GetSoundPath(SoundName) return SFX.SoundsPath[SoundName] end function SFX:GetSoundLength(SoundName) local Length = 0 if SFX.SoundsRunning[SoundName] then for Id, Thread in pairs(SFX.SoundsRunning[SoundName]) do Length = Thread.Length break end end return Length end -- Overrides -- function playSFX(SoundName, ...) if SFX.SoundsPath[SoundName] then return SFX:Play(SoundName, ...) end return _playSFX(SoundName, ...) end function playSound(SoundName, ...) if SFX.SoundsPath[SoundName] then return SFX:Play(SoundName, ...) end return _playSound(SoundName, ...) end _G.SFX = SFX; return SFX:Constructor();