Perfect, thank you so very much
The Aaron said:
Ok, Phil merged this in this morning (because he's AWESOME!) so this should be in the 1-click now.
!token-mod --set statusmarkers|!fluffy-wingElevation Change
!token-mod --set statusmarkers|?fluffy-wing:?{Elevation:|Up,+|Down,-}?{Height in tens of feet, i.e. 30 = 3|0}
The Aaron said:
Hmm. I'll have to check the code. I've only ever tested the ? With relative changes, with the intent of removing it at 0.
!token-mod --set statusmarkers|fluffy-wing[2]:3|fluffy-wing[1]:5I'll look into how I can make that easier to use. =D
The Aaron said:
Makes sense. =D You can use the array syntax if you want more digits...!token-mod --set statusmarkers|fluffy-wing[2]:3|fluffy-wing[1]:5I'll look into how I can make that easier to use. =D
The Aaron said:
I have lots of plans like that... just need more time to do it in... =D
!token-mod --set statusmarkers|-bleeding-eye|-broken-heart|-edge-crack|-screaming|-grab|-lightning-helix|-aura|-chemical-bolt|-back-pain|-fishing-net|-fist|-sleepy|-ninja-mask|-angel-outfit|-red|-blue|-green|-brown|-purple|-pink|-yellow|-dead|-skull|-sleepy|-half-heart|-half-haze|-interdiction|-snail|-lightning-helix|-spanner|-chained-heart|-chemical-bolt|-death-zone|-drink-me|-edge-crack|-ninja-mask|-stopwatch|-fishing-net|-overdrive|-strong|-fist|-padlock|-three-leaves|-fluffy-wing|-pummeled|-tread|-arrowed|-aura|-back-pain|-black-flag|-bleeding-eye|-bolt-shield|-broken-heart|-cobweb|-broken-shield|-flying-flag|-radioactive|-trophy|-broken-skull|-frozen-orb|-rolling-bomb|-white-tower|-grab|-screaming|-grenade|-sentry-gun|-all-for-one|-angel-outfit|-archery-target name|@{selected|character_name}
Craven said:
I call this macro clear status.!token-mod --set statusmarkers|-bleeding-eye|-broken-heart|-edge-crack|-screaming|-grab|-lightning-helix|-aura|-chemical-bolt|-back-pain|-fishing-net|-fist|-sleepy|-ninja-mask|-angel-outfit|-red|-blue|-green|-brown|-purple|-pink|-yellow|-dead|-skull|-sleepy|-half-heart|-half-haze|-interdiction|-snail|-lightning-helix|-spanner|-chained-heart|-chemical-bolt|-death-zone|-drink-me|-edge-crack|-ninja-mask|-stopwatch|-fishing-net|-overdrive|-strong|-fist|-padlock|-three-leaves|-fluffy-wing|-pummeled|-tread|-arrowed|-aura|-back-pain|-black-flag|-bleeding-eye|-bolt-shield|-broken-heart|-cobweb|-broken-shield|-flying-flag|-radioactive|-trophy|-broken-skull|-frozen-orb|-rolling-bomb|-white-tower|-grab|-screaming|-grenade|-sentry-gun|-all-for-one|-angel-outfit|-archery-target name|@{selected|character_name}
Sylverlokk said:
What am I doing wrong with this:
!token-mod --set statusmarkers|!bleeding-eye:?{Turns|1}
it's just supposed to ask for how many turns and set that status on with that number regardless of whether it was on before or not. Is that not possible? Or am I just doing it wrong?
Ziechael said:
You'd be best off posting in the tokenMod thread for help with commands relating to that script but on the face of it I'd say you need to use:!token-mod --set statusmarkers|!bleeding-eye:[[?{Turns|1}]]
To get it to place the status regardless of other ones with a single query (but may affect other statuses if you have a low turn count) you could do:!token-mod --set statusmarkers|!bleeding-eye[?{Turns|1}]:[[?{Turns|1}]]
Or if you are happy with multiple queries:!token-mod --set statusmarkers|!bleeding-eye[?{Index|1}]:[[?{Turns|1}]]
!token-mod --set statusmarkers|bleeding-eye:?{Turns|1}
on('ready',() => { on('chat:message', (msg) => { const who=(getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname'); let cmd, ids, whisper=false; if('api' !== msg.type){ return; } ids = msg.content.split(/\s+/); cmd = ids.shift(); ids = _.union( (playerIsGM(msg.playerid) ? ids : []), ((msg.selected && _.pluck(msg.selected,'_id')) || []) ); switch(cmd){ case '!wstatus': whisper=true; /* eslint-disable no-fallthrough */ case '!status': /* eslint-enable no-fallthrough */ if(ids.length){ _.chain(ids) .uniq() .map( (id) => getObj('graphic',id) ) .reject(_.isUndefined) .reduce( (m,t)=>{ m.push(`<div><b>${t.get('name')}</b>: ${t.get('statusmarkers').split(/,/).map((s)=>s.replace(/@(\d+)/,(a,b)=>`(x${b})`)).join(', ')}</div>`); return m; }, []) .tap((m)=>{ sendChat('',`${whisper ? `/w "${who}" `: ''} ${m.join('')}`); }); } else { sendChat('',`/w "${who}" Use <code>!status</code> with one or more tokens selected, or supply token IDs with <code>!status ID1 ID2</code>. You can use <code>!wstatus</code> to have the results whispered to you.`); } } }); });
!statusto get a listing of their statuses. If you'd rather they were whispered, use:
!wstatusYou can also specify one or more ids as arguments to either command:
!wstatus @{target|token_id}
The Aaron said:
The issue is the ! before bleeding-eye. ! toggle a status on and off, so this would set bleeding-eye with a number on the first use, then clear it, then set it again, etc.
This is probably what you want:!token-mod --set statusmarkers|bleeding-eye:?{Turns|1}
[[1d20+@{selected|status_blue}]]and add 3 if the blue status marker has a 3 on it?
!torg-set
!torg 1d20 --Using some fancy things.
on('ready',()=>{ const version = '0.1.0', lastUpdate = 1507950226, schemaVersion = 0.1; const apiCmd = /^!torg\b($|\s+)/i; const apiCmdSet =/^!torg-set\b/i; const statuses = [ 'red', 'blue', 'green', 'brown', 'purple', 'pink', 'yellow', // 0-6 'skull', 'sleepy', 'half-heart', 'half-haze', 'interdiction', 'snail', 'lightning-helix', 'spanner', 'chained-heart', 'chemical-bolt', 'death-zone', 'drink-me', 'edge-crack', 'ninja-mask', 'stopwatch', 'fishing-net', 'overdrive', 'strong', 'fist', 'padlock', 'three-leaves', 'fluffy-wing', 'pummeled', 'tread', 'arrowed', 'aura', 'back-pain', 'black-flag', 'bleeding-eye', 'bolt-shield', 'broken-heart', 'cobweb', 'broken-shield', 'flying-flag', 'radioactive', 'trophy', 'broken-skull', 'frozen-orb', 'rolling-bomb', 'white-tower', 'grab', 'screaming', 'grenade', 'sentry-gun', 'all-for-one', 'angel-outfit', 'archery-target' ]; const statusColormap = ['#C91010', '#1076c9', '#2fc910', '#c97310', '#9510c9', '#eb75e1', '#e5eb75']; const getStatusIconByIndex = (idx) => (idx<7) ? `<div style="width: 1em; height: 1em; border-radius:20px; display:inline-block; margin: 0; border:0; cursor: pointer;background-color: ${statusColormap[idx]}"></div>` :`<div style="width: 1em; height: 1em; display:inline-block; margin: 0; border:0; cursor: pointer;padding:0;background-image: url('https://app.roll20.net/images/statussheet.png');background-repeat:no-repeat;background-position: ${((-(34/24))*(idx-7))}em 0;background-size:auto 100%;"></div>` ; const getStatusIcon = (status) => getStatusIconByIndex(_.indexOf(statuses,status)); const parseStatuses = (statuses) => { let s = statuses.split(/,/).map((sb)=>({status:sb.split(/@/)[0],num:sb.split(/@/)[1]||0})); return { roll:_.map(s,(st)=>`(${state.TorgStatus.negativeStatuses.includes(st.status) ? '-' :''}${st.num}[${st.status}])`).join('+'), mesg:_.map(s,(st)=>`${state.TorgStatus.negativeStatuses.includes(st.status) ? '-' :'+'}${st.num}${getStatusIcon(st.status)}`).join('') }; }; const checkInstall = () => { log('-=> TorgStatus v'+version+' <=- ['+(new Date(lastUpdate*1000))+']'); if( ! _.has(state,'TorgStatus') || state.TorgStatus.version !== schemaVersion) { log(' > Updating Schema to v'+schemaVersion+' <'); switch(state.TorgStatus && state.TorgStatus.version) { case 0.0: case 'UpdateSchemaVersion': state.TorgStatus.version = schemaVersion; break; default: state.TorgStatus = { version: schemaVersion, negativeStatuses: [] }; break; } } }; on('chat:message',(orig_msg)=>{ if('api' === orig_msg.type) { if(apiCmd.test(orig_msg.content) ){ let msg=_.clone(orig_msg); if(_.has(msg,'inlinerolls')){ msg.content = _.chain(msg.inlinerolls) .reduce(function(m,v,k){ var ti=_.reduce(v.results.rolls,function(m2,v2){ if(_.has(v2,'table')){ m2.push(_.reduce(v2.results,function(m3,v3){ m3.push(v3.tableItem.name); return m3; },[]).join(', ')); } return m2; },[]).join(', '); m['$[['+k+']]']= (ti.length && ti) || v.results.total || 0; return m; },{}) .reduce(function(m,v,k){ return m.replace(k,v); },msg.content) .value(); } let args = msg.content.split(/\s+--/); let roll = args.shift().replace(apiCmd,'')||'0d0'; let mesg = args.join(' '); _.chain(msg.selected) .map((o)=>getObj('graphic',o._id)) .reject(_.isUndefined) .map((o)=>({ t: o, b: parseStatuses(o.get('statusmarkers')) })) .map((o)=>`<div><img style="max-height:1.1em;max-width:2em;" src="${o.t.get('imgsrc')}">[[${roll}+(${o.b.roll})]] ${mesg} ${o.b.mesg}</div>`) .tap(m=>sendChat('',m.join(''))) ; } else if(apiCmdSet.test(orig_msg.content) && playerIsGM(orig_msg.playerid) ){ let who=(getObj('player',orig_msg.playerid)||{get:()=>'API'}).get('_displayname'); _.chain(orig_msg.selected) .map((o)=>getObj('graphic',o._id)) .reject(_.isUndefined) .reduce((m,o)=>_.union(m,o.get('statusmarkers').split(/@\d,|@\d|,/)),[]) .filter(s=>s.length&&s!=='dead') .tap(s=>state.TorgStatus.negativeStatuses=s) .tap(s=>sendChat('',`/w "${who}" Negative Statuses: ${_.map(s,getStatusIcon).join('')}`)) ; } } }); checkInstall(); });
!torg [[0d0 + @{target|DodgeAdds}]] --Using some fancy things.
!torg 1d6 ==level test test|max --some bunch of words to describe things, if you want== must come before --, you can append |max to get the max value, they'll get added in if they exist:
!torg ==level test test|max --some bunch of words to describe things, if you wantand you'll just get the total of the bonuses:
on('ready',()=>{ const version = '0.1.0', lastUpdate = 1508011212, schemaVersion = 0.1; const apiCmd = /^!torg\b($|\s+)/i; const apiCmdSet =/^!torg-set\b/i; const statuses = [ 'red', 'blue', 'green', 'brown', 'purple', 'pink', 'yellow', // 0-6 'skull', 'sleepy', 'half-heart', 'half-haze', 'interdiction', 'snail', 'lightning-helix', 'spanner', 'chained-heart', 'chemical-bolt', 'death-zone', 'drink-me', 'edge-crack', 'ninja-mask', 'stopwatch', 'fishing-net', 'overdrive', 'strong', 'fist', 'padlock', 'three-leaves', 'fluffy-wing', 'pummeled', 'tread', 'arrowed', 'aura', 'back-pain', 'black-flag', 'bleeding-eye', 'bolt-shield', 'broken-heart', 'cobweb', 'broken-shield', 'flying-flag', 'radioactive', 'trophy', 'broken-skull', 'frozen-orb', 'rolling-bomb', 'white-tower', 'grab', 'screaming', 'grenade', 'sentry-gun', 'all-for-one', 'angel-outfit', 'archery-target' ]; const statusColormap = ['#C91010', '#1076c9', '#2fc910', '#c97310', '#9510c9', '#eb75e1', '#e5eb75']; const getStatusIconByIndex = (idx) => (idx<7) ? `<div style="width: 1em; height: 1em; border-radius:20px; display:inline-block; margin: 0; border:0; cursor: pointer;background-color: ${statusColormap[idx]}"></div>` :`<div style="width: 1em; height: 1em; display:inline-block; margin: 0; border:0; cursor: pointer;padding:0;background-image: url('https://app.roll20.net/images/statussheet.png');background-repeat:no-repeat;background-position: ${((-(34/24))*(idx-7))}em 0;background-size:auto 100%;"></div>` ; const getStatusIcon = (status) => getStatusIconByIndex(_.indexOf(statuses,status)); const parseStatuses = (statuses) => { let s = statuses.split(/,/).map((sb)=>({status:sb.split(/@/)[0],num:sb.split(/@/)[1]||0})); return { roll:s.map(st=>`( ${state.TorgStatus.negativeStatuses.includes(st.status) ? '-' :''}${st.num} [${st.status}])`).join('+'), mesg:s.map(st=>` <span style="white-space: nowrap;display:inline-block;border: 1px solid #999;background-color:#eff;border-radius:.4em;padding: .1em .4em;">${state.TorgStatus.negativeStatuses.includes(st.status) ? '-' :'+'}${st.num} ${getStatusIcon(st.status)}</span> `).join(''), total:s.reduce((m,st)=>m+(state.TorgStatus.negativeStatuses.includes(st.status) ? -1 : 1) * st.num, 0) }; }; const checkInstall = () => { log('-=> TorgStatus v'+version+' <=- ['+(new Date(lastUpdate*1000))+']'); if( ! _.has(state,'TorgStatus') || state.TorgStatus.version !== schemaVersion) { log(' > Updating Schema to v'+schemaVersion+' <'); switch(state.TorgStatus && state.TorgStatus.version) { case 0.0: case 'UpdateSchemaVersion': state.TorgStatus.version = schemaVersion; break; default: state.TorgStatus = { version: schemaVersion, negativeStatuses: [] }; break; } } }; const outer = (contents) => `<div style="margin-bottom: .3em;border:1px solid #999;background-color: #ffe;padding: .2em; border-radius:.2em;">${contents}<div style="clear:both;"></div></div>`; const inner = (contents) => `<div>${contents}</div>`; const result = (contents) => `<div style="display:inline-block;font-size: 1.5em; border: 1px solid #999; background-color: #fef; font-weight: bold; border-radius: .2em; padding: .4em .2em;margin-right: .2em;">${contents}</div>`; const icon = (img)=>`<img style="max-height:2.6em;max-width:4em; float:left;" src="${img}">`; const rollFmt = (contents) =>`[[${contents}]]`.replace(/\[\[\s+/,'[[').replace(/\[\[\s+\[\[/,'[[[['); const attrRoll = (attrs) => attrs.map(a=>`${parseInt(a.value)||0} [${a.attr}]`).join('+'); const attrMesg = (attrs) => attrs.map(a=>` <span style="white-space: nowrap;display:inline-block;border: 1px solid #999;background-color:#eff;border-radius:.4em;padding: .1em .4em;">${a.value} ${a.attr}</span> `).join(''); const attrTotal = (attrs) =>attrs.reduce((m,a)=>m+parseFloat(a.value)||0,0); on('chat:message',(orig_msg)=>{ if('api' === orig_msg.type) { if(apiCmd.test(orig_msg.content) ){ let msg=_.clone(orig_msg); if(_.has(msg,'inlinerolls')){ msg.content = _.chain(msg.inlinerolls) .reduce(function(m,v,k){ var ti=_.reduce(v.results.rolls,function(m2,v2){ if(_.has(v2,'table')){ m2.push(_.reduce(v2.results,function(m3,v3){ m3.push(v3.tableItem.name); return m3; },[]).join(', ')); } return m2; },[]).join(', '); m['$[['+k+']]']= (ti.length && ti) || v.results.total || 0; return m; },{}) .reduce(function(m,v,k){ return m.replace(k,v); },msg.content) .value(); } let mesg = msg.content.split(/\s+--/); let attrs = mesg.shift().split(/\s+==/); let roll = attrs.shift().replace(apiCmd,'').trim()||''; attrs=attrs.reduce((m,a)=>_.union(m,a.split(/\s+/)),[]).map(a=>a.toLowerCase()).reduce((m,a)=>{ let p=a.split(/\|/); let n=p[0]; let f=(p[1]==='max'?'max':'current'); return Object.assign(m,{[n]:(m[n]||[]).concat([f])}); },{}); mesg = mesg.join(' '); _.chain(msg.selected) .map((o)=>getObj('graphic',o._id)) .reject(_.isUndefined) .map((o)=>({ t: o, a: findObjs({type:'attribute',characterid:o.get('represents')}) .filter((a)=>Object.keys(attrs).includes(a.get('name').toLowerCase())) .reduce((m,a)=>m.concat(attrs[a.get('name').toLowerCase()].map(f=>({attr:`${a.get('name')}${f==='max'?'|max':''}`,value:a.get(f)}))),[]), b: parseStatuses(o.get('statusmarkers')) })) .map((o)=>outer( icon(o.t.get('imgsrc'))+ inner( result(roll.length ? rollFmt(`${roll}+[attributes:](${attrRoll(o.a)})+[status:](${o.b.roll})`) : (attrTotal(o.a)+o.b.total))+ (mesg.length ? mesg : '') ) + `<div>${attrMesg(o.a)}${o.b.mesg}</div>` )) .tap(m=>{try{sendChat('',m.join(''));}catch(e){log(m);$d({roll});}}) ; } else if(apiCmdSet.test(orig_msg.content) && playerIsGM(orig_msg.playerid) ){ let who=(getObj('player',orig_msg.playerid)||{get:()=>'API'}).get('_displayname'); _.chain(orig_msg.selected) .map((o)=>getObj('graphic',o._id)) .reject(_.isUndefined) .reduce((m,o)=>_.union(m,o.get('statusmarkers').split(/@\d,|@\d|,/)),[]) .filter(s=>s.length&&s!=='dead') .tap(s=>state.TorgStatus.negativeStatuses=s) .tap(s=>sendChat('',`/w "${who}" Negative Statuses: ${_.map(s,getStatusIcon).join('')}`)) ; } } }); checkInstall(); });