Trey, You can try this script I wrote. It is by no means anywhere as comprehensive as The Aaron's TokenNameNum, but it works for me. It requires adding a couple of attributes ('TokenDropper' and 'TokenCount') to each character you want to drop multiple copies of onto the virtual table top, but this will allow you to turn on/off the ability on a per character basis and will also tally how many copies of the character you have dropped. Enjoy! //TokenDropper v1.0 by Christopher Craig 20200425 // //Program Contract: //Requirement 1: Character objects must be created using D&D 5e OGL character sheet using the NPC set of statistics. //Requirement 2: Character objects must have default tokens created and assigned the character sheet. //Requirement 3: Default token object defined on the character sheet must reference the correct character in it's "Represents Character" field. //Requirement 4: Character object must have a 'TokenDropper' attribute added to it with the current value = "on" //Requirement 5: Character object must have a 'TokenCount' attribute added with a valid number value assigned to the current value (suggest 0). //Requirement 6: Patience! Because of the way token graphic objects are created, it was necessary to put a stalling routine after the graphic token is and // before all of the properties can be assigned. // //After all requirements above are met, dragging and dropping a character entry from your journal to the virtual table top will produce the following: //Output 1: graphic token based on the default token definition for the character object is create (normal Roll20 function). //Output 2: After a delay of 3 seconds, the token's name will be updated to include a number afterward to differentiate between the multiple copies of this token. //Output 3: The character will have hit points (health) rolled for it based on the npc_hpformula attribute of the character sheet. //Output 4: Bar 1 current and max values will be populated with the number rolled for hitpoints. //Output 5: Bar 2 will be updated with the character's armor class from the attribute of the character sheet. //Output 6: Bar 3 will be updated with the character's speed from the attribute of the character sheet. //Output 7: A yellow status marker will be added with the last digit of the modified token's name. These are easier for the players to see, especially in melee // combat when the nameplates show in sqaures below the graphic token. //Output 8: bar1_link, bar2_link, and bar3_link will be set to null - DO NOT LINK THESE to your character attributes!! If you do, a change in one toke will // change the stat for ALL tokens that also have that attribute linked to one of the stat bars. // // //Will only be called for new objects that get added, since existing objects have already been loaded before the ready event fires. on("ready", function() { log ("TD checkpoint 1: Sandbox Ready"); //Watch for a new token/grahpic item on("add:graphic", function(obj) { //Declare and assign the character variable to the character represented by the new graphic var objDroppedChar = getObj("character",obj.get("represents")); //If graphic has an associated character object then continue if (objDroppedChar!==undefined) { //Declare and assign objTokenDropper attribute to the boolean TokenDropper attribute. var objTokenDropper = getAttrByName(objDroppedChar.id, "TokenDropper"); if (objTokenDropper!==undefined) { if (objTokenDropper="on") { var objTokenCount = findObjs({name: "TokenCount",_type: "attribute", _characterid: objDroppedChar.id}, {caseInsensitive: false})[0]; var numTokenCount = Number(objTokenCount.get("current"))+1; objTokenCount.set("current", numTokenCount); log('numTokenCount: '+numTokenCount); var strTokenName = objDroppedChar.get("name"); strTokenName = strTokenName + " " + numTokenCount; log('strTokenName: '+strTokenName) var objHPFormula = findObjs({name: "npc_hpformula",_type: "attribute", _characterid: objDroppedChar.id}, {caseInsensitive: false})[0]; var strHPFormula = objHPFormula.get('current'); log('strHPFormula: '+strHPFormula); setTimeout(myFunction, 3000); function myFunction() { obj.set({ name:strTokenName, bar1_link:null, bar2_link:null, bar3_link:null, bar2_value:getAttrByName(objDroppedChar.id, "npc_speed"), bar3_value:getAttrByName(objDroppedChar.id, "npc_ac"), showname:true, showplayers_name:true, showplayers_bar1:false, showplayers_bar2:false, showplayers_bar3:false, statusmarkers:"yellow@"+(numTokenCount%10), }); }; sendChat('','/r '+strHPFormula,function(r){ var numHP=0; _.each(r,function(subr){ var val=JSON.parse(subr.content); if(_.has(val,'total')) { numHP+=val.total; } }); obj.set({ bar1_value: numHP, bar1_max: numHP }); }); }; }; }; }); });