It's all good, Tim. You've got plenty of room to do what you want to do. To be clear, though, when you speak of "script" I am understanding you to have written some amount of javascript code that you are invoking by some text handle through chat. For instance: !thereAreSomeWhoCallMe_Mod If that's the case, then your mod script has already built the above panel... which means that it knows the value of each of the undead types (like that "Vampire" is a 4). Now, while you can do this with ScriptCards or metascripts through chat, you indicated that you wanted to do this in your script, so let's stay there. Also, a script cannot generate the 3D dice on the game board, so you don't *have* to do it as a die roll (you can call the randomInteger() function with the size of die you want to roll: randomInteger(20) ...and assign it to a variable you use for your calculations. But you said "script" and you said "roll", so let's do it. There are two things you have to do to handle the dice you roll: locate the roll in your command line extract the value from the inline roll If you already know how to do the former, skip to the section on the latter. Locating the Roll What you're going to want is a way to break your command line down so you can read the various data components. Once you have that, you can construct the command line of the buttons so that they will send an appropriately formatted message. While you could format your command line however makes sense to you (you just have to be able to "encode" AND "decode" it, or "build" and "read" it), it really comes down to a handful of levers you can pull, in this case... something like: !undeadify --Vampire --[[1d20]] !undeadify --type=Vampire --roll=[[1d20]] !undeadify --type=Vampire --target=4 --roll=[[1d20]] The data is divided to segments separated by "white space plus a double hyphen". That let's us split the command line to read the data. After that, it's a matter of answering questions: Is the line going to ALWAYS be built the same (that is, will it only ever be run from your menu, built by your script, so you know the order of arguments will never change)? Is the target number for the undead type ALWAYS going to be the same? Or is it generated by some in-game effect (ie, this time the Vampire target might be 4, but next time it might be 5, or 8)? What other command pathways are you going to have to handle beyond this success check? (For instance, would there be a follow up menu with more buttons to click depending on situation?) Just for demonstration, let's say that your answer to #1 is YES (your command line will always be constructed the same way), and the answer to #2 is also YES/FIXED (a fixed value that is the same every time you roll against a Vampire type). Since you mentioned that the further roll of the 1d12 and the 3d4 should be automatic based on success of the first 1d20, I'm not seeing that as another button that the user has to click, so for now the answer to #3 is NA (there are no other commands you have to handle). That means that your command line can be the simplest (the one at the top): !undeadify --Vampire --[[1d20]] Importantly, your script is going to see that as referring to data: !handle --undeadType --checkRoll So now you can split the line on the white-space-double-hyphen, and reference the parts as necessary: let args = msg.content.split(/\s*--/); // args[0] is the "handle": !undeadify // args[1] is the "undeadType": Vampire // args[2] is the "checkRoll": $[[0]] Alternatively, this is functionally the same, but gives you named variables for the parts: let [handle, undeadType, checkRoll] = msg.content.split(/\s*--/); // handle: !undeadify // undeadType: Vampire // checkRoll: $[[0]] Extract the Value from the Roll If you can locate the roll in your command line, you're halfway there. Now you have to extract the value. There are a couple of ways to do that. First, some verbiage. The roll is implemented above (ie, [[1d20]] ) is an inline roll . When it goes through the Roll20 parsers, you're left with a roll marker , which is a formation like: $[[0]] ...where the number between the double brackets is the roll index . All of the data for an inline roll (as long as your not using a beacon sheet like the 2024 sheet) is on the message object in the inlinerolls property. The property contains an array where each roll is ordered according to its roll index (so $[[0]] refers to the first roll in the array, $[[1]] refers to the second, etc.). All of the roll data is there, but it's a bit... "WHERE'S THE SOIL?!" It's a bit everywhere. So your first option is to process the rolls in the command line down to their values right in the command line... If the d20 rolled a 14 and was assigned the roll index of 0 (the first roll), then processing the rolls in the command line would replace every instance of $[[0]] with 14. Then, when you went to parse the line and retrieve the "checkRoll" value (the result of the d20 roll), the text would already have been changed to be 14 rather than $[[0]]. The Aaron shared a code snippet that does that. He might have updated it from this version (to handle extended edge cases), but for what you're doing, this will work: const escapeRegExp = (string) => { return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); }; const processInlinerolls = (msg) => { if (msg.inlinerolls && msg.inlinerolls.length) { return msg.inlinerolls .reduce((m, v, k) => { let ti = v.results.rolls.reduce((m2, v2) => { if (v2.hasOwnProperty('table')) { m2.push(v2.results.reduce((m3, v3) => [...m3, (v3.tableItem || {}).name], []).join(", ")); } return m2; }, []).join(', '); return [...m, { k: `$[[${k}]]`, v: (ti.length && ti) || v.results.total || 0 }]; }, []) .reduce((m, o) => m.replace(new RegExp(escapeRegExp(o.k), 'g'), o.v), msg.content); } else { return msg.content; } }; The processInlineRolls function takes the message object, and returns the modified command line string with the values from the dice swapped into their places. That means you can swap it into your line parsing: let args = processInlineRolls(msg).split(/\s*--/); ...OR... let [handle, undeadType, checkRoll] = processInlineRolls(msg).split(/\s*--/); ...and now wherever you would refer to the roll, you are no longer reading the roll marker ($[[0]]), you are reading the value of the roll. Your other option for getting the data from the roll would be to use something like libInline (a library script you can install and reference as a dependency). That option does make for simpler code, but it's a bit like bringing a nuke to a knife fight, for this application, so I'll just include the link to the original write up of its usage and let you decide what you want to do. Post back if any of this isn't clear or you have more questions.