The Aaron said: Something like this? Toggle with: !toggle-flashing Note that you need to be fast to toggle them off, when the API makes changes to a token, it deselects it in the UI. If that becomes a problem, I can code up a solution. You can change up the settings at the top of the script. CHANGE_MIN and CHANGE_MAX are the minimum and maximum time between changes. If they are the same, all the selected tokens will flash in sequence, if they're farther apart, you'll get a more random look. EmitPattern is the bright and dim light settings it makes every PHASE_DELAY ms (100ms currently), which is what gives it the pinging look. Code: on('ready',()=>{
const scriptName = 'RandomLightFlash';
const version = '0.1.0';
const schemaVersion = 0.1;
const lastUpdate = 1643644316;
const CHANGE_MIN = 5;
const CHANGE_MAX = 7;
const EmitPattern = [[0,2.5],[2.5,5],[5,10],[5,5],[2.5,5],[0,2.5]];
const PHASE_DELAY = 100;
const checkInstall = () => {
log(`-=> ${scriptName} v${version} <=- [${lastUpdate}]`);
if (
!state.hasOwnProperty(scriptName) ||
state[scriptName].version !== schemaVersion
) {
log(` > Updating Schema to v${schemaVersion} <`);
switch (state[scriptName] && state[scriptName].version) {
case 0.1:
/* break; // intentional dropthrough */ /* falls through */
case "UpdateSchemaVersion":
state[scriptName].version = schemaVersion;
break;
default:
state[scriptName] = {
version: schemaVersion,
options: {},
tokenMap: {}
};
break;
}
}
};
const flashToken = (t) => {
t.set({
emits_bright_light: true,
emits_low_light: true,
});
let phases = [...EmitPattern];
const burndown = () => {
let phase = phases.shift();
if(phase){
t.set({
bright_light_distance: phase[0],
low_light_distance: phase[0]+phase[1]
});
setTimeout(burndown,PHASE_DELAY);
} else {
t.set({
emits_bright_light: false,
emits_low_light: false,
bright_light_distance: 0,
low_light_distance: 0
});
}
};
burndown();
};
const checkTokens = () => {
let now = Date.now();
Object.keys(state[scriptName].tokenMap).forEach(t=>{
if(state[scriptName].tokenMap[t].nextChange < now){
let token = getObj('graphic',t);
if(token){
flashToken(token);
state[scriptName].tokenMap[t].nextChange = now + (CHANGE_MIN + randomInteger(CHANGE_MAX-CHANGE_MIN))*1000;
} else {
delete state[scriptName].tokenMap[t];
}
}
});
};
let interval = setInterval(checkTokens,1000);
on('chat:message',msg=>{
if('api'===msg.type && /^!toggle-flashing(\b\s|$)/i.test(msg.content) && playerIsGM(msg.playerid)){
let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');
let now = Date.now();
(msg.selected || [])
.map(o=>getObj('graphic',o._id))
.filter(g=>undefined !== g)
.forEach(token=>{
if(state[scriptName].tokenMap.hasOwnProperty(token.id)){
delete state[scriptName].tokenMap[token.id];
} else if(token.get('sides').length) {
state[scriptName].tokenMap[token.id] = {
nextChange: now + (CHANGE_MIN + randomInteger(CHANGE_MAX-CHANGE_MIN))*1000
};
}
})
;
}
});
checkInstall();
});
ok this is exactly what i was wanting, unfortunately at the moment it doesn't seem to work, i'm sure it's my fault: it only seems to work on one specific token i use, it's a token called lightsource that i made, it's a multi sided token which can look like several different kinds of lightsource, campfire/torch/brazier/etc. the images are ones i created it has a character sheet with a few basic macros that use token-mod to witch between a few lighting options quickly, it isn't attached to any character or in the player journal, i have tried using other tokens, some with character sheets attached some without, some I've made and also ones from roll20, I've tried using the images that make up the lightsource token but they don't work either, only specifically the lightsource token seems to work, i can't figure out whats special about it compared to the others