Jump to content

Addlibs

Members
  • Posts

    1,060
  • Joined

  • Last visited

  • Days Won

    9

Everything posted by Addlibs

  1. local lastTrigger -- at what hour was the sound last played (to prevent replays in same hour) -- server function timeFunction() local timehour, timeminute = getTime() if lastTrigger == timehour then return -- abort here if we already played the sound for this hour (in case the timer manages to execute twice within the same hour) end if (timehour >= 6 and timehour <= 19) and timeminute == 0 then -- if it's between 6am and 7pm and it's a full hour triggerClientEvent(root, "onClientPlaySound", resourceRoot) triggerClientEvent(root, "onClientPlaySoundAmb", resourceRoot) lastTrigger = timehour -- mark the hour at which it was last triggered elseif (timehour >= 20 or timehour <= 5) and timeminute == 0 then -- if it's 8pm or after, or 5am or before and it's a full hour triggerClientEvent(root, "onClientPlaySoundNight", resourceRoot) triggerClientEvent(root, "onClientPlaySoundAmbNight", resourceRoot) lastTrigger = timehour -- mark the hour at which it was last triggered end end function init() setTimer(timeFunction, 1000, 0) -- keep checking the time every second end addEventHandler("onResourceStart", resourceRoot, init) (slightly corrected, accidentally used equality comparison rather than assignment in lastTrigger and timehour.) This code works for me, triggering these events every minute (an ingame hour). If you want it to work on real hours, you need to use local lastTrigger -- at what hour was the sound last played (to prevent replays in same hour) -- server function timeFunction() local realtime = getRealTime() local timehour, timeminute = realtime.hour, realtime.minute if lastTrigger == timehour then return -- abort here if we already played the sound for this hour (in case the timer manages to execute twice within the same hour) end if (timehour >= 6 and timehour <= 19) and timeminute == 0 then -- if it's between 6am and 7pm and it's a full hour triggerClientEvent(root, "onClientPlaySound", resourceRoot) triggerClientEvent(root, "onClientPlaySoundAmb", resourceRoot) lastTrigger = timehour -- mark the hour at which it was last triggered elseif (timehour >= 20 or timehour <= 5) and timeminute == 0 then -- if it's 8pm or after, or 5am or before and it's a full hour triggerClientEvent(root, "onClientPlaySoundNight", resourceRoot) triggerClientEvent(root, "onClientPlaySoundAmbNight", resourceRoot) lastTrigger = timehour -- mark the hour at which it was last triggered end end function init() setTimer(timeFunction, 60000, 0) -- keep checking the time every minute end addEventHandler("onResourceStart", resourceRoot, init)
  2. -- server function timeFunction(sourcePlayer) local timehour = getTime() if timehour == 6 or timehour == 7 or timehour == 8 or timehour == 9 or timehour == 10 or timehour == 11 or timehour == 12 or timehour == 13 or timehour == 14 or timehour == 15 or timehour == 16 or timehour == 17 or timehour == 18 or timehour == 19 then triggerClientEvent(getRootElement(), "onClientPlaySound", resourceRoot) triggerClientEvent(getRootElement(), "onClientPlaySoundAmb", resourceRoot) end end addEventHandler("onResourceStart", getResourceRootElement(getThisResource()), timeFunction) function timeFunctionNight(sourcePlayer) local timehour, timeminute = getTime() if timehour == 20 or timehour == 21 or timehour == 22 or timehour == 23 or timehour == 0 or timehour == 1 or timehour == 2 or timehour == 3 or timehour == 4 or timehour == 5 then triggerClientEvent(getRootElement(), "onClientPlaySoundNight", resourceRoot) triggerClientEvent(getRootElement(), "onClientPlaySoundAmbNight", resourceRoot) end end addEventHandler("onResourceStart", getResourceRootElement(getThisResource()), timeFunctionNight) This won't work. You need to put it on a timer otherwise you're checking the time only at the time the resource starts. What you want to do is check repeatedly, for example, every minute, if the time is a full hour (that is, minutes == 0) and if so, play the sound, otherwise ignore the call. local lastTrigger -- at what hour was the sound last played (to prevent replays in same hour) -- server function timeFunction() local timehour, timeminute = getTime() if lastTrigger == timehour then return -- abort here if we already played the sound for this hour (in case the timer manages to execute twice within the same hour) end if (timehour >= 6 and timehour <= 19) and timeminute == 0 then -- if it's between 6am and 7pm and it's a full hour triggerClientEvent(root, "onClientPlaySound", resourceRoot) triggerClientEvent(root, "onClientPlaySoundAmb", resourceRoot) lastTrigger == timehour -- mark the hour at which it was last triggered elseif (timehour >= 20 or timehour <= 5) and timeminute == 0 then -- if it's 8pm or after, or 5am or before and it's a full hour triggerClientEvent(root, "onClientPlaySoundNight", resourceRoot) triggerClientEvent(root, "onClientPlaySoundAmbNight", resourceRoot) lastTrigger == timehour -- mark the hour at which it was last triggered end end function init() setTimer(timeFunction, 1000, 0) -- keep checking the time every second end addEventHandler("onResourceStart", resourceRoot, init)
  3. So what do you want? Non-repeated but freezing at last frame? setPedAnimation(thePlayer, "sunbathe", "parksit_w_in", -1, false, false, false, false) -- ^^^^^ loop ^^^^^ freeze at last frame -- this one will not loop and will freeze at last frame: setPedAnimation(thePlayer, "sunbathe", "parksit_w_in", -1, false, false, false, true)
  4. Do you perhaps have a problem with counting? What's so hard in changing a true to a false? setPedAnimation(source, "shop", "smoke_ryd", -1, true, false, false, false) -- ^^^^ change this into a false
  5. The 5th argument is a bool indicating whether to loop or not. Change it to false and it won't loop (repeat) setPedAnimation(source, "shop", "smoke_ryd", -1, true, false, false, false)
  6. If you think anyone will help you if you just dump 959 lines of code, you're quite mistaken. The guides for this section clearly state that you're supposed to post relevant parts of the code, not the whole code. We're not here to make changes in a script you post here, we're here to help you make those changes. The function which creates the weapons is create_client and it is the first function in the client-side code. The code appears to take in arguments (weapon, weapon2, weapon3) which are all elements (presumably dummy elements, but I cannot tell since you didn't post the part of the code that involves triggering createRealWeapon). It is invoked by an event handler for createRealWeapon, so what you need is the server to createElement 3 weapon dummies (or whatever elements they're supposed to be), attach them to the vehicle where you want them attached, and triggerClientEvent createRealWeapon passing along those elements.
  7. Why do you need to disable that text? Do you want to prevent players on your server from getting tips on how to navigate the map?
  8. Which event is canAccessElement attached to?
  9. It should be getTeamFromName("Gangster") instead of just "Gangster", as the function expects a team-element as input, not the name of the team. When the bots are on the same team they will not attack each other in "guarding" mode. To reward players for killing the bots, you'll want to use the "onBotWasted" (parameters are element attacker, float weapon, float bodypart) event called by the slothbot resource, and give money to the attacker.
  10. If you want to use it on the client, you can't use functions like triggerClientEvent. As I've outlined in my post above, on the client, you can literally just add bindKey("F5", "down", func_that_handles_enableRoadblockGUI_event) outside any function and it'll bind as soon as the script loads on the client. If you prefer to use server-side, you can just use the code I gave in that other post
  11. function bindKeysForPlayer(plr) bindKey(source or plr, "F5", "down", funcInput) -- bind it to the event's source (onPlayerJoin) or the first parameter if source doesn't exist (i.e. function wasn't called by an event but by script) end addEventHandler("onPlayerJoin", root, bindKeysForPlayer) function bindKeysForAllPlayers() for k, v in pairs(getElementsByType("player")) do bindKeysForPlayer(v) -- call the binding function for each player end end addEventHandler("onResourceStart", resourceRoot, bindKeysForAllPlayers, false) Unless the server code does anything else other than trigger the client event (e.g. access control), you may just as well move this whole part over to the client. That way you can just bind the key in the main scope of the file outside of any function and it'll bind as soon as the script loads. On the server, you have to use an event to bind the key when a player joins.
  12. It is a method of keeping references to created objects for example. Let's say you want to allow each player to place one object only. What you'll want to have is a table objects with the player as key and object as value. That way, you can easily check if the player already placed an object (i.e. objects[player] is not a nil value), or destroy it easily (i.e. destroyElement(objects[player])). It associates the key (player) to the value (his/her object), keeping a reference you can use elsewhere in the script. The inverse is not as efficient however, to find the key under which it exists (or player to whom it belongs), you'd have to iterate through the table until you find the value referencing the object you want, and then save its key (player) to a variable. Sometimes you'll find scripters use a two tables, one associating the player to the object and another mirror-image table associating objects to players (but if not careful, these two tables can diverge easily and not have the exactly mirrored pairs)
  13. What do you mean? Why is the variable initialized with an empty table? That's so that the indexing operator [] works. It doesn't work on any other value than a table (except custom classes with a metatable). example[1] = 7 -- error: attempt to index a nil value -- so we initialize it because [] doesn't work on nil values example = 1 example[1] = 7 -- error: attempt to index a number value -- but [] doesn't work on numbers either. it only works on tables, -- so we must initialize a table, and because we don't want anything -- inside it, we initialize it as an empty table example = {} example[1] = 7 -- works
  14. local rnd = math.random(1, #cells[dim]) "attempt to get length of field '?' (a nil value)" means you've tried to get the length (# operator) of a nil value (cells[dim]), which means there is no value in the cells table with the index corresponding to the value of dim. Your if-check sets the value of dim to the value of defaultCells, 174, but cells[174] also doesn't exist. Only cells[10] exists. cells = { --[Int ID] = {{Cellák pos}} [10] = {215.36199951172, 108.91190338135, 1000.9522705078, 180}, [10] = {219.84390258789, 108.5353012085, 1000.9569702148, 180}, [10] = {223.37170410156, 107.92459869385, 1000.8811035156, 180}, [10] = {227.17649841309, 107.85209655762, 1000.6198120117, 180}, } By the way, you can't have multiple values under one index. The table above, after construction, is equivalent to cells = { [10] = {227.17649841309, 107.85209655762, 1000.6198120117, 180} } that is, every line starting with [10] = overrides the previous line starting with [10] = You probably wanted something like cells = { --[Int ID] = { [Dim ID] = { {Cellák pos}, {Cellák pos}, ... }, } [10] = { -- in interior 10 [174] = { -- in dimension 174 {215.36199951172, 108.91190338135, 1000.9522705078, 180}, -- first cell in int 10 dim 174 {219.84390258789, 108.5353012085, 1000.9569702148, 180}, -- second cell in int 10 dim 174 {223.37170410156, 107.92459869385, 1000.8811035156, 180}, -- third cell in int 10 dim 174 {227.17649841309, 107.85209655762, 1000.6198120117, 180}, -- fourth cell in int 10 dim 174 }, }, } -- ... local int = getElementInterior(player) if int == 0 or not cells[int] then -- if interior is 0 or there are no cells in the interior int = defaultInt -- set int to default (10) end local dim = getElementDimension(player) if not cells[int][dim] then -- if there are no cells in that interior and dimension dim = defaultCells -- set dimension to default (174) end local rnd = math.random(1, #cells[int][dim]) -- pick a random cell from 1 to however many there are for that interior and dimension local randomCell = cells[int][dim][rnd] -- index the cells table for the random cell -- ...
  15. Addlibs

    Help with SQL

    The client itself doesn't and shouldn't have access to the SQL database. If you need to run an SQL command upon the request of a client, do so by having the client triggerServerEvent and the server executeSQLQuery. Do not let the client choose what query to run. The server should always build the query and look out for and prevent possibilities of SQL injection (e.g. a client asking the server to remove the whole database - big no-no).
  16. rank = ind arank = tonumber(rank)+1 areach = levels[arank] -- arank is not guarenteed to be a valid index, thereby returning a nil value oreach = val.reach -- and thus this line would fail by attempting to index such nil value You need to check if whether the player is at the last level before trying to calculate areach. Also, you should definitely look into using local variables more, it's inefficient to use global variables. function getRankForEXP(plr,exp) local newrank = false local currank = tonumber(getElementData(plr,"Level")) or 0 local curreach = tonumber(getElementData(plr,"LevelXP")) or 100 local curoreach = tonumber(getElementData(plr,"oLevelXPReach")) or 0 local rank, areach, oreach -- declare these local in this scope, so when they're written to they don't use _G but rather upvalues for ind,val in ipairs(levels) do if ind > currank and val.reach <= exp then rank = ind areach = levels[ind+1] -- optimised this a little if areach then areach = areach.reach else -- TODO: final level, no areach end oreach = val.reach newrank = true end end if newrank then return rank,areach,oreach end return currank, curreach, curoreach end
  17. The snippet you've posted seems to be so carelessly copied and pasted it doesn't look valid. I can take a couple guesses such as 'or' actually being 'for', etc. but it would be better if you posted a more complete example, including the definition of the levels table, and the definition of getRankForEXP (if it's not the code right above, stripped of it's function definition line)
  18. You should never create a timer on every frame like you're doing right now. It will create 60 timers in a second, 300 in 5 seconds (meaning you'll have up to 30 timers running at any one time just from this code). Looking at the code, you don't even need the timer if you're using interpolateBetween, so remove lines 25 through 28. The pos variable can and should be local to make lookup and reading faster on Lua. Your problem appears to be in duration math. local endTime = start + 1000 local duration = endTime - start -- should just be local duration = 1000 Second problem is that you don't seem to move the text at all, just the rectangle, but I hope you can figure that one out on your own.
  19. dxDrawImage3D useful function (based upon dxDrawMaterialLine3D) is what you're looking for.
  20. Addlibs

    table problem

    local button = {} function createMenu() button[1] = ... button[2] = ... -- either add handlers yourself addEventHandler("onClientGUIClick", button[1], click, false) addEventHandler("onClientGUIClick", button[2], click, false) -- if you add a false after the function name (getPropagated parameter), the function won't trigger for the elements parents (e.g. the parent gui window) -- or use a loop here for i = 1, #button do -- start at i = 1 and perform the body of the block and increment i until i = #button (number of elements in button table) addEventHandler("onClientGUIClick", button[i], click, false) end end function click() -- beacuse getPropagated is set to false on all handlers, you don't need to test whether this is a valid source (that is, source will never be your guiwindow), all you need to do is branch depending on which button it is if source == button[1] then ... elseif source == button[2] then ... end end Would be a much better way of doing this, imo. I'm not sure but you may need to put the click function above the function with addEventHandlers.
  21. If you nullify the unix_socket variable (nil or false), it will use the 'host' variable. Put the IP you want in host. mainDB = dbConnect("mysql", (unix_socket and "unix_socket="..unix_socket or "host="..host)..";dbname="..dbname, user, password) local unix_socket = nil local host = "255.255.255.255" -- your ip here mainDB = dbConnect("mysql", (unix_socket and ("unix_socket="..unix_socket) or ("host="..host))..";dbname="..dbname, user, password)
  22. To check if JSON is valid itself, all you need to do is check whether the result of fromJSON is not a nil. If you want to make sure the actual values within that JSON are correct and within bounds, you'll simply need to make your own function which tests every part of the JSON, makes sure the required keys are present or assign default values to them, make sure the values are within the bounds, etc. function checkJson(text) local theTable = fromJSON(text) if not theTable then return false end -- it's not valid JSON if not theTable.some_required_key then return false end -- doesn't have the required key-value pair if theTable.some_required_key > maximum_allowed_value then return false end -- actual value exceeds allowed value if theTable.some_other_key and theTable.some_other_key > maximum_allowed_value then theTable.some_optional_key = maximum_allowed_value end -- update the value to be within the bounds if it would otherwise be outside it -- etc return theTable -- return the updated table if changes were made end function loadMyJson() local f = fileOpen("settings.json") local json = fileRead(f, fileGetSize(f)) fileClose(f) local settings = checkJson(json) if not settings then outputChatBox("Could not load settings.json. Loading defaults...") settings = g_DefaultSettings end -- etc end If you simply don't want people to change the file manually at all, you could encodeString with TEA, or encodeString with TEA a SHA256 hash of it and store it alongside, and check if the hashes match. The person won't be able to generate a valid hash if they don't know how the TEA secret. This is in effect similar to what a HMAC does but I don't think MTA has HMAC functions built in. Naturally, if you choose the latter, the safest bet would be to have the server send the tea secret via an event rather than having that secret hardcoded in the script file. It would still be possible to lift it out of memory either way, but at least if it's on the server it can't be somehow extracted out of the file offline, through decrypting, decompiling or whatever.
  23. Addlibs

    warnings

    Well, I'm not sure if there's any significant performance loss, but definitely no timer is better than with timer. Timers, however little performance impact they have, do add up, and too many timers may contribute to slowdowns. A better approach would be like this local x,y = guiGetScreenSize() local duration = 8000 -- duration of full alpha, in miliseconds local fadeTime = 700 -- duration of fading from 255 to 0 local startTick = getTickCount() -- do this whenever you want the "LEVEL UP!" text to appear for duration + fadeTime function drawText() local ticksPassed = getTickCount() - startTick -- compare the current tick count to the starting tick count to calculate the number of ticks passed local alpha = 255 -- set the alpha to full 255 at the beginning (this'll be used as the alpha value until ticksPassed is greater than duration) if ticksPassed > duration then -- if number of ticks passed exceeds threshold, start reducing alpha alpha = math.max(0, alpha - ((ticksPassed - duration) / fadeTime)) -- subtract from 255 a progressively larger number as the ticks past duration approach duration + fadeTime, clamping at 0 so it doesn't go into negatives end if alpha > 0 then -- if alpha is greater than 0, queue the text draw (a little optimisation as there's no need to queue it if it's completely invisible, while at a cost of branching evaluation, it's still faster than calling hardcoded functions) dxDrawText("LEVEL UP!", x/2, y/2, x/2, y/2, tocolor(255,255,255,alpha), 2, "bankgothic", "center", "center") end end addEventHandler("onClientRender", root, drawText) -- an additional improvement would be to only bind the event to a handler when necessary, unbinding it once the text doesn't need to appear. After all, this function will be triggered every frame simply for it to make some math and draw no text if getTickCount() - startTick > duration + fadeTime This is a lot more maintainable, and uses only one function to do one thing. Your code uses to functions to do what one could do. This code only has one dxDrawText call, meaning if you want to change some parameters, you only need to do it in one place, not two.
  24. Addlibs

    warnings

    The errors appear because you're constantly attempting to bind the onClientRender event to drawText or fadeText when it's already bound to it. Specifically, line 5 creates a new timer every single frame, and after 5 seconds all those timers elapse and attempt to bind the event to fadeText, at the same rate (e.g. 30 times a second if you run on 30 FPS and hence create 30 timers per second). The easiest way to solve this would be an isTimer check before creating a new timer to make sure it doesn't exist yet. However, the whole code design is messy and not ideal. You should think about another way of writing that code, from scratch. Using only one event handler.
×
×
  • Create New...