O Editor de Scripts
Para editar os scripts do teu jogo, clica no link "Mod (API) Scripts" na página de Detalhes do Jogo para o teu jogo (no mesmo local onde estão opções como "Chat Log" e "Copy/Extend Game"). Ser-lhe-ão apresentadas várias funcionalidades:
- Uma lista de separadores na parte superior. O seu jogo pode ter vários guiões para facilitar a organização. Note 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 substituir os mesmos valores ao mesmo tempo, caso contrário pode 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 depois colá-los aqui.
- Uma "Consola Mod (API)" localizada na parte inferior (ver abaixo).
Sempre que clicar no botão "Guardar Scripts", a caixa de areia do seu jogo seráreiniciada(perdendo todos os dados na memória que não tenham sido persistidos no objeto de estadoou em objectos Roll20). Isto também se aplica se adicionar um novo script, eliminar um script ou alternar um script para o ativar/desativar.
A Consola Mod (API)
A Consola Mod (API) é a "janela" para os teus scripts. Uma vez que os Scripts Mod (API) são executados numa sandbox, não tens acesso direto a eles enquanto estão em execução para ver informações sobre os resultados ou erros do script. A Consola Mod (API) mostra esta informação fora da sandbox para que a possas ver enquanto estás a editar os teus scripts. Todos os comandos log()
vão aparecer aqui, bem como quaisquer erros que ocorram durante a execução dos teus scripts. Para obter mais informações, consulteo artigo sobre Depuração de scripts.
Scripts Reativos: Ouça Eventos, Modifique Objetos
O primeiro (e mais simples tipo) de utilização de Mod (API) é reagir a alterações no tabletop e depois responder com funcionalidades adicionais aos objetos alterados. Esse tipo de script é composto por várias funções que ouvem eventos que ocorrem durante o jogo. Em seguida, ele irá modificar objetos que são passados durante esses eventos, o que alterará o que acontece no tabuleiro.
Um script básico que move uma peça mais 5 pés (considerando as configurações padrão da página) seria:
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + 70
});
});
Como você pode ver, criamos uma função simples chamada on, que será executada sempre que o evento change:graphic for ouvido. 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 no jogo de tabuleiro.
set
eget
para definir e obter os valores atuais dos objetos, caso contrário, suas alterações não serão salvas. (Veja abaixo uma lista dos tipos de objetos e suas propriedades, bem como uma lista de todos os eventos e os argumentos que cada evento recebe.)Uma Observação sobre Funções de Utilidade
Claro, o exemplo anterior não é muito útil porque sempre adiciona 70 pixels à localização do token. Mas e se o usuário tiver alterado sua escala para que 5ft seja 140 pixels? A API do Roll20 fornece várias funções de utilidade úteis para ajudar com isso (e outros) cenários comuns. Vamos modificar o nosso exemplo anterior para utilizar a funçãodistanceToPixels
, que nos dirá quantos pixels são "cinco pés" (ou polegadas, ou metros, ou qualquer outro tipo de distância que tenha sido definido) no tampo 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 dimensionamento de grelha predefinido,distanceToPixels(5);
ainda devolverá 70 pixels, mas se a página estiver configurada para ter uma escala com o dobro do tamanho normal, devolverá 140.
É sempre uma boa ideia usar funções utilitárias sempre que estiverem disponíveis para ajudar a evitar que seu script quebre se as configurações de uma página ou token mudarem.
Scripts Proativos: Faça Coisas Sem Intervenção do Usuário
Além de reagir a eventos do usuário, você também pode fazer coisas com a API automaticamente que não estão vinculadas a um evento específico dos jogadores. Por exemplo, vamos ter um token que patrulha de um lado para o outro no mapa.
Nota: Embora este tipo de script não dependa da interação do utilizador, os scripts Mod (API) para o teu jogo só vão ser executados quando pelo menos uma pessoa estiver ligada ao teu jogo.
on("ready", function() {
//Aguarde até que o evento ready seja disparado para sabermos que o jogo está completamente carregado.
//Obtenha uma referência ao nosso token de patrulha.
var patroltoken = findObjs({_type: "graphic", name: "Guard A"})[0]; //Sabemos que há um token no jogo chamado "Guard A".
var direction = -1*distanceToPixels(5); //Ande para a esquerda 70 pixels.
var stepstaken = 0; //Quantos passos já andamos na direção atual?
setInterval(function() {
if(stepstaken > 3) {
//Troque de direção!
direction = direction * -1; //irá "inverter" a direção que estamos andando
stepstaken = 0; //redefinir passos para 0.
}
patroltoken.set("left", patroltoken.get("left") + direction); //andar!
stepstaken++;
}, 5000); //tomar uma ação a cada 5 segundos
});
Um Tratado sobre Funções Assíncronas
Uma função assíncrona é aquela que retorna o controle da thread para o escopo de chamada imediatamente e realiza alguma tarefa em segundo plano. Aqui está um exemplo muito simples e fácil de entender que podes colar na aba de scripts Mod (API):
on('load', function() {
log('Escopo Pai - Antes da chamada da função assíncrona.');
setTimeout(function() {
log('Escopo da Função Assíncrona - Fazendo o trabalho da função assíncrona.');
}, 10 /* 10 milissegundos */);
log('Escopo Pai - após a chamada da função assíncrona.');
});
Na consola Mod (API), vais ver algo como isto:
"Escopo Pai - Antes da chamada da função assíncrona." "Escopo Pai - após a chamada da função assíncrona." "Escopo da Função Assíncrona - Fazendo o trabalho da função assíncrona."
Olhando para esse código, você pensa "Claro que vai acontecer depois, você disse para executar em 10 milissegundos, né?". Aqui está um exemplo menos óbvio que terá as mesmas mensagens de log:
on('load', function() {
log('Escopo Pai - Antes da chamada da função assíncrona.');
sendChat('Função Assíncrona', 'Avalie isso: [[1d6]]', function(msg) {
log('Escopo da Função Assíncrona - Fazendo o trabalho da função assíncrona.');
});
log('Escopo Pai - após a chamada da função assíncrona.');
Funções assíncronas são necessárias para evitar que a API fique travada o tempo todo. Se cada rolagem de dados fosse tratada de forma síncrona, a API ficaria super lenta e sem resposta. Quase qualquer função que você vê que recebe um retorno de chamada é assíncrona. (Exceção para algumas das funções _.map, _.reduce, etc, esses são exemplos de programação funcional em contraste com a programação procedural com a qual a maioria das pessoas está acostumada.)