-
Notifications
You must be signed in to change notification settings - Fork 568
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding hooks to allow token resizing on image change
- Loading branch information
Showing
2 changed files
with
399 additions
and
3 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,395 @@ | ||
// ModifyTokenImage v1.0.5 | ||
// By: Zachare Sylvestre | ||
// Concept was based on ChangeTokenImage but utilizes the Handout Repository, which allows for a little more robust look for tokens. | ||
// | ||
// Version History: | ||
// 1.0.4: Refactoring the GMNotes so that it works a little better with different JSON Objects that might want to use the same item. | ||
// 1.0.5: Adding optional token size parameters to the handout gmnotes. | ||
|
||
var ModifyTokenImage = ModifyTokenImage || (function() { | ||
'use strict'; | ||
var version = '1.0.4'; | ||
var isGmRestricted = true; | ||
var outputDebug = false; | ||
|
||
var setIsGmRestricted = function() { | ||
isGmRestricted = !isGmRestricted; | ||
}; | ||
|
||
var showHelp = function(msg) { | ||
logDebugOutput('showHelp'); | ||
whisperTalker(msg, '<div style="border: solid 1px #000; background-color: #FFF; padding: 3px; width: 100%">' | ||
+ '<div style="padding: 5px; background-color: #FFC; font-weight: bold; text-align: center; margin: 5px; width: 100%; font-size: 14px;">ModifyTokenImage v' + version + '</div>' + | ||
+ 'This API addon allows you to change the current token image to a specific one.' | ||
+ '<br />' | ||
+ '<span style="font-weight: bold;">Setup:</span>' | ||
+ '<p style="margin-left: 4px;">There must be a folder named "Token Images" located in the Journal. For each token you want to enable this functionality, it must have its own folder named under the same name as the token.</p>' | ||
+ '<span style="font-weight: bold;">Commands</span>' | ||
+ '<p style="margin-left: 4px;"><strong>!ModifyTokenImage --next</strong><br />Sets the next Token Image for the selected token.</p>' | ||
+ '</div>'); | ||
}; | ||
|
||
var getTokenImageFolder = function() { | ||
logDebugOutput("getTokenImageFolder"); | ||
var journalFolder = JSON.parse(Campaign().get("_journalfolder")); | ||
var tokenImageFolder = null; | ||
_.each(journalFolder, function(folder) { | ||
if (folder.n == "Token Images") { | ||
tokenImageFolder = folder; | ||
} | ||
}); | ||
return tokenImageFolder; | ||
} | ||
|
||
var getTokenFolder = function(name) { | ||
logDebugOutput("getTokenFolder"); | ||
var tokenImageFolder = getTokenImageFolder(); | ||
if (tokenImageFolder == null) { | ||
return null; | ||
} | ||
var tokenFolder = null; | ||
_.each(tokenImageFolder.i, function (folder) { | ||
if (folder.n == name) { | ||
tokenFolder = folder; | ||
} | ||
}); | ||
return tokenFolder; | ||
}; | ||
|
||
var showCampaignFolder = function(msg) { | ||
logDebugOutput('showCampaignFolder'); | ||
|
||
_.each(getTokenImageFolder, function(folder) { | ||
var folderName = folder.n; | ||
var folderItems = folder.i.length; | ||
whisperTalker(msg, folderName + " Contains " + folderItems + " objects"); | ||
}); | ||
}; | ||
|
||
var currentDateOutput = function() { | ||
var date = new Date(); | ||
var month = date.getMonth() + 1; | ||
var day = date.getDate(); | ||
var hours = date.getHours(); | ||
var minutes = date.getMinutes(); | ||
var seconds = date.getSeconds(); | ||
if (month < 10) { month = "0" + month; } | ||
if (day < 10) { day = "0" + day; } | ||
if (hours < 10) { hours = "0" + hours; } | ||
if (minutes < 10) { minutes = "0" + minutes; } | ||
if (seconds < 10) { seconds = "0" + seconds; } | ||
return date.getFullYear() + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds; | ||
}; | ||
|
||
var setGmNotes = function(token, gmNotesObject) { | ||
token.set({"gmnotes": JSON.stringify(gmNotesObject)}); | ||
}; | ||
|
||
var getGmNotes = function(token) { | ||
var gmNotes = token.get("gmnotes") || "{}"; | ||
try { | ||
gmNotes = decodeURIComponent(gmNotes); | ||
} catch (ex) { | ||
//Ignore. This may fail when the token is empty. | ||
} | ||
if (gmNotes && gmNotes.length) { | ||
gmNotes = gmNotes.trim(); | ||
} | ||
return JSON.parse(gmNotes); | ||
}; | ||
|
||
var whisperTalker = function(msg, contents) { | ||
logDebugOutput('whisperTalker'); | ||
sendChat('ModifyTokenImage', '/w ' + msg.who + ' ' + contents); | ||
}; | ||
|
||
var logDebugOutput = function(item) { | ||
if (!outputDebug) { return; } | ||
log('[ModifyTokenImage:DEBUG:' + currentDateOutput() + '] ' + item); | ||
}; | ||
|
||
var logOutput = function(item) { | ||
log('[ModifyTokenImage:' + currentDateOutput() + '] ' + item); | ||
}; | ||
|
||
var getCleanImagesrc = function (imgsrc) { | ||
var parts = imgsrc.match(/(.*\/images\/.*)(thumb|med|original|max)([^?]*)(\?[^?]+)?$/); | ||
if(parts) { | ||
return parts[1]+'thumb'+parts[3]+(parts[4]?parts[4]:`?${Math.round(Math.random()*9999999)}`); | ||
} | ||
return; | ||
}; | ||
|
||
const getHandoutGmNotes = (handout) => { | ||
return new Promise((resolve) => { | ||
handout.get("gmnotes", (value)=> { | ||
value = decodeURIComponent(value).trim().toString(); | ||
value = value.replace(/(<([^>]+)>)/ig, ';'); | ||
const hashTable = {}; | ||
var valueList = value.split(';'); | ||
for (let i = 0; i < valueList.length; i++) { | ||
var keyval = valueList[i].split(":"); | ||
if (keyval.length != 2) { | ||
continue; | ||
} | ||
var key = keyval[0].trim(); | ||
var val = keyval[1].trim(); | ||
hashTable[key] = val; | ||
} | ||
resolve(hashTable); | ||
}); | ||
}); | ||
}; | ||
|
||
var resizeToken = async function(token, handout) { | ||
let gmnotesObj = await getHandoutGmNotes(handout); | ||
let unit_pixels = 70; | ||
var height = 1; | ||
var width = 1; | ||
|
||
if (gmnotesObj) { | ||
if ("size" in gmnotesObj) { | ||
height = Number(gmnotesObj["size"]); | ||
width = Number(gmnotesObj["size"]); | ||
} else { | ||
if ("width" in gmnotesObj) { | ||
width = Number(gmnotesObj["width"]); | ||
} | ||
if ("height" in gmnotesObj) { | ||
height = Number(gmnotesObj["height"]); | ||
} | ||
} | ||
|
||
} | ||
|
||
let size_params = {"height": (unit_pixels * height), | ||
"width": (unit_pixels * width) }; | ||
token.set(size_params); | ||
}; | ||
|
||
var handleInput = function(msg) { | ||
if (msg.type !== "api") { return; } | ||
if (isGmRestricted && !playerIsGM(msg.playerid)) { return; } | ||
|
||
if (_.has(msg,'inlinerolls')) { | ||
msg.content = _.chain(msg.inlinerolls) | ||
.reduce(function(m,v,k){ | ||
var ti=_.reduce(v.results.rolls,function(m2,v2){ | ||
if(_.has(v2,'table')){ | ||
m2.push(_.reduce(v2.results,function(m3,v3){ | ||
m3.push(v3.tableItem.name); | ||
return m3; | ||
},[]).join(', ')); | ||
} | ||
return m2; | ||
},[]).join(', '); | ||
m['$[['+k+']]']= (ti.length && ti) || v.results.total || 0; | ||
return m; | ||
},{}) | ||
.reduce(function(m,v,k){ | ||
return m.replace(k,v); | ||
},msg.content) | ||
.value(); | ||
} | ||
logDebugOutput(msg.content); | ||
|
||
var args = msg.content | ||
.replace(/<br\/>\n/g, ' ') | ||
.replace(/(\{\{(.*?)\}\})/g," $2 ") | ||
.split(/\s+--/); | ||
|
||
var isModifyTokenImage = false; | ||
|
||
var first = args.shift(); | ||
var command = null; | ||
var setCommand = null; | ||
|
||
logDebugOutput('first:' + first); | ||
switch (first) { | ||
case '!ModifyTokenImage': | ||
while (args.length) { | ||
var cmds = args.shift().match(/([^\s]+[|#]'[^']+'|[^\s]+[|#]"[^"]+"|[^\s]+)/g); | ||
|
||
switch (cmds.shift()) { | ||
case 'help': | ||
showHelp(msg); | ||
return; | ||
case 'campaignfolder': | ||
showCampaignFolder(msg); | ||
return; | ||
case 'next': | ||
isModifyTokenImage = true; | ||
command = 'next'; | ||
break; | ||
case 'previous': | ||
command = 'previous'; | ||
isModifyTokenImage = true; | ||
break; | ||
case 'set': | ||
if (cmds.length) { | ||
command = 'set'; | ||
setCommand = cmds.shift(); | ||
isModifyTokenImage = true; | ||
} else { | ||
showHelp(msg); | ||
return; | ||
} | ||
break; | ||
case 'gm': | ||
if (!playerIsGM(msg.playerid)) { return; } | ||
setIsGmRestricted(); | ||
var allowed = "allow players to use ModifyTokenImage."; | ||
if (!isGmRestricted) { | ||
allowed = "restrict ModifyTokenImage commands to GMs only." | ||
} | ||
whisperTalker(msg, "Now set to " + allowed); | ||
return; | ||
case 'debug': | ||
if (!playerIsGM(msg.playerid)) { return; } | ||
outputDebug = !outputDebug; | ||
var debug = "Debug output enabled."; | ||
if (!outputDebug) { | ||
debug = "Debug output disabled."; | ||
} | ||
whisperTalker(msg, debug); | ||
return; | ||
} | ||
} | ||
break; | ||
} | ||
if (!isModifyTokenImage) { return; } | ||
_.chain(msg.selected) | ||
.uniq() | ||
.map(function(o) { return getObj('graphic', o._id); }) | ||
.reject(_.isUndefined) | ||
.each(function(token) { | ||
if (!playerIsGM(msg.playerid)) { | ||
var controlledBy = token.get("controlledby").split(","); | ||
if (!controlledBy.includes("All") && !controlledBy.includes(msg.playerid)) { | ||
return; | ||
} | ||
} | ||
var name = token.get("name"); | ||
var tokenFolder = getTokenFolder(name); | ||
if (tokenFolder == null) { | ||
whisperTalker(msg, name + " does not have a Token Folder."); | ||
return; | ||
} | ||
var gmNotes = getGmNotes(token); | ||
var current = gmNotes.ModifyTokenImage || {current:0}; | ||
logDebugOutput("currentToken = " + current.current); | ||
var handoutItemId = null; | ||
switch (command) { | ||
case 'next': | ||
var nextHandout = null; | ||
var loops = 0; | ||
while (!nextHandout) { | ||
current.current = current.current + 1; | ||
if (current.current >= tokenFolder.i.length) { | ||
current.current = 0; | ||
loops = loops + 1; | ||
} | ||
if (loops > 2) { | ||
whisperTalker(msg, name + " does not have any valid icons in its folder!"); | ||
return; | ||
} | ||
handoutItemId = tokenFolder.i[current.current]; | ||
nextHandout = getObj("handout", handoutItemId); | ||
} | ||
break; | ||
case 'previous': | ||
var previousHandout = null; | ||
var loops = 0; | ||
while (!previousHandout) { | ||
current.current = current.current - 1; | ||
if (current.current < 0) { | ||
current.current = tokenFolder.i.length - 1; | ||
loops = loops + 1; | ||
} | ||
if (loops > 2) { | ||
whisperTalker(msg, name + " does not have any valid icons in its folder!"); | ||
return; | ||
} | ||
handoutItemId = tokenFolder.i[current.current]; | ||
previousHandout = getObj("handout", handoutItemId); | ||
} | ||
break; | ||
case 'set': | ||
var active = 0; | ||
_.each(tokenFolder.i, function(itemId) { | ||
logDebugOutput("handout: " + itemId); | ||
var item = getObj("handout", itemId); | ||
if (item == null) { | ||
//Ignore this. If its not a handout, it doesn't count! | ||
return; | ||
} | ||
logDebugOutput(" == " + item.get("name")); | ||
if (item.get("name") == setCommand) { | ||
handoutItemId = itemId; | ||
current.current = active; | ||
} else { | ||
active++; | ||
} | ||
}); | ||
break; | ||
} | ||
if (!handoutItemId) { | ||
whisperTalker(msg, name + " did not find a valid item id to switch to!"); | ||
return; | ||
} | ||
var handout = getObj("handout", handoutItemId); | ||
if (!handout) { | ||
whisperTalker(msg, name + " had some invalid handout error. It failed."); | ||
return; | ||
} | ||
var avatar = handout.get("avatar"); | ||
logDebugOutput("avatar = " + avatar); | ||
if (!avatar) { | ||
whisperTalker(msg, handout.get("name") + " handout didn't have an image set."); | ||
return; | ||
} | ||
var cleanImage = getCleanImagesrc(avatar); | ||
logDebugOutput("cleanImage = " + cleanImage); | ||
|
||
gmNotes.ModifyTokenImage = current; | ||
setGmNotes(token, gmNotes); | ||
token.set({"imgsrc": cleanImage}); | ||
|
||
resizeToken(token, handout); | ||
|
||
}); | ||
}; | ||
|
||
var checkInstall = function() { | ||
logOutput('v' + version + ' Starting Up...'); | ||
}; | ||
|
||
var finishInstall = function() { | ||
if (getTokenImageFolder() == null) { | ||
sendChat("ModifyTokenImage", "WARNING: Startup Failed! You need a 'Token Images' Folder for this addon to work properly."); | ||
logOutput("No 'Token Images' folder detected. Addon functions will fail until this folder is created."); | ||
} else { | ||
logOutput('Started up and running properly.'); | ||
} | ||
|
||
} | ||
|
||
var registerEventHandlers = function() { | ||
on('chat:message', handleInput); | ||
logOutput('Event Handlers registered.'); | ||
}; | ||
|
||
|
||
return { | ||
CheckInstall: checkInstall, | ||
RegisterEventHandlers: registerEventHandlers, | ||
FinishInstall: finishInstall | ||
}; | ||
}()); | ||
|
||
on("ready", function() { | ||
'use strict'; | ||
ModifyTokenImage.CheckInstall(); | ||
ModifyTokenImage.RegisterEventHandlers(); | ||
ModifyTokenImage.FinishInstall(); | ||
}); |
Oops, something went wrong.