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

Looking for a script that will spawn my whole party on a map

Looking for a script that will spawn my whole party on a map, Similar to the summoning script but uses their default tokens.
1585849921

Edited 1585849970
Dumbhuman
Pro
Marketplace Creator
I just tested the version of the Summon script that I use, because I was positive it always summoned the default tokens.&nbsp; However, I did discover that if you set any new default tokens, the script doesn't seem to be able to summon those characters anymore until you restart the API (at which point it will correctly use their new default tokens).&nbsp; Except for that little caveat, it will work to spawn your whole party on the map so long as you have a token to select when you run the command.&nbsp; Maybe someone else has created a script better suited to that specific task though. GIF of the problem and the fix: And the code of the Summon script I use, because there are lots of versions floating around out there: /* This is an improved Summoning API that was built upon. Original author: Brandon W. Original here: <a href="https://app.roll20.net/forum/post/466778/scipt-au" rel="nofollow">https://app.roll20.net/forum/post/466778/scipt-au</a>... Special thanks to Brian for helping me with some of the script. I hope this serves others well, do not hesistate to contact me regarding bugs or improvements. -GM King Usage: 1. Select token you want the monster to appear next to. 2. In chat, type "!summon (name of monster) (number to summon)" without brackets or quotation marks. 3. By default the monster will take up a 5x5 ft square (medium or small creature). To summon larger creatures add a letter to the end of the message: F= Fine, D = Diminutive, T= Tiny, L = large, H = Huge, G = Gargantuan, C = Colossal, cust = customised size (this tag must be followed by two numbers, see examples). 4. You can also summon a torch that will give 40 ft of vision with 20 ft of dim light (torch must be in the name). NB. The name of the monster must be in your character sheet list and the image must be the token image you wish to use (marketplace images do not work). Examples: !summon torch !summon eagle !summon eagle 2 !summon eagle 1d3 !summon eagle 1d3+1 !summon cave troll 1d3+1 H !summon flame sphere cust 140 140 NB. When making a custom size every 70 = 1 square. */ /* global TokenNameNumber */ on('ready',function(){ const getCleanImgsrc = 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; }, processCreated = (( 'undefined' !== typeof TokenNameNumber &amp;&amp; TokenNameNumber.NotifyOfCreatedToken ) ? TokenNameNumber.NotifyOfCreatedToken : _.noop ) , summonToken = function(character,pageid,baseX,baseY,baseW,baseH){ "use strict"; const page=getObj('page',pageid); baseW=baseW||70; baseH=baseH||70; character.get('defaulttoken',function(defaulttoken){ const dt = JSON.parse(defaulttoken); if(dt &amp;&amp; getCleanImgsrc(dt.imgsrc)){ dt.imgsrc=getCleanImgsrc(dt.imgsrc); dt.left=((baseX+baseW+dt.width)&gt;page.get('width') ? baseX-dt.width : baseX+baseW); dt.top=((baseY+baseH+dt.width)&gt;page.get('height') ? baseY-dt.width : baseY+baseH); dt.pageid = pageid; processCreated(createObj('graphic',dt)); } else { sendChat('','/w gm Cannot create token for &lt;b&gt;'+character.get('name')+'&lt;/b&gt;'); } }); }; on("chat:message", function(msg) { if (msg.type == "api" &amp;&amp; msg.content.indexOf("!summon ") === 0) { var GM = ""; var size1 = 0; var size2 = size1; var s = 0; var inputName = ""; var howMuch = 0; var amount = 0; // Amount of summoned monsters. var mod = 0; // Modifier to amount. var skip = false; var action = "Summons "; var section = msg.content.split(/\s+/); // Breaks API call into sections. if (section.length &gt; 1) { for (var j=1;j&lt;section.length;j++) { if (typeof parseInt(section[j]) === 'number' &amp;&amp; Math.round(parseInt(section[j])) % 1 == 0 || section[j].length &lt;= 4 &amp;&amp; section[j].toLowerCase().search("d") != -1 &amp;&amp; /\dd/.test(section[j]) || section[j].toLowerCase() == 'cust') { if (section[j].toLowerCase() == 'cust') { howMuch = j; break; } else { if (j != section.length-1) { for (var m = j+1; m &lt; section.length; m++) { if (typeof parseInt(section[m]) === 'number' &amp;&amp; Math.round(parseInt(section[m])) % 1 == 0 || section[m].length &lt;= 4 &amp;&amp; section[m].toLowerCase().search("d") != -1 &amp;&amp; /\dd/.test(section[m])) { skip = true; } else { skip = false; } } } else { skip = false; } if (skip == false) { howMuch = j; break; } } } } if (howMuch &gt; 0) { for (var k=1;k&lt;howMuch;k++) { if (k == howMuch-1) { inputName = inputName + section[k]; } else { inputName = inputName + section[k] + " "; } } if (section[howMuch].toLowerCase().search("d") != -1) // If user chose to roll. { if (section[howMuch].indexOf("+") != -1) { mod = section[howMuch].split("+"); // If user specified a modfier. section[howMuch] = mod[0]; mod = parseInt(mod[1],10); } var count = 0; var diceRoll = section[howMuch].split("d"); diceRoll[0] = diceRoll[0].replace(/\D/g,''); diceRoll[1] = diceRoll[1].replace(/\D/g,''); var lowEnd = parseInt(diceRoll[0]); var highEnd = parseInt(diceRoll[1]); while (count &lt; lowEnd) { amount = amount + randomInteger(highEnd); // Rolls dice. count++; log("Summoner: rolls a " + amount); } } else if (section[howMuch].toLowerCase() != 'cust') { amount = parseInt(section[howMuch],10); // Creates variable for number of summoned monsters. } else { amount == 1; } amount = amount + mod; } else if (howMuch == 0) { if (section[section.length-1].length == 1) { s = 1; howMuch = section.length - 2; } amount = 1; for (k=1;k&lt;section.length-s;k++) { if (k == section.length-1-s) { inputName = inputName + section[k]; } else { inputName = inputName + section[k] + " "; } } } if (section.length &gt; (howMuch+1) &amp;&amp; section[howMuch].toLowerCase() != "cust") { if (section[howMuch+1].toLowerCase() == "f") { size1 = -63; size2 = size1; } else if (section[howMuch+1].toLowerCase() == "d") { size1 = -56; size2 = size1; } else if (section[howMuch+1].toLowerCase() == "t") { size1 = -35; size2 = size1; } else if (section[howMuch+1].toLowerCase() == "l") { size1 = 70; size2 = size1; } else if (section[howMuch+1].toLowerCase() == "h") { size1 = 140; size2 = size1; } else if (section[howMuch+1].toLowerCase() == "g") { size1 = 210; size2 = size1; } else if (section[howMuch+1].toLowerCase() == "c") { size1 = 280; size2 = size1; } else if (section[howMuch+1].toLowerCase() == "cust") { if (typeof section[howMuch+2] != 'undefined') { size1 = parseInt(section[howMuch+2]); } else { sendChat(msg.who, "/w gm Please ensure the \"cust\" tag is followed by two values (every 70 = 1 square)."); // If monster is not in character list. } if (typeof section[howMuch+3] != 'undefined') { size2 = parseInt(section[howMuch+3]); } else { sendChat(msg.who, "/w gm Please ensure the \"cust\" tag is followed by two values (every 70 = 1 square)."); // If monster is not in character list. } } } else if (section[howMuch].toLowerCase() == "cust") { if (typeof section[howMuch+1] != 'undefined') { size1 = parseInt(section[howMuch+1]); } else { sendChat(msg.who, "/w gm Please ensure the \"cust\" tag is followed by two values (every 70 = 1 square)."); // If monster is not in character list. } if (typeof section[howMuch+2] != 'undefined') { size2 = parseInt(section[howMuch+2]); } else { sendChat(msg.who, "/w gm Please ensure the \"cust\" tag is followed by two values (every 70 = 1 square)."); // If monster is not in character list. } } } else { sendChat(msg.who, "/w gm No monsters specified to summon"); // If user writes too many things. } var check = findObjs({ _type: "character", name: inputName },{caseInsensitive: true})[0]; if (typeof check == 'undefined') { sendChat(msg.who, "/w gm Monster of name \"" + inputName + "\" does not exist."); // If monster is not in character list. } else { var list = findObjs({ _type: "character", name: inputName},{caseInsensitive: true}); var characterId = list[0].id; // Extract character ID from character sheet var characterName = list[0].get('name'); // Extract character name from character sheet var characterImage = getCleanImgsrc(list[0].get('avatar')); // Extract character image URL from character sheet var character; if (!characterImage) { sendChat(msg.who, "/w gm Monster of name \"" + inputName + "\" has a marketplace image or is missing. &lt;code&gt;"+list[0].get('avatar')+"&lt;/code&gt;"); // Error message } else { var selected = msg.selected; _.each(selected, function(obj) { var tok = getObj("graphic", obj._id); // Create variable for selected token (for summoned monster positioning) var HP = findObjs({ _type: "attribute", name: "hitpoints", _characterid: characterId },{caseInsensitive: true})[0]; //finds the health from charactersheet if (typeof HP == 'undefined') { HP = "-1"; } else { HP = (HP) ? HP.get("current") : 0; // Changes HP to useable string } var SP = findObjs({ _type: "attribute", name: "speed", _characterid: characterId },{caseInsensitive: true})[0]; //finds the speed from charactersheet if (typeof SP == 'undefined') { SP = "-1"; } else { SP = (SP) ? SP.get("current") : 0; // Changes SP to useable string } var AC = findObjs({ _type: "attribute", name: "armorclass", _characterid: characterId },{caseInsensitive: true})[0]; // finds the ac from charactersheet if (typeof AC == 'undefined') { AC = "-1"; } else { AC = (AC) ? AC.get("current") : 0; // Changes AC to useable string } if (amount == 0) { amount = 1; } else if (amount &gt; 20) { var tooMany = amount; amount = 20; log("Summoner: User specified " + tooMany + " monsters. Scaling to 20."); // If user spams the field. } for (var i=0;i&lt;amount;i++) { if (HP == "-1" &amp;&amp; AC == "-1" &amp;&amp; msg.content.toLowerCase().search("torch") != -1) { action = "Lights"; createObj("graphic", { represents: characterId, // Links new token to charactersheet left: tok.get("left")+70, top: tok.get("top"), width: 70+size1, height: 70+size2, name: characterName, pageid: tok.get("pageid"), imgsrc: characterImage, layer: "objects", light_radius: 40, light_dimradius: 20, light_otherplayers: true }); } else if (HP == "-1" &amp;&amp; AC == "-1") { character = getObj('character',characterId); if(character){ summonToken( character, tok.get('pageid'), tok.get('left'), tok.get('top'), tok.get('width'), tok.get('height') ); } else { sendChat('','/w gm No character for id: &lt;b&gt;'+characterId+'&lt;/b&gt;'); } } else { character = getObj('character',characterId); if(character){ summonToken( character, tok.get('pageid'), tok.get('left'), tok.get('top'), tok.get('width'), tok.get('height') ); } else { sendChat('','/w gm No character for id: &lt;b&gt;'+characterId+'&lt;/b&gt;'); } } } }); if (amount &gt; 1) { inputName = inputName + "s"; // If more than 1 summon, adds plural. } else if (amount == 1 &amp;&amp; action == "Lights") { amount = " a"; inputName = "torch"; } if (typeof amount === 'number') { amount = amount.toString(); } // sendChat(msg.who, GM + action + amount + " " + inputName + "!"); // Announces how many and what Summoner has summoned. } } } }); });
That works perfectly except instead of using their default token it puts their health in bar 3 and their AC in bar 2 instead of their default. Which is bar 1 hp bar 2 hit_dice and bar 3 ac.
1585863523
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
IIRC, summon doesn't actually pull the default token, but creates it, based on some scripted criteria. I stopped using it because of this issue.
1585884160

Edited 1585885326
Dumbhuman
Pro
Marketplace Creator
Anthony V. said: That works perfectly except instead of using their default token it puts their health in bar 3 and their AC in bar 2 instead of their default. Which is bar 1 hp bar 2 hit_dice and bar 3 ac. That's just happening in my gif because that's the way that I prefer to set up my tokens.&nbsp; However you set up your default tokens is the way it will summon them (just as long as you remember to restart the API after you've changed any default tokens). keithcurtis said: IIRC, summon doesn't actually pull the default token, but creates it, based on some scripted criteria. I stopped using it because of this issue. Isn't that true of all tokens though?&nbsp; I imagine that's why you get a unique token_id every time you drag a character onto the tabletop.&nbsp; As far as I can tell though, using that Summon script gives the same results (apart from the API restart caveat) as dragging a character onto the tabletop. &nbsp; I just changed a token's auras, added a couple of token markers, changed its emit light range, unclicked has sight, changed who could see the auras, etc. then I set it as the default token, restarted the API sandbox, and when I summoned the character it maintained all of the settings just fine.
1585885238
Dumbhuman
Pro
Marketplace Creator
Ah, okay... I found at least one thing that differs.&nbsp; Setting bar location to below isn't honored by the Summon script version I use.&nbsp; It will summon a token with the bars back on top.&nbsp; There might be other settings that were overlooked as well, but the ones I use for my tokens (size, bars, auras, light/sight, etc.) are all covered so I never noticed anything missing before.
I'm pretty sure it makes a token from the character's portrait rather than default token. I'd love a version that brings a character's default token to the VTT as well, but idk if the API has access to that.
1585919459
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
KC . said: Ah, okay... I found at least one thing that differs.&nbsp; Setting bar location to below isn't honored by the Summon script version I use.&nbsp; It will summon a token with the bars back on top.&nbsp; There might be other settings that were overlooked as well, but the ones I use for my tokens (size, bars, auras, light/sight, etc.) are all covered so I never noticed anything missing before. That's a general API issue. When the dev team revamped the token bars early last year, they did not include bar control in the API library. No script can do this. The Aaron or I clamor for this every few months, but to date, the defaulttoken command will not touch these settings. As for the other tests you ran, that's good to hear in general. But until the general API deficiency is addressed, I'll keep pulling the tokens out manually or copying an d pasting, the way our caveman ancestors did when Roll20 was young and dinosaurs ruled the earth. :)
1585929073

Edited 1585931873
Dumbhuman
Pro
Marketplace Creator
Persephone said: I'm pretty sure it makes a token from the character's portrait rather than default token. I'd love a version that brings a character's default token to the VTT as well, but idk if the API has access to that. It requires them to have a portrait and will give misleading error messages if they don't, but at least with the version that I use, it definitely doesn't make the token from it. I know there are lots of versions of that script floating around though.&nbsp; The code I posted in this thread is one that Aaron had tweaked some time ago to include TokenNameNumber support so maybe he changed the default token aspects as well.&nbsp; He also recently tweaked a version of it to include some post-summon TokenMod support, but for some inexplicable reason that one doesn't work for me and crashes my sandbox (which is annoying because I would love that functionality to be able to make a macro which summons 8 beasts, automatically spread out and with hit points rolled). Edit:&nbsp; Okay, so that recently modified version I mentioned was apparently based on the version of the Summon script you all remember as using the avatar rather than the default token and I agree it's really not worth it.&nbsp; I highly recommend the code posted in this thread as opposed to that one, but maybe one day someone will really adopt/update the Summon script and get it into the one click installs to end all the confusion once and for all!
Oh, well that's good to know. I'll have to do some more testing with the one you shared because last time i tried it, it wouldn't maintain the light emission settings for tokens that I summoned.
No luck with that script still, it crashes the API every time I try to summon something :/
1586382028
Dumbhuman
Pro
Marketplace Creator
That's so strange.&nbsp; The other one that Aaron more recently modified crashes my API sandbox even if it's the only script installed, but this one doesn't crash mine at all.&nbsp; Perhaps it has to do with character sheet settings?
I've honestly no clue. The main characters I have that I'd use this for are familiars and spell templates, most of them with marketplace images, which it can't summon. The ones with custom images cause this crash and don't show up on the VTT. Some have multisided tokens, and it says it can't create a token from them. Others say it just doesn't exist altogether. Some are assigned to players, some aren't.