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

How to go about creating a custom sheet for multiple degrees of success?

I'm making a system that uses d100s measured against a character's skills to determine level of success (where 1 is the best you can roll and 100 is the worst): Roll result is 1/5 of skill or lower = Critical Success Roll result is 1/2 of skill or lower = Success Roll result is lower than skill = Partial Success Roll result is 50 + (Skill/2) or lower = Complication Roll result is lower than 95 = Failure Roll result is 95 or higher = Critical Failure The intent is that the highest degree of success to be satisfied is used as the outcome. So, for example, if you had a Bowcraft skill of 50: Rolling a 10 or lower = Critical Success Rolling a 25 or lower = Success Rolling a 50 or lower = Partial Success Rolling a 75 or lower = Complication Rolling a 76 - 95 = Failure Rolling a 96 - 100 = Critical Failure If this were a non-digital game, each skill would need a matrix that you'd need to look up every time to see what degree of success you got. With a virtual table top, however, I hope to make all of that happen in the background when a player clicks to roll on their sheet so it can immediately calculate and tell you what the degree of success is.  My question is, if I were to create my own custom character sheet, how would I go about implementing the "if the roll is not this, then check if it is this" framework? I've been looking at the documentation and between Macros, Roll Templates, Custom Sheets, Sheetworkers, HTML, CSS, and Javascript, I'm not sure how to accomplish this the most efficiently. Where can I put the logic of "if the die roll satisfies this parameter, then this is the degree of success that will be posted in chat." Ideally I want to make it pretty too, but that can wait. Thanks for the help.
1677046922
GiGs
Pro
Sheet Author
API Scripter
If you were doing this in a custom character sheet, there are two main ways do to do it: Rolltemplate with Logic helpers (which will need HTML and CSS) Custom Roll Parsing (which will need HTML, CSS, Rolltemplate, and Javascript - and a fairly complicated interpretation of JS). It should be obvious which I recommend. CRP is more powerful, but a lot trickier to set up. You can nest logic helpers inside each other (and often need to). To make this work, you need to suuply each category in the roll, like {{roll=[[1d100]]}} {{skill=[[@{skill}]]}} {{critical=[[round(@{skill}/5)]]}} {{success=[[round(@{skill}/2)]]}} etc You can then use the rolltemplate logic helpers to compare roll vs skill, critical, and so on. I have questions about this bit: Roll result is lower than skill = Partial Success Roll result is 50 + (Skill/2) or lower = Complication If skill is 100, those are equal. Above 100 and below 100 will give a different order. Does that every happen? If so you might need to go the CRP route to an excessively complicated rolltemplate.
1677096456
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Heh, I personally think the CRP route is easier, at least in the long term. Reading through a complicated roll template like that can be a nightmare. I'd probably do it something like this (untested): HTML <input type="number" name="attr_skill"> <button type="action" name="act_skill-roll">Skill</button> <rolltemplate class="sheet-rolltemplate-example"> {{d100}}={{computed::result}} </rolltemplate> Sheetworker // array list of our various skills const skills = ['skill']; skills.forEach(skill => { // listen for our button click on(`clicked:${skill}-roll`,() => { // get the value of our skill // use the async flag so we can use async/await with startRoll getAttrs([skill],async (attributes) => { // Send the roll, and wait for the result from the roll20 roller const roll = await startRoll(`&{template:example} {{d100=[[1d100]]}} {{result=[[0[computed value]]]}}`); // extract the result of our d100 so that we can work with it more easily const rollResult = roll.results.d100.result; // Create an empty object to hold the computations we will need to make. const computedObj = {}; // Do the logic switch(true){ case (rollResult <= (attributes[skill] / 5)): computedObj.result = 'Critical Success'; break; case (rollResult <= (attributes[skill] / 2)): computedObj.result = 'Success'; break; case (rollResult < attributes[skill]): computedObj.result = 'Partial Success'; break; case (rollResult <= (50 + Math.floor(attributes[skill] / 2))): computedObj.result = 'Complication'; break; case (rollResult < 95): computedObj.result = 'Failure'; break; default: computedObj.result = 'Critical Failure'; break; } // Send the manipulated rolls back to roll20 and release the roll for sending to chat. finishRoll(roll.rollId,computedObj); }) }); });
1677118738
GiGs
Pro
Sheet Author
API Scripter
That is easier to read than I was imagining the rolltemplate, but creating it in the first place takes a lot more internalised knowledge. But it's written now, so OP should definitely use it.