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 .
×

TurnMarker1 - option for the marker not to follow?

TurnMarker1... the API we've all grown up with. So always, I say a quiet thank you to The Aaron. (thank you) Question: currently, the marker follows the token. What I find is that my players (and I, for NPCs) often want to retrace their steps back to the square where they started, because of a misunderstanding (e.g. a player says "Oh, I didn't realize we had already identified those squares as trapped, cuz I was in the bathroom or whatever... can I go back and redo my move?). Maybe I'm missing the option, but could we have one where the turn marker doesn't follow the character, but rather serves as an anchor for where it started its turn?
If you select the player's token and hold down the X key it should show you the path that they took.
Craig M. said: TurnMarker1... the API we've all grown up with. So always, I say a quiet thank you to The Aaron. (thank you) Question: currently, the marker follows the token. What I find is that my players (and I, for NPCs) often want to retrace their steps back to the square where they started, because of a misunderstanding (e.g. a player says "Oh, I didn't realize we had already identified those squares as trapped, cuz I was in the bathroom or whatever... can I go back and redo my move?). Maybe I'm missing the option, but could we have one where the turn marker doesn't follow the character, but rather serves as an anchor for where it started its turn? There was something produced by the Aaron I think which I have in my game called Mark Turn Start. This leaves a blue marker where the token starts its turn. Not sure where I got it from though. Hopefully a forum search might find it. 
1769536960
The Aaron
Roll20 Production Team
API Scripter
This is probably it: /* global GroupInitiative */ on('ready',()=&gt;{ const scriptName = 'MarkTurnStartLocation'; const version = '0.1.0'; const schemaVersion = 0.1; const lastUpdate = 1612845685; const getTurnArray = () =&gt; ( '' === Campaign().get('turnorder') ? [] : JSON.parse(Campaign().get('turnorder'))); 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, options: { markerImage: `<a href="https://s3.amazonaws.com/files.d20.io/images/4996490/Ii0ukmjd-IFyjKHtfRrG5w/thumb.png?1406962627`" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/4996490/Ii0ukmjd-IFyjKHtfRrG5w/thumb.png?1406962627`</a>, scale: 1.7 } }; break; } } }; const showImg = (img) =&gt; `&lt;img src="${img}" style="max-width: 3em;max-height: 3em;border:1px solid #333; background-color: #999; border-radius: .2em;"&gt;`; const getCleanImgsrc = (imgsrc) =&gt; { let parts = imgsrc.match(/(.*\/images\/.*)(thumb|med|original|max)([^?]*)(\?[^?]+)?$/); if(parts) { return parts[1]+'thumb'+parts[3]+(parts[4]?parts[4]:`?${Math.round(Math.random()*9999999)}`); } return; }; on('chat:message',msg=&gt;{ if('api'===msg.type &amp;&amp; /^!mark-start(\b\s|$)/i.test(msg.content) &amp;&amp; playerIsGM(msg.playerid)){ let who = (getObj('player',msg.playerid)||{get:()=&gt;'API'}).get('_displayname'); let tokens = (msg.selected || []) .map(o=&gt;getObj('graphic',o._id)) .filter(g=&gt;undefined !== g) ; let msgs = []; let args = msg.content.split(/\s+--/).slice(1); if(0 === args.length){ args.push('help'); } args.forEach((a)=&gt;{ let parts = a.split(/\s+/); switch(parts.shift().toLowerCase()){ case 'set-marker': { if(1 === tokens.length){ let imgsrc = getCleanImgsrc(tokens[0].get('imgsrc')); if(imgsrc){ state[scriptName].options.markerImage = imgsrc; msgs.push(`&lt;div&gt;&lt;div&gt;${showImg(imgsrc)}&lt;/div&gt;Updated start marker.&lt;/div&gt;`); } else { msgs.push(`&lt;div&gt;&lt;div&gt;${showImg(imgsrc)}&lt;/div&gt;&lt;code&gt;Error: Cannot use Marketplace image.&lt;/code&gt;&lt;/div&gt;`); } } else { msgs.push(`&lt;div&gt;&lt;code&gt;Error: Select a single token to collect the image from.&lt;/code&gt;&lt;/div&gt;`); } } break; case 'set-scale': { let scale = parseFloat(parts.shift())||0; if(scale){ if(scale &gt; 5.0){ msgs.push(`&lt;div&gt;&lt;code&gt;Warning: Scale seams pretty large.&lt;/code&gt;&lt;/div&gt;`); } else if( scale &lt; 0.1 ) { msgs.push(`&lt;div&gt;&lt;code&gt;Warning: Scale seams pretty small.&lt;/code&gt;&lt;/div&gt;`); } state[scriptName].options.scale = scale; msgs.push(`&lt;div&gt;Updated start marker scale to &lt;code&gt;${scale}&lt;/code&gt;.&lt;/div&gt;`); } else { msgs.push(`&lt;div&gt;&lt;code&gt;Error: Scale should be a decimal number where 1 means the same size as the token, 1.5 means 50% larger, etc.&lt;/code&gt;&lt;/div&gt;`); } } break; case 'help': { msgs.push(`&lt;h3&gt;MarkTurnStartLocation v${version}&lt;/h3&gt;`); msgs.push(`&lt;div&gt;Creates a marker to show where a token started on when its turn began.&lt;/div&gt;`); msgs.push(`&lt;div&gt;&lt;code&gt;!mark-start [--set-marker] [--set-scale NUMBER]&lt;/code&gt;&lt;/div&gt;`); msgs.push(`&lt;ul&gt;&lt;li&gt;&lt;code&gt;--set-marker&lt;/code&gt; Set the marker image to the image source of the single selected token.&lt;/li&gt;&lt;li&gt;&lt;code&gt;--set-scale NUMBER&lt;/code&gt; Set the scale of the marker image to the supplied NUMBER. Default is &lt;code&gt;1.7&lt;/code&gt;. &lt;code&gt;1.0&lt;/code&gt; makes the image the same size as the token.&lt;/li&gt;&lt;/ul&gt;`); } break; } }); sendChat('',`/w "${who}" &lt;div style="border:1px solid #999;background-color: white;padding:.5em;"&gt;${msgs.join('')}&lt;/div&gt;`); } if('api'===msg.type &amp;&amp; /^!eot\b/.test(msg.content)){ setTimeout(()=&gt;handleTurnOrderChange(Campaign(),{initiativepage:false,turnorder:JSON.stringify([{id:-1}])}),1000); } }); let ClearedIDs = {}; const clearMarkers = ()=&gt;{ findObjs({ type: 'graphic', controlledby: scriptName }).forEach(g=&gt;{ ClearedIDs[g.id]=true; g.remove(); }); }; const addMarker = (tid) =&gt; { let t = getObj('graphic',tid); if(t){ let layer = (t.get('layer') == 'gmlayer') ? 'gmlayer' : 'map'; let props = [ 'pageid', 'left', 'top', 'width', 'height' ] .reduce((m,p)=&gt;({...m,[p]:t.get(p)}),{ imgsrc: state[scriptName].options.markerImage, controlledby: scriptName, layer }); props.width *= state[scriptName].options.scale; props.height *= state[scriptName].options.scale; let m = createObj('graphic', props); if('gmlayer' === layer){ toBack(m); } else { toFront(m); } } }; const handleTurnOrderChange = (obj,prev) =&gt; { let force = (obj.get('initiativepage') !== prev.initiativepage); if(obj.get('initiativepage')){ setTimeout(()=&gt;{ let t = getTurnArray()[0]; if(t){ let pto = (''===prev.turnorder ? [] : JSON.parse(prev.turnorder)); if(pto[0].id !== t.id || force){ clearMarkers(); addMarker(t.id); } } },100); } else { clearMarkers(); } }; const handleChangeGraphic = (obj,prev) =&gt; { if(scriptName === prev.controlledby){ obj.set(prev); } }; const handleDestroyGraphic = (obj) =&gt; { if(ClearedIDs[obj.id]){ setTimeout(()=&gt;delete ClearedIDs[obj.id],1000); } else { let prev = JSON.parse(JSON.stringify(obj)); if(scriptName === prev.controlledby){ prev.pageid=prev._pageid; let m = createObj('graphic',prev); if('gmlayer' === prev.layer){ toBack(m); } else { toFront(m); } } } }; const registerEventHandlers = () =&gt; { on('change:campaign:turnorder',handleTurnOrderChange); on('change:campaign:initiativepage',handleTurnOrderChange); on('change:graphic',handleChangeGraphic); on('destroy:graphic',handleDestroyGraphic); if('undefined' !== typeof GroupInitiative &amp;&amp; GroupInitiative.ObserveTurnOrderChange){ GroupInitiative.ObserveTurnOrderChange((o,p)=&gt;handleTurnOrderChange(Campaign(),{initiativepage: false, turnorder:p})); } }; checkInstall(); registerEventHandlers(); if(Campaign().get('initiativepage')){ handleTurnOrderChange(Campaign(),{initiativepage:false,turnorder:JSON.stringify([{id:-1}])}); } });