Ok, I wrote this script that should do what you want. Just copy the contents into the API in a new script and save. it. It will start working on the Game fixing all the tokens. You'll see output like: When it's done, you should have everything set the way you want it, with all tokens and characters updated. For NPCs, it will set their hp current to max and max to max, for PCs, it will set the current to whatever the current is, and the max to the max. Here's the script. As usual, I suggest trying this on a copy of the Game before doing it on the real deal. on('ready',()=>{
const attr = (c,n) => (findObjs({ type: 'attribute', characterid: c.id, name: n })[0]||{get:()=>0});
let characters = {};
const fixToken = (t) => {
let c = getObj('character',t.get('represents'));
if(c){
let npc = (attr(c,'npc').get('current')>0);
let ac = attr(c, (npc ? 'npc_ac' : 'ac'));
let wis = attr(c,'wisdom_mod');
let per_skill = attr(c,'perception_prof');
let per_base = attr(c,'npc_perception_base');
let senses = (`${attr(c,'npc_senses').get('current')}`.match(/passive\s+perception\s+(\d+)/i)||[0,0])[1];
let hp = attr(c,'hp');
let pb = attr(c,'pb');
let pw = attr(c,'passive_wisdom');
let passivePerception = 10 + (npc ? parseInt(per_base.get('current')) : (parseInt(wis.get('current')) + parseInt(((`${per_skill.get('current')}`.length>0) ? pb.get('current') : 0))));
t.set({
bar1_link: ( ac ? ac.id : (npc ? 'sheetattr_npc_ac' : 'sheetattr_ac' )),
bar2_link: (npc ? '' : (pw ? pw.id : 'sheetattr_passive_wisdom')),
bar3_link: ( npc ? '' : hp.id),
bar1_value: ac.get('current'),
bar2_value: (parseInt(senses) || passivePerception),
bar3_value: (npc ? hp.get('max') : hp.get('current')),
bar1_max: '',
bar2_max: '',
bar3_max: hp.get('max')
});
let p = getObj('page',t.get('pageid'));
let scale = parseFloat(p.get('snapping_increment'));
if( !characters.hasOwnProperty(c.id) && c.get('name') === t.get('name')) {
let w = parseInt(t.get('width'));
let h = parseInt(t.get('height'));
if(scale<1){
let mod = 1/scale;
t.set({
height: Math.floor(h*mod),
width: Math.floor(w*mod)
});
}
setDefaultTokenForCharacter(c,t);
if(scale<1){
t.set({
height: h,
width: w
});
}
characters[c.id] = true;
}
}
};
on('chat:message', (msg) => {
if('api'===msg.type && /^!fix-bars\b/i.test(msg.content) && playerIsGM(msg.playerid)) {
let args = msg.content.split(/\s+/).map(s => s.toLowerCase());
let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');
let workQueue = {};
if(args.includes('--all')){
workQueue = findObjs({type:'graphic'});
} else if(msg.selected){
workQueue = msg.selected
.map(o=>getObj('graphic',o._id))
.filter(g=>undefined !== g)
;
} else {
sendChat('Fix Bars', `/w "${who}" <div>Select one or more tokens to fix bar mappings on, or use <code>!fix-bars --all</code> to fix bar mappings on all tokens in the game.</div>`);
return;
}
let count = 0;
let timeMark = Date.now();
const drainQueue = ()=>{
let t = workQueue.shift();
if(t){
fixToken(t);
++count;
if((Date.now()-timeMark)>5000){
timeMark = Date.now();
sendChat('Fixing Tokens',`/w gm ...${count}`);
}
setTimeout(drainQueue,0);
} else {
characters = {};
sendChat('Fixing Tokens',`/w gm Finished Fixing Tokens`);
}
};
sendChat('Fixing Tokens',`/w gm Fixing ${workQueue.length} Tokens`);
drainQueue();
}
});
});
Edit: Changed script to default to using the passive Perception number in npc senses, falling back on calculation. (Thanks Keith!) Edit 2: Updated the script to fix the map scale causing the token to be small. Also made some speed improvements. Edit 3: Change to only set default token if the name of the Token matches the name of the Character. Fix for scaling issues. Edit 4: Changed to require the !fix-bars command to be run instead of kicking off immediately. If you have nothing selected, it will fix all tokens. If you have some set of tokens selected, it will only fix those tokens (and the default token for the character), but not any other tokens representing that character. Edit 5: Added --all option to fix all tokens, and help output if nothing is selected to tell you what to do.