• Content Count

  • Joined

  • Last visited

Community Reputation

95 Popular


About MrTasty

  • Rank
    Road Dawg


  • Location
    United Kingdom
  • Occupation
    Scripting Guru

Recent Profile Visitors

2,050 profile views
  1. MrTasty

    How to set AK-47 weapon properties to TEC-9?

    Then you probably just want to do setWeaponProperty(32, "pro", "flags", 0x000800) -- toggle 'can use 2x guns at same time' flag -- or setWeaponProperty(32, "pro", "flag_type_dual", false) -- turn off flag_type_dual (I've never used this method, can't attest as to whether it works)
  2. MrTasty

    How to set AK-47 weapon properties to TEC-9?

    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 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
  3. MrTasty


    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
  4. MrTasty

    Client script Cache, fileDelete(), luac

    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.
  5. MrTasty

    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.
  6. MrTasty

    "Permanent" ID System

    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.
  7. MrTasty

    assalt-bank- help amount of four or more players to rob

    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)
  8. MrTasty

    [HELP] How to use .CMF files

    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.
  9. MrTasty


    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
  10. MrTasty

    play sound when sending top bar messages

    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.
  11. MrTasty

    I want to encode script

    If you're talking abot compiling with encryption (extra obfuscation), you can use
  12. MrTasty

    Replacing CJ hair .dff files on server

    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).
  13. MrTasty

    [HELP] Map bug

    Try setOcclusionsEnabled
  14. MrTasty

    Group name over head.

    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.
  15. MrTasty

    Help in script

    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.