Ceeser

Members
  • Content Count

    26
  • Joined

  • Last visited

Community Reputation

6 Neutral

About Ceeser

  • Rank
    Advanced Member

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Ceeser

    Camera + Cursor

    Maybe take a look into [editor] - freecam resource, that might help you or is exactly what you need
  2. Ive once made a scoreboard which you could use and edit the config: https://ffs.gg/threads/82322-Release-Scoreboard-Easy-editable-Video?highlight=speedscripting
  3. Hello guys, A while ago I've been thinking "saving data is pretty annoying.. alot of lines, you are often doing it multiple times for different scripts." So I decided to make a resource as a central handler of data storing/loading. Now I want to share this resource to the community and hope that it will also help you save some time at scripting. The resource (including its functions) are added to the MTA Wiki which can be found here. What is xmlData? xmlData is a resource that provides 3 shared (so server- and client-side) exported functions for automated saving/loding/deleting of files: xmlSaveData (Wiki Page) xmlLoadData (Wiki Page) xmlDeleteData (Wiki Page) xmlSaveData require the data it should store to be a table and xmlLoadData will return the data as a table. These functions are exported function by the resource, so you need to call them. Example: local xml = exports.xmlData local tbl = {posX = 500, posY = 300, sizeX = 300, sizeY = 200} -- Saving xml:xmlSaveData("myFileName", tbl, false, true) -- This will save the file non-serverProtected but encrypted -- or you can do this xml:xmlSaveData("myFileName", tbl, 7) -- This will save the file serverProtected, encrypted, resourceProtected -- Loading local myTable = xml:xmlLoadData("myFileName", 7) -- This will attempt to load the data saved in highest security level -- Note: You need to load the data on the same security level as you saved it. Data security This resource also gives you ways to secure the data you want to store: Server protection -- If a file is server protected, only the server that has created it is able to read/modify it Encryption -- If a file is encrypted humans won't be able to read/modify it Resource Protection -- If a file is resource protected only a resource with the same name is able to read/modify it Combining these parameters will give you different levels of security for your file. For simplification you can instead of passing booleans just pass the security level you want to have (see the functions syntax please) 0 - No protection (any server, any resource or humans could read/modify) 1 - Very low protection (creator resource on any server or humans could read/modify) 2 - Very low protection (any resource on any server could read/modify, humans cant) 3 - Low protection (only creator resource on any server could read/modify, humans cant) 4 - Medium protection (any resource on the creator server or humans could read/modify) - Default setting if no 'security parameters' are given 5 - Medium protection (only creator resource on the creator server or humans could read/modify) 6 - High protection (any resource on the creator server could read/modify, humans cant) 7 - Very high protection (only creator resource on creator server could read/modify, humans cant) Other uses You can ofc use this script for example to save protected login data, but you can also use it in these ways for example: Cross-Resource communication: You could save a file called "settings" in resourceA and then load it in resourceB. Like this you have an easy way to make your server resources talk with each other without the need of events, exported functions and passing arguments. (if the file is not resourceProtected) Cross-Server communication: One step further could be that for example mapping script settings could be synchronized between different mapping servers (if the file is not serverProtected) Download The download for this resource can be found on the MTA Community page. Note: This resource does not require admin/any acl rank. I hope you like it and it will save you some work Sincerely, Ceeser
  4. As far as I know you get this error message in case the called function / resource has errors or as IIYAMA said the resource with the exported function is not started. So in case the required resource is started, check for errors in the debugscript that got outputted before your 'failed to call' error.
  5. Well it seems like you are only creating one bike variable. If you handle this serverside and want multiple players to have a bike, instead save one bike to each player.
  6. Hello scripters and the ones who want to become a scripter, since a few days I've been frequently visiting this site and I often see problems that shouldnt even exist or some that can easily be fixed by knowing what you do. So thats why I wanted to make this topic to give some general instructions about how to script And by 'how to script' I don't mean that I'll teach you scripting, instead I would like to give you some tips and guidelines which you can follow to improve scripting, debugging, remembering your script. 1. Variables Okay, lets start with some instructions to Lua: Lua is a very beginners-friendly 'programming language'. In Lua itself there are only a few syntaxes you need to remember, it doesnt cry if you use or dont use brackets at some points etc. The variables are type-undefined which is nice for an easy use, but also a point where you can lose track of what you are doing. For example: local myVariable = 1234 -- I gave this variable the value 1234 now -- some stuff in the script between myVariable = "asdf" -- Now I overwrote 'myVariable' with a string Lua is fine with that. You can do it. BUT it's very bad practice. By doing this you can easily break your script if you lose track of your script somewhere and actually need the number instead of a string. That's the point for my first tip: 1.1: Hungarian Notation Hungarian Notation actually comes from other programming languages, but it's a nice way to declear your variables in Lua as well. Using Hungarian Notation basically means: Add the variable type as a prefix to your variables name. This will immediatly help you knowing what type your variable will / should contain. (And let you know that you made a mistake somewhere if there is a wrong type) I personally use these prefixes for variables (Lua, MTA specific): i = integer (any number value - ignoring float, double, unsigned etc since Lua doesnt care if your number is an integer (round value), float (comma value) or positive/negative str = string (string means a combination of characters, a-z, A-Z, 0-9 - yes, numbers can also be displayed as characters in a string, and all sorts of special characters) tbl = table (a list / array of variables) u = userdata (players, vehicles, objects, timers, ... all MTA elements are a kind of userdata) f = function (yes, you can also store a function in a variable for faster/easier to handle/more performant use. Code examples: local iPositionLeft = 500; -- i = The name describes that this variable is meant for numbers only and I will never put another type in it. local strMessage = "Hello World"; -- This is a string (str) local tblPositions = {x = 200, y = 333, z = 1234}; -- This is a table/array Okay, now that we have the correct prefixes it's time for part 2: 1.2: Proper names for variables Give all variables a proper name which you remember and from which you know what its meaning/what its purpose. I know, programmers are lazy - but writing a few more characters will help you later on. Example: -- The following variables are no joke. They actually exist in a script of a server-lobby. local x,y = guiGetScreenSize() local l_sizeX,l_sizeY = x/9,x/4/4.5 local l_posX,l_posY = x/2-l_sizeX/2,y/70 local l_alpha = 0 local r_scrollX = 0 local r_px,r_py,r_size = x/2-x/10/2,y/2,x/10 local a_size = x/40 local a_posX,a_posY = x/2-a_size/2,y/2-a_size local a_posY_d = 0 -- When you define these variables like this you may know what they mean.. but take a look into the script a few days later or even -- weeks/months later.. have fun searching for every single variable. And if another scripter sees this script - rip. -- Instead of doing the stuff as above, better do it like this: SX, SY = guiGetScreenSize(); -- define the screen sizes properly as global instead of seperate for every client script. local iLoginSizeX = SX / 2; local iLoginSizeY = SY / 2; local iLoginPosX = SX / 2 - iLoginSizeX / 2; local iLoginPosY = SY / 2 - iLoginSizeY / 2; ... -- Like this you immediatly know what each variable means.. but it takes alot of space to declear each variable. Please read below. Also, as you see in the example above: I really do recommend to seperate words by an uppercase character.. what is more readable: local iloginsizex = SX / 2; local iLoginSizeX = SX / 2; Now, since our variables are well defined and readable, lets move to the next step: 1.3: Constants and variables that belong together Tables are a nice way to sort and organize your variables - especially when you have to deal with UI rendering. Rendering an UI can be a pain in the ass or fun to make, depending on how you do it imo. I personally always use a 'constants_c.Lua' file (_c describes that its defined as client file in meta and used on client side only). Inside that file I create all variables that will be used often inside a table of the name it belongs to. This will help you organize your script even more and saves alot of performance, because you dont need to calculate every number onClientRender anymore. It can also help you remembering positions etc - so faster scripting for UI's. Also, make a difference between "normal" variables and constants. Constants don't really exist in Lua, so you have to make your own rules. Constant mean that they will never be overwritten by a script (exception: If you can drag/move a panel or whatever they can be recalculated). Give a constant variable an full-uppercase name so that you immediatly see that it is a constant. (mainly for positioning variables) Additionaly, store them in a table with the name it belongs to. (POS as a general positions table, sub-names as element specified names) I personally only name the variable name itself with a lowercase character and without hungarian notation in a positions table. Example: -- So instead of declearing these variables local SX, SY = guiGetScreenSize(); local iLoginPosX = SX / 2; .... -- Do this: Create a constants_c.Lua file and define all variables there as global. SX, SY = guiGetScreenSize(); -- Define the screen size X and Y once for the whole resource POS = {}; -- Global positions table POS.LOGIN = {}; -- Login specific positions table POS.LOGIN.sizeX = SX / 2; -- sizeX of the login POS.LOGIN.sizeY = SY / 2; POS.LOGIN.posX = SX / 2 - POS.LOGIN.sizeX / 2; POS.LOGIN.posY = SY / 2 - POS.LOGIN.sizeY / 2; -- If we now render a rectangle 'dxDrawRectangle(POS.LOGIN.posX, POS.LOGIN.posY, POS.LOGIN.sizeX, POS.LOGIN.sizeY, white)' -- The 'login window rectangle' will be perfectly centered -- For other UI 'elements' continue like this: POS.SCOREBOARD = {}; ... -- Yes I know, usually you dont have a login panel and scoreboard in the same resource.. this is just an example. 1.4: Globals and performance Basically every variable you didn't define as 'local' is a global variable, but global variables are accessable from any script of the resource (ofc split to client and server side). This will cost some performance - so try to define everything as local if you can, you can even define functions as a 'local function XY()' Even (global) math functions like math.sin can be defined as 'local sin = math.sin' to save some performance if you use it often (onClientRender + for loop as example) If you want to make a (non-constant) variable globally accessable (so for multiple scripts inside the resource) always mark it as a global by putting g_ infront of the variables name. This will help you notice its a global, non-constant variable and prevent unwanted overwriting / name-duplications. 2. Debugging Debugging is a very important part of programming, especially if you are new to scripting / the type of script you are doing. (PS: Dont be afraid of making bugs.. programming is 50% creating bugs and 50% fixing bugs until you get what you want^^) MTA offers several ways of debugging: outputChatBox - The mose obvious one, but it will/can spam the chat, errors in onClientRender using this debug method can also cause lag and it gives only the information you enter - useless for most debugs. - Only use this for test-wise debugging, alone. outputDebugString - This is the one you should take for debugging and information outputs, you can also specify errorType and color. iprint - A bit lazy, huh? Joke. This one has its 'i' for a reason: Its itelligent. It's displaying various datatypes without requiring tostring - it can even display table structures More detailed information on screen? Use dxDrawText and display the information you need where you want it to be. 3. Help For any problem you have there is a solution - thats for sure. But if you need help, the best practice is not to make a big shout-out for help on any mta-scripting-help-forum, instead: Please try to fix the problem yourself - make several tests / experiment around, because by finding out what you have done wrong you will learn the most. If you immediatly ask for help and get a finished solution you basically learned nothing about it - always remember that: Testing will help yourself improve. If you cant find a solution: MTA Wiki is your friend. Its well documented and give you any information you need about any implemented function. Maybe search for the function you have problems with or utility (aka 'useful') functions that users have created. In many cases you can find a solution by searching in the wiki. In the case you really cant find any solution there are some free sites to ask like this mta-sa scripting forum or the ffs-gaming scripting forum. I bet you will find somebody who can help you with any problem there if you cant find any solution. 4. Script organizing Organizing each script, documentation and comments can help you alot. When writing code, simply add a comment ('-- text') behind some importent lines while the comment should explain what it does / for what reason as short but understandable as possible. Seperate your code in several sections so that its easier to find functions that are somehow connected (if you have multiple render functions, put them all in a '-- Render' section for example) Also organize your script by adding a (lets call it:) 'namespace' to each script - so each script get its own table (defines as local or global as you need) - THIS IS NOT OOP! Example: -- ************************************************************************************************************************** -- -- VARIABLES, EVENTS AND INFO -- local Login = {}; -- Define the scripts "namespace", this is now local - so for this script only, not for the resource. Login.show = true; Login.accEdit = guiCreateEdit(0, 0, 0, 0, ""); Login.passEdit = guiCreateEdit(0, 0, 0, 0, ""); Login.selectedEdit = Login.accEdit; -- The selected edit (focused) to enter characters in -- ************************************************************************************************************************** -- -- RENDERING -- function Login.render() -- Yes, this function is basically a variable of "Login". if (Login.show) then -- Render login window end end -- ************************************************************************************************************************** -- -- CLICKING -- function Login.click(strButton, strState) if (strState == "down") then -- Handle clicking of login window end end -- ************************************************************************************************************************** -- -- START AND STOP -- function Login.start() addEventHandler("onClientClick", root, Login.click); addEventHandler("onClientRender", root, Login.render); end addEventHandler("onClientResourceStart", resourceRoot, Login.start); function Login.stop() removeEventHandler("onClientClick", root, Login.click); removeEventHandler("onClientRender", root, Login.render); end 5. Stick to one language Yes i know, this can sometimes be hard, but its nevertheless way better than a mix of different languages. English is ofc the language you should chose if you can, because its the most spoken/known language in the world. This can not only improve your english skills, it will also help others alot if they see your script for help/revision/enhancement. Thats it for now, this topic might be continued. If you have questions, simply write a comment, maybe I'll add the answer to this topic.
  7. local relX = valueX / screenW -- this will return a 0.X value, so the relative you need But in general I really recommend to use dxDraw values in a different way: SX, SY = guiGetScreenSize(); -- Define the screen variables global for all scripts inside the resource (NO local!) -- Then draw by dividing that dxDrawLine(SX / 2, SY / 4, SX / 2, SY / 2, tocolor(255, 165, 0, 255)); -- Draws a vertical line from SY / 4 to SY / 2 (so from 1/4 of you screens height to your screen center)
  8. i guess you are using this resource: https://wiki.multitheftauto.com/wiki/Resource:Bone_attach If so, this resource also brings an build in function for that: bool isElementAttachedToBone (element theElement)
  9. Yes, you get that error, because you called the function parameter "vehicle" now instead of "AparecerBike"
  10. MarkerBike = createMarker(1086.3326416016,-1802.1416015625,12.60143661499, "cylinder", 1.5, 255,255,255,50) BlipLS = createBlipAttachedTo(MarkerBike, 33) setBlipVisibleDistance(BlipLS, 800) --local Veiculos = {510} -- IDs dos Veículos. Rumpo = {} AparecerBike = Rumpo[source] -- EDIT tblBikes = {}; -- /EDIT function spawn (source) if isElementWithinMarker(source, MarkerBike) then if getPlayerMoney(source) >= 500 then takePlayerMoney (source, 500) if AparecerBike and isElement(AparecerBike) then destroyElement(AparecerBike) end AparecerBike = createVehicle (510, 1091.2088623047,-1796.9704589844,13.606305122375) setElementData(AparecerBike, "kart.race", true) setElementData(source, "owner", AparecerBike) setElementData(AparecerBike, "conta.tempo", false) setElementRotation(AparecerBike,0,0,0) fadeCamera ( source, false, 0, 0, 0, 0 ) -- EDIT tblBikes[AparecerBike] = {}; tblBikes[AparecerBike].fadeTimer = setTimer ( fadeCamera, 500, 1, source , true, 0.5 ) tblBikes[AparecerBike].targetTimer = setTimer ( setCameraTarget, 500, 1, source ) -- /EDIT outputChatBox ("#FF0000✘ #ffffffINFO #FF0000✘➺ #FF0000Bicicleta Alugada com sucesso, faça bom uso!", source, 255, 255, 255, true) warpPedIntoVehicle (source, AparecerBike) else outputChatBox("#FF0000✘ #ffffffINFO #FF0000✘➺ #FF0000Você não tem dinheiro suficiente para alugar uma bike!", source, 255,255,255,true) end end end addCommandHandler("alugar", spawn) function enterVehicle ( player, seat, jacked ) if getElementData(source, "kart.race") == true and seat == 0 then local owner = getElementData(source, "owner") else cancelEvent() outputChatBox ( "Você não é dono desta bicicleta, alugue sua bike para poder usá-la.", player ) end end addEventHandler ( "onVehicleStartEnter", getRootElement(), enterVehicle ) function destroyVehicle(vehicle) local check=false for i,player in ipairs(getElementsByType("player")) do if getPedOccupiedVehicle(player)==vehicle then check=true end end if check==false then -- EDIT if (tblBikes[AparecerBike]) then for _, timer in pairs(tblBikes[AparecerBike]) do if (isTimer(timer) then killTimer(timer) timer = nil end end end -- /EDIT destroyElement(AparecerBike) end end local minutos = 1 function exitVehicle(AparecerBike, seat) if getElementData(AparecerBike, "kart.race") == true and seat == 0 then if isTimer(Rumpo[AparecerBike]) then killTimer(Rumpo[AparecerBike]) -- killTimer does not work. end Rumpo[AparecerBike] = setTimer(destroyVehicle,5000*minutos,0,AparecerBike) -- This timer does not stop... end end addEventHandler("onPlayerVehicleExit",getRootElement(),exitVehicle) function onPlayerVehicleEnter (AparecerBike, seat) if getElementData(AparecerBike, "kart.race") == true and seat == 0 then if isTimer(Rumpo[AparecerBike]) then killTimer(Rumpo[AparecerBike]) end end end addEventHandler("onPlayerVehicleEnter", getRootElement(), onPlayerVehicleEnter) function onResourceStop (AparecerBike) if isTimer(Rumpo[AparecerBike]) then killTimer(Rumpo[AparecerBike]) end end addEventHandler("onResourceStop", getResourceRootElement( getThisResource() ), onResourceStop) function DestroyVeiculo () if getElementData(source, "kart.race") then setElementData(source, "kart.race", false) destroyElement (AparecerBike) killTimer(Rumpo[AparecerBike]) end end addEventHandler ("onPlayerLogout", root, DestroyVeiculo) addEventHandler ("onPlayerQuit", root, DestroyVeiculo) addEventHandler ("onPlayerWasted", root, DestroyVeiculo) addEventHandler ("onPlayerBan", root, DestroyVeiculo) addEventHandler ("onResourceStop", root, DestroyVeiculo) Dunno what this "Rumpo" stuff is, so i just made an example in the destroyVehicle function, hope you get what im on about, marked all changes with --EDIT and --/EDIT
  11. local iStartTick = 0 -- Needs to get set using getTickCount() when you want to start your animation local iAnimDuration = 2000 -- The animation takes 2s to perform local x1 = 100 -- Left START position of your rectangle local y1 = 100 -- Top START position of your rectangle local x2 = 500 -- Left END position local y2 = 500 -- Top END position function render() local iProgress = (getTickCount() - iStartTick) / iAnimDuration -- Get the difference between now and startTick and divide by wanted duration to get the progress of your animation local x, y = interpolateBetween(x1, y1, 0, x2, y2, 0, iProgress, "Linear") dxDrawRectangle(x, y, 100, 100, tocolor(255, 255, 255, 255)) if (iProgress >= 1) then -- If the animation is done stop the animation + rendering iStartTick = 0; removeEventHandler("onClientRender", root, render) end end function startAnimation() -- Call this function when you want to start your animation iStartTick = getTickCount() addEventHandler("onClientRender", root, render) end This will start rendering and animation always when you call startAnimation() Hope with this you can do everything you want.
  12. Hey, a timer is also a kind of userdata, so you need to pass the timer 'link' somewhere. Maybe you can set the timers as elementDatas on the vehicle, otherwise store the vehicle + timers belonging to it in a table
  13. @thund3rbird23 You cant do it like this, because your script is serverside. Add the onClientRender event clientside in the function that get triggered by your event.
  14. I would recommend to create a team. onClientPlayerDamage gives you the attacker. Check if the player that want to deal damage is in the same team and if so, cancel the event.
  15. Either im just dumb or others dont get this as well.. What do you mean by "REMOVE the trigger"? remove the eventHandler? remove the function? remove the triggerEvent? its still unclear what you exactly mean by remove trigger