.Dev

Members
  • Content Count

    13
  • Joined

  • Last visited

  • Days Won

    3

.Dev last won the day on March 7

.Dev had the most liked content!

Community Reputation

31 Good

About .Dev

  • Rank
    Square
  • Birthday 11/05/1997

Details

  • Gang
    New Dream's Roleplay
  • Location
    Brazil
  • Occupation
    Dev
  • Interests
    MTA Scripts

Recent Profile Visitors

210 profile views
  1. Lord Henry, agradeço ter respondido no tópico. Em relação as aspas simples ou duplas é questão de vicio mesmo, eu mesmo acabo usando geralmente as simples em Lua, é algo que não me confunde em outras linguagens quando necessito das aspas duplas, mas vou prestar mais atenção nisso em relação aos códigos para ajudar o pessoal. E agradeço pela coreção do ipairs e pairs vai ser util para o pessoal, se estiver tudo bem pra você, vou anexar ao post, ou deixo teu comentario, como achar melhor.
  2. Post Anterior: Eai pessoal tudo bom? Continuando o Curso básico, hoje vamos um pouco sobre tabelas: Tabelas Tabelas em Lua é um assunto bem interessante, porque elas podem ser classificadas como varias coisas diferentes, e pode não fazer muito sentido agora, mas é só continuar com o post que vão compreender. Para começar podemos classificar tabelas como: Arrays - Sequencias de valores numéricos; Dicionários - Conteúdo com Chaves e Valores associados; Objetos - Classes e Módulos, com atributos e métodos. Mas antes de mais nada, vamos entender como se declara uma tabela. Como explicado anteriormente, as variáveis em Lua são dinâmicas, portanto, basta declarar a mesma da forma correta que o próprio Lua se encarrega de compreender e alocar o espaço especifico. Para se declarar uma tabela, nos usamos o construtor de tabelas que consiste em um par de chaves "{ --bloco-- }", então para o nosso exemplo ficaria assim: local tabela = {}; Assim com o exemplo acima, nos criamos um espaço alocado com o nome de "tabela", e demos a ele um espaço dinâmico. Essa é uma das características das tabelas, como eu expliquei nos posts anteriores, as variáveis em Lua recebem geralmente 1 único valor, por exemplo: local nome = "dev"; Caso eu tente passar 2 ou mais valores ele vai retornar nil em ambos os caras por exemplo: local nome, idade = 'dev', 22; Porque o espaço alocado não é dinâmico, e sim o tipo da variável, no caso das tabelas isso não acontece, eu poderia simplesmente armazenar quantos valores eu quisesse. local num = {11, 22, 30}; e caso eu desse print receberia a resposta de todos eles normalmente. Mas para darmos um print nos teríamos que passar o index, e alguns de vocês podem estar se perguntando, "Oque diabos é um index?". Vamos definir o index como um ponto de partida para facilitar o entendimento. Se estivessemos falando da linguagem C por exemplo, o primeiro index ou seja o ponto de partida, seria 0, mas Lua se utiliza do ponto 1. Só para facilitar o entendimento, nos poderíamos escrever a tabela dessa forma: local num = {[1] = 11, [2] = 22, [3] = 30}; **Esse tipo de organização é feita automaticamente pelo Lua, portanto não é necessário escrever desse jeito.** Como podem ver a organização é definida da seguinte forma: tabela = {[index] = valor}; Então para visualizarmos o conteúdo dentro de uma tabela, teríamos que passar o index da mesma da seguinte forma: print(num[1]) res => [ 11 ]; print(num[2]) res => [ 22 ]; print(num[3]) res => [ 30 ]; ou poderíamos executar um for para facilitar a vida: for i=1, #num do print(num[i]) end que o resultado seria => [11 , 22, 30]; -- Lembrando que eu já expliquei como funciona o for. Só para explicar a vocês o "#" é o "Operador de Comprimento", ele verificar quantos index a tabela possui, e como vocês devem lembrar podemos ler o for como PARA valor, max/min incremento FAÇA; **Só para esclarecimento, o # só serve para index numéricos.** Como tabelas em Lua são estruturas básicas de dados, nós podemos armazenar informações em tabelas de outras formas, como foi explicado logo acima o método arrays, nos também podemos utilizar o dicionário: local usuario = { nome = 'Carlos', idade = 25 }; Como eu expliquei logo acima, dicionário consiste em uma chave + valor. No exemplo acima, a tabela "usuarios" recebeu 2 chaves com seus valores, se déssemos um print por exemplo: print(usuarios[1]) res => [ nil ] -- Receberíamos nil, pelo fato de termos alterado o index 1 para "nome". Quando se trata de nomes (strings) nos podemos utilizar 2 métodos para acionar a data: tabela['chave'] ou tabela.chave por exemplo: print(usuarios['nome']) res => [ Carlos ]; print(usuarios.nome) res => [ Carlos ]; Ambas as formas estão corretas, mas a segunda se torna bem mais pratica que a primeira. Lembrando que, caso a chave possua espaço, é necessário utilizar a primeira, por exemplo: local usuarios = { ['nome do usuario'] = 'Carlos' }; print(['nome do usuário']) res => [ Carlos ]; **Só a critérios de explicação, não se recomenda a utilização de espaços em nome de var ou tabelas.** Assim como no exemplo acima, poderíamos nomear uma chave dessa forma, sem espaço e acessar utilizando o "." local usuarios = { ['nome'] = 'dev' }; print(usuario.nome) res => [ dev ]; **Podemos executar dessa forma, desde que não haja espaços.** Ainda podemos criar chaves dentro de chaves por exemplo: local usuarios = { ['user'] = { ['nome'] = 'carlos', ['sobrenome'] = 'andrade' }, }; E poderíamos acessar da seguinte forma: print(usuarios.user['nome']) res => [ Carlos ]; print(usuario.user.sobrenome) res => [ Andrade ]; Em relação a objetos podemos entrar mais a fundo em outros posts caso vocês queiram, ainda temos classes e herança e metatabelas para abordar, mas como esse curso é básico não acho que seria um conteúdo interessante de jogar em cima de quem está começando. Para acessar os dados da tabela e modificar o mesmo nos podemos utilizar: local num = {x=11, y=22}; Nos podemos modificar o valor da seguinte forma: local num.y = 30; ou podemos adicionar um novo campo: local num.z = 5; As tabelas ainda nos possibilitam adicionar funções a mesma, e utilizar como objetos e/ou módulos externos e Namespace, como por exemplo: local tabela = function() print('Olá!') end Depois poderíamos chamar como uma função normal tabela(); res => [ Olá! ] Também poderíamos passar como: [ local tabela = function(args) end ] ou [ function tabela () end ] E o interessante sobre isso, é que podemos usar as regras de acesso a tabelas que foram explicadas mais a cima, e podemos criar objetos e módulos de execução de código, além de poder salvar como módulos externo e importar com um require. Mas para fixar melhor vamos utilizar um exemplo de código de vetor: local vector = {}; -- Aqui abrimos a tabela que vai ser utilizada para adição das funções. local vector.create = function(x,y) -- Aqui criamos um novo index chamado "create" e atribuimos a função a ele. return(x = x, y = y) end **No caso o primeiro X referece ao valor X a ser exportado, e o segundo X o argumento.** local vector.soma = function(num1, num2) -- Aqui criamos o index "soma" e atribuímos a ele a função. resultado = {}; -- Aqui criamos uma nova tabela, dentro de "soma", que vai armazenar o resultado. resultado.x = num1.x + num2.x -- Criamos o index "x", dentro da tabela resultado, e atribuímos a formula. resultado.y = num1.y + num2.y -- Criamos o index "y", dentro da tabela resultado, e atribuímos a formula. return resultado end local vector.print = function(n) -- Aqui criamos o index "print", e atribuímos a ele a função. print("(" .. n.x .. ", " .. n.y .. ")") end num1 = vector.create(,25) -- Aqui estamos atribuindo o valor aos argumentos e chamando a vector.create como função. num2 = vector.create(10,50) -- Aqui estamos atribuindo o valor aos argumentos e chamando a vector.create como função. vector.print(num1, num2) -- Aqui estamos chamando a função "print", como definimos e passando os valores atribuídos a ela. Se fossemos visualizar essa tabela como um todo ela estaria da seguinte forma: local vector = { ['create'] = function(x,y) return(x = x, y = y) end ['soma'] = function(num1, num2) resultado = {}; resultado.x = num1.x + num2.x resultado.y = num1.y + num2.y return resultado end ['print'] = function(n) print("(" .. n.x .. ", " .. n.y .. ")") end }; Essa seria a visualização completa da tabela, podemos ver como cada função fica em seu espaço e porque o uso do tabela.função retorna. **Podemos chamar esse tipo de construção de modulo/biblioteca, para facilitar o entendimento.** Essas funções como foram definidas acima, podem ser salvas em um arquivo externo e importadas em qualquer script, com o comando require por exemplo: local vector = require(scripts/vector); assim sempre que chamássemos vector.soma e etc, ele serie executado como um modulo, isso se torna bem util para funções uteis do MTA, como isPlayerInACL() e etc. Manipulação de Tabelas Além do que foi explicando, ainda temos como manipular as tabelas de outras forma. Que seria com a utilização da biblioteca do proprio Lua, abaixo vou explicar quais são as manipulações e como utilizar elas: table.insert (table, [pos,] value) -- Insere uma informação na tabela, na posição (index) desejada. [PUSH] table.maxn (table) -- Retorna o maior index da tabela. [POP] table.remove (table [, pos]) -- Remove dados da posição especificada da tabela. table.sort (table [, comp]) -- Ordena os elementos da tabela em uma dada ordem. table.concat (table [, sep [, i [, j]]]) Pra facilitar vou dar um exemplo: print(table.concat({"(", n.x,", ", n.y,")"})) No exemplo acima, nos criamos uma tabela dinamica dentro do print, e concatenamos (juntamos), os valores. Isso é uma boa pratica, pelo fato de quando trabalhamos com strings muito longas, os valores podem acabar se misturando, então pra evitar o uso de " .. " e resultado de erros, podemos usar o concat. E ainda evitamos o overhead do " .. " Outras funções next(table, index) -- Itera sobre cada um dos elementos na tabela. unpack(table, index) -- Retorna uma tupla com os elementos. pairs(table(t)) -- Retorna um iterador sobre todos os elementos da tabela. ipairs(table) -- Iterador sobre os indices numericos da tabela. [Parecido com forEach()] **Tupla é uma sequencia finita e ordenada de objetos.** Exemplo de Utilização do pairs e ipairs: local table = {10, 22, 33, 'dev'}; for index, value in ipairs(table) do print(index, value) end No exemplo acima estamos imprimindo todos os valores numericos da table, porem o index não chegará até o 4, porque 'dev' é uma string não um int, nesse caso poderiamos subistituir o ipairs por pairs assim teriamos todos os resultados. [Pairs não tem garantia de ordenação!] No caso do next, é bem simples a utilização vamos pensar nele dessa forma: local tabela = {40, 12, 85}; print(next(tabela[index] + 1)) -- Isso é só para facilitar a visualização! O next sempre imprime o proximo index, no caso a tabela[0] + 1 é tabela[1] res => [ 40 ]; Então se continuarmos seria res => [ 12 ]; E assim por diante. Ainda é possivel passar next(tabela, index); Exemplo de unpack: local val = {1,2} function soma(num1, num2) return num1 + num2 end print(soma(val[1], val[2])) res => [ 3 ]; Porem o unpack realiza isso para nos, portanto, poderiamos utilizar: print(soma(unpack(val))) res => [ 3 ]; **Unpack funciona apenas em elementos numericos.** Caso queiram, podem postar o código nesse tópico, e caso tenham alguma duvida, deixem logo a baixo. Só lembrando ao pessoal que já entende do assunto, ou pelo menos sabe o básico, vamos ajudar quem ta começando, todo mundo começou sem saber quase nada. Pessoal, gostaria de saber oque vocês querem no ultimo post sobre Lua, na parte de MTA, exemplos de resources e etc, e porfavor comentem se gostariam de ver um curso intermediario/avançado de Lua, cobrindo os pontos que não abordei durante esses posts.
  3. Post Anterior: Eai pessoal tudo bom? Continuando o Curso básico, hoje vamos um pouco sobre a Wiki e Funções: MTA WIKI Antes de mais nada, praticamente todo o conteúdo da wiki do mta, se encontra em inglês, portanto se você não entende bem o idioma use algum método de tradução, apesar que sinceramente, eu recomendo aprender inglês, afinal quando se trata de programação uns 80% do conteúdo é em inglês. Para começamos, segue o link oficial da Wiki do MTA: https://wiki.multitheftauto.com/wiki/Main_Page Como podem notar quando abrirem o link, a wiki conta com uma grande variedade de conteúdo, então para ser sincero eu vou simplesmente citar os conteúdos que eu considero essenciais para criação de scripts, e os algumas dicas e métodos para ajudar quem não está familiarizado com a wiki entender como ela é organizada. Antes de mais nada, a wiki possui uma barra de pesquisa, que fica localizada a esquerda da página, como mostra a imagem: https://prnt.sc/r98vua Nesta barra de pesquisa, você pode digitar o nome de funções para saber sua funcionalidade, por exemplo vamos pesquisar onPlayer: https://prnt.sc/r98wa4 Como podem ver a pesquisa nos retorna possíveis resultados, acredito eu que seja baseado em ordem de adição ou visualização que os conteúdos são mostrados, mas não tenho certeza. Quando encontrar o recurso que procura, basta clicar no nome que sera direcionado a pagina com a explicação e exemplo de código sobre o recurso, por exemplo onPlayerWasted(): https://wiki.multitheftauto.com/wiki/OnPlayerWasted Novamente o próprio nome da função já diz para que ela serve, por isso recomendo que aprendem inglês ou traduzam caso tenham dificuldades. OnPlayerWasted pode ser lido como "Quando o Jogador Morrer" (tradução livre),esse recurso, como o nome já diz, só será executado quando o jogador for morto, na wiki também é possível visualizar os argumentos que o recurso recebe por exemplo: int totalAmmo, element killer, int killerWeapon, int bodypart, bool stealth Lembrando que Anteriormente eu expliquei que int = interger que significa "Valor Numérico", portanto sempre que vocês verem int lembrem-se que se trata de números. Vamos separar por partes os argumentos da função: int totalAmmo = Numero total de munições da vitima; -- Recebe Numero element killer = Quem é o assassino; -- Recebe o elemento int killerWeapon = Qual arma ele usava; -- Recebe Numero int bodypart = Qual parte do corpo da Vitima, foi atingido; -- Recebe Numero bool stealth = Se foi uma execução ou não; -- Recebe true ou false Bom vamos entender algumas coisas. O principal nessa função é o Element o Bodypart e o Source, como a propria wiki explica: https://prnt.sc/r98zkl O Source desse recurso é quem foi morto. Então tenham em mente que até os paramentos de elementos são passados na wiki. Só para esclarecimento, element (elemento), no MTA pode ser considerado tudo aquilo que é uma entidade existente, por exemplo: Ped, jogadores, carros, markers e etc. Tudo que existe e foi criado é um elemento. No caso da killerWeapon temos que levar em consideração como as armas no MTA são organizadas, para isso a wiki tem uma tabela com todas as armas e suas informações: https://wiki.multitheftauto.com/wiki/Weapons Os pontos principais a serem observados em questão de armas são: https://prnt.sc/r99134 Nessa mesma página da wiki, um pouco mais a baixo, a wiki sempre nos surege recursos relacionados ao que estamos pesquisando, por exemplo: https://prnt.sc/r991qy **Clicando em algum desses links, sera redirecionado até a página do recurso, onde pudera encontrar, todas as informações necessárias.** Eu sei que pode parecer meio vago a explicação da Wiki, mas aqui cobrimos os principais pontos, o exemplos de código, os argumentos, source e elementos, e alem de tudo isso a wiki ainda conta com exemplos de código, retornando ao onPlayerWasted, por exemplo: addEventHandler( "onPlayerWasted", getRootElement(), function() setTimer( spawnPlayer, 2000, 1, source, 0, 0, 3 ) end) Esse é um exemplo de código, no caso a wiki conta com outro bem mais explicativo, mas para não deixar o tópico com muito código da wiki, vou me ater apenas aos básicos para explicação. Além dos exemplos de código, a wiki ainda conta com recursos relacionados, então se tirarem um tempo para olhar melhor a wiki, tenho certeza que vão encontrar tudo que precisa. Outra coisa a se manter atenção na wiki são os "lados" dos códigos, sempre que se depararem com exemplos de código, em uma caixa laranja como a da foto: https://prnt.sc/r993el , se trata de um código que deve ser executado do lado Server. Caso contrário, encontrem uma janela vermelha como a da foto: https://prnt.sc/r9941b , se trata de um código que deve ser executado do lado Client. **Caso um código tenha apenas uma caixa branca, ou possua as 2 caixas, significa que ele é shared ou seja funciona em ambos os lados. Salvo casos de funções exclusivas de cada lado.** Mas alguns de vocês devem estar se perguntando qual a diferença entre o lado Client e o Server. Eu poderia entrar em toda a explicação do porque são diferentes e etc, mas para facilitar o entendimento, vamos considerar que: Client Side: Tudo que roda na máquina do Jogador/Usuário; Server Side: Tudo que roda no servidor, sem interação ou necessidade dela, pelo Usuário. E qual a importância da utilização correta do Client e do Server? Bem, por questão de segurança mesmo, eu recomendo que sempre utilizem informações sensíveis, e recursos em Server Side, e exportem apenas a parte gráfica e valores necessários para exibição para o lado client. Assim você evitar que pessoas roubem os teus scripts e também evita que jogadores tenham acesso a dados sensíveis, como datas, sets e etc. Para facilitar a pesquisa de vocês, eu vou linkar ao post os links uteis da wiki, mas só lembrando que eles podem ser encontrados na pagina inicial: Introdução ao Script:https://wiki.multitheftauto.com/wiki/Scripting_Introduction Introdução ao Script com Interface Gráfica: https://wiki.multitheftauto.com/wiki/Introduction_to_Scripting_the_GUI Funções do Lado Server: https://wiki.multitheftauto.com/wiki/Server_Scripting_Functions Eventos do Lado Server: https://wiki.multitheftauto.com/wiki/Server_Scripting_Events Funções do Lado Client: https://wiki.multitheftauto.com/wiki/Client_Scripting_Functions Eventos do Lado Client: https://wiki.multitheftauto.com/wiki/Client_Scripting_Events Funções Uteis: https://wiki.multitheftauto.com/wiki/Useful_Functions Elemento do MTA: https://wiki.multitheftauto.com/wiki/Element Classes do MTA: https://wiki.multitheftauto.com/wiki/MTA_Classes Os ID podem ser encontrados na pagina inicial como mostrado na imagem, não vou linkar porque seria muitos links: https://prnt.sc/r998ga Outro link que recomendo muito a leitura é sobre os eventos: https://wiki.multitheftauto.com/wiki/Event_system Ok Tendo tudo isso em mente, vamos começa a entender funções. Alguns podem achar que a introdução sobre a wiki é perda de tempo, porem, enquanto estiverem programando, é importante saber como utilizar a wiki, ja que a maiorias se não todas as duvidas, podem ser tiradas lá. Vou dizer algo que o pessoal pode não querer ouvir, mas ninguém é obrigado a ti ajudar. Nunca, nem em código nem na vida, ninguém é obrigado a isso, as pessoas fazem porque querem, ou ganham algo com isso. Mas nem sempre vão fazer ou ganhar algo, então eu realmente sugiro que aprendam a aprender, e a maneira mais fácil de fazer isso é pesquisando e lendo. **Meio irônico vindo do cara que ta escrevendo isso, mas acreditem isso vale para vida, aprendem a se virar.** Funções Primeiro vamos definir oque são funções, pudemos definir funções como blocos de código que executam tarefas especificas. Podemos escrever também como "Funções dão programas, dentro de programas.", e acreditem essa frase faz sentido, programa é tudo aquilo que realiza algo, e as funções são blocos de código, que executam tarefas específicas como eu mencionei logo acima, portanto são programas por si só, e estão dentro fazem parte de um programa maior. Antes de começarmos a falar de funções, é necessário que se entenda a sintaxe dela em Lua. function nome_daFunção(argumentos) -- Bloco de Código end **Vamos lembrar das boas praticas de programação quando formos nomear as funções.** Bom para declarar uma função utilizamos o function seguido do nome da mesma e (), dentro desses parênteses, podemos passar argumentos caso haja. Mas oque seriam argumentos? Vamos pensar nas funções como chamados, nós estamos chamando algo, e podemos direcionar esse chamado, por exemplo, vamos supor que estamos chamando uma pessoa, no meio da multidão, então essa pessoa tem um nome, como verificaríamos que essa pessoa é a qual procuramos? Com o uso de condicionais acredito que vocês ja devam conseguir pensar em algo mas vamos a um exemplo: function chamar_pessoa(nome) if nome == "Dev" then print('Você encontrou a pessoa!') else print('Você não encontrou a pessoa!') end end Sendo assim a função logo acima está bem logica, mas como iriamos chamar a pessoa de fato? utilizando a seguinte sintaxe: nome_daFunção(argumento) No nosso exemplo ficaria assim: chamar_pessoa('Dev') E o resultado seria => [ Você encontrou a pessoa! ] Então para deixamos claro, uma função não é executada a menos que a gente chame ela. No caso do MTA nos temos os eventos e Handlers que poderíamos pensar como pequenos robôs chamando as funções para nos, por exemplo o onPlayerWasted(), ela é uma função que só é chamado quando o jogador morre, outro exemplo seria o onPlayerLogin() que só execu a quando o jogador entra no servidor. Mas tirando esses casos de auto execução, as funções só serão chamadas caso você queira, ou defina alguma forma do usuário chamar por exemplo com o addCommandHandler(). Só para relembrar, funções podem receber Condicionais, iterações e afins, mas ainda seguem a mesma logica de concatenação e etc. Outra coisa importante, funções recebem argumentos em ordem sequencial, isso significa que pode exemplo uma função com: function soma_numeros(a1, a2) if a1 and a2 then local resultado = a1 + a2 return resultado end end Caso eu chame a função por exemplo soma_numeros(1,2); o resultado seria => 3. Porem caso eu não passe algum dos argumentos, ele vai retornar nil e dará um erro, e lembre se de separar os argumentos por virgula " , ". Para ajudar vocês, deem uma lida sobre os handlers e etc nos links abaixo: addEvent: https://wiki.multitheftauto.com/wiki/AddEvent addEventHandler: https://wiki.multitheftauto.com/wiki/AddEventHandler cancelEvent: https://wiki.multitheftauto.com/wiki/CancelEvent Exercícios 1. Faça um programa que receba do usuário um numero é faça o seguinte ( n * n/4 - 1 ); 2. Faça um programa onde uma função main() ira executar uma verificação sobre a existência de um numero X, e passar a uma função externa, que deva imprimir o resultado; 3. Faça uma função que divida numero enviado pelo usuário; 4. Faça uma função que imprime um certo numero de linhas, recebidos em um for; 5. Faça uma função main() que executa uma função ao fim de um repeat. Caso queiram, podem postar o código nesse tópico, e caso tenham alguma duvida, deixem logo a baixo. Só lembrando ao pessoal que já entende do assunto, ou pelo menos sabe o básico, vamos ajudar quem esta começando, todo mundo começou sem saber quase nada. Parte 05:
  4. Post Anterior: Comentando o Código Antes de mais nada, boas praticas de programação, não são uma regra fixa que não pode mudar, mas sim, praticas (como o nome já diz), que facilitam o desenvolvimento, e o trabalho em equipe em um código. A principal boa pratica de programação é comentar o código, em Lua os comentários podem ser feitos da seguinte forma. Para comentar linhas únicas se utiliza ( "--" ) da seguinte forma. if condição then -- Comentário do IF. Para comentar em blocos se utiliza --[[ Bloco a ser comentado ]] Tentem manter ao máximo a pratica de comentar oque cada função faz, variáveis e etc, assim fica mais fácil para você se encontrar no código, e para quem estiver trabalhando junto com você no código. Desenvolvimento & Identação Sempre que forem programar tente manter em mente que seu código deve ser: 1. Simples - Deve ser de fácil compreensão; 2. Direto - Deve executar aquilo que é proposto, sem rodeios, e sem funções desnecessárias e sem utilidade; 3. Organizado - Deve seguir uma ordem de organização (mais a baixo vou exemplificar uma organização.) 4. Sem duplicidade - não faz o que outra parte do código já faz; 5. Elegante e Único - Seu código deve ser algo que você se orgulhe de ter feito, que seja elegante, e funcional e que principalmente seja seu. Um dos pilares para organização do código e para facilitar a visualização do mesmo, seria a utilização de uma boa identação, como por exemplo: Código sem identação: addEventHandler( "onPlayerWasted", getRootElement( ),function() setTimer( spawnPlayer, 2000, 1, source, 0, 0, 3 ) end) Mesmo ainda sendo legível o exemplo básico de código logo acima, se ele for identado fica melhor a compreensão do mesmo. Código Identado: addEventHandler( "onPlayerWasted", getRootElement( ), function() setTimer( spawnPlayer, 2000, 1, source, 0, 0, 3 ) end) Pode parecer algo besta, só alguns tabs para organização, mas em um código com mais de 300 linhas, isso faz muita diferença. **Só para lembrar, Lua não necessariamente precisa de identação já que tem then/do e etc, mesmo assim é uma boa pratica.** Nome de Variáveis e Outras boas Praticas Outra boa pratica de programação é a forma como se nomeia as variáveis e funções, não há uma regra definidas mas existem padrões em outras linguagens para facilitar a leitura, por exemplo: Variáveis se escrevem com nome_nome = valor Funções se escrevem com nome_nome() Eu recomendo que nomeiem as funções dessa forma ou nomeNome = valor; nomeNome(); Além disso recomendo que sempre utilizem nomes que façam sentido por exemplo: local nomeJogador = getPlayerName(source) -- Vou explicar quando usar Source/Player/thePlayer na parte de Script. Caso fosse uma função poderia ser obterNomeJogador() ou obter_nomeJogador(), o importante é que seja legível e você consiga identificar oque ela faz. Alguns podem se perguntar, porque não utilizar tudo minúsculo e junto, bom quando você começa a trabalhar com letras iguais isso se torna um problema por exemplo: local casaamarela = x, y, z Nesse caso seria recomendável uma separação, por padrão eu sugerido que sempre usem minusco e _ dessa forma casa_amarela = x, y, z; Assim mesmo que as letras sejam iguais, você não teria que se preocupar com descobrir oque aquele variável faz. Um pratica que eu não recomendo de forma alguma é abreviação ou o uso de letras por exemplo: local obter_nomeJogador() Que passaria a ser local onj() Para você que esta programando pode fazer o maior sentido agora, mas para outras pessoas ficam muito confuso, além de que você pode se esquecer ou nomear funções com as mesmas letras mais a frente no código, oque geraria conflito com a informação. Outra boa pratica de programação seria a de utilização de parênteses () em verificações, eu pessoalmente não me atenho muito a isso, porem facilita muito a vida de quem esta começando exemplo: local x = 10; local y = 50; if x < y then Passaria a ser: if (x < y) then Essa pratica torna a condição muito mais visível, e facilita o entendimento da verificação. ** Porem no caso de Lua assim como o ; ao final das var não é de uso obrigatório, outras linguagens podem ser.** Loops e Condicionais Como foi explicado no post passado, os loops e condicionais são muito uteis e fazem grande parte da programação, porque querendo ou não, temos que verificar coisas, e agir de acordo com elas. Tendo isso em mente, vou dar uma dica básica, evite chamar funções em loops ou condicionais complexas, principalmente em loops. Oque acontece aqui é que mesmo um while/repeat executa varias vezes um mesmo bloco de código, até prover uma condição favorável a saída, e isso pode parecer Simples, mas imagine você chamando 10,20 ou 30 vezes uma mesma função, que atribui valores locais na memoria, e executa. Em Lua isso não se torna um problema muito grande, mas em outras,linguagens como C ou mesmo JS isso pode causar um crash na aplicação muito fácil, então para evitarmos que esses problemas possam acontecer, evitem ao máximo chamar funções dentro de l ops ou condições complexas. Negações no IF Outra pratica que e interessante se evitar, é utilizar as condicionais no negativo, por exemplo o if not. Lembre-se que uma condição, só é executada quando a condição se torna verdadeira, e um if not é uma negativa verdadeira, parece algo besta, mas você poderia lidar com ela no else, isso é mais uma recomendação mesmo, trate as verificações sempre como produtos verdadeiros e lide com os negativos no processo, não faça uma negativa verdadeira. Organização de Código No começo do código, geralmente é recomendável a importação de bibliotecas, funções externas, e etc. Depois a atribuição de variáveis globais se necessário. Podem seguir esse modelo básico: Variáveis globais e Datas; Objetos e Afins; Funções e Condicionais; Exports e Imports; Handles e eventos. Pode parecer meio confuso agora, mas quando chegarmos na parte de Script de MTA, vamos seguir essa organização e garanto que tudo vai ficar mais fácil. Como esse post trata de praticas de programação, eu recomendo que você retorne em seus códigos antigos e tentem refazer eles utilizando essas técnicas, e organizar o seu código da melhor maneira possível. O único exercício que eu vou deixar aqui, é que vocês tentem diminuir a quantidade de linhas nos seus código antigos, sem perder funcionalidade. Caso queiram, podem postar o código nesse tópico, e caso tenham alguma duvida, deixem logo a baixo. Só lembrando ao pessoal que já entende do assunto, ou pelo menos sabe o básico, vamos ajudar quem esta começando, todo mundo começou sem saber quase nada. Parte 04:
  5. Post Anterior: Eai pessoal tudo bom? Continuando o Curso básico, hoje vamos falar sobre Condicionais, Iteração e Variáveis: Para vocês irem se familiarizando eu vou começar a utilizar trechos de código em Lua. Nos exemplos anteriores além de utilizamos apenas linguagem padrão, e portugol, nos utilizamos apenas execuções sequenciais, ou seja, o algoritmo poderia apenas executar uma vez, e em uma sequencia, da linha 01 até a última, mesmo com o exemplo básico de verificação que nos fizemos, ainda sim, era uma execução sequencial. Para mudar isso, vou apresentar a vocês os principais condicionais e como utilizar o mesmo, e uma breve explicação sobre variáveis. Vamos começar pelas variáveis que são mais simples em grande parte. Diferente de outras linguagem as variáveis de Lua não são de tipo fixo, elas podem receber qualquer tipo de valor, as mesmo assim, elas respeitam a logica de combinação como por exemplo: local nome = "Dev" -- Atribuímos a um espaço de memoria o valor "Dev" e nomeamos esse espaço como "nome". local numero = 1 -- Atribuímos a um espaço de memoria o valor "1" e nomeamos esse espaço como "numero". Se fossemos utilizar outra linguagem, como C por exemplo, nos teríamos que definir o tipo de variavel, por exemplo: char nome = "dev"; int numero = 1; Em C no caso nós devemos nos prender a sintaxe padrão, e a utilização dos tipos: Sintaxe: <tipo> <nome_da_variável> ; int: armazena valores numéricos inteiros. char: armazena caracteres. float: armazena números com ponto flutuante (reais) com precisão simples. double: armazena números com ponto flutuante, com precisão dupla, ou seja normalmente possui o dobro da capacidade de uma variável do tipo float. E os principais tipos de dados seriam: Inteiro: armazena números inteiros Real: armazena números com casas decimais, são as variáveis de ponto flutuante; No caso de Lua essa lógica ainda existe. E ainda podemos armazenar dados do tipo Boolean (true/false) & nil. Como vocês puderam perceber as variáveis em Lua, funcionam de uma maneira muito pratica, porque você simples insere o valor nela, e automaticamente, ela entende o tipo e organiza a memoria dessa forma. Tendo isso em mente, vamos a algum exemplos básicos. Iguais combinam com iguais. Isso significa que se eu puxar a minha variável dev e a variável numero, e tentar unir as duas vai retornar um erro, pelo fato do tipo das duas serem diferentes. Imagem ilustratva: https://imgur.com/a/n0u9pL5 Para executar o print(dev + numero), teríamos que modificar o valor de numero para uma string. Com a utilização de tostring(numero); Para mudar o tipo de inteiro para string. Prestem atenção nisso, porque um numero pode ser um string por exemplo local numero = "1"; no caso esse 1 seria uma string e não um numero, oque impossibilitaria operações matemáticas com o mesmo. Nesse caso também poderia usar o tonumber(numero); para mudar o tipo. Caso tenham duvida sobre o valor de uma variável podem utilizar type(var); para saber qual tipo ela seria, por exemplo: local num = 1; --> Number/Integer local nam = "2"; --> String local status = false --> Boolean Caso desse um print(type(var)); e cada uma dessas receberia os valores citados acima. Caso você tente utilizar em uma var que não foi atribuída ira retornar o valor nil que significa que não há nada ali, não tem memoria atribuída nem valor a essa var. Condicionais Iniciando em condicionais vamos começar pela mais usada e básica de todas o if. O if funciona da seguinte maneira: if expressão_lógica then -- bloco de comandos end **Lembrando, o IF deve sempre ser fechado com o END, não se esqueçam disso.** Se ficar mais facil pode-se ler if como SE, então ficaria da seguinte forma SE expressão_lógica ENTÂO. Agora oque seria essa expressão lógica? Essa é a verificação que deve ser executada antes de se dar continuidade ao código, no nosso exemplo em linguagem padrão nos utilizamos o SE o relógio marcar = 6:30 ENTÂO, no caso a expressão_lógica será relógio marcar = 6:30 que só poderia retornar true ou false, no caso de uma verificação o valor true é sempre tido como condição principal a não ser que você exemplifique o contrario por exemplo: local nome = "dev"; if nome then -- código end A verificação aqui é simples, SE existir nome ENTÂO. Porque a condição é true, agora eu poderia usar: local nome = "dev"; if not nome then -- código end A verificação aqui é ao contrario da anterior, no estamos utilização a condição not como negação a existência da var então ficaria SE NÂO existir nome ENTÂO. Para vocês terem uma ideia melhor das expressão_lógicas vamos listar cada uma delas: Igual a | == | -- Verifica se os valores são iguais. Diferente de | ~= | -- Verifica se os valores são diferentes. Maior que | > | -- Verifica se o 1 valor é maior que o 2. Menor que | < | -- Verifica se o 1 valor é menor que o 2. Maior ou igual a | >= | -- Verifica se o 1 valor é maior OU igual ao 2. Menor ou igual a | <= | -- Verifica se o 1 valor é menor OU igual ao 2. As principais são true e false, exemplos: local x = 10; local y = 50; if x == y then -- Aqui estamos verificando se X é igual a Y, oque obviamente é uma mentira então o retorno será false, e o código abaixo não será executado. if x > y then -- Aqui também estamos em uma verificação False, portanto o código não ira executar, porem se usarmos not if not x > y then -- Aqui no caso o retorno é verdadeiro, então o código abaixo ira executar. Outro tipo de condição que nos podemos usar são os de concatenação: Conjunção | and | -- Verifica se duas ou mais condições são atendidas. Disjunção | or | -- Verifica se uma ou qualquer outra condição é atendida. Negação | not | -- Verifica se alguma condição não é atendida. Alguns exemplos: local x = 10; local y = 50; local nome = "dev"; local status = true; if nome == "dev" and status == true then -- Aqui verificamos se a var nome possui o valor "dev", e se a var status possui true, caso ambas sejam atendidas, o código executa. if status == false or x < y then -- Aqui estamos verificando se alguma das condições são verdadeiras, no caso o x é < que o y então o código executa. if not status == true or x > y or type(nome) == string then -- Aqui estamos passando mais de uma verificação com o OR e caso alguma delas seja verdadeira o código ira executar. Com essa regras básica em mente, eu sugiro que vocês, façam códigos simples utilizando esses conceitos para gravarem eles melhor. Continuando a falar sobre o if. O if ainda possui uma condição negativa por padrão que é chamada de else, da seguinte forma: if expressão_lógica then -- Bloco de comandos else -- Bloco de comandos end Dessa vez no fazemos uma verificação e caso ela não seja atendida nos executando outro bloco de código por exemplo: local x = 10; local y = 50; if x > y then print('X é maior que Y') else print('X é menor que Y') end Nesse caso nossa verificação não ira retornar true porque x não é maior que y, então o bloco 1 do código não será executado, porem com o else, o bloco dois será. Ainda no IF no temos o elseif que é uma segunda condicional dentro da primeira por exemplo: local x = 10; local y = 50; if x > y then print('X é maior que Y') else print('X é menor que Y') end Nesse caso nossa verificação não ira retornar true porque x não é maior que y, então o bloco 1 do código não será executado, porem com o else, o bloco dois será. Ainda no IF no temos o elseif que é uma segunda condicional dentro da primeira por exemplo: local x == 10; local y == 50; if x > y then -- bloco 1 elseif x < y then -- bloco 2 else -- bloco 3 end Nesse caso a primeira verificação é falsa, então a sequencia continua, a segunda verificação retorna true e então é executada, caso nenhuma das duas seja true, seria executado o bloco 3 do else. ** Lembrando o elseif sempre vem ante do else, e não tem limite de uso, apesar de não ser uma boa pratica de programação, enfiar um monte de if/elseif no código.** Iterações As iterações são estruturas de repetição, elas são o for / while e repeat. Vamos começar pelo while e repeat que são bem semelhantes: a sintaxe do while consiste em: while condição do -- código end Seguindo essa lógica a condição de entrada em um loop de while é definida antes do inicio. Para ficar mais simples pode-se ler while como: ENQUANTO condição FAÇA -- código FIM Vamos ao exemplo: local x = 1; local y = 10; while x < y do x = x + 1 end Nesse caso estamos executando um loop, da seguinte forma: ENQUANTO x for menor que Y FAÇA PEGUE x e Adicione X + 1 FIM Caso a gente desse um print(x) nesse caso a saida seria: 1 2 3 ... Até o 10. Ou seja o while significa **repita tal ação até que a condição seja verdadeira.** o repeat funciona semelhante ao while porem a condição de saida/verificação é posta no final, com a seguinte sintaxe: repeat -- bloco de código until(condição) Vamos usar o mesmo exemplo acima: local x = 1; local y = 10; repeat print(x) x = x + 1 until(x == y) O for pode ser ler PARA valor, max/min incremento FAÇA, a diferença do for para o while/repeat é que o for você tem um numero máximo e mínimo de execuções, que deve ser definidas no inicio da condicional por exemplo: for i=1, 10, 1 do print(i) end Aqui vamos ir do 1 ao 10 somando sempre 1 ao numero anterior, com uma saída de 1,2,3,4,5..10. Poderíamos utilizar 2, 3, -1 e qual numero quiséssemos no acréscimo Dentro de variáveis ainda temos os Arrays (tabelas), mas vou deixar para explicar depois de funções, já que tabelas em luas são bem extensas e com muitas funcionalidades. Exercícios 1. Faça um programa que verifique as medias dos alunos, em 2 cursos, e retorne aprovado ou reprovado baseado em média geral superior a 5. 2. Faça um programa que se repete até uma condição numérica retorne verdadeira, condição essa superior a 10. 3. Faça um programa que imprima na tela, tipos de variáveis utilizando um for. 4. Faça um programa que muda o tipo de variáveis e imprima elas. 5. Faça um programa que leia oque o usuário digitou e retorne na tela. Site que podem ser Uteis: https://www.Lua.org/portugues.html https://www.tutorialspoint.com/Lua/index.htm Caso queiram, podem postar o código nesse tópico, e caso tenham alguma duvida, deixem logo a baixo. Só lembrando ao pessoal que já entende do assunto, ou pelo menos sabe o básico, vamos ajudar quem ta começando, todo mundo começou sem saber quase nada. Parte 03:
  6. Eai pessoal tudo bom? Eu percebi que muitas das duvidas que o pessoal posta aqui no fórum e também na comunidade, são duvidas muito simples, principalmente com erros de logica, ou mau uso dos recursos da linguagem. Então decidi desenvolver um curso básico para auxiliar quem está começando, nesse curso básico vou abordar os seguintes assuntos: Lógica de Programação & Algoritmo; Condicionais & Variáveis (Básico); Sintaxe & Indentação; Boas Praticas de Programação; Como usar a Wiki; Funções(); Tabelas (Arrays); Scripts voltado ao MTA; Exercícios. Antes que venham falar "Quem é você para fazer um curso?", vou me apresentar: Eu me chamo Marcelo, trabalho com programação a cerca de 7 anos, já trabalhei com desenvolvimento, back-end e front-end. Atualmente eu trabalho na área de SI (Segurança da Informação) prestando serviço como pentester e consultor a uma empresa. Comecei a me envolver com Lua, por que joguei MTA por muito tempo, e percebi que a maioria dos servidores não atendia as minhas expectativas, então junto com um amigo, decidimos criar um novo servidor, o New Dream's Roleplay. Mas como o assunto aqui é o Tutorial, vou me ater apenas a ele, e deixo para falar do servidor outra hora. Lógica de Programação & Algoritmo Para deixar bem claro, vou usar as minhas definições das palavras durante o curso, porque acredito ser mais didática dessa forma. Antes de mais nada vamos deixar bem claro algumas coisas: Programação é lógica, a linguagem e etc, são apenas ferramentas para organizar e dar sentido a essa lógica. Portanto se você dominar a lógica de programação, poderá aplicar ela a qualquer linguagem. Tendo isso em mente, a aplicação da lógica podemos chamar de algoritmo. O Algoritmo por sua vez é uma sequencia de instruções, para a execução de uma tarefa. Claro que levando em consideração que o algoritmo conta com verificações, iterações e etc. Pois bem eu acredito que lógica só se aprenda fazendo, então vamos com alguns exemplos: Para facilitar a vida de alguns de vocês na compreensão, vou utilizar o Portugol como "linguagem" nesses exemplos, e recomendo que usem também nos exercícios. Para acessar o Portugol utilizem o link: http://lite.acad.univali.br/portugol/. Vamos começar pelo código mais repetido do mundo o "Olá Mundo" algoritmo OlaMundo; -- Aqui nos definimos o nome do Algoritmo inicio -- Aqui damos inicio ao mesmo imprima("Olá, Mundo!"); -- Aqui solicitamos que o Computador imprima a frase "Olá, Mundo!" fim -- Aqui encerramos Como podem reparar, toda a formação obedece uma lógica simples, você define, inicia, executa e encerra. Para termos um exemplo mais lúdico, vou usar linguagem padrão e descrever a seguinte situação: Acordar e sair para o trabalho. 01. Abrir os olhos; 02. Olhar o relógio; 03. Levantar da cama; 04. Ir ao banheiro; 05. Sair do quarto, e ir a cozinha; 06. Preparar o café da manha; 07. Sentar a mesa; 08. Comer o café da manha; 09. Lavar a louça do café da manha; 10. voltar ao quarto; 11. Vestir a roupa 12. Sair do Apartamento; 13. Descer o elevador; 14. Entrar no carro; 15. Ir ao trabalho. O exemplo acima é um algoritmo em linguagem padrão, quero que vocês percebam como ele utiliza uma sequencia lógica para executar uma tarefa. Agora, mais a frente iremos ver condicionais e verificações, mas já quero apresentar uma introdução sobre a mesma, nesse exemplo a cima, vamos adicionar uma verificação básica ali em cima na linha 02 01. Abrir os olhos; 02. Olhar o relógio CASO o relógio marque = 6:30 ENTÂO Faça a linha 03. CASO CONTRARIO espere até dar 06:30; 03. Levantar da cama; ... Nesse exemplo colocamos uma verificação simples, caso o horário seja o qual nos queremos, então vamos continuar com o algoritmo, isso é uma condição verdadeira ou falsa, e uma condição única, poderíamos adicionar outra condições por exemplo: 01. Abrir os olhos; 02. Olhar o relógio CASO o relógio marque = 6:30 && NÂO SEJA sabado OU domingo ENTÂO Faça a linha 03; 03. Levantar da cama; ... Aqui estamos adicionando outra verificação, e ambas precisam ser verdadeiras para que a sequencia se complete. Com esses exemplos em mente, vou deixar alguns exercícios para vocês, podem fazer tanto em linguagem padrão como em portugol (recomendo mais o portugol). 1. Acordar e ir ao trabalho; 2. Lavar o carro; 3. Um robô que pegue caixas; 4. Planejar uma viagem; 5. Jogar um jogo. Caso queiram, podem postar o código nesse tópico, e caso tenham alguma duvida, deixem logo a baixo. Só lembrando ao pessoal que já entende do assunto, ou pelo menos sabe o básico, vamos ajudar quem ta começando, todo mundo começou sem saber quase nada. Parte 02:
  7. Se eu não me engano, o dano do Hydra é o mesmo da M4, então provavelmente você teria que fazer uma condição com onPlayerDamage ou algo assim, se não quiser mudar a M4 junto.
  8. Tem uma forma de você alterar o dano das armas, você poderia usar as funções onPlayerDamage / onClientPlayerDamage, teria que setar o dano de cada arma com getElementHealth e setElementHealth, alem de ter que considerar o dano variado para cada parte do corpo, como cabeça, tronco , braços e pernas. Funciona legal mas da um trabalho de caramba fazer isso. Em realação a alterar a arma, apenas o modelo dela, sendo a .dff e a.txd, não acredito que tu possar criar uma nova cadencia de tiro e etc, apesar que no setWeaponProperty, tu pode mudar numero de balas e afins, mas na wiki tenho certeza que tu deve encontrar as outras opções as vezes da pra fazer algo legal, mas mudar completamente acho muito dificil. EDIT: Com essa função custom, tu poderia criar tipo um nivel de habilidade de armas, setando bonus de dano para jogadores e afins, poderia definir por ACL e etc, ai é só usar a imaginação mesmo.
  9. Então Tommy, obrigado por responder, mas no exemplo de código acima eu já uso o toggleAllControls e ja tentei usar o toggleControl, porem o jogador continua conseguindo cancelar a animação e se movimentar. Teria alguma outra opção pra frezzar ou proibir o mesmo de realizar qualquer ação, porque eu já tentei bloquear os 3 tipos de controle e mesmo assim não adiantou.
  10. Olá pessoal, gostaria de uma ajuda, eu estou editando um script de Taser e encontrei os seguintes problemas: - O jogador fica freezado, porem não inicia a animação; - O Jogador inicia a animação porem não fica freezado; Também tentei bloquear as teclas com "onClientKey", e uma tabela com todas as teclas seguido de um cancelEvent(), pra evitar que o mesmo burle a animação, ou simplesmente se mova enquanto está caido. Para fazer isso eu fiz um script para pegar onde foi o tiro no jogador utilizando a função "onClientPlayerDamage" e "onClientPedDamage". Deixando de lado as animações diferentes eu fiz uma função para trigar o evento do lado server: -- Freezar Player que Tomou Taser -- function playerTased(source) setPedFrozen(source, true) toggleAllControls(source, false, false, false) setTimer(function() setPedFrozen(source, false) toggleAllControls(source, true, true, true) end, 5000, 1) end addEvent("onPlayerTased", true) addEventHandler("onPlayerTased", getRootElement(), playerTased) E passei do lado client chamando o evento da seguinte forma: triggerServerEvent("onPlayerTased", localPlayer, source) setPedAnimation(source, "ped", "KO_shot_face", 10000, false, true, false) A minha duvida é a seguinte, tem alguma forma de eu forçar o Freeze com o cara no chão no final da animação? Existe alguma outra função que possa me ajudar, porque sendo um servidor RP, não tem como eu deixar o cara ter a possibilidade de se mover ou até mesmo atirar, que é esse um dos outros problemas, quando a animação não acontece, o jogador ainda consegue atirar, mesmo quando eu usei o cancelEvent() e o For com as keys.
  11. Entendi DNL, eu fiz tudo server side, mas vou usar interface grafica do lado client, minha ideia pra evitar que mais pessoas aceitem o trabalho, seria verificar uma tabela com quem já aceitou e nomear o primeiro, e setar o blip e etc. Assim apenas uma pessoa poderia aceitar um pedido por vez, no caso uma VTR de policia, mas vou usar a base pra todos os trabalho, mecanicos, taxi e etc.
  12. Obrigado Henry, mas tenho mais uma duvida, seria necessário triggar um event para que o jogador aceitasse o Job, ou posso só passar as funções normais com o o bindKey? Porque na minha cabeça eu tinha que fazer um evento para iniciar o trabalho, depois as keys para iniciar o evento de trabalho, e uma para negar, funciona dessa forma ou apenas as funções aceitar/negar e o commandHadle daria conta?
  13. Olá pessoal, gostaria de uma ajuda, estou começando a programar para MTA e queria fazer um Script de trabalho com as seguintes funcionalidades: O cliente iria solicitar o Trabalho, eu pegaria a posição dele, e mandaria um aviso para todas as pessoas que estão naquele trabalho, por exemplo a policia, então o policial iria apertar uma tecla definida para aceitar o chamado ou negar o chamado. A minha duvida é como vou pegar essa tecla sem inutilizar ela para o jogador, alguém poderia me dizer quais os nomes das funções que poderia me ajudar, que o resto eu olho na wiki e faço os testes. Desde já obrigado.