Jump to content

Pasta Data - Intermediario De Lua


tibiaa4e

Recommended Posts

Pasta Enciclopedia com todos os links de outros tutoriais !

http://www.xtibia.com/forum/Pasta-Data-Enc...r-E-t99746.html

 

Tutorial de Lua (Intermediario)

 

Bem aqui meu primeiro tuto como colaborador.

Esse tutorial tenta melhorar seus conhecimentos sobre lua, facilitar os proximos scripts e até melhor entender alguns

scripts mais avançados.

Aqui terá algumas noções de for,while,repeat,vetores e o addevent que não vem do Lua mais achei apropriado explica-lo aqui.

 

O problema é que para saber addevent tem que saber criar funções, e para isso é bom saber sobre escopos. O que sempre é ensinado após

ou antes dos loopings. Então vamos fazer isso tudo junto.

 

Escopo e variaveis locais

Para melhor explicar os loopings, é bom você entender o que seria escopo e as variaveis locais. Praticamente escopo só serve para variaveis

locais mesmo (pelo menos não lembro outro motivo pra ele). Veja esse exemplo

 

 if item.uid == 2300 then --inicio escopo 1
local escopo1 = 2500
queststatus = getPlayerStorageValue(cid,2300)
	if queststatus == -1 then --inicio escopo 2
		local escopo2 = 3000
		if playerCap >= itemWeight then --inicio escopo3
			local escopo3 = 2000
			doPlayerSendTextMessage(cid,24,"You have found a demon helmet.")
			doPlayerAddItem(cid,2493,1)
			setPlayerStorageValue(cid,2300,1)
		else
			doPlayerSendTextMessage(cid,24,"You have found a demon helmet. Weighing 29.50 oz it is too heavy.")
		end --fim escopo 3
	else
		doPlayerSendTextMessage(cid,24,"The chest is empty.")
	end --fim escopo 2
end --fim escopo 1

 

No caso, usei essas variaveis locais, para tenta explicar o que é escopo. Cada variavel local indica o escopo existente. Escopo é um espaço

do script, normalmente entre condicionais ou loopings. Os comentarios indicam inicio e fim de cada escopo. No caso de otserver, escopo não chega

a ser muito util, porém ajuda nas outras linguagens e ensina como usar as variaveis locais.

 

A importancia da variavel local, é fazer ela valer apenas no escopo, para não haver confusões de 2 scripts correntes usarem a mesma variavel

e ferrar seu servidor.

 

 

Laços de Repetição (looping)

 

Os loopings, são condicionais usadas para facilitar certas ações, e não deixar os script com um tamanho gigantesco, os mais usados são o

for,while e repeat.

Em tese eles fazem a mesma coisa, que é repetir tudo que está dentro do escopo, porém cada uma tem seu jeito de fazer.

 

For

 

O for talvez seja o looping mais usado. O que ele faz é repetir todo seu escopo o numero de vezes mandando.

Vou dar a sintaxe dele.

 

	for variavel = numero inicial, numero final do
	comandos
end

 

 

Em português estruturado :

	para variavel = numero inicial, numero final faça
	comandos
fim

 

 

Um exemplo pratico :

 

	for i= 1,24 do
	doPlayerAddItem(cid,2150,1)
end

 

Esse script acima vai adicionar 24x o item 2150 ao player. Então no caso você economizo no minimo 21 linhas. Claro que essa estrutura

não serve so para isso.

Lembrando que esse i não é obrigatorio, ele é a chamada variavel de controle. Até hoje não sei porque todo mundo usa i como variavel

de controle do for.

 

Você também pode fazer um for mais util do que esse, ao final do script mostrarei outros exemplo.

 

while

O meu looping favorito de se usar, também é muito utilizado. Ele repete o seu escopo, enquanto a condicional for verdadeira.

 

Exemplo :

 

	while (variavel == 60) do
	comandos
end

 

Ou :

 

	enquanto (worldtime > 60) faça
	comandos
fim

 

Ai no caso enquanto a variavel for igual a 60 ele irá executar todos os comandos dentro dele. O while se assemelha um pouco ao if, pois deve

se usar sinais matematicos tem o and e o or.

 

Eu achei um exemplo na função :

 

function getTibiaTime()
local worldTime = getWorldTime()
local hours = 0
while (worldTime > 60) do
	hours = hours + 1
	worldTime = worldTime - 60
end

return {hours = hours, minutes = worldTime}
end

 

 

Então enquanto o worldtime for menor que 60, ele irá pegar a hours e somar + 1, depois pegará o worldtime e diminuirá em 60

Ou seja ele irá contar as horas em 3 linhas. O que será uma tarefa impossivel sem um looping. E veja que faze-la no for também seria

dificil, já que teriamos que saber que horas seria. O que seria anormal, pois para que saber a hora, se ja sabemos ???

 

 

repeat

Esse ultimo looping e não menos importante, ele faz as repetições até que aconteça algo.

 

	repeat
comandos
until ( variavel == 1)

 

Ou :

 

	repita
comandos
atéque (variavel == 1)

 

Aqui nos meu ot ainda não achei nenhum com repeat, porém pode ser que ache algum util para ele. Dá para usar o exemplo do while aqui

 

	repeat
	hours = hours + 1
	worldtime = worldtime - 60
until (worltime >60)

 

Lembrando que o repeat não tem end, se vc colocar vai dar erro xD.

 

Aqui você viu os três loopings mais importantes, e sem duvidas isso ajudará a compreender alguns scripts e até diminuir outros.

Agora quando usar cada cabe a você decidir, já que cada um tem vantagens e desvantagens.

 

Um exemplo é esse desafio. Adicionar Magic Plate armors no player até a capacidade acabar ou no maximo 30 delas.

 

com for :

	for i=1,30 do
	if getPlayerFreeCap(cid) >= 85.00 then
		doPlayerAddItem(cid,2472,1)
	end
end

 

com while :

	while (cap >= 85.00) and (mag <=30) do
	cap = getPlayerFreeCap(cid)
	mag =mag+1
	doPlayerAddItem(cid,2472,1)
end

 

com repeat :

	repeat
	cap = getPlayerFreeCap(cid)
	doPlayerAddItem(cid,2472,1)
	mag =mag+1
until (cap >= 85.00) and (mag <=30)

 

Veja que no for eu nem tentei (até pq n lembrava maneira) de colocar até a capacidade acabar. Porém para adicionar um

numero exato de itens ou sequencia ele é melhor que os outros.

Porém o while e o repeat se dão melhor ao adicionar até a capacidade acabar.

 

 

Agora que você ja entende, ou pelo menos ficou menos confuso, vou tentar explicar vetores.

 

Vetores e Matrizes

 

Alguns devem se perguntar que escremento é esse ? Entretanto, devem conhecer pelo nome array.

 

Agora o vetor é uma variavel que armazena varias variaveis. Por exemplo imagine uma tabela do excel, as linhas seriam os vetores.

Ou seja cada linha pode guardar varios dados.

 

Já a matriz seria colunas e linhas, porém no otserver dificilmente ou nunca vc irá usar matriz, até porque LUA não prescisa

declarar variavel e acho que matriz nem existe no LUA.

 

Voltando aos vetores, existem algumas vantagens, ao usa-los. Muitos dizem que ocupa menos memoria ram, é verdade, porém

ao menos que você tenha 2 mb de ram, não irá fazer diferença nenhuma.

Eu acho a principal vantagem é poder deixar mais organizado e até facilitar a compreensão de scripts.

 

Por exemplo vou mostrar um script de quando eu era iniciante.

 

--function by ta4e--
--for tibia 7.92--
function onUse(cid, item, frompos, item2, topos)

presente = math.random(1,11)
pos = getPlayerPosition(cid)

--surprise bag blue--
if presente == 1 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,2687,10) --cookie
doRemoveItem(item.uid,1)

elseif presente == 2 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,6394,1) --cream cake
doRemoveItem(item.uid,1)

elseif presente == 3 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,6280,1) --party cake
doRemoveItem(item.uid,1)

elseif presente == 4 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,6574,1) --bar of chocolate
doRemoveItem(item.uid,1)

elseif presente == 5 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,6578,1) -- party hat
doRemoveItem(item.uid,1)

elseif presente == 6 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,6575,1) -- red baloon
doRemoveItem(item.uid,1)

elseif presente == 7 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,6577,1) -- green baloon
doRemoveItem(item.uid,1)

elseif presente == 8 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,6569,3) -- candy
doRemoveItem(item.uid,1)

elseif presente == 9 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,6576,1) -- firework rocket
doRemoveItem(item.uid,1)

elseif presente == 10 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,6572,1) -- party trumpet
doRemoveItem(item.uid,1)

elseif presente == 11 then
doSendMagicEffect(pos,27)
doPlayerAddItem(cid,2114,1) -- piggy bank
doRemoveItem(item.uid,1)
end

return 1
end

 

Enormee e grotesco. Agora veja o que a SVN fez (roubou meu script ¬¬) diminuiu xD

 

local bluePresent = {2687, 6394, 6280, 6574, 6578, 6575, 6577, 6569, 6576, 6572, 2114}
local redPresent = {2152, 2152, 2152, 2153, 5944, 2112, 6568, 6566, 2492, 2520, 2195, 2114, 2114, 2114, 6394, 6394, 6576, 6576, 6578, 6578, 6574, 6574}

function onUse(cid, item, fromPosition, itemEx, toPosition)
local count = 1
if item.itemid == 6570 then
	local randomChance = math.random(1, 11)
	if randomChance == 1 then
		count = 10
	elseif randomChance == 2 then
		count = 3
	end
	doPlayerAddItem(cid, bluePresent[randomChance], count)
elseif item.itemid == 6571 then
	local randomChance = math.random(1, 22)
	if randomChance > 0 and randomChance < 4 then
		count = 10
	end
	doPlayerAddItem(cid, redPresent[randomChance], count)
end
doSendMagicEffect(fromPosition, CONST_ME_GIFT_WRAPS)
doRemoveItem(item.uid, 1)
return TRUE
end

 

Só por curiosidade esses true e false são as variaveis boolenanas. Onde true vale 1 e false 0.

 

Esse ainda funciona com a red. Tirando a parte da red surprise bag, os dois funcionam da mesma forma, porém para quem entende

scripts o segundo é bem mais facil.

 

Bem a sintaxe da matriz é muito facil.

nome da matriz = {primeiro item,segundo item}

 

Para usar deve se usar como se fosse a variavel mais o numero da "coluna".

 

Por exemplo

 

local itens = {"boots of haste","giant sword"}

if math.random (1,3) == 1 then
	doPlayerAddItem(cid,itens[1],1)
else
	doPlayerAddItem(cid,itens[2],1)
end

 

Veja se a sorte do player for 1 ele adiciona o item boots of haste, se for 2 ou 3 ele adiciona a giant sword. Claro que esse

scripts não iria funcionar. Porém é so um exemplo para melhor explicar o bendito vetor.

 

Porém acho que é mais comum você observar o vetor sendo usado para indicar varios itens ao inves de apenas um.

 

local useWorms = FALSE
local waterIds = {493, 4608, 4609, 4610, 4611, 4612, 4613, 4614, 4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624, 4625}

function onUse(cid, item, fromPosition, itemEx, toPosition)
if isInArray(waterIds, itemEx.itemid) == TRUE then
	if itemEx.itemid ~= 493 then
		if useWorms == FALSE or useWorms == TRUE and doPlayerRemoveItem(cid, ITEM_WORM, 1) == TRUE then
			if math.random(1, (100 + (getPlayerSkill(cid, SKILL_FISHING) / 10))) <= getPlayerSkill(cid, SKILL_FISHING) then
				doPlayerAddItem(cid, ITEM_FISH, 1)
			end
			doPlayerAddSkillTry(cid, SKILL_FISHING, 1)
		end
	end
	doSendMagicEffect(toPosition, CONST_ME_LOSEENERGY)
	return TRUE
end
return FALSE
end

 

Nesse caso o autor do script ele diminui varias linhas usando o vetor.

 

	if isInArray(waterIds, itemEx.itemid) == TRUE then

 

 

No Português Estruturado :

	Se estiver no vetor (nome do vetor, uid ) == verdadeiro faça

 

Ou seja tudo que tiver no vetor waterIds e for itemEx (item2) vai ser considerado.

 

O vetor tem essas duas utilidades nos otserver, se você observar bem o seu uso vem sendo aumentado a algum tempo. E

não domina-lo é um erro para grandes scripts.

Um bom exemplo é meu script da arena que na versão 3.0 os três scripts de movements tinham 1200 linhas, na 4.0 com uso

de umas funções e if melhorados diminui para 400. E na futura versão 4.0 Virarão torno de 80 linhas, com uso dos arrays e for.

 

 

Funções

 

Criar funções é uma coisa maravilhosa, se você costuma sempre incrementar algo no seu otserver é muito util saber criar algumas delas.

Por exemplo todos esses doPlayerAddItem e doSetPlayerStorageValue são funções. Quem leu o segundo tutorial entendeu as funções de otserver.

 

E pelo que me lembre expliquei que podemos dividir as funções em dois grupos. As retornam valores e as que não.

Porém na verdade 99% das funções retornam valores, porém torno de 60% são erros. Por exemplo se vc manda o otserver adicionar

um item que não existe ele retorna uma mensagem de erro. Porém essa mensagem é inutil para o script, só mostra que você esqueceu

ou é burro (xD).

 

Um exemplo de função que retorna o seu dinheiro no player.

 

	function getPlayerMoney(cid)
return ((getPlayerItemCount(cid, ITEM_CRYSTAL_COIN) * 10000) + (getPlayerItemCount(cid, ITEM_PLATINUM_COIN) * 100) + getPlayerItemCount(cid, ITEM_GOLD_COIN))
end

 

(Observe as frescuras da SVN de tentar deixar o script bom para iniciantes, e depois eles usam variaveis que só tem nas sources.)

 

Se você gosta de frescura pode "socar" variaveis no global.lua com nomes para ser ids. Eu ja odeio isso xD.

Voltando ao script, ao usar essa função, ele irá retornar a quantidade de din din que vc tem

Sendo usada assim.

 

dinheiro = getPlayerMoney(cid)

doCreatureSay(cid,dinheiro,TALKTYPE_ORANGE2)

 

Ou do jeito que você quiser, veja que essa função retorna algo. Espero que entendam essa parte.

 

Agora a vantagem de fazer uma função ? Pode tirar a repetição de alguma coisa. Por exemplo :

 

 if item.uid == 2300 then
 queststatus = getPlayerStorageValue(cid,2300)
 if queststatus == -1 then
  if playerCap >= itemWeight then
doPlayerSendTextMessage(cid,24,"You have found a demon helmet.")
doPlayerAddItem(cid,2493,1)
setPlayerStorageValue(cid,2300,1)
  else
doPlayerSendTextMessage(cid,24,"You have found a demon helmet. Weighing 29.50 oz it is too heavy.")
  end
 else
  doPlayerSendTextMessage(cid,24,"The chest is empty.")
 end

 

Cada bloco desse é uma quest do meu otserver, e pelo que contei aqui tenho 90. Imagine que lindo para eu me achar ?

 

Criei so por diversão uma função.

 

function doQuest(cid, item, count, storage, value, take)
	local itemWeight = getItemWeightById(item, 1)
	local playerCap = getPlayerFreeCap(cid)

	if getPlayerStorageValue(cid, storage) == -1 then
		if playerCap >= itemWeight then
			doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, 'You have found a ' .. getItemNameById(item) .. '.')
			container = doPlayerAddItem(cid, item, count)
			setPlayerStorageValue(cid, storage, value)
		else
		doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, 'You have found a ' .. getItemNameById(item) .. ' weighing ' .. itemWeight .. ' oz it\'s too heavy.')
		end
	else
	doPlayerSendTextMessage(cid,24,'The ' ..take.. ' is empty.')
	end
end

 

E agora cada linha de quest minha fica.

 

if item.uid == 2300 then
doQuest(cid,2493,1,2300,1,'chest')
end

 

Melhor ? O unico problema é que no TFS 0.3.0+ ela da um erro (O bau abre como chest, porém a quest é feita normalmente.)

 

Essa é uma função media, porém se você leu todos meus tutoriais ja entende ela facinho.

Mais vou explicar como fazer passo a passo ela.

 

	function doQuest(cid, item, count, storage, value, take)

 

Aqui você indica como ela será usada no script. Os nomes não importam, o que importa é vc usar eles em todo o script o mesmo.

A ideia aqui é pegar tudo que vc prescisa.

 

Item : É o id do item que o bau irá dar.

count : A quantidade desse item.

storage : É o storage value adicionado.

value : O valor do storage adicionado.

take : O nome do lugar que vc pega.

 

Claro que eu fiz uma que atendesse todas minhas necessidades. O value e o take podem ser facilmente excluidos.

Depois que declarei todos os requesitos devemos passa a parte de como fazer.

 

local itemWeight = getItemWeightById(item, 1)

local playerCap = getPlayerFreeCap(cid)

 

if getPlayerStorageValue(cid, storage) == -1 then

if playerCap >= itemWeight then

doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, 'You have found a ' .. getItemNameById(item) .. '.')

container = doPlayerAddItem(cid, item, count)

setPlayerStorageValue(cid, storage, value)

else

doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, 'You have found a ' .. getItemNameById(item) .. ' weighing ' .. itemWeight .. ' oz it\'s too heavy.')

end

else

doPlayerSendTextMessage(cid,24,'The ' ..take.. ' is empty.')

end

 

.. variavel.. é a chamada junção de string. Ele junta a variavel entre .. e adiciona a frase.

 

Veja que usei todas as variaveis, usadas na função aqui dentro.

Uma das regras da programação é : A maquina é burra, você tem que dar passo a passo o que ela deve fazer.

 

Ou seja não esqueça de nenhum passo nas funções. Um erro gravissimo é o cara esquecer de meter no cid no começo. Se vc esquecer

quando for rodar no otserver, vai dar milhões de erros, e tudo porque você esqueceu o cid.

 

Lembrando novamente que não importam os nomes, eu poderia fazer isso.

 

	function doQuest(macaco, lixo, quantidade, seila, tipo, ultima)

 

Se eu colocasse esses nomes no motor dele, iria funcionar normalmente.

E também você pode usar funções suas dentro de funções suas, que irão funcionar normalmente.

 

O lugar mais adequado de coloca-las é no global.lua. Se vc usa the forgotten server coloque-as no funcitons.lua.

Porém se você for mais alienado pode criar um arquivo para suas variaveis. É só adicionar no global.lua essa linha

 

	dofile('data/meuarquivo.lua')

 

Isso se ele tiver na pasta data (de preferencia dentro dela.)

Mais uma inutilidade que você aprende aqui.

 

 

Depois dessa volta enorme que demos aqui. É hora de explicar o bendito addEvent.

 

addEvent e stopEvent

 

Bem essa parte tem até certos creditos ao tutorial do noobinhu, pois eu não sabia que tinha stopEvent. Porém eu vou explicar da

minha maneira. Também ao meu grande amigo Soulblaster que foi que me ensino a base sobre isso.

 

O dificil do addEvent é explicar como o cara deve fazer a função. Já que vcs devem saber, o resto é facil.

 

A função do addEvent é fazer rodar uma função num certo tempo. Ao contrario do que muitos pensam (até eu), colocar uma função depois do

addEvent não fará ela rodar após ele.

 

exemplo :

	addEvent(lever1, 5000)
	doSendMagicEffect(xadrexpos,12)

 

Esse doSend... rodará antes dos 5 segundos. Ou seja, tudo que tenha que rodar em 5 segundos deverá estar na função.

Isso vale também para varios addEvents.

 

	addEvent(tp1, 1000,cid)
addEvent(tp2, 1000,cid)
addEvent(tp3, 1000,cid)
addEvent(tp4, 1000,cid)

 

No caso acima todos irão rodar juntos, já que ele não espera um acabar para rodar o proximo.

 

	addEvent(tp1, 1000,cid)
addEvent(tp2, 2000,cid)
addEvent(tp3, 3000,cid)
addEvent(tp4, 4000,cid)

 

Esse seria o efeito certo.

 

Agora que dei os macetes, explicarei a sintaxe.

 

addEvent(função,tempo em milessegundos,parametros)

 

Milessegundos é 1000 = 1 segundo e assim vai, os parametros são os das funções. Se houver apenas 1 parametro coloque-o direto. Se houver varios

deve ser colocar entre chaves.

 

addEvent(tp1, 1000,{cid=cid, topos= topos}

 

Ou fazer o que muitos fazem :

 

p = {cid=cid,topos=topos}
addEvent (tp1, 1000,p}

 

Esse p também é opcional, e não sei pq o usam sempre...

 

 

Isso é mais simples, e você deve usar todos os parametros da função.

Lembra que falei que o nome não importa na função ? Aqui meio que importa já que você deve declarar tudo. É mais ou menos como se fosse

usa-la em um script.

 

Exemplo :

 

p = {cid = cid, item = 2493, count = 1, storage = 2300, value = 1, take = "chest"}
addEvent (doQuest, 3000 , p)

 

Facil ? Eu acho que sim.

 

O stopEvent é simples também

 

stopEvent (função )

 

Nunca usei, será util se você colocar o addEvent em um looping ou sei lá.

 

E digo mais que no tempo que comecei tivesse um tuto porco desse, eu acho que seria m scripter bem melhor.

 

Bem espero que esse tutorial seja util ao todos que leram, qualquer duvida ou dificuldade reportem, se gostarem não deixem de comentar.

Não sei se ficou muito bom (até pq são 02:43 mins da madrugada, e como não bebo e não tem coca-cola, tomei uns 30 copo de leite). E aguardem os proximos!!!

Edited by tibiaa4e
Link to comment
Share on other sites

  • 3 weeks later...

x.x booaaa gostei mais vo tenk da uma olhada nas outras partes pra mim entender tudo. depois edito xD

 

---EDIT----

 

sera que voce poderia coloca uns "exercicios", pra mim é mais facil de aprender fazendo exercicios.

 

tambem nao entendi uma coisa,, o storage, ele sempre é 2300?? ou ele muda? por exemplo:

setPlayerStorageValue(cid,2300,1)

e o numero "1" ao lado do 2300, oque ele é ? ele muda ?

 

Desculpa o incomodo...

Edited by ricktcs
Link to comment
Share on other sites

@rickts

 

Exercicios será depois... nos tutos de actions e movements...

 

E esse storage 2300 muda sim, ele seria um valor fixo para controle de quests

 

Vc pode usar de 1000 a 65535 e esse 1 seria o valor desse numero, é usado para questlogs e simplificar scripts

Link to comment
Share on other sites

  • 10 months later...

Perfeitos os tutoriais! :D

Ajuda muito a quem não entende do assunto, e até a quem entende!

Só corrige aqui ó:

 

com repeat :

    repeat
        cap = getPlayerFreeCap(cid)
        doPlayerAddItem(cid,2472,1)
        mag =mag+1
    until (cap >= 85.00) and (mag <=30)

 

na verdade era pra ser "or" ao invés de "and"

Ficaria assim:

 

com repeat :

    repeat
        cap = getPlayerFreeCap(cid)
        doPlayerAddItem(cid,2472,1)
        mag =mag+1
    until (cap >= 85.00) or (mag <=30)

Link to comment
Share on other sites

  • 1 year later...
×
×
  • Create New...