Jump to content

Lord Henry

Other Languages Moderators
  • Posts

    3,955
  • Joined

  • Last visited

  • Days Won

    178

Everything posted by Lord Henry

  1. Tópico movido para a seção de Programação Lua. Na próxima vez, poste na área correta.
  2. ElementDatas só serão nil se você setar esse valor nele. ElementDatas que não existem, não vão aparecer ali no getAllElementData. Se você quer que tal elementData exista mas não esteja sendo usada, normalmente definimos valor false nela. Se for o caso de setar false na data, você faria a condição ali assim: if objeto then -- É o mesmo que if objeto ~= false then
  3. CURIOSIDADES Em questão de performance, a diferença entre eles é irrelevante. Mas se considerarmos casos extremos de tabelas gigantes com milhares de itens, a execução do pairs é um pouco mais leve do que ipairs, visto que ele não precisa obedecer ordem nenhuma em sua execução, enquanto que o ipairs precisa sempre verificar a cada execução se o próximo índice existe na tabela inteira. Por esse motivo, se você for obcecado por otimização, prefira usar o pairs. Para saber quantos itens uma tabela possui, geralmente usamos #NomeDaTabela. Mas vale ressaltar que o caractere # na verdade retorna o maior índice conhecido (veremos casos abaixo em que pode existir um índice maior, mas ele não é conhecido). Sendo assim, ele não funciona em tabelas cujos índices não sejam inteiros sequenciais e também retornará a quantidade errada de itens em tabelas que tenham algum índice da sequência faltando. Para contar itens numa tabela de índices aleatórios, usamos uma variável de contador, que vai aumentando em +1 a cada execução do loop e no final nos mostra quantas verificações foram feitas, indicando quantos itens tem na tabela. Vejamos alguns exemplos: local tabela1 = { [4] = "a", [2] = "b", [5] = "c", [1] = "d", [3] = "e" } print("Tabela1: "..#tabela1) -- Retornará 5. Pois é o maior índice conhecido. local tabela2 = { [1] = "a", [2] = "b", [3] = "c", [4] = "d", [6] = "e", } print("Tabela2: "..#tabela2) -- Retornará 6. Mesmo tendo apenas 5 itens, o índice 6 é o maior. local tabela3 = { ["um"] = "a", [22] = "b", ["3"] = "c", [1] = "d", [0] = "e" } print("Tabela3: "..#tabela3) -- Retornará 1. Ele começa a verificar a partir do índice 1, então o índice 0 seria ignorado de qualquer forma. -- Em tabelas que possuem somente índices inteiros, ele iria encontrar o 22. Mas se tiver outros tipos de índices, ele não sabe qual a sequência correta e não verifica os demais. local contador = 0 for _,v in pairs(tabela3) do -- Maneira correta de contar itens numa tabela onde o ipairs não funciona. contador = contador+1 end print("Tabela3 de novo: "..contador) -- Retornará 5. Independente dos índices.
  4. Neste tutorial irei explicar qual a diferença entre um loop usando pairs e um loop usando ipairs. Mas antes de prosseguir, é necessário entender o que é uma tabela indexada e uma tabela não indexada. Tabela indexada é aquela cujos itens tem seu índice declarado. Os índices podem ser números, textos ou elementos. Tabela não indexada é aquela cujos itens não tem seu índice declarado. Porém a linguagem Lua automaticamente indexará essas tabelas com inteiros sequenciais. local tabela = {"1", 2, "três", 0.4, false, 0} -- Tabela não indexada. -- O MTA vai considerar a tabela acima dessa forma: local tabela = { -- Tabela indexada com inteiros sequenciais. [1] = "1", [2] = 2, [3] = "três", [4] = 0.4, [5] = false, [6] = 0 } -- Escrevi a tabela na vertical para facilitar a leitura, não faz diferença escrever tudo na mesma linha. É importante saber disso pois ipairs leva em consideração os índices dos itens de uma tabela, como veremos a seguir. CONCEITO Tanto o pairs quanto o ipairs são utilizados para fazer loops que percorrem uma tabela usando o laço de repetição for. Mas existem situações em que um ipairs não funciona e também há situações em que o pairs não atende ao objetivo que o scripter precisa. Basicamente, o pairs percorre os itens de uma tabela mas não garante a mesma ordem em que eles foram declarados e nem a sequência de seus índices. Sem qualquer ordem específica, ele não exige que a tabela seja indexada por inteiros sequenciais, já que ele não leva em consideração a ordem dos índices da tabela. Enquanto o ipairs (significado: index-value pairs) percorre os itens de uma tabela sempre seguindo a sequência de seus índices. Verificando primeiro o item de índice 1, depois o item de índice 2 e assim por diante. Se um índice da sequência estiver faltando, ele não percorrerá o resto e vai parar de verificar. Também não importa a ordem em que os índices são declarados. Se você declara o item de índice 2 e depois o item de índice 1, mesmo assim ele vai ler o item de índice 1 primeiro e depois o item de índice 2. O ipairs também não é capaz de verificar itens cujo índice não seja um inteiro, pois ele não sabe a sequência que ele pertence, portanto itens de índice string não são verificados pelo ipairs. EXEMPLOS Usando o pairs: (note que o exemplo é server-side, mas tanto o pairs quanto o ipairs podem ser usados client-side também) Server-side addCommandHandler("eae", function(thePlayer, cmd) -- Vamos setar algumas elementDatas em si mesmo só para testes. setElementData(thePlayer, "vida", 100) setElementData(thePlayer, "colete", 90) -- (Datas fictícias, não alteram de verdade a vida nem colete do jogador). setElementData(thePlayer, "vivo", true) setElementData(thePlayer, "procurado", false) setElementData(thePlayer, "emprego", "Mecânico") local datas = getAllElementData(thePlayer) -- Obtém uma tabela com todas as elementDatas do jogador que executou o comando /eae -- A tabela retornada seria assim: (supondo que o jogador não tenha outras elementDatas setadas nele) --[[ local datas = { ["vida"] = 100, ["colete"] = 90, ["vivo"] = true, ["procurado"] = false, -- Este é o único jeito de saber se uma elementData false existe mesmo. ["emprego"] = "Mecânico" } --]] -- Para verificar cada item dessa tabela, o pairs precisa ser usado pois os índices são strings enquanto o ipairs só funciona com índices inteiros sequenciais. for name, value in pairs(datas) do print(name.." = "..tostring(value)) end -- Não há qualquer garantia de que os itens sejam verificados na mesma ordem em que foram declarados. Consideramos isso aleatório. end) Obs: O pairs também funciona em tabelas com índices inteiros sequenciais como o ipairs, porém percorre de maneira aleatória enquanto o ipairs segue a sequência dos índices. 1) Se trocar o pairs por um ipairs, nenhum item será verificado. Pois não foi encontrado o índice 1. Obs2: Mesmo se você definir uma elementData com nome "1", o índice continuará sendo uma string, não sendo lido pelo ipairs. Vimos acima um exemplo que precisa usar pairs pois o ipairs não funcionaria. Agora veremos um exemplo onde o ipairs seria mais adequado. Client-side local palavras = { [1] = "Neste ", [2] = "caso ", [3] = "a ", [4] = "ordem ", [6] = "importa " -- Esqueci do índice 5 de propósito. } local mensagem = "" for i, v in ipairs(palavras) do mensagem = mensagem..v end print(mensagem) Faça os seguintes testes: 1) Execute o código acima do jeito que está, veremos que a mensagem final aparece incompleta. Pois ele não encontrou o índice 5 e parou de verificar o resto dos itens. Retornando a mensagem "Neste caso a ordem " 2) Se trocarmos o ipairs por um pairs, veremos que a mensagem ficará bagunçada, pois os itens foram verificados de maneira aleatória. Porém desta vez todas as palavras serão verificadas, pois o índice não é levado em consideração pelo pairs, somente pelo ipairs. 3) Troque o pairs pelo ipairs de volta e substitua o índice 6 por 5. A mensagem aparecerá completa e com as palavras em ordem. Já que não haverá nenhum índice faltando na sequência. 4) Troque a ordem dos itens da tabela dessa forma: (preste atenção na vírgula, ela é obrigatória em todos os itens, exceto no último) local palavras = { [4] = "ordem ", [2] = "caso ", [5] = "importa ", [1] = "Neste ", [3] = "a " } Veremos que o ipairs continuará verificando cada item na ordem correta. Já que o que importa para ele são os índices e não a ordem em que os itens foram declarados na tabela.
  5. Não funcionaria, pois você está usando ipairs que só serve para tabelas indexadas com inteiros sequenciais. Perceba que no exemplo da wiki do getAllElementData ele usa pairs.
  6. Só server-side pra conseguir obter as datas sem saber os nomes.
  7. local texture = dxCreateTexture("info.png", "argb", true, "clamp") -- MTA San Andreas 1.5\MTA\cgui\images\info.png addEventHandler("onClientRender", root, function() local x, y, z = getElementPosition(localPlayer) local cx, cy, cz = getCameraMatrix() local sx, sy = getScreenFromWorldPosition (x, y, z+1, 0, false) -- Exemplo 1 dxDrawMaterialLine3D (x, y, z+1.08, x, y, z+0.9, false, texture, 0.17, 0xFFFFFFFF, false, cx, cy, cz) -- Tamanho fixo no mundo (fica menor se afastar a câmera e maior se aproximar a câmera) -- Exemplo 2 if sx then dxDrawImage (sx-21, sy, 42, 42, texture) -- Tamanho fixo na tela (mantém o tamanho igual mesmo se afastar a câmera) end end) Lembrando que vc pode mudar a câmera usando a tecla V.
  8. Não, vc teria que ficar usando o getElementPosition para obter a posição do player e depois ficar dando dxDrawImage3D com essa posição XYZ do player. Obs: Optei por usar o dxDrawMaterialLine3D pois a função útil dxDrawImage3D não tem os parâmetros de faceToward para apontar para a câmera.
  9. Não funciona pois os blips foram criados nos clientes dos policiais e não no servidor. OnPlayerWasted é server-side. Tente usar essa função client-side, mas usando o evento onClientPlayerWasted.
  10. Normalmente no client espera-se que você já saiba quais elementDatas um elemento pode ter. Nesse caso você cria primeiro uma tabela com os nomes de todas as datas que o elemento possa ter e verifica com um loop quais datas o elemento possui, ou se não possui tal data específica. local datas = { "dataName1", "dataName2", "dataName3", } function checkData(elemento) for _, data in pairs(datas) do -- Para cada nome de data que está na tabela datas, faça: local value = getElementData(elemento, data) -- Obtém o valor dessa elementData no elemento, se não existir retorna false. if not value then -- Se o elemento NÃO TEM essa data, então: -- faz algo -- OBS: Se a data existir mas estiver definida com valor false, vai ser o mesmo que não existir. end end end
  11. DX não é um elemento, vc não pode anexar ele em alguma coisa. Pegue a posição da coisa que o DX deve seguir dentro do onClientRender e fique atualizando a posição 3D do DX a cada frame. A posição da câmera tbm precisa estar dentro do onClientRender para ser atualizada a cada frame.
  12. Você pode usar essa função útil: DxDrawImage3D E então nos parâmetros faceTowardX, faceTowardY, faceTowardZ você coloca a posição da câmera para fazer a imagem sempre ficar apontada para a câmera do jogador. Você pode obter a posição da câmera com getCameraMatrix.
  13. Seu triggerClientEvent está incorreto, a indentação também tem que corrigir. Em vez de chamar vários triggers (1 para cada policial) é mais fácil vc primeiro obter todos os players policiais numa tabela e depois dar um único trigger para essa tabela de policiais. Sempre prefira fazer um trigger grande do que vários pequenos. Exemplo maroto: -- SERVER-SIDE function getCops() local cops = {} -- Tabela de policiais. for _, players in pairs(getElementsByType("player")) do if isObjectInACLGroup("user."..getAccountName(getPlayerAccount(players)), aclGetGroup("Policie")) then -- Tem certeza que a ACL Group tem esse nome? table.insert(cops, players) -- Adiciona esse jogador na lista "cops" se ele estiver na ACL Group "Policie". end end return cops end addCommandHandler("eae", function(thePlayer, cmd) local policiais = getCops() -- Obtém uma lista de players policiais online. if #policiais > 0 then -- Se tem algum policial no server (tabela não está vazia), então: triggerClientEvent(policiais, "BlipPM", thePlayer) -- Ativa esse evento só pros policiais, usando thePlayer como source do evento. end end) -- CLIENT-SIDE function BlipPolicia() local blip = createBlipAttachedTo(source) -- Se o ícone for 0, não precisa declará-lo. setTimer(destroyElement, 5*1000, 1, blip) -- Destrói o blip após 5 segundos. end addEvent("BlipPM", true) addEventHandler("BlipPM", root, BlipPolicia)
  14. Mesmo copiando o código-fonte da função útil dxDrawTextOnElement, você fez questão de mudar a indentação dela para deixar errada, por qual motivo? (todas as variáveis locais tem +4 espaços) O texto não aparece pois está atravessando a porta. A função útil tem uma condição de que o texto só aparece se não tiver nada entre o texto e a câmera. Remova essa condição e o texto sempre aparecerá mesmo estando dentro da porta. Se quer usar código de cores no texto, você precisará fazer um upgrade na função útil para incluir o parâmetro colorCoded no dxDrawText. Tente algo assim: theObj = createObject (1491, 2487, -1666, 12.3) -- Cria uma porta dinâmica na Grove Street. bindKey("e", "down", function() setElementFrozen(theObj, not isElementFrozen(theObj)) -- Congela/descongela essa porta específica ao apertar a tecla E. end) function TextoPortas() for i, portas in ipairs(getElementsByType("object")) do if getElementModel(portas) == 1491 then if isElementFrozen(portas) then dxDrawTextOnElement(portas, "#FF8000[E] #FFFFFFPara Abrir", 1, 6, tocolor(255, 255, 255, 255), 3.1, "default-bold", "center", "center", false, false, false, true) else dxDrawTextOnElement(portas, "#FF8000[E] #FFFFFFPara Fechar", 1, 6, tocolor(255, 255, 255, 255), 3.1, "default-bold", "center", "center", false, false, false, true) end end end end addEventHandler("onClientRender", root, TextoPortas) function dxDrawTextOnElement(theElement, text, height, distance, color, size, font, alignX, alignY, clip, wordBreak, postGUI, colorCoded) local x, y, z = getElementPosition(theElement) local x2, y2, z2 = getCameraMatrix() local distance = distance or 20 local height = height or 1 -- if (isLineOfSightClear(x, y, z+2, x2, y2, z2)) then -- Oculta o texto se tiver algo entre ele e a câmera. local sx, sy = getScreenFromWorldPosition(x, y, z+height) if sx and sy then local distanceBetweenPoints = getDistanceBetweenPoints3D(x, y, z, x2, y2, z2) if distanceBetweenPoints < distance then dxDrawText(text, sx+2, sy+2, sx, sy, color or 0xFFFFFFFF, (size or 1)-(distanceBetweenPoints / distance), font or "arial", alignX or "center", alignY or "center", clip or false, wordBreak or false, postGUI or false, colorCoded or false) end end -- end end
  15. Olá. É melhor aprender a programar em Lua. Vai dar menos trabalho do que se fosse tentar integrar outras linguagens ao MTA.
  16. guiFocus move o elemento cegui pra frente como se você tivesse clicado nele. No caso de editbox e memos, ele também coloca o cursor de digitação nele. Assim você não precisa clicar no campo de input antes de digitar, pois o cursor de texto já estará lá. Um exemplo básico é este campo de texto aqui no fórum. Por padrão ele vem "fechado" quando você abre esta página. Então você precisa clicar nele para abrir e depois pode começar a digitar sua mensagem. O guiFocus faz isso no MTA, ele meio que "clica" no editBox para você poder digitar direto sem precisar clicar nele antes. Ele também pode ser usado em janelas cegui que estejam sobrepostas. Use guiFocus na janela que deseja mover para frente como se clicasse nela. O guiFocus também é útil para mover para frente os elementos que você não consegue clicar pois tem algo na frente atrapalhando. A função oposta ao guiFocus é o guiBlur. Normalmente só usamos isso em editFields e memos, para quando você quer parar de digitar neles, como se fosse clicar fora deles pro cursor de texto sair deles. Você também pode usar guiBringToFront para mover um elemento gui para frente. Mas no caso de editBox e memos, o cursor de texto não aparece neles com essa função, sendo necessário clicar neles para poder digitar. Seu oposto é o guiMoveToBack, a diferença dele pro guiBlur, é que no caso de editBox e memos, o cursor de texto continua neles mesmo eles estando atrás de outros elementos gui. Resumindo: guiFocus e guiBlur "clicam" e "desclicam" os elementos gui, além de movê-los para frente e para trás. Enquanto que guiBringToFront e guiMoveToBack apenas movem para frente ou para trás sem "clicar" nem "desclicar" neles.
  17. guiSetVisible apenas oculta o elemento gui como se tivesse colocado o alpha dele em 0. Mas não destrói ele. Se quer destruir, use destroyElement mesmo. A diferença entre o guiSetVisible e o guiSetAlpha é que o guiSetAlpha ainda permite que você interaja com o elemento invisível, enquanto que o guiSetVisible além de ocultar o elemento gui, também desabilita ele para que não seja possível interagir com ele.
  18. Não vejo necessidade de definir true no postGUI dos DX. Basta dar dxDraw neles na ordem correta.
  19. Nesse caso teria q ser server-side. Não tenho como testar se destruiria para os outros clientes. Pela lógica, iria destruir só pra você. Tem que testar com mais alguém conectado para ver se dá pra fazer client-side.
  20. Pq vc não binda o "Enter" ou então cria um botão com uma lupa para pesquisar? Assim ele não precisa ficar atualizando a cada caractere que você digita.
  21. Testei seu script e funcionou aqui. Porém precisa usar showCursor(true) para mostrar o cursor. Não funciona se o cursor estiver visível por abrir o chatBox ou o Client Console (F8). Ele não considera o cursor visível ao apertar T ou F8. Você também pode testar abrindo o painel admin, já que ele tem um showCursor(true) ao abrir.
  22. Mostre a parte do código que você está tentando fazer.
  23. @Silveiraa23 não fazemos drop de resources. Mas se você quiser criar seu próprio resource, podemos te ajudar.
×
×
  • Create New...