Sorry for the delay, holidays and such. =D So, doing it from text in the GM Notes is a bit complicated. I'd set it up so you have lines like this: trait: trait-table
status: status-table Then look for those lines on newly created tokens. Here are the complicated parts: First, the notes are stored in an escaped form: %3Cp%3Etraits%3A%20trait-table%3C/p%3E%3Cp%3Estatus%3A%20status-table%3C/p%3E You can convert that back to readable with the unescape function, which will give you: <p>traits: trait-table</p><p>status: status-table</p> Next you have to split this into reasonable lines. HTML has elements that are "block elements", meaning they define a single unit. I threw together a function that will find the start and end of the blocks and split on them, giving an array of conceptual lines: [
"<p>traits: trait-table</p>",
"<p>status: status-table</p>"
] Then strip out all the HTML tags: [
"traits: trait-table",
"status: status-table"
] Next write a function that pulls out the "key: value" pairs for "traits" and "status", and you have the settings. The next complication is that you don't want to pass bad table names to the roll function or it will crash the API. For that, I wrote a function that verifies that a table for that name exists and returns the inline roll for it. The function I wrote is a little bit slow (because it does a find for every execution, I'll probably tidy that up with some lazy caching later. Edit: Ok, it's later... I went ahead and added caching for the existence of rollable tables. There were a few complications with that, which made it interesting. =D Table names are not unique, so it needs to track the table id as well. Additionally, adding new tables, they always are named "new-table", so it needs to handle changing the names of tables to something reasonable. Fun, fun! Anyway, here is the code with those changes: on('ready',()=>{
const getNoteLines = (()=> {
const blockElements = [
'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'pre', 'address',
'blockquote', 'dl', 'div', 'fieldset', 'form', 'hr', 'noscript', 'table','br'
];
const rStart=new RegExp(`<\\s*(?:${blockElements.join('|')})\\b[^>]*>`,'ig');
const rEnd=new RegExp(`<\\s*\\/\\s*(?:${blockElements.join('|')})\\b[^>]*>`,'ig');
return (str) =>
(rStart.test(str)
? str
.replace(/[\n\r]+/g,' ')
.replace(rStart,"\r$&")
.replace(rEnd,"$&\r")
.split(/[\n\r]+/)
: str
.split(/(?:[\n\r]+|<br\/?>)/)
)
.map((s)=>s.trim())
.filter((s)=>s.length)
;
})();
const stripHTML = (t) => t.replace(/<[^>]*>/g,'');
const getSetting = (()=>{
const properties = [
'traits','status'
];
const rSetting = new RegExp(`^\\s*(${properties.join('|')})\\b\\s*:\\s*(.*)\\s*$`,'i');
return (s) => {
let m = (s||'').match(rSetting);
if(m){
return [m[1],m[2]];
}
};
})();
const getRollString = (()=>{
let tableNames = findObjs({type:'rollabletable'}).reduce((m,t)=>({...m,[t.get('name')]:[...(m[t.get('name')]||[]),t.id]}),{});
on('add:rollabletable',(t)=>tableNames[t.get('name')]=[...(tableNames[t.get('name')]||[]),t.id]);
on('change:rollabletable',(tn,tp)=>{
tableNames[tp.name]=(tableNames[tp.name]||[]).filter(i=>i!==tp._id);
if(0 === tableNames[tp.name].length){
delete tableNames[tp.name];
}
tableNames[tn.get('name')]=[...(tableNames[tn.get('name')]||[]),tn.id];
});
on('destroy:rollabletable',(t)=>{
tableNames[t]=(tableNames[t]||[]).filter(i=>i!==t.id);
if(0 === tableNames[t].length){
delete tableNames[t];
}
});
return (t) => {
if(tableNames.hasOwnProperty(t)) {
return `[[1t[${t}]]]`;
}
return '';
};
})();
const getMatchData = (t) => getNoteLines(unescape(t.get('gmnotes')))
.map(stripHTML)
.reduce((m,l)=>{
let s = getSetting(l);
if(s) {
return { ...m, [s[0]]:s[1]};
}
return m;
},{});
let tokenIds = [];
const processInlinerolls = (msg) => {
if(msg.hasOwnProperty('inlinerolls')){
return msg.inlinerolls
.reduce((m,v,k) => {
let ti=v.results.rolls.reduce((m2,v2) => {
if(v2.hasOwnProperty('table')){
m2.push(v2.results.reduce((m3,v3) => [...m3,(v3.tableItem||{}).name],[]).join(", "));
}
return m2;
},[]).join(', ');
return [...m,{k:`$[[${k}]]`, v:(ti.length && ti) || v.results.total || 0}];
},[])
.reduce((m,o) => m.replace(o.k,o.v), msg.content);
} else {
return msg.content;
}
};
const setTokenThings = (obj,prev,force=false) => {
if(tokenIds.includes(obj.id) || force){
tokenIds=tokenIds.filter(id => id !== obj.id);
if(
'graphic' === obj.get('type') &&
'token' === obj.get('subtype')
) {
let md = getMatchData(obj);
if(md.hasOwnProperty('traits')) {
sendChat('',`${getRollString(md.traits)}%%SEP%%${getRollString(md.status)}`,r=>{
let n = processInlinerolls(r[0]).split(/%%SEP%%/);
obj.set({
showname:true,
showplayers_name:true,
name: n[0],
statusmarkers: n[1]
});
});
}
}
}
};
const saveTokenId = (obj) => {
tokenIds.push(obj.id);
};
on('add:graphic', saveTokenId);
on('change:graphic', setTokenThings);
});