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

Pretty stat rolling macro

Hi three, trying to make a macro for an upcoming campaign that will roll for stats in a pretty box and show totals. Or even a more fancy one if anyone knows how to pull it off. Our campaign is going to use this for our stats: Roll 4d6, take highest 3 as stat. Repeat 6 times. Total must be between 62 and 82, if it is not, reroll. You may reroll once if you do not like your number spread, but you MUST take the second set. I found this macro while googling and it has a really nice appearance, but does not total the stats at the end. &{template:default} {{name= Ability Scores}} {{[[4d6kh3]][[4d6kh3]][[4d6kh3]][[4d6kh3]][[4d6kh3]][[4d6kh3]]}} I also found this one that shows the scores and posts the total, but it doesn't look very nice. /r [[4d6k3]] + [[4d6k3]] + [[4d6k3]] + [[4d6k3]] + [[4d6k3]] + [[4d6k3]]
1546459850
GiGs
Pro
Sheet Author
API Scripter
There's no way to do exactly what you want without a Pro-level account. Basic macros cannot do conditionals: you cant show individual dice, and then the total of those dice. The two options you have above are probably the best options available for you.
I sponsored my DM to be a pro for a few months, could he make the macro and provide to the players? (figured he would get more bang for the buck out of it as a DM than I would as a player.)
1546460295
GiGs
Pro
Sheet Author
API Scripter
Making your GM Pro is the best way. Yes, he'll be able to make a macro to do this. The first way would be to use the Power Cards script. There's a thread for it in the API forum - are you able to see that? (I know the pro forum is only accessible to pro users, dont know about the API forum). Someone there will be able to provide the macro needed. Your GM will need to go to the API scripts tab of the campaign settings first, and install the script from there. The second way would be to write a custom script. If you are he know javascript, that would be a pretty easy script to write. If not, and you prefer to go that way rather than Power Cards, let us know and we can whip it up for you.
Neither of us is well versed in JS, haven't touched in in years. I'll see what I can view in the forum and post back. thanks!
Whew that all looks pretty confusing. What would one of you charge to whip up the script and how fancy could it be? Could it be set to automatically scrap a result and reroll if not within the parameters?
1546464616
GiGs
Pro
Sheet Author
API Scripter
There's no need to offer money. This is a fairly simple project. (Though a donation to my roll20 account to support my Pro subscription would not be refused!) You definitely could have the script reroll if not within the parameters. I would suggest instead to have a button printed in chat, that players could click to roll the buttons, and which reports the total, telling them if its outside the parameters. So they have to click the button again if needed. This mirrors the tabletop experience a bit more: you might have some players having to click the button 2 or 3 times to get their used stats - that feels like a more faithful experience. But if you prefer to have it roll the stats and keep rerolling without player intervention, that would be doable. So would you prefer: a) The method I suggested above, requiring manual rerolling when outside parameters b) The script rerolls as many times as needed, printing all attempts in chat, this showing how many attempts were needed c) the script rerolls as many times as needed, but only shows the final attempt that succeeded I'll write up a draft copy of the script tomorrow, and set it up in a test campaign for you to test it out.
I would prefer to keep the clutter to a minimum within the chat pane so having it reroll until a solution fitting the parameters was obtained and only showing the solution would be best.. Having a button to reroll to generate another valid set would also be nice to have.
1546528012

Edited 1546528054
GiGs
Pro
Sheet Author
API Scripter
Here's a script that will do what you need. The styling is basic and could be improved with extra work. The output looks like this: The bottom one is an example of a situation where the player needed to roll multiple times. There's an option in the script to disable displaying previous rolls, but I thought I'd include this to see if you liked it. It doesn't take up too much clutter. Here's a campaign where you can test it out: <a href="https://app.roll20.net/join/4097815/MWGvsA" rel="nofollow">https://app.roll20.net/join/4097815/MWGvsA</a> If you type this in chat you'll get a button which anyone can click to use the script: [Ability Rolls](!dndabilityrolls) I've added this as a universal Macro in the above campaign, named ability-rolls. To use the script in your own campaigns, your GM will need to copy and paste this script into your campaigns scripts tab. on('ready', function () { &nbsp; &nbsp; const showAllRolls = 1, // change this to 0 if you dont want to display previous rolls. &nbsp; &nbsp; &nbsp; &nbsp; getSpeaker = function (msg) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let characters = findObjs({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _type: 'character' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let speaking; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; characters.forEach(function (chr) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (chr.get('name') == msg.who) speaking = chr; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let speaker = speaking ? 'character|' + speaking.id : 'player|' + msg.playerid; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return speaker; &nbsp; &nbsp; &nbsp; &nbsp; }, &nbsp; &nbsp; &nbsp; &nbsp; getTitle = function (speaker) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const args = speaker.split('|'); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const type = args[0]; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const id = args[1]; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let title = ''; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (type === 'player') { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; title = getObj("player", id).get("displayname") || ''; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (type === 'character') { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; title = getAttrByName(id, 'character_name') || ''; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return title; &nbsp; &nbsp; &nbsp; &nbsp; }, &nbsp; &nbsp; &nbsp; &nbsp; processInlinerolls = function (msg) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (_.has(msg, 'inlinerolls')) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return _.chain(msg.inlinerolls) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .reduce(function (previous, current, index) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; previous['$[[' + index + ']]'] = current.results.total || 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return previous; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, {}) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .reduce(function (previous, current, index) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return previous.replace(index, current); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, msg.content) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .value(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return msg.content; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; on('chat:message', function (msg) { &nbsp; &nbsp; &nbsp; &nbsp; if (msg.type === "api" &amp;&amp; msg.content.match("!dndabilityrolls") &amp;&amp; !_.has(msg, 'inlinerolls')) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let speaker = getSpeaker(msg); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat(speaker, `!dndabilityrolls--${speaker}--[[4d6kh3]]--[[4d6kh3]]--[[4d6kh3]]--[[4d6kh3]]--[[4d6kh3]]--[[4d6kh3]]`); &nbsp; &nbsp; &nbsp; &nbsp; } else if (msg.type === "api" &amp;&amp; msg.content.match("!dndabilityrolls") &amp;&amp; _.has(msg, 'inlinerolls')) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const message = processInlinerolls(msg); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const args = message.split('--'); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const speaker = args[1]; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const title = getTitle(speaker); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let attempts = ''; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (showAllRolls) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (let i = 8; i &lt; args.length; i++) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; attempts += args[i]; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let output = `&amp;{template:default} {{name=Ability Scores: ${title}}} ${attempts} {{`; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let total = 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (let i = 2; i &lt; 8; i++) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output += `${args[i]} `; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (i !== 7) output += '- '; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total += parseInt(args[i], 10) || 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output += `=Total: ${total}}}`; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (total &lt; 62 || total &gt; 82) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; attempts += `--{{${args[2]} - ${args[3]} - ${args[4]} - ${args[5]} - ${args[6]} - ${args[7]}=Total: ${total}}}`; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat(speaker, `!dndabilityrolls--${speaker}--[[4d6kh3]]--[[4d6kh3]]--[[4d6kh3]]--[[4d6kh3]]--[[4d6kh3]]--[[4d6kh3]]--${attempts}`); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat(speaker, output); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; }); });
Wow that's actually perfect! You wrote that so fast. Thank you so much for taking the time to help us with this!
1546550097
GiGs
Pro
Sheet Author
API Scripter
You're welcome - happy to help :)
&amp;{template:5e-shaped} {{title=Determine your Fate...[init](<a href="https://i.imgur.com/isHH55L.png)}}{{.[[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]]" rel="nofollow">https://i.imgur.com/isHH55L.png)}}{{.[[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]][[4d6d1]]</a>}}
1546578193
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Nice, but it rolls 8 stats, not 6, and doesn't show the total, which is what the OP was asking for.
1546590795
GiGs
Pro
Sheet Author
API Scripter
Also, only works for people using the Shaped 5e sheet. Travis hadn't said which sheet they are using.