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

Negative 3d Space movement

I'm looking for an API or macro that handles movement in 3d space in both up and down, from a starting (zero) plane.  The Flight API handles basic elevation nicely, except you can't enter a negative elevation.  Is there something out there that can do that or is there a way to add that ability to Flight? Like is there a simple way to add a "-" to a number on the status marker or even just a color change to the number?  
1607564138

Edited 1607564154
The Aaron
Roll20 Production Team
API Scripter
Depending on how you are setting things up, using TokenMod to set the name with an appended elevation can be pretty useful: !token-mod --set name|"@{selected|character_name} [?{Elevation}m]" ... So I was going to hack the existing fly script to add positive and negative values, but that was obnoxious for a few reasons, so I just rewrote it.  Works just like the old one but supports positive and negative numbers. (Positive are on green, negative are on red) Edit the upStatus and downStatus with the tag names of other statuses if you want something different (look at the help for TokenMod for the tag names of the format:  marker::1234 ) The code:  on('ready', () => { const upStatus = 'green'; const downStatus = 'red'; const decomposeStatuses = (statuses) => statuses.split(/,/).reduce((memo,st,idx) => { let parts=st.split(/@/); let entry = { mark: parts[0], num: parseInt(parts[1],10), idx: idx }; if(isNaN(entry.num)){ entry.num=''; } if(parts[0].length) { memo[parts[0]] = ( memo[parts[0]] && memo[parts[0]].push(entry) && memo[parts[0]]) || [entry] ; } return memo; },{}); const composeStatuses = (statuses) => Object.keys(statuses).reduce((m,k) => { statuses[k].forEach((sd)=>m.push(sd)); return m; },[]) .sort((a,b)=>a.idx-b.idx) .map( (s) => ('dead'===s.mark ? 'dead' : ( s.mark+(s.num!=='' ? '@'+s.num : ''))) ) .join(','); const statusSetter = (n) => { let s = { [n>0?upStatus:downStatus]: n.toString() .split('') .filter(c=>/\d/.test(c)) .map((c,i) => ({ mark: (n>0 ? upStatus : downStatus), num: c, idx: 10000+i })) }; const clean = (sm) => { delete sm[ (n>0 ? downStatus : upStatus) ]; return sm; }; const set = (sm) => ({...sm,...s}); return (t) => t.set({ statusmarkers: composeStatuses(set(clean(decomposeStatuses(t.get('statusmarkers'))))) }); }; const processInlinerolls = (msg) => { if(msg.hasOwnProperty('inlinerolls')){ return msg.inlinerolls .reduce((m,v,k) => { let ti=v.results.rolls.reduce((m2,v2) => { if(v2.hasOwnProperty('table')){ m2.push(v2.results.reduce((m3,v3) => [...m3,v3.tableItem.name],[]).join(", ")); } return m2; },[]).join(', '); return [...m,{k:`$[[${k}]]`, v:(ti.length && ti) || v.results.total || 0}]; },[]) .reduce((m,o) => m.replace(o.k,o.v), msg.content); } else { return msg.content; } }; on('chat:message',msg=>{ if('api'===msg.type && /^!fly(\b\s|$)/i.test(msg.content) ){ let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname'); let args = processInlinerolls(msg).split(/\s+/); if(args.length < 2) { sendChat('fly', `/w "${who}" <div><b>Usage:</b> <code>!fly [NUMBER]</code> with tokens selected.</div>`); return; } let num = parseInt(args[1]); let tokens = (msg.selected || []) .map(o => getObj('graphic',o._id)) .filter(t => undefined !== t) .filter(t => t.get('subtype') === 'token') ; let ss = statusSetter(num); tokens.map(ss); } }); });
1607604440
David M.
Pro
API Scripter
Nifty. Now if only I can remember to use it when my PCs get high enough level for flight and/or underwater combat :)
@ The Aaron, that is prefect! thanks