You are correct, you need an API script involved. I have one I wrote that depends on libTokenMarkers from the 1-click. This script will create attributes on the character named sm_MARKER_NAME, so sm_blue, sm_poisoned, etc. for every available status marker and set the value to 0. It will then adjust the value to whatever number you assign to it. I wrote this script a while ago, so let me know if it has any problems, and be sure to install libTokenMarkers along with it. Code: /* global libTokenMarkers */
on('ready',() => {
// Make sure libTokenMarkers exists, and has the functions that are expected
if('undefined' === typeof libTokenMarkers
|| (['getStatus','getStatuses','getOrderedList'].find(k=>
!libTokenMarkers.hasOwnProperty(k) || 'function' !== typeof libTokenMarkers[k]
))
) {
// notify of the missing library
sendChat('',`/w gm <div style="color:red;font-weight:bold;border:2px solid red;background-color:black;border-radius:1em;padding:1em;">Missing dependency: libTokenMarkers</div>`);
} else {
const markerOnValue = 1;
let allMarkers = libTokenMarkers.getOrderedList();
let tagToMarkerLookup = allMarkers.reduce((m,tm)=>{
m[tm.getTag()]=tm;
return m;
},{});
const markerAttrRegexp=new RegExp(`^sm_(?:${allMarkers.map(m=>m.getName()).join('|')})$/;`,'i');
const getOrCreateAttr = (()=>{
let cache = findObjs({ type: 'attribute'})
.filter( a => markerAttrRegexp.test(a.get('name')))
.reduce( (m,a) => {
const cid=a.get('characterid');
m[cid]=m[cid]||{};
m[cid][a.get('name')]=a;
return m;
},{});
return (p)=>{
if(!cache.hasOwnProperty(p.characterid) || !cache[p.characterid].hasOwnProperty(p.name)){
cache[p.characterid]=cache[p.characterid]||{};
cache[p.characterid][p.name] = createObj('attribute',p);
}
return cache[p.characterid][p.name];
};
})();
const setStatus = (cid, m, v) => getOrCreateAttr({
type: 'attribute',
name: `sm_${m.getName()}`,
characterid: cid
}).set('current',parseInt(v,10)||0);
const handleStatusMarkerChange = _.debounce((obj,prev) => {
if(obj.get('represents').length) {
let character = getObj('character',obj.get('represents'));
if(character && character.get('controlledby').length){
let sm = obj.get('statusmarkers');
if(sm!==prev.statusmarkers){
prev.statusmarkers.split(/,/)
.filter(s=>s.length)
.map((s)=>s.split(/@/))
.forEach( s => setStatus(character.id,tagToMarkerLookup[s[0]]))
;
sm.split(/,/)
.filter(s=>s.length>0)
.map((s)=>s.split(/@/))
.forEach( s => setStatus(character.id,tagToMarkerLookup[s[0]],parseInt(s[1],10)||markerOnValue))
;
}
}
}
},10);
const markersFor = (c) => allMarkers.map( m => ({characterid: c.id, name: `sm_${m.getName()}`, current: 0}) );
const preCreateMarkersOn = (c) => {
let queue = markersFor(c);
const dequeue = () => {
let prop = queue.shift();
if(prop){
getOrCreateAttr(prop);
setTimeout(dequeue,0);
}
};
dequeue();
};
const handleControlledbyChange = (obj,prev) => {
if( 0 === prev.controlledby.length) {
preCreateMarkersOn(obj);
}
};
on('change:graphic',handleStatusMarkerChange);
on('change:character:controlledby',handleControlledbyChange);
/* global TokenMod */
if('undefined' !== typeof TokenMod && TokenMod.ObserveTokenChange){
TokenMod.ObserveTokenChange(handleStatusMarkerChange);
}
const workQueue = findObjs({ type: 'character' })
.filter( c => c.get('controlledby').length )
.reduce( (m,c) => [...m, ...markersFor(c)], []);
log(`RealizeStatusmarkers: Initializing attributes: ${workQueue.length}`);
const drainQueue = () => {
let prop = workQueue.shift();
if(prop){
getOrCreateAttr(prop);
setTimeout(drainQueue,0);
} else {
log(`RealizeStatusmarkers: Finished initializing attributes.`);
}
};
drainQueue();
}
});