Last active
October 7, 2022 07:04
-
-
Save keithcurtis1/a30ebe9baffda532f68ed3c6b2ac8d95 to your computer and use it in GitHub Desktop.
Script to change token faces on Roll20
This file contains hidden or 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
var API_Meta = API_Meta || {}; | |
API_Meta.Faces = { | |
offset: Number.MAX_SAFE_INTEGER, | |
lineCount: -1 | |
}; { | |
try { | |
throw new Error(''); | |
} catch (e) { | |
API_Meta.Faces.offset = (parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/, '$1'), 10) - (4)); | |
} | |
} | |
on('ready', () => { | |
const version = '0.1.0'; | |
log('Faces v' + version + ' is ready! --offset ' + API_Meta.Faces.offset + ' -- Use the command !faces [Rollable Table Name] to get started'); | |
}); | |
on('chat:message', (msg_orig) => { | |
let msg = _.clone(msg_orig); | |
if (!/^!faces/.test(msg.content) || msg.content.length === 6) { | |
return; | |
} | |
let whom = ((!playerIsGM(msg.playerid)) ? `"${msg.who}"` : "gm "); | |
let arg = msg.content.split('!faces ')[1]; | |
let imgSrc = ""; | |
let tableName = ""; | |
let itemName = ""; | |
let addName = ""; | |
let argType = ""; | |
let validTable = true; | |
let tokens = []; | |
let tokenID = ""; | |
let newName = ""; | |
let output = ""; | |
let noteButtons = ""; | |
let style = ""; | |
let filterTerm = ""; | |
if (msg.content.includes("filter|")) { | |
filterTerm = msg.content.split(/filter\|/)[1].match(/\b[-?(\w+)?]+\b/gi); | |
msg.content = msg.content.split(/ filter\|/)[0]; | |
arg = msg.content.split('!faces ')[1]; | |
} | |
if (arg.includes("images/")) { | |
argType = "image"; | |
imgSrc = 'https://s3.amazonaws.com/files.d20.io/' + arg; | |
} else { | |
if (msg.content.includes("!faces add ")) { | |
argType = "add"; | |
addName = msg.content.split(/^!faces add /)[1].split(/ to /)[0]; | |
tableName = msg.content.split(/^!faces add .* to /)[1].split(/ using /)[0]; | |
tokenID = msg.content.split(/^!faces add .* using /)[1]; | |
} else { | |
if (msg.content.includes("!faces name ")) { | |
argType = "name"; | |
newName = msg.content.split(/^!faces name /)[1]; | |
} else { | |
if (msg.content.includes("!faces tokennote ")) { | |
argType = "tokennote"; | |
newName = msg.content.split(/^!faces tokennote /)[1]; | |
} else { | |
if (msg.content.includes("!faces tooltip ")) { | |
argType = "tooltip"; | |
newName = msg.content.split(/^!faces tooltip /)[1]; | |
} else { | |
if (msg.content.includes("!faces compact ")) { | |
argType = "table"; | |
style = "compact"; | |
tableName = arg.split('compact ')[1]; | |
} else { | |
if (msg.content.includes("!faces create ")) { | |
argType = "create"; | |
tableName = arg.split('create ')[1]; | |
} else { | |
if (msg.content.includes("!faces existing")) { | |
argType = "tokenFaces"; | |
tableName = "tokenFaces"; | |
} else { | |
argType = "table"; | |
tableName = arg | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
const randomImageButton = "<a href = '!faces images/random "+tableName+"' style = 'display:inline-block; float:right; background-color:transparent; border:none; font-family: pictos; color:#ddd'>;</a>"; | |
const openReport = "<div style='color: #000; border: 1px solid #000; background-color: #ccc; box-shadow: 0 0 3px #000; display: block; text-align: left; font-size: 13px; padding: 5px; margin-bottom: 2px; font-family: sans-serif; white-space: pre-wrap;'>"; | |
const closeReport = '</div>'; | |
const openHeader = "<div style='font-weight:bold; color:#fff; background-color:#404040; margin:0px 3px 3px 0px; padding:3px;'>" | |
const closeHeader = `</div>`; | |
const openButton = "<div style='clear:left; display:inline-block; height: 87px; text-align:center; background-color:#404040; color: #eee; padding: 2px 2px 0px 2px; border-width:1px; border-style: groove; border-radius:43px 43px 3px 3px; margin-right:3px; overflow: hidden'>"; | |
const openNotesButton = "<div style='clear:left; display:inline-block; height: 87px; text-align:left; background-color:#404040; color: #eee; padding: 2px 2px 0px 2px; border-width:1px; border-style: groove; border-radius:40px 3px 3px 3px; margin-right:3px; overflow: hidden'>"; | |
const closeButton = `</div>`; | |
const buttonStyle = `'display: block; text-align:center; padding:0px 5px; margin:10px 0px 0px 0px; color: #eee; background-color:##404040; border-radius:10px'`; | |
const noteButtonStyle = `'display: block; float:right; font-size:11px; line-height:11px; text-align:center; padding:0px 2px 0px 6px; margin:2px 0px 0px 2px; color: #333; background-color:#aaa; border-width:0px; border-radius:10px 0px 0px 10px'`; | |
const noteDeleteButtonStyle = `'display: block; float:right; font-size:11px; line-height:11px; text-align:center; padding:0px 6px 0px 2px; margin:2px 2px 0px px; color: #333; background-color:#aaa; border-width:0px; border-radius:0px 10px 10px 0px'`; | |
function makeImage(url, itemNote) { | |
imageCode = url.split('d20.io/')[1].replace(/thumb\.|med\.|max\.|original\./, 'thumb' + '.') || url; | |
if (style === 'compact') { | |
return `<a href='!faces ${imageCode}' style='width: 35px; height:35px; margin: 0px; padding: 0px; background-color:transparent; border:none'><img src='${url}'></a>` | |
} else { | |
if (!itemNote) { | |
return `<a href='!faces ${imageCode}' style='width: 70px; height: 70px; margin: 0px; padding: 0px; background-color:transparent; border:none'><img src='${url}'></a>` | |
} else { | |
return `<div><a href='!faces ${imageCode}' style='float:left; width: 70px; height: 70px; margin: 0px; padding: 0px; background-color:transparent; border:none'><img src='${url}'></a><div style='display:inline-block; float:left; margin-left:5px; font-size:11px; line-height:12px; height:60px; width:130px;overflow:hidden'>${itemNote}</div></div>` | |
} | |
} | |
} | |
function makeChangeNameButton(name, itemNote) { | |
if (!itemNote) { | |
return "<div style='clear:both '><a style = 'max-width: 70px;white-space: nowrap; overflow: hidden; text-overflow: ellipsis; background-color: transparent; padding: 0px; margin:0px; border:none; color:#eee' title='" + name + "' href='!faces name " + name + "'>" + name + "</a></div>" | |
} else { | |
return "<div style='clear:both '><a style = 'background-color: transparent; padding: 0px; margin:0px; border:none; color:#eee; align:left;' href='!faces name " + name + "'>" + name + "</a><a style = " + noteDeleteButtonStyle + "href = '!faces tooltip -'>x</a><a style = " + noteButtonStyle + "href = '!faces tooltip " + itemNote + "'>tooltip</a><a style = " + noteDeleteButtonStyle + "href = '!faces tokennote -'>x</a><a style = " + noteButtonStyle + "href = '!faces tokennote " + itemNote + "'>notes</a></div>"; | |
} | |
} | |
function makeNotesArea(note) { | |
return ''; | |
} | |
function chatBox(title, text) { | |
if (text) { | |
sendChat('Faces', `/w ${whom}` + openReport + openHeader + title + closeHeader + text + closeReport, null, { | |
noarchive: true | |
}); | |
} else { | |
sendChat('Faces', `/w ${whom}` + openReport + title + closeReport, null, { | |
noarchive: true | |
}); | |
} | |
} | |
switch (argType) { | |
case 'table': | |
case 'add': | |
let tables = findObjs({ | |
type: 'rollabletable', | |
name: tableName | |
}); | |
if (tables.length < 1) { | |
sendChat('Faces', `/w ${whom}` + openReport + openHeader + tableName + randomImageButton + closeHeader + "No table by this name. For this script to work you must use the name of a table that has an image and name for every table item." + closeReport, null, { | |
noarchive: true | |
}); | |
return; | |
} | |
tables = tables[0]; | |
let output = ""; | |
let tableitems = findObjs({ | |
type: 'tableitem', | |
_rollabletableid: tables.get('_id'), | |
}); | |
if (filterTerm.length > 0) { | |
filterTerm.forEach(ft => { | |
tableitems = tableitems.filter(function(t) { | |
return t.get("name").includes(ft); | |
}); | |
}); | |
} | |
tableitems.forEach(t => { | |
itemAvatar = t.get('avatar'); | |
if (itemAvatar.length < 1) { | |
validTable = false | |
} | |
itemName = t.get(('name')).split('--')[0] || t.get(('name')); | |
itemNote = ''; | |
if (t.get('name').includes(' --')) { | |
itemNote = t.get(('name')).split('--')[1]; | |
} | |
if (itemNote.length > 1) { | |
noteButtons = `<a style = ${noteButtonStyle} href = '!tooltip'>tooltip</a>`; | |
} else { | |
noteButtons = ""; | |
} | |
if (itemName.length < 1) { | |
validTable = false | |
} | |
if (validTable) { | |
output = output + `${((itemNote) ? openNotesButton : openButton)}${makeImage(itemAvatar, itemNote)}<BR>${makeChangeNameButton(itemName, itemNote)}${noteButtons}${closeButton}`; | |
} else { | |
output = "Not a valid table. For this script to work you must use the name of a table that has an image and name for every table item."; | |
} | |
}); | |
if (validTable) { | |
output = output + "<br><a style=" + buttonStyle + "href='!faces add ?{name} to " + tableName + " using @{target|token_id}'> Add an image to this table.</a>" | |
} | |
let header = `${openHeader}${tableName}${randomImageButton}${closeHeader}`; | |
if (argType === "add") { | |
if (tokenID !== "") { | |
tokens = getObj('graphic', tokenID) | |
} | |
if (!tokens.get("imgsrc").includes("marketplace")) { | |
createObj('tableitem', { | |
name: addName, | |
_rollabletableid: tables.get('_id'), | |
avatar: tokens.get("imgsrc"), | |
}); | |
output = addName + " added to " + tableName + ".<BR>" + `${openButton}${makeImage(tokens.get("imgsrc"))}<BR>${addName}${closeButton}`; | |
output = output + "<br><a style=" + buttonStyle + "href='!faces " + tableName + "'> Display this table.</a>"; | |
output = output + "<a style=" + buttonStyle + "href='!faces add ?{name} to " + tableName + " using @{target|token_id}'> Add another image to this table.</a>"; | |
} else { | |
output = "API scripts cannot affect marketplace images"; | |
} | |
} | |
sendChat('Faces', `/w ${whom}` + openReport + header + output + closeReport, null, { | |
noarchive: true | |
}); | |
break; | |
//################### Existing Token Faces ############### | |
case 'tokenFaces': | |
if (undefined !== msg.selected) { | |
token = msg.selected | |
.map(o => getObj('graphic', o._id)) | |
.filter(o => undefined !== o)[0] | |
let sides = token.get("sides"); | |
if (sides.length < 1) { | |
sides = token.get("imgsrc") | |
} | |
let tableitems = sides.split('|'); | |
tableName = "Faces for " + ((token.get('name')) ? (token.get('name')) : "Unnamed Token"); | |
let output = ''; | |
tableitems.forEach(t => { | |
itemAvatar = decodeURIComponent(t); | |
itemName = token.get('name'); | |
itemNote = ''; | |
noteButtons = ""; | |
//output = output + `${((itemNote) ? openNotesButton : openButton)}${makeImage(itemAvatar, itemNote)}<BR>${makeChangeNameButton(itemName, itemNote)}${noteButtons}${closeButton}`; | |
output = output + `${((itemNote) ? openNotesButton : openButton.replace("height: 87px","height: 74px"))}${makeImage(itemAvatar)}${closeButton}`; | |
}); | |
let header = `${openHeader}${tableName}${closeHeader}`; | |
sendChat('Faces', `/w ${whom}` + openReport + header + output + closeReport, null, { | |
noarchive: true | |
}); | |
} | |
break; | |
//################### Assign Token Faces ############### | |
case 'image': | |
if (undefined !== msg.selected) { | |
tokens = msg.selected | |
.map(o => getObj('graphic', o._id)) | |
.filter(o => undefined !== o) | |
let randomImage = 0; | |
tokens.forEach(t => { | |
if (t.get("type") === 'graphic') { | |
if (imgSrc.includes('https://s3.amazonaws.com/files.d20.io/images/random')) { | |
tableName = imgSrc.split('https://s3.amazonaws.com/files.d20.io/images/random ')[1]; | |
let tables = findObjs({ | |
type: 'rollabletable', | |
name: tableName | |
}); | |
if (tables.length < 1) { | |
sendChat('Faces', `/w ${whom}` + openReport + openHeader + tableName + closeHeader + "No table by this name. For this script to work you must use the name of a table that has an image and name for every table item." + closeReport, null, { | |
noarchive: true | |
}); | |
return; | |
} | |
tables = tables[0]; | |
tableItems = findObjs({ | |
type: 'tableitem', | |
_rollabletableid: tables.id | |
}); | |
randomImage = tableItems[Math.floor(Math.random() * tableItems.length)].get("avatar") | |
.replace(/thumb\.|med\.|max\.|original\./, 'thumb' + '.'); | |
newImgSrc = randomImage; | |
t.set("imgsrc", newImgSrc); | |
} else { | |
t.set("imgsrc", imgSrc); | |
} | |
} | |
}); | |
} else { | |
sendChat('Faces', `/w ${whom}` + openReport + 'You must select a token you control in order to change the face.' + closeReport, null, { | |
noarchive: true | |
}); | |
} | |
break; | |
case 'name': | |
if (undefined !== msg.selected) { | |
tokens = msg.selected | |
.map(o => getObj('graphic', o._id)) | |
.filter(o => undefined !== o) | |
tokens.forEach(t => { | |
if (t.get("type") === 'graphic') { | |
t.set("name", newName); | |
} | |
}); | |
} | |
break; | |
case 'tokennote': | |
if (newName === '-') { | |
newName = '' | |
}; | |
if (undefined !== msg.selected) { | |
tokens = msg.selected | |
.map(o => getObj('graphic', o._id)) | |
.filter(o => undefined !== o) | |
tokens.forEach(t => { | |
if (t.get("type") === 'graphic') { | |
t.set({ | |
gmnotes: newName | |
}); | |
} | |
}); | |
} | |
break; | |
case 'tooltip': | |
if (newName === '-') { | |
newName = '' | |
}; | |
if (undefined !== msg.selected) { | |
tokens = msg.selected | |
.map(o => getObj('graphic', o._id)) | |
.filter(o => undefined !== o) | |
tokens.forEach(t => { | |
if (t.get("type") === 'graphic') { | |
t.set("tooltip", newName); | |
} | |
}); | |
} | |
break; | |
case 'create': | |
let newTable = tableName; | |
let allTables = findObjs({ | |
type: 'rollabletable', | |
name: tableName | |
}); | |
let tokenFaces = ""; | |
let theFace = "" | |
let tableFaces = []; | |
let i = 0 | |
if (!msg.selected || msg.selected.length < 1) { | |
sendChat("faces", "/w gm You must select a token with at least one face."); | |
return | |
} | |
tokens = msg.selected | |
.map(o => getObj('graphic', o._id)) | |
.filter(o => undefined !== o); | |
tokens.forEach(t => { | |
if (t.get("type") === 'graphic') { | |
tokenFaces = decodeURIComponent(t.get("sides")).split("|"); | |
if (tokenFaces.length === 1) { | |
tokenFaces = t.get("imgsrc").split("|"); | |
} | |
} | |
if (allTables.length < 1) { | |
tableName = tableName.replace(" ", "-"); | |
chatBox(tableName, "Creating new table.") | |
createObj('rollabletable', { | |
name: tableName | |
}); | |
allTables = findObjs({ | |
type: 'rollabletable', | |
name: tableName | |
}); | |
} | |
if (i < 1) { | |
chatBox("Adding faces.") | |
} | |
tableID = allTables[0].get("id"); | |
tokenFaces.forEach(tf => { | |
i++; | |
createObj('tableitem', { | |
name: 'Item_' + i, | |
avatar: tf, | |
_rollabletableid: tableID | |
}); | |
}); | |
}); | |
break; | |
default: | |
log(`nothing happens here.`); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment