Jump to content

Addlibs

Members
  • Posts

    1,060
  • Joined

  • Last visited

  • Days Won

    9

Everything posted by Addlibs

  1. setWeaponProperty(30, "poor", "flags", 0x000002) -- toggle 'only needs arm to aim' setWeaponProperty(30, "poor", "flags", 0x000800) -- toggle 'can use 2x guns at same time' -- etc. You need to use the numbers from https://wiki.multitheftauto.com/wiki/Weapon_Flags to toggle them between on and off. If you want to know if it's on, use function isWeaponFlagSet(weapon, skill, flagBit) return bitAnd(getWeaponProperty(weapon, skill, "flags"), flagBit) ~= 0 -- collects the current weapon bitflags, filters them using a bitwise And operation to only retain bits of flagBit, and checks if it's not 0 end or if you prefer, you can use this function to explicitly enable or disable rather than switch flipping current state -- Set or clear an individual weapon flag bit function setWeaponPropertyFlag( weapon, skill, flagBit, bSet ) local bIsSet = bitAnd( getWeaponProperty(weapon, skill, "flags"), flagBit ) ~= 0 if bIsSet ~= bSet then setWeaponProperty(weapon, skill, "flags", flagBit) end end -- from setWeaponProperty wiki example
  2. Addlibs

    coroutine

    I believe coroutines cannot be sent over via callback arguments, so you'll have to store the coroutine reference in a table t at some index i and then send i for callback, and resume t[ i ] in the callback function. gDatabaseConnection = --[[ this would be your database connection here ]] local coroutines = {} -- coroutines will be stored here function gCallbackFn(qh, id) -- this is called when dbQuery thread returns indicating the query is ready to poll local result = dbPoll(qh, 0) -- since it's ready to poll, timeout is irrelevant and can be 0 coroutine.resume(coroutines[id], result) -- resume the coroutine with query result data end function handleQuery(queryStr, ...) if not coroutine.running() then error("handleQuery can only be called from within a coroutine.", 2) end local id = table.maxn(coroutines) + 1 -- calculate next unused table index (not sure whether # or maxn is better here) coroutines[id] = coroutine.running() -- store this coroutine in that table index dbQuery(gCallbackFn, {id}, gDatabaseConnection, queryStr, ...) -- this splits into two threads, first one continutes over to coroutine.yield function, other is internal to MTA and handles the query, and continues from gCallbackFn afterwards. local qData = coroutine.yield() -- since we want to wait for the query thread to return, we need to yield/pause this coroutine execution, and let gCallbackFn resume it when the query thread returns return qData -- return the query result data end -- now call handleQuery at some arbitrary point, here, after 1000ms (1s) c = coroutine.wrap( -- coroutine.wrap creates a coroutine wrapped in a function that, when called, will start/resume the coroutine function() local result = handleQuery("SELECT * sometable WHERE id = ?", 2) iprint(result) end ) setTimer(c, 1000, 1) -- call the function-wrapped coroutine after 1000ms I've only tested this using timers instead of dbQuery but it should work. N.B. this handleQuery function must be called from within a coroutine. If you're calling this when an event happens, you can override addEventHandler to automatically wrap handlers into coroutines too. local addEventHandler_ = addEventHandler function addEventHandler(eventName, attachedTo, handlerFn, propagation, priority) return addEventHandler_(eventName, attachedTo, coroutine.wrap(handlerFn), propagation, priority) end
  3. Using cache="false" is definitely safer, as they cannot be downloaded directly via http://serverip:serverport/resourcename/path/to/file.lua (you'll get "This script is not client cacheable" return message), and the only way to hijack the source code would be via a hacked client or by wiretapping the connection with Wireshark or something and somehow breaking the encryption on it. On the other hand, without blocking caching, users can technically download the file (provided they know the path and its filename) without executing it, thus the file wouldn't be deleted via fileDelete. However, this also means if you're using a fast download external server to serve files, these files aren't cached or served by that external server, and instead, served directly from the game server. External servers like nginx can provide good compression to downloaded data, while MTA internal HTTP download server is very primitive and does not support compression or multiple client connections[source]. Now to answer the other questions: - Client scripts don't unload from memory except when restarting a resource or reconnecting to the server, in which case they're requested from the server again and downloaded (and saved if caching is enabled) and executed. - If you're using cache="false" there's no need to use fileDelete, and indeed it could risk revealing file paths unless you also check fileExists before, as errors in clientscript.log may reveal paths if the file is attempted to be deleted but does not exist.
  4. Addlibs

    Team Blip Color

    function setBlipsToTeamColor() for _,player in ipairs(getElementsByType("player")) do for _,blip in ipairs(getElementsByType("blip")) do local team = getPlayerTeam(player) if (team and getElementAttachedTo(blip) == player) then -- only if this blip is attached to `player` local r,g,b = getTeamColor(team) setPlayerNametagColor(player,r,g,b) setBlipColor(blip,r,g,b,255) end end end end setTimer(setBlipsToTeamColor,500,0) Also I've renamed the function since you should avoid naming your function with the same name as existing hardcoded functions (namely, setTeamColor) as that makes them inaccessible.
  5. If you want to have permanent IDs, it's best to simply assign ID numbers to accounts — and then insert and remove the player from the playerid table on login (and on resource start), logout and quit.
  6. Use code blocks next time, please. And give some more details at what you mean to achieve. The title doesn't go into enough detail to get help - what should qualify four players? Four players online? Four players in proximity? Four players of a specific team? Four players of a specific team within proximity? And then, what should happen when there isn't four players? Should it continue if it started with four, or should it end abruptly? Et cetera. A lot of unanswered questions. The following code is reformatted to be more readable and has whitespace corrections that were bugging me, but behaviour-wise, it is unchanged. function openMyGate(Jogador) if isElementWithinMarker(Jogador, markers[1]) then setTimer(function() outputChatBox(getPlayerName(Jogador).." #00ff88● #FFFFFFEsta tentando assaltar empresa da BRINKS agora", players, 255, 255, 255, true) moveObject(objetos[1], 2500, 847.20001220703, -1371.5999755859, 22.700000762939) setElementPosition(markers[1], 848.06927490234-0.2, -1374.2985839844, 3000) destroyElement(markers[1], root, false) setTimer(function() -- wait 4502ms ped1 = exports["slothBot"]:spawnBot(830.59997558594, -1372, 25, 268, 163, 0, 0, nil , 38, "guarding") -- guarda parede 1 setTimer(function() exports["slothbot"]:setBotAttackEnabled(ped1, true) end, 100, 1) setTimer( function () -- wait 200ms ped2 = exports["slothBot"]:spawnBot(830.59997558594, -1367, 25, 262, 164, 0, 0, nil , 31, "guarding")-- guarda parede 2 setTimer(function() exports["slothbot"]:setBotAttackEnabled(ped2, true) end, 100, 1) setTimer(function() -- wait 200ms ped3 = exports["slothBot"]:spawnBot(832.90002441406, -1364, 25, 180, 165, 0, 0, nil , 27, "guarding") -- guarda cliente 1 setTimer(function() exports["slothbot"]:setBotAttackEnabled(ped3, true) end, 100, 1) setTimer(function() -- wait 200ms ped4 = exports["slothBot"]:spawnBot(838, -1363.9000244141, 25, 180, 166, 0, 0, nil, 31, "guarding") -- guarda client 2 setTimer(function() exports["slothbot"]:setBotAttackEnabled(ped4, true) end, 250, 1) ped9 = exports["slothBot"]:spawnBot(843.29998779297, -1363.8000488281, 25, 186, 163, 0, 0, nil , 38, "guarding") -- guarda cliente 3 setTimer(function() exports["slothbot"]:setBotAttackEnabled(ped9, true) end, 100, 1) ped10 = exports["slothBot"]:spawnBot(830.40002441406, -1375, 25, 262, 164, 0, 0, nil, 27, "guarding") -- guarda 1 parede gerente setTimer(function() exports["slothbot"]:setBotAttackEnabled(ped10, true) end, 100, 1) ped11 = exports["slothBot"]:spawnBot(830.5, -1383, 25, 286, 165, 0, 0, nil, 31, "guarding") -- guarda 2 parede gerente setTimer(function() exports["slothbot"]:setBotAttackEnabled(ped11, true) end, 100, 1) end, 200, 1) end, 200, 1) end, 200, 1) end, 200, 1) end, 4502, 1) setPedRotation(Jogador, 87.794250488281) setElementPosition(Jogador, 847.806640625, -1374.2625732422, 22.59531211853) setPedAnimation(Jogador, "KISSING", "GF_CarSpot", 4500, false, false, false, false) setTimer(function() -- wait 1000ms triggerEvent(eventorestart, root) end, 1000, 1) end end addCommandHandler("arrombar", openMyGate)
  7. Firstly, I believe those aren't scripts, but rather models, images and whatnot - the filenames don't sound like script files. Secondly, it's probably a normal text file with either the raw data or encrypted (TEA perhaps) data. You can simply rename your models to use a different extention and they'll continue to work, while being more obscute to individuals lurking in downloaded resources cache. For more protection, you can store encrypted data in those files, and decrypt it on the go in a script. Dignum memoria, decrypting anything on a remote machine requires you to send a decryption key to it (via event or as a constant in a script file, or some other way), meaning that it will be possible for people to decrypt the data on their own, just a lot harder.
  8. You could using string.match to ensure that from start to end, only letters (%a) and the underscore (_) symbol are allowed. E.g. return string.match(str, "^[%a_]+$") == str ^ matches beginning of string, [...] makes a set, %a includes all letters (uppercase and lowercase) into the set, _ adds underscore into the set, the + means it can match more than once, and $ matches the ending of the string. The function returns the matched string, which should be identical to the input string since we're matching from start to end. It returns a nil if nothing matched, that is, the input string wasn't from start to end only letters and underscores. It is very lenient and allows names even like Test__, or __john_sMiTh__, etc. No enforcement of where the underscore can be, how much can there be, and no enforcement of capitals. If you want it to be a little more rigid, for example, that the underscore must separate two different words made of letters, you could use the following return string.match(str, "^%a+_%a+$") == str and if you want to enforce capital letters at the beginning of these two words, return string.match(str, "^%u%l+_%u%l+$") == str -- must begin with capital letter and all subsequent must be lowercase return string.match(str, "^%u%a+_%u%a+$") == str -- must begin with capital letter and all subsequent can be either case
  9. function sendClientMessage(msg, r, g, b, img, checkImgPath) -- line 49 if (checkImgPath == nil) then checkImgPath = true end if (img and sourceResource and checkImgPath) then img = ":"..tostring(getResourceName(sourceResource)).."/"..img end local sound = playSound("notif.wav") setSoundVolume(sound, 0.8) return _sendClientMessage(msg, r, g, b, img) end Make sure you added notif.wav in meta.xml in a <file> tag. Also please remove function message (messagesound) -- line 230 local sound = playSound("notif.wav") setSoundVolume(sound, 0.8) end addEventHandler("onClientRender", localPlayer, message) Trying to play a sound every frame? That is, up to 60 times a second? By the way, source for onClientRender is always root, so attaching it to localPlayer will not work.
  10. If you're talking abot compiling with encryption (extra obfuscation), you can use luac.multitheftauto.com.
  11. I believe he's concerned about DFFs, not textures. I dont think its possible use engineReplaceModel for clothes. Seems like only engineImportTXD allows IDs that high (or clothes names strings).
  12. Try setOcclusionsEnabled
  13. addEventHandler("onClientRender", getRootElement(), function () for k,v in ipairs(getElementsByType("player")) do local group = getElementData(v,"Group") if group and v ~= localPlayer then dxDrawTextOnElement(v,group,1,20,0,0,255,255,1,"arial") end end end ) group = getElementData(v,"Group") on line 2 was the problem, v wasn't defined at that point.
  14. Just some points from the top. First, please note it's called a gridlist, not grindlist. Secondly, your indenting is inconsistent (sometimes you use spaces, other times tabs — just stick to one of them, otherwise it gets ugly when shared on the forum) Now, let's get to some rudimentary debugging. Add debug messages in the code so you can trace the flow of execution (which blocks of code were executed and which weren't), and inspect variables or return values of functions. By the way, in Lua, brackets after if and before then are optional. addEventHandler ("onClientGUIClick", getRootElement(), function (button, state, absoluteX, absoluteY) outputDebugString("onClientGUIClick called.") -- if this is appears in debugscript, that means the event was triggered and this function handled it local me = not guiGetVisible (WinMission) if (source == accepted) then outputDebugString("guiGridListGetSelectedItem(ListMissions): "..guiGridListGetSelectedItem(ListMissions)) -- if this appears in debugscript, that means (source == accepted) is true. if (guiGridListGetSelectedItem(ListMissions) == 1) then outputDebugString("1 was selected") elseif (guiGridListGetSelectedItem(ListMissions) == 2) then outputDebugString("2 was selected") elseif (guiGridListGetSelectedItem(ListMissions) == 3) then outputDebugString("3 was selected") elseif (guiGridListGetSelectedItem(ListMissions) == 4) then outputDebugString("4 was selected") end end end ) Try the code above and report back what you get in /debugscript 3.
  15. local animTable = { ifp = {}, anims = { -- ... } } addEventHandler("onClientResourceStart", resourceRoot, function() animTable.ifp["block"] = "ped" animTable.ifp["ifp"] = engineLoadIFP("ped.ifp", animTable.ifp["block"]) for _, v in ipairs(animTable.anims) do engineReplaceAnimation(localPlayer, "ped", v, animTable.ifp["block"], v) -- replace the animations on localPlayer end end ) addEventHandler("onClientElementStreamIn", root, function() if getElementType(source) == "player" or getElementType(source) == "ped" and source ~= localPlayer then for _, v in ipairs(animTable.anims) do engineReplaceAnimation(source, "ped", v, animTable.ifp["block"], v) -- replace the animations on streamed in ped end end end ) addEventHandler("onClientElementStreamOut", root, function() if getElementType(source) == "player" or getElementType(source) == "ped" and source ~= localPlayer then engineRestoreAnimation(source, "ped") -- restore the animations on streamed out ped end end ) engineReplaceAnimation replaces anims only on the screen of the client that executed the function, and only on the ped that was passed in that function. If you want yourself and others to see everyone else with the anims, you need to execute this function for every ped (that streams in, in this example) on each client.
  16. Then you'll need to monitor getTimerDetails every now and then (perhaps even by render event but it's overkill - you do not need to do this every frame). local duration = --[[ define a duration in ms ]] local timeLeft = getTimerDetails(--[[ the timer ]]) local timeDone = duration - timeLeft local percent = timeDone / duration guiProgressBarSetProgress(--[[ progressbar element ]], percent)
  17. I'm sorry but I can't understand what help you need. If you're not good with English, I'd suggest trying in your native language section.
  18. If I recall correctly, setElementFrozen will immediately reset the door's rotation to closed position so you don't have to worry about it freezing in the wrong rotation.
  19. How us the relevant part of the code. It's most likely that you're calling the function with a variable of nil value, or an expired userdata reference such as a player who has already quit or something.
  20. Addlibs

    Webmap

    Its been broken for a long time now. Firstly, the backend is provided by OpenLayers and map images by code.opencoding.net (presumably operated by eAi, the creator of the script) but the CGI script serving images is broken (e.g. http://code.opencoding.net/tilecache/tilecache.cgi/1.0.0/sa_aerial_map/0). And secondly, webmap's script.js attempts to use jQuery selectors but jQuery isn't present. Due to the image provider being broken, I don't think there is any easy workaround other than creating your own webmap script. The relevant Github issue is multitheftauto/mtasa-resources#130.
  21. Is this an error or a bug? That is, is there an actual error message that you could provide us, or does this code simply not do what you intended it to do? If its the latter, I'd point towards this line engineReplaceAnimation( localPlayer, "ped", "ped", customBlockName, "ped" ) -- ^block ^animation name (doesn't exist) and the fact that there isn't an animation named "ped" in the ped block.
  22. You could do this via a rendertarget (draw the rotated image on the RT and draw the render target unrotated) (RTs aren't designed for this purpose, however. RTs are slower than drawing the contents individually unless you write to them less often than every frame), or via a shader
  23. Depending on whether the 7 digit number is a real number or a string containing digits. function formatNumber(number) if (type(number)=="number") then -- if 'number' was a number rather than a string number = string.format("%07d", number) -- format the number into 7 digits padded by 0 from the front if the number is less than 1000000 end if (type(number)~="string") then return false end -- return a false and exit function if 'number' isn't a string at this point return string.sub(number, 1, 3) .. "-" .. string.sub(number, 4, -1) -- put characters 1 to 3, follow it with a dash, and characters 4+ end
  24. Don't know what you mean by prove. Yes, by having the client send onCustomAnimationSet and the server broadcast onClientCustomAnimationSet to all joined players, and caching the current anim so that new players joining also get the sync. onClientCustomAnimationSet then sets the custom animation on each client it is sent to. You could have gotten all of that just by reading the code, without having to ask us.
  25. Addlibs

    clan panel

    Here's all the help you deserve based on the effort of your original post: https://wiki.multitheftauto.com/wiki/Introduction_to_Scripting_the_GUI
×
×
  • Create New...