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

Help with Toggle grid API

Hi everyone, I am trying to make an API that will toggle on and off the grid on a map. Can anyone tell me what's going wrong with this one? on('chat:message', function(message) {     // Listen for a command like "!togglegrid"     if(message.type == "api" && message.content.indexOf("!togglegrid") !== -1) {         var currentPage = Campaign().get("playerpageid"); // Get the current page ID                  var page = getObj("page", currentPage); // Get the page object                  if(page) {             var isGridEnabled = page.get("showgrid"); // Get current grid status                          // Toggle the grid status             page.set({                 showgrid: !isGridEnabled             });         }     } });
1693244259

Edited 1693244573
The Aaron
Roll20 Production Team
API Scripter
This is a bit of a weird one, and is hard to understand if you don't have some debugging scripts to track what's happening.&nbsp; Here's the minimal changes to get your script working: on('chat:message', function(message) { // Listen for a command like "!togglegrid" if(message.type == "api" &amp;&amp; message.content.indexOf("!togglegrid") !== -1) { let currentPage = Campaign().get("playerpageid"); // Get the current page ID let page = getObj("page", currentPage); // Get the page object if(page) { let isGridEnabled = page.get("showgrid"); // Get current grid status let snapping_increment = isGridEnabled ? 0 : 1; // Toggle the grid status page.set({ showgrid: !isGridEnabled , snapping_increment }); } } }); I've bolded the important parts.&nbsp; It's not obvious, but changing the show grid toggle in the UI actually changes 2 things: showgrid is toggled between true and false snapping_increment is toggled between 0 and 1 In reality, it's toggled from whatever it is (say 2 if you've set your cell width to 140px squares) to 0 then to 1. The above will set the increment to 0 and 1 based on what the grid is changing to, just like the UI. There are a few issues with this script: It works on the page the player ribbon is on, not the page the GM is on. It works for players and the GM (possibly not intended) It loses the snapping increment for pages. Here's how I'd write it to address all three of those: on('ready',()=&gt;{ const scriptName = 'ShowGrid'; const version = '0.1.0'; const schemaVersion = 0.1; const lastUpdate = 1693243590; const checkInstall = () =&gt; { log(`-=&gt; ${scriptName} v${version} &lt;=- [${lastUpdate}]`); if ( !state.hasOwnProperty(scriptName) || state[scriptName].version !== schemaVersion ) { log(` &gt; Updating Schema to v${schemaVersion} &lt;`); switch (state[scriptName] &amp;&amp; state[scriptName].version) { case 0.1: /* break; // intentional dropthrough */ /* falls through */ case "UpdateSchemaVersion": state[scriptName].version = schemaVersion; break; default: state[scriptName] = { version: schemaVersion, pageSnappingIncrementMap: {} }; break; } } }; const getPageForPlayer = (playerid) =&gt; { let player = getObj('player',playerid); if(playerIsGM(playerid)){ return player.get('lastpage') || Campaign().get('playerpageid'); } let psp = Campaign().get('playerspecificpages'); if(psp[playerid]){ return psp[playerid]; } return Campaign().get('playerpageid'); }; const toggleGrid = (pageid) =&gt; { let p = getObj('page',pageid); if(p){ let showgrid = p.get('showgrid'); if(showgrid) { state[scriptName].pageSnappingIncrementMap[pageid] = p.get('snapping_increment'); p.set({ showgrid: false, snapping_increment: 0 }); return `Disabled grid for &lt;code&gt;${p.get('name')||'[Unnamed map]'}&lt;/code&gt;.`; } else { p.set({ showgrid: true, snapping_increment: (state[scriptName].pageSnappingIncrementMap[pageid]||1) }); delete state[scriptName].pageSnappingIncrementMap[pageid]; return `Enabled grid for &lt;code&gt;${p.get('name')||'[Unnamed map]'}&lt;/code&gt;.`; } } }; on('chat:message',msg=&gt;{ if('api'===msg.type &amp;&amp; /^!togglegrid(\b\s|$)/i.test(msg.content) &amp;&amp; playerIsGM(msg.playerid)){ let pageid = getPageForPlayer(msg.playerid); let note = toggleGrid(pageid); const who = (getObj('player',msg.playerid)||{get:()=&gt;'API'}).get('_displayname'); sendChat('',`/w "${who}" &lt;div&gt;${note}&lt;/div&gt;`); } }); checkInstall(); }); For making sure it works for the GM's current page, you need to check a couple things.&nbsp; I've got a function that handles them, getPageForPlayer(), and it works for players and GMs.&nbsp; Players can be split to their own pages based on "playerspecificpages", or they are on the player ribbon page stored in "playerpageid".&nbsp; GMs add the additional possibility of being on a page stored on the GM's player object in the property "lastpage".&nbsp; The function handles all of that and just returns the page they are most likely to be on (because there are a few undetectable edge cases that are unlikely to happen but can't be accounted for.). For making sure only the GM can toggle the grid, you can check if the player calling the command is a GM with the playerIsGM() function built into Roll20. For the snapping_increment, you have to use a persistent storage to backup the value, which is generally the "state" object.&nbsp; The "state" object is a persisted object accessible to all scripts.&nbsp; Be sure you aren't stomping on it and breaking other scripts.&nbsp; Generally, you create a key on it for your script and do what you like in there.&nbsp; I added a state property for ShowGrid and maintain a mapping from pageid to snapping_increment and then use it to restore the value when toggling the grid on. More info on state:&nbsp;<a href="https://wiki.roll20.net/API:Objects#state" rel="nofollow">https://wiki.roll20.net/API:Objects#state</a> Some other things you might consider in this version if you plan to write more API Scripts: It's a good idea to wrap your script in the on('ready',...) event so that it doesn't initialize until the full sandbox is loaded.&nbsp; There are some cases you might not want to do that, but you won't need them until you've written enough scripts to know what they are. When looking for a command, you should make sure the message starts with the command, rather than just contains it.&nbsp; If someone is using your script with some other script, you might get weird behavior matching the command in the middle. It's always nice to see people diving into the API, so definitely ask questions if you have them!&nbsp; Here are some links you might find useful: <a href="https://app.roll20.net/forum/post/6605115/namespaces-novice-seeks-help-exploring-the-revealing-module-pattern" rel="nofollow">https://app.roll20.net/forum/post/6605115/namespaces-novice-seeks-help-exploring-the-revealing-module-pattern</a> <a href="https://app.roll20.net/forum/post/6584105/creating-an-object-that-holds-specific-character-dot-id-and-character-name/?pagenum=1" rel="nofollow">https://app.roll20.net/forum/post/6584105/creating-an-object-that-holds-specific-character-dot-id-and-character-name/?pagenum=1</a> <a href="https://app.roll20.net/forum/post/6237754/slug%7D" rel="nofollow">https://app.roll20.net/forum/post/6237754/slug%7D</a>
Thank you so much for taking the time to do this. it is working perfectly now and you are a star!
1693255867
The Aaron
Roll20 Production Team
API Scripter
No problem!&nbsp; I'd spend all my time with things like this if only I could. =D&nbsp; Glad it's working for you!