O Editor de Roteiros
Para editar os scripts do seu jogo, clique no link «Mod (API) Scripts» na página «Game Details» (Detalhes do jogo) do seu jogo (no mesmo local onde se encontram opções como «Chat Log» (Registo de chat) e «Copy/Extend Game» (Copiar/Estender jogo)). Serão apresentadas várias funcionalidades:
- Uma lista de separadores na parte superior. O seu jogo pode ter vários scripts para facilitar a organização. Observe que todos os scripts continuarão a ser executados no mesmo contexto, o que significa que não deve ter vários scripts a tentar sobrescrever os mesmos valores ao mesmo tempo, pois poderá obter resultados indesejados.
- Um editor de código de script. Pode utilizar este editor ou editar os seus scripts num editor externo à sua escolha e, em seguida, colá-los aqui.
- Um "Console Mod (API)" localizado na parte inferior (veja abaixo).
Sempre que clicar no botão «Guardar Scripts», a área restrita do seu jogo seráreiniciada(perdendo quaisquer dados na memória que não tenham sido mantidos no objetode estadoou nos objetos Roll20). Isto também se aplica se adicionar um novo script, excluir um script ou alternar um script para ativá-lo/desativá-lo.
A Consola Mod (API)
A Consola Mod (API) é a "janela" para os seus scripts. Como os scripts Mod (API) são executados numa área restrita, não é possível aceder diretamente a eles enquanto estão em execução para visualizar informações sobre os resultados ou erros do script. A Consola Mod (API) exibe essas informações fora da área restrita para que possa visualizá-las enquanto edita os seus scripts. Todos os comandos log()serão exibidos aqui, bem como quaisquer erros encontrados durante a execução dos seus scripts. Para obter mais informações, consulte o artigo sobre Depuração de scripts.
Scripts reativos: escutar eventos, modificar objetos
O primeiro (e mais simples) tipo de utilização do Mod (API) consiste em reagir às alterações na mesa e, em seguida, responder com funcionalidades adicionais aos objetos alterados. Este tipo de script é composto por várias funções que monitorizam os eventos que ocorrem durante o jogo. Em seguida, ele modificará os objetos que são passados durante esses eventos, o que alterará o que ocorre na mesa.
Um script básico que move uma peça adicionais 5 pés (assumindo configurações padrão da página) seria:
on("change:graphic", função(obj) {
obj.set({
left: obj.get("left") + 70
});
});
Como pode observar, criámos uma função simples que será executada sempre que o evento change:graphic for detetado. A função recebe o objeto gráfico obj. Para fazer uma alteração, basta modificar o obj usando a função set — quaisquer propriedades que alterarmos serão detectadas e alteradas na mesa.
setegetpara definir e obter os valores atuais dos objetos, caso contrário, as alterações não serão guardadas. (Veja abaixo uma lista dos tipos de objetos e suas propriedades, bem como uma lista de todos os eventos e quais argumentos cada evento é passado.)Uma observação sobre funções de utilidade
É evidente que o exemplo anterior não é extremamente útil, pois adiciona sempre 70 pixels à localização do token. No entanto, o que ocorre se o utilizador tiver alterado a sua escala de forma que 5 pés correspondam a 140 pixels? A API Roll20 oferece várias funções úteis para auxiliar neste e em outros cenários comuns. Vamos modificar o nosso exemplo anterior para utilizar afunção distanceToPixels, que nos informará quantos pixels correspondem a «cinco pés» (ou polegadas, ou metros, ou qualquer outro tipo de distância que tenha sido definido) na superfície da mesa.
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + distanceToPixels(5);
});
});
Agora, se a página atual estiver configurada para utilizar o tamanho padrão da grelha,distanceToPixels(5);continuará a retornar 70 pixels, mas se a página estiver configurada para ter uma escala duas vezes maior que o normal, retornará 140.
É sempre recomendável utilizar funções utilitárias sempre que estiverem disponíveis para evitar que o seu script seja interrompido caso as configurações de uma página ou token sejam alteradas.
Scripts proativos: execute tarefas sem a intervenção do utilizador
Além de reagir aos eventos dos utilizadores, também é possível realizar ações automaticamente com a API que não estão vinculadas a um evento específico dos jogadores. Por exemplo, vamos considerar um token que patrulha o mapa de um lado para o outro.
Observação: Embora este tipo de script não dependa da interação do utilizador, os scripts Mod (API) para o seu jogo só serão executados quando pelo menos uma pessoa estiver conectada ao seu jogo.
on("ready", function() {
//Aguardar até que o evento ready seja disparado para sabermos que o jogo está completamente carregado.
Obtenha uma referência ao nosso token de patrulhamento.
var patroltoken = findObjs({_type: "graphic", name: "Guarda A"})[0]; //Sabemos que existe um token no jogo chamado "Guarda A".
var direção = -1*distanceToPixels(5); //Ande 70 pixels para a esquerda.
var passosdados = 0; //Quantos passos já percorremos na direção atual?
setInterval(função() {
if(passosdados > 3) {
//Mude de direção!
direção = direção * -1; //irá "inverter" a direção em que estamos a caminhar
passos dados = 0; //reinicializa os passos para 0.
}
patroltoken.set("left", patroltoken.get("left") + direction); //walk!
stepstaken++;
}, 5000); //executar uma ação a cada 5 segundos
});
Um Tratado sobre Funções Assíncronas
Uma função assíncrona é aquela que retorna o controlo da thread para o escopo de chamada imediatamente e executa alguma tarefa em segundo plano. Aqui está um exemplo muito simples e fácil de entender que pode ser inserido na guia de scripts Mod (API):
on('load',function(){
log('Escopo pai - Antes da chamada para a função assíncrona.');
setTimeout(function(){
log('Escopo da função assíncrona - Executando a função assíncrona.');
},10 /* 10 milissegundos */);
log('Escopo pai - Após a chamada para a função assíncrona.');
});
No registo Mod (API), poderá observar algo semelhante a isto:
"Âmbito pai - Antes da chamada para a função assíncrona." "Âmbito pai - após chamada para função assíncrona." Âmbito da função assíncrona - Executando a função assíncrona.
Ao analisar esse código, você pode pensar: "É claro que isso ocorrerá posteriormente, você instruiu para que fosse executado em 10 milissegundos, não é mesmo?". Aqui está um exemplo menos óbvio que apresentará as mesmas mensagens de registo:
on('load',function(){
log('Âmbito pai - Antes da chamada para a função assíncrona.');
sendChat('Função assíncrona','Avalie isto: [[1d6]]',function(msg){
log('Âmbito da função assíncrona - Executando a função assíncrona.');
});
log('Âmbito pai - após a chamada para a função assíncrona.');
Funções assíncronas são necessárias para evitar que a API fique travando constantemente. Se cada lançamento de dados fosse tratado de forma síncrona, a API ficaria extremamente lenta e sem resposta. Quase todas as funções que aceitam uma chamada de retorno são assíncronas. (Exceção para algumas das funções _.map, _.reduce, etc., que são exemplos de programação funcional em contraste com a programação procedural à qual a maioria das pessoas está acostumada.)