script_name('soundboard')
script_properties('work-in-pause')
require 'lib.sampfuncs'
local rmu = require 'rmlib.utils' --small library of my functions
local SE = require 'lib.samp.events'
local ML = require 'moonloader'
local inicfg = require 'inicfg'
local slink = {
"https://pastebin.com/raw/tEMBtwkd"
}
local coreset = inicfg.load({
sb = {
slink = 1,
enabled = true,
sb_3d = false,
autocomp = false,
chain = false,
ch_max = 3,
str_max = 5,
str_vol = 1,
r_vol = 1,
dbg = false
}
}, "rm_coreset")
if coreset.sb.dbg then rmu.dbg = true end
local operators = {}
local sb_patt = ":(%w+):"
local uid
local uname
local str_sources = {}
local str_groups = {}
local str_info = {}
local str_locals = {}
local str_table = {}
local scount = 0
local rstream
local r_sources = {}
local player_mutes = {}
local str_mutes = {}
local str_vol_mult = {}
local sb_acthr
local sb_ac_cls = false
local debugstr
local soundsearch = {
dict = nil,
spctbl = {},
revtbl = {}
}
local radiosearch = {
dict = nil,
spctbl = {},
revtbl = {}
}
local objArray = {}
local dl_reg = {}
local dl_codes = {}
local users = {}
local rm_ready = false
function inTable(list,key)
return list[key] ~= nil
end
function load_strvol(tname, tbl)
local afile = io.open('moonloader/soundboard/'..tname..'.txt', 'r')
if afile then
for line in io.lines('moonloader/soundboard/'..tname..'.txt') do
local alias, vlm = string.match(line,"(%w+) (%S+)")
vlm = tonumber(vlm)
if alias and vlm then tbl[alias] = vlm end
end
end
end
function dl_handler(id, status, p1, p2)
local tstatus
local pstatus
local code
if dl_codes[status] then code = dl_codes[status] else code = status end
dl_reg[id] = status
if coreset.sb.dbg then
tstatus = "rm.src_dl: "..code.." "..p1.."/"..p2
if pstatus ~= tstatus then sampfuncsLog(tstatus) end
pstatus = tstatus
end
end
function src_dl(link, path)
if not path or not link then return nil end
if coreset.sb.dbg then sampfuncsLog("rm.src_dl: "..path) end
local dl_id = downloadUrlToFile(link, path, dl_handler)
dl_reg[dl_id] = false
return dl_id
end
function dcodes()
local ori = ML.download_status
local output = {}
for k, v in pairs(ori) do output[v] = k end
return output
end
local set_info = {
sb = {
mute = "Disables sound command processing from player SB MUTE [ID/NAME]",
unmute = "Enables sound command processing from player SB UNMUTE [ID/NAME]",
volume = "Sets main volume SB VOLUME/VOL [1-100]",
strvol = "Adjusts single sound command volume without affecting others SB STRVOL [SOUND] [1-100]",
ignore = "Ignores single sound processing (mutes it) SB IGNORE [SOUND]",
unignore = "Enables ignored sound processing back SB UNIGNORE [SOUND]",
strmax = "Sets maximum simultaneous playing sound limit SB STRMAX [1-20-!!100!!]",
setlink = "Allows usage of backup source in case of Google issues SB SETLINK [PRIMARY/SECONDARY] (SB SBRELOAD after this cmd)",
sound3d = "Switches 3D sound attachment SB SOUND3D [ENABLE/DISABLE]",
autocomplete = "Fills the chat with most matching sound command as you type SB AUTOCOMPLETE/AC [ENABLE/DISABLE]",
chain = "Switches multiple sound chains on/off, or sets maximum chain length SB CHAIN [ENABLE/DISABLE/NUM(2-20)]",
sbreload = "Resets all temporary data and attempts to reload from source SB SBRELOAD",
radio = "Plays radio stream, sets its volume or stops it SB RADIO [STREAM ALIAS/STOP/VOLUME/VOL] [0-100]",
sinfo = "Displays sound command description SB SINFO [SOUND]",
ginfo = "Shows all sound commands in a group SB GINFO [GROUP] [PAGE]",
search = "Browses all avalible sound commands by part of a sound name SB SEARCH [NAME]",
cmds = "mute unmute volume strvol ignore unignore sound3d radio sinfo ginfo search"
}
}
local sb_set = {
mute = function(op)
if not op[2] then getinfo({"info","mute"}) ; return nil end
local pname = rmu.nicheck(op[2])
if not pname then sampAddChatMessage("[SB] Player ID "..op[2].." not connected", 0xC1C1C1) ; return nil end
player_mutes[string.lower(pname)] = true
rmu.updatelist('moonloader/soundboard/muted.txt', player_mutes)
sampAddChatMessage("[SB] "..pname.." is muted", 0xC1C1C1)
end,
unmute = function(op)
if not op[2] then getinfo({"info","unmute"}) ; return nil end
local pname = rmu.nicheck(op[2])
if not pname then sampAddChatMessage("[SB] Player ID "..op[2].." not connected", 0xC1C1C1) ; return nil end
if inTable(player_mutes, string.lower(pname)) then
player_mutes[string.lower(pname)] = nil
rmu.updatelist('moonloader/soundboard/muted.txt', player_mutes)
sampAddChatMessage("[SB] "..pname.." is no longer muted", 0xC1C1C1)
else
sampAddChatMessage("[SB] "..pname.." was not muted", 0xC1C1C1)
end
end,
volume = function(op)
local vlm = tonumber(op[2])
if vlm and vlm >= 0 and vlm <= 100 then
coreset.sb.str_vol = vlm/100
sampAddChatMessage("[SB] Volume set to "..vlm, 0xC1C1C1)
else
sampAddChatMessage("[SB] Volume should be a number between 0 and 100", 0xC1C1C1)
end
end,
strvol = function(op)
local vlm = tonumber(op[3])
if not vlm or vlm < 1 or vlm > 100 then sampAddChatMessage("[SB] Stream volume should be a number between 1 and 100", 0xC1C1C1) ; return nil end
if inTable(str_sources, op[2]) then
if vlm == 100 then str_vol_mult[op[2]] = nil else str_vol_mult[op[2]] = vlm/100 end
io.open('moonloader/soundboard/strvols.txt', 'w'):close()
local afile = io.open('moonloader/soundboard/strvols.txt', 'a')
for k, v in pairs(str_vol_mult) do
afile:write(k.." "..v.."\n")
end
afile:close()
sampAddChatMessage("[SB] Sound command '"..op[2].."' relative volume set to "..vlm, 0xC1C1C1)
else
sampAddChatMessage("[SB] Sound command not found", 0xC1C1C1)
end
end,
ignore = function(op)
if not op[2] then getinfo({"info","ignore"}) ; return nil end
if inTable(str_sources, op[2]) then
str_mutes[op[2]] = true
sampAddChatMessage("[SB] Sound command '"..op[2].."' will be ignored", 0xC1C1C1)
rmu.updatelist('moonloader/soundboard/ignored.txt', str_mutes)
else
sampAddChatMessage("[SB] Sound command not found", 0xC1C1C1)
end
end,
unignore = function(op)
if not op[2] then getinfo({"info","unignore"}) ; return nil end
if inTable(str_mutes, op[2]) then
str_mutes[op[2]] = nil
sampAddChatMessage("[SB] Sound command '"..op[2].."' will be activated", 0xC1C1C1)
rmu.updatelist('moonloader/soundboard/ignored.txt', str_mutes)
else
sampAddChatMessage("[SB] Sound command was not ignored", 0xC1C1C1)
end
end,
strmax = function(op)
local smax = tonumber(op[2])
if smax and smax >= 1 and smax <= 100 then
if smax > 20 then
sampAddChatMessage("[SB] You are setting max possible simultaneous playing streams above 20", 0xC1C1C1)
sampAddChatMessage("[SB] I will let that sink in for a minute", 0xC1C1C1)
end
coreset.sb.str_max = smax
sampAddChatMessage("[SB] str_max set to "..coreset.sb.str_max..". Hope you know what youre doing.", 0xC1C1C1)
else
sampAddChatMessage("[SB] Max running stream count must be a number between 1 and 100", 0xC1C1C1)
end
end,
chain = function(op)
if not op[2] then getinfo({"info","chain"}) ; return nil end
local cmax = tonumber(op[2])
if cmax then
if cmax > 1 and cmax < 21 then
coreset.sb.ch_max = cmax
sampAddChatMessage("[SB] Sound command chain max length set to "..cmax, 0xC1C1C1)
else
sampAddChatMessage("[SB] Sound command chain length cannot exceed 20. Because.", 0xC1C1C1)
end
elseif op[2] == "enable" then
coreset.sb.chain = true
sampAddChatMessage("[SB] Sound command chain enabled", 0xC1C1C1)
elseif op[2] == "disable" then
coreset.sb.chain = false
sampAddChatMessage("[SB] Sound command chain disabled", 0xC1C1C1)
else
getinfo({"info","chain"})
end
end,
setlink = function(op)
if not op[2] then getinfo({"info","setlink"}) ; return nil end
if op[2] == "primary" or op[2] == "1" then
coreset.sb.slink = 1
sampAddChatMessage("[SB] streams.txt source set to primary", 0xC1C1C1)
elseif op[2] == "secondary" or op[2] == "2" then
coreset.sb.slink = 2
sampAddChatMessage("[SB] streams.txt source set to secondary", 0xC1C1C1)
else
getinfo({"info","setlink"})
end
end,
sound3d = function(op)
if not op[2] then getinfo({"info","sound3d"}) ; return nil end
if op[2] == "enable" or op[2] == "1" then
coreset.sb.sb3d = true
sampAddChatMessage("[SB] 3D sound commands enabled", 0xC1C1C1)
elseif op[2] == "disable" or op[2] == "0" then
coreset.sb.sb3d = false
sampAddChatMessage("[SB] 3D sound commands disabled", 0xC1C1C1)
else
getinfo({"info","sound3d"})
end
end,
autocomplete = function(op)
if not op[2] then getinfo({"info","autocomplete"}) ; return nil end
if op[2] == "enable" or op[2] == "1" then
coreset.sb.autocomp = true
sampAddChatMessage("[SB] Sound command autocomplete enabled", 0xC1C1C1)
elseif op[2] == "disable" or op[2] == "0" then
coreset.sb.autocomp = false
sampAddChatMessage("[SB] Sound command autocomplete disabled", 0xC1C1C1)
else
getinfo({"info","autocomplete"})
end
end,
sbreload = function()
lua_thread.create(function()
sampAddChatMessage("[SB] RELOADING: please wait", 0xC1C1C1)
sbquiet() ; sampAddChatMessage("[SB] ending running audio commands", 0xC1C1C1)
sb_set["radio"]({"radio","stop"}) ; sampAddChatMessage("[SB] stopping radio", 0xC1C1C1)
coreset.sb.enabled = false ; sampAddChatMessage("[SB] disabling command listening", 0xC1C1C1)
str_sources = {} ; sampAddChatMessage("[SB] clearing data", 0xC1C1C1)
str_locals = {}
str_table = {}
player_mutes = {}
str_mutes = {}
str_vol_mult = {} ; sampAddChatMessage("[SB] downloading streams", 0xC1C1C1)
src_dl(slink[coreset.sb.slink], getGameDirectory()..'\\moonloader\\soundboard\\streams.txt') ; sampAddChatMessage("[SB] loading mutes", 0xC1C1C1)
rmu.loadlist('moonloader/soundboard/muted.txt', player_mutes) ; sampAddChatMessage("[SB] loading ignores", 0xC1C1C1)
rmu.loadlist('moonloader/soundboard/ignored.txt', str_mutes) ; sampAddChatMessage("[SB] loading volume array", 0xC1C1C1)
load_strvol("strvol", str_vol_mult)
wait(3000)
loadstreams() ; sampAddChatMessage("[SB] streams loaded", 0xC1C1C1)
rmu.dictload(str_sources, soundsearch) ; sampAddChatMessage("[SB] loading soundsearch dictionary", 0xC1C1C1)
rmu.dictload(r_sources, radiosearch) ; sampAddChatMessage("[SB] loading radiosearch dictionary", 0xC1C1C1)
coreset.sb.enabled = true ; sampAddChatMessage("[SB] enabling command listening", 0xC1C1C1)
sampAddChatMessage("[SB] reloaded", 0xC1C1C1)
end)
end,
radio = function(op)
if not op[2] then getinfo({"info","radio"}) ; return nil end
if op[2] == "stop" then
if rstream then
setAudioStreamState(rstream, ML.audiostream_state.STOP)
rstream = nil
end
elseif op[2] == "volume" or op[2] == "vol" then
local vlm = tonumber(op[3])
if vlm and vlm >= 0 and vlm <= 100 then
coreset.sb.r_vol = vlm/100
sampAddChatMessage("[SB] Radio volume set to "..vlm, 0xC1C1C1)
if rstream then setAudioStreamVolume(rstream, coreset.sb.r_vol) end
else
sampAddChatMessage("[SB] Volume should be a number between 0 and 100", 0xC1C1C1)
end
else
if inTable(r_sources, op[2]) then
if rstream then
setAudioStreamState(rstream, ML.audiostream_state.STOP)
rstream = nil
end
rstream = loadAudioStream(r_sources[op[2]])
if coreset.sb.r_vol ~= 1 then setAudioStreamVolume(rstream, coreset.sb.r_vol) end
setAudioStreamState(rstream, ML.audiostream_state.PLAY)
if inTable(str_info, op[2]) then sampAddChatMessage("[SB] Now playing "..str_info[op[2]], 0xC1C1C1) end
else
if coreset.sb.dbg then sampfuncsLog("rm.sb_set.radio: Could not find radio stream "..op[2]) end
end
end
end,
sinfo = function(op)
if not op[2] then getinfo({"info","sinfo"}) ; return nil end
local alias = string.lower(op[2])
if inTable(str_info, alias) then sampAddChatMessage("[SB] "..alias..": "..str_info[alias], 0xC1C1C1) end
end,
ginfo = function(op)
if not op[2] then getinfo({"info","ginfo"}) ; return nil end
local list = ": "
local page = 1
local gname = string.lower(op[2])
if not gname then return nil end
if inTable(str_groups, gname) then
local ppar = tonumber(op[3])
if ppar then if ppar >= 1 then page = ppar end end
local eist = 1+(page-1)*10
for ei = eist, #str_groups[gname] do
list = list..str_groups[gname][ei].." "
if ei > 9+(page-1)*10 then
list = list.."(and "..#str_groups[gname]-ei.." more)"
break
end
end
sampAddChatMessage("[SB] "..string.upper(gname)..list, 0xC1C1C1)
end
end,
search = function(op)
if not op[2] then getinfo({"info","search"}) ; return nil end
local dfind
local rfind
if op[3] then
if string.lower(op[3]) == "scmds" then result, dfind, mcount = rmu.dictfind(op[2], soundsearch) end
if string.lower(op[3]) == "radio" then result, rfind, mcount = rmu.dictfind(op[2], radiosearch) end
else
result, dfind, mcount = rmu.dictfind(op[2], soundsearch)
result, rfind, mcount = rmu.dictfind(op[2], radiosearch)
end
if dfind then sampAddChatMessage("[SB] scmds:"..dfind, 0xC1C1C1) end
if rfind then sampAddChatMessage("[SB] radio:"..rfind, 0xC1C1C1) end
end,
info = function(op)
if not op[2] then
sampAddChatMessage("[SoundBoard v1.0.2] Lua script by Pink. RAF2020UIF", 0xFF7AD1)
else
if inTable(set_info.sb, string.lower(op[2])) then
sampAddChatMessage("[SB] "..string.upper(op[2])..": "..set_info.sb[string.lower(op[2])], 0xC1C1C1)
else
if inTable(sb_set, string.lower(op[2])) then
sampAddChatMessage("[SB] No information about that command", 0xC1C1C1)
else
sampAddChatMessage("[SB] Unknown command", 0xC1C1C1)
end
end
end
end,
help = function(op)
sampAddChatMessage("[SoundBoard] Write '//sb info cmds' for command list. Write //sb info [command] for cmd syntax and info", 0xC1C1C1)
end
}
sb_set.vol = sb_set.volume
sb_set.find = sb_set.search
sb_set.ac = sb_set.autocomplete
function getinfo(par)
sb_set.info(par)
end
function sbenable(par)
if #par == 0 then
coreset.sb.enabled = not coreset.sb.enabled
sampAddChatMessage("[SB] Soundboard "..(coreset.sb.enabled and "enabled" or "disabled"), 0xC1C1C1)
else
operators = {}
for op in par:gmatch("%S+") do table.insert(operators, string.lower(op)) end
if inTable(sb_set,operators[1]) then sb_set[operators[1]](operators) end
end
end
function sbquiet()
for i=1, scount do
if getAudioStreamState(str_table[i]) == ML.audiostream_status.PLAYING then
setAudioStreamState(str_table[i], ML.audiostream_state.STOP)
end
str_table[i] = nil
scount = scount - 1
end
end
function playstream(alias, pname, pid)
local astream
lua_thread.create(function()
if not inTable(str_locals, alias) then
if not doesFileExist('moonloader\\soundboard\\mp3\\'..alias..'.mp3') then
local dl_id = downloadUrlToFile(str_sources[alias], getGameDirectory()..'\\moonloader\\soundboard\\mp3\\'..alias..".mp3", dl_handler)
dl_reg[dl_id] = false
local tim = 1
repeat
wait(100)
tim = tim + 1
until (dl_reg[dl_id] == ML.download_status.STATUSEX_ENDDOWNLOAD or tim > 50)
wait(1000)
if dl_reg[dl_id] == ML.download_status.STATUSEX_ENDDOWNLOAD then astream = loadstream('moonloader\\soundboard\\mp3\\'..alias..'.mp3',coreset.sb.sb3d) end
end
str_locals[alias] = true
end
if not astream then astream = loadstream('moonloader\\soundboard\\mp3\\'..alias..'.mp3',coreset.sb.sb3d) end
if not astream then
if coreset.sb.dbg then sampfuncsLog("rm.playstream: Failure to load stream "..alias.. ", retrying") end
wait(2000)
astream = loadstream('moonloader\\soundboard\\mp3\\'..alias..'.mp3',coreset.sb.sb3d)
wait(500)
if not astream then if coreset.sb.dbg then sampfuncsLog("rm.playstream: Failure to reload stream "..alias) end ; return nil end
end
local end_vol = coreset.sb.str_vol
if not coreset.sb.sb3d then
if inTable(str_vol_mult, alias) then end_vol = end_vol * str_vol_mult[alias] end
else
if pid == uid then
setPlay3dAudioStreamAtChar(astream, playerPed)
else
local result, ped = sampGetCharHandleBySampPlayerId(pid)
if result and doesCharExist(ped) then setPlay3dAudioStreamAtChar(astream, ped) end
end
end
setAudioStreamVolume(astream, end_vol)
setAudioStreamState(astream, ML.audiostream_state.PLAY)
table.insert(str_table, 1, astream)
scount = scount + 1
if scount > coreset.sb.str_max then
if getAudioStreamState(str_table[coreset.sb.str_max + 1]) == ML.audiostream_status.PLAYING then
setAudioStreamState(str_table[coreset.sb.str_max + 1], ML.audiostream_state.STOP)
end
str_table[coreset.sb.str_max + 1] = nil
scount = scount - 1
end
end)
return astream
end
function loadstream(strLink, play3d)
if coreset.sb.dbg then sampfuncsLog("rm.loadstream: Loading "..strLink..(play3d and " for 3d support" or "")) end
if play3d then return load3dAudioStream(strLink) else return loadAudioStream(strLink) end
end
local loadfunc = {
scmds = function(input)
local alias, str_link = string.match(input,"(%w+) (%S+)")
if alias and str_link then str_sources[alias] = str_link end
end,
rstreams = function(input)
local rname, str_link = string.match(input,"(%w+) (%S+)")
if rname and str_link then r_sources[rname] = str_link end
end,
sinfo = function(input)
local alias, info = string.match(input,":(%w+): (.+)")
if alias and info then str_info[alias] = info end
end,
sgroups = function(input)
local gname, contents = string.match(input,":(%w+): (.+)")
if gname and contents then
local ctable = {}
for entry in contents:gmatch("%w+") do table.insert(ctable, entry) end
str_groups[gname] = ctable
end
end
}
function loadstreams()
local result
lua_thread.create(function()
local timeout = false
local curfunc = "scmds"
local afile = io.open('moonloader/soundboard/streams.txt', 'r')
::reloadstreams::
if afile then
for line in io.lines('moonloader/soundboard/streams.txt') do
if line ~= '' then
local lfunc = string.match(line,"^%[(%w+)%]")
if lfunc then
if inTable(loadfunc, lfunc) then curfunc = string.lower(lfunc) end
else
loadfunc[curfunc](line)
end
end
end
result = true
elseif afile == nil and timeout == false then
timeout = true
if coreset.sb.dbg then sampfuncsLog("rm.loadstreams: Failure to load streams, retrying") end
tim = 1
while (afile == nil or tim < 10) do
wait(200)
afile = io.open('moonloader/soundboard/streams.txt', 'r')
wait(500)
tim = tim + 1
end
if afile then goto reloadstreams else result = false end
end
end)
return result
end
function main()
sampRegisterChatCommand("/sb", sbenable)
sampRegisterChatCommand("/sbq", sbquiet)
local scr_handle = thisScript()
local tim
dl_codes = dcodes()
if not doesDirectoryExist('moonloader/soundboard') then createDirectory('moonloader/soundboard') end
if not doesDirectoryExist('moonloader/soundboard/mp3') then createDirectory('moonloader/soundboard/mp3') end
local streams_load = src_dl(slink[coreset.sb.slink], getGameDirectory()..'\\moonloader\\soundboard\\streams.txt')
tim = 1
local load_result = false
local dl_end = ML.download_status.STATUSEX_ENDDOWNLOAD
repeat
wait(100)
if dl_reg[streams_load] == dl_end then load_result = true else load_result = false end
tim = tim + 1
until (load_result or tim > 50)
rmu.loadlist('moonloader/soundboard/muted.txt', player_mutes)
rmu.loadlist('moonloader/soundboard/ignored.txt', str_mutes)
load_strvol("strvol", str_vol_mult)
if not load_result then wait(3000) end
local sload = loadstreams()
tim = 1
repeat
wait(100)
tim = tim + 1
until (sload or tim > 50)
if not sload then
if coreset.sb.dbg then sampfuncsLog("rm.main: Script failed to create stream dictionary. Soundboard will be disabled.") end
coreset.sb.enabled = false
end
result = rmu.dictload(str_sources, soundsearch)
if result == false then
sampfuncsLog("Script failed to create stream dictionary. Soundboard will be disabled.")
coreset.sb.enabled = false
end
result = rmu.dictload(r_sources, radiosearch)
if result == false then sampfuncsLog("Radio sources were not present to load radio dictionary") end
while not isSampAvailable() do wait(0) end
while not sampIsLocalPlayerSpawned() do wait(0) end
_, uid = sampGetPlayerIdByCharHandle(playerPed)
uname = sampGetPlayerNickname(uid)
rm_ready = true
watchman()
--[[addEventHandler('onWindowMessage', function(msg, wparam, lparam)
if coreset.sb.autocomp then
if msg == 0x100 then
if wparam == VK_T then
lua_thread.create(ac_eval)
elseif wparam == VK_RETURN then
if sb_acthr then if not sb_acthr.dead then sb_acthr:terminate() end end
end
end
end
end)]]
while true do
wait(0)
end
end
function watchman()
local paused
local ltime = os.time()
lua_thread.create(function()
while true do
if (isGamePaused() or (os.time() - ltime > 5)) and rm_ready then
rm_ready = false
if coreset.sb.dbg then sampfuncsLog("rm.watchman: paused") end
end
if not isGamePaused() and (os.time() - ltime < 5) and not rm_ready then
wait(1000)
rm_ready = true
if coreset.sb.dbg then sampfuncsLog("rm.watchman: ready") end
end
ltime = os.time()
wait(0)
end
end)
end
function ac_eval()
wait(50)
local active = sampIsChatInputActive()
if active then
if sb_acthr then
if sb_acthr.dead then autocomplete() end
else
autocomplete()
end
else
if sb_acthr then
if not sb_acthr.dead then sb_acthr:terminate() end
end
end
end
function autocomplete()
local rinput = false
local pstring
local cstring
local lastsign
local strbody
local scmd
local smatch
local smatchcount
local sset
local function sClear()
rinput = false
pstring = nil
cstring = nil
lastsign = nil
strbody = nil
scmd = nil
smatch = nil
sset = nil
end
local function chatset(input, cls)
cstring = input
sampSetChatInputText(cstring)
if cls then
rinput = false
sClear()
end
end
local function sconstr()
smatch, _, smatchcount = rmu.dictfind(scmd, soundsearch, true)
if smatch and smatch ~= scmd then
sset = strbody..":"..scmd..string.char(smatchcount > 1 and 166 or 124)..string.sub(smatch, #scmd-#smatch)
else
sset = strbody..":"..scmd
end
end
sb_acthr = lua_thread.create(function()
while true do
cstring = sampGetChatInputText()
if cstring and pstring and pstring ~= cstring then
lastsign = string.sub(cstring, -1)
if #cstring > #pstring then
if lastsign == ":" then
if rinput then
sClear()
else
strbody = pstring
rinput = true
end
elseif rinput and lastsign ~= ":" then
if lastsign:match("%a") then
scmd = scmd and scmd..lastsign or lastsign
sconstr()
chatset(sset, false)
elseif lastsign == " " or lastsign == ":" then
if smatch then chatset(strbody..":"..smatch..":", false) end
sClear()
else
sClear()
end
end
else
if rinput and scmd then
scmd = string.sub(scmd, 1, #scmd-1)
if #scmd > 0 then
sconstr()
chatset(sset, false)
else
chatset(strbody, true)
end
end
end
end
pstring = cstring
wait(10)
end
end)
end
function SE.onChatMessage(playerId, text)
if not rm_ready then return nil end
if not coreset.sb.enabled then return nil end
if text == nil then return nil end
if not sampIsPlayerConnected(playerId) then return nil end
local pname = sampGetPlayerNickname(playerId)
if inTable(player_mutes, string.lower(pname)) then return nil end
sb_rextest(text, pname, playerId)
end
function SE.onServerMessage(color, text)
if not rm_ready then return nil end
if not coreset.sb.enabled then return nil end
if text == nil then return nil end
local smatch = string.match(text, "(%S+%(%d+%))")
if smatch == nil then return nil end
local pname = string.match(smatch, "(%S+)%(%d+%)")
local pid = tonumber(string.match(smatch, "%S+%((%d+)%)"))
if inTable(player_mutes, string.lower(pname)) then return nil end
sb_rextest(text, pname, pid)
end
function SE.onSendChat(message)
if coreset.sb.autocomp then
if message then
msg, _ = string.gsub(message, "(.*:%a+)["..string.char(166)..string.char(124).."](%a+)$", "%1%2:", 1)
if msg ~= message then
sb_ac_cls = true
return {msg}
end
end
end
end
function SE.onSendCommand(message)
if coreset.sb.autocomp then
if message then
msg, _ = string.gsub(message, "(.*:%a+)["..string.char(166)..string.char(124).."](%a+)$", "%1%2:", 1)
if msg ~= message then
sb_ac_cls = true
return {msg}
end
end
end
end
function sb_rextest(text, pname, pid)
local chi
local astream
lua_thread.create(function()
chi = 1
for sb_match in string.gmatch(text,sb_patt) do
if string.len(sb_match) > 2 and string.len(sb_match) < 21 then
if inTable(str_sources, sb_match) then
if not inTable(str_mutes, sb_match) then astream = playstream(sb_match, pname, pid) end
if not coreset.sb.chain then break end
local tim = 1
local as_state
repeat
if astream then as_state = getAudioStreamState(astream) end
tim = tim + 1
wait(50)
until (as_state == ML.audiostream_status.STOPPED or tim > 200)
end
end
chi = chi + 1
if chi > coreset.sb.ch_max then break end
end
end)
end
function onScriptTerminate(script, quitGame)
if script == thisScript() then inicfg.save(coreset, "rm_coreset") else return nil end
end
function onQuitGame()
inicfg.save(coreset, "rm_coreset")
setClipboardText(debugstr)
end
--[[function onWindowMessage(msg, wparam, lparam)
if coreset.sb.autocomp then
if msg == 0x100 then
if wparam == VK_T then
lua_thread.create(ac_eval)
elseif wparam == VK_RETURN then
if sb_acthr then if not sb_acthr.dead then sb_acthr:terminate() end end
end
end
end
end]]