Jump to content

Search the Community

Showing results for tags 'Lua'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • A Cidade OTBR
    • OTServ Brasil
    • Atendimento
    • Taverna
  • OpenTibia
    • Notícias e Discussões
    • Suporte - Dúvidas, Bugs, Erros
    • Downloads
    • Tutoriais
    • Show-Off
    • Divulgação de Servidores
    • Projetos e Formações de Equipes
  • Outros
    • Design

Found 11 results

  1. The Forgotten Server 1.3, Versão: 10.98 Bom dia pessoal! Minha dúvida é a seguinte: Estou fazendo um sistema em que vou ter que fazer uma busca por vários registros. Como eu busco e percorro esses registros utilizando as funções existentes? Eu conheço algumas funções de executar query, buscar resultado, mas não encontrei nenhum exemplo de como percorrer vários resultados. Só encontrei como pegar os valores do primeiro resultado. Ex: De código Obs: Sei mexer com banco de dados, não sei percorrer as linhas do resultado utilizando os comandos lua do servidor Forgotten.
  2. Scripting Cooldown

    Base: The Forgotten Server 1.2, Versão: 8.60 Qual a sua pergunta? Estou com problemas em arrumar o exhaustion de uma runa, queria que ela não tivesse muito, ser algo que possa ser muito rápido, porém, parece que tem um minimo de exhaustion e não pode ser menor que o minimo e eu não faço a minima ideia de como deixar ela rapida. Tentei mudar no spells.xml, colocar no script (vi que dava certo '-') a função "Player.getExhaustion" e "Player.setExhaustion"... Tentei mudar na distro no spells.cpp o cooldown estava 1000 e eu deixar em 1 (pensei que era um padrão), mas não funcionou.... Alguem tem alguma ideia? Você tem o código disponível? Se tiver poste-o na caixa de código que está dentro do spoiler abaixo: (A runa seria uma arma de fogo, nesse exemplo a ak47) Eu fiz varios testes no script, então o que eu utilizava dês do inicio era esse
  3. Scripting Ajuda a configurar !

    configurar esse script para encher 3 de life e 1 de mana a cada 1 segundo e meio do kina . 3 de mana e 1 de life o do mage e 2 de mana e 2 de life o do pala, tudo a cada 1.5 segundos. (+rep) <?xml version="1.0" encoding="UTF-8"?> <vocations> <vocation id="0" clientid="0" name="None" description="none" gaincap="10" gainhp="5" gainmana="5" gainhpticks="12" gainhpamount="1" gainmanaticks="6" gainmanaamount="2" manamultiplier="4.0" attackspeed="2000" basespeed="220" soulmax="100" gainsoulticks="120" fromvoc="0"> <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> <skill id="0" multiplier="1.5" /> <skill id="1" multiplier="2.0" /> <skill id="2" multiplier="2.0" /> <skill id="3" multiplier="2.0" /> <skill id="4" multiplier="2.0" /> <skill id="5" multiplier="1.5" /> <skill id="6" multiplier="1.1" /> </vocation> <vocation id="1" clientid="3" name="Sorcerer" description="a sorcerer" gaincap="10" gainhp="5" gainmana="30" gainhpticks="12" gainhpamount="1" gainmanaticks="3" gainmanaamount="2" manamultiplier="1.1" attackspeed="2000" basespeed="220" soulmax="100" gainsoulticks="120" fromvoc="1"> <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> <skill id="0" multiplier="1.5" /> <skill id="1" multiplier="2.0" /> <skill id="2" multiplier="2.0" /> <skill id="3" multiplier="2.0" /> <skill id="4" multiplier="2.0" /> <skill id="5" multiplier="1.5" /> <skill id="6" multiplier="1.1" /> </vocation> <vocation id="2" clientid="4" name="Druid" description="a druid" gaincap="10" gainhp="5" gainmana="30" gainhpticks="12" gainhpamount="1" gainmanaticks="3" gainmanaamount="2" manamultiplier="1.1" attackspeed="2000" basespeed="220" soulmax="100" gainsoulticks="120" fromvoc="2"> <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> <skill id="0" multiplier="1.5" /> <skill id="1" multiplier="1.8" /> <skill id="2" multiplier="1.8" /> <skill id="3" multiplier="1.8" /> <skill id="4" multiplier="1.8" /> <skill id="5" multiplier="1.5" /> <skill id="6" multiplier="1.1" /> </vocation> <vocation id="3" clientid="2" name="Paladin" description="a paladin" gaincap="20" gainhp="10" gainmana="15" gainhpticks="8" gainhpamount="1" gainmanaticks="4" gainmanaamount="2" manamultiplier="1.4" attackspeed="2000" basespeed="220" soulmax="100" gainsoulticks="120" fromvoc="3"> <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> <skill id="0" multiplier="1.2" /> <skill id="1" multiplier="1.2" /> <skill id="2" multiplier="1.2" /> <skill id="3" multiplier="1.2" /> <skill id="4" multiplier="1.1" /> <skill id="5" multiplier="1.1" /> <skill id="6" multiplier="1.1" /> </vocation> <vocation id="4" clientid="1" name="Knight" description="a knight" gaincap="25" gainhp="15" gainmana="5" gainhpticks="6" gainhpamount="1" gainmanaticks="6" gainmanaamount="2" manamultiplier="3.0" attackspeed="2000" basespeed="220" soulmax="100" gainsoulticks="120" fromvoc="4"> <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> <skill id="0" multiplier="1.1" /> <skill id="1" multiplier="1.1" /> <skill id="2" multiplier="1.1" /> <skill id="3" multiplier="1.1" /> <skill id="4" multiplier="1.4" /> <skill id="5" multiplier="1.1" /> <skill id="6" multiplier="1.1" /> </vocation> <vocation id="5" clientid="3" name="Master Sorcerer" description="a master sorcerer" gaincap="10" gainhp="5" gainmana="30" gainhpticks="12" gainhpamount="1" gainmanaticks="2" gainmanaamount="2" manamultiplier="1.1" attackspeed="1500" basespeed="220" soulmax="200" gainsoulticks="15" fromvoc="1"> <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> <skill id="0" multiplier="1.5" /> <skill id="1" multiplier="2.0" /> <skill id="2" multiplier="2.0" /> <skill id="3" multiplier="2.0" /> <skill id="4" multiplier="2.0" /> <skill id="5" multiplier="1.5" /> <skill id="6" multiplier="1.1" /> </vocation> <vocation id="6" clientid="4" name="Elder Druid" description="an elder druid" gaincap="10" gainhp="5" gainmana="30" gainhpticks="12" gainhpamount="1" gainmanaticks="2" gainmanaamount="2" manamultiplier="1.1" attackspeed="1500" basespeed="220" soulmax="200" gainsoulticks="15" fromvoc="2"> <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> <skill id="0" multiplier="1.5" /> <skill id="1" multiplier="1.8" /> <skill id="2" multiplier="1.8" /> <skill id="3" multiplier="1.8" /> <skill id="4" multiplier="1.8" /> <skill id="5" multiplier="1.5" /> <skill id="6" multiplier="1.1" /> </vocation> <vocation id="7" clientid="2" name="Royal Paladin" description="a royal paladin" gaincap="20" gainhp="10" gainmana="15" gainhpticks="6" gainhpamount="1" gainmanaticks="3" gainmanaamount="3" manamultiplier="1.4" attackspeed="1500" basespeed="220" soulmax="200" gainsoulticks="15" fromvoc="3"> <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> <skill id="0" multiplier="1.2" /> <skill id="1" multiplier="1.2" /> <skill id="2" multiplier="1.2" /> <skill id="3" multiplier="1.2" /> <skill id="4" multiplier="1.1" /> <skill id="5" multiplier="1.1" /> <skill id="6" multiplier="1.1" /> </vocation> <vocation id="8" clientid="1" name="Elite Knight" description="an elite knight" gaincap="25" gainhp="15" gainmana="5" gainhpticks="4" gainhpamount="1" gainmanaticks="6" gainmanaamount="3" manamultiplier="3.0" attackspeed="1500" basespeed="220" soulmax="200" gainsoulticks="15" fromvoc="4"> <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> <skill id="0" multiplier="1.1" /> <skill id="1" multiplier="1.1" /> <skill id="2" multiplier="1.1" /> <skill id="3" multiplier="1.1" /> <skill id="4" multiplier="1.4" /> <skill id="5" multiplier="1.1" /> <skill id="6" multiplier="1.1" /> </vocation> <vocation id="9" name="Dark Master Sorcerer" description="an Dark master sorcerer" needpremium="1" gaincap="10" gainhp="5" gainmana="30" gainhpticks="4" gainhpamount="10" gainmanaticks="2" gainmanaamount="25" manamultiplier="1.1" attackspeed="750" soulmax="200" gainsoulticks="15" fromvoc="5" lessloss="50"> <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="1.0" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/> <skill fist="1.5" club="2.0" sword="2.0" axe="2.0" distance="2.0" shielding="1.5" fishing="1.1" experience="1.0"/> </vocation> <vocation id="10" name="Divine Elder Druid" description="an Divine elder druid" needpremium="1" gaincap="10" gainhp="5" gainmana="30" gainhpticks="4" gainhpamount="10" gainmanaticks="2" gainmanaamount="25" manamultiplier="1.1" attackspeed="750" soulmax="200" gainsoulticks="15" fromvoc="6" lessloss="50"> <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="1.0" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/> <skill fist="1.5" club="1.8" sword="1.8" axe="1.8" distance="1.8" shielding="1.5" fishing="1.1" experience="1.0"/> </vocation> <vocation id="11" name="Epic Royal Paladin" description="an epic royal paladin" needpremium="1" gaincap="20" gainhp="10" gainmana="15" gainhpticks="3" gainhpamount="15" gainmanaticks="3" gainmanaamount="20" manamultiplier="1.4" attackspeed="750" soulmax="200" gainsoulticks="15" fromvoc="7" lessloss="50"> <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="1.0" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/> <skill fist="1.2" club="1.2" sword="1.2" axe="1.2" distance="1.1" shielding="1.1" fishing="1.1" experience="1.0"/> </vocation> <vocation id="12" name="Heroic Elite Knight" description="an Heroic elite knight" needpremium="1" gaincap="25" gainhp="15" gainmana="5" gainhpticks="8" gainhpamount="25" gainmanaticks="4" gainmanaamount="10" manamultiplier="3.0" attackspeed="750" soulmax="200" gainsoulticks="15" fromvoc="8" lessloss="50"> <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="1.0" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/> <skill fist="1.1" club="1.1" sword="1.1" axe="1.1" distance="1.4" shielding="1.1" fishing="1.1" experience="1.0"/> </vocation> </vocations>
  4. Preciso de uma ajuda para arrumar o erro ao tentar desenvolver o código abaixo. Ele consiste em fazer a alteração da Outfit e Vocação ao pegar determinado nível. Ao regredir de nível, deixa de ter a Outfit e Vocação que conseguiu e volta para a anterior. O erro acontece na linha aonde ele addOutfit -> player:addOutfit(arrayOutfit[o][2]) Aparentemente ele não está detectando o [o] (está dando como nulo), que é justamente a dúvida que tenho. Não estou conseguindo formular o problema apesar de parecer algo fácil e/ou algum erro bobo. Eu criei uma variável local o = 1 e local v = 1 e deu certo. Porque nesse caso ele está pegando os nomes das arrays que são 1 mesmo, mas eu quero que ele pegue automaticamente de acordo com o "for" que fiz. function onAdvance(player, skill, oldlevel, newlevel) -- OUTFITS -- local OUTFIT0001 = 905 -- 01 local OUTFIT0002 = 129 -- 02 local arrayOutfit = { [1] = {OUTFIT0001, OUTFIT0002} } local arrayVocation = { [1] = {1, 2} } local L01 = 10 -- Storage_Evolution local storage00000 = 70000 local storage00001 = 70001 local outfit = player:getOutfit() for _, o in pairs(arrayOutfit) do if type(o) == 'table' then if isInArray(o, outfit.lookType) and (skill == SKILL_LEVEL) then for _, v in pairs(arrayVocation) do if type(v) == 'table' then if isInArray(v, player:getVocation():getId()) then if (player:getStorageValue(storage00000) ~= 1) and (player:getLevel() < L01) then player:setStorageValue(storage00000, 1) player:setStorageValue(storage00001, 0) player:addOutfit(arrayOutfit[o][1]) player:removeOutfit(arrayOutfit[o][2]) outfit.lookType = arrayOutfit[o][1] player:setOutfit(outfit) player:setVocation(arrayVocation[v][1]) end if (player:getStorageValue(storage00001) ~= 1) and (player:getLevel() >= L01) then player:setStorageValue(storage00000, 0) player:setStorageValue(storage00001, 1) player:addOutfit(arrayOutfit[o][2]) outfit.lookType = arrayOutfit[o][2] player:setOutfit(outfit) player:setVocation(arrayVocation[v][2]) end end end end end end end return true end O erro é o seguinte: Lua Script Error: [CreatureScript Interface] data/creaturescripts/scripts/outfitVoc_onAdvance.lua:onAdvance data/creaturescripts/scripts/outfitVoc_onAdvance.lua:41: attempt to index a nil value stack traceback: [C]: in function '__index' data/creaturescripts/scripts/outfitVoc_onAdvance.lua:41: in function <data/creaturescripts/scripts/outfitVoc_onAdvance.lua:1> [C]: in function 'addExperience' data/actions/scripts/other/itemlevel.lua:7: in function <data/actions/scripts/other/itemlevel.lua:6>
  5. Scripting Error teleport.lua

    [Error - Action Interface] data/actions/scripts/other/teleport.lua:onUse Description: attempt to index a number value stack traceback: [C]: in function 'doTileQueryAdd' data/actions/scripts/other/teleport.lua:13: in function <data/actions/scripts/other/teleport.lua:4> Script: teleport.lua local UP_FLOORS = {1386, 3678, 5543, 8599, 10035} local DRAW_WELL = 1369 function onUse(cid, item, fromPosition, itemEx, toPosition) if(item.itemid == DRAW_WELL and item.actionid ~= 100) then return false end fromPosition.stackpos = STACKPOS_GROUND if(isInArray(UP_FLOORS, item.itemid)) then fromPosition.z = fromPosition.z - 1 fromPosition.y = fromPosition.y + 1 if(doTileQueryAdd(cid, fromPosition, 4, false) ~= RETURNVALUE_NOERROR) then fromPosition.y = fromPosition.y - 2 end else fromPosition.z = fromPosition.z + 1 end if(doTileQueryAdd(cid, fromPosition, 4, false) ~= RETURNVALUE_NOERROR) then return false end local pos, dir = getCreaturePosition(cid), SOUTH if(pos.x < fromPosition.x) then dir = EAST elseif(pos.x == fromPosition.x) then if(pos.y == fromPosition.y) then dir = getCreatureLookDirection(cid) elseif(pos.y > fromPosition.y) then dir = NORTH end elseif(pos.x > fromPosition.x) then dir = WEST end doTeleportThing(cid, fromPosition, false) doCreatureSetLookDirection(cid, dir) return true end
  6. Object SQL

    Como funciona? Esta lib funciona como um façade para trabalhar com queries de um jeito mais "programador". A seguinte query, por exemplo: (...) tmp = db.getResult("SELECT `id`, `begin`, `end`, `payment` FROM `guild_wars` WHERE `guild_id` = " .. guild .. " AND `enemy_id` = " .. enemy .. " AND `status` = 0") if(tmp:getID() == -1) then (...) Se transforma no seguinte código: (...) tmp = query:select('id', 'begin', 'end', 'payment'):from('guild_wars'):where('guild_id', guild):where('enemy_id', enemy):where('status', 0):execute() if (tmp.id == -1) then (...) Quem já está acostumado com frameworks e outras facilidades de transformar queries em objetos vai sentir diferença na facilidade para escrever queries. Em outro exemplo, executando um update: db.executeQuery("UPDATE `guilds` SET `balance` = `balance` - " .. tmp:getDataInt("payment") .. " WHERE `id` = " .. guild) Com a lib, se torna: query:update('guilds'):set('balance', dec(tmp.payment)):where('id', guild):execute() Esta é outra facilidade, adicionei os modificadores inc e dec para incrementar ou decrementar, respectivamente, os campos em questão, e levam um parâmetro opcional que indica a quantidade a ser alterada. Nada o impede, também, de construir a query em vários passos: query:update('guilds') local payment = tmp.payment query:set('balance', dec(payment)) local id = getPlayerGuild(cid) --não sei se essa função existe, é apenas um exemplo query:where('id', id) E também, você pode saber se sua query foi executada ou não: if query:execute() then (...) Veja outros exemplos de código: query:insert_into('players'):values({name = 'Lordfire\'Rook', account_id = 0, level = 39, vocation = 0}):execute() query:update('players'):set({vocation = 4, access = inc(), level = inc(5)}):where('name', 'Lordfire\'Rook'):execute() query:select():from('players', 'accounts'):where('players.level', '>=', 39):where('players.access', 1):execute() query:delete_from('players'):where('level', '>=', 30):where('access', 0):execute() Repare que, para inserir, você usa o método values e envia uma tabela com as informações. A query automaticamente ordena os campos a serem preenchidos com seus respectivos dados. Você pode informar múltiplas tabelas no método from, mas deve indicar os campos com o nome da tabela para evitar redundância (por exemplo: level -> players.level) O método where também leva um parâmetro opcional, no meio, caso você queira usar alguma comparação que seja diferente de =. Estes códigos geram as seguintes queries, para efeito de consulta, que você pode pegar com o método query(), caso queira usar junto com outra query: INSERT INTO `players`(`account_id`,`vocation`,`name`,`level`)VALUES(0,0,"Lordfire'Rook",39); UPDATE players SET `level`=`level`+5,`vocation`=4,`access`=`access`+1 WHERE `name`="Lordfire'Rook"; SELECT * FROM `players`,`accounts` WHERE `players`.`level`>=39 AND `players`.`access`=1; DELETE FROM players WHERE `level`>=30 AND `access`=0; Lib: Pastebin: [Hidden Content] Código: function mod(key, _type, value) if value == nil then value = 1 end return key .. _type .. value end function inc(value) return function(key) return mod(key, [[+]], value) end end function dec(value) return function(key) return mod(key, [[-]], value) end end Query = {} function Query:new() return setmetatable({type = [[]], columns = [[]], tables = [[]], conditions = {}}, {__index = self}) end -- C function Query:insert_into(_table) self.type, self.columns, self.tables, self.conditions = [[insert]], [[]], [[`]] .. _table .. [[`]], {} return self end function Query:values(values) local _columns, _values = {}, {} for k, v in pairs(values) do table.insert(_columns, [[`]] .. k .. [[`]]) if type(v) == "string" then v = [["]] .. v:gsub([[\"]], [[\"]]) .. [["]] end table.insert(_values, v) end self.columns, self.conditions = [[(]] .. table.concat(_columns, [[,]]) .. [[)]], _values return self end -- R function Query:select(...) self.type, self.columns, self.tables, self.conditions = [[select]], [ [*]], [[]], {} local columns = {...} if #columns > 0 then for i, c in ipairs(columns) do columns[i] = [[`]] .. c .. [[`]] end self.columns = table.concat(columns, [[,]]) end return self end -- U function Query:update(_table) self.type, self.columns, self.tables, self.conditions = [[update]], [[]], _table, {} return self end function Query:set(columns) local _columns = {} for k, v in pairs(columns) do k = [[`]] .. k:gsub([[\.]], [[`.`]]) .. [[`]] if type(v) == "string" then v = [["]] .. v:gsub([[\"]], [[\"]]) .. [["]] elseif type(v) == "function" then v = v(k) end table.insert(_columns, k .. [[=]] .. v) end self.columns = table.concat(_columns, [[,]]) return self end -- D function Query:delete_from(_table) self.type, self.columns, self.tables, self.conditions = [[delete]], [[]], _table, {} return self end -- RU function Query:where(...) local params = {...} local column, comparison, value = [[`]] .. params[1]:gsub([[%.]], [[`.`]]) .. [[`]], [[=]], nil if #params == 2 then value = params[2] elseif #params == 3 then if params[2]:find("[<>]=") then comparison, value = params[2], params[3] else comparison = [[ ]] .. params[2] .. [[ ]] end else return false end if type(value) == "string" then value = [["]] .. value:gsub([[\"]], [[\"]]) .. [["]] end table.insert(self.conditions, column .. comparison .. value) return self end -- RD function Query:from(...) local tables = {...} for i, t in ipairs(tables) do tables[i] = [[`]] .. t .. [[`]] end self.tables = table.concat(tables, [[,]]) return self end function Query:query() local query = [[]], {} if self.type == [[insert]] then query = [[iNSERT INTO ]] .. self.tables .. self.columns .. [[VALUES(]] .. table.concat(self.conditions, [[,]]) .. [[)]] elseif self.type == [[select]] then local where = [[]] if self.conditions ~= [[]] then where = [[ WHERE ]] .. table.concat(self.conditions, [[ AND ]]) end query = [[sELECT ]] .. self.columns .. [[ FROM ]] .. self.tables .. where elseif self.type == [[update]] then local where = [[]] if self.conditions ~= [[]] then where = table.concat({[[ WHERE]], table.concat(self.conditions, [[ AND ]])}, [[ ]]) end query = [[uPDATE ]] .. self.tables .. [[ SET ]] .. self.columns .. where elseif self.type == [[delete]] then local where = [[]] if self.conditions ~= [[]] then where = table.concat({[[ WHERE]], table.concat(self.conditions, [[ AND ]])}, [[ ]]) end query = [[DELETE FROM ]] .. self.tables .. where end return query .. [[;]] end function Query:execute() local query, result = self:query() if self.type == [[insert]] then local result = {} query = db.getResult(query) for k, v in pairs(query.val) do result[k] = v end return result end return db.executeQuery(query) end query = Query:new() Avisos: Isso não é uma biblioteca completa de MVC ou qualquer coisa parecida. É apenas um "wrapper" para construir queries de um jeito mais dinâmico, organizado e sem se preocupar com concatenação e afins. Não há sanitização de strings, testes para verificar se as funções existem ou coisa do tipo, portanto, tome cuidado. A biblioteca ainda está em fase de testes, não cheguei a usar ela num servidor com muitos players online. Se alguém puder fazer isso, ficarei agradecido. Posso transformar as queries para a sintaxe da biblioteca, se necessário.
  7. Funções iteradoras em Lua

    Iteradores são funções especiais criadas para iterar, ou seja, percorrer, listas, vetores (arrays), matrizes, tabelas ou o que quisermos. Nós criamos iteradores para usar na função for. Um exemplo de iterador que você já deve conhecer é o pairs. Vamos supor que eu tenha a seguinte tabela: k = {1, 2, 3, 4, 5} E eu queira iterar por todos eles imprimindo o seu quadrado. Como faríamos isso? Casualmente, o código seria este: for i = 1, 5 do print(i ^ 2) end Mas e se eu quiser fazer isso várias vezes? Com uma lista que não segue um padrão? Então criamos um iterador, mas primeiro, vamos entender a estrutura de um em pseudocódigo Lua: function iterator(values) local pos = 0 --posição do iterador na lista return function() pos = pos + 1 if values[pos] ~= nil then return values[pos] end return nil end end Perceba que eu não retorno um valor especifico ao chamar a função iterator(), eu retorno uma nova função. Essa função será chamada pelo for até que seu retorno seja nil, onde Lua assume que o iterador acabou. E como eu sei quando acaba? Simples, há uma variável (chamei, neste caso, de pos) que armazena a posição dentro do array values do próximo valor a ser retornado. A cada iteração, o valor aumenta em 1 dentro da função. Quando eu acessar um índice dentro do array que não existe, seu valor (values[pos]) será nil, portanto eu testo essa condição. Parece bastante complexo, mas vamos voltar ao exemplo do quadrado. Chamarei minha função iteradora de square: function square(numbers) local pos = 0 return function() pos = pos + 1 if values[pos] ~= nil then return values[pos] ^ 2 end return nil end end A cada chamada da função de retorno, eu aumento a posição e retorno este elemento elevado ao quadrado. Então, usarei a função assim: for i in square(k) do print(i) end Que funciona como o esperado: O que mais podemos fazer com iteradores? Podemos, por exemplo, bloquear uma palavra usando a função onTalk do xotservx (pesquise no Google): local palavra = "jujuba" function splitWords(phrase) local pos = 0, words = phrase:gmatch("%w+") return function() pos = pos + 1 if words[pos] ~= nil then return words[pos] end return nil end end function onTalk(cid, type, text, position) for w in splitWords(text) do if w = palavra then return false end end return true end Claro que esse exemplo é bastante simplório, mas demonstra a utilidade dos iteradores. Neste caso, eu testo todas as palavras que o player falou para encontrar uma palavra especifica que eu defini. Podemos transformar isso tudo em um loop while, para você entender um pouco melhor: local words = splitWords(text) while w = words() do if w == nil then break end if w = palavra then return false end end end return true Usando o iterador, ganhamos organização no código e o controle do for. Espero que façam bom uso de iteradores para organizar seus códigos
  8. The Zodiac ~

    ┌──────────────────────────────────────────────────┐ │Nome: Sign of Zodiac │Versão do script: 1.0.0 │Tipo do script: Sistema (Creature Script, Talkaction e Lib) │Servidor Testado: The Forgotten Server 0.4.0 Doomed Elderberry │Autor: Lwkass └──────────────────────────────────────────────────┘ Por mais que o feedback do meu ultimo post (Lib para criar Spell) tenha sido pouco, vou postar mais um script... É um sistema de Signo do Zodíaco, onde cada signo da um bônus (por enquanto apenas 2), a ideia está bem inicial, mas pretende continua-lo. - Características: - Explicando: Para escolher o signo o player deve colocar o dia e o mês do aniversário e o sistema automaticamente coloca o signo, comando: Só para deixar claro como o sistema funciona, usando de exemplo o signo de Leão (Leo) que é do elemento Fire: * Se receber um dano do elemento Fire, absorve 5% (modificável) do dano total, ou seja, o dano seria igual a 95% do que seria (dano absorvido indicado por animatedText). * Se matar um monstro que tenha uma defesa contra Fire maior que 0% ganha bônus de 10% (modificável) da exp total, ou seja, ganha-se 110% (exp extra indicada por animatedText). Se o signo fosse do elemento Earth, então seria a mesma coisa só que com o elemento Earth, se fosse Ice ou Lighting a mesma coisa. Pode-se usar o comando !zodiac info para informações. - Script: Primeiro, na pasta data/lib (caso a pasta não exista, crie) do seu servidor crie um arquivo Lua com o nome zodiac-Lib.lua (Lib com maiúscula) e salve com isso dentro: --[[ Sign of Zodiac System v1.0.0 by: Lwkass ([email protected]) ]] Zodiac = { constant = { OPTION_PERCENT_BLOCK = 5, -- In Percent OPTION_EXTRA_EXP_RATE = 10, -- In Percent STORAGE_SIGN = 16161, elements = { ["Fire"] = { combat = COMBAT_FIREDAMAGE, color = COLOR_ORANGE }, ["Earth"] = { combat = COMBAT_EARTHDAMAGE, color = COLOR_LIGHTGREEN }, ["Lighting"] = { combat = COMBAT_ENERGYDAMAGE, color = COLOR_TEAL }, ["Ice"] = { combat = COMBAT_ICEDAMAGE, color = COLOR_LIGHTBLUE } } }, signs = { ["Aries"] = { date = {"21/03", "20/04"}, element = "Fire" }, ["Taurus"] = { date = {"21/04", "20/05"}, element = "Earth" }, ["Gemini"] = { date = {"21/05", "20/06"}, element = "Lighting" }, ["Cancer"] = { date = {"21/06", "21/07"}, element = "Ice" }, ["Leo"] = { date = {"22/07", "22/08"}, element = "Fire" }, ["Virgo"] = { date = {"23/08", "22/09"}, element = "Earth" }, ["Libra"] = { date = {"23/09", "22/10"}, element = "Lighting" }, ["Scorpio"] = { date = {"23/10", "21/11"}, element = "Ice" }, ["Sagittarius"] = { date = {"22/11", "21/12"}, element = "Fire" }, ["Capricorn"] = { date = {"22/12", "20/01"}, element = "Earth" }, ["Aquarius"] = { date = {"21/01", "19/02"}, element = "Lighting" }, ["Pisces"] = { date = {"20/02", "20/03"}, element = "Ice" } }, getSignInfo = function (signName) return Zodiac.signs[signName] end, set = function (cid, signName) setPlayerStorageValue(cid, Zodiac.constant.STORAGE_SIGN, signName) end, get = function (cid) return getPlayerStorageValue(cid, Zodiac.constant.STORAGE_SIGN), Zodiac.getSignInfo(getPlayerStorageValue(cid, Zodiac.constant.STORAGE_SIGN)) or 0 end, getElement = function (cid) return Zodiac.getSignInfo(getPlayerStorageValue(cid, Zodiac.constant.STORAGE_SIGN)).element end, getSign = function (cid, day, month) for sign, info in pairs(Zodiac.signs) do _, _, beginDay, beginMonth = info.date[1]:find("(%d+)/(%d+)") _, _, endDay, endMonth = info.date[2]:find("(%d+)/(%d+)") beginDay, beginMonth, endDay, endMonth = tonumber(beginDay), tonumber(beginMonth), tonumber(endDay), tonumber(endMonth) if ((month == beginMonth and day >= beginDay) or (month == endMonth and day <= endDay)) then return sign, info end end end } Agora na pasta data/creaturescripts/scripts: No arquivo login.lua adicione isso antes do return: -- Zodiac registerCreatureEvent(cid, "zodiacKill") registerCreatureEvent(cid, "zodiacStats") if (getPlayerLastLogin(cid) <= 0 or getPlayerStorageValue(cid, 16160) == 1) then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Please, when is your birthday date ? (Example: !zodiac day/month = !zodiac 1/2, !zodiac 23/7,...)") setPlayerStorageValue(cid, 16160, 1) -- Talk state else doPlayerSetSpecialDescription(cid, ", sign of " .. getPlayerStorageValue(cid, 16161)) end E crie esses arquivos: zodiacKill.lua dofile('data/lib/zodiac-Lib.lua') function getMonsterPath(monstername) f = io.open ("data/monster/monsters.xml", 'r') for line in f:lines() do _, _, name, path, file_name = string.find(line, '<monster name="(.+)" file="(.+)/(.+).xml"/>') if (name and path and file_name and name:lower() == monstername:lower()) then f:close() return path .. "/" .. file_name .. ".xml" end end end function getMonsterElementDefense(monstername, element) f = io.open ("data/monster/" .. getMonsterPath(monstername), 'r') for line in f:lines() do if (string.find(line, '</elements>')) then break end _, _, n = string.find(line, '<element '.. element:lower() ..'Percent="([-%d]+)"/>') if (n) then f:close() return tonumber(n) end end f:close() return 0 end ------- function onKill(cid, target, lastHit) if (isMonster(target) and getMonsterElementDefense(getCreatureName(target), (Zodiac.getElement(cid) == "Lighting" and "Energy" or Zodiac.getElement(cid))) > 0) then local exp_bonus = math.ceil(getMonsterInfo(getCreatureName(target)).experience * (Zodiac.constant.OPTION_EXTRA_EXP_RATE/100)) doSendAnimatedText(getThingPos(cid), exp_bonus, COLOR_GREY) doPlayerAddExperience(cid, exp_bonus) end return true end zodiacStats.lua dofile('data/lib/zodiac-Lib.lua') function onStatsChange(cid, attacker, type, combat, value) playerSign = Zodiac.get(cid) if (combat == Zodiac.constant.elements[Zodiac.getElement(cid)].combat) then valuem = math.ceil(value*(Zodiac.constant.OPTION_PERCENT_BLOCK/100)) doCreatureAddHealth(cid, valuem) doSendAnimatedText(getThingPos(cid), "+"..valuem, Zodiac.constant.elements[Zodiac.getElement(cid)].color) end return true end Certo, agora no arquivo data/creaturescripts/creaturescripts.xml, adicione isso: <event type="statschange" name="zodiacStats" event="script" value="zodiacStats.lua"/> <event type="kill" name="zodiacKill" event="script" value="zodiacKill.lua"/> Na pasta data/talkactions/scripts, adicione um arquivo Lua com o nome de zodiacTalk.lua: dofile('data/lib/zodiac-Lib.lua') function onSay(cid, words, param, channel) if (param:len() == 0) then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "You can use '!zodiac day/month' or '!zodiac info'") return true end playerSign, Info = Zodiac.get(cid) if (type(playerSign) == "string" and param:lower() == "info") then doPlayerPopupFYI(cid, [[ Zodiac Informations ~ ------------------------------- * Sign: ]] .. playerSign .. [[ * Element: ]] .. Info.element .. [[ * Bonus: +]] .. Zodiac.constant.OPTION_EXTRA_EXP_RATE .. [[% experience of ]] .. Zodiac.getElement(cid) .. [[ monsters +]] .. Zodiac.constant.OPTION_PERCENT_BLOCK .. [[% of defense in attacks with ]] .. Zodiac.getElement(cid) .. [[ element ]]) elseif (getPlayerStorageValue(cid, 16160) == 1) then _, _, day, month = string.find(param, "(%d+)/(%d+)") day, month = tonumber(day), tonumber(month) if (day and month and day > 0 and day <= 31 and month > 0 and month <= 12) then Zodiac.set(cid, Zodiac.getSign(cid, day, month)) playerSign = Zodiac.get(cid) doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, param) doSendMagicEffect(getThingPos(cid), math.random(28, 30)) doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "You sign of zodiac is " .. playerSign .. " which is of element " .. Zodiac.getElement(cid) .. " !") doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "You can see more information saying '!zodiac info', remember this...") setPlayerStorageValue(cid, 16160, -1) else doPlayerSendCancel(cid, "You put a invalid date.") end end return true end Coloque essa tag no arquivo data/talkactions/talkactions.xml <talkaction words="!zodiac" event="script" value="zodiacTalk.lua"/> ChangeLog: E é isso ! Qualquer dúvida, sugestão, critica só dizer ^^
  9. Patterns

    Pattern Pattern ("Padrão" em pt-br) é uma poderosa funcionalidade para manipulação de strings (caso você não saiba o que é uma "string", busque saber antes de continuar, recomendo também ter um certo domínio sobre a biblioteca string), e usada para buscar um padrão de texto pré-definido. Porque aprender ? Possui recursos indispensáveis quando se precisa trabalhar com strings, alta aplicabilidade em scripts direcionados a otserv (talkactions), não que se vá usar isso a todo o momento, mas é altamente recomendado que se saiba trabalhar com patterns, é extremamente útil as vezes. Funções Algumas funções da biblioteca padrão string que aceitam pattern em seus parâmetros: string.find(string, pattern) – Procura a primeira instância da pattern na string string.gfind(string, pattern) – Quando for chamada repetidamente, retorna cada instância da pattern na string string.gsub(string, pattern, replace) – Retorna uma string em que todas as instâncias da pattern foram substituidas por replace string.match(string, pattern, init) – Retorna uma lista de ocorrências da pattern na string, começando em init (1 significa o primeiro caractere da string, 2 o segundo, assim por diante) Conjuntos Quando se constrói uma pattern, se utiliza alguns caracteres, cada um representando um conjunto diferente: x (onde "x" não é um caractere mágico ^$()%.[]*+-?) → Representa o caractere "x" mesmo; . → Representa todos os caracteres; %a → Representa todas as letras; %c → Representa todos os caracteres de controle; %d → Representa todos os dígitos; %l → Representa todas as letras minusculas; %p → Representa todos os caracteres de pontuação; %s → Representa todos os caracteres de espaço; %u → Representa todas as letras maiúsculas; %w → Representa todos os caracteres alfanuméricos; %x → Representa todos os dígitos hexadecimais; %z → Representa o caractere com a representação do 0 (zero). Ao usar zeros na pattern ela não irá funciona, use esta nesse caso; Ao usar letra maiúscula, isso faz representar o contrário (Exemplo: %A → Representa tudo que não for letras; %D → Representa tudo que não for um digito; assim por diante...). Como dito anteriormente, para se criar uma pattern é necessário utilizar esses conjuntos, uma pattern é feita de uma sequência desses conjuntos. Se você quisesse criar uma pattern para encontrar uma certa string em um texto, por exemplo, para encontrar os números da string "23otserv", você teria que usar esta pattern "%d%dotserv", assim você estaria definindo que quer os numeros que estão ao lado da palavra ‘otserv’. Mas e se tivesse que encontrar um numero com 10 "casas" ? Por isso existe os modificadores, para evitar essa repetição desnecessária. Modificadores Servem principalmente para poupar serviço e são quatro, entenda 'x' como sendo algum conjunto (%a, %c, %d, ...): x* → Retorna 0 ou mais repetições do conjunto x. Sempre retornará a maior cadeia possível encontrada; x+ → Retorna 1 ou mais repetições do conjunto x. Sempre retornará a maior cadeia possível encontrada; x- → Retorna 0 ou mais repetições do conjunto x. Sempre retornará a menor cadeia possível encontrada; x? → Retorna 0 ou 1 ocorrência de x; Elementos especiais Existe também quatro elementos especiais: %n → Sendo n um numero entre 1 e 9, busca a enésima captura (apenas vi sendo usada na função string.gsub); %bxy → Procura uma string que inicia com x e termina com y; ^ → Quando está no começo da pattern, força a pattern a ser encontrada no começo da string; $ → Quando está no final da pattern, força a pattern a ser encontrada no fim da string; Nota: Se ^ ou $ estiverem em outros lugares da pattern, não fazem nada, apenas representam eles mesmos. Construindo uma pattern Vamos construir algumas patterns com os elementos citados acima. Primeiro alguns exemplos e depois uma explicação mais detalhada de cada elemento da pattern: String para as patterns: "Exemplo lua de pattern lua feito em lua" exemplos toscos, a gente se vê por aqui Pattern: (%a+) lua Capturaria: Exemplo lua de pattern lua feito em lua Ele só retornará o primeiro caso que corresponder com a pattern. Agora, ao invés de usar o "%a" fosse usado o "." (que captura tudo), aconteceria isso: Pattern: (.+) lua Capturaria: Exemplo lua de pattern lua feito em lua Como "%a" captura apenas letras e não o "espaço", foi por isso que no primeiro exemplo só capturou a palavra "Exemplo" e no segundo exemplo, como foi usado o "." que captura tudo, capturou uma parte maior (ai que vêm a parte do modificador) por causa do modificador "+" que sempre vai buscar a maior cadeia possivel, agora veja um exemplo usando o "-": Pattern: (.-) lua Capturaria: Exemplo lua de pattern lua feito em lua O modificador "-", como dito anteriormente, captura a menor cadeia e por isso capturaria apenas o "Exemplo". Todos os modificadores são importantes. Um exemplo maior: Pattern: (%a+) lua (.-) lua (.+) Capturaria: Exemplo lua de pattern lua feito em lua Para quem não entendeu Explicação passo a passo: (%d+) Captura → O parenteses define que você quer que retorne essa captura. Conjunto → No caso é o de digitos. Modificador → No caso mostra que é para obter a maior cadeia possivel com 1 ou mais repetições do conjunto. Um exemplo mais avançado Agora usando de exemplo a pattern da função string.trim, que remove os espaços em branco do lado esquerdo e direito da string. function string.trim(str) -- Function by Colandus return ([b]string.gsub(str, "^%s*(.-)%s*$", "%1")[/b]) end string.gsub(str, "^%s*(.-)%s*$", "%1") str → Uma string qualquer; ^ → Força o começo da pattern ser encontrada no começo de str; %s* → Conjunto de espaços, podendo ter 0 ou mais repetições; (.-) → A captura principal, a que vai ser retornada, podendo ser digitos, letras, espaço, etc; $ → Força o final da pattern ser encontrada no fim de str; %1 → Retorna a 1ª captura da pattern e usa como parametro da função (Esse é um dos elementos especiais, %n); Dessa forma será removido os espaços apenas no começo e no fim da string ! Complemento Depois de dominar e entender como funciona as patterns, vamos aplica-las em funções, vou mostrar um exemplo de cada função (as que foram citadas no começo). string.find: [b]init[/b], [b]end[/b], [b]case1[/b], [b]case2[/b] = string.find("minha string123", "(%a+) (.+)") init → Onde inicia a captura encontrada (nesse caso, init = 1); end → Onde termina a captura encontrada (end = 15); case1 → Primeira captura que equivale a pattern (%a+) (case1 = minha); case2 → Segunda captura que equivale a pattern (.+) (case2 = string123); string.gfind: for [b]occ[/b] in string.gfind("a1a2a3a4a5", "(%a%d)") do print([b]occ[/b]) end occ → Terá um valor para cada instância da pattern (%a%d) encontrada, então irá printar a1, a2, a3, a4 e a5. string.match: [b]case1[/b], [b]case2 [/b]= string.match("Eu tenho 50 reais", "(%d+) (%a+)") case1 → Primeira captura que equivale a pattern (%d+) (case1 = 50); case2 → Segunda captura que equivale a pattern (%a+) (case2 = reais); Referência [Hidden Content] [Hidden Content] Então é isso, espero ter sido o mais claro possivel, Qualquer dúvida, erro ou sugestão, poste !
  10. Desafio Decodificação

    Eu desenvolvi uma função que codificou uma frase (string) qualquer nisto: 010101100110111101100011111010100010000001100100011001010111001101100011011011110110001001110010011010010111010100100000001110100110111100101100001000000111000001100001011100100110000101100010111010010110111001110011001011000010000001100001011100110010000001101100011001010111010001110010011000010111001100100000011000010010000001110011011001010110011101110101011010010111001000100000011100111110001101101111001000000111001111110011001000000111000001110010011000010010000001100110011010010110001101100001011100100010000001101101011000010110100101110011001000000110010011101101011001100110100101100011011010010110110000111010001000000110000101101100011000010110111101101100011000010110110001100001011010000111010101100101011010000111010101110101011010000111010101110101011010000111010101100101011011000110010101110100011100100110000101101000011001010110100001100101011010000110010101101000011001010110100001100101 A tarefa de vocês é desenvolver uma que decodifique isso, e descobrir a frase inteira que eu codifiquei, a função que voce fez tem que estar junta pra provar que alguem não fez por você, etc, etc, etc ... Dicas (vou colocando aos poucos) B inary Dig IT 8 bits 1 byte É bem fácil mesmo, se você pensar em uma coisa obvia, é isso ... Quem descobrir primeiro e postar a função junto com a frase leva 50V$ :coolface: (pode ser qualquer função, de qualquer maneira menos pog, desde que ela funcione) PS: Mock, ou qualquer um dos avançados, nao acabem com a graça por favor ._.
  11. Estou procurando Scripter's que SAIBAM fazer de tudo com .lua, E por favor, não postem suas sugestões e suas duvidas, não elogiem nem critiquem, se quiser fazer isso faça por PM ¬¬ Nome: Quantos anos meche com Script: Idade: E-mail:
×