Skip to content

Instantly share code, notes, and snippets.

@joesinghaus
Last active April 18, 2017 19:52
Show Gist options
  • Save joesinghaus/62e0449c38092e28b1c7ec45ab0fe394 to your computer and use it in GitHub Desktop.
Save joesinghaus/62e0449c38092e28b1c7ec45ab0fe394 to your computer and use it in GitHub Desktop.
Syncing rollable table tokens with attribute values in Roll20
// Version: 2017-04-17
// Description: This an API script for Roll20 that allows you to sync rollable table tokens
// with the value of an attribute.
// Usage: Create a rollable table where the x-th entry of the table corresponds to value x
// of the attribute.
//
// * Adding tokens to sync: Create one or more rollable table tokens. Set them to represent
// the character you want them to synchronise with. Select the tokens and enter
// !sync-table add <name>,
// where <name> is the name of the attribute to sync with, e.g. !sync-table add stress.
//
// * Removing tokens from sync list: select them and enter !sync-table remove.
//
// * Showing all synced tokens/characters/attributes: enter !sync-table show.
//
// * Reset everything to defaults: enter !sync-table clear.
//
//
// WARNING: The script does not necessarily check for presence of characters or tokens.
// Just deleting synchronised characters or tokens may lead to a crash in bad cases. If
// the attribute takes a value bigger than the highest entry on the rollable table, the
// last value will be used instead.
var syncTableToken = syncTableToken || (function () {
'use strict';
let checkInstall = function () {
state.SyncTableToken = (state.SyncTableToken || {
data: []
});
state.SyncTableToken.data = state.SyncTableToken.data.filter(v => {
return (getObj('graphic', v.token) && getObj('character', v.character));
});
},
handleInput = function (msg) {
if (msg.type === 'api' && msg.content.match(/^!sync-table/) && playerIsGM(msg.playerid)) {
switch (msg.content.split(' ')[1]) {
case 'add':
if (!msg.selected) return;
let attrName = msg.content.split(' ')[2];
if (!attrName) {
sendChat('', '/w GM You need to supply an attribute name to sync with.');
} else {
msg.selected.forEach(function (o) {
let token = getObj('graphic', o._id);
if (!token || !token.get('sides')) return;
let character = getObj('character', token.get('represents'));
if (!character) return;
state.SyncTableToken.data.push({
character: token.get('represents'),
token: token.id,
attribute: attrName.toLowerCase()
});
sendChat('', `/w GM Synchronization added for attribute ${attrName} and character ${character.get('name')}.`,
null, {
noarchive: true
});
});
}
break;
case 'remove':
if (!msg.selected) return;
let selectedIDs = msg.selected.map(o => o._id);
state.SyncTableToken.data = state.SyncTableToken.data.filter(function (v) {
if (selectedIDs.includes(v.token)) {
let charName = getObj('character', v.character).get('name');
sendChat('', `/w GM Synchronization removed for attribute ${v.attribute} and character ${charName}.`,
null, {
noarchive: true
});
return false;
} else return true;
})
break;
case 'show':
let output = '/w GM SyncTable is active for characters ' +
state.SyncTableToken.data.map(v => getObj('character', v.character).get('name')).join(', ') + '.';
sendChat('', output, null, {
noarchive: true
});
break;
case 'clear':
state.SyncTableToken = {
data: []
};
sendChat('', '/w GM SyncTable cleared.', null, {
noarchive: true
});
}
}
},
handleSideChange = function (token) {
state.SyncTableToken.data.filter(v => (v.token === token.id)).forEach(function (data) {
let attr = findObjs({
type: 'attribute',
characterid: data.character,
name: data.attribute
}, {
caseInsensitive: true
})[0] || createObj({
type: 'attribute',
characterid: data.character,
name: data.attribute
});
attr.set('current', token.get('currentSide'));
});
},
handleAttrChange = function (attr) {
state.SyncTableToken.data.filter(v => {
return (v.character === attr.get('characterid')) && (v.attribute === attr.get('name').toLowerCase());
}).forEach(function (data) {
let current = parseInt(attr.get('current')) || 0,
token = getObj('graphic', data.token);
if (!token) return;
let sides = token.get('sides').split('|');
token.set({
currentSide: current,
imgsrc: decodeURIComponent(sides[current] || sides[sides.length - 1]).replace('max', 'thumb')
});
});
},
handleTokenRemove = function (token) {
state.SyncTableToken.data = state.SyncTableToken.data.filter(v => (v.token !== token.id));
},
handleCharRemove = function (character) {
state.SyncTableToken.data = state.SyncTableToken.data.filter(v => (v.character !== character.id));
},
registerEventHandlers = function () {
on('chat:message', handleInput);
on('change:graphic:currentSide', handleSideChange);
on('change:attribute', handleAttrChange);
on('destroy:graphic', handleTokenRemove);
on('destroy:character', handleCharRemove);
};
return {
CheckInstall: checkInstall,
RegisterEventHandlers: registerEventHandlers
};
}());
on('ready', function () {
'use strict';
syncTableToken.CheckInstall();
syncTableToken.RegisterEventHandlers();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment