Jump to content

DiSaMe

Helpers
  • Posts

    1,447
  • Joined

  • Last visited

  • Days Won

    32

Everything posted by DiSaMe

  1. You can't control "WorldModel" as element, but you can remove it and create an object in its place using createObject. Such solution looks clean enough to me, although a little more than that may be needed if there are low detail objects involved.
  2. First of all, your id table is needlessly nested. {481}, {462} and {509} are tables on their own, so unless you're going to add some other data in addition to IDs, it's better to replace them with plain numbers: local id = { 481, 462, 509, } Now, to get to the point, the table id has 3 fields, which makes #id equal to 3, therefore your math.random call generates a number 2 or 3, and uses it as vehicle model ID. What you need to do is to generate a random number to choose the table index and then retrieve the value under that index from the table: createVehicle(id[math.random(1, #id)], v[1], v[2], v[3]) Same but more verbose: local idCount = #id local index = math.random(1, idCount) local modelId = id[index] createVehicle(modelId, v[1], v[2], v[3])
  3. Then you probably need onClientGUIClick instead of onClientClick. onClientClick is an event for general purpose clicking detection. onClientGUIClick is an event for detection of clicking of GUI elements. You can bind different handler functions to different buttons.
  4. To bind a function to a command: addCommandHandler To retrieve the weapons: getPedWeapon To remove the weapons: takeAllWeapons To restore the weapons: giveWeapon
  5. Most stuff in 3D graphics is made of things that are straight/flat. If you want a curved line, you can make one by putting multiple straight lines together.
  6. First of all, use code blocks (preferably with Lua highlighting) instead of spoiler blocks. It's hard to read it the way it is. Second, did you try to understand why those messages are there? Did you try doing things like checking the variable values, like this: outputDebugString("veh = "..tostring(veh)) Documentation of both getVehicleOccupant and getPedOccupiedVehicle tells what return values are possible. If you check the variable values when the warnings appear and read the documentation on when those values are returned, it should be easy to understand why it happens. Perhaps your topics were locked because of lack of research on your part (or at least it looked like that), so I'm trying to lead you on the right track.
  7. There is another solution that doesn't require render targets, and it's closer to dxDrawImageSection in the way it works: dxDrawMaterialPrimitive. dxDrawImageSection only operates on rectangular sections. dxDrawMaterialPrimitive allows you to draw triangles, specifying the texture coordinates for each vertex, and since triangles can be put together to form other shapes, you can do what dxDrawImageSection does but not limited to rectangular sections. There isn't an example in the wiki page on how to use it, but dxDrawPrimitive has one, and dxDrawMaterialPrimitive works in a similar way, only it takes image as second argument, and each vertex has 5 parameters instead of 3 (2 extra parameters are for image coordinates). I came up with some function, for drawing a radially cut out section of an image. I only tested it as much as I could test it in standalone Lua interpreter so I don't know if it works in MTA, but if it does, someone may put it on useful functions page in wiki ? It uses trianglefan primitive type, puts the first vertex in the center and other vertices around it. local white = tocolor(255, 255, 255, 255) local degToRad = math.pi/180 local function makeVertexAtAngle(centerX, centerY, halfWidth, halfHeight, angle, color) local angleRad = angle*degToRad local xAdd, yAdd = math.sin(angleRad), -math.cos(angleRad) local maxAdd = math.max(math.abs(xAdd), math.abs(yAdd)) xAdd, yAdd = xAdd/maxAdd, yAdd/maxAdd return { centerX+xAdd*halfWidth, centerY+yAdd*halfHeight, color, 0.5+xAdd*0.5, 0.5+yAdd*0.5 } end function dxDrawRadialImageSection(posX, posY, width, height, image, startAngle, stopAngle, color, postGUI) if color == nil then color = white end if postGUI == nil then postGUI = false end local halfWidth, halfHeight = width*0.5, height*0.5 local centerX, centerY = posX+halfWidth, posY+halfHeight local roundedStartAngle = math.floor((startAngle-45)/90+1)*90+45 local roundedStopAngle = math.ceil((stopAngle-45)/90-1)*90+45 local vertices = {{centerX, centerY, color, 0.5, 0.5}} table.insert(vertices, makeVertexAtAngle(centerX, centerY, halfWidth, halfHeight, startAngle, color)) for angle = roundedStartAngle, roundedStopAngle, 90 do table.insert(vertices, makeVertexAtAngle(centerX, centerY, halfWidth, halfHeight, angle, color)) end table.insert(vertices, makeVertexAtAngle(centerX, centerY, halfWidth, halfHeight, stopAngle, color)) dxDrawMaterialPrimitive("trianglefan", image, postGUI, unpack(vertices)) end This example should display a looping 5-second animation of image going from 0 to 360 (if I didn't screw anything up): function drawAnimatedRadialSection() local angle = (getTickCount() % 5000) / 5000 * 360 dxDrawRadialImageSection(100, 100, 200, 200, "your_image.png", 0, angle) end addEventHandler("onClientRender", root, drawAnimatedRadialSection)
  8. It clearly says that image/blip/6.png failed to load. Does that file exist? Is it added in meta.xml?
  9. There are problems with this code. First, the source of "onResourceStart" event is the root element of that resource (same as resourceRoot, I think), but bindKey requires player as first argument. Second, the handler functions for bindKey don't have sources. Instead, the player is passed as first argument. I don't know if bindKey has call propagation (call propagation means a function call made on an element will apply to its children elements). If it does, we can pass root to the player argument of bindKey and the key binding will be added for all players: function killMe(player) killPed(player) end function onStartBindKill() bindKey(root, "n", "down", killMe) end addEventHandler("onResourceStart", resourceRoot, onStartBindKill) If bindKey doesn't have call propagation, the above code is still wrong and we have to call bindKey separately for each player. That means calling bindKey every time a player joins. But a resource might be started after some players have already joined, so we also have to call bindKey for already present players when it starts: function killMe(player) killPed(player) end function onJoinBindKill() bindKey(source, "n", "down", killMe) end addEventHandler("onPlayerJoin", root, onJoinBindKill) function onStartBindKill() local players = getElementsByType("player") for key, player in ipairs(players) do bindKey(player, "n", "down", killMe) end end addEventHandler("onResourceStart", resourceRoot, onStartBindKill)
  10. spawnPlayer works when the player is spawned and alive as far as I know, but it does more things than just teleporting, such as setting the skin and resetting the health to full, which is why it's not the right choice for teleporting.
  11. The problem is that collisions unload when objects are far enough from the camera. You can use setElementFrozen to freeze the player in place when you put the camera somewhere else, then unfreeze when you reset the camera to follow the player.
  12. The purpose of this forum section is to allow people to lead other people on the right track, which is exactly what I'm trying to do. The problem isn't that the number of arguments doesn't match, the problem is that in the end the operations get performed on values that are invalid for those operations. triggerServerEvent("serverAddVehicleUpgrade", getRootElement(), veh, tonumber(whl[1][1]) ) ? ? | | | | +-------------------------------+ | | | | | | | | +--------------------------------------+ | | | | | | | | +----------------------------------------------------+ | | | | | | | | +------------------------------------------------------+ | | | | V V V V function serverAddVehicleUpgrade(vehicle, upgrade, player, price) | | +----------------------------+ | | | | | +--------------------------+ | | | | V V | | if getPlayerMoney(player) > price then | | | | +--------------------------+ | | | | +--------------------------+ | | V V takePlayerMoney(player, price)
  13. I'm not familiar with HLSL syntax (never did any programming in HLSL), but based on https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-per-component-math#the-vector-type, it should look something like this: float x = VS.Position.x; float y = VS.Position.y; float z = VS.Position.z; If it's unpacking syntax that you want (assigning to multiple variables from a single vector at once), I don't think HLSL has it, but you could write a function with one in vector argument and three out scalar arguments for each component.
  14. You trigger the event like this: triggerServerEvent("serverAddVehicleUpgrade", getRootElement(), veh, tonumber(whl[1][1])) Arguments for handler function start at argument 3. Therefore, two arguments are passed, veh and tonumber(whl[1][1]). However, the handler function looks like this: function serverAddVehicleUpgrade(vehicle, upgrade, player, price) There are four arguments - more than were passed from the client. Only vehicle and upgrade get assigned. player and price default to nil.
  15. You could store the weapon elements in a table and then check in onClientPlayerDamage if attacker is in that table.
  16. You need to detect when the weapon hits a player using onClientPlayerDamage, check if the attacker (first parameter) is a weapon element that's not supposed to do damage and call cancelEvent.
  17. I was supposed to notice this thread a little sooner, but anyway. Started playing regularly and scripting in 2008, drifted away during 2013-2016, came back to this forum this year, not playing anymore, but visiting here regularly because of the great moments I had years ago.
  18. Did you try outputting the variable values and tracking down where the booleans get introduced? I assume you're using getScreenFromWorldPosition, assigning the return values to sx and sy and not checking those values. The thing is, if the point is off screen, that means there isn't a valid position on the screen for that point, and the function returns false (edgeTolerance argument can prevent this for some positions, but the function will still return false if the point is behind the camera). So false and nil get assigned to sx and sy respectively, and then you attempt to subtract from those values. That's where the error comes from. If you only draw one nametag in that event handler, it makes sense that it appears to work fine, because the error only occurs in cases where the nametag wouldn't be visible anyway.
  19. You need to get the screen resolution with guiGetScreenSize and use it to calculate the coordinates for that resolution. That page has examples for this particular purpose.
  20. @Dutchman101 already mentioned putting elements into a table, and I want to elaborate on that. These functions that return the lists of elements, they create a new table and fill it with elements every time they're called, which is inefficient to do repeatedly if we can reuse previously attained information. An example: local players = {} local function resourceStarted() -- when the script starts, we populate the table with players that are already playing for key, player in ipairs(getElementsByType("player")) do players[player] = true end end addEventHandler("onClientResourceStart", resourceRoot, resourceStarted) local function playerJoined() -- when a player joins, we add that player to the table players[source] = true end addEventHandler("onClientPlayerJoin", root, playerJoined) local function playerQuit() -- when a player quits, we remove that player from the table players[source] = nil end addEventHandler("onClientPlayerQuit", root, playerQuit) -- looping through all players: for player in pairs(players) do end That is, we only retrieve the elements with getElementsByType at the beginning, and keep track of subsequent changes by ourselves. If you only want to track the streamed in elements, you can add the needed arguments to getElementsByType like @IIYAMA showed and replace "onClientPlayerJoin" and "onClientPlayerQuit" with "onClientElementStreamIn" and "onClientElementStreamOut" respectively. But then again, you will also need to use getElementType to filter out elements of other types. Note that whereas getElementsByType returns a sequence (the key is a number, the value is an element), the table in my example is a set (the key is an element, the value is true). Looping is slightly different for that reason.
  21. DiSaMe

    Sporadic

    You need string.sub function, it returns a substring of the string. Using the same position for start and end, you get single characters. local value = "Text" local P1, P2, P3, P4 = string.sub(value, 1, 1), string.sub(value, 2, 2), string.sub(value, 3, 3), string.sub(value, 4, 4) Because the value is a string, you can call string functions on it as methods, using OOP syntax. This one is a little shorter and does the same thing as above: local value = "Text" local P1, P2, P3, P4 = value:sub(1, 1) value:sub(2, 2), value:sub(3, 3), value:sub(4, 4)
  22. I would never tell you that - to the contrary, bots were too underused in MTA last time I checked, and I don't know how much the situation has changed since then (it was long ago though). If you want to make bots that perform tasks, that's great. However, if you're not a scripter, it won't be that easy. MTA provides functions for low level control of bots, such as setPedControlState. The good thing about it is that you can make the bot do anything. The bad thing is that this "anything" has to be made from primitive actions. Making a bot drive from point A to B by setting acceleration, braking and steering controls takes a considerable amount of effort. The scripts that @IIYAMA posted links to, may help you. npc_hlc provides scripting functions for higher level controls and takes care of control states for you - so instead of calculating the angles and telling the bot "steer left/right and accelerate", you can tell it "drive to that point". npc_tseq is basically a GUI for npc_hlc. It allows you to create peds and assign tasks to them via GUI. However, even those scripts only have fairly primitive tasks. You can tell the bot to "drive straight to that point" or "drive along that line", but you can't just provide the destination position and have the bot drive there while following the roads. That is, no pathfinding. Meaning you have to put a bunch of "drive along line" tasks into one path. If you have a fixed set of source-destination pairs, you can retrieve the coordinates manually and build sequences out of them. But if you need the bot to travel between arbitrary points, then you have to do pathfinding, which is a problem if you have no scripting experience.
  23. That's a good point. It may look like a matter of taste, but there is a difference which may have big implications. If you call dbExec from within the command handler of "ck", right after kickPlayer, then the character only gets deleted when the player uses that command. If you call dbExec whenever the player gets kicked, the character gets deleted even if the player gets kicked by other means. The consequences may be very undesirable if there's some progress associated with a character. Suppose you have an AFK kicker script. The player stays idle for a few minutes, gets kicked - all progress they've made on that character is gone.
  24. Actually, you shouldn't have to manage the life of bots yourself. At least they shouldn't be invincible by default. I suspect where the problem might be. You create the bots at z position 0 or 2. z = 0 means sea level. You're creating them below the ground. And there is no water in that place, they just fall down. Which leads to this: When peds fall below z coordinate -100 or something similar, the game teleports them at some point on ped path. However, that's from the perspective of GTA SA. If you weren't the syncer when that happened, MTA server still sees the ped at the position where it was created. So you see the peds near the gym but they're invincible because the syncer controls the damage and the peds have no syncer. You may think you're the syncer because you see them close to you, but you're not. To become the syncer, you have to come closer to their actual position, where MTA server sees them. It may be confusing because the positions of unsynced peds aren't updated on clients to match the one that the server sees - unless the server calls setElementPosition, in which case the clients will see the ped teleporting to the specified position, but afterwards there's nothing that stops the ped from straying again. If anything, it's position of unsynced bots that you have to manage yourself, because the server doesn't have physics. For simplicity, you could make a timer on the server that, if the ped is unsynced (using getElementSyncer), gets the position of the ped and assigns that same position. That would keep teleporting the unsynced peds back to their actual positions.
  25. Thanks everyone, I'm happy to know my works are appreciated here. Yes, but this is one of the reasons why I regret leaving for so long. If I had left without having done anything important for people to remember me, it would have been easier. No one looking for me and wondering where the hell I disappeared. Now it's more like I created expectations for people and then vanished. I heard about it when my website went down, and I thought I should bring it back, maybe run a server myself, but I never did because "I'm not in the mood at this moment". Glad I didn't even have to in the end. Anyway, it seems that bone_attach is the most popular of my resources. Its main purpose wasn't even to manage the state (attaching/detaching), its main purpose was to provide rotation calculations because that's what I considered the hard part. I remember there was a time when I could calculate 2 angles from 2 positions but not 3 angles from 3 positions, meaning I could align the object to the bone but not rotate it along with the bone around the bone's axis. But... Yes, until recently. With getElementBoneRotation being introduced, that part is now obsolete. Regarding my resources in general, I made them because I wanted to benefit MTA, but I remember being somewhat annoyed by relative lack of action from the rest of the community. There were servers that I enjoyed playing in, some of them running simple but original gamemodes. But like anywhere else, for every good server there were lots of not-so-good ones. And then there were many people looking for some traffic script but hardly anyone trying to make one themselves. It felt so disappointing. Ped scripting capabilities were very underused, especially considering with them you can do far more than just peds randomly walking and driving around. I mean yes, it's expected that in any gaming community most people would be just players and not scripters. But for everything that's possible to do with MTA, that was a huge waste. Perhaps I was just overreacting because I was a little anxious, being unsure where my life was going while also worrying about MTA at the same time. But it all seems good enough now.
×
×
  • Create New...