
spellbooks = function() { //Checks for and Creates a Rollable Table as a Spell List checkCreateSpellListTable();
//Finds all the Classes a Character has and builds a spell list. getCurrentSpellList();
//builds all the spells as items on the tables buildTableItems();
//Deprecates extra spells deprecateSpells(); }; --------------------------------------------------------------------------------------------- checkCreateSpellListTable(); Creates tables with the characters name and the characters ID concatenated (character names sometimes change.) --------------------------------------------------------------------------------------------- getCurrentSpellList(); Based on the 5E sheet, grabs all classes with a Level value > 0 and builds a spell list from an array of all 5E spells. --------------------------------------------------------------------------------------------- buildTableItems(); Based on the class or classes add spells as items (in this example Friar-Tuck is a cleric.) --------------------------------------------------------------------------------------------- deprecateSpells(); Deprecates spells if the class is abandoned... (in this example Friar-Tuck gave up all cleric levels and became a barbarian.) Why use tables at all? The table are character specific a lists of all spells available by class(s) to the character; however the "weight" of the item can be used as a UI to control which spells the player should have actually have access to. Spell exists on the list with the weight of "0" the character could have the spell based on class(s) but does not have access to the spell. Spell exists on the list with the weight of "1" the character could have the spell based on class(s) AND does have access to the spell. Parity between these player lists and the record sheets can be maintained and new spells automatically added to the record-sheet complete with Power Card friendly macros. Script as it exist so far (only some spells are provided as an example.) var roll20API = roll20API || {}; roll20API.AbjurationURL = "<a href="https://s3.amazonaws.com/files.d20.io/images/5522736/JVPsnlD_KzqIIVRQSy5Htg/thumb.png?1410310482" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/5522736/JVPsnlD_KzqIIVRQSy5Htg/thumb.png?1410310482</a>"; roll20API.ConjurationURL = "<a href="https://s3.amazonaws.com/files.d20.io/images/5522756/cCOJ2oR8b81-Tec2fI0-Ow/thumb.png?1410310524" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/5522756/cCOJ2oR8b81-Tec2fI0-Ow/thumb.png?1410310524</a>"; roll20API.DivinationURL = "<a href="https://s3.amazonaws.com/files.d20.io/images/5522755/0Ml9HschVlL1OJ0xoqiH2Q/thumb.png?1410310524" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/5522755/0Ml9HschVlL1OJ0xoqiH2Q/thumb.png?1410310524</a>"; roll20API.EnchantmentURL = "<a href="https://s3.amazonaws.com/files.d20.io/images/5522758/MHE0WbCtMuN37Ay7VtMOyw/thumb.png?1410310526" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/5522758/MHE0WbCtMuN37Ay7VtMOyw/thumb.png?1410310526</a>"; roll20API.EvocationURL = "<a href="https://s3.amazonaws.com/files.d20.io/images/5522753/EtKxP8f9QiVvHW56b2ssGA/thumb.png?1410310523" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/5522753/EtKxP8f9QiVvHW56b2ssGA/thumb.png?1410310523</a>"; roll20API.IllusionURL = "<a href="https://s3.amazonaws.com/files.d20.io/images/5522751/BpLZxpc8udFoPoP1z2RD0Q/thumb.png?1410310523" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/5522751/BpLZxpc8udFoPoP1z2RD0Q/thumb.png?1410310523</a>"; roll20API.NecromancyURL = "<a href="https://s3.amazonaws.com/files.d20.io/images/5522752/mKpQqwceP8KcpV8E9oh-zA/thumb.png?1410310523" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/5522752/mKpQqwceP8KcpV8E9oh-zA/thumb.png?1410310523</a>"; roll20API.TransmutationURL = "<a href="https://s3.amazonaws.com/files.d20.io/images/5522754/O8SGFsdAgkca9g95Oqjyww/thumb.png?1410310523" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/5522754/O8SGFsdAgkca9g95Oqjyww/thumb.png?1410310523</a>"; roll20API.DeprecatedURL = "<a href="https://s3.amazonaws.com/files.d20.io/images/5527555/1ukVm1LJhbvtXrHtD8-vrg/thumb.png?1410358340" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/5527555/1ukVm1LJhbvtXrHtD8-vrg/thumb.png?1410358340</a>"; roll20API.spellbooks = [ {Class: "Barbarian", Short: "BN", Name: "barbarian_level"}, {Class: "Bard", Short: "BD", Name: "bard_level"}, {Class: "Cleric", Short: "CC", Name: "cleric_level"}, {Class: "Druid", Short: "DD", Name: "druid_level"}, {Class: "Fighter", Short: "FR", Name: "fighter_level"}, {Class: "Monk", Short: "MK", Name: "monk_level"}, {Class: "Paladin", Short: "PN", Name: "paladin_level"}, {Class: "Ranger", Short: "RR", Name: "ranger_level"}, {Class: "Rogue", Short: "RE", Name: "rogue_level"}, {Class: "Sorcerer", Short: "SR", Name: "sorcerer_level"}, {Class: "Warlock", Short: "WK", Name: "warlock_level"}, {Class: "Wizard", Short: "WD", Name: "wizard_level"} ]; roll20API.spelllist = [ { Call:"acid_splash", Name:"Acid Splash", Class:"Sorcerer,Wizard", SubClass:"", Ritual:"N", Concentration:"N", Level:"0", School:"Conjuration", component:"V,S", Material:"", Range:"60 feet", CastingTime:"1 action", Duration:"Instantaneous", Description:"I hurl a bubble of acid. Choose one creature within range, or choose two creatures within range that are within 5 feet of each other. A target must succeed on a Dexterity saving throw or take 1d6 acid damage.", HigherLevel:"This spell's damage increases by 1d6 when I reach 5th level (2d6), 11th level (3d6), and 17th level (4d6).", Effect:"I target **@{target|t1|token_name}**, and **@{target|t2|token_name}** who is within 5 feet. --Make a DEX save|vs [[8+@{selected|spellcastingability}+@{selected|PB}]] --Failed Save|[[1d6+{floor((@{level})/5),1}kl1*1d6+{floor((@{level})/11),1}kl1*1d6+{floor((@{level})/17),1}kl1*1d6]] acid damage.", PowerCard:"I hurl a bubble of acid. --text1|^*Choose one creature within range, or choose two creatures within range that are within 5 feet of each other. --text2|^*A target must succeed on a **Dexterity Saving Throw** or take **1d6 Acid Damage**." }, { Call:"blade_ward", Name:"Blade Ward", Class:"Bard,Sorcerer,Warlock,Wizard", SubClass:"", Ritual:"N", Concentration:"N", Level:"0", School:"Abjuration", component:"V,S", Material:"", Range:"Self", CastingTime:"1 action", Duration:"1 round", Description:"I extend my hand and trace a sigil of warding in the air. Until the end of my next turn, I have resistance against bludgeoning, piercing, and slashing damage dealt by weapon attacks.", HigherLevel:"", Effect:"", PowerCard:"I extend my hand and trace a sigil of warding in the air. --text1|^*Until the end of my next turn, I have **Resistance** against Bludgeoning, Piercing, and Slashing damage dealt by weapon attacks." }, { Call:"chill_touch", Name:"Chill Touch", Class:"Sorcerer,Warlock,Wizard", SubClass:"", Ritual:"N", Concentration:"N", Level:"0", School:"Necromancy", component:"V,S", Material:"", Range:"120 feet", CastingTime:"1 action", Duration:"1 round", Description:"I create a ghostly, skeletal hand in the space of a creature within range. I make a ranged spell attack against the creature to assail it with the chill of the grave. On a hit, the target takes 1d8 necrotic damage, and it can't regain hit points until the start of my next turn. Until then, the hand clings to the target. If I hit an undead target, it also has disadvantage on attack rolls against me until the end of my next turn. ", HigherLevel:"The spell’s damage increases by 1d8 when I reach 5th level (2d8), 11th level (3d8), and 17th level (4d8).", Effect:"My conjured ghostly hand attacks **@{target|t1|token_name}**. --Ranged Attack|[[1d20+@{selected|spellcastingability}+@{selected|PB}]]|[[1d20+@{selected|spellcastingability}+@{selected|PB}]] vs. AC --On Hit|[[1d8+{floor((@{level})/5),1}kl1*1d8+{floor((@{level})/11),1}kl1*1d8+{floor((@{level})/17),1}kl1*1d8]] necrotic damage, and it can't regain hit points until the start of my next turn.", PowerCard:"I create a ghostly, skeletal hand in the space of a creature within range. --text1|^*I make a **Ranged Spell Attack** against the creature to assail it with the chill of the grave. --text2|^*On a hit, the target takes **1d8 Necrotic Damage**, and it can't regain hit points until the start of my next turn. --text3|^*Until then, the hand clings to the target. If I hit an **Undead** target, it also has **Disadvantage** on attack rolls against me until the end of my next turn." }, { Call:"dancing_lights", Name:"Dancing Lights", Class:"Bard,Sorcerer,Wizard", SubClass:"", Ritual:"N", Concentration:"Y", Level:"0", School:"Evocation", component:"V,S,M", Material:"(a bit of phosphorus or wychwood, or a glowworm)", Range:"120 feet", CastingTime:"1 action", Duration:"Concentration, up to 1 minute", Description:"I create up to four torch-sized lights within range, making them appear as torches, lanterns, or glowing orbs that hover in the air for the duration. I can also combine the four lights into one glowing vaguely humanoid form of medium size. Whichever form I choose, each light sheds dim light in a 10-foot radius. As a bonus action on my turn, I can move the lights up to 60 feet to a new spot within range. A light must be within 20 feet of another light created by this spell, and a light winks out if it extends the spell's range.", HigherLevel:"", Effect:"", PowerCard:"I create up to four torch-sized lights within range, making them appear as torches, lanterns, or glowing orbs that hover in the air for the duration. --text1|^*I can also combine the four lights into one glowing vaguely humanoid form of medium size. --text2|^*Whichever form I choose, each light sheds dim light in a 10-foot radius. As a bonus action on my turn, I can move the lights up to 60 feet to a new spot within range. --text3|^*A light must be within 20 feet of another light created by this spell, and a light winks out if it extends the spell's range." }, { Call:"druidcraft", Name:"Druidcraft", Class:"Druid", SubClass:"", Ritual:"N", Concentration:"N", Level:"0", School:"Transmutation", component:"V,S", Material:"", Range:"30 feet", CastingTime:"1 action", Duration:"Instantaneous", Description:"Whispering to the spirits of nature, I create one of the following effects within range: • I create a tiny, harmless sensory effect that predicts what the weather will be at my location for the next 24 hours. The effect might manifest as a golden orb for clear skies, a cloud for rain, falling snowflakes for snow, and so on. This effect persists for 1 round. • I instantly make a flower blossom, a seed pod open, or a leaf bud bloom. • I create an instantaneous, harmless sensory effect, such as falling leaves, a puff of wind, the sound of a small animal, or the faint odor of skunk. The effect must fit in a 5-foot cube. • I instantly light or snuff out a candle, a torch, or a small campfire.", HigherLevel:"", Effect:"", PowerCard:"Whispering to the spirits of nature, I create one of the following effects within range: --• 1|I create a tiny, harmless sensory effect that predicts what the weather will be at my location for the next 24 hours. The effect might manifest as a golden orb for clear skies, a cloud for rain, falling snowflakes for snow, and so on. This effect persists for 1 round. --• 2|I instantly make a flower blossom, a seed pod open, or a leaf bud bloom. --• 3|I create an instantaneous, harmless sensory effect, such as falling leaves, a puff of wind, the sound of a small animal, or the faint odor of skunk. The effect must fit in a 5-foot cube. --• 4|I instantly light or snuff out a candle, a torch, or a small campfire." }, { Call:"eldritch_blast", Name:"Eldritch Blast", Class:"Warlock", SubClass:"", Ritual:"N", Concentration:"N", Level:"0", School:"Evocation", component:"V,S", Material:"", Range:"120 feet", CastingTime:"1 action", Duration:"Instantaneous", Description:"A beam of crackling energy streaks toward a creature within range. I make a ranged spell attack against the target. On a hit, the target takes 1d10 force damage.", HigherLevel:"The spell creates more than one beam when I reach higher levels, two beams at 5th level, three beams at 11th level, and four beams at 17th level. I can direct the beams at the same target or at different ones. I make a seperate attack roll for each beam.", Effect:"Crackling energy streaks toward **@{target|t1|token_name}**. --Ranged|[[1d20+@{selected|spellcastingability}+@{selected|PB}]]|[[1d20+@{selected|spellcastingability}+@{selected|PB}]] vs AC --(5th) Ranged:|[[{floor((@{level})/5),1}kl1*1d20+{floor((@{level})/5),1}kl1*(@{selected|spellcastingability}+@{selected|PB})}]]|[[{floor((@{level})/5),1}kl1*1d20+{floor((@{level})/5),1}kl1*(@{selected|spellcastingability}+@{selected|PB})}]] --(11th) Ranged|[[{floor((@{level})/11),1}kl1*1d20+{floor((@{level})/11),1}kl1*(@{selected|spellcastingability}+@{selected|PB})}]]|[[{floor((@{level})/11),1}kl1*1d20+{floor((@{level})/11),1}kl1*(@{selected|spellcastingability}+@{selected|PB})}]] --(17th) Ranged|[[{floor((@{level})/17),1}kl1*1d20+{floor((@{level})/17),1}kl1*(@{selected|spellcastingability}+@{selected|PB})}]]|[[{floor((@{level})/17),1}kl1*1d20+{floor((@{level})/17),1}kl1*(@{selected|spellcastingability}+@{selected|PB})}]] --On Hit|[[1d10]] force damage. ", PowerCard:"A beam of crackling energy streaks toward a creature within range. --text1|^*I make a **Ranged Spell Attack** against the target. --text2|^*On a hit, the target takes **1d10 Force Damage**." }, { Call:"fire_bolt", Name:"Fire Bolt", Class:"Sorcerer,Wizard", SubClass:"", Ritual:"N", Concentration:"N", Level:"0", School:"Evocation", component:"V,S", Material:"", Range:"120 feet", CastingTime:"1 action", Duration:"Instantaneous", Description:"I hurl a mote of fire at a creature or object within range. I make a ranged spell attack against the target. On a hit, the target takes 1d10 fire damage. A flammable object hit by this spell ignites if it isn’t being worn or carried.", HigherLevel:"This spell’s damage increases by 1d10 when I reach 5th level (2d10), 11th level (3d10), and 17th level (4d10).", Effect:"I hurl a mote of fire at **@{target|t1|token_name}**. --Ranged Attack|[[1d20+@{selected|spellcastingability}+@{selected|PB}]]|[[1d20+@{selected|spellcastingability}+@{selected|PB}]] vs. AC. --On Hit|[[1d10+{floor((@{level})/5),1}kl1*1d10+{floor((@{level})/11),1}kl1*1d10+{floor((@{level})/17),1}kl1*1d10]] fire damage. --^Effect-|A flammable object hit by this spell ignites if it isn’t being worn or carried.", PowerCard:"I hurl a mote of fire at a creature or object within range. --text1|^*I make a **Ranged Spell Attack** against the target. On a hit, the target takes 1d10 fire damage. --text2|^*A flammable object hit by this spell ignites if it isn’t being worn or carried." }, { Call:"friends", Name:"Friends", Class:"Bard,Sorcerer,Warlock,Wizard", SubClass:"", Ritual:"N", Concentration:"Y", Level:"0", School:"Enchantment", component:"S,M", Material:"(a small amount of makeup applied to the face as this spell is cast)", Range:"Self", CastingTime:"1 action", Duration:"Concentration, up to 1 minute", Description:"For the duration, I have advantage on all Charisma checks directed at one creature of my choice that isn't hostile towards me. When the spell ends, the creature realizes that I used magic to influence its mood and becomes hostile towards me. A creature prone to violence might attack me. Another creature might seek retribution in other ways (at the Dm's discretion).", HigherLevel:"", Effect:"", PowerCard:"For the duration, I have **Advantage** on all Charisma checks directed at one creature of my choice that isn't hostile towards me. --text1|^*When the spell ends, the creature realizes that I used magic to influence its mood and becomes hostile towards me. A creature prone to violence might attack me. Another creature might seek retribution in other ways (at the Dm's discretion)." }, { Call:"guidance", Name:"Guidance", Class:"Cleric,Druid", SubClass:"", Ritual:"N", Concentration:"N", Level:"0", School:"Divination", component:"V,S", Material:"", Range:"Touch", CastingTime:"1 action", Duration:"Concentration, up to 1 minute", Description:"I touch one willing creature. Once before the spell ends, the target can roll a d4 and add the number rolled to one ability check of its choice. It can roll the die before or after making the ability check. The spell then ends.", HigherLevel:"", Effect:"I touch **@target|t1|token_name}**.", PowerCard:"I touch one willing creature. Once before the spell ends, the target can roll a **1d4** and add the number rolled to one ability check of its choice. --text1|^*It can roll the die before or after making the ability check. The spell then ends." }, { Call:"light", Name:"Light", Class:"Bard,Cleric,Sorcerer,Wizard", SubClass:"", Ritual:"N", Concentration:"N", Level:"0", School:"Evocation", component:"V,M", Material:"(a firefly or phosphorus moss)", Range:"Touch", CastingTime:"1 action", Duration:"1 hour", Description:"I touch one object that is no larger than 10 feet in any dimension. Until the spell ends, the object sheds bright light in a 20-foot radius and dim light for an additional 20 feet. The light can be colored as I like. Completely covering the object with something opaque blocks the light. The spell ends if I cast it again or dismiss it as an action. If I target an object held or worn by a hostile creature, that creature must succeed on a Dexterity saving throw to avoid the spell.", HigherLevel:"", Effect:"If object held by hostile creature, they must~ --Make a DEX save|vs [[8+@{selected|spellcastingability}+@{selected|PB}]] --Failed Save|The object is lit.", PowerCard:"I touch one object that is no larger than 10 feet in any dimension. --text1|^*Until the spell ends, the object sheds **Bright Light** in a **20-Foot Radius** and dim light for an additional 20 feet. The light can be colored as I like. --text2|^*Completely covering the object with something opaque blocks the light. --text3|^*The spell ends if I cast it again or dismiss it as an action. --text4|^*If I target an object held or worn by a hostile creature, that creature must succeed on a **Dexterity Saving Throw** to avoid the spell." }, { Call:"mage_hand", Name:"Mage Hand", Class:"Bard,Sorcerer,Warlock,Wizard", SubClass:"", Ritual:"N", Concentration:"Y", Level:"0", School:"Conjuration", component:"V,S", Material:"", Range:"30 feet", CastingTime:"1 action", Duration:"1 minute", Description:"A spectral, floating hand appears at a point I choose within range. The hand lasts for the duration or until I dismiss it as an action. The hand vanishes if it is ever more than 30 feet away from me or if I cast this spell again. I can use my action to control the hand. I can use the hand to manipulate an object, open an unlocked door or container, stow or retrieve an item from an open container, or pour the contents out of a vial. I can move the hand up to 30 feet each time I use it. The hand can’t attack, activate magic items, or carry more than 10 pounds.", HigherLevel:"", Effect:"", PowerCard:"A spectral, floating hand appears at a point I choose within range. --text1|^*The hand lasts for the duration or until I dismiss it as an action. The hand vanishes if it is ever more than 30 feet away from me or if I cast this spell again. --text2|^*I can use my action to control the hand. I can use the hand to manipulate an object, open an unlocked door or container, stow or retrieve an item from an open container, or pour the contents out of a vial. I can move the hand up to 30 feet each time I use it. --text3|^*The hand can’t attack, activate magic items, or carry more than 10 pounds." } ]; on("chat:message", function (msg) { // Exit if not an api command if (msg.type != "api") return; // Get the API Chat Command msg.who = msg.who.replace(" (GM)", ""); msg.content = msg.content.replace("(GM) ", ""); var command = msg.content.split(" ", 1); if(command == "!spellbooks") { spellbooks(); }; }); spellbooks = function() { //Checks for and Creates a Rollable Table as a Spell List checkCreateSpellListTable(); //Finds all the Classes a Character has and builds a spell list. getCurrentSpellList(); //builds all the spells as items on the tables buildTableItems(); //Deprecates extra spells var characters = findObjs({type: "character"}); var rollabletables = findObjs({type: "rollabletable"}); _.each(characters, function(indexCharacters) { if(indexCharacters.get("controlledby") != ""){ var characterID = indexCharacters.get("_id"); _.each(rollabletables, function(indexrollabletables) { var rollabletableName = indexrollabletables.get("name"); var start_pos = rollabletableName.indexOf("{") + 1; var end_pos = rollabletableName.indexOf("}",start_pos); var characterIDfound = rollabletableName.substring(start_pos,end_pos); if(characterIDfound == characterID){ var tableItems = findObjs({ _type: "tableitem", _rollabletableid: indexrollabletables.get("_id")}); if(tableItems.length != 0){ _.each(tableItems, function(indextListedSpells) { var validSpell = false; _.each(roll20API.spellListClass, function(indexPlayerSpells) { var itemName = indexPlayerSpells.Level + "_" + indexPlayerSpells.Call; if(indextListedSpells.get("name") == itemName){validSpell = true}; }); if(validSpell == false){ var itemID = indextListedSpells.get("_id") findObjs({ _type: "tableitem", _id: itemID })[0].set({name: "999_deprecated"}); }; }); }; }; }); }; }); }; buildTableItems = function() { var characters = findObjs({type: "character"}); var rollabletables = findObjs({type: "rollabletable"}); _.each(characters, function(indexCharacters) { if(indexCharacters.get("controlledby") != ""){ var characterID = indexCharacters.get("_id"); _.each(rollabletables, function(indexrollabletables) { var rollabletableName = indexrollabletables.get("name"); var start_pos = rollabletableName.indexOf("{") + 1; var end_pos = rollabletableName.indexOf("}",start_pos); var characterIDfound = rollabletableName.substring(start_pos,end_pos); if(characterIDfound == characterID){ var tableItems = findObjs({ _type: "tableitem", _rollabletableid: indexrollabletables.get("_id")}); if(tableItems.length != 0){ _.each(roll20API.spellListClass, function(indexPlayerSpells) { var spellFoundAsItem = false; var itemName = indexPlayerSpells.Level + "_" + indexPlayerSpells.Call; _.each(tableItems, function(indextListedSpells) { if(indextListedSpells.get("name") == itemName){spellFoundAsItem = true}; }); if(spellFoundAsItem == false){ var avatarURL = ""; if(indexPlayerSpells.School == "Abjuration"){avatarURL = roll20API.AbjurationURL}; if(indexPlayerSpells.School == "Conjuration"){avatarURL = roll20API.ConjurationURL}; if(indexPlayerSpells.School == "Divination"){avatarURL = roll20API.DivinationURL}; if(indexPlayerSpells.School == "Enchantment"){avatarURL = roll20API.EnchantmentURL}; if(indexPlayerSpells.School == "Evocation"){avatarURL = roll20API.EvocationURL}; if(indexPlayerSpells.School == "Illusion"){avatarURL = roll20API.IllusionURL}; if(indexPlayerSpells.School == "Necromancy"){avatarURL = roll20API.NecromancyURL}; if(indexPlayerSpells.School == "Transmutation"){avatarURL = roll20API.TransmutationURL}; var itemName = indexPlayerSpells.Level + "_" + indexPlayerSpells.Call; if(characterID == indexPlayerSpells.ID){ createObj("tableitem", { _rollabletableid: indexrollabletables.get("_id"), name: itemName, avatar: avatarURL, weight: 0, }); }; }; }); }else{ _.each(roll20API.spellListClass, function(indexPlayerSpells) { var avatarURL = ""; if(indexPlayerSpells.School == "Abjuration"){avatarURL = roll20API.AbjurationURL}; if(indexPlayerSpells.School == "Conjuration"){avatarURL = roll20API.ConjurationURL}; if(indexPlayerSpells.School == "Divination"){avatarURL = roll20API.DivinationURL}; if(indexPlayerSpells.School == "Enchantment"){avatarURL = roll20API.EnchantmentURL}; if(indexPlayerSpells.School == "Evocation"){avatarURL = roll20API.EvocationURL}; if(indexPlayerSpells.School == "Illusion"){avatarURL = roll20API.IllusionURL}; if(indexPlayerSpells.School == "Necromancy"){avatarURL = roll20API.NecromancyURL}; if(indexPlayerSpells.School == "Transmutation"){avatarURL = roll20API.TransmutationURL}; var itemName = indexPlayerSpells.Level + "_" + indexPlayerSpells.Call; if(characterID == indexPlayerSpells.ID){ createObj("tableitem", { _rollabletableid: indexrollabletables.get("_id"), name: itemName, avatar: avatarURL, weight: 0, }); }; }); }; }; }); }; }); }; getCurrentSpellList = function() { var characters = findObjs({type: "character"}); var classString; roll20API.spellListClass = ""; roll20API.spellListClass = []; _.each(characters, function(indexCharacters) { classString = ""; if(indexCharacters.get("controlledby") != ""){ var characterID = indexCharacters.get("_id"); _.each(roll20API.spellbooks, function(indexBooks) { var characterSheet = getObj("character", characterID); var CurrentLevel = getAttrByName(characterSheet.id, indexBooks.Name) * 1; if(CurrentLevel > 0){classString += indexBooks.Class + ","}; }); }; classString = classString.substring(0, classString.length - 1); if(classString.length > 0){ _.each(roll20API.spelllist, function(indexSpells) { var spellFound = false; var arr1 = indexSpells.Class.split(","); var arr2 = classString.split(","); for (var i = 0; i < arr1.length; i++) { for (var j = 0; j < arr2.length; j++) { if (arr1[i] === arr2[j]) { if(spellFound == false){ roll20API.spellListClass.push({ID: characterID, Level: indexSpells.Level, School: indexSpells.School, Call: indexSpells.Call}); spellFound = true; }; }; }; }; }); }; }); }; checkCreateSpellListTable = function() { var rollabletables = findObjs({type: "rollabletable"}); var characters = findObjs({type: "character"}); _.each(characters, function(indexCharacters) { var characterID = indexCharacters.get("_id"); var characterName = indexCharacters.get("name").replace(/[^a-zA-Z ]/g, ""); characterName = characterName.split(' ').join('-'); if(indexCharacters.get("controlledby") != ""){ var tableFound = false; var tableID = ""; _.each(rollabletables, function(indexrollabletables) { if(tableFound == false){ var rollabletableName = indexrollabletables.get("name"); var start_pos = rollabletableName.indexOf("{") + 1; var end_pos = rollabletableName.indexOf("}",start_pos); var characterIDfound = rollabletableName.substring(start_pos,end_pos); if(characterIDfound == characterID){tableFound = true; tableID = indexrollabletables.get("_id");}; }; }); if(tableFound == false){ var nameToUse = characterName+"{"+characterID+"}"; createObj("rollabletable", {name: nameToUse, showplayers: false,}); tableID = findObjs( {_type: "rollabletable", name: nameToUse})[0].get("_id"); tableFound = true; }; }; }); }; Not sure this is the best way to go..... What do you think? Right track? Wrong Track? Once the tables are "set" and controlled... should be real easy to add/predicate: Spells in the record Sheet Standard Powercard Token Actions Query the tables for spells or such.