Here's an untested script that should call any Macro named "OnTurn" and any character ability named "OnTurn" whenever the turn order changes. This will only activate for token turns, so not for Custom Turn Entries. If you need that capability, let me know. It also respects the !eot command used by many scripts to change the turn. on('ready',()=>{
const playerCanControl = (obj, playerid='any') => {
const playerInControlledByList = (list, playerid) => list.includes('all') || list.includes(playerid) || ('any'===playerid && list.length);
let players = obj.get('controlledby')
.split(/,/)
.filter(s=>s.length);
if(playerInControlledByList(players,playerid)){
return true;
}
if('' !== obj.get('represents') ) {
players = (getObj('character',obj.get('represents')) || {get: function(){return '';} } )
.get('controlledby').split(/,/)
.filter(s=>s.length);
return playerInControlledByList(players,playerid);
}
return false;
};
const resolver = (token,character) => (text) => {
const attrRegExp = /@{(?:([^|}]*)|(?:(selected)|(target)(?:\|([^|}]*))?)\|([^|}]*))(?:\|(max|current))?}/gm;
const attrResolver = (full, name, selected, target, label, name2, type) => {
let simpleToken = JSON.parse(JSON.stringify(token));
let charName = character.get('name');
type = ['current','max'].includes(type) ? type : 'current';
const getAttr = (n, t) => (
findObjs({type: 'attribute', name:n, characterid: character.id})[0]
|| {get:()=>getAttrByName(character.id,n,t)}
).get(t);
const getFromChar = (n,t) => {
if('name'===n){
return charName;
}
return getAttr(n,t);
};
const getProp = (n, t) => {
switch(n){
case 'token_name':
return simpleToken.name;
case 'token_id':
return simpleToken._id;
case 'character_name':
return charName;
case 'bar1':
case 'bar2':
case 'bar3':
return simpleToken[`${n}_${'max'===t ? 'max' : 'value'}`];
}
return getFromChar(n,t);
};
if(name){
return getFromChar(name,type);
}
return getProp(name2,type);
};
return text.replace(attrRegExp, attrResolver);
};
const runCommandsForToken = (token) => {
if(token && token.get('represents')){
let character = getObj('character',token.get('represents'));
let ability = findObjs({
name: 'OnTurn',
type: 'ability',
characterid: character.id
}, {caseinsensitive: true})[0];
let TCRes = resolver(token,character);
if(ability){
let content = TCRes(ability.get('action')).replace(/\[\[\s+/g,'[[');
try {
sendChat(character.get('name'),content);
} catch(e){
log(`OnTurn: ERROR PARSING: ${content}`);
log(`OnTurn: ERROR: ${e}`);
}
}
// look for a macro
findObjs({
type: 'macro',
name: 'OnTurn'
}, {caseinsensitive: true})
.forEach(macro=>{
// if gm macro, always run. Otherwise, run if the token is controlled by the player
if(playerIsGM(macro.get('playerid')) || playerCanControl(character, macro.get('playerid'))){
let content = TCRes(macro.get('action')).replace(/\[\[\s+/g,'[[');
try {
sendChat(character.get('name'),content);
} catch(e){
log(`OnTurn: ERROR PARSING: ${content}`);
log(`OnTurn: ERROR: ${e}`);
}
}
});
}
};
const getTurnArray = () => ( '' === Campaign().get('turnorder') ? [] : JSON.parse(Campaign().get('turnorder')));
const getCurrentTurnToken = () => getObj('graphic',(getTurnArray()[0]||{}).id);
const DoOnEachTurn = () => {
runCommandsForToken(getCurrentTurnToken());
};
on('chat:message', (msg)=>{
if('api'===msg.type && /^!doet\b/i.test(msg.content) && playerIsGM(msg.playerid)){
DoOnEachTurn();
}
});
on('change:campaign:turnorder', ()=>setTimeout(()=>DoOnEachTurn(),1000));
on('chat:message', (msg) => {
if('api'===msg.type && /^![ep]ot\b/.test(msg.content)){
setTimeout(()=>DoOnEachTurn(),1000);
}
});
});