Jump to content

Dzsozi (h03)

Members
  • Posts

    682
  • Joined

  • Last visited

  • Days Won

    2

Everything posted by Dzsozi (h03)

  1. Thank you, I didn't know I could do this with getElementsByType ?
  2. This is a great idea and would be much simpler and easier indeed, now that you said I realised it. But I think the reason I wanted to do a scanning type solution is because of the custom placed objects (i know I can check those and I already did in the original script), but also, more likely because of the removed world models. What would you suggest to check that, if I were doing the solution you mentioned? I have some custom maps which for sure remove some lamps, I made some that removes even a whole street.
  3. Sorry for bumping this topic that late, I got some free time now, I still wasn’t able to finish this project based on the examples, also I just realised that the scan will be going diagonally if I add to x and y at the same time, therefore the scan wouldn’t apply to the whole world. I would like to achieve an effect of scanning such as from the top left corner of the map to the bottom right, going sideways, and when the camera reaches the right side, it snaps back to the left and gets offset on the y axis. I am not sure about how to achieve this between the range of -3000 to 3000 on the x and y axis inside a coroutine function with loops, am I even doing it the right way by using for loop? I would have to prevent the loop from happening on the y axis before the scanX reaches the right side. Right now I can’t send my current code and I can’t remember what errors I got, I’m at work but I wanted to reply and let you know that I’m still interested and trying to fix & get it done. I will post my code asap, could you please maybe help me finishing and correcting it?
  4. Thank you for teaching me, really, I tried to make the scanning with these functions, I get an error spam "cannot resume dead coroutine" because of the timer (this line) STREET_LIGHTS.SCAN_TIMER = setTimer(resumeScan, 1000, 0) Here's my current code, could you help me with what am I doing wrong? local STREET_LIGHTS = { VALID_MODELS = { [1294] = {name = "mlamppost", offsets = {Vector3(0,0.3,1)}, radius = {start = 0.075, stop = 50}}, [1297] = {name = "lamppost1", offsets = {Vector3(0,0.3,1)}, radius = {start = 0.075, stop = 50}}, [1290] = {name = "lamppost2", offsets = {Vector3(3,0.03,5.4), Vector3(-3,0.03,5.4)}, radius = {start = 0.075, stop = 75}}, [1226] = {name = "lamppost3", offsets = {Vector3(-1.3,0.165,3.675)}, radius = {start = 0.075, stop = 50}}, }, OBJECT_LIGHTS = {}, } local SCAN = { current = Vector2(-3000, -3000), } local SCAN_WORLD = coroutine.create(function() for x = SCAN.current.x, 3000, 10 do if math.abs(x) % 100 == 100 then SCAN.current.x = x print"yield" coroutine.yield() end for y = SCAN.current.y, 3000, 10 do if SCAN.current.x >= 3000 and SCAN.current.y >= 3000 then if isTimer(STREET_LIGHTS.SCAN_TIMER) then killTimer(STREET_LIGHTS.SCAN_TIMER) end STREET_LIGHTS.SCAN_TIMER = nil setCameraTarget(localPlayer) coroutine.yield() break end if math.abs(y) % 100 == 100 then SCAN.current.y = y coroutine.yield() end setCameraMatrix(x, y, 500, x, y, 0) local hit, _,_,_,_,_,_,_,_,_,_,worldModelID,worldX,worldY,worldZ,worldRotX,worldRotY,worldRotZ,_ = processLineOfSight( x, y, 500, x + 5, y + 5, 0, true, false, false, true, false, false, false, false, nil, true, false ) if hit then --if STREET_LIGHTS.VALID_MODELS[worldModelID] then print(worldModelID) -- do i actually get the models on screen? i get some numbers for sure but camera is stuck and position is not updating --end end end end return true end) local function resumeScan() return coroutine.resume(SCAN_WORLD) end addEventHandler("onClientResourceStart", resourceRoot, function() if not isTimer(STREET_LIGHTS.SCAN_TIMER) then STREET_LIGHTS.SCAN_TIMER = setTimer(resumeScan, 1000, 0) end return true end) And actually I don't even get the "yield" output as expected from this line: if math.abs(x) % 100 == 100 then SCAN.current.x = x print"yield" coroutine.yield() end Camera is stuck at one place on the top right corner of the map and first I get a bunch of spam of 3 or 4 numbers, then the error about cannot resume dead coroutine.
  5. Sorry I didn’t make time to reply, my fault. Actually it is not so clear, I don’t really know how to use coroutine functions, I never did before. Not so sure how to implement it for the purpose I need. Thank you for the advice I didn’t even think about that and actually makes sense to do it.
  6. Hello! I would like to get the positions of all the lampposts. I was trying to use processLineOfSight to achieve this, since getElementsByType("object") doesn't return default world objects. I tried using a loop from 0 to 3000 on the x and y axis, but I get an infinite running script error. Why do I get this error and how could I achieve a scan on the world? Here's my current code: (I commented out most parts while trying to find the cause of the problem, so I would only see the positions of all the lamps if the scan was successful) local STREET_LIGHTS = { VALID_MODELS = { [1294] = {name = "mlamppost", offsets = {Vector3(0,0.3,1)}, radius = {start = 0.075, stop = 50}}, [1297] = {name = "lamppost1", offsets = {Vector3(0,0.3,1)}, radius = {start = 0.075, stop = 50}}, [1290] = {name = "lamppost2", offsets = {Vector3(3,0.03,5.4), Vector3(-3,0.03,5.4)}, radius = {start = 0.075, stop = 75}}, [1226] = {name = "lamppost3", offsets = {Vector3(-1.3,0.165,3.675)}, radius = {start = 0.075, stop = 50}}, }, OBJECT_LIGHTS = {}, } function processStreetLights() for x = 0, 3000, 5 do for y = 0, 3000, 5 do local hit, _,_,_,_,_,_,_,_,_,_,worldModelID,worldX,worldY,worldZ,worldRotX,worldRotY,worldRotZ,_ = processLineOfSight( x, y, 0, x + 5, y + 5, 500, true, false, false, true, false, false, false, false, nil, true, false ) if hit then --[[if STREET_LIGHTS.VALID_MODELS[worldModelID] then local data = STREET_LIGHTS.VALID_MODELS[worldModelID] local searchlights = {} for i, offset in pairs(data.offsets) do local startPos = Vector3(worldX, worldY, worldZ + offset.z) --Vector3(exports["sa_utility"]:getPositionFromElementOffset(obj, offset.x, offset.y, offset.z)) startPos.x = worldX + math.sin( math.rad( worldRotZ ) ) * offset.x startPos.y = worldY + math.cos( math.rad( worldRotZ ) ) * offset.y local endPos = startPos --Vector3(exports["sa_utility"]:getPositionFromElementOffset(obj, offset.x, offset.y, 0.25)) endPos.z = worldZ + 0.25 searchlights[i] = SearchLight(startPos, endPos, data.radius.start, data.radius.stop, true) end --STREET_LIGHTS.OBJECT_LIGHTS[obj] = searchlights table.insert(STREET_LIGHTS.OBJECT_LIGHTS, searchlights) end]] print(worldX, worldY, worldZ) end end end --[[for k, obj in pairs(getElementsByType("object")) do if STREET_LIGHTS.VALID_MODELS[obj.model] then local data = STREET_LIGHTS.VALID_MODELS[obj.model] local searchlights = {} for i, offset in pairs(data.offsets) do local startPos = Vector3(exports["sa_utility"]:getPositionFromElementOffset(obj, offset.x, offset.y, offset.z)) local endPos = Vector3(exports["sa_utility"]:getPositionFromElementOffset(obj, offset.x, offset.y, 0.25)) searchlights[i] = SearchLight(startPos, endPos, data.radius.start, data.radius.stop, true) end STREET_LIGHTS.OBJECT_LIGHTS[obj] = searchlights end end]] return true end addEventHandler("onClientResourceStart", resourceRoot, function() processStreetLights() return true end) Thank you for help in advance!
  7. It is working and the text is drawn, the problem is that you are setting the text position outside of the render target canvas size. When you are drawing inside a render target, the positions start from 0 again. textureWidth, textureHeight = 100, 50 texture = dxCreateRenderTarget(textureWidth, textureHeight, true) dxSetRenderTarget(texture, true) dxDrawText("text", 5, 5, textureWidth, textureHeight) dxSetRenderTarget() dxDrawImage(posx, posy, textureWidth, textureHeight, texture) This will draw the render target as an image wherever you want, and inside of it will be the text on the top left corner, offset by 5 pixels.
  8. Thank you so much, it works and I also managed to do the step 4 to manage remaining items, so I can add to main inventory or drop them. I appreciate it and your time
  9. Hello! I started re-doing my inventory system, I made some functions based on this topic I did everything without a problem, everything works fine, except a calculation I am trying to do when giving an item to a container. I have stack limits defined for items inside an ITEM_TABLE. The stack limit for, let's say Apple item is 5. When calling the giveItem function, I would like to check if the count exceeds the stack limit, then loop the item giving process until the newly calculated count value is less than the stack limit. So let's say I call -- itemID, count giveItem(1, 8) -- give 8 apples, but the apple has a stack limit of 5, so I would like the player to end up with 2 apple items, one with a count of 5 and one with a count of 3 So then I would like the player to have 2 different apple items, one with a count of 5 and one with a count of 3 This is how I was trying to do it, but it seems like I can't use the repeat until/while loop properly, or I am missing calculations, I can't get the result I want. function ContainerMethods:giveItem(itemID, count) local itemDetails = getItemDetails(itemID) if not itemDetails then return false end count = tonumber(count) or 1 local carrySlot = self:findExistingItemSlot(itemID) if carrySlot and carrySlot.count + count <= itemDetails.stacklimit then -- if the container has an item like this and it's less than the stack limit, add the count carrySlot.count = carrySlot.count + count else local tempCount = count repeat -- i don't know if i should use repeat until, or while loop, repeat until seems like the correct way of doing it --while tempCount > itemDetails.stacklimit do local slotX, slotY = self:findFreeSlotForItem(itemID) if slotX and slotY then -- i am working with a grid inventory with different item sizes for x = slotX, slotX + itemDetails.size.x - 1, 1 do for y = slotY, slotY + itemDetails.size.y - 1, 1 do self.grid[x][y] = true end end local newItem = { ["itemID"] = itemID, ["count"] = tempCount, -- should i make calculations here as well?? i don't think so but i could be wrong ["slot"] = {x = slotX, y = slotY}, } table.insert(self.items, newItem) tempCount = tempCount - itemDetails.stacklimit -- tempCount is the difference print(tempCount) else print("no empty space for item '" .. itemID .. "' in container '" .. self.name .. "'") return false end --end until tempCount < itemDetails.stacklimit -- repeat adding a new item until the count is less than the stack limit end return true end But the result I get is: Notice that the debugscript prints 3, but my inventory has only one item with the count of 8, instead of 5 and 3. How can I make this function properly, so I don't have to worry about it in the future when I give an item to the player? Thank you for your help in advance!
  10. Sorry for not responding, meanwhile I solved the problem and this topic went unnoticed by me. I solved it by using Kam's updated scripts made by gold_fish ([REL] KAM's GTA Scripts (2018) / UPD: 31.05.2020 / - Tools - GTAForums). I read that this updated script supports exporting and importing normals and also reflections, therefore the problems were solved. Also I think I had some issues with the model itself, I was playing around with the smoothing groups and etc. Using the updated scripts solves the problem, however I will have to remake my model tho. This topic can be locked.
  11. setElementData might come handy in these cases. Good luck with scripting!
  12. The second function has a problem returning the occupied vehicle, I don't know if that could be the cause of the problem you are having, or is that just a typo while you were writing the examples on forum. function toggleLights(playerSource, cmd) local vehicle = getPedOccupiedVehicle(playerSource) -- use playerSource instead of thePlayer, thePlayer is not defined so this will return an error and toggling lights won't happen if (vehicle) then Yes, this would cause lag and lots of unnecessary data flow. You don't have to get a mysql result everytime you lock/start a vehicle. If I were doing toggleLock and toggleEngine functions for vehicles, I would just simply use them when a player types a command / presses a key, as you are doing, inside those toggleLock and toggleEngine functions simply use setVehicleLocked and setVehicleEngineState like function toggleLock(vehicle, state) if not vehicle then return false end setVehicleLocked(vehicle, state) return true end For the command you would do function lockCommand(player, command) local vehicle = getPedOccupiedVehicle(player) if vehicle then toggleLock(vehicle, not isVehicleLocked(vehicle)) end end addCommandHandler("lockveh", lockCommand) Keep the actual toggle functions seperate from the command functions, that way it will be easier for you to see, utilize and use those functions later as well. Then have a different save resource or function to save the data to mysql. You can make a timer every 5 seconds to call the saving, and inside the save function you would get every desired vehicle and their state of engine and locks to update mysql data with the new ones. This would make data usage and network flow much more less in my opinion, other than calling for mysql everytime a player types a command; imagine if they start spamming. Of course you can make anti-spam checks, but overall that way would be much more inefficient. Also there is a resource that you can use to check the usage of resources: performancebrowser - Multi Theft Auto: Wiki I believe it is already included in default MTA resources.
  13. Try muzzle_texture* instead of muzzle_texture4 engineApplyShaderToWorldTexture(theTechnique, "muzzle_texture*")
  14. Possibility to create functioning ladders, create a ladder without the custom object, for default world ladders, or create a brand new one. Only vertical ladders are supported with Z rotation. Features one custom object. Easy to use functions, ~240 lines of code. Sprint button for fast climbing Jump button for jumping off a ladder Forward button for climbing up Backward button for climbing down You can basically create any length ladder with correct positions, since you can adjust offsets for start and end positions, so shifting leadders in the ground is a possibility to match the height of a building. Ladder is using collision tuboids for player detection. Contains a "/getladderpos" utility command to get the corrected position and rotation in front of player, copies Vector3 and int rotation to clipboard. Power of creating more interesting maps, possibility and an idea for a new "ladder parkour" gamemode, or just create more interesting roleplay / deathmatch / other scenarios by adding climbable ladders to the environment. I am planning to add custom animations, these default ones are good for now, and default world ladder positions in the future. I'm waiting for your feedback, let me know if you like it and/or have any suggestions!
  15. Thank you again! I will try to make and implement it! Really appreciate your time, have a nice day!
  16. Finally, thank you so much!! This is what I was looking for, I just couldn't figure out how to implement it, I already knew in my mind that I will have to make 2 tables for this. For some reason I thought I can make the 'update' and 'destroy' functions in the same table as the 'new' function, turns out I can't if I want to avoid bad things to happen. Now I have this setup at the beginning and it works fine as intended local Highlight = {} --Highlight.__index = Highlight -- I DONT THINK I WILL NEED THIS ANYMORE setmetatable(Highlight, {__call = function(_,...) return Highlight:new(...) end}) -- calling Highlight will call the Highlight:new method local HighlightConstructor = {} HighlightConstructor.__index = HighlightConstructor -- I NEED THIS INSTEAD playerHighlight.style returns given style, playerHighlight.new or playerHighlight:new doesn't work like I wanted to. Yes, I knew that, thank you for giving a heads up! I changed it from . to : because you did it that way as well in your response, I am not sure tho what difference it makes in this case. I mean it should make no difference right here, if I am correct, since I am not using self inside the Highlight:new method. Anyways thank you once again! I learned new stuff and I am happy for that, also I can finally finish this resource xd EDIT: By the way, can I get rid of CREATED_HIGHLIGHTS and make it part of Highlight table? Will it work with a Highlight = {created = {}} setup or something like this? Or should I just keep them seperate? Since I was thinking about making methods like Highlight.getAllByElementType and such so I can get every created highlight of vehicles for example.
  17. I am still in need of help about sending different Vector3 values to an array inside HLSL, then reading those different Vector3 values in HLSL.
  18. For more explanation, please read the comments I made in the scripts as well; I am sorry, but I don't really understand how should I change my code. Could you please provide me a solution for this? So I have a Highlight table, each time this table gets called, a new Highlight is being created for the given element variable (I would like to make it function like the default MTA OOP stuff, like Vehicle(model, position) instead of Vehicle.new(model, position), so I have this setup here: local CREATED_HIGHLIGHTS = {} local Highlight = {} Highlight.__index = Highlight setmetatable(Highlight, {__call = function(_,...) return Highlight.new(...) end}) function Highlight.new(element, style, color, flashSpeed, intensityOrThickness) if not isElement(element) then return false end if CREATED_HIGHLIGHTS[element] then return false end local data = setmetatable({}, Highlight) -- this has something else to do with it I guess -- set variables -- data.element = element -- and so on return data end And I have methods for it like Highlight:update() and Highlight:destroy(), the way I did it for example: function Highlight:destroy() if not CREATED_HIGHLIGHTS[self.element] then return false end if self.shader then self.shader:destroy() end CREATED_HIGHLIGHTS[self.element] = nil return true end When I create a new highlight for the localPlayer, like: local playerHighlight = Highlight(localPlayer, "outline", {255,0,0,255}, 0, 1) Now everything works fine above, highlight gets created, I can access the data with playerHighlight.thickness and such, BUT I can then use the playerHighlight table (which should contain only data, like style, thickness etc) to create a new highlight on a totally different element like: local dumpster = Object(1337, localPlayer.position + Vector3(0,3,1)) print(playerHighlight.new(dumpster, "fresnel", {100,200,255,255}, 2, 0.5)) -- returns table, I don't want to use .new here -- how can I make it return nil, or avoid calling of .new, but keep the :update() and :destroy() methods -- I would like playerHighlight to contain only the data given before Now I understand that the data table inherits from Highlight table at the Highlight.new function, so to the data table the methods get passed as well, but how should I change it so it won't inherit all the functions, I would like to access actual data and only methods with colon (:update, :destroy), not with dot (.new) . So my guess is that this line should be changed to something else instead of Highlight, I imagine local data = setmetatable({}, Highlight) -- change Highlight to what? Am I missing the creation of another table? Sorry if it looks like I am asking the same question twice, I am not ignoring your reply but I don't understand your explanation @IIYAMA, I mean I don't understand how should I implement it in this case.
  19. UPDATE: I got rid of the loadstring()() injection concept for this Class.lua script because it looks unnecessary, I will just make classes independently in resources because it is almost the same effort to do right now for what I would like to achieve, so I just changed local Highlight = {} --instead of Class() -- Highlight:new to Highlight.new, and inside the .new function local data = setmetatable({}, {__index = Highlight}) However, I can still call .new function in the testing section with -- testing local playerHighlight = Highlight(localPlayer, "fresnel", {0,255,0,255}, 0, 1) -- creating new Highlight class for player local dumpster = Object(1337, localPlayer.position) playerHighlight.new(dumpster) -- [[ I DON'T WANT TO DO THIS :/ ]]
  20. That's how I did it in the first place, but I came up with an easier, and imo clenaer looking injector for lua files, this is how I did it: ooplib/Class.lua (however, if I make Class = {} a local variable, I get Attempt to call global 'Class' nil value error, I am curious why?) Class = {} Class.__index = Class setmetatable(Class, {__call = function( _,... ) return Class.new(...) end }) function Class.new(properties) local self = setmetatable(properties or {}, Class) return self end ooplib/infuse.lua function getFileContent(filePath) if not filePath then return false end if not fileExists(filePath) then error("Can't open '"..filePath.."' (file doesn't exist)", 2) return false end local f = fileOpen(filePath, true) local content = f:read(f.size) f:close() return content end function classTemplate() return getFileContent("Class.lua") end otherresource/testscript.lua loadstring(exports["sa_ooplib"]:classTemplate())() -- inject the Class.lua file's content local Highlight = Class() -- call the Class function from the injected script Highlight.__index = Highlight setmetatable(Highlight, {__call = function(_,...) return Highlight:new(...) end}) -- making this so I can call Highlight() function Highlight:new(element, style, color, flashSpeed, intensityOrThickness) -- create a Highlight class local data = setmetatable({}, {__index = self}) -- COULD BE A PROBLEM HERE? Change self to what? Or is it okay like this? -- set variables data.element = element -- and so on return data end -- testing local playerHighlight = Highlight(localPlayer, "fresnel", {0,255,0,255}, 0, 1) setTimer(function() local dumpster = Object(1337, localPlayer.position) playerHighlight:new(dumpster) -- [[ I DON'T WANT TO DO THIS :/ ]] end, 2000, 1) But as you look at the testscript.lua script, I commented a line which I have new problems with. I can call the :new method from the returned playerHighlight data. How can I avoid doing that? Now I imagine that I would have to change the __index from self to something else? local data = setmetatable({}, {__index = self}) Am I missing steps on setting up the Class.lua script?
  21. engineSetModelLODDistance setFogDistance setFarClipDistance Combining these functions should do the trick if you are trying to make the view distance higher. In some cases using setFarClipDistance should be enough. Also there are setVehiclesLODDistance and setPedsLODDistance Take a good look on these functions' wiki pages, high values for some of these could cause fps lag. Some of these functions' maximum values are also locked to a certain value.
  22. UPDATE: I think I found the cause of the problem; if I make the Class table a global variable instead of a local variable, the script works, debugscript outputs 'xd' from testscript.lua as intended. But wouldn't the loadstring function make the script look basically like this? --[[ after using loadstring(createClass())() I imagine the script would have local Class = {} Class.__index = Class setmetatable(Class, {__call = function( _,... ) return Class.new(...) end }) function Class.new() local self = setmetatable({}, Class) return self end at the beginning, after that comes the part down below | | V ]] local testClass = Class() testClass.name = "xd" function testClass:getName() return self.name end print(testClass:getName()) So I don't understand why making the 'Class' table as a local variable would be a problem. Is it because the type is defined as 'shared' in the meta, that's why I should make it a global variable?? UPDATE: I changed Class.lua type from 'shared' to 'server' to match testscript.lua type, made Class a local table again, and I got the error again, so I don't understand really why it should be a global variable. Anyways, the fix was changing function createClass() return [[ local Class = {} Class.__index = Class setmetatable(Class, {__call = function( _,... ) return Class.new(...) end }) function Class.new() local self = setmetatable({}, Class) return self end ]] end to function createClass() return [[ Class = {} Class.__index = Class setmetatable(Class, {__call = function( _,... ) return Class.new(...) end }) function Class.new() local self = setmetatable({}, Class) return self end ]] end in case if you need this for your scripts. I would still appreciate if somebody could answer my questions regarding that problem!
  23. Hello! Lately I've been trying to make every script in OOP for simplicity. Since you have to define metatables and setup classes and methods for OOP to work properly, I tried to make an export function for it so I can create classes more easily. But when I was trying to do that and test it, I get an error message, which says: And I don't really understand the reason why. What am I doing wrong? Right now I have 2 lua files, one of which contains the class creation, which is the following: Class.lua (set to 'shared' type in meta) function createClass() return [[ local Class = {} Class.__index = Class setmetatable(Class, {__call = function( _,... ) return Class.new(...) end }) function Class.new() local self = setmetatable({}, Class) return self end ]] end and I have a test script, which is in the same resource, just a different lua file: testscript.lua (set to 'server' type in meta) loadstring(createClass())() local testClass = Class() testClass.name = "xd" function testClass:getName() return self.name end print(testClass:getName()) As you can see I am using loadstring() function to infuse the class creation to the testscript.lua, but despite the fact I still get an error about Class() function being nil, why? Also, I have the Class.lua (which is set as 'shared') before anything else in the meta, so I really don't understand what causes this error. Just in case if you were wondering, here is the meta.xml: <meta> <oop>true</oop> <script src="Class.lua" type="shared"/> <script src="testscript.lua" type="server"/> </meta> Right now this is the full resource basically. Thank you for your answer in advance!
  24. That could be a solution as well. I don't know the way you made your script since you didn't post it. But I would say that with my example you wouldn't need to check spamming with the onPlayerCommand event, I think it would make things easier. Also, the timer in my example is not necessary, I thought you would like to add 2.5 seconds delay to destroy the object, for some reason. But yes, in my opinion, if you are using this table method it would make things much easier for you to handle. Here's a little bit simpler version without the 'delay' timer, you could test it to see the difference for yourself. local SMOKERS = {} function isPlayerSmoking(player) if SMOKERS[player] then return true end return false end function startSmoking(player) if isPlayerSmoking(player) then outputChatBox("You already have a cigarette.") return false end SMOKERS[player] = {} SMOKERS[player].cigarette = createObject(...) -- fill this with the correct data setPedAnimation(player, "-", "-",false,false,false,false) -- set anim to smoking, you have to correct this exports["pAttach"]:attach(SMOKERS[player].cigarette, player) -- some more stuff you have to do, fill the bone positions and more return true end function stopSmoking(player) if not isPlayerSmoking(player) then outputChatBox("You don't have a lit cigarette.") return false end setPedAnimation(player) exports["pAttach"]:detach(SMOKERS[player].cigarette, player) destroyElement(SMOKERS[player].cigarette) SMOKERS[player] = nil -- i don't think you need spam protection if you are using the table method, because the player can only start to smoke again if we set the table value of him to nil return true end Also, this way each player has their "own" cigarette. If you were using local variables for the object, and have 2 players, you couldn't destroy player 1's cigarette because the variable gets a new userdata value when you are creating the cigarette object for player 2. I hope I was understandable with my statements.? Note that I didn't test the script in game!
  25. My guess is that when executing the command while doing the smoking, the local variables ('smoking', which is the cigarette object I suppose) gets overwritten by a new userdata, the same goes for the timer. Try using a table structure for things like this, that way you can make a difference between players, something like: local SMOKE = { players = {}, } function startSmoking(player) if SMOKE.players[player] then return false end -- this is needed so you can't start smoking if you are already doing it SMOKE.players[player] = {} SMOKE.players[player].cigarette = createObject(...) -- fill this with the correct data SMOKE.players[player].stopTimer = nil setPedAnimation(player, "-", "-",false,false,false,false) -- set anim to smoking, you have to correct this exports["pAttach"]:attach(SMOKE.players[player].cigarette, player) -- some more stuff you have to do, fill the bone positions and more return true end function stopSmoking(player) if not SMOKE.players[player] then return false end -- check whether we should continue running the script, if the player is not smoking then don't execute furthermore if isTimer(SMOKE.players[player].stopTimer) then -- make sure to always kill the timer to avoid the glitch you were experiencing killTimer(SMOKE.players[player].stopTimer) SMOKE.players[player].stopTimer = nil end setPedAnimation(player) -- remove the animation if not SMOKE.players[player].stopTimer then -- check if the timer exists, just for safety SMOKE.players[player].stopTimer = setTimer(function() -- you want to always create the timer, so that's why it's outside the if isTimer statement exports["pAttach"]:detach(SMOKE.players[player].cigarette, player) -- detaching before destroying the object, idk if it's necessary to include detach if you destroy the object, maybe you can delete this line destroyElement(SMOKE.players[player].cigarette) SMOKE.players[player] = nil end, 2500, 1) end return true end Also with this method you can check for the currently smoking players and make a function for it, like: function getSmokingPlayers() return SMOKE.players end But this getSmokingPlayers() function is only necessarry if you would like to get the smoking players in other resources, so you could make an export for it. If you were going to loop it then the index will be the player and the value will be a table, you could make something like: function stopSmokingAllPlayers() for player, data in pairs(getSmokingPlayers()) do -- NOTE THAT: getSmokingPlayers() is the same as SMOKE.players, you could also do that, only in the same script/resource tho print(type(data.cigarette)) -- should output 'object' in the debugscript stopSmoking(player) end return true end I have not tested this script, but I think it should work fine.
×
×
  • Create New...