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

Sheet button to randomize from a hidden table, only display the result?

I cannot for the life of me figure out how to make this work from a custom character sheet and not have to add a macro for every campaign with it. I need a button that randomly chooses ("rolls") a result from a list of results (a "table"), and then displays the result. For example, rolling a d20 on a Wild Magic table, but instead of showing "You got a 3! 1 - Explode, 2 - flowers everywhere, 3-4 - A dog appears[...]" I only want the chat to show "You got a 3! A dog appears". How do I achieve this?
1708528011
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
For a custom sheet, I'd recommend using custom roll parsing to rolll the random result using a die and then replace the die result with the appropriate text.
1708537017
GiGs
Pro
Sheet Author
API Scripter
You could do this with a rolltemplate, but it would require you to build the table of results into the formatting.
1708544897

Edited 1708551242
vÍnce
Pro
Sheet Author
Maybe this would work... (caveat: this is my first foray into Custom Roll Parsing and I'm not sure if using js to create a random result inside the sheet is acceptable.  I may post a 2nd version using roll20's quantum randomizer) example; <button type="action" name="act_random-roll">Roll</button> <script type="text/worker"> on('clicked:random-roll', (eventInfo) => { let result = ''; // roll random with a range of 1-3 const min = 1; const max = 3; const randomNumber = Math.floor(Math.random() * (max - min + 1)) + min; // outcome sent to chat switch (randomNumber) { case 1: result = '&{template:default}{{name=Random Result}}{{One}}'; break; case 2: result = '&{template:default}{{name=Random Result}}{{Two}}'; break; case 3: result = '&{template:default}{{name=Random Result}}{{Three}}'; break; default: // out of range } startRoll(result, (roll) => { finishRoll(roll.rollId); }); }); </script> edit/update: changed the min and max variables as per GiGs suggestion below.
1708548489

Edited 1708550307
GiGs
Pro
Sheet Author
API Scripter
You can do a dice roll inside start roll which means you can bypass the question of whether to use randomisers in code. (I prefer to use roll20's dice roll mechanics, because they exist! and players can see them - but if completely hidden from players, you might as well use JS random function). also this const min = Math.ceil(1); const max = Math.floor(3); could just be const min = 1; const max = 3; Finally, I've noticed you like to use switch Vince. There are places it's good to use it, but if you are just returning a single value an array or object is better. It's usually a lot less code and may be easier to read. The big stumbling block for me with custom roll parsing is that you need to make a rolltemplate to handle the output, though there some sutuations you can avoid that with a default rolltemplate.
1708552052

Edited 1708552951
vÍnce
Pro
Sheet Author
Thanks for the advice GiGs. Finally, I've noticed you like to use switch Vince. There are places it's good to use it, but if you are just returning a single value an array or object is better. It's usually a lot less code and may be easier to read. I suppose I thought switch was perfect when checking against a single test with "potentially" lots of outcomes. (only 3 in my example but a large table could be much bigger). The array seems like a great option and sadly, I would have never thought of that with my troglodyte js brain. ;-P Here's an updated version that uses an array of outcomes.  Definitely alleviates some of my superfluous code and logic. <button type="action" name="act_random-roll">Roll</button> <script type="text/worker"> on('clicked:random-roll', (eventInfo) => { // an array of outcomes const outcomes = [ '&{template:default}{{name=Random Result}}{{One}}', '&{template:default}{{name=Random Result}}{{Two}}', '&{template:default}{{name=Random Result}}{{Three}}', ]; // randomly determine an outcome against the array const randomNumber = Math.floor(Math.random() * outcomes.length); const roll_string = outcomes[randomNumber]; // post the outcome startRoll(roll_string, (roll) => { finishRoll(roll.rollId); }); }); </script>
1708554887

Edited 1708554938
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Yep, doing the roll inside startRoll was what I was thinking: <button type="action" name="act_table">Roll on Table</button> <rolltemplate class="sheet-rolltemplate-table"> {{computed::roll}} </rolltemplate> <script> on('clicked:table',async () => { const options = [ 'Table option 1', 'table option 2', 'table option 3' ]; const roll = await startRoll(`&{template:table} {{roll=[[1d${options.length} - 1]]}}`); const computeObj = {}; computeObj.roll = options[roll.results.roll.result]; finishRoll(roll.rollId,computeObj); }); </script> It'd be a little more complicated if the table results don't all have the same probability, but that's the rough idea of how to run it. And of course, you probably want more elements in your roll template so it can be styled nicely. Note that the async/await methodology is preferred when using startRoll. It allows you to write your code as if it was synchronous and allows for better branching logic if you need it.
1708558229

Edited 1708570044
GiGs
Pro
Sheet Author
API Scripter
I tend to avoid the async/await approach with startRoll. Like you, I do think it is better, but the fact it only works for that and other functions use the nested approach means that it stands out as different. I like to use the same method, it makes the code easier I think - more consistent at least. Once async/await gets opened up for things like getAttrs and getSectionIDs, I'll jump on it so fast.
vÍnce said: Thanks for the advice GiGs. Finally, I've noticed you like to use switch Vince. There are places it's good to use it, but if you are just returning a single value an array or object is better. It's usually a lot less code and may be easier to read. I suppose I thought switch was perfect when checking against a single test with "potentially" lots of outcomes. (only 3 in my example but a large table could be much bigger). The array seems like a great option and sadly, I would have never thought of that with my troglodyte js brain. ;-P Here's an updated version that uses an array of outcomes.  Definitely alleviates some of my superfluous code and logic. <button type="action" name="act_random-roll">Roll</button> <script type="text/worker"> on('clicked:random-roll', (eventInfo) => { // an array of outcomes const outcomes = [ '&{template:default}{{name=Random Result}}{{One}}', '&{template:default}{{name=Random Result}}{{Two}}', '&{template:default}{{name=Random Result}}{{Three}}', ]; // randomly determine an outcome against the array const randomNumber = Math.floor(Math.random() * outcomes.length); const roll_string = outcomes[randomNumber]; // post the outcome startRoll(roll_string, (roll) => { finishRoll(roll.rollId); }); }); </script> this is the code that worked for me! thank you! <3
1708878970
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
So, the thing with switch is that it's really just syntactic sugar in JS. Unlike other programming languages, there's no performance difference between using a switch and a long if/else chain in JS, it's really just whatever you find easier to read.