Ir para conteúdo

Skyen

Campones
  • Total de itens

    36
  • Registro em

  • Última visita

  • Dias Ganhos

    5

Tudo que Skyen postou

  1. Acho que arrumei quase tudo o que estava bugado. Realmente esse negócio de tab me encheu o saco. Outro bug dele é que o editor convertia algumas letras maiúsculas com acentos em minúsculas e adicionava um monte de espaços em lugares que não devia. Mas, enfim, acho que tá arrumado. E quanto à tabela, eu passei muito tempo pensando nisso e decidi que assim fica mais legível porque tabelas de linha única contém poucos atributos, e o espaço adicional geralmente ajuda a quebrar uma outra regra que eu sigo mas não adicionei ali pra não complicar: Máximo de 80 caracteres na horizontal. Mas claro, como eu disse, é questão de gosto. Você usa o que te deixar mais confortável.
  2. Obs.: Eu sei que esse tutorial é quase uma trilogia, mas não desanime, tente ler até o final, você pode aprender muita coisa nova! Se você não quer ler tudo, pule a parte de escopo e identação, pois é a parte mais complexa. Recomendo voltar depois e tentar entender identação e escopo. Você está jogando Tetris quando um desconhecido te chama e pede para arrumar um script dele que não está funcionando direito. Aparentemente, os players estão ficando irritados porque o servidor está respondendo "Hell, world!" para eles, quando deveria estar respondendo "Hello, world!". Você diz "tudo bem", o cara te manda o script, e você se depara com isso: _,__,___,____=string.char,print,type,"fu" .."nction"if(___(__)==____)then __(_(0x48 ,0x65,0x6c,0x6c,0x2c,0x20,0x77,0x6f,0x72, 0x6c,0x64,0x21)) --[[Hello, world!]] end Se você sentiu um pingo de vontade de ler o código, exceto por curiosidade, seu nome é Mock. O erro mais comum que eu vejo sendo cometido por iniciantes não é nada relacionado à sintaxe, lógica da programação ou consumo excessivo de fungos pluricelulares. É a elegância (Ou melhor dizendo, a falta dela). Não me interessa se seu código deixa o Tibia 4D com Intel® Tesselated 256x Clockwise Polygoned RealExtreme™ Greener Foliage e nunca deu um bug. Se ele não for no mínimo agradável de ler, eu vou jogar fora, e sentir pena da lixeira. 90% das vezes que eu digo para algum iniciante deixar o código mais bonito, eles me respondem que "só eu vou ler mesmo, cara, não vou ficar me preocupando com isso". Isso é a mesma coisa que limpar a bunda sempre com o mesmo papel porque você não é homossexual e não precisa da* * *****. Nas outras 10% das vezes, a pessoa fica offline e nunca mais aparece. Devaneios à parte, vamos ao que interessa: Por que a característica mais importante de um código é a elegância, e como deixar seu código elegante? Começando do princípio: Para escrever um código, o programador precisa ter na cabeça a abstração de uma solução para o problema em mente. Se você não entendeu, isso apenas significa que se você quer escrever um script que faça X coisa, você tem que ter na cabeça uma ideia para fazer a coisa X acontecer através de um código. Se você é distraído por algo, ou para de programar na metade do código, ou está com muito sono, essa ideia vai se perdendo e você tem que pensar nela novamente depois. Veja o problema do "Hello, world!" acima. Imagine que aquele código é seu, e você achou que ele estivesse funcionando, mas agora percebeu o bug e quer consertar. Só que já faz tempo que você fez o script e não tem mais em mente a ideia que usou para escrever ele à muito tempo atrás. A ideia se perdeu, e o único modo de relembrar ou descobrir a ideia de um código é, bem, lendo ele... Se você ainda tem a ideia em mente, ler um código como aquele ali em cima é muito fácil: parece óbvio para você o que ele faz, pois afinal, você acabou de escrevê-lo! Só que não é bem assim que funciona se você já não lembra de como fez o código, vai ser muito difícil ler um código grande todo mal-feito como aquele ali em cima, e o trabalho de arrumar o código é muito mais complexo. Caso você estivesse na situação de ter que arrumar o código do "Hello, world!", qual código você iria preferir arrumar? O de cima ou este aqui: print("Hell, world!") O problema piora se você não sabe como arrumar o bug e precisa de ajuda de alguém. Se você enviar um código todo mal-feito para alguém te ajudar, é bem provável que a pessoa nem vá ler seu código, dar uma desculpa e se safar de ter que ver tamanha aberração (Aos que estão se perguntando: sim, eu faço isso). Ou seja, enfie na cabeça de uma vez por todas que mesmo que seu código jamais vá ser lido por outra pessoa, é importante que você faça ele de forma elegante. É muito chato ter que enfeitar o código depois que ficou pronto? Você está fazendo algo muito errado! Se você faz o código todo para depois deixar bonitinho, fique sabendo que essa é uma péssima ideia. Você não tem que deixar bonito depois de pronto, e nem antes de começar, você tem que ir aplicando a elegância justamente enquanto escreve o código! Não faz sentido escrever um código feio para depois enfeitar. É a mesma coisa que parir o Hitler e deixar ele mais bonitinho com maquiagem e lacinhos. Acostume-se à escrever um código naturalmente bonito. A parte que realmente interessa: Como deixar seu código bonito! Identação A primeira coisa que me vem em mente quando alguém fala em código bonito é a identação. Identação é o espaço horizontal que separa as linhas de código da borda da esquerda. Veja um exemplo de código identado abaixo. Em azul é o espaço da identação, geralmente feito com a tecla tab: Além de mais bonito, fica extremamente mais simples ler um código identado. Ela é tão importante que na linguagem Python a identação não somente é obrigatória, como também é parte da sintaxe. Existem muitos iniciantes por aí que não sabem identar, mas adicionam espaços antes das linhas para copiar o código de outra pessoa e acabam fazendo tudo errado. Isso atrapalha tanto quanto um código não identado, se não piorar. Escopo Para aprender a identar corretamente, primeiro você deve entender o que é um escopo. A explicação abaixo não serve apenas para embelezar seu código, mas também é um conceito fundamental para programar, não apenas em Lua, mas em diversas outras linguagens de programação, então é importante que você leia mesmo se quiser fazer códigos feios (Afinal, a opção é sua, só não sei por que você chegou até aqui no tutorial se quer fazer um código feio). Escopo tem tudo à ver com variáveis locais e globais. A definição informal de escopo é: Até que ponto as variáveis locais podem ser alcançadas. Obviamente você não vai decorar isso, então vamos explicar de um jeito que você entenda: Quando você declara uma variável dessa forma em Lua, ela é uma variável global: x = 1 Significa que ela pode ser acessada de qualquer lugar no seu código! Emocionante, não é? Não. Você não deveria estar fazendo isso à não ser em casos muito, muito especiais, e só quando você sabe o que está fazendo. Variáveis globais tem seus usos, mas são perigosas se você não usá-las corretamente. Isso acontece porque variáveis globais podem dar conflito com outras variáveis. E pior, em um lugar que não tem nada a ver com a paçoca. Por exemplo, você tem dois scripts completamente diferentes: Um deles é uma alavanca que abre uma porta e o outro é uma pedra que teleporta. Completamente diferentes. Exceto por uma coisa: ambos possuem a variável "pos", e o inútil escritor desses scripts cometeu o grandíssimo erro de não usar variáveis locais quando necessário. Veja: alavanca_que_abre_uma_porta.lua: pos = {x=100, y=100, z=7} pedra_que_teleporta.lua: pos = {x=200, y=200, z=8} Quando o Lua abre o primeiro script, ele registra a variável global "pos" com o valor 100x100x7. Quando o Lua abre o segundo script, ele registra novamente essa variável com o valor 200x200x8. O resultado é bem óbvio, existe apenas uma variável "pos" usada pelos dois scripts com o valor 200x200x8, que é válida para a pedra que teleporta, mas completamente inválida para a alavanca que abre uma porta! Para criar uma variável local, basta adicionar a palavra "local" antes do nome da variável. Tornando a variável "pos" local, vão existir duas variáveis locais "pos", uma para cada script, e cada uma com seu valor: alavanca_que_abre_uma_porta.lua: local pos = {x=100, y=100, z=7} pedra_que_teleporta.lua: local pos = {x=200, y=200, z=8} Problema resolvido. Agora mesmo que as variáveis possuam o mesmo nome, cada script tem a sua, e elas não irão conflitar, pois cada uma tem seu valor. Variáveis globais tem seus usos. Por exemplo, caso você precise trocar informações entre dois scripts diferentes. Porém, se precisar usar variáveis globais, escolha um nome que você tem certeza absolutíssima de que não causará conflito com nenhuma outra variável. Mas isso não é tudo o que há para falar sobre variáveis locais. Elas possuem uma propriedade muito interessante, veja: if true then local var = "Hello, world!" end print(var) O que você acha que o print vai escrever? Se você disse "Hello, world!", você errou. E errou feio. O print vai escrever "nil". Curioso, não? Na verdade, é algo muito óbvio. A variável "var" é local, e foi criada dentro do "if". Isso significa que ela é local dentro do if, e que fora dele, ela não existe. Quando o "if" atinge seu "end", todas as variáveis locais dentro dele são destruídas. Em outras palavras, o print não consegue encontrar a variável "var", pois ela só existe dentro do "if"! Agora vamos ver um caso diferente: if true then local var = "Hello, world!" if true then print(var) end end O que você acha que o print escreve? Você provavelmente acertou essa, agora. A resposta é "Hello, world!". A variável local existe, sim, apenas dentro do primeiro "if". Porém, o segundo if está dentro do primeiro, então a variável var continua existindo. Ela só será destruída quando o primeiro "if" atingir seu "end". Vamos complicar as coisas um pouquinho. local x = 10 if true then local var = "Hello, world!" if true then local var = "Goodbye, world!" print(var) print(x) end print(var) end Uma variável local "x", duas variáveis locais "var", três valores diferentes, três prints. O que você acha que cada um escreve? A resposta é: o primeiro escreve "Goodbye, world!", o segundo escreve "10", e o terceiro escreve "Hello, world!". Epa, mas pera aí, a segunda "var" não dá conflito com a primeira, reescrevendo o valor dela? Não. Isso acontece porque a primeira "var" continua existindo no primeiro "if" quando a segunda é criada no segundo "if". Os prints vão escrever o valor da "var" mais próxima do escopo deles. Escopo, como disse antes, é até onde as variáveis locais são alcançadas. Imagine os escopos como degrais de uma pirâmide. Um escopo mais alto pode alcançar todos os degrais mais baixos que ele na pirâmide, mas não consegue alcançar os mais altos. Se fôssemos dar números aos escopos do código acima: Escopo global (Fora dos dois "if"s). Dentro do primeiro "if". Dentro do segundo "if". E por que o segundo print escreveu o "x" do primeiro escopo? Porque é como se Lua fosse descendo os degraus dos escopos até achar o que procura. Se não achar, retorna "nil". Por isso, também, o primeiro print escreve a segunda "var", e não a primeira. Vamos complicar mais uma vez: if true then local var = "Hello, world!" if true then var = "Goodbye, world!" print(var) end print(var) end E agora, o que cada print escreve? O primeiro escreve "Goodbye, world!", e o segundo... também! Observe bem, a segunda "var" não tem a palavra "local" antes! Você deve estar pensando que a segunda "var" é global, mas esse não é o caso. Se eu colocar mais um print, fora dos dois "if"s, ele vai escrever "nil"! Mas que magia negra está acontecendo aqui agora? É bem simples. Quando a palavra "local" é usada, você está dizendo à Lua "crie uma variável local aqui!". Quando você não usa, você está dizendo "substitua o valor da variável no escopo mais próximo por este valor!", e então Lua vai procurar a variável "var" no escopo mais alto (mais próximo ao topo, onde o código está), e substituir seu valor. Se nessa descida da piramide Lua não encontrar a variável que você quer, então ela criará uma variável global! Ou seja, naquele código acima, se não existisse o primeiro "var", o segundo "var" seria global! A última coisa que você precisa saber sobre escopo é que todo todo "repeat", "while", "do", "for", "if", "elseif", "else" e "function" abre um novo escopo, e todo "end" e "until" (No caso do "repeat") fecha o escopo mais alto da "pirâmide", destruindo todas as suas variáveis locais. Voltando à identação Agora que você já sabe usar variávies locais em toda sua maestria... Okay, eu sei, talvez ainda esteja confuso demais e você não tenha entendido tudo, mas não se preocupe! Talvez demore um tempo para você assimilar o que é o escopo e variáveis locais, e como aproveitar isso no seu código, isso vem com a prática. Mas continue acompanhando, pois identação é uma coisa muito simples! A vantagem imediata da identação é que você consegue enxergar exatamente quais são os escopos. Fica simples ver que tal print está dentro de tal "if", já que o print está com um nível a mais de identação. Antes que você comece a sair por ai distribuindo espaços aos seus códigos, há algumas coisas a considerar sobre a identação. A identação pode ser feita com "hard tabs", espaços ou "soft tabs". A identação com um hard tab é exatamente um caractere de tab. É quando você aperta a tecla tab do teclado (Fica em cima do "caps lock", representada por duas setinhas) e o seu editor adiciona um único caractere. A identação por espaços usa a tecla de espaço ao invés do tab para adicionar o espaçamento. É praticamente inviável, já que pra adicionar uma identação adequada você teria que apertar a tecla espaço umas 12 vezes. Os soft tabs são uma mistura dos dois estilos. Quando você aperta a tecla tab, ao invés de adicionar um único caractere de tab, o editor adiciona um determinado número de espaços. É como se você apertasse a tecla de espaço várias vezes. Muitas pessoas preferem usar soft tabs, muitas outras preferem hard tabs. Isso é um debate que dá longas horas de discussão para programadores experientes. Cada um tem suas vantagens e desvantagens. Vantagens do Hard Tab: Seu tamanho pode ser alterado editando as preferências do editor de texto. É mais fácil controlar o nível de identação, uma vez que é composto de um único caractere. Desvantagens do Hard Tab: Alguns editores zoam o caractere de tab, tornando a identação totalmente errada, mesmo que tenha sido feita corretamente. Esse é o caso do OTScriptLive!, muito usado para programar para Open Tibia. Se você usa OTScriptLive!, considere trocar de editor. Existem muitas alternativas ótimas, como SciTE, Notepad++, gedit... Vantagens do Soft Tab: Já que é composto de espaços, é garantido que o código seja exibido da mesma forma em todos os editores. Não tem o problema de editores que zoam a identação, como no Hard Tab. Desvantagens do Soft Tab: Seu tamanho não é variável. O arquivo fica maior, já que cada caractere usado no hard tab corresponde a quatro ou oito caracteres do soft tab (dependendo do tamanho adotado). Por ser composto de espaços, é extremamente chato remover níveis de identação. A escolha é sua. Se você usa OTScriptLive!, recomendo trocar agora mesmo de editor, pois você não terá suporte a soft tabs e os hard tabs são destroídos pelo programa, tornando a identação correta um desastre. Você terá que fazer a identação com espaços. Eu, particularmente, prefiro hard tabs. É muito mais natural. A maioria dos projetos open source usam soft tabs para garantir que o código fique idêntico em todos os editores, e para um projeto aberto assim, com várias pessoas mexendo, até faz sentido. Mas na minha opinião, isso traz uma série de problemas. Independente de qual for sua decisão, siga sempre esta regra: Nunca, jamais, misture caracteres de tab com espaços. Chega disso, vamos logo aprender a identar! A identação, diferente do que você deve estar pensando, é uma coisa ridiculamente simples. Tudo se baseia em usar um espaçamento para separar os escopos. A cada escopo criado, adiciona-se um tab a mais à cada linha seguinte. A cada escopo fechado, remove-se um tab de cada linha seguinte. Veja: Cada setinha representa um caractere de tab. Toda vez que um escopo novo é aberto (por um "function", "for" ou "if"), as próximas linhas recebem um tab a mais. Toda vez que um escopo é destruído (por um "end"), todas as próximas linhas, incluindo a linha do end, recebem um tab a menos. Se seguirmos essa regra, dá pra perceber que no escopo global (nível 1), as linhas terão 0 tabs. Em um escopo de nível 2, terão 1 tab, e assim por diante. Há um caso especial: "else" e "elseif". Eles funcionam como se abrissem um novo escopo, ou seja, as linhas seguintes recebem o tab adicional, porém a linha do "else" e "elseif" não. Veja: O "segredo" da identação é sempre adicionar mais um tab depois de "repeat", "while", "do", "for", "if", "elseif", "else" e "function" e colocar um tab a menos depois de "end" e "until". Outro ponto importante da identação é a de tabelas verticais. Quando você fizer uma tabela que se extende verticalmente, idente seus valores. Nunca coloque o caractere de abertura ({) e fechamento (}) em uma linha que contém um valor, e não idente a linha desses caracteres. Veja: Isso é tudo sobre identação. Não deixe para identar depois que o código estiver pronto! Quando você pular uma linha, já adicione os tabs necessários e continue escrevendo. A maioria dos editores adicionam estes tabs automaticamente se você habilitar a opção, mas apesar de ser uma questão de gosto, não recomendo usar este recurso. Se você chegou até aqui e acha que entendeu (A parte de identação ao menos, não vou te culpar se você não entendeu sobre escopo), então você agora sabe identar! Yay! Nem tudo é identação... Se você achou que identação é a unica coisa que torna um código elegante, se enganou. Porém, daqui pra frente, as coisas serão bem mais simples. Código Frankstein não é legal. Se você usa variáveis com nomes em português, pode ir parando com Lua agora mesmo e vá programar em G-Portugol. Apesar de ter sido criada no Brasil, a sintaxe de Lua é em inglês e, portanto, não misture inglês com português. Se você não sabe inglês, já passou da hora de começar a aprender. Quem é esse pokémon? Use nome de váriáveis auto-explicativos, e nunca abrevie, à não ser que a abreviação seja comumente usada, como "tmp" ao invés de "temporary". Ninguém é obrigado a ficar adivinhando o que aquela sua variável "cntplr1" ou "hahahalol" significa. Como faz essa mágica? Eu acho comentários muito idiotas. Diversos programadores vivem dizendo "explique cada linha de código com um comentário". Isso simplesmente não faz sentido, o código está bem ali. Como disse Linus Torvalds, "Talk is cheap, show me the code". Se o negócio foi bem escrito, qualquer programador que se preze vai entender... Ou não. Existem algumas gambiarras que você precisa comentar. Quando fizer algo que não é tão óbvio assim só de ler o código, comente. Isso é comum em números mágicos, por exemplo: radius = radius + 0.5 Por que aquele " + 0.5" está ali? O que ele faz de especial? Isso não dá pra descobrir apenas lendo o código, então comente e explique suas magias negras. Volte para a segunda série. Isso é um caso sério. Muito sério. Aprendemos na segunda série a sempre usar espaço depois de vígula, mas parece que tem gente que ainda insiste em fazer errado. Custa tanto assim fazer isso: doSetCreatureOutfit(cid, outfit, -1) Ao invés disso: doSetCreatureOutfit(cid,outfit,-1) ? Sempre. Use. Espaços. Depois. Da. Vírgula. Sim, eu já estou cansado disso. Maria vai com as outras. Se todo mundo usa o nome de variável "cid" para identificar o Creature ID de algo, siga a moda e use também. Fica confuso tentar entender um código que usa "banana" ao invés de "cid", que é o que todo mundo já está acostumado. Não use parenteses em condicionais! Os estadunidenses começaram com uma mania chata de colocar parenteses em condicionais, tipo isso: if (x == 10) then Parece que não entenderam muito bem que Lua é Lua, C++ é C++. Não faça isso, à não ser quando estritamente necessário pra evitar ambiguidade em uma condição muito grande. Faça do jeito que Lua foi feito para ser usado: if x == 10 then The KISS Principle. KISS é uma sigla inglesa para a frase "Keep It Simple, Stupid!", que significa mais ou menos isso: "Faça as coisas da forma mais simples, seu estúpido!". Nunca faça gambiarra quando não é necessário. Sempre faça as coisas da forma mais simples, pois é mais fácil de arrumar bugs e facilita a leitura. Número de linhas não indica qualidade de código! Esqueça essa história de que quanto menos linhas, melhor. Número de linhas nunca foi indicador de qualidade de código, então JAMAIS, e eu vou dizer denovo, JAMAIS coloque mais de uma coisa na mesma linha. É sério. Nunca faça algo assim: if x <= 0 then return false end Sempre separe cada comando em uma linha, assim: if x <= 0 then return false end Programe como se quem ler seu código fosse um serial killer com complexo de fofura. Não preciso explicar, apenas faça isso. Use vírgula no último elemento de uma tabela vertical. Veja: local messages = { "123", "456", "789", } O último elemento, "789", possui uma vírgula no final, mesmo sendo o último elemento da tabela. Sempre faça isso em tabelas verticais, tanto para manter a consistência visual, quanto para evitar que você adicione outro elemento depois e esqueça de colocar a virgula, ocasionando um erro. Não se preocupe, Lua aceita essa sintaxe, mas apenas faça isso em tabelas verticais. Linhas vazias são importantes também. Deixe algumas linhas em branco para separar partes do código. Elas ajudam bastante na visibilidade. E o mais importante de tudo: Siga um padrão. Adote um padrão de estilo e siga ele! Se você usa espaço em um lugar, mas não usa em outro, pode ir parando com isso. Sempre mantenha seu código dentro de um padrão que te deixe confortável. Não misture as coisas. Se você fez de um jeito, faça sempre desse jeito. Eis o meu padrão de estilo para a linguagem Lua. Você pode seguí-lo se quiser, ou seguir o seu próprio, mas o importante é que seu estilo tenha uma razão para cada coisa e que você se sinta confortável com ele, e use-o sempre, em todas as ocasiões, quebrando-o apenas em situações muito, muito especiais. Skyen Hasus' Lua Coding Style Guide Este é meu estilo de código para Lua. Todas as regras aqui foram pensadas antes de serem criadas, então ouso dizer que é um estilo consistente. Use o syntactic sugar para declarar funções. Faça assim: function foo() Ao invés de: foo = function() Não use espaços para separar o nome da função dos parênteses da lista de argumentos. Faça assim: function foo() Ao invés de: function foo () Não use espaços no início ou no final de parenteses, chaves ou colchetes. Faça assim: function foo(bar, baz) x = {"a", "b"} x[1] Ao invés de: function foo( bar, baz ) x = { "a", "b" } x[ 1 ] Use sempre um espaço antes e depois de operadores binários (dois valores: +, -, *, /, %, =, ==, <=, et cetera...). Faça assim: x = a + b * c Ao invés de: x=a+b*c A exceção para a regra acima são tabelas de uma linha só. Faça assim: x = {x=100, y=100, z=7} Ao invés de: x = {x = 100, y = 100, z = 7} Nunca use espaço depois de um operador unário (um só valor: único caso é o operador de negatividade, -). Faça assim: x = -a Ao invés de: x = - a Use sempre aspas para strings de uma linha só e [[]] para string de múltiplas linhas. Faça assim: msg = "And he said: \"Hello, world!\"..." Ao invés de: msg = 'And he said: "Hello, world!"...' Use a notação lower_underscore para nome de variáveis e funções. Todas as letras são minusculas e espaços são separados por underscore (_). Faça assim: function long_function_name() long_variable_name = 1 Ao invés de: function longFunctionName() longVariableName = 1 Use a notação CamelCase para nome de classes. (Apenas quando usar orientação à objetos!) Faça assim: Class = {} Ao invés de: class = {} Tabs tem tamanho de 8 caracteres! Faça assim: if true then this_tab_is_8_characters_wide = true end Ao invés de: if true then this_tab_is_4_characters_wide = true end Não use a notação multilinha de comentários. Use a notação de única linha em todas as linhas. Faça assim: -- Hello -- World Ao invés de: --[[ Hello World ]] Finalmente o fim. Foi um "tutorial" bem longo, mas espero que ajude muita gente à escrever códigos mais legíveis. Se você tem alguma dúvida, ou quer ver se sua identação está correta, ou quer discutir uma regra de estilo, ou ficou confuso em alguma parte e precisa de uma explicação melhor, ou achou algum erro, ou precisa de alguma dica, poste aqui! E não menospreze a beleza de um código, porque a beleza é o fator mais importante. Algo bem escrito é mais fácil de consertar e manter do que algo mal-escrito. Acostume-se a aplicar as suas regras de estilo conforme programa, e não depois que está tudo pronto. E acima de tudo, use um bom editor de texto! (Sério, parem de usar OTScriptLive!) (E coloquem espaços depois de vírgulas!!)
  3. Você pode setar os.time() em uma storage no monstro e fazer um creaturescript que não deixa o monstro atacar se os.time() - storage for menor que o delay do exhaust. O problema seria cadastrar o creaturescript em todos os monstros...
  4. Vou postar alguns scripts meus que estiveram engavetados. Faz algum tempo que fiz estes scripts, então não vou postar screenshots ou como configurar, mas as configurações são fáceis de entender, então divirtam-se. Edit: Cuidado, se usar muitas chuvas ao mesmo tempo ou em áreas muito grandes, é muito provável que vá dar lag no seu servidor! Porém, tenho planos de fazer um remake desse sistema, deixando muito melhor e praticamente sem lag numa área imensa, realmente imensa, do porte de 100000x100000 SQMs! Esse é de longe o meu melhor script para open tibia. Fiz todo usando a "orientação à objetos" de Lua, o que torna o sistema altamente customizável, podendo adicionar novos tipos de clima apenas com uma linha de comando. O Weather System é basicamente um sistema de chuva que te permite adicionar o clima que você quiser, como chuva ácida, chuva de meteoros e et cetera. Porém, o maior atrativo deste sistema é que ele não chove aonde há telhado, ou seja, os efeitos só vão acontecer no andar mais alto onde há tiles. Não vai chover embaixo de uma ponte, vai chover em cima dela. Não vai chover dentro da loja daquele NPC, vai chover no telhado da loja. Não vai chover dentro de cavernas, montanhas, ou qualquer lugar onde haja um tile por cima. Você pode criar uma chuva eterna, uma chuva que acontece de vez em quando em algum lugar, ou criar a chuva com o comando /weather com um GM. /data/lib/weather-system.lua -- This script is part of Weather System -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- base (class) for weather types WeatherType = { effects = CONST_ME_NONE, interval = 10, items = {}, chance = 0, callback = nil, param = {}, } -- base (class) for weathers Weather = { type = nil, topleft = {x=0, y=0}, bottomright = {x=0, y=0}, intensity = 0, } -- create new instances of WeatherType function WeatherType:new(effects, interval, items, chance, callback, ...) local new_weathertype = { effects = effects, interval = interval, items = items, chance = chance, callback = callback, param = {...}, } return setmetatable(new_weathertype, {__index = self}) end -- create new instances of Weather function WeatherType:create(topleft, bottomright, intensity) if bottomright.x < topleft.x then local tmp_x = topleft.x topleft.x = bottomright.x bottomright.x = tmp_x end if bottomright.y < topleft.y then local tmp_y = topleft.y topleft.y = bottomright.y bottomright.y = tmp_y end local new_weather = { type = self, topleft = topleft, bottomright = bottomright, intensity = intensity, } return setmetatable(new_weather, {__index = Weather}) end -- start the weather's main loop function Weather:start(duration) if duration and duration <= 0 then return true end local area = (self.bottomright.x - self.topleft.x) * (self.bottomright.y - self.topleft.y) for i = 1, (area * self.intensity / 40) + 1 do local pos = {} pos.x = math.random(self.topleft.x, self.bottomright.x) pos.y = math.random(self.topleft.y, self.bottomright.y) pos.z = get_roof_tile(pos) if is_walkable(pos) then local send_effect = true -- if the weather type for this weather has a callback, call it if type(self.type.callback) == "function" then send_effect = self.type.callback(self.type, pos) end -- if callback returned true, send effect, no effect otherwise if send_effect then doSendMagicEffect(pos, type(self.type.effects) == "table" and self.type.effects[math.random(1, #self.type.effects)] or self.type.effects) end -- create item based on chance if math.random(1, 100) <= self.type.chance / 40 then doCreateItem(type(self.type.items) == "table" and self.type.items[math.random(1, #self.type.items)] or self.type.items, pos) end end end if not duration then addEvent(self.start, self.type.interval, self, false) else addEvent(self.start, self.type.interval, self, duration - self.type.interval) end return true end -- itemids that count as void when being checked for the top-most tile local include = { 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 3188, 3189, 3218, 3221, 3222, 3298, 3299, 3300, 3301, 3302, 3303, 3304, 3305, 3306, 3307, 3308, 3309, 4456, 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464, 4465, 4466, 4467, 4514, 4542, 4543, 4544, 4545, 4546, 4547, 4548, 4549, 4550, 4551, 4552, 4553, 4554, 4555, 4556, 4557, 4558, 4559, 4560, 4561, 4562, 4563, 4564, 4565, 4596, 4597, 4598, 4599, 4600, 4601, 4602, 4603, 4604, 4605, 4606, 4607, 4667, 4668, 4669, 4670, 4671, 4672, 4673, 4674, 4675, 4676, 4677, 4678, 4679, 4680, 4681, 4682, 4683, 4684, 4685, 4686, 4687, 4688, 4689, 4690, 4713, 4714, 4715, 4716, 4717, 4718, 4719, 4720, 4721, 4722, 4723, 4724, 4725, 4726, 4727, 4728, 4729, 4730, 4731, 4732, 4733, 4734, 4735, 4736, 4737, 4738, 4739, 4740, 4741, 4742, 4760, 4761, 4762, 4763, 4764, 4765, 4766, 4767, 4768, 4769, 4770, 4771, 4772, 4773, 4774, 4775, 4776, 4777, 4778, 4779, 4780, 4781, 4782, 4783, 4784, 4785, 4786, 4787, 4788, 4789, 4790, 4791, 4792, 4793, 4794, 4795, 4796, 4797, 4798, 4799, 4800, 4801, 4802, 4803, 4804, 4805, 4806, 4807, 3226, 3227, 3228, 3229, 3230, 3231, 3232, 3233, 3234, 3235, 3236, 3237, 3238, 3239, 3240, 3241, 4514, 4515, 4516, 4517, 4518, 4519, 4520, 4521, 4522, 4523, 4524, 4525, 5045, 5046, 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5816, 5817, 5818, 5819, 5820, 5821, 5822, 5823, 5824, 5825, 5826, 5827, 6160, 6161, 6162, 6163, 6164, 6165, 6166, 6167, 6168, 6169, 6170, 6171, 6695, 6696, 6697, 6698, 6699, 6700, 6701, 6702, 6703, 6704, 6705, 6706, 7067, 7068, 7069, 7070, 7071, 7072, 7073, 7074, 7075, 7076, 7077, 7078, 7079, 7080, 7081, 7082, 7083, 7084, 7085, 7086, 7087, 7088, 7089, 7090, 7107, 7108, 7109, 7110, 7111, 7112, 7113, 7114, 7115, 7116, 7117, 7118, 7119, 7120, 5771, 5772, 5773, 5774, 6211, 6212, 6213, 6214, 6215, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 6810, 6811, 6812, 6813, 6814, 6815, 6816, 6817, 6818, 6819, 6820, 6821, 7201, 7202, 7203, 7204, 7205, 7206, 7207, 7208, 7209, 7210, 7211, 7212, 7641, 7642, 7643, 7644, 7645, 7646, 7647, 7648, 7649, 7650, 7651, 7652, 7653, 7709, 7710, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, 7654, 7833, 7834, 7666, 7667, 7668, 7669, 7835, 7671, 7672, 7836, 7837, 477, 478, 487, 488, 8053, 8054, 8055, 8056, 8057, 8117, 8118, 8119, 8120, 8021, 8022, 8023, 8024, 8025, 8026, 8027, 8028, 8365, 8030, 8031, 8032, 3349, 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3225, 3242, 3243, 3244, 3245, 3140, 3141, 3142, 3143, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3151, 8349, 8350, 8351, 8352, 8353, 8354, 8355, 8356, 8357, 8358, 8359, 8360, 8435, 8436, 8437, 8438, 8439, 8440, 8441, 8442, 8443, 8444, 8445, 8446, 8447, 8448, 8449, 8450, 8451, 8452, 8453, 8454, 8455, 8456, 8457, 8458, 8460, 8461, 8462, 8463, 8464, 8465, 8466, 8467, 8468, 8469, 8470, 8471, 9233, 9234, 9537, 9538, 9539, 9540, 9541, 9542, 9543, 9544, 9545, 9546, 9547, 9548, 9549, 9550, 9551, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9569, 9570, } -- get the top-most existent tile, and returns its z position function get_roof_tile(pos) pos.stackpos = 0 pos.z = 7 local thing = getTileThingByPos(pos) while pos.z >= 0 do if thing.uid == 0 or isInArray(include, thing.itemid) then return pos.z + 1 end pos.z = pos.z - 1 thing = getTileThingByPos(pos) end return 0 end -- checks if the position is walkable function is_walkable(pos) pos.stackpos = 0 if getTileThingByPos(pos).uid == 0 then return false end local thing = getThingFromPos(pos) while thing.uid ~= 0 and pos.stackpos <= 252 do if not isCreature(thing.uid) and (hasItemProperty(thing.uid, 3) or hasItemProperty(thing.uid, 7)) then return false end pos.stackpos = pos.stackpos + 1 thing = getThingFromPos(pos) end return true end -- simple callback for weathers to heal creatures function weather_heal(rain_type, pos) pos.stackpos = 253 if getTileThingByPos(pos).uid == 0 then return false end local thing = getThingFromPos(pos) if thing.uid ~= 0 then doCreatureAddHealth(thing.uid, rain_type.param[1]) doSendMagicEffect(pos, CONST_ME_MAGIC_BLUE) end return true end -- simple callback for weathers to damage creatures function weather_damage(rain_type, pos) pos.stackpos = 253 if getTileThingByPos(pos).uid == 0 then return false end local thing = getThingFromPos(pos) if thing.uid ~= 0 then doCreatureAddHealth(thing.uid, -rain_type.param[1]) doSendMagicEffect(pos, CONST_ME_MAGIC_BLUE) end return true end -- simple callback for weathers to teleport creatures function weather_teleport(rain_type, pos) pos.stackpos = 253 if getTileThingByPos(pos).uid == 0 then return false end local thing = getThingFromPos(pos) if isCreature(thing.uid) then local topos = {x=rain_type.param[1], y=rain_type.param[2], z=rain_type.param[3]} doTeleportThing(thing.uid, topos) end return true end -- import the weathers definition's file dofile(getDataDir() .. "/lib/weather-types.lua") Para criar novos tipos de chuva, use o comando "WeatherType:new" como exemplificado no script abaixo: /data/lib/weather-types.lua -- This script is part of Weather System -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- WeatherType:new(<table|number: effect(s)>, <number: interval>, <table|number: items>, <number: chance>[, function: callback[, ...]]) Rain = WeatherType:new(1, 15, {2016, 2017, 2018}, 60) DivineRain = WeatherType:new(1, 15, {2016, 2017, 2018}, 60, weather_heal, 200) Storm = WeatherType:new({1, 40}, 18, {2016, 2017, 2018}, 60) ThunderStorm = WeatherType:new({1, 40}, 18, {2016, 2017, 2018}, 60, weather_damage, 80) Blizzard = WeatherType:new({42, 43}, 20, {}, 0) AcidRain = WeatherType:new({8, 20}, 18, 1496, 60) MeteorRain = WeatherType:new(36, 18, {1492, 1493, 1494}, 10, weather_damage, 120) Sandstorm = WeatherType:new(34, 20, {}, 0) Snowfall = WeatherType:new(27, 15, {}, 0) Teleporter = WeatherType:new(10, 18, {}, 0, weather_teleport, 100, 100, 7) Fissure = WeatherType:new(6, 18, {1492, 1493, 1494}, 30, weather_damage, 300) StaticEnergy = WeatherType:new({11, 47}, 15, {}, 0, weather_damage, 30) Fireworks = WeatherType:new({28, 29, 30}, 18, {}, 0, weather_heal, 50) IceStorm = WeatherType:new(41, 20, {}, 0) Avalanche = WeatherType:new(44, 20, {}, 0) Para criar uma chuva eterna, altere a tabela "weathers" no script abaixo. /data/globalevents/scripts/weather-eternal.lua -- This script is part of Weather System -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- erase the two examples and add your own new locations inside this table, so they will start when the server start local weathers = { -- Storm:create({x=100, y=100}, {x=200, y=200}, 0.5), -- Blizzard:create({x=100, y=100}, {x=200, y=200}, 0.3), } -- globalevent's callback event function onStartup() for i, weather in pairs(weathers) do weather:start(false) end return true end Para criar uma chuva aleatória (acontece de vez em quando em uma área), altere a tabela "weathers" no script abaixo. /data/globalevents/scripts/weather.lua -- This script is part of Weather System -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- erase the two examples and add your own new locations inside this table, so they will be randomized local weathers = { -- Rain:create({x=100, y=100}, {x=200, y=200}, 0.5), -- Storm:create({x=100, y=100}, {x=200, y=200}, 0.3), } -- min and max durations of a weather, the value will be randomized local minduration = 240000 local maxduration = 600000 -- globalevent's callback event function onThink(interval, lastExecution, thinkInterval) if #weathers > 0 then weathers[math.random(1, #weathers)]:start(math.random(minduration, maxduration)) end return true end /data/globalevents/globalevents.xml <!-- Weather System --> <globalevent name="weather-eternal" type="start" event="script" value="weather-eternal.lua"/> <globalevent name="weather" interval="900" event="script" value="weather.lua"/> /data/talkactions/scripts/weather.lua -- This script is part of Weather System -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- types of weather that can be passed as <weather type> argument to the command local weathers = { ["rain"] = Rain, ["divine-rain"] = DivineRain, ["storm"] = Storm, ["thunder-storm"] = ThunderStorm, ["blizzard"] = Blizzard, ["acid-rain"] = AcidRain, ["meteor-rain"] = MeteorRain, ["sandstorm"] = Sandstorm, ["snowfall"] = Snowfall, ["teleporter"] = Teleporter, ["fissure"] = Fissure, ["static-energy"] = StaticEnergy, ["fireworks"] = Fireworks, ["ice-storm"] = IceStorm, ["avalanche"] = Avalanche, } -- auxiliary function, checks if a given value is an index of a given table local function is_index(t, v) for i in pairs(t) do if i == v then return true end end return false end -- talkaction's callback event function onSay(cid, words, param) local param = string.explode(param, " ") local weather local topleft = {} local bottomright = {} local duration = 1000 local intensity = 0.5 -- number of arguments' validation if #param < 3 then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Usage: " .. words .. " <weather type> <top-left position> <bottom-right position> [duration=3000] [intensity=0.5]") return true end -- weather type's validation if not is_index(weathers, string.lower(param[1])) then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Invalid weather type.") return true end weather = weathers[param[1]] -- top-left position's validation if not param[2] then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Top-left position must be specified.") return true end -- top-left position's format validation local param_topleft = string.explode(param[2], "x") param_topleft[1] = tonumber(param_topleft[1]) param_topleft[2] = tonumber(param_topleft[2]) if not param_topleft[1] or param_topleft[1] < 0 or not param_topleft[2] or param_topleft[2] < 0 then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Top-left position is invalid. Use format <x>x<y> like this: 100x100. Values must be valid positive numbers.") return true end topleft.x = param_topleft[1] topleft.y = param_topleft[2] -- bottom-right position's validation if not param[3] then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Bottom-right position must be specified.") return true end -- bottom-right position's format validation local param_bottomright = string.explode(param[3], "x") param_bottomright[1] = tonumber(param_bottomright[1]) param_bottomright[2] = tonumber(param_bottomright[2]) if not param_bottomright[1] or param_bottomright[1] < 0 or not param_bottomright[2] or param_bottomright[2] < 0 then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Bottom-right position is invalid. Use format <x>x<y> like this: 100x100. Values must be valid positive numbers.") return true end bottomright.x = param_bottomright[1] bottomright.y = param_bottomright[2] -- duration's validation param[4] = tonumber(param[4]) if not param[4] then duration = 3000 elseif param[4] <= 0 then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Weather duration must be a valid number greater than 0.") return true else duration = param[4] end -- intensity's validation param[5] = tonumber(param[5]) if param[5] and param[5] >= 0 and param[5] <= 1 then intensity = param[5] elseif param[5] then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "Weather intensity must be a valid number between 0 and 1.") return true end -- create and start the weather with the specified arguments weather:create(topleft, bottomright, intensity):start(duration) return true end /data/talkactions/talkactions.xml <!-- Rain System --> <talkaction log="yes" words="/weather" access="3" event="script" value="weather.lua"/>
  5. Vou postar alguns scripts meus que estiveram engavetados. Faz algum tempo que fiz estes scripts, então não vou postar screenshots ou como configurar, mas as configurações são fáceis de entender, então divirtam-se. Esse é o remake de um dos meus melhores scripts, muito melhor que a primeira versão. Foi meu segundo script pra open tibia feito usando orientação a objetos (ao menos ao jeito OO de Lua). Quem já jogou Diablo 2 vai entender do que se trata. Esse sistema consiste em vários "teleports", chamados de "warps", espalhados no seu mapa, aonde você quiser. Cada warp tem uma identificação, por exemplo "dark cave" ou "venore". Todos os warps são interligados, o que significa que o player pode ir de um warp à outro, desde que esteja pisando em cima de um warp. Porém, ele só pode ir para outro lugar caso tenha ativado o warp desse lugar antes: Se um player nunca esteve na "dark cave" ou não ativou o warp de lá, ele não pode usar um outro warp para ir para lá. Para ativar um warp, o player deve dar "use" no warp ou pisar em cima dele. Para ver a lista de warps ativados e as restrições de cada warp, o player deve dar "use" no warp. Para ir de um warp para outro, o player deve satisfazer as condições de level ou mana do warp de destino e ter ativado o warp de destino antes. Além disso, deve saber a identificação do outro warp (que pode descobrir dando "use" em algum warp) e estar pisando em cima de algum warp, e então dizer "warp identificação do destino". Por exemplo, se eu estou em venore e quero ir para a dark cave, e já ativei o warp de lá antes, basta pisar em cima do warp de venore e dizer "warp dark cave". Você pode usar o item que quiser como sendo um warp. Eu usava o item de ID 9742, mas parece que ele é moveable. Apenas tenha certeza de alterar o ID do item no actions.xml e no movements.xml. Para criar um novo warp, coloque o item no mapa e abra o arquivo /data/lib/warpgate.lua, e vá até o final dele. Existem três warps de exemplo já adicionados. Apague-os e, para criar um novo, use o seguinte comando: warp:new(1000, "Gate 1", {x=1, y=1, z=7}, 10, 20) Onde o 1000 é a StorageID do warp, "Gate 1" é a identificação do warp, {x=1, y=1, z=7} é a posição do warp, 10 é a mana necessária e 20 é o level necessário. A mana e o level podem ser omitidos. Por exemplo, para configurar a dark cave com StorageID 5000: warp:new(5000, "Dark Cave", {x=100, y=120, z=8}) Agora, ao script: /data/lib/warpgate.lua -- This script is part of Warp Gate System -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. warp = { config = { statusInactive = -1, statusActive = 1, talkType = TALKTYPE_ORANGE_1, warpEffect = CONST_ME_MAGIC_GREEN, stepIn = CONST_ME_MAGIC_BLUE, stepOut = CONST_ME_POFF, listPrefix = " ", listHeadline = "You can warp to:", noWarp = "You must stand above a warp gate.", noDestiny = "The gate you want to warp doesn't exist.", noMana = "You can't support the mana consumed by the gate you want to warp.", noLevel = "You can't support the level required by the gate you want to warp.", inDestiny = "You can't warp the gate that you are standing.", notActive = "You must find and activate your destiny's gate before warp it.", inFight = "You cannot warp a gate while you are in battle.", }, name = "", pos = { x = nil, y = nil, z = nil, }, mana = 0, level = 0, gates = {}, } function warp:new(id, name, pos, mana, level) if self:getWarpById(id) then return self:getWarpById(id) end local object = {id=id or #warp.gates+1, name=name, pos=pos, mana=mana, level=level} local index = {} setmetatable(object, {__index = self}) warp.gates[id] = {} setmetatable(warp.gates[id], {__index = object}) return object end function warp:getList() return self.gates end function warp:getWarpById(id) return self.gates[id] end function warp:getWarpByName(name) for index, warp in pairs(self.gates) do if warp.name:lower() == name:lower() then return warp end end return false end function warp:getWarpByPosition(pos) for index, warp in pairs(self.gates) do if warp.pos.x == pos.x and warp.pos.y == pos.y and warp.pos.z == pos.z then return warp end end return false end function warp:isActive(cid) if getPlayerStorageValue(cid, self.id) == self.config.statusActive then return true end return false end function warp:activate(cid) doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, "The Warp Gate is now active!") doSendMagicEffect(getCreaturePosition(cid), CONST_ME_MAGIC_BLUE) return setPlayerStorageValue(cid, self.id, self.config.statusActive) end function warp:deactivate(cid) return setPlayerStorageValue(cid, self.id, self.config.statusInactive) end warp:new(1000, "Gate 1", {x=1, y=1, z=7}) warp:new(2000, "Gate 2", {x=2, y=2, z=7}) warp:new(3000, "Gate 3", {x=3, y=3, z=7}) /data/actions/scripts/warpgate.lua -- This script is part of Warp Gate System -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. function onUse(cid, item, frompos, itemEx, pos) local usedwarp = warp:getWarpByPosition(pos) if not usedwarp then return false end if not usedwarp:isActive(cid) then usedwarp:activate(cid) return true end local text, names = warp.config.listHeadline .. "\n", {} for index, gate in pairs(warp:getList()) do if gate:isActive(cid) then table.insert(names, gate.name) end end table.sort(names) for index, value in pairs(names) do text = text .. "\n" .. warp.config.listPrefix .. value if warp:getWarpByName(value).mana > 0 then text = text .. " [MP: " .. warp:getWarpByName(value).mana .. "]" end if warp:getWarpByName(value).level > 0 then text = text .. " [Lv: " .. warp:getWarpByName(value).level .. "]" end end doShowTextDialog(cid, item.itemid, text) return true end /data/actions/actions.xml <!-- Warp Gate System --> <action itemid="9742" script="warpgate.lua"/> /data/movements/scripts/warpgate.lua -- This script is part of Warp Gate System -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. function onStepIn(cid, item, pos) local usedwarp = warp:getWarpByPosition(pos) if usedwarp then if not usedwarp:isActive(cid) then usedwarp:activate(cid) return true end doSendMagicEffect(pos, warp.config.stepIn) end return true end function onStepOut(cid, item, pos) if warp:getWarpByPosition(pos) then doSendMagicEffect(pos, warp.config.stepOut) end return true end /data/movements/movements.xml <!-- Warp Gate System --> <movevent type="StepIn" itemid="9742" script="warpgate.lua"/> <movevent type="StepOut" itemid="9742" script="warpgate.lua"/> /data/talkactions/scripts/warpgate.lua -- This script is part of Warp Gate System -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. function onSay(cid, words, param) local pos = getCreaturePosition(cid) local usedwarp = warp:getWarpByPosition(pos) local destwarp = warp:getWarpByName(param) if not usedwarp then doPlayerSendCancel(cid, warp.config.noWarp) doSendMagicEffect(pos, CONST_ME_POFF) return true end if not destwarp then doPlayerSendCancel(cid, warp.config.noDestiny) doSendMagicEffect(pos, CONST_ME_POFF) return true end if not destwarp:isActive(cid) then doPlayerSendCancel(cid, warp.config.notActive) doSendMagicEffect(pos, CONST_ME_POFF) return true end if getCreatureCondition(cid, CONDITION_INFIGHT) then doPlayerSendCancel(cid, warp.config.inFight) doSendMagicEffect(pos, CONST_ME_POFF) return true end if pos.x == destwarp.pos.x and pos.y == destwarp.pos.y and pos.z == destwarp.pos.z then doPlayerSendCancel(cid, warp.config.inDestiny) doSendMagicEffect(pos, CONST_ME_POFF) return true end if getCreatureMana(cid) < destwarp.mana then doPlayerSendCancel(cid, warp.config.noMana) doSendMagicEffect(pos, CONST_ME_POFF) return true end if getPlayerLevel(cid) < destwarp.level then doPlayerSendCancel(cid, warp.config.noLevel) doSendMagicEffect(pos, CONST_ME_POFF) return true end doSendMagicEffect(destwarp.pos, warp.config.warpEffect) doCreatureSay(cid, words .. " " .. param, warp.config.talkType) doCreatureAddMana(cid, -destwarp.mana) doTeleportThing(cid, destwarp.pos) return true end /data/talkactions/talkactions.xml <!-- Warp Gate System --> <talkaction words="warp" sensitive="false" event="script" value="warpgate.lua"/>
  6. Skyen

    The Bard

    Vou postar alguns scripts meus que estiveram engavetados. Faz algum tempo que fiz estes scripts, então não vou postar screenshots ou como configurar, mas as configurações são fáceis de entender, então divirtam-se. Um dos scripts que eu mais me diverti fazendo é, por incrível que pareça (fazer NPC é muito chato), esse aqui. É um bardo que, de tempo em tempo, começa a cantar músicas (que você pode configurar e colocar as suas próprias músicas, quantas você quiser!). Os players podem até mesmo pedir para o NPC tocar uma música por apenas 10 moedas de ouro! Ótimo para colocar em castelos e tavernas. /data/npc/scripts/bard.lua -- This script is part of The Bard -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. dofile(getDataDir() .. "/npc/scripts/songs.lua") local price = 10 local min_delay = 300 local max_delay = 1000 local min_random_delay = 30 local max_random_delay = 300 local max_distance = 4 local talk_duration = 180 local keywords = { greet = {"hi", "hello", "hey", "greetings"}, farewell = {"bye", "goodbye", "farewell", "cya"}, refuse = {"no", "not"}, song = {"song", "songs", "list", "yes", "ok"}, play = {"play", "yes", "ok"}, } local songs = BARD_SONGS local notes = {18, 19, 21, 22, 23, 24} local song_lyrics = false local song_line = 1 local next_line = 0 local next_random_song = os.time() + math.random(min_random_delay, max_random_delay) local talk = {} function is_talking(cid) for i, v in pairs(talk) do if i == cid then return true end end return false end function get_state(cid) if not is_talking(cid) then return false end return talk[cid].state end function get_last(cid) if not is_talking(cid) then return false end return talk[cid].last end function get_request(cid) if not is_talking(cid) then return false end return talk[cid].request end function set_request(cid, song) if not is_talking(cid) then return false end talk[cid].request = song end function start_talk(cid) if is_talking(cid) then return false end talk[cid] = {} talk[cid].state = "start" talk[cid].last = os.time() return true end function update_talk(cid, state) if not is_talking(cid) then return false end if state then talk[cid].state = state end talk[cid].last = os.time() return true end function stop_talk(cid) if not is_talking(cid) then return false end talk[cid] = nil return true end function say(cid, msg) addEvent(selfSay, math.random(min_delay, max_delay), msg, cid) return true end function start_song(song) song_lyrics = song song_line = 1 next_line = os.time() end function stop_song() song_lyrics = nil song_line = 1 next_line = 0 next_random_song = os.time() + math.random(min_random_delay, max_random_delay) end function msgcontains(message, keyword) if type(keyword) == "table" then for i, v in ipairs(keyword) do if msgcontains(message, v) then return v end end return false end local message = (" " .. message .. " "):lower() local keyword = ("[%s%p]+" .. keyword .. "[%s%p]+"):lower() local a, b = message:find(keyword) if a ~= nil and b ~= nil then return keyword end return false end function onCreatureAppear(cid) return true end function onCreatureDisappear(cid) return true end local song_list = {} local song_list_str = "" for i, v in ipairs(songs) do if v.title then table.insert(song_list, v.title) song_list_str = song_list_str .. "{" .. v.title .. "}" if i < #songs - 1 then song_list_str = song_list_str .. ", " elseif i == #songs - 1 then song_list_str = song_list_str .. " and " end end end function onCreatureSay(cid, type, msg) if getNpcDistanceTo(cid) > max_distance then return true end if msgcontains(msg, keywords.greet) then if song_lyrics then say(cid, "Sorry, I'm singing now. Wait a moment...") elseif not is_talking(cid) then say(cid, "Hello there, friend. Would you like to hear a {song}?") start_talk(cid) else say(cid, "I'm already talking with you.") update_talk(cid) end elseif msgcontains(msg, keywords.song) and get_state(cid) == "start" then if song_lyrics then say(cid, "Sorry, I'm singing now. Wait a moment...") else say(cid, "Very well, " .. getCreatureName(cid) .. ". For a small fee of 10 gold coins I can sing you " .. song_list_str .. ".") update_talk(cid) end elseif msgcontains(msg, song_list) and get_state(cid) == "start" then if song_lyrics then say(cid, "Sorry, I'm singing now. Wait a moment...") else local song = msgcontains(msg, song_list) for i, v in ipairs(songs) do if v.title == song then song = v break end end say(cid, song.title .. (song.artist and (" by " .. song.artist) or "") .. ", huh? Okay, that will cost you " .. price .. " gold coins. Would you like me to play that song?") set_request(cid, song) update_talk(cid, "play") end elseif msgcontains(msg, keywords.play) and get_state(cid) == "play" then if song_lyrics then say(cid, "Sorry, I'm singing now. Wait a moment...") else local song = get_request(cid) if getPlayerMoney(cid) > price then say(cid, "Then " .. song.title .. (song.artist and (" by " .. song.artist) or "") .. " it is!") doPlayerRemoveMoney(cid, price) start_song(song) else say(cid, "Sorry, you don't have enough money...") end update_talk(cid, "start") end elseif msgcontains(msg, keywords.refuse) then if song_lyrics then say(cid, "Sorry, I'm singing now. Wait a moment...") else say(cid, "Well, maybe later then, huh?") update_talk(cid, "start") end elseif msgcontains(msg, keywords.farewell) and is_talking(cid) then say(cid, "Goodbye, " .. getCreatureName(cid) .. "!") stop_talk(cid) end return true end function onThink() selfFocus(0) for cid, v in pairs(talk) do if not isPlayer(cid) or os.time() > v.last + talk_duration or getNpcDistanceTo(cid) > max_distance then if isPlayer(cid) then say(cid, "Goodbye, then...") end stop_talk(cid) else selfFocus(cid) end end if os.time() > next_random_song and not song_lyrics then local song = song_list[math.random(1, #song_list)] for i, v in ipairs(songs) do if v.title == song then song = v break end end start_song(song) end if song_lyrics then selfFocus(getNpcId()) if os.time() >= next_line then local line = song_lyrics[song_line] if type(line) == "string" then selfSay(line) next_line = os.time() elseif type(line) == "number" then if line == 0 then doSendMagicEffect(getThingPosition(getNpcId()), notes[math.random(1, #notes)]) next_line = os.time() else next_line = os.time() + line end end song_line = song_line + 1 end if song_line > #song_lyrics then stop_song() end end return true end /data/npc/scripts/songs.lua -- This script is part of The Bard -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. BARD_SEND_NOTE = 0 BARD_PAUSE_TINY = 1 BARD_PAUSE_SMLL = 3 BARD_PAUSE_NORM = 5 BARD_PAUSE_LONG = 6 BARD_SONGS = { { title = "Ragnar the red", artist = "Bethesda, from Skyrim", BARD_PAUSE_LONG, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Oh there once was a hero named Ragnar the Red", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Who came riding to Whiterun from ole Rorikstead", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And the braggart did swagger and brandish his blade", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "As he told of bold battles and gold he had made", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "But then he went quiet, did Ragnar the Red", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "When he met the shieldmaiden Matilda who said;", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "\"Oh, you talk and you lie and you drink all our mead", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Now I think that its time that you lie down and bleed\"", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And so then came clashing and slashing of steel", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "As the brave lass Matilda charged in full of zeal", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And the braggart named Ragnar was boastful no more", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "When his ugly red head rolled around on the floor", BARD_PAUSE_SMLL, }, { title = "My love is like a red rose", artist = "Robert Burns", BARD_PAUSE_LONG, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Oh, my love's like a red, red rose", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "That's newly sprung in June;", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Oh, my love's like the melodie", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "That's sweetly play'd in tune.", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "As fair art thou, my bonnie lass,", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "So deep in love am I:", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And I will love thee still, my dear,", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Till a' the seas gang dry:", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Till a' the seas gang dry, my dear,", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And the rocks melt wi' the sun:", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I will love thee still, my dear,", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "While the sands o' life shall run.", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And fare thee well, my only love", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And fare thee well, a while!", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And I will come again, my love,", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Tho' it were ten thousand mile.", BARD_PAUSE_SMLL, }, { title = "Begging I will go", BARD_PAUSE_LONG, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Of all the trades in England, a beggin' is the best", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "For when a beggar's tired, You can lay him down to rest.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And a begging I will go, a begging I will go.", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I got a pocket for me oatmeal, and another for me rye.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I got a bottle by me side to drink when I am dry.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And a begging I will go, a begging I will go.", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I got patches on me cloak, and black patch on me knee.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "When you come to take me home, I'll drink as well as thee.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And a begging I will go, a begging I will go.", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I got a pocket for me ... and another for me malt", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I got a pair of little crutches, you should see how I can halt.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And a begging I will go, a begging I will go.", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I sleep beneath an open tree, and there I pay no rent.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Providence provides for me, and I am well content.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And a begging I will go, a begging I will go.", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I fear no plots against me. I live an open cell.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Who would be a king then when beggars live so well.", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And a begging I will go, a begging I will go.", BARD_PAUSE_SMLL, }, { title = "Greybeard Halt", artist = "Will Treaty, from Rangers Apprentice", BARD_PAUSE_LONG, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Greybeard Halt is a friend of mine", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "He lives on Redmont's hill", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Greybeard Halt never took a bath", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "And they say he never will!", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Fare thee well, greybeard Halt", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Fare thee well, I say", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Fare thee well, greybeard Halt", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I'll see you on your way", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Greybeard Halt, he lives with goats that's what I've heard tell", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "He hasn't changed his socks for years", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "But the goats doesn't mind the smell!", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Fare thee well, greybeard Halt", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Fare thee well, I say", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Fare thee well, greybeard Halt", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I'll see you on your way", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Greybeard Halt is a fighting man", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I've heard common talk", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "That greybeard Halt, he cuts his hair", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "With a carving knife and fork!", BARD_PAUSE_NORM, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Fare thee well, greybeard Halt", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Fare thee well, I say", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "Fare thee well, greybeard Halt", BARD_PAUSE_SMLL, BARD_SEND_NOTE, BARD_PAUSE_TINY, "I'll see you on your way", BARD_PAUSE_SMLL, }, } /data/npc/will.xml <?xml version="1.0"?> <npc name="Will" script="bard.lua"> <look type="132" head="39" body="117" legs="2" feet="59"/> </npc>
  7. Não usem com itens stackables. Vou postar alguns scripts meus que estiveram engavetados. Faz algum tempo que fiz estes scripts, então não vou postar screenshots ou como configurar, mas as configurações são fáceis de entender, então divirtam-se. Este é um sisteminha bem simples: Coloque uma ActionID (configurável nos .xml) em um item, e ele ficará imóvel e inutilizável, servido apenas como item de exibição. Bom para fazer lojas sem aquelas bancadas pra bloquear o caminho do player. Ele não conseguirá arrastar o item nem usar, então você pode colocar o item no meio da sala, em um lugar que todos possam chegar perto. Quando algum player dá look no item, vai ser exibido no final da descrição que o item é só de exposição. /data/actions/scripts/sample.lua -- This script is part of Sample Items -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. function onUse(cid, item) if not isPlayer(cid) then return true end doPlayerSendDefaultCancel(cid, RETURNVALUE_CANNOTUSETHISOBJECT) return true end /data/actions/actions.xml <!-- Sample Items --> <action actionid="9000" event="script" value="sample.lua"/> /data/creaturescripts/scripts/login.lua registerCreatureEvent(cid, "SampleItems") /data/creaturescripts/scripts/sample.lua -- This script is part of Sample Items -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. local actionid = 9000 local message = "This item is just a sample." function onLook(cid, thing, pos, dist) local descr if not isPlayer(cid) or thing.actionid ~= 9000 then return true end descr = getItemInfo(thing.itemid).description if descr then descr = descr .. " " end descr = (descr or "") .. message doItemSetAttribute(thing.uid, "description", descr) return true end /data/creaturescripts/creaturescripts.xml <!-- Sample Items --> <event type="look" name="SampleItems" event="script" value="sample.lua"/> /data/movements/scripts/sample.lua -- This script is part of Sample Items -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. function onRemoveItem(item, tile, lastpos, cid) if not isPlayer(cid) then return true end doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTMOVEABLE) doTeleportThing(item.uid, lastpos, true) return true end /data/movements/movements.xml <!-- Sample Items --> <movevent type="RemoveItem" actionid="9000" event="script" value="sample.lua"/>
  8. Skyen

    Detect Life

    Vou postar alguns scripts meus que estiveram engavetados. Faz algum tempo que fiz estes scripts, então não vou postar screenshots ou como configurar, mas as configurações são fáceis de entender, então divirtam-se. O primeiro deles é uma spell, "detect life", que funciona igual à um exiva, mas detecta todos os players perto de você (incluindo monstros e npcs na versão "ultimate"). /data/spells/scripts/detect life.lua -- This script is part of Detect Life Spell -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- Radius of floors that will be detected by the spell local floors = 0 -- Magic effect shown on detected creatures local effect = CONST_ME_MAGIC_BLUE -- Message sent as a warning to detected players, false to deactivate local warn = "You feel like you're being watched." -- Message sent when no living creature is found nearby local nolife = "You detected no signs of life nearby." -- If true, the message will show in detail how many creatures of each type are in each direction. local detailed = false local area = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0}, {0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0}, {0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0}, {0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0}, {0, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0}, {0, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 0}, {0, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0}, {7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 5, 5, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3}, {0, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 0}, {0, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 0}, {0, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0}, {0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0}, {0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0}, {0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, } local keys = { [1] = "north", [2] = "northeast", [3] = "east", [4] = "southeast", [5] = "south", [6] = "southwest", [7] = "west", [8] = "northwest", } function is_index(t, index) for i, v in ipairs(t) do if index == i then return true end end return false end local function get_message(life, keys) local msg local add = {} if life.total == 0 then return false end for key, direction in ipairs(keys) do local keymsg = "" local keyadd = {} if life[key].players == 1 then if not msg then msg = "There is " end table.insert(keyadd, "a player") elseif life[key].players > 1 then if not msg then msg = "There are " end table.insert(keyadd, life[key].players .. " players") end if life[key].monsters == 1 then if not msg then msg = "There is " end table.insert(keyadd, "a monster") elseif life[key].monsters > 1 then if not msg then msg = "There are " end table.insert(keyadd, life[key].monsters .. " monsters") end if life[key].npcs == 1 then if not msg then msg = "There is " end table.insert(keyadd, "a NPC") elseif life[key].npcs > 1 then if not msg then msg = "There are " end table.insert(keyadd, life[key].npcs .. " NPCs") end for i = 1, #keyadd do if i == #keyadd and #keyadd > 1 then keymsg = keymsg .. " and " elseif i ~= 1 then keymsg = keymsg .. ", " end keymsg = keymsg .. keyadd[i] end if #keyadd > 0 then table.insert(add, keymsg .. " by the " .. keys[key]) end end for i = 1, #add do if i == #add and #add > 1 then msg = msg .. " and " elseif i ~= 1 then msg = msg .. ", " end msg = msg .. add[i] end return msg .. "." end local function detect_life(area, keys, pos, floors, effect, warn) local detected = {} local center = {} -- Make sure the area is large enought and has a center if #area < 1 or #area[1] < 1 or #area % 2 == 0 or #area[1] % 2 == 0 then error("The size of the area is invalid.") return false end center.y = math.ceil(#area / 2) center.x = math.ceil(#area[1] / 2) detected.total = 0 for key, value in pairs(keys) do detected[key] = { players = 0, monsters = 0, npcs = 0, } end for z = -floors, floors do for y = 1, #area do -- Make sure that the size of the area doesn't vary if #area[y] ~= #area[1] then error("The size of the area varies.") return false end for x = 1, #area[y] do local dpos = {} local key = area[y][x] dpos.x = pos.x - center.x + x dpos.y = pos.y - center.y + y dpos.z = pos.z + z dpos.stackpos = STACKPOS_TOP_CREATURE local thing = getThingFromPos(dpos, false) if thing.uid ~= 0 and is_index(keys, key) and not isPlayerGhost(thing.uid) then if isPlayer(thing.uid) then if warn then doPlayerSendTextMessage(thing.uid, MESSAGE_EVENT_ADVANCE, warn) end detected[key].players = detected[key].players + 1 elseif isMonster(thing.uid) then detected[key].monsters = detected[key].monsters + 1 elseif isNpc(thing.uid) then detected[key].npcs = detected[key].npcs + 1 end detected.total = detected.total + 1 doSendMagicEffect(dpos, effect) end end end end return detected end function onCastSpell(cid, var) local pos = getThingPosition(cid) local life = detect_life(area, keys, pos, floors, effect, warn) if not life then return false end local message = "There " .. (life.total == 1 and "is " or "are ") .. life.total .. " creatures nearby." if detailed then message = get_message(life, keys) end if life.total == 0 then message = nolife end doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, message) return true end /data/spells/scripts/ultimate detect life.lua -- This script is part of Detect Life Spell -- Copyright (C) 2011 Skyen Hasus -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- Radius of floors that will be detected by the spell local floors = 1 -- Magic effect shown on detected creatures local effect = CONST_ME_MAGIC_BLUE -- Message sent as a warning to detected players, false to deactivate local warn = false -- Message sent when no living creature is found nearby local nolife = "You detected no signs of life nearby." -- If true, the message will show in detail how many creatures of each type are in each direction. local detailed = true local area = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0}, {0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0}, {0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0}, {0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0}, {0, 0, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 0, 0}, {0, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0}, {0, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 0}, {0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 5, 5, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, {0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0}, {0, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 0}, {0, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 0}, {0, 0, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 0, 0}, {0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0}, {0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, } local keys = { [1] = "north", [2] = "northeast", [3] = "east", [4] = "southeast", [5] = "south", [6] = "southwest", [7] = "west", [8] = "northwest", } function is_index(t, index) for i, v in ipairs(t) do if index == i then return true end end return false end local function get_message(life, keys) local msg local add = {} if life.total == 0 then return false end for key, direction in ipairs(keys) do local keymsg = "" local keyadd = {} if life[key].players == 1 then if not msg then msg = "There is " end table.insert(keyadd, "a player") elseif life[key].players > 1 then if not msg then msg = "There are " end table.insert(keyadd, life[key].players .. " players") end if life[key].monsters == 1 then if not msg then msg = "There is " end table.insert(keyadd, "a monster") elseif life[key].monsters > 1 then if not msg then msg = "There are " end table.insert(keyadd, life[key].monsters .. " monsters") end if life[key].npcs == 1 then if not msg then msg = "There is " end table.insert(keyadd, "a NPC") elseif life[key].npcs > 1 then if not msg then msg = "There are " end table.insert(keyadd, life[key].npcs .. " NPCs") end for i = 1, #keyadd do if i == #keyadd and #keyadd > 1 then keymsg = keymsg .. " and " elseif i ~= 1 then keymsg = keymsg .. ", " end keymsg = keymsg .. keyadd[i] end if #keyadd > 0 then table.insert(add, keymsg .. " by the " .. keys[key]) end end for i = 1, #add do if i == #add and #add > 1 then msg = msg .. " and " elseif i ~= 1 then msg = msg .. ", " end msg = msg .. add[i] end return msg .. "." end local function detect_life(area, keys, pos, floors, effect, warn) local detected = {} local center = {} -- Make sure the area is large enought and has a center if #area < 1 or #area[1] < 1 or #area % 2 == 0 or #area[1] % 2 == 0 then error("The size of the area is invalid.") return false end center.y = math.ceil(#area / 2) center.x = math.ceil(#area[1] / 2) detected.total = 0 for key, value in pairs(keys) do detected[key] = { players = 0, monsters = 0, npcs = 0, } end for z = -floors, floors do for y = 1, #area do -- Make sure that the size of the area doesn't vary if #area[y] ~= #area[1] then error("The size of the area varies.") return false end for x = 1, #area[y] do local dpos = {} local key = area[y][x] dpos.x = pos.x - center.x + x dpos.y = pos.y - center.y + y dpos.z = pos.z + z dpos.stackpos = STACKPOS_TOP_CREATURE local thing = getThingFromPos(dpos, false) if thing.uid ~= 0 and is_index(keys, key) then if isPlayer(thing.uid) then if warn then doPlayerSendTextMessage(thing.uid, MESSAGE_STATUS_DEFAULT, warn) end detected[key].players = detected[key].players + 1 elseif isMonster(thing.uid) then detected[key].monsters = detected[key].monsters + 1 elseif isNpc(thing.uid) then detected[key].npcs = detected[key].npcs + 1 end detected.total = detected.total + 1 doSendMagicEffect(dpos, effect) end end end end return detected end function onCastSpell(cid, var) local pos = getThingPosition(cid) local life = detect_life(area, keys, pos, floors, effect, warn) if not life then return false end local message = "There " .. (life.total == 1 and "is " or "are ") .. life.total .. " creatures nearby." if detailed then message = get_message(life, keys) end if life.total == 0 then message = nolife end doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, message) return true end /data/spells/spells.xml <!-- Detect Life Spell --> <instant name="Detect Life" words="exiva vita" lvl="1" mana="0" aggressive="0" selftarget="1" exhaustion="1000" needlearn="0" event="script" value="detect life.lua"/> <instant name="Ultimate Detect Life" words="exiva mas vita" lvl="60" mana="820" aggressive="0" selftarget="1" exhaustion="1000" needlearn="0" event="script" value="ultimate detect life.lua"/> Se quiserem usem apenas uma das versões da spell, estão bem customizáveis.
  9. O erro está aqui: local item3 == getPlayerItemById(cid,true,1949) == é operador de igualdade (comparar se um valor é igual ao outro), e não de atribuição (dar um valor à uma variável). Use o operador de atribuição. E, por favor, idente seus códigos. function onTextEdit(cid, item, newText) if item.itemid == 1949 then local item3 = getPlayerItemById(cid, true, 1949) if newText ~= getItemAttribute(item3.uid, "credito") then doPlayerSendTextMessage(cid, 27, "Sua senha esta incorreta.") end setPlayerStorageValue(cid, 98123, 1) doPlayerSendTextMessage(cid, 27, "Seu banco está aberto.") end return true end
  10. Arrumei um bug que dava quando o player que estava resolvendo o puzzle era removido forçadamente de lá (com, por exemplo, /r): Na onThink, troque isto: if target == 0 then return true end Por isto: if target == 0 then return true end if not isPlayer(target) then target = 0 doChangeSpeed(getNpcId(), -getCreatureSpeed(getNpcId())) doSetCreatureOutfit(getNpcId(), outfit, -1) doTeleportThing(getNpcId(), pos_start) doSendMagicEffect(pos_device, CONST_ME_MAGIC_BLUE) turn_stairs(false) return true end Recomendo colocar a sala inteira do puzzle como no-logout zone, mas o fix acima resolve o problema do player sair do jogo no meio do puzzle. Também fiz o NPC copiar o que o player fala, só que ao contrário. Quem quiser, adicione isto no final do script: function onCreatureSay(cid, type, msg) if cid == target then selfSay(msg:reverse()) end end Divirtam-se.
  11. Não quis ameaçar ninguém, mas vocês já foram rippados para saber como é? A pelomenos 6 meses atrás eu enviei uma mensagem particular para 8 pessoas da equipe falando sobre o ripping do meu nick, e só agora o caso foi analisado por ter sido postado neste tópico, então eu acho que vocês deviam ser mais rigidos contra o ripping, pois sendo punido com alertas, quem liga? Quanto ao que o Mock falou, eu acho que deixar livre para os membros postarem é mais democrático, porém sempre tem os engraçadinhos que querem acabar com a felicidade alheia, então eu acho que os scripts postados deviam ser analisados antes de serem enviados a público, evitando problemas com códigos maliciosos e ripping. Um jeito simples, fácil e 90% eficiente para descobrir ripping é colar pequenos trechos do código no www.google.com.br e no www.cade.com.br. Se os buscadores acharem algo, vocês analisam se pode ou não ter sido ripping.
  12. Bem, por respeito aos membros e por questões éticas, o ripping na ##### é severamente punido com um banimento imediado e permanente, e os tópicos rippados nem mesmo chegam à publico. Antes mesmo que eu entrasse como moderador da seção scripting de lá, nunca vi nenhuma reclamação contra ripping. Se vocês não manterem um controle adequado contra o ripping, então também não seremos obrigados a manter, e então vocês e seus membros poderão sentir o gostinho do constrangimento de ser rippado e nada ser feito contra isso. Garanto que é amargo.
  13. http://www.xtibia.com/forum/Ripping-global...em-t117038.html http://www.xtibia.com/forum/action-Pocao-E...es-t115319.html Os tópicos foram fechados, mas por que o script não foi removido, ou no mínimo, os créditos não foram adicionados? Continua sendo um ripping, mesmo após ter sido fechado. http://www.xtibia.com/forum/Syken-Husus-m239105.html Olhe o nick deste membro. Parece extremamente parecido com o meu, não acham? Eu já reportei e nada foi feito. Tenho quase certeza que esta é uma conta-dupla do usuário esK~. Quando o Mock reporta, vocês se mechem. Por que quando eu reporto vocês ignoram? Os dois scripts acima só fóram fechados com um "toque" do Mock, porque quando eu reportei, nada foi feito. Expliquem.
  14. alguns só tem conta aqui pra verificar se não estão sendo rippados, um exemplo sou eu só pra lembrar, o plagio é proibido por uma lei brasileira.........
  15. Poxa cara, adorei o meu script. Você não tem vergonha de copiar o trabalho dos outros? Ainda coloca o crédito para outro membro sem vergonha, que copiou meu nome. Para quem não me conhece, sou o scripter Skyen Hasus, moderador da seção scripting da OTS Network. Perdi o interesse neste fórum quando um tal de Syken Husus copiou meu nick, pois este fórum está decaindo cada dia mais. 90% dos scripts daqui são copiados de outros fórums. Já enviei mensagem particular para os administradores e moderadores. Nada foi feito, mais um motivo para dizer que este fórum está decaindo. Esteja avisando, caso eu descubra o nick na OTS Network dos engraçadinhos que estão se passando por mim aqui, não vou perdoar. Minha rixa é somente com os membros esK~ e Syken Husus, e não com este fórum, mas se os administradores e moderadores se recusarem a ouvir um membro só porque possui um cargo inferior ao deles, como fizeram com minhas mensagens, a minha rixa será contra este fórum. Querem guerra? Então que esta seja declarada, e que vença o melhor.
  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...