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

The Aaron's GM Notes script

1486864546
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
I've been looking into  this as a way to distribute some room notes about my map on the GM layer, but don't know how to configure it to whisper only to the GM. I'm sure it's pretty simple, but my javascript is weak to non-existent. Can you give me a clue? Thanks! Code (so's ya don't have to look it up): on('ready',function(){ 'use strict'; on('chat:message',function(msg){ if('api' === msg.type && msg.content.match(/^!gmnote/) && playerIsGM(msg.playerid) ){ _.chain(msg.selected) .map( s => getObj('graphic',s._id)) .reject(_.isUndefined) .each( o => { sendChat(o.get('name'),decodeURIComponent(o.get('gmnotes'))); }); } }); });
1486868592

Edited 1486868704
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Try changing the sendchat line to this: sendChat(o.get('name'),'/w gm '+ decodeURIComponent(o.get('gmnotes')));
1486869759
The Aaron
Pro
API Scripter
If I hadn't packed my laptop for a trip, I'd get you a slightly better version of that snippet. If I remember tomorrow, I still will... :)
1486873627
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Thanks Scott. Aaron, you posted a more elaborate version in the same thread, but I didn't need the filtering ability. Thank you, too.
1486874054
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
You might be able to not change the snippet at all, and just put "/w gm " at the start of GM notes that you want whispered to you. I'm not sure if decodeURIComponent removes the slash of the slash commands or not.
1486920587
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Ah! I'll give that a try. That would be the best of both worlds.
Here's a version of something similar I started working on, but haven't finished yet... my intention is to allow for players to select their character, run this macro and make skill checks against objects they can target and pull information from that target via the tokens GM Notes section. The info is entered as a json object. // SCRIPT INFO on("ready", function() {     var MapNotes5e_Author = "SkyCaptainXIII";     var MapNotes5e_Version = "Alpha";     var MapNotes5e_LastUpdated = 1479080695;     log("-=> MapNotes v" + MapNotes5e_Version + " <=-  [" + (new Date(MapNotes5e_LastUpdated * 1000)) + "]");     //log (Date.now().toString().substr(0, 10)); }); // API COMMAND HANDLER on("chat:message", function(msg) {     if (msg.type !== "api") return;     if (msg.content.split(" ")[1] == undefined) {         sendChat("ERROR", "/w " + who + " You must select or target a token or supply a token id.");         return;     }     var who = msg.who.replace("(GM)", "").trim();          // TOKEN INFOMATION     var Command = msg.content.split(" ")[0];     var TokenID = msg.content.split(" ")[1];     var Token = (TokenID != undefined) ? getObj("graphic", TokenID) : sendChat("ERROR:", "/w GM MapNotes was unable to locate a token with ID: " + TokenID + ". (Triggered by " + who + ")");     var TokenNotes = Token.get("gmnotes");          // MAPNOTE     var MapNotes = {};     try { TokenNotes = decodeURIComponent(TokenNotes).trim(); }     catch (err) { TokenNotes = unescape(TokenNotes).trim(); }     if (TokenNotes) {         try {             TokenNotes = TokenNotes.split(/<[/]?.+?>/g).join('');             MapNotes = JSON.parse(TokenNotes);         }         catch (err) {             sendChat("ERROR", "/w GM " + Token.get("name") + " has an invalid JSON entry.");             sendPing(Token.get("left"), Token.get("top"), Token.get("_pageid"));             return;         }     }     // log (MapNotes.info);          // ARCANA     if (Command === "!mn-arcana") {              }          if (Command === "!mn-desc") {         sendChat('', '/desc ' + MapNotes.info);     }          // HISTORY SKILL     if (Command === "!mn-history") {              }          // GENERAL INFORMATION     if (Command === "!mn-info") {         sendChat('MapNotes', '/w ' + who + ' ' + MapNotes.info);     }          // INVESTIGATE     if (Command === "!mn-investigate") {              }          // PERCEPTION     if (Command === "!mn-perception") {              } });
1486925178
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Scott C. said: You might be able to not change the snippet at all, and just put "/w gm " at the start of GM notes that you want whispered to you. I'm not sure if decodeURIComponent removes the slash of the slash commands or not. Did not work. :( Still, the code change you gave above did what I wanted it to do. Thanks.
1486925307
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Looks like an interesting script, SkyCaptainXIII. My remote players tend to share a connection though. We don't use enough per-player automation to warrant it. They don't even use macros. I do all the heavy lifting.
It's not a script solution, but I've really enjoyed this approach. How to Make a Hidden GM-Only Note on the Token Layer Best of all, you don't have to switch to the GM layer since players can't see it. (But you can put it there if you want.) And, you can of course edit the text whenever you'd like, etc. This is how I label and add descriptions for all the numbered zones on my maps, mark traps, etc.
Goodness! Keithcurtis and Jen, you've come up with the concept for the most useful GM script I've seen in a long time. I would very much like to see a weaponized version. For example, if the API was designed to create GM Notes tokens and link them to handouts (say using the chat console), it would become a very powerful tool for helping GMs access their content. Especially in games with hundreds of handouts and assets (such as the Storm King's Thunder module), this kind of script allows GMs to locate and access Journal items from the tabletop , at locations where those references are needed, rather than always scrolling folders in the Journal area (hoo boy!). For Modules with numbered references on maps (e.g. "Area 3" or "Area 4), the numbered tokens can be linked to the relevant handout items. That concept already works with this simple model you've provided. I wish Storm King's Thunder was designed to use an API like this. This script provides table-top reference points that: Link directly to mutiple handouts with flavor text and NPC character sheets with bios, or Describe/explain traps or other on-map items, whispering them to the GM or outputting them as GM "/Desc" chat. But more, if the handouts are written in a structured way with quality markup, you could do powerful things like call sections within the handouts, or output only Flavor Text to the chat (using /Desc), while the rest outputted only to the GM (using /w GM). Create one of Jen's Tokens or use a numbered icon: Add links to Handouts to the GM Notes: Run API to output links to Chat. Conditions and Overview of Act 1 are clickable to their respective handouts: I'm sure some of our Level 50 GMs are already doing all this. But GM organizational tools are becoming more essential as the robust D&D modules are produced, and this is the best one I've seen so far.
1490474562
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Whoah, now. That's Jen's and The Aaron's code. I didn't do anything other than cross-post at the top. I am not even the Silver Surfer to herald the world-consuming power of the Jen's or The Aaron's Cosmic Scripting. I'm more like Man #3 on Street, here. :)
1490478743
The Aaron
Pro
API Scripter
Woot!!  :)
As the GM Notes script is currently written, are there limitations on the copy you can add to the GM Notes area of the token? Sometimes when I run the gm notes script, it throws some errors and shuts down the sandbox due to a malformed URI. It seems to be caused by the content I'm adding into the GM Notes, but I am having a hard time determining what exactly is doing it. I tried stripping out formatting and special characters, but it hasn't worked. I thought it might be reserved characters in the copy, but I am uncertain. Here's the error: Here's the version of the gm notes script I'm using: on('ready',function(){     'use strict';     on('chat:message',function(msg){         if('api' === msg.type && msg.content.match(/^!gmnote/) && playerIsGM(msg.playerid) ){             _.chain(msg.selected)             .map( s => getObj('graphic',s._id))             .reject(_.isUndefined)             .each( o => {                 sendChat(o.get('name'),'/w gm '+ decodeURIComponent(o.get('gmnotes')));             });         } }); });
1490552550
The Aaron
Pro
API Scripter
Can you post an example of what you have in the GMNotes?
I've tried a number of different input scenarios, all text, with and without formatting like Bold or Heading 3. For example, this works: Cistern This rectangular reservoir is clean and filled with cold, fresh water. It is 10 feet deep with a rim 2 feet higher than the surrounding floor so that the bottom of the cistern is 8 feet below the floor. Drain pipes from the roof of the old manor above fill the cistern with water. Secret Door A secret door is located in the southwest corner of the room. See the General Features section for more information on secret doors. Add this text and the error is triggered: Developments No monsters or villains are found in this area, but the ruffians in area 2 take notice if the characters make a lot of noise here. They creep into the room, gaining surprise if the characters don’t hear them see Surprise in the rulebook. If the ruffians fight in this area and two are defeated, the last ruffian might reveal the secret door by fleeing in that direction. I removed the apostrophe from the word don't (’) and it started working again. It's not always clear what's triggering the error, but I'm guessing it's the use of html related characters I wasn't noticing in my trial and error process.
1490740591

Edited 1490740810
This is a really cool and strange script. I'm trying to use two version of this scrip at once (one for me and one for my players) and I'm trying to get the filtering function to work with both. So far getting the public chat version to filter has been no problem, (although setting up drop-down roll queries with it was interesting because it doesn't work properly if you put a space before the comma) but the gm version always seems to output everything in the GM notes regardless of what you try to use to filter it and it doesn't matter if you use a typed command (Like: !wgmnote-P1) or a roll query (Like: !wgmnote-?{Item to show|Perception 1 Net hit, P1|Perception 2 Net hits, P2}). The two scripts are completely identical other than being called with a modified command (!wgmnote instead of !gmnote)       on('ready',function(){           'use strict';                  on('chat:message',function(msg){               if('api' === msg.type && msg.content.match(/^!wgmnote/) && playerIsGM(msg.playerid) ){                   let match=msg.content.match(/^!wgmnote-(.*)$/),                       regex;                   if(match && match[1]){                       regex = new RegExp(`^${match[1]}`,'i');                   }                                                          _.chain(msg.selected)                       .map( s => getObj('graphic',s._id))                       .reject(_.isUndefined)                       .reject((o)=>o.get('gmnotes').length===0)                       .each( o => {                           if(regex){                               let lines=_.filter(decodeURIComponent(o.get('gmnotes')).split(/(?:[\n\r]+|<br\/?>)/),(l)=>regex.test(l)).join('\r');                              sendChat(o.get('name'),'/w gm '+ decodeURIComponent(o.get('wgmnotes')));                           } else {                               sendChat(o.get('name'),'/w gm '+ decodeURIComponent(o.get('gmnotes')));                           }                       });               }           });       });