Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[Script] Character List

1531769240

Edited 1531835673
MyRoll20Stuffs
API Scripter
After a ton of work and a ton of help from the Aaron, here is the latest version of !character-list Syntax: !character-list (Get a full list of all PCs/NPCs on the map that aren't blacklisted. Clicking on the button pings the token and moves screen to them) !character-list blacklist (Shows you a full list of all PCs/NPCs that aren't blacklisted. Clicking on the button for the specified token/sheet will blacklist it and it won't show up when running "!character-list".) !delete-blacklist (Completely clear all blacklisted tokens/sheet and resets "!character-list" to the default setting of showing ALL NPC/PCs) !blacklist [character id] (Blacklist a specific character sheet. You can opt to run "!character-list blacklist" and blacklist sheets by pressing the buttons, or do it manually with this command if you know the sheet ID) !whitelist [character id] (Remove a certain sheet from the blacklist by specifying the sheet ID.) In order for this script to work, it requires the !ping script I wrote to use the functionality of chat buttons being able to call API functions. It also requires the APISelection script written by The Aaron (Thanks again!) to manage the blacklist. First, here is the updated !character-list script. // By: Kastion // Syntax: !character-list // Profile: <a href="https://app.roll20.net/users/3173313/kastion" rel="nofollow">https://app.roll20.net/users/3173313/kastion</a> const getPageForPlayer = (playerid) =&gt; { let player = getObj('player',playerid); if(playerIsGM(playerid)){ return player.get('lastpage'); } let psp = Campaign().get('playerspecificpages'); if(psp[playerid]){ return psp[playerid]; } return Campaign.get('playerpageid'); }; var Represents = Represents || (function(){ 'use strict'; const keyCharacterBlacklist = 'character-list:blacklist'; var handleInput = function(msg) { if ( "api" !== msg.type || !playerIsGM(msg.playerid) ) { return; } if (msg.content.indexOf("!character-list") === -1 &amp;&amp; msg.content.indexOf("!blacklist") === -1 &amp;&amp; msg.content.indexOf("!delete-blacklist") === -1 &amp;&amp; msg.content.indexOf("!whitelist") === -1) return; let blacklist = APISelection.getList(keyCharacterBlacklist); var rep_id = "" ; rep_id = msg.content.split(" ")[1]; const playerPageID = getPageForPlayer(msg.playerid); const tokens = findObjs({ _pageid: playerPageID, _type: "graphic" }); var buttons = "", hide = ""; if (msg.content.indexOf("!delete-blacklist") !== -1) { APISelection.deleteList(keyCharacterBlacklist); sendChat("CharacterList","/w gm The blacklist has been deleted."); return; } if (msg.content.indexOf("!blacklist") !== -1 &amp;&amp; rep_id !== "") { APISelection.addToList(keyCharacterBlacklist, [rep_id]); sendChat("CharacterList","/w gm The character sheet with the ID [**" + rep_id + "**] has been blacklisted and will not show up when !character-list is ran."); return; } if (msg.content.indexOf("!whitelist") !== -1 &amp;&amp; rep_id !== "") { if (!blacklist.includes(rep_id)) { sendChat("CharacterList","/w gm There was no sheet found with that ID in the blacklist."); return; } else { APISelection.removeFromList(keyCharacterBlacklist, [rep_id]); sendChat("CharacterList","/w gm The character sheet with the ID [**" + rep_id + "**] has been removed from the blacklist."); return; } } if(tokens.length) { _.each(tokens, function(obj) { if (obj.get("represents") != "" &amp;&amp; !blacklist.includes(obj.get('represents'))) { var thisToken = findObjs({ _pageid: playerPageID, _type: "graphic", _represents: obj.get("represents")}); if (thisToken) { var token_name = obj.get("_name").replace(/\(/g,'').replace(/\)/g,'').replace(/\[/g,'').replace(/\]/g,''); if (token_name === "") token_name = "NO NAME"; buttons = buttons + "[" + token_name + "](!ping " + obj.get("_id") + ")"; if (!blacklist.includes(obj.get('represents'))) hide = hide + "[BLACKLIST " + token_name.toUpperCase() + "](!blacklist " + obj.get("represents") + ")"; } } }); if (buttons) { if (msg.content.split(" ")[1] &amp;&amp; msg.content.split(" ")[1] == "blacklist") sendChat("","/w gm " + hide); else sendChat("","/w gm " + buttons); } }; }, registerEventHandlers = function() { on('chat:message', handleInput); }; return { RegisterEventHandlers: registerEventHandlers }; }()); on("ready",function(){ 'use strict'; Represents.RegisterEventHandlers(); log("-=&gt; Character List Script Loaded &lt;=- [Last Edited July 16th 2018]"); }); on('ready',()=&gt;{ on('chat:message',(msg)=&gt;{ if('api' !== msg.type ) { return; } var cmdName = "!ping"; var msgTxt = msg.content; if (msg.type == "api" &amp;&amp; msgTxt.indexOf(cmdName) !== -1 &amp;&amp; playerIsGM(msg.playerid)) { let args = msg.content.split(/\s+/); switch(args.shift().toLowerCase()){ case '!ping': { var t = findObjs({ _pageid: Campaign().get("playerpageid"), _type: "graphic", _id: args[0] }); _.each(t, function(obj) { sendPing(obj.get("left"), obj.get("top"), Campaign().get('playerpageid'), msg.playerid, true); }); } break; } } }); log("-=&gt; Ping command loaded (!ping) &lt;=-") }); // Github: <a href="https://github.com/shdwjk/Roll20API/blob/master/APISelection/APISelection.js" rel="nofollow">https://github.com/shdwjk/Roll20API/blob/master/APISelection/APISelection.js</a> // By: The Aaron, Arcane Scriptomancer // Contact: <a href="https://app.roll20.net/users/104025/the-aaron" rel="nofollow">https://app.roll20.net/users/104025/the-aaron</a> const APISelection = (() =&gt; { // eslint-disable-line no-unused-vars const version = '0.1.0'; const lastUpdate = 1531793735; const schemaVersion = 0.1; const checkInstall = () =&gt; { log('-=&gt; APISelection v'+version+' &lt;=- ['+(new Date(lastUpdate*1000))+']'); if( ! state.hasOwnProperty('APISelection') || state.APISelection.version !== schemaVersion) { log(` &gt; Updating Schema to v${schemaVersion} &lt;`); state.APISelection = { version: schemaVersion, lists: {} }; } }; const isString = (s)=&gt;'string'===typeof s || s instanceof String; const assureArray = (a) =&gt; Array.isArray(a) ? a : [a]; const getList = (id) =&gt; [...(state.APISelection.lists[id] || [])]; const setList = (id, list) =&gt; [ ...(state.APISelection.lists[id] = [...new Set(assureArray(list).filter(isString))])]; const deleteList = (id) =&gt; delete state.APISelection.lists[id] &amp;&amp; []; const removeFromList = (id, list) =&gt; [...(state.APISelection.lists[id] = (state.APISelection.lists[id]||[]).filter((s)=&gt;!assureArray(list).includes(s)))]; const addToList = (id, list) =&gt; [...(state.APISelection.lists[id] = [...new Set([...state.APISelection.lists[id]||[],...assureArray(list).filter(isString)||[]])])]; const handleInput = (msg) =&gt; { if (msg.type !== "api" || !playerIsGM(msg.playerid)) { return; } let args = msg.content.split(/\s+/); switch(args[0]) { case '!api-selection': { const who=(getObj('player',msg.playerid)||{get:()=&gt;'API'}).get('_displayname'); sendChat('API Selection', `/w "${who}" &lt;div&gt;&lt;ul&gt;${Object.keys(state.APISelection.lists).map((id)=&gt;`&lt;li&gt;&lt;code&gt;${id}&lt;/code&gt;&lt;ul&gt;${state.APISelection.lists[id].map((v)=&gt;`&lt;li&gt;${v}&lt;/li&gt;`).join('')}&lt;/ul&gt;&lt;/li&gt;`).join('')}&lt;/ul&gt;&lt;/div&gt;`); } break; } }; const registerEventHandlers = () =&gt; { on('chat:message', handleInput); }; on('ready', () =&gt; { checkInstall(); registerEventHandlers(); }); return { getList, setList, deleteList, removeFromList, addToList }; })(); Thanks again The Aaron for your contributions to this script. If anyone has any issues with the script or if you have any suggestions on how to improve it please let me know.
I get the follow error with this. API Output Console Your scripts are currently disabled due to an error that was detected. Please make appropriate changes to your scripts and click the "Save Script" button and we'll attempt to start running them again.&nbsp; More info... For reference, the error message generated was:&nbsp; SyntaxError: Invalid regular expression: /(/: Unterminated group SyntaxError: Invalid regular expression: /(/: Unterminated group at apiscript.js:22074:56 at Function._.each._.forEach (/home/node/d20-api-server/node_modules/underscore/underscore.js:186:9) at handleInput (apiscript.js:22066:11) at eval (eval at &lt;anonymous&gt; (/home/node/d20-api-server/api.js:151:1), &lt;anonymous&gt;:65:16) at Object.publish (eval at &lt;anonymous&gt; (/home/node/d20-api-server/api.js:151:1), &lt;anonymous&gt;:70:8) at /home/node/d20-api-server/api.js:1634:12 at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560 at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147) at Kd (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546) at Id.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:489) at Zd.Ld.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:94:425) at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:111:400
Sorry about that I accidentally posted an older version of the script while I was still working on it. First post has been updated. Use that version and the problem should be gone.
That fixed it.
1531776370
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Nice!
Script has been updated with additional features made possible by The Aaron's assistance. Any issues or suggestions for features you have feel free to let me know.
1531796161

Edited 1531796251
The Aaron
Pro
API Scripter
I went ahead and published that APISelection script. You can read about it here:&nbsp; <a href="https://app.roll20.net/forum/post/6590837/script-apiselection-a-library-for-script-developers-to-easily-save-persisted-lists-of-ids-and-share-them-between-other-scripts" rel="nofollow">https://app.roll20.net/forum/post/6590837/script-apiselection-a-library-for-script-developers-to-easily-save-persisted-lists-of-ids-and-share-them-between-other-scripts</a> It should show up in the 1-click tomorrow or maybe next week. =D (I went ahead and updated your copy above to the latest version as I made a few minor changes before publishing it. =D)
The Aaron said: I went ahead and published that APISelection script. You can read about it here:&nbsp; <a href="https://app.roll20.net/forum/post/6590837/script-apiselection-a-library-for-script-developers-to-easily-save-persisted-lists-of-ids-and-share-them-between-other-scripts" rel="nofollow">https://app.roll20.net/forum/post/6590837/script-apiselection-a-library-for-script-developers-to-easily-save-persisted-lists-of-ids-and-share-them-between-other-scripts</a> It should show up in the 1-click tomorrow or maybe next week. =D (I went ahead and updated your copy above to the latest version as I made a few minor changes before publishing it. =D) Thanks a ton The Aaron. You've been integral in getting Character List working with the ability to blacklist / whitelist tokens &amp; sheets from the list. I was wondering - what is necessary to get a script added to the 1-click? I've had a script or two that has been requested to be added to 1-click but I don't know where to even start the process. Could you PM me with the details?
1531842067
The Aaron
Pro
API Scripter
For 1-click, you basically need to send a pull request for your script to the github repo, in the proper format, and with the proper script.json file accompanying it.&nbsp; Details here:&nbsp; <a href="https://github.com/Roll20/roll20-api-scripts/blob/master/README.md" rel="nofollow">https://github.com/Roll20/roll20-api-scripts/blob/master/README.md</a> &nbsp; Once your pull is accepted, and provided your script.json is sufficiently filled out, it should get into the 1-click installs.