Ir para conteúdo

Tibia Guitar Hero [0.36~0.4]


Night Wolf

Posts Recomendados

Fala pessoal do XT, hoje vim trazer pra vocês um sistema que eu desenvolvi nessa última semana e inclusive fiz um tópico na seção de show off (confira o tópico aqui) numa tentativa de agitar um pouco e prover uma certa especulação em relação ao sistema. Bom, eu to aqui hoje pra informar que deu mais que certo e que meu tópico humilde (que eu realmente acreditava que seria ignorado, ainda mais numa seção morta como aquela) teve uma repercursão enorme (inclusive indo parar no portal do XT xeyes.png )

Bom, toda pessoa quando faz um código espera que ele agrade aos demais e tenha um certo valor, e bem, vocês superaram minhas expectativas.. com isso nada mais justo do que compartilhar com essa comunidade que me recebeu tão bem aww.png .
Chega de falatório e vamos direto aos negócios:

  • Introdução:

O sistema em si é uma cópia dos jogos de ritmo (GuitarFreaks, Band Hero, Rocksmith e o próprio Guitar Hero). Neste jogo pequenas notas irão cair pela tela até atingir um local especial, onde você poderá usar as teclas (Shift + 7, Shift + 8, Shift + 9, ou apenas 7, 9 e 9 [com Num Lock desativado]) para escolher as direções que as notas estão afim de "ativá-las". Uma vez ativada a nota ela será "queimada" e será considerado 1 acerto. Caso você não consiga ativar a nota e ela passar direto, um efeito de fumaça indicará o "Miss", o mesmo vale para se você tentar ativar uma região sem notas.

  • Sistema de pontuação:

Haverão 3 classificadores estatísticos para cada música tocada, sendo eles:
Notas acertadas: O principal fator de ponto, ele que definirá seu recorde e o valor máximo q ele pode assumir será o número de notas da música.
Movimentos errados: Quantidade de movimentos que você fez para alguma região que não possuia notas, conta como pontuação punitiva.
Notas passadas/erradas: Quantidade de notas que você deixou escapar, note que as notas acertadas + notas passadas compõe o número total de notas da música.

Por enquanto o sistema não possui nenhum preço para se jogar mas também não possui nenhuma recompensa, fiz com o intuito de ser apenas um mini game divertido dentro do Tibia. Porém o código é livre e está disponibilizado aqui embaixo pra qualquer um modificar como desejar.

  • Video explicativo:



 

  • Dificuldades:

O mini game possui 3 dificuldades, porém essa quantidade é tão configurável quanto as pré definições de cada dificuldade. Além da quantidade de notas ser diferente, a velocidade com que elas descem e consequentemente o tempo que você tem pra acertá-las fica diminuido. irritated.png

 

  • Diferenciais:

Um forte diferencial desse sistema é que ele foi feito seguindo todas as regras possíveis pra melhorar seu desempenho, desde funções recursivas leves até separação em funções encapsuladas que carregam apenas as informações necessárias. O sistema contém também algumas seguranças que serão explicadas mais abaixo juntamente com o código para prevenir bugs e garantir diversão sem dores de cabeça!

  • Instalação (Map Editor):

Primeiramente faça uma área parecida com essa daqui:


UrKlHMe.png


Não precisa ser igualzinha, apenas seguir a mesma proporção

Agora use a ferramenta de No-Logout para setar os quadradinhos que contém UID e UID2 escritos como No-Logout, isso vai impedir que players desloguem e fiquem presos dentro da sala (se eles derem exit, quando eles relogarem estarão do lado de fora da sala)


ZPSRP3B.png

 

Ainda olhando a foto acima, coloque 42320 nos pisos que estão escritos UID, e 42319 no piso que contém UID2.

Nas alavancas, coloque uid 2819 em todas elas e coloque actionid 101 para a alavanca do fácil, 102 na alavanca do médio e 103 na do dificil;
A regra é sempre 100 + dificuldade, como nós estamos utilizando apenas 3 será do 101 ao 103.
Note que se você esquecer ou colocar uma dificuldade não existente o sistema adotará a dificuldade 1 como padrão para aquela alavanca.


wnKOx7t.png




Se chegou até aqui, meus parabéns. Muito provável que você tenha feito tudo certo. Agora vamos à parte do código.

  • Instalação (scripts):

Em actions.xml insira essa linha

<action uniqueid="2819" event="script" value="GHtest.lua"/>

Agora em data/actions/scripts crie um arquivo com extensão.lua e chameo de GHtest. Insira o seguinte bloco de instruções dentro dele:

 

local function isRoomEmpty() -- funcao que verifica se a sala nao esta ocupada
    return getGlobalStorageValue(19281) < 1 and true or false
end

local npos = {x = 141, y = 51, z = 7} -- posicao mais da esquerda que as notas nascem, as outras duas vao ser baseadas nessa daqui x = 142 e x = 143
local startPos = {x = 142, y = 58, z= 7} -- posicao que vc vai ao clicar na alavanca
local finalPos = {x = 145, y = 57, z= 7} -- poscao q vc vai ao terminar o tempo

local storage_point = 12721 -- storage que salva os pontos
local storage_erradas = 12722 -- storage que salva as notas erradas
local storage_passadas = 12723 -- storage que salva as notas que passaram

function onUse(cid, item, itemEx, fromPos, toPos)
	if isRoomEmpty() then
		doTeleportThing(cid, startPos)
		setGlobalStorageValue(19281, 1)
		setGlobalStorageValue(19282, 0)
		local d = dif[item.actionid - 100] and item.actionid - 100 or 1
		addEvent(function()
			setGlobalStorageValue(19281, 0)
			if isCreature(cid) then
				if getPlayerStorageValue(cid, storage_point) > getPlayerStorageValue(cid, recorde[d]) then
					setPlayerStorageValue(cid, recorde[d], getPlayerStorageValue(cid, storage_point))
				end
				setPlayerStorageValue(cid, storage_passadas, getGlobalStorageValue(19282))
				local msg = "Estatísticas da partida:\n\n| Notas acertadas: ".. getPlayerStorageValue(cid, storage_point) .."\n| Movimentos errados: ".. getPlayerStorageValue(cid, storage_erradas) .."\n| Notas passadas: ".. getPlayerStorageValue(cid, storage_passadas) .."\n\n| Seu recorde pessoal para esta dificulade é: ".. getPlayerStorageValue(cid, recorde[d]) .. ""			
				doShowTextDialog(cid, 2349, msg)
				doTeleportThing(cid, finalPos)
			end
		end, (#dif[d] + 9) * delay[d])
		for j = 1, #dif[d] do
			addEvent(function()
				if dif[d][j] ~= nil then
					callWave({x= npos.x + dif[d][j], y = npos.y, z = npos.z}, 0, 1679 + dif[d][j], delay[d], 19282)
				end
			end, (delay[d] + 30) * j)
		end
	else
		doPlayerSendCancel(cid, "The room is busy right now, try again later.")
    end
return true
end

 



Aproveite e já configure as posições npos, startPos e finalPos de acordo com as posições do seu map editor (olhe na segunda imagem para ver onde deve ser cada uma das posições com base na sala)

Feito isso crie um arquivo em data/lib com nome qualquer, aqui em casa eu utilizei o nome 120 - Guitar Hero Lib e a extensão.lua.
Coloque isto dentro desse arquivo e salve:

 

--[[ Lib for Guitar Hero: by Night Wolf (aka xWhiteWolf) and dalvorsn ]]


function callWave(pos, i, id, delay, gstr) -- funcao que carrega cada nota pra baixo
	if i > 0 then
		prevPos = {x = pos.x, y = pos.y - 1 + i , z = pos.z}
		local prevItem = getTileItemById(prevPos, id)
		if prevItem.uid > 0 then
			doRemoveItem(prevItem.uid, 1)
			if i == 7 then
				doSendMagicEffect(prevPos, 2)
				setGlobalStorageValue(gstr, getGlobalStorageValue(gstr) + 1)
			end
		end
	end
	if i < 7 then
		local cPos = {x = pos.x, y = pos.y + i, z = pos.z}
		local item = doCreateItem(id, 1, cPos)
		if i == 6 then
			doItemSetAttribute(item, "aid", 1010)
		end
        addEvent(callWave, delay, pos, i+1, id, delay, gstr)
	end		
end

function cleanRoom(npos)
	for x = 0, 2 do 
		for y = 0, 6 do 
			local pos = {x = npos.x + x, y = npos.y + y, z = npos.z }
			local tile_info = getTileInfo(pos)
			if tile_info.trashed then
				doCleanTile(pos)
			end
		end
	end
end

dif = { -- [dificuldade] = notas que serao tocadas (nil = vazio, 0 = primeira posicao, 1 = segunda e 2 = terceira)
	[1] = {nil,nil,0,1,2,nil,nil,2,1,1,0,0,2,0,1},
	[2] = {nil,nil,0,1,1,2,1,1,0,0,2,0,1,nil,1,2,1,1,0,0,2,0,1},
	[3] = {nil,nil,0,nil,1,nil,1,1,0,0,2,0,1,1,1,nil,0,2,1,1,0,0,2,1,1,0,nil,2,2,1,1,1,1,2}
}

delay = { -- delay entre cada nota de acordo com a dificuldade [dificuldade] = delay
	[1] = 500,
	[2] = 400,
	[3] = 300
}
	
recorde = { -- salva os recordes de cada dificuldade separadamente
	[1] = 12724,
	[2] = 12725,
	[3] = 12726
}
	

 



Agora adicione a seguinte tag em data/movements/movements.xml:

<movevent type="StepIn" uniqueid="42320;42319" event="script" value="GHTestmov.lua"/>

Por fim crie um arquivo chamado GHTestmov.lua em data/movements/scripts e preencha seu conteúdo com as linhas abaixo:

 

local itemid = 1680 --- coloque o id da nota do meio
local npos = {x = 141, y = 51, z = 7} -- posicao que ira nascer a primeira nota
local storage_point = 12721 -- storage que salva os pontos
local storage_erradas = 12722 -- storage que salva as notas erradas
local storage_passadas = 12723 -- storage que salva as notas que passaram

function onStepIn(cid, item, position, lastPosition, fromPosition, toPosition, actor)
	if item.uid == 42319 then
		if math.abs(fromPosition.x - toPosition.x) > 2 then
			cleanRoom(npos)
			setPlayerStorageValue(cid, storage_erradas, 0)
			setPlayerStorageValue(cid, storage_point, 0)
			return true
		end
	else
		local corrector = toPosition.x - fromPosition.x
		local checkItem = getTileItemById(toPosition, itemid + corrector)
		if checkItem.uid > 0 and checkItem.actionid == 1010 then
			doRemoveItem(checkItem.uid, 1)
			doSendMagicEffect(toPosition, 15)
			setPlayerStorageValue(cid, storage_point, getPlayerStorageValue(cid, storage_point) + 1)
		else
			doSendMagicEffect(toPosition, 2)
			setPlayerStorageValue(cid, storage_erradas, getPlayerStorageValue(cid, storage_erradas) + 1)
		end
		doTeleportThing(cid, fromPosition)
	end
return true
end

 



Aproveite para deixar a npos idêntica à npos que você configurou lá no actions se baseando na posição da sua sala no map editor.


------------------------ FIM ------------------
O sistema já deve funcionar como foi planejado, se você não manja de código ou quer o sistema exatamente como foi mostrado no vídeo você pode ignorar a parte abaixo.

  • Configurando seu sistema (básico):

Para as pessoas que querem configurar apenas as coisas básicas, você pode fazê-lo nas primeiras linhas de cada script (actions/movements) ou alterando diretamente na lib, irei ensinar passo a passo aqui oque significa cada coisa.

  • Alterando a lib

As coisas básicas que podem ser alteradas na lib são as seguintes:

dif = { -- [dificuldade] = notas que serao tocadas (nil = vazio, 0 = primeira posicao, 1 = segunda e 2 = terceira)
[1] = {nil,nil,0,1,2,nil,nil,2,1,1,0,0,2,0,1},
[2] = {nil,nil,0,1,1,2,1,1,0,0,2,0,1,nil,1,2,1,1,0,0,2,0,1},
[3] = {nil,nil,0,nil,1,nil,1,1,0,0,2,0,1,1,1,nil,0,2,1,1,0,0,2,1,1,0,nil,2,2,1,1,1,1,2}
}

delay = { -- delay entre cada nota de acordo com a dificuldade [dificuldade] = delay
[1] = 500,
[2] = 400,
[3] = 300
}

recorde = { -- salva os recordes de cada dificuldade separadamente
[1] = 12724,
[2] = 12725,
[3] = 12726
}

dif separa como será cada música de cada dificuldade, as notas sempre serão nesse exato formato. nil significa que não estarei usando posição nenhuma naquela linha, 0 significa a primeira posição (nota verde), 1 significa segunda opção (nota vermelha) e 2 significa terceira opção (nota azul). Eu aconselho a começar todas as músicas com 2 ou mais 'nil' para dar tempo de o player entender que vai começar. A distribuição que eu usei foi meio que aleatória então sinta-se a vontade pra mudar tanto o tamanho das musicas quanto a variedade de notas.

delay é a tabela que oganiza os delays de cada dificuldade, isso significa que para a dificuldade 1(fácil) nós temos 500 milisegundos para cada mudança de nota (1000 milisegundos = 1 segundo), ou seja, a cada 2 passadas de nota temos 1 segundo dentro da sala. No modo hard a cada 300 milisegundos mudamos a nota, deixando o jogo muito mais rápido e dificil.

recorde é a tabela que possui os storages que irão salvar os recordes nas respectivas dificuldades.

  • Alterando actions
    local storage_point = 12721 -- storage que salva os pontos
    local storage_erradas = 12722 -- storage que salva as notas erradas
    local storage_passadas = 12723 -- storage que salva as notas que passaram
    

    Apenas mude os storages

  • Alterando movements
    local itemid = 1680 --- coloque o id da nota do meio
    local npos = {x = 141, y = 51, z = 7} -- posicao que ira nascer a primeira nota
    local storage_point = 12721 -- storage que salva os pontos
    local storage_erradas = 12722 -- storage que salva as notas erradas
    local storage_passadas = 12723 -- storage que salva as notas que passaram
    

    aconselho mexer somente nos storages, mantendo igual à action.

 

 

 

 

Só abra o spoiler abaixo se você estiver descontente com a forma que seu código roda e tiver certeza absoluta de que você tem o conhecimento necessário para alterar as coisas que vou explicar.

 

  • Configurações (intermédiarias e avançadas)

Na lib ainda podemos definir comprimento da area que vamos utilizar, o padrão é 7 sqms mas podemos aumentar alterando a função callWave que está na lib.

 

function callWave(pos, i, id, delay, gstr) -- funcao que carrega cada nota pra baixo

if i > 0 then
prevPos = {x = pos.x, y = pos.y - 1 + i , z = pos.z}
local prevItem = getTileItemById(prevPos, id)
if prevItem.uid > 0 then
doRemoveItem(prevItem.uid, 1)
if i == 7 then
doSendMagicEffect(prevPos, 2)
setGlobalStorageValue(gstr, getGlobalStorageValue(gstr) + 1)
end
end
end
if i < 7 then
local cPos = {x = pos.x, y = pos.y + i, z = pos.z}
local item = doCreateItem(id, 1, cPos)
if i == 6 then
doItemSetAttribute(item, "aid", 1010)
end
end
if i < 7 then
addEvent(callWave, delay, pos, i+1, id, delay, gstr)
end
end

 

Nos locais que estão demarcados em vermelho você deve aumentar sempre seguindo a proporção, se coloca 9 no lugar do 7 o 6 deverá virar um 8. Arrume também no actions nessa parte aqui:

end, (#dif[d] + 9) * delay[d])

 

e coloque 2 números acima do numero de sqms que você irá percorrer. Se colocar 9 sqms, use 11 ali.
Note que o nosso sistema possui um sistema de clean antes de cada partida, esse sistema foi desenvolvido pelo nosso colega @dalvorsn e também se baseia no numero de sqms que o sistema possui. Altere nessa linha da lib

 

for y = 0, 6 do

Altere o 6 para o numero de sqms - 1. Se tiver 9 sqms vc coloca o 8 ali.


Ao chegar na posição que podemos tocar a nota, ela recebe um action id para garantir que pessoas não joguem pillows naquela posição e façam pontos de forma roubada, se quiser alterar o actionid utilizado mude na linha em verde, MAS LEMBRE-SE DE MUDAR TAMBÉM NESSA LINHA DO MOVEMENTS

if checkItem.uid > 0 and checkItem.actionid == 1010 then

 

 

Alterando as mensagens:

 

local msg = "Estatísticas da partida:\n\n| Notas acertadas: ".. getPlayerStorageValue(cid, storage_point) .."\n| Movimentos errados: ".. getPlayerStorageValue(cid, storage_erradas) .."\n| Notas passadas: ".. getPlayerStorageValue(cid, storage_passadas) .."\n\n| Seu recorde pessoal para esta dificulade é: ".. getPlayerStorageValue(cid, recorde[d]) .. ""
doShowTextDialog(cid, 2349, msg)

 

a primeira linha são os textos (o \n serve para pular linha)
a segunda linha em azul indica o id do item que será mostrado na janela ao te dar as estatísticas, utilizei o item 2349 que é a blue note.

 

 

Se você achar que o sistema está com problema para reconhecer notas iguais seguidas, procure no actions essa linha aqui

 

end, (delay[d] + 30) * j)

e ali no 30 coloque um numero maior (tente fazer algo menor que 100 para evitar muita diferença entre as chamas de nota e as transições de nota). No meu servidor eu uso 20, coloquei 30 pra vocês aqui mas alguns servers mais lagados podem precisar de numeros em torno de 50.

Para alterar os ids utilizados você deve modificar a função callWave, o parametro dela recebe a posição que a nota deverá ir (0, 1 ou 2) e soma no id do pillow.
1679 é o id que será usado caso a nota seja 0
1680 é o id que será usado caso a nota seja 1
1681 é o id que será usado caso a nota seja 2.

1679 + dif[d][j] 

Altere tanto essa linha do actions

callWave({x= npos.x + dif[d][j], y = npos.y, z = npos.z}, 0, 1679 + dif[d][j], delay[d], 19282) 

quanto o itemid no movements

local itemid = 1680 --- coloque o id da nota do meio

Por fim, se vc for alterar os uniqueids utilizados na tag do movements.xml, não esqueça de alterar também no script do movements.

 

 

if item.uid == 42319 then

<movevent type="StepIn" uniqueid="42320;42319" event="script" value="GHTestmov.lua"/>

 

 



Espero que vocês tenham curtido, façam um bom uso e qualquer dúvida postem nos comentários abaixo.

Agradecimento ao @dalvorsn pela função que limpa a sala antes de começar o jogo e ao pessoal do servidor Refugia que fez um script de guitar hero lá e me deu a idéia. Abraços do Lobo. laugh.png

 

Editado por Night Wolf
Link para o comentário
Compartilhar em outros sites

  • Administrador

73QrLPZ.png



Parabéns pelo ótimo sistema, eu já esperava algo assim vindo de você.


Espero que a galera edite e utilize, nunca tinha visto isso pra Tibia antes. (Quem sabe surge um otc com som pro evento rs)


Link para o comentário
Compartilhar em outros sites

se rodar isso no otc é só colocar as funções de audio.play que dá pra fazer tocar via notas uma musica OU deixar a musica tocando enquanto vc tá lá e soltar um som de erro quando errar as notas, ficaria muito bom ^-^

Link para o comentário
Compartilhar em outros sites

Um possível bug que eu vi no vídeo: o record individual de cada dificuldade está "globalizado" em ambas as 3 o recorde é o mesmo. Não se tornando individual por dificuldade.

 

Ex.: 10 na fácil, 15 na média e 5 na difícil. Estão todas com 10, no caso o primeiro recorde.

 

Se não for isso, desculpe, rs. Ótimo sistema!

Link para o comentário
Compartilhar em outros sites

@@Lumus, as duas primeiras vezes no vídeo eu fui no easy e meu recorde lá é 11 (numero máximo de notas) mesmo jogando e errando tudo o recorde ja tá salvo. Na ultima vez que fui no hard e aí meu recorde ficou 19 naquela dificuldade. É diferente mesmo.. não tá bugado não

Link para o comentário
Compartilhar em outros sites

^ remove essa linha do seu movements

 

seu sv nao tem a função que o dalvorsn utilizou na função, mas isso não afeta muita coisa.

saiu os erros obg, mas vc poderia me falar no que afetara tanto se remover essa linha ? tipo oque acontece ?

Link para o comentário
Compartilhar em outros sites

o sistema auto limpava a sala antes de qualquer inicio de musica, agr ele não vai limpar mas isso pouco afeta o jogo em si. Os cleans do próprio servidor devem dar conta de remover qualquer lixo que os players venham a jogar na sala

Link para o comentário
Compartilhar em outros sites

Olhando as scripts do lobo agente aprende muitas coisas. Espero um dia chegar ao nível em scripts igual ao dele. Mais cada vez que vejo uma script Nova dele agente se surpreende mais ainda.

Link para o comentário
Compartilhar em outros sites

×
×
  • Criar Novo...