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 you get a DL drawing object via the api? How about a specific one? Oooooo, that would be cool.

1726290533

Edited 1726290754
GM
Pro
They don't have token IDs. So how can we select one programmatically? By color maybe? That would be convenient. Use case: I want to move a light barrier as I move a token on the objects layer. This will allow enemy ships (or our own) to hide behind things like asteroids. Further in depth... I have a radar scope, and I wanted to simulate ship movement. To accomplish this, I move all token that are on the GM or objects layer that include certain bar 2 values in the opposite direction from the one the Ship pilot indicates (see below). Those too far away (at the edge of the scope) are moved to the gmlayer to not mess with the Battle UI appearance. I manually move them back to the objects layer if they are discovered. All good, right? It works beautifully, but not with an object that blocks light. For that, I need to move those walls/one-ways just like any other token on my list. "But how?", he asks... tokens.forEach(token => { const bar3 = token.get('bar3_value'); if (['obstacle', 'ship', 'base', 'torpedo', 'moon', 'planet','los'].includes(bar3) && token.get('name') !== 'Ship') { // Move the token according to the direction const currentX = token.get('left'); const currentY = token.get('top'); const offsetX = offsets[direction].x; const offsetY = offsets[direction].y; token.set({ left: currentX + offsetX, top: currentY + offsetY }); // Check distance from the "Ship" token const distance = Math.sqrt(Math.pow((token.get('left') - ship.get('left')), 2) + Math.pow((token.get('top') - ship.get('top')), 2)); if (distance > 12.5 * hexSize) { token.set('layer', 'gmlayer', 'walls'); } }
1726325355
The Aaron
Roll20 Production Team
API Scripter
You can definitely do this.  As an example, here's a little script I threw together for a game.  It links a bunch of DL lines to a graphic so that if you move the graphic, it moves the lines in correspondence. Usage: Select a graphic and run !dl-link Switch to the DL layer and select some lines, run !dl-link Repeat step 2 until all lines are linked to the token. Code: on('ready',()=>{ const scriptName = 'DLLink'; const version = '0.1.0'; const schemaVersion = 0.1; const lastUpdate = 1662075424; let pendingToken; const checkInstall = () => { log(`-=> ${scriptName} v${version} <=- [${lastUpdate}]`); if ( !state.hasOwnProperty(scriptName) || state[scriptName].version !== schemaVersion ) { log(` > Updating Schema to v${schemaVersion} <`); switch (state[scriptName] && state[scriptName].version) { case 0.1: /* break; // intentional dropthrough */ /* falls through */ case "UpdateSchemaVersion": state[scriptName].version = schemaVersion; break; default: state[scriptName] = { version: schemaVersion, options: {}, links: {} }; break; } } }; checkInstall(); on('chat:message',msg=>{ if('api'===msg.type && /^!dl-link(\b\s|$)/i.test(msg.content) && playerIsGM(msg.playerid)){ let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname'); let objs = (msg.selected || []) .map(o=>getObj(o._type,o._id)) .filter(g=>undefined !== g) ; objs.forEach(o=>{ if('graphic' === o.get('type')){ pendingToken = o; } else if('path'=== o.get('type')){ if(pendingToken){ state[scriptName].links[pendingToken.id] = [...(state[scriptName].links[pendingToken.id]||[]), o.id]; } } }); } }); on('change:graphic', (obj,prev)=>{ let s=state[scriptName].links[obj.id]; if(s){ let dR = obj.get('rotation')-prev.rotation; let dX = obj.get('left')-prev.left; let dY = obj.get('top')-prev.top; s.map(id=>getObj('path',id)) .filter(g=>undefined !== g) .forEach(p=>p.set({ rotation: p.get('rotation')+dR, left: p.get('left')+dX, top: p.get('top')+dY })); } }); });
1726376119

Edited 1726376431
GM
Pro
Holy Cow @The Aaron. That's a crazy helpful script. I can think of a few places I'd use that. I ended up solving this problem just now the way I solve most of them... I'm lying in bed not thinking about it, and I smack my forehead and get up. I simply moved the DL barriers in the same way I move the tokens. No need to tie them to each other, as all objects move the same direction/distance relative to the only token named "ship". I also don't have to worry about moving all my fixed barriers, since I just randomly defaulted to yellow on those, and I now use exclusively white strokes on the ones that are "moving objects". Plus, #ffffff is easy to remember and type. In the script I called the DL barriers "lights" because I don't know why. It's late here in central florida. on('chat:message', function(msg) { if (msg.type !== 'api') return; const args = msg.content.split(' '); if (args[0] !== '!mover') return; const direction = args[1]; // up, down, upR, upL, downR, downL const hexSize = 24; // Size of one hex in Roll20 // Define movement offsets for each direction const offsets = { up: { x: 0, y: -hexSize * 1.144 }, down: { x: 0, y: hexSize * 1.144 }, upR: { x: hexSize, y: -hexSize * 0.566 }, upL: { x: -hexSize, y: -hexSize * 0.566 }, downR: { x: hexSize * 0.995, y: hexSize * 0.566 }, downL: { x: -hexSize * 0.995, y: hexSize * 0.566 } }; const page = getObj('page', Campaign().get('playerpageid')); if (!page || page.get('name') !== 'GHUD') return; const tokens = findObjs({ type: 'graphic', pageid: page.id }); const lights = findObjs({ type: 'path', stroke: '#ffffff' }); const ship = tokens.find(token => token.get('name') === 'Ship'); if (!ship) return; tokens.forEach(token => { const bar3 = token.get('bar3_value'); if (['obstacle', 'ship', 'base', 'torpedo', 'moon', 'planet'].includes(bar3) && token.get('name') !== 'Ship') { // Move the token according to the direction const currentX = token.get('left'); const currentY = token.get('top'); const offsetX = offsets[direction].x; const offsetY = offsets[direction].y; token.set({ left: currentX + offsetX, top: currentY + offsetY }); // Check distance from the "Ship" token const distance = Math.sqrt(Math.pow((token.get('left') - ship.get('left')), 2) + Math.pow((token.get('top') - ship.get('top')), 2)); if (distance > 12.5 * hexSize) { token.set('layer', 'gmlayer', 'walls'); } } }); lights.forEach(light => { const stroke = light.get('stroke'); if (stroke === '#ffffff') { // Move the token according to the direction const currentX = light.get('left'); const currentY = light.get('top'); const offsetX = offsets[direction].x; const offsetY = offsets[direction].y; light.set({ left: currentX + offsetX, top: currentY + offsetY }); // Check distance from the "Ship" token const distance = Math.sqrt(Math.pow((light.get('left') - ship.get('left')), 2) + Math.pow((light.get('top') - ship.get('top')), 2)); if (distance > 12.5 * hexSize) { light.set('layer', 'gmlayer', 'walls'); } } }); });