L'Editor di Script
Per modificare i tuoi script di gioco, fai clic sul collegamento "Mod (API) Scripts" nella pagina dei dettagli del gioco per il tuo gioco (lo stesso posto dove si trovano le opzioni come il "Registro Chat" e "Copia/Estendi Gioco"). Ti verranno presentate diverse funzionalità:
- Una lista di schede nella parte superiore. Il tuo gioco può avere script multipli per una migliore organizzazione. Nota che tutti gli script verranno comunque eseguiti nello stesso contesto, il che significa che non dovresti avere più script che cercano di sovrascrivere gli stessi valori contemporaneamente o potresti ottenere risultati indesiderati.
- Un editor di codice degli script. Puoi utilizzare questo editor o modificare gli script con un editor esterno a tua scelta e quindi incollarli qui.
- Una "Mod (API) Console" situata nella parte inferiore (vedi sotto).
Ogni volta che clicca sul pulsante "Salva script", la sandbox del suo gioco verràriavviata(perdendo tutti i dati in memoria che non sono stati persistiti nell'oggettostato
o negli oggetti Roll20). Questo vale anche se aggiungi un nuovo script, elimini uno script o attivi/disattivi uno script.
La Console Mod (API)
La Console Mod (API) è la "finestra" sui tuoi script. Poiché gli script Mod (API) vengono eseguiti in una sandbox, non hai accesso diretto a essi mentre sono in esecuzione per visualizzare informazioni sui risultati o sugli errori dello script. La Console Mod (API) visualizza queste informazioni fuori dalla sandbox in modo che tu possa visualizzarle mentre modifichi i tuoi script. Tutti i comandi log()
saranno visualizzati qui, così come eventuali errori riscontrati durante l'esecuzione dei tuoi script. Per maggiori informazioni, consultil'articolo sul debug degli script.
Script reattivi: Ascolta eventi, modifica oggetti
Il primo (e più semplice tipo) di utilizzo di Mod (API) è reagire ai cambiamenti sul tavolo e quindi rispondere con funzionalità aggiuntive agli oggetti modificati. Questo tipo di script è composto da una serie di funzioni che ascoltano gli eventi che avvengono durante il gioco. Successivamente, modificherà gli oggetti passati durante tali eventi, il che cambierà ciò che accade sul tabletop.
Uno script di base che sposta un pezzo di 5 piedi aggiuntivi (assumendo le impostazioni predefinite della pagina) sarebbe:
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + 70
});
});
Come puoi vedere, abbiamo creato una semplice funzione on che verrà eseguita ogni volta che viene ascoltato l'evento change:graphic. Alla funzione viene passato l'oggetto grafico, obj. Per apportare una modifica, basta modificare obj utilizzando la funzione set: qualsiasi proprietà che cambiamo verrà rilevata e modificata nel gioco da tavolo.
set
eget
per impostare e ottenere i valori correnti degli oggetti, altrimenti le modifiche non verranno salvate. (Vedi sotto per un elenco dei tipi di oggetti e delle loro proprietà, nonché un elenco di tutti gli eventi e degli argomenti passati a ciascun evento.)Nota sulle funzioni di utilità
Naturalmente, l'esempio precedente non è particolarmente utile perché aggiunge sempre 70 pixel alla posizione del token. Ma cosa succede se l'utente ha modificato la scala in modo che 5ft corrisponda a 140 pixel? L'API di Roll20 fornisce diverse funzioni di utilità utili per aiutare in questo (e in altri) scenari comuni. Modifichiamo il nostro esempio precedente per utilizzare la funzionedistanceToPixels
, che ci dirà quanti pixel sono "cinque piedi" (o pollici, o metri, o qualsiasi altro tipo di distanza sia stato impostato) sul piano del tavolo.
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + distanceToPixels(5);
});
});
Ora, se la pagina corrente è impostata per utilizzare il dimensionamento predefinito della griglia,distanceToPixels(5);
restituirà ancora 70 pixel, ma se la pagina è impostata per avere una scala doppia rispetto a quella normale, restituirà 140.
È sempre una buona idea utilizzare le funzioni di utilità quando sono disponibili per evitare che lo script si rompa se le impostazioni di una pagina o di un token cambiano.
Script proattivi: fai cose senza intervento dell'utente
Oltre a reagire agli eventi dell'utente, puoi anche fare cose automaticamente con l'API che non sono legate a un evento specifico dei giocatori. Ad esempio, facciamo in modo che un token faccia la ronda avanti e indietro sulla mappa.
Nota: Sebbene questo tipo di script non dipenda dall'interazione dell'utente, gli script Mod (API) per il tuo gioco verranno eseguiti solo quando almeno una persona è connessa al tuo gioco.
on("ready", function() {
//Aspetta fino a quando l'evento di caricamento è completamente caricato.
//Ottieni un riferimento al nostro token di pattuglia.
var patroltoken = findObjs({_type: "graphic", name: "Guardia A"})[0]; //Sappiamo che c'è un token nel gioco chiamato "Guardia A".
var direction = -1*distanceToPixels(5); //Cammina a sinistra di 70 pixel.
var stepstaken = 0; //Quanti passi abbiamo fatto nella direzione attuale?
setInterval(function() {
if(stepstaken > 3) {
//Cambia direzione!
direction = direction * -1; //"inverterà" la direzione in cui stiamo camminando
stepstaken = 0; //riporta i passi a 0.
}
patroltoken.set("left", patroltoken.get("left") + direction); //cammina!
stepstaken++;
}, 5000); //fai un'azione ogni 5 secondi
});
Un Trattato sulle Funzioni Asincrone
Una funzione asincrona è una funzione che restituisce subito il controllo allo scope chiamante e svolge qualche compito in background. Ecco un esempio molto semplice e facile da comprendere che puoi incollare in una scheda degli script Mod (API):
on('load', function() {
log('Parent Scope - Before call to asynchronous function.');
setTimeout(function() {
log('Asynchronous Function Scope - Doing the Asynchronous function work.');
}, 10 /* 10 milliseconds */);
log('Parent Scope - after call to asynchronous function.');
});
Nel log dei Mod (API), vedrai qualcosa di simile a questo:
"Parent Scope - Before call to asynchronous function." "Parent Scope - after call to asynchronous function." "Asynchronous Function Scope - Doing the Asynchronous function work."
Guardando quel codice, pensi "Certo che succederà dopo, gli hai detto di eseguire tra 10 millisecondi, duh?". Ecco un esempio meno ovvio che avrà gli stessi messaggi di log:
on('load', function() {
log('Parent Scope - Before call to asynchronous function.');
sendChat('Async Function', 'Valuta questo: [[1d6]]', function(msg) {
log('Asynchronous Function Scope - Doing the Asynchronous function work.');
});
log('Parent Scope - after call to asynchronous function.');
Le funzioni asincrone sono necessarie per evitare che l'API si blocchi tutto il tempo. Se ogni lancio di dado fosse gestito in modo sincrono, l'API sarebbe estremamente lenta e non reattiva. Quasi ogni funzione che vedi che prende una callback è asincrona. (Eccezione per alcune delle funzioni _.map, _.reduce, ecc., queste sono esempi di programmazione funzionale in contrasto con la programmazione procedurale a cui la maggior parte delle persone è abituata.)