Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Can Token Mod be used to set GM Notes?

The title pretty much says it all. Can token mod be used to set GM text?
1499974254
The Aaron
Pro
API Scripter
Not currently.  That's a complicated proposition.  I've discussed it with several people before (Ziechael most recently). Let me ask you this, what is your use case?  I have some other scripts that I might be able to easily repurpose.  The complication with adding it to TokenMod is accepting multi-line values, and what is the right selection of operations (concatenation, replace, line indexed changes, inserts, etc).  Making a one off would be pretty easy.
I have been playing around with Matt's Door Script and have been extremely impressed. The only down side is that the script cannot recognize attributes from repeating sections and it takes a fair amount of data entry to set it up. Matt says he is playing around with adding the ability to recognize repeating sections, but I figure I can take care of some of the reptition in setting up the switch tokens by using token mod.  Right now the macro is  !token-mod --ids @{target|1|token_id} @{target|2|token_id} @{target|3|token_id} @{target|4|token_id} @{target|5|token_id} --set bar1_value|?{Locked or Unlocked?|Locked,1|Unlocked,0} bar1_max|?{Enter Lock DC|0} bar2_value|?{Trapped?|No Trap,0|Trap is armed,1|Trap is armed and will reset when triggered,2} bar2_max|?{Enter Trap DC|0} It would be nice to alter the GM notes to reflect a couple of different types of standard traps at the same time.  As a side note- that token mod command macro works fine if I enter it directly into chat or if I hit the test macro button in edit macro mode, but it just ouputs the name of the macro if I use it from a token macro... not sure why but am playing around with it.
1499981798

Edited 1499981822
The Aaron
Pro
API Scripter
Here: on('ready',function(){     'use strict';     const formatMsg = (c)=>c.replace(/^!set-gmnote\s*/,'').replace(/(^{{\s*|\s*}}$)/gm,'');     on('chat:message',function(msg){         if('api' === msg.type && msg.content.match(/^!set-gmnote/) && playerIsGM(msg.playerid) ){             let content = formatMsg(msg.content),                 who=(getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');             if(_.has(msg,'inlinerolls')){                 content = _.chain(msg.inlinerolls)                     .reduce(function(m,v,k){                         var ti=_.reduce(v.results.rolls,function(m2,v2){                             if(_.has(v2,'table')){                                 m2.push(_.reduce(v2.results,function(m3,v3){                                     m3.push(v3.tableItem.name);                                     return m3;                                 },[]).join(', '));                             }                             return m2;                         },[]).join(', ');                         m['$[['+k+']]']= (ti.length && ti) || v.results.total || 0;                         return m;                     },{})                     .reduce(function(m,v,k){                         return m.replace(k,v);                     },content)                     .value();             }             if(content.length){                 _.chain(msg.selected)                 .map( s => getObj('graphic',s._id))                 .reject(_.isUndefined)                 .each( o => {                     o.set({                         gmnotes: content                     });                 });             } else {                 sendChat('',`/w "${who}" Use <code>!set-gmnote Some Text</code> or <code>!set-gmnote {{ some multi-line text}}</code>.`);             }         }     }); }); Usage: !set-gmnote [message] [message] may be multi line by placing {{ and }} around it [message] may contain inline rolls, which will be substituted for their values (rollable tables too!) Examples: !set-gmnote Some simple note on the first line Results in: Some simple note on the first line !set-gmnote {{Some line 1 Some line 2 Some line 3}} Results in: Some line 1 Some line 2 Some line 3 !set-gmnote {{ Second line (note the blank above and below) }} Results in: Second line (note the blank above and below) !set-gmnote {{Armor: [[1t[ArmorTypes]]] Quantity: [[3d8+3]] Have a nice day!}} Might result in: Armor: Chainmail Quantity: 18 Have a nice day! Cheers!
1499981861
The Aaron
Pro
API Scripter
It will apply the notes to all selected tokens, btw, and happily overwrite whatever is there.
Awesome- thank you very much. 
1500131454
GiGs
Pro
Sheet Author
API Scripter
This looks very handy for me.  Would it be possible to amend this to give two choices:  select between writing to player notes, and GM notes select between replacing existing text, and appending to existing text ?
1500134965
The Aaron
Pro
API Scripter
This is adjusting the gmnotes on a token, which doesn't have a bio. A script that adjusts this things would be possible though. Ditto appending. 
1500140484

Edited 1500140568
GiGs
Pro
Sheet Author
API Scripter
I didnt realise tokens could have GM notes, except via an attached journal bio. I need to read up on that. (Edit: Doh! of course they can. I have seen that so many times and ignored it, that I completely blanked it was there.) I'd still be very interested in a script that could do those things for a bio.
1500231902

Edited 1500232276
The Aaron
Pro
API Scripter
Sure, give this a try: on('ready',function(){     'use strict';     const cmdregex=/^(!(?:set|add)-(?:c?gmnote|bio))\s*/,         formatMsg = (c)=>c.replace(cmdregex,'').replace(/(^{{\s*|\s*}}$)/gm,'');     on('chat:message',function(msg){         if('api' === msg.type) {             let match=msg.content.match(cmdregex);             if(match && playerIsGM(msg.playerid) ){                 let content = formatMsg(msg.content),                     who=(getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');                 if(_.has(msg,'inlinerolls')){                     content = _.chain(msg.inlinerolls)                         .reduce(function(m,v,k){                             var ti=_.reduce(v.results.rolls,function(m2,v2){                                 if(_.has(v2,'table')){                                     m2.push(_.reduce(v2.results,function(m3,v3){                                         m3.push(v3.tableItem.name);                                         return m3;                                     },[]).join(', '));                                 }                                 return m2;                             },[]).join(', ');                             m['$[['+k+']]']= (ti.length && ti) || v.results.total || 0;                             return m;                         },{})                         .reduce(function(m,v,k){                             return m.replace(k,v);                         },content)                         .value();                 }                 if(content.length){                     let tokens = _.chain(msg.selected)                         .map( s => getObj('graphic',s._id))                         .reject(_.isUndefined)                         ;                     switch(match[1]){                         case '!set-gmnote':                             tokens.each( o => {                                 o.set({                                     gmnotes: content                                 });                             });                             break;                         case '!set-cgmnote':                             tokens.map( o => getObj('character',o.get('represents')))                                 .reject(_.isUndefined)                                 .each( o => {                                     o.set({                                         gmnotes: content                                     });                                 });                             break;                                                      case '!set-bio':                             tokens.map( o => getObj('character',o.get('represents')))                                 .reject(_.isUndefined)                                 .each( o => {                                     o.set({                                         bio: content                                     });                                 });                             break;                         case '!add-gmnote':                             tokens.each( o =>{                                 o.set({                                     gmnotes: `${o.get('gmnotes')}<br>\n${content}`                                 });                             });                             break;                         case '!add-cgmnote':                             tokens.map( o => getObj('character',o.get('represents')))                                 .reject(_.isUndefined)                                 .each( o => {                                     o.get('gmnotes',(notes)=>{                                         _.defer(()=>o.set({                                             gmnotes: `${notes}<br>\n${content}`                                         }));                                     });                                 });                             break;                         case '!add-bio':                             tokens.map( o => getObj('character',o.get('represents')))                                 .reject(_.isUndefined)                                 .each( o => {                                     o.get('bio',(notes)=>{                                         _.defer(()=>o.set({                                             bio: `${notes}<br>\n${content}`                                         }));                                     });                                 });                             break;                     }                 } else {                     sendChat('',`/w "${who}" <div>`+                         `<div>Use <code>COMMNAD Some Text</code> or <code>COMMAND {{ some multi-line text}}</code>.</div>`+                         `<div><b>Commands:</b></div>`+                         `<div><ul>`+                             `<li><code>!set-gmnote</code> -- Replaces contents of token gmnotes.</li>`+                             `<li><code>!set-cgmnote</code> -- Replaces contents of character gmnotes.</li>`+                             `<li><code>!set-bio</code> -- Replaces contents of character bio.</li>`+                             `<li><code>!add-gmnote</code> -- Appends to contents of token gmnotes.</li>`+                             `<li><code>!add-cgmnote</code> -- Appends to contents of character gmnotes.</li>`+                             `<li><code>!add-bio</code> -- Appends to contents of character bio.</li>`+                         `</ul></div>`                     );                 }             }         }     }); }); Commands: !set-gmnote  -- As above. !set-cgmnote -- As above, but for the representing character's GMNotes. !set-bio -- As above, but for the representing character's bio. !add-gmnote -- As above, but appends to the existing GMNotes. !add-cgmnote -- As above, but appends to the existing character's GMNotes. !add-bio -- As above, but appends to the existing character's bio.
1500242348
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Very nice, Aaron! I think I'll have to add that to my roster.
1500244180
The Aaron
Pro
API Scripter
:)