El Editor de Script
Para editar tus scripts de juego, haz clic en el enlace "Mod (API) Scripts" en la página de Detalles del Juego de tu juego (el mismo lugar donde se encuentran opciones como "Registro de Chat" y "Copiar/Extender Juego"). Se te presentarán varias características:
- Una lista de pestañas en la parte superior. Tu juego puede tener varios guiones para facilitar la organización. Ten en cuenta que todos los guiones se ejecutarán en el mismo contexto, lo que significa que no debes tener varios guiones tratando de sobrescribir los mismos valores al mismo tiempo o podrías obtener resultados no deseados.
- Un editor de código de guion. Puedes usar este editor o editar tus guiones en un editor externo de tu elección y luego pegarlos aquí.
- Una "Consola Mod (API)" ubicada en la parte inferior (ver a continuación).
Cada vez que haga clic en el botón "Guardar scripts", la caja de arena de su juego sereiniciará(perdiendo cualquier dato en memoria que no haya sido persistido en el objetode estadoo en objetos Roll20). Esto también se aplica si agregas un nuevo guion, eliminas un guion o activas/desactivas un guion.
La Consola Mod (API)
La Consola Mod (API) es la "ventana" hacia tus scripts. Dado que los Scripts Mod (API) se ejecutan en un entorno seguro, no tienes acceso directo a ellos mientras se están ejecutando para ver información sobre los resultados o errores del script. La Consola Mod (API) muestra esta información fuera del entorno seguro para que puedas verla mientras editas tus scripts. Todos los comandos log()
se mostrarán aquí, así como cualquier error que se encuentre durante la ejecución de tus scripts. Para más información, consulteel artículo sobre depuración de scripts.
Scripts Reactivos: Escuchar eventos, modificar objetos
El primer (y más simple) tipo de uso de Mod (API) es reaccionar a cambios en la mesa de juego, y luego responder con funcionalidad adicional a los objetos cambiados. Este tipo de script está compuesto por una serie de funciones que escuchan eventos que ocurren durante el juego. Luego modificará los objetos que se pasan durante esos eventos, lo que cambiará lo que sucede en el tablero.
Un script básico que mueve una pieza 5 pies adicionales (suponiendo la configuración de página predeterminada) sería:
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + 70
});
});
Como puedes ver, creamos una función simple usando on que se ejecutará cada vez que se escuche el evento change:graphic. La función recibe el objeto gráfico, obj. Para hacer un cambio, simplemente modificamos obj usando la función set; cualquier propiedad que cambiemos se detectará y cambiará en el tablero de juego.
set
yget
para establecer y obtener los valores actuales de los objetos, de lo contrario tus cambios no se guardarán. (Consulta a continuación una lista de los tipos de objetos y sus propiedades, así como una lista de todos los eventos y los argumentos que se pasan a cada evento).Nota sobre las funciones de utilidad
Por supuesto, el ejemplo anterior no es muy útil porque siempre agrega 70 píxeles a la ubicación del token. Pero, ¿qué sucede si el usuario ha cambiado su escala para que 5 pies sean 140 píxeles? La API de Roll20 proporciona varias funciones de utilidad prácticas para ayudar con esto (y otros) escenarios comunes. Modifiquemos nuestro ejemplo anterior para utilizar la funcióndistanceToPixelsfunction
, que nos dirá cuántos píxeles hay "cinco pies" (o pulgadas, o metros, o cualquier otro tipo de distancia que se haya establecido) sobre el tablero.
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + distanceToPixels(5);
});
});
Ahora bien, si la página actual está configurada para utilizar el tamaño de cuadrícula por defecto,distanceToPixels(5);
seguirá devolviendo 70 píxeles, pero si la página está configurada para tener una escala dos veces mayor que la normal, devolvería 140.
Siempre es una buena idea utilizar funciones de utilidad cuando estén disponibles para ayudar a evitar que su script se rompa si cambian la configuración de una página o un token.
Scripts proactivos: hacer cosas sin intervención del usuario
Además de reaccionar a eventos del usuario, también puedes hacer cosas automáticamente con la API que no están vinculadas a un evento específico de los jugadores. Por ejemplo, vamos a tener un token que patrulla de un lado a otro en el mapa.
Nota: Aunque este tipo de script no depende de la interacción del usuario, los scripts Mod (API) para tu juego solo se ejecutarán cuando al menos una persona esté conectada a tu juego.
on("ready", function() {
//Espera hasta que el evento de listo se ejecute para saber que el juego está completamente cargado.
//Obtener una referencia a nuestro token de patrulla.
var patroltoken = findObjs({_type: "graphic", name: "Guardia A"})[0]; //Sabemos que hay un token en el juego llamado "Guardia A".
var direccion = -1*distanceToPixels(5); //Caminar hacia la izquierda 70 píxeles.
var stepstaken = 0; //¿Cuántos pasos hemos dado en la dirección actual?
setInterval(function() {
if(stepstaken > 3) {
//¡Cambia de dirección!
direccion = direccion * -1; //cambiará la dirección en la que caminamos
stepstaken = 0; //restablecer los pasos a 0.
}
patroltoken.set("left", patroltoken.get("left") + direccion); //¡Caminar!
stepstaken++;
}, 5000); //realizar una acción cada 5 segundos
});
Un tratado sobre funciones asíncronas
Una función asíncrona es aquella que devuelve el hilo de control al ámbito de llamado de inmediato y realiza alguna tarea en segundo plano. Aquí tienes un ejemplo muy simple y fácil de entender que puedes pegar en la pestaña de scripts Mod (API):
on('load',function(){
log('Parent Scope - Antes de llamar a la función asincrónica.');
setTimeout(function(){
log('Scope de la Función Asincrónica - Realizando el trabajo de la función asincrónica.');
},10 /* 10 milisegundos */);
log('Scope Padre - después de llamar a la función asincrónica.');
});
En el registro Mod (API), verás algo como esto:
"Scope Padre - Antes de llamar a la función asincrónica." "Scope Padre - después de llamar a la función asincrónica." "Scope de la Función Asincrónica - Realizando el trabajo de la función asincrónica."
Al ver ese código, piensas "Por supuesto que ocurrirá más tarde, le dijiste que se ejecutara en 10 milisegundos, ¿no?". Aquí tienes un ejemplo menos obvio que tendrá los mismos mensajes en el registro:
on('load',function(){
log('Scope Padre - Antes de llamar a la función asincrónica.');
sendChat('Función Asincrónica','Evaluar esto: [[1d6]]',function(msg){
log('Scope de la Función Asincrónica - Realizando el trabajo de la función asincrónica.');
});
log('Scope Padre - después de llamar a la función asincrónica.');
Las funciones asíncronas son necesarias para evitar que la API se bloquee todo el tiempo. Si cada lanzamiento de dados se manejara de forma síncrona, la API sería muy lenta y no respondería adecuadamente. Casi cualquier función que veas que utiliza un callback es asíncrona. (Excepción para algunas de las funciones _.map, _.reduce, etc, estas son ejemplos de programación funcional en contraste con la programación procedural a la que la mayoría de la gente está acostumbrada.)