Skip to content

Instantly share code, notes, and snippets.

@Parmeisan
Last active November 18, 2017 04:12
Show Gist options
  • Save Parmeisan/9864305 to your computer and use it in GitHub Desktop.
Save Parmeisan/9864305 to your computer and use it in GitHub Desktop.
Roll20 - Deck Utilities
var parm_deck_util = parm_deck_util || {};
parm_deck_util.debugging = false;//true;//
parm_deck_util.speak_as = "Deck-Util";
parm_deck_util.whisper = "";
parm_deck_util.deck;
parm_deck_util.rtable;
on("chat:message", function(msg)
{
var ns = parm_deck_util;
var words = msg.content.split(" ");
var w = 0;
if(msg.type == "api" && words[w++] == "!deck-util")
{
// You must include one or both of a Deck name or a Rollable Table name
// If the Deck is "none" or invalid, then it uses the Rollable Table.
// If you leave out the Rollable Table, it checks for one with the same
// name as the Deck. If that's "none" or invalid, it uses weights all at 1.
var deck_name = words[w++];
var rtable_name;
if (words[w].indexOf("!") == 0) rtable_name = deck_name;
else rtable_name = words[w++];
ns.deck = findObjs({ _type: "deck", name: deck_name })[0];
ns.rtable = findObjs({ _type: "rollabletable", name: rtable_name })[0];
// Check to see whether to to randomly pick one (the default) or to return everything.
var listing = (_.indexOf(words, "!all") >= 0);
// Check whether to create a token or not. At some point, this will deal from the
// deck when a valid deck is given, but right now all it can do is create new
// tokens objects, so I'll just use the rollable table image or card images.
var make_token = (_.indexOf(words, "!token") >= 0);
// Check to see who to reply to (everyone by default)
ns.whisper = (_.indexOf(words, "!w") >= 0) ? "/w " + msg.who + " " : "";
// If the input contains !filter, parse from that to the end (or the next !)
// All the words in this section should begin and end with quotes.
// Words with no operator must be in the results.
// Words beginning with ^ must not be in the results.
var filters = [];
for (var i = _.indexOf(words, "!filter") + 1; 0 < i && i < words.length; i++)
{
if (words[i].indexOf("!") == 0) break;
else
{
// Technically, all words and word groups must be surrounded with quotes.
// In practice, I'm going to add all words that don't start with a quote
// to the preceding word, and ignore all other quotes.
// Except the first word - it should still be treated as the first word.
var trimmed = ns.replaceAll(words[i], "\"", "");
if (words[i].indexOf("\"") == 0)
filters[filters.length] = trimmed;
else
{
var pos = _.max([0 , filters.length - 1]);
filters[pos] = filters[pos] + " " + trimmed;
}
}
}
// Anything that isn't expected is ignored.
// Now... *rubs hands*
ns.debug("Deck: " + deck_name);
ns.debug("RTable: " + rtable_name);
ns.debug("Filters: " + filters);
// Load up an array with the Rollable Table values that match
var rt = [];
if (ns.isnull(ns.rtable)) {} // Fill from deck instead
else
{
var rt_items = findObjs({ _type: "tableitem", _rollabletableid: ns.rtable.get("id") });
ns.debug("Found " + rt_items.length);
_.each(rt_items, function (item, key)
{
var desc = item.get("name");
var weight = item.get("weight");
if (ns.matches(desc, filters))
{
// Include once if listing, once per weight if picking randomly
if (listing) rt[rt.length] = desc;
else for (var i = 0; i < weight; i++) rt[rt.length] = desc;
}
});
}
// Report the reults
ns.debug("rt: " + rt);
if (ns.isnull(rt)) ns.info("No matches.")
else
{
ns.info("Matches:");
if (listing)
{
// Output them all
_.each(rt, function (item, key) { ns.result(item, make_token); });
}
else
{
// Now randomly choose one.
var r = Math.floor(Math.random() * rt.length);
ns.result(rt[r], make_token);
}
}
}
});
// Outputs the result of the query, create a token if needed
parm_deck_util.result = function(i_name, make_token)
{
var ns = parm_deck_util;
ns.info(i_name);
if (make_token)
{
// The image URL is very important, it must be exactly right
var img_src;
var img_w = 70; // FIXME: Grid size... or *something*
var img_h = 70;
if (!ns.isnull(ns.rtable))
{
// Try the rollable table...
var tbl_item = findObjs({ _type: "tableitem", _rollabletableid: ns.rtable.get("id"), name: i_name })[0];
ns.debug(tbl_item);
img_src = tbl_item.get("avatar");
}
if (ns.isnull(img_src) && !ns.isnull(ns.deck))
{
// Try the deck...
ns.debug("Deck: " + ns.deck);
img_w = ns.deck.get("defaultwidth");
img_h = ns.deck.get("defaultheight");
var card = findObjs({ _type: "card", _deckid: ns.deck.get("id"), name: i_name })[0];
img_src = card.get("avatar");
}
// If it's still null, too bad, we can't do this. Otherwise...
if (!ns.isnull(img_src))
{
var pos1 = img_src.lastIndexOf("/");
var pos2 = img_src.lastIndexOf("?");
img_src = img_src.substring(0, pos1 + 1) + "thumb.png" + img_src.substring(pos2);
ns.debug(img_src);
o = createObj("graphic", {
pageid: Campaign().get("playerpageid"), layer: "objects",
imgsrc: img_src, left: 105, top: 105, width: img_w, height: img_h //width: 70, height: 70
});
}
//var grid_size = 70; // FIXME: Actually find this.
//var img_w = nvl(o.get("width"));
//var img_h = nvl(o.get("height"));
}
}
// Takes a string and an array describing match conditions.
// Returns a boolean indicating whether or not the string passed.
parm_deck_util.matches = function(desc, filters)
{
var ns = parm_deck_util;
var passed = true;
_.each(filters, function (condition, key)
{
// The first letter may indicate something.
var indicator = condition[0];
if (indicator != "/" && indicator != "^") indicator = "";
// Remove the indicator from the string if one was found.
var s = condition.substring(indicator.length);
// Now for our tests...
if (passed)
{
if (indicator == "/")
{
// Regular expression
var regex = new RegExp(s);
passed = regex.test(desc);
}
else
{
// Filter with (the default) or without (^ indicator) this word
var wanted = (indicator != "^");
var contains = (desc.indexOf(s) >= 0);
passed = (contains == wanted);
}
//debug(desc + (passed ? " meets ": " fails ") + s);
}
//if (!passed) break; // Can't break out of _each, consider switching to _find
});
ns.debug(desc + (passed ? " passes.": " fails."));
return passed;
};
// My function library
parm_deck_util.debug = function(s) { if (parm_deck_util.debugging) log(s); };
parm_deck_util.error = function(s) { sendChat(parm_deck_util.speak_as, parm_deck_util.whisper + "Error: " + s); };
parm_deck_util.info = function(s) { sendChat(parm_deck_util.speak_as, parm_deck_util.whisper + s); };
parm_deck_util.nvl = function(o, v) { return parm_deck_util.isnull(o) ? v : o; };
parm_deck_util.isnull = function(o) { return typeof o == 'undefined' || o == null || o.length == 0; };
parm_deck_util.replaceAll = function(s, a, b) { return s.split(a).join(b); };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment