Last active
April 18, 2017 19:52
-
-
Save joesinghaus/62e0449c38092e28b1c7ec45ab0fe394 to your computer and use it in GitHub Desktop.
Syncing rollable table tokens with attribute values in Roll20
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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