Ok, here's rough cut on a first pass script, it works off of Handouts. Name the handout "Dialog: SOMETHING", then run: !dialog --list It will list all dialog handouts with a Next and Reset button. If you click Next, it outputs the next line from the handout and moves it to the end of the GM Notes section. If you click the Reset button, it moves all the GM Notes section to the start of the handout. Each time it prints out a line from the handout, it whispers a footer to the GM with >>> for next and Reset buttons. You can also just call: !dialog --next To print the next line from the most recent Dialog that was being output. Here's some screenshots to show what I mean: Anyway, give that a try and let me know how it goes. I'll clean up the output, and add a help function. Script: on('ready',()=>{
let lastID;
class DoubleDashArgs {
#cmd;
#args;
constructor(line){
let p=line.split(/\s+--/);
this.#cmd = p.shift();
this.#args = [...p.map(a=>a.split(/\s+/))];
}
get cmd() {
return this.#cmd;
};
has(arg) {
return !!this.#args.find(a=>arg===a[0]);
}
keys() {
return this.#args.map(a=>a[0]);
}
params(arg,slice=1) {
return [...(this.#args.find(a=>arg===a[0])||[])].slice(slice);
}
toObject() {
return {cmd:this.#cmd,args:this.#args};
}
}
const showHelp = (who) => {
sendChat('',`/w "${who}" Dialog Help...`);
};
const listDialogs = (who) => {
let d = findObjs({type:'handout'})
.filter(h=>/^dialog:/i.test(h.get('name')))
.map(d=>`<li><b>${d.get('name')} </b><a href="!dialog --next ${d.id}">Next</a><a href="!dialog --reset ${d.id}">Reset</a></li>`)
;
sendChat('',`/w "${who}" <div><h3>Dialogs</h3><ul>${d}</ul></div>`);
};
const nextDialog = (who, id) => {
prevLastID = lastID;
lastID=id;
let d = getObj('handout',lastID);
if(d){
d.get('notes',(n)=>{
d.get('gmnotes',(g)=>{
if(/^null$/.test(g)){
g='';
}
let p = n.indexOf('</p>');
let line;
if(-1 === p){
line = n;
n='';
} else {
line = n.substr(0,p+4);
n=n.slice(p+4);
}
g+=line;
d.set('notes',n);
d.set('gmnotes',g);
sendChat('',line);
sendChat('',`/w "${who}" <div style="font-size: .7em;; line-height:.7em;text-align:center;font-weight:bold;float:right;width:90%;">${n.length ? `<a href="!dialog --next ${id}">&gt;&gt;&gt;</a>` : ''} <a style="float:right;" href="!dialog --reset ${id}">Reset</a><div style="clear:both;"></div></div>`);
});
});
} else {
sendChat('',`/w "${who}" <div><b>Error:</b> Couldn't find dialog for id: <code>${lastID}</code>`);
lastID=prevLastID;
}
};
const resetDialog = (who, id) => {
prevLastID = lastID;
lastID=id;
let d = getObj('handout',lastID);
if(d){
d.get('notes',(n)=>{
d.get('gmnotes',(g)=>{
if(/^null$/.test(g)){
g='';
}
n = g+n;
g='';
d.set('notes',n);
d.set('gmnotes',g);
sendChat('',`/w "${who}" <div style="font-size: .7em;; line-height:.7em;align:center;font-weight:bold;float:right;width:90%;">${n.length ? `<a href="!dialog --next ${id}">&gt;&gt;&gt;</a>` : ''} </div>`);
});
});
} else {
sendChat('',`/w "${who}" <div><b>Error:</b> Couldn't find dialog for id: <code>${lastID}</code>`);
lastID=prevLastID;
}
};
// !dialog
// !dialog --help
// show help
// !dialog --list
// list dialog handouts
// !dialog --next
// !dialog --next <id>
// show next line of dialog
// !dialog --reset
// !dialog --reset <id>
// reset dialog script
on('chat:message',msg=>{
if('api'===msg.type && /^!dialog(\b\s|$)/i.test(msg.content) && playerIsGM(msg.playerid)){
let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');
let args = new DoubleDashArgs(msg.content);
if(0 === args.keys().length || args.has('help')){
showHelp(who);
return;
}
args.keys().forEach(k=>{
switch(k.toLowerCase()){
case 'list':
listDialogs(who);
break;
case 'next':
nextDialog(who, args.params(k));
break;
case 'reset':
resetDialog(who, args.params(k));
break;
}
});
}
});
});